いまさら必要に迫られてH8/300のボードを入手したのですが、あっという間に当初の目的を達成して用済みになってしました。
あまりにももったいないので、もう少し使ってみます。
やってみる
このへんと同じです。
ではつまらないので、ちょっとした制約をつけて、全部C言語で書いてみたいと思います。
犠牲になるターゲットはH8SX1668です。
内蔵のメモリがそれなりに大きい(RAM 56KByte)ので、足りないってことはないだろうということで。
準備
以前のRX版を適当に直して使うので、ports/rxをコピーしてports/h8300を作ります。
> mdkir ports/h8300
> cp ports/rx/* ports/h8300
なおす
- crt0.s → いらない
- main.c → crt0の初期化部分を移動
- rx62n.ld → h8300用に書き直し
- Makefile → 適宜修正
- uart_core → SCI用に微修正
くらいでいいはず
初期化
試行錯誤の結果、こんな書き方で期待したコードがでてきました。
# if defined(__H8300SX__)
# if MCU == H8SX1668
# define SCKCR 0x00FFFDC4
# define MSTPCRB 0x00FFFDCA
# define P6ICR 0x00FFFB95
# define SCR4 0x00FFFE92
# define SMR4 0x00FFFE90
# define BRR4 0x00FFFE91
# elif
# error Unknown MCU
# endif
static void h8sx_init()
{
/* CPG Initialize */
/* XTAL:12MHz, ICLK:48MHz (x4), PCLK:24MHz (x2) */
*(volatile unsigned short *)SCKCR = 0x0010;
/* SCI4 enable */
*((volatile unsigned short *)MSTPCRB) &= ~0x1000;
/* SCI4 RxD enable */
*((volatile unsigned char *)P6ICR) |= 0x02;
/* SCI4 Initialize */
*((volatile unsigned char *)SCR4) = 0x00;
*((volatile unsigned char *)SMR4) = 0x00;
*((volatile unsigned char *)BRR4) = 77; /* 9600 bps */
*((volatile unsigned char *)SCR4) = 0x30;
}
# endif
static void __attribute__((noinline, optimize("O1"))) init_sect(void)
{
extern char sdata[], edata[], sidata[];
extern char sbss[], ebss[];
char *s, *d;
/* initialize .data */
s = sidata;
d = sdata;
while(d < edata)
*d++ = *s++;
/* initialize .bss */
d = sbss;
while(d < ebss)
*d++ = 0;
}
void __attribute__((section(".text.startup"), noreturn, optimize("O0"), optimize("omit-frame-pointer"))) start(void)
{
register void *er7 __asm__("er7");
extern int estack[];
er7 = estack;
er7 = er7;
init_sect();
h8sx_init();
main(0, NULL);
while(1);
}
void (*vector[128])(void) __attribute__((section(".vector"))) = {
start,
};
リセットするとstart関数に飛んでくるようにしています。
attributeでいろいろつけているのは、余計なプロローグがつかないようにした努力の結果です。
なにも初期化していない状態でスタックフレーム使われても、どこかへんなところを読み書きするだけなので、まずはスタックポインタなer7を適切な値で初期化します、
CPUによってはリセットでスタックポインタも初期化してくれますが、h8300はそこまで親切じゃないので、明示的に初期化しています。
ちなみにstartをコンパイルした結果はこんなかんじ。
_start:
mov.l #_estack,er7
jsr @_init_sect
jsr @_h8sx_init
sub.l er1,er1
sub.l er0,er0
jsr @_main
.L2:
bra .L2
自分で書いてもだいたいこんな感じかなーということで、C言語だけで書くという目標はなんとか達成できました。
が、面倒くさいだけなので、たぶん二度とやらない。
あと、init_sectでO1にしているのは、新し目なgccのおせっかいでmemcpy/memsetの呼び出しにされてしまうのを防ぐためです。
ドキュメントにはO2以上と書いてあるんですが、Osも影響するようです。-ffreestandingなら無効とかにしてほしい。
動かしてみる
h8300-elfのgccとbinutilsを用意してビルドします。
LINK build/mpython.elf
text data bss dec hex filename
101260 512 2528 104300 1976c build/mpython.elf
こんな感じでelfができるので、objcopyでsrecとかにして内蔵フラッシュメモリに書き込みます。
で、上のソースにある通りSCI4が端末なので、シリアルケーブルで接続して端末を開くとこんな感じで動いているような気がします。
おまけ
バイナリのサイズを見ると、そのへんにたくさん転がっていそうなH8/3069(ROM512KByte/RAM16KByte)でも入りそうな気がしたので、やってみました。
ハードウエアの初期化とldscriptのメモリ割り当てを変えるだけです。
うちにもボードが何個か転がっているはずですが、ずっと使っていなくて発掘するのが面倒なのでqemuで動かしてみます。
REPLのところでCPUスタックの使用量を確認してみましたが、数百バイトくらいだったのでものすごくスタックを消費しなければ大丈夫そうです。
余談
公式ページを見たら
Yet it is compact enough to fit and run within just 256k of code space and 16k of RAM.
て書いてあったのがこの話のオチになってしまうという…
成果物