Amsterdam Compiler Kit を6800向けに改造する (6) 色々悩んでいる

BASICMASTER, 昔のパソコン

Amsterdam Compiler Kit を改造してMC6800用のコードを出力する試みの6回目。実はスタックマシンの動作が思っていたのと違っていてテストが動きません。

関数引数が1バイトのときのendian問題のときにもっと調べておけばよかった。


スタック上でのデータの持ち方

ACKのEMインタプリタはワードマシンである。Littele Endian。なんだけど、word幅のときに、どちらが上位バイトであるかは実装依存であり、コンパイラはそれに依存するコードを出さない。

ただし、関数引数が1バイトであるとき、引数は関数呼び出し時にword拡張した上でpushされる。関数本体ではLittele Endianを前提したコードが生成される。
そのため、関数開始時に1バイト引数の場所を修正するコードが出力される(これはLittle Endianマシンでは不要なので、オプティマイザによって削除される)。
(詳細は Amsterdam Compiler Kit を6800向けに改造する (4) 関数引数がcharのとき | ず@沖縄

さて、問題は関数引数だけだと思っていたら別の場所でも問題があった。4バイト変数とビット配列(inn)である。

4バイト変数問題

4バイト変数の場合、数値 0x12345678 はLittle Endian では 78 56 34 12 の順で格納される。Big Endian では 12 34 56 78 である。

しかし、ackではBig endianであっても、word としての順序はLittle Endianだと想定していたようだ(現在もそうなのかはわからない)。

なので、Big Endian マシンでは 56 78 12 34 の順に入っていることになっている。

しかしながら、これは実際のBig Endianマシン(MC68000)などとは異なるので、MC68000のコードジェネレーターはこれを補正するコードを出している。

私は6800のコード生成部を書くときに、まさかこんな仕様だとは思わなくて素直にBig Endianで実装してしまった。

齟齬は cii命令のテストで発覚した。下記のコードは2byteの0x0001を4バイトに拡張して0x00000001になるかを確認する。

4バイト拡張後の0x00000001を表現するために2バイトの0000、0001をスタックに積んでいる (上から 00 01 00 00 の順になる)。

oneshort
onebyte
rom 1
(中略)
loe oneshort
loc 2
loc 4
cii
loc 0
loc 1
cmu 4

ただし、Cコンパイラは4バイトの値はlocではなくldc命令で生成するようなので、C言語で使っている場合は問題は起こらない。

困ったのでテストの方を変更して loc 0 loc 1 の代わりに ldc 1 にしてパスするようにした。他に矛盾がなければこれで済ませようと思ったのである。

innの問題

EMインタプリタはPascalの集合型(set)を表すために inn命令を使う。

当然ながら、これもLittle Endianになっていて、スタックの底の方がbit0になっている。16bit単位でスタックの浅い方向に移動する。

MC6800用は、素直にスタックの浅い方がbit0になっていて、テストに失敗する。

さてどうしたものか。こちらはテスト修正でなんとかなるのかどうかよくわからない。Pascalを無視すれば良さそうな気もするが…

悩みながら続く