2021年5月9日日曜日

6809ボードマイコンにTL/1コンパイラを移植する


 今更ですが自作の6809SBCに、いにしえの6800用TL/1コンパイラを移植しました

TL/1コンパイラは1980年に大西博さんが制作された6800用のコンパイラで、その特徴は変数のサイズが1バイト(8ビット!)であることで、サイズも4kB余りとコンパクトなワンパスコンパイラです。大西さんがその前に制作されたGAME言語と同様、ソースが公開されていたので様々なパソコンに移植されました。私もFM-7に移植されたTL1-FM版を入力して使用していましたが、FM77に移行してからは使用することが少なくなりました。

いつかは自分なりの言語を作りたいと思っていて、あれこれ考えているのですが(考えているだけで全然進んでいない...)、1バイト変数なら比較的簡単に作れるのではないかと思い、まず6800用のTL/1を6809に移植することでコンパイラ作成に関する具体的な知識を得ようと思って始めましたが、何と一ヶ月近くもかかってしまいました。

多少なりともどなたかの参考になればと思い、ここに顛末を記しておきます。


移植の手順ですが次のように行いました。

(1)ソースプログラムの6800の命令コードを6809の命令コードに置き換える。

多くの命令は単純に置き換えることができますが、スタックの使い方が6800と6809とでは異なるので注意が必要です。特に、スタックを演算等に使用している部分は新たに書き換える必要があります。また、CPX命令($8C, $9C)を演算ではなく次命令のスキップに使用しているケースもあります。

(2)コンパイラの生成コードを6800用から6809用に置き換える。

6800と6809とではバイナリレベルでの互換性はないと言われているのですが、同じ命令コードのものが結構多くあります。異なっているものでも、LDX($DE→$9E)のようにすぐわかるものは良いのですが、同じような機能であるにもかかわらず、一部異なっているという命令があるので厄介です。(下に記述)


移植した6809ボードです。これは2018年10月15日のブログ「6809/6802両用基板が完成しました」で紹介したボードで、6809と6802をスイッチで切り替えることができます。切り替えた際、メモリはクリアされないので一方のCPUで作成したデータを他方のCPUで利用することができます。また、ACIAを2個搭載しており、一方はコンソール用で他方はデータ入出力用で、どちらも38400Baudで動作しています。



移植した6809/6802 DualBoard


具体的には、次のような手順で進めました。

準備として、オリジナルのTL/1ではGAMEで作成したソースファイルが$3000からにストアされているものとしてコンパイルしますが、毎回GAMEを起動するのは面倒ですし、行番号を付けるのも煩わしいので、Windows上のエディタでソースを作り、それをGAME形式に変換したうえでmot形式に変換するソフトCvtTxtTl1Src.exeを作成しました。機能としては、行番号の付加、その行番号のバイナリ変換、行末コードの$00への変換、ファイル末への$FFの付加、そしてmot形式への変換です。

下図のように、ファイルをドラッグ&ドロップするだけで変換結果が得られます。



CvtTxtTl1Src




作業手順


(1)自作6809SBCに搭載しているモニタのLコマンドでmot形式のソースを$3000からに読み込む。

(2)mot形式に変換した試作コンパイラを$1000からに読み込む。

(3)モニタのGコマンドで$1000から実行し、オブジェクトを生成する。

(4)生成途中でエラーが出たら、コンパイラのソースをチェックして関係ありそうな箇所を修正する。修正後(2)から繰り返す。

(5)無事にオブジェクトが生成されたら、Gコマンドで$2000から実行してみる。エラーが出たり、結果がおかしかったりしたらソースを修正して(2)から繰り返す。

(6)意図した通りの実行結果が得られたら完成。


このような手順で、変数への代入、制御構造の確認、関数や手続きのデータの受け渡しなどを順に確認していきましたが、最後まで手間取ったのは関数や手続きで2個以上のローカル変数があると動作がおかしくなるというバグでした。

使用した6809SBCは6802と6809のDualボードですので、正常に動作することが分かっている6800TL/1でオブジェクトを作成し、それと6809TL/1で作成したものとを比較しながらチェックを繰り返しましたが、例えばオリジナルのTL/1の記事中の8-QUEENのオブジェクトなどは6802と6809とで全く同等のものが作成されるようになったにもかかわらず、6802では正常に動作するのに対して6809ではハングアップしてしまいます。もちろん、ランタイムルーチンが正常に動作していることは確認してあります。

こんな状態が1~2週間ほど続き、いい加減倦んできて諦めようかと思ったりもしましたが、私のSBCには自作のモニタの他に6802にはMIKBUG2、6809にはASSIST09を搭載してありますので、TL/1の入出力をASSIST09に合うように書き換えてASSIST09に移行し、そのトレース命令を用いて、1命令実行するごとにワークエリアとオブジェクトのエリアをダンプしてチェックするという面倒な作業を繰り返すことで、ようやくバグの原因をつかむことができました。

バグの原因は、STA n,Xというインデックス命令でした。6800ではnは8ビット範囲であるのに対して、6809ではnが0~7Fの範囲では5ビット命令となるのです。TL/1ではSTA n,Xのnを動作中に書き換えるというコードを多用していますが、例えばnを0から1ずつ増やしていくと15までは正値ですが、その次は負値の-16になってしまうのです。

6809ではアキュムレータオフセット命令がありますので、

  6800での命令        →  6809での命令

  (2命令で計5バイト)       (1命令で2バイト)

  STB xxxx  (xxxxはnのアドレス)   STA B,X

  STA n,X

という計5バイトの命令を2バイト命令に置き換えることができ、これでバグを解消できました。

まだ全ての組み込み関数などのチェックを終えているわけではありませんが、現在の所は動作におかしな点は見つかっていません。

それにしても、オブジェクトコードを動作中に書き換えることでコンパクトなコードを生成できているわけですが、一方、この点でROM化できないという批判的評価があったことを思い返すと、6809特有の命令に置き換えることで図らずもこの点が解消されたのは嬉しいことでもあります。さらに、$2000からのランタイムルーチンを含めて、生成コードをポジション独立にすることができればOS-9上で動作させることも夢ではなくなるかもしれません。


この移植作業を通して、制御構造などに対するオブジェクトの生成法の理解が進みました。

しかし、ASSIST09のトレース命令はとても強力なツールですね。できれば私のモニタにも実装したいものです。

最終目標は、6809SBCにOS-9Level1をインプリメントして、その上でTL/1などの言語を走らせることですが、ほんの少しですが先に進めたような気がします。

確か、大西博さんは大学の先生で文系の方だったと思いますが、GAMEやTL/1の発想というか独創性には本当に感心します。


いつも参照している下記の2冊

・MC6809-MC6809E マイクロプロセッサ プログラミング マニュアル(Motorola)

・6809アセンブリプログラミング(末永朝雄著、サイエンス社)

に加えて、この本が大変参考になりました。特にオブジェクトの生成法の解説がTL/1の理解に役立ちました。

・Z80CPU対応 新言語オリジナルコンパイラ作成の技法(大貫広幸著、MIA社)



0 件のコメント:

コメントを投稿