MicroPython for H8/300

いまさら必要に迫られてH8/300のボードを入手したのですが、あっという間に当初の目的を達成して用済みになってしました。
あまりにももったいないので、もう少し使ってみます。

#やってみる
[このへん](https://qiita.com/yoshinori_sato/items/068c0ae572e6996fef11)と同じです。
ではつまらないので、ちょっとした制約をつけて、全部C言語で書いてみたいと思います。

~~犠牲になる~~ターゲットは[H8SX1668](https://www.renesas.com/jp/ja/products/microcontrollers-microprocessors/other-mcus-mpus/h8sx-family-mcus/h8sx1668m-microcontrollers-32-bit-cisc-cpu-system-control-applications-non-promotion)です。
内蔵のメモリがそれなりに大きい（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が端末なので、シリアルケーブルで接続して端末を開くとこんな感じで動いているような気がします。
![mpython-sx.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/316355/09ab2c61-0d24-b545-9798-eb1a77cc61af.png)

#おまけ
バイナリのサイズを見ると、そのへんにたくさん転がっていそうなH8/3069（ROM512KByte/RAM16KByte）でも入りそうな気がしたので、やってみました。
ハードウエアの初期化とldscriptのメモリ割り当てを変えるだけです。
うちにもボードが何個か転がっているはずですが、ずっと使っていなくて発掘するのが面倒なのでqemuで動かしてみます。
![mpython-qemu.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/316355/7530cb9e-3f25-ea40-62bb-58a6638177c1.png)
REPLのところでCPUスタックの使用量を確認してみましたが、数百バイトくらいだったのでものすごくスタックを消費しなければ大丈夫そうです。
##余談
[公式ページ](https://micropython.org/)を見たら
>Yet it is compact enough to fit and run within just 256k of code space and 16k of RAM.

て書いてあったのがこの話のオチになってしまうという…

#成果物
https://github.com/ysat0/micropython