もくもく1stステップ

12ステップで作る組込みOS自作入門

12ステップで作る組込みOS自作入門

この本の読書メモ。

ld.scr
SECTIONS
{
	. = 0x0;

	.vectors : {
		vector.o(.data)

.vectorsを0x0に配置。vector.cでここに割り込みベクタを配置。

/* 送信可能か? */
int serial_is_send_enable(int index)
{
  volatile struct h8_3069f_sci *sci = regs[index].sci;
  return (sci->ssr & H8_3069F_SCI_SSR_TDRE);
}

/* 1文字送信 */
int serial_send_byte(int index, unsigned char c)
{
  volatile struct h8_3069f_sci *sci = regs[index].sci;

  /* 送信可能になるまで待つ */
  while (!serial_is_send_enable(index))
    ;
  sci->tdr = c;
  sci->ssr &= ~H8_3069F_SCI_SSR_TDRE; /* 送信開始 */

  return 0;
}
***vector.c
>|c|
void (*vectors[])(void) = {
  start, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 

起動時にジャンプするアドレスは割り込みベクタの0番目のエントリで指定。
なので割り込みはまだ使ってないけど割り込みベクタが要るのか。なる。

startup.s
	.h8300h
	.section .text
	.global	_start
#	.type	_start,@function
_start:

さっきのstart()の実体がこれ

	mov.l	#0xffff00,sp

スタックポインタを0xffff00に設定

	jsr	@_main

main()を関数コール

main.c
int main(void)
{
  serial_init(SERIAL_DEFAULT_DEVICE);

まずシリアルの初期化を以下で追ってみる。

defines.h
#define SERIAL_DEFAULT_DEVICE 1

serial_init()に渡していたのは1だった

serial.c
#define H8_3069F_SCI0 ((volatile struct h8_3069f_sci *)0xffffb0)
#define H8_3069F_SCI1 ((volatile struct h8_3069f_sci *)0xffffb8)
#define H8_3069F_SCI2 ((volatile struct h8_3069f_sci *)0xffffc0)

シリアルのレジスタのアドレス

struct h8_3069f_sci {
  volatile uint8 smr;
  volatile uint8 brr;
  volatile uint8 scr;
  volatile uint8 tdr;
  volatile uint8 ssr;
  volatile uint8 rdr;
  volatile uint8 scmr;
};

シリアルのレジスタの配置を構造体で表現
なんかUNIXv6を思い出す。

static struct {
  volatile struct h8_3069f_sci *sci;
} regs[SERIAL_SCI_NUM] = {
  { H8_3069F_SCI0 }, 
  { H8_3069F_SCI1 }, 
  { H8_3069F_SCI2 }, 
};

シリアルのレジスタの配列。index番号からレジスタアドレスを引くのに使用。

int serial_init(int index)
{
  volatile struct h8_3069f_sci *sci = regs[index].sci;

  sci->scr = 0;
  sci->smr = 0;
  sci->brr = 64; /* 20MHzのクロックから9600bpsを生成(25MHzの場合は80にする) */
  sci->scr = H8_3069F_SCI_SCR_RE | H8_3069F_SCI_SCR_TE; /* 送受信可能 */
  sci->ssr = 0;

  return 0;

レジスタの初期化。main()から初期化していたのがSCI1である事がわかる

main.c
  puts("Hello World!\n");

続いてputs()

lib.c
int putc(unsigned char c)
{
  if (c == '\n')
    serial_send_byte(SERIAL_DEFAULT_DEVICE, '\r');
  return serial_send_byte(SERIAL_DEFAULT_DEVICE, c);
}

int puts(unsigned char *str)
{
  while (*str)
    putc(*(str++));
  return 0;
}

str[n] == '\0'になるまでserial_send_byte()で一文字づつ送っているようだ

serial.c
/* 送信可能か? */
int serial_is_send_enable(int index)
{
  volatile struct h8_3069f_sci *sci = regs[index].sci;
  return (sci->ssr & H8_3069F_SCI_SSR_TDRE);
}

/* 1文字送信 */
int serial_send_byte(int index, unsigned char c)
{
  volatile struct h8_3069f_sci *sci = regs[index].sci;

  /* 送信可能になるまで待つ */
  while (!serial_is_send_enable(index))
    ;
  sci->tdr = c;
  sci->ssr &= ~H8_3069F_SCI_SSR_TDRE; /* 送信開始 */

  return 0;
}

ssrレジスタにTDREビットが立つと送信可能(立つまでビジーループで待ってる)
tdrレジスタに文字を書いてssrレジスタからTDREビットを外す事で送信開始
この繰り返し

まとめ

スタックポインタとシリアルデバイスの初期化以外何もやらなくていいらしい。単純明快。