2008.05.07
こんにちはH8の世界
H8マイコンで動く”Hello, world!”を作ってみます。
ここで紹介するのは、以前に公開したh8monが書き込まれているAKI-H8/3069Fマイコンボードで動作するものです。
とは言ってもOSも無ければ標準出力も無い環境です。とりあえず出力はh8monでもコンソール入出力に使っているRS232Cで行うこととします。
方法としては直接SCI1(RS232C)を制御してアスキーコード文字列を出力することが考えられますが、以下のようなソース(hello.c)でも文字を出力することが出来ます。
void putch(char ch) { asm("mov.l #0, er2"); asm("trapa #2"); } static void print(char *str) { while(*str) { putch(*str); str ++; } } int main(void) { print("Hello, H8 world!\r\n"); return 0; }
このソースだけではまだ実行は出来ません。スタートアッププログラムが必要なのですが、まずはmain()を解説します。
printf()のような標準入出力関数は(使う方法はあるのですが)使えません。printf()の代わりの文字列出力関数としてprint()を書きました。中は文字列の終わり(0)まで一文字づつputch()に引数として渡しているだけです。
putch()の中身はインラインアセンブラで書かれています。
内容はer2レジスタを0にして、「trapa #2」を実行しています。
実はh8monではtrapa #2でSCI1から文字を入出力することが出来ます。er2を0にするとer0に書かれたデータが出力されます。er2を1にするとSCI1が受信したデータをer0に書き込みます。つまり戻り値として参照できます。
(このコードはあまり良い例ではありません。このコードは引数がer0で渡されて、他のレジスタが破壊されないことを期待しています。実際にそうなるのですが、本来は「拡張アセンブリ構文」を使うべきです。今回はソースの見易さを優先してこのようにしています。)
以下はスタートアップルーチン(start.s)です。
.h8300h .section .text .global _start .extern _stack_bottom .extern _bss_start .extern _bss_end _start: ; mov.l #0x600000,er7 ; Set SP mov.l er0,@-er7 mov.l er1,@-er7 ;; .data section initialize mov.l #_dataRAM_start,er0 mov.l #_dataRAM_end,er1 mov.l #_dataROM_start,er2 bra loop11 loop1: mov.l @er2,er3 mov.l er3,@er0 add #4,er0 add #4,er2 loop11: cmp.l er0,er1 bf loop1 ;; .bss section initialize mov.l #_bss_start,er0 mov.l #_bss_end,er1 mov.l #0,er2 bra loop21 loop2: mov.l er2,@er0 add #4,er0 loop21: cmp.l er0,er1 bf loop2 mov.l @er7+,er1 mov.l @er7+,er0 jsr _main ; Goto main() ; rts trapa #3 .end
各セクションを初期化してmain()をコールしています。最後の「trapa #3」はh8monに処理を戻すための物です。h8monではソフトウェアブレークとしてtrapa #3を使用しています。スタックポインタ(er7)の初期化も必要なのですが、上記ではコメントにしています。この場合、スタックポインタはh8monが設定する初期値(0xFFFF20:内蔵SRAM)で動作します。
以下はリンクスクリプト(h83069.lds)です。
OUTPUT_FORMAT("elf32-h8300") OUTPUT_ARCH(h8300h) ENTRY("_start") MEMORY { ram(rx) : o = 0x400000, l = 0x080000 } SECTIONS { .text : { *(.text) *(.strings) *(.rodata) *(.rodata.str1.1) _dataROM_start = . ; } > ram .data ALIGN(4) : { _dataRAM_start = . ; *(.data) _dataRAM_end = . ; } > ram .bss ALIGN(4) : { _bss_start = . ; *(.bss) *(COMMON) _bss_end = . ; } > ram }
プログラムを0x400000番地に配置するようにしています。この番地にはAKI-H8/3069FマイコンボードではDRAMが実装されています。h8monでは起動後、DRAMが使用できるようにBSC(バスコントローラ)を初期化しています。
最後にMakefileです。
CROSS = h8300-elf- CC = $(CROSS)gcc AS = $(CROSS)as LD = $(CROSS)gcc OBJCOPY = $(CROSS)objcopy CFLAGS = -mh -g -O2 -Wall LDSCRIPT= h83069.lds LDFLAGS = -mh -Wl,-Map,$*.map -Wl,-T$(LDSCRIPT) -nostartfiles PROGRAM = hello.mot OBJS = start.o hello.o SRCS = start.s hello.c .SUFFIXES: .mot .exe .a .o .c .s .h .c.o: $(CC) $(CFLAGS) -c $< .elf.mot: $(OBJCOPY) -Osrec $< $@ all: $(PROGRAM) $(PROGRAM): $(OBJS) $(START) $(LDSCRIPT) $(DEPEND) $(LD) $(LDFLAGS) -o $*.elf $(START) $(OBJS) -lgcc $(OBJCOPY) -Osrec $*.elf $*.mot clean: rm -f -r $(OBJS) $(PROGRAM) $(DEPEND) *.mot *.map *.elf *~
以前紹介したクロスコンパイラでコンパイルできます。
makeコマンドでコンパイルすると「hello.mot」が出来るはずです。
h8monでは「l」コマンドでhello.motをロードすることが出来ます。ターミナルソフトは「Tera Term Pro」がおすすめです。h8monでlコマンド入力後、「ファイル送信」機能かhello.motファイルをドロップして転送します。
h8monのgコマンドでロードしたプログラムを実行します。
実際に動かした画面は以下のようになります。
H8/300(H) 3069F Monitor Ver. 0.80 (c)2003,2004,2007 Takashi SHUDO Virtual vector table area : FFBF20 - FFC01F Monitor used RAM area : FFC020 - FFC475 Monitor stack end address : FFC608 Build date : 11:27:06 May 3 2008 >l Please send S-records data. Load address : 400000 - 4000B2 Excution address : 400000 Done. >g Hello, H8 world! Break. PC = 400062 CCR = 84 R0 = 00FF0000 R1 = 00FFC090 R2 = 00FFC0F0 R3 = 00FFC09D R4 = 00000000 R5 = 00000000 R6 = 00000000 R7 = 00FFFF20 400062 : 57 30 trapa #0x3:3 >
「Hello, H8 world!」の文字が出力されています。今回のソースはここに置いておきます。
ここまで読んでくれた方、お疲れ様でした。次回はh8monの目玉?である、gdbを使ったソフトの実行、デバッグを予定しています。(いつになったは工作の話になるんだろう(^^;;;)
Trackback URL
Comment & Trackback
Comment feed
Comment