ラベル GAME68コンパイラ の投稿を表示しています。 すべての投稿を表示
ラベル GAME68コンパイラ の投稿を表示しています。 すべての投稿を表示

2024年3月24日日曜日

6800用GAMEインタプリタとコンパイラの6809への移植がようやく完成

 6800用のGAMEインタプリタとコンパイラの6809への移植がようやく完成しました

時代錯誤ではありますが、折を見ながら昔のマイコン時代に使用していたGAME言語を6809に移植する試みを続けていまして、今までに2回報告しています。

・2021年5月19日のブログ「6800用のGAMEインタプリタとコンパイラを6809に移植」https://www.blogger.com/blog/post/edit/1662007451717538019/285975797531168690

・2019年5月8日のブログ「6802基板でGAME68コンパイラを走らせる」https://www.blogger.com/blog/post/edit/1662007451717538019/2314144451913456377

できる限りオリジナルから改変せずに自作の6802/6809両用カードにインタプリタとコンパイラを移植することを目指したので、既に他の方々が実践されているような高速化・高機能化とは無縁ですが、移植過程の経験とソースを得られることが目標でした。

上記2回の報告では、とりあえず動作したというレベルでしたので、何とか完成させたいと折を見ながら取り組んできましたが、ようやく完成と言ってもよいものができあがりましたので紹介するとともに作成したファイルを公開します。


作成に使用した自作マイコンですが、以前のブログで紹介したものと同じ6802/6809両用カードを使用しています。(見出しに画像を表示させるために以前と同じ画像を張り付けてあります。)


6802/6809両用カード


1.GAME3インタプリタ

まずインタプリタですが、ASCII誌に連載されたオリジナルのGAME3に作者の大西氏が行編集機能を追加されたものを使用しています。

オリジナルのソースに追加する必要があるのはI/O関係の1文字入力、1文字出力、ブレーク判定ルーチンのみで、変更点はRUB,DELコード、RAM末アドレスなどですが、これらについてはソースプログラムを添付しますのでそれを見ていただければ分かると思います。


2.GAME3コンパイラ

前回のブログで紹介しましたが、ASCII誌に掲載された松島義明さんのH68/TR・TV用の「GAME68コンパイラ」を移植しました。(松島さんには申し訳ないのですが、名称をGAME3コンパイラに変更させていただきました。)

これはGAME3自身で記述されており、6809に移植しやすいということで使用しました。

基本的にはオリジナルのままで動作しますが、インタプリタ中のルーチンを使用していますので、上記のインタプリタとセットで使用します。

変更点は220行のモニタへのアドレス$F0B1と、オリジナルのままではコンパイル結果のバイナリを実行後に暴走しますので、80行の末尾にA:0)=$39を追加した2点のみです。


3.GAME9インタプリタ

6800用GAME3インタプリタを元にして、6809用GAME9インタプリタを作成するわけですが、以前のブログで報告しましたように、基本的にはソースプログラムが公開されていますのでその6800の命令を6809の命令に置き換えるだけです。

置き換えに当たってはスタックポインタをインデックスポインタとして使用している箇所や比較命令CPXを1バイトスキップに利用している箇所に注意するだけで良いはずなのですが、何と終了判定にプログラムコード中の$00を利用している箇所があり、6800と6809では命令の長さが異なるために判定位置がずれてしまうことに気づかず、最後まで悩まされました。

以上に注意しながらインタプリタのソースを書き換えた結果、正常に動作させることができました。出来上がったものは基本的にただ6800の命令を6809の命令に置き換えただけですので、他の方々が移植されたものとは速度や機能の面で劣りますが、とにかく正常に動作するソースが作成できたということで良しとします。


4.GAME9コンパイラ

続いて「GAME68コンパイラ」の移植に取り組みましたが、これも以前のブログで報告しましたが、まずランタイムルーチンのバイナリを逆アセンブルしてソースを起こし、それを6809の命令に書き換えました。

続いてコンパイラの移植ですが、まず、GAME自身で記述されているコンパイラのリスト中の、インタプリタ中のルーチンを呼んでいるアドレスを書き換え、次に、6800の命令コードを発行している箇所を見つけて6809の命令に置き換えました。 同じバイト数で置き換えられるものは単純に置き換えられるのですが、バイト数が変わる場合はそれに応じて、その周辺を書き換える必要がありました。

最後に、多少なりとも6809らしいコードを出力して欲しいということで、AccAとAccBの両方を使用している箇所をAccDに置き換える等を試みましたが、全てを置き換えることはできませんでした。

結果として作成したコンパイラですが、いくつかのサンプルプログラムを実行して正常にコンパイルできていることを確認し、最後にコンパイラ自身をコンパイルしてみました。

その結果、得られたバイナリが正常に動作しましたし、さらにそのバイナリでもう一度コンパイルしてみたところ、そのバイナリも正常に動作しました。

ただし、GAME9コンパイラ自身をコンパイルする過程では、最終行までコンパイルした後にハングアップしてしまいましたが、調べてみるとインタプリタに戻るアドレスが書き込まれていませんでしたので、手作業で該当の2個所に$0103を書き込むことで正常に動作するオブジェクトが得られました。

(この現象はGAME3でも同様でしたので、元のGAME68コンパイラに原因があるのではないかと思っていますが、コンパイルせずにそのまま使用した場合には正常に動作するので、原因については良く分かりません。)


以上により得られたファイルは次のようです。

[1]GAME3

・GAME3EX インタプリタ

・GAME3C  コンパイラ(GAME言語で書かれたもの)

・GAME3CC コンパイラオブジェクト(GAME3Cを自身でコンパイルしたもの)

・RELSUB3  コンパイラ用ランタイムルーチン($2000-212Aだが移動可能)

コンパイル結果のオブジェクトの実行開始アドレスはランタイムルーチンの先頭アドレス+$012Bです。


[2]GAME9

・GAME9EX インタプリタ

・GAME9C  コンパイラ(GAME言語で書かれたもの)

・GAME9CC コンパイラオブジェクト(GAME9Cを自身でコンパイルしたもの)

・RELSUB9 コンパイラ用ランタイムルーチン($2000-2106だが移動可能)

ランタイムルーチンがGAME3用よりも小さいのですが、操作を統一するためにコンパイル結果の実行開始アドレスをGAME3と同じランタイムルーチンの先頭アドレス+$012Bに揃えてあります。


メモリマップです。
もちろんソースプログラムの位置は変更可能です。
コンパイラの方は、ランタイムやコンパイル結果の配置も変更可能です。



メモリマップ

コンパイラの動作速度を知るために、参考までに、インタプリタで300行弱のコンパイラプログラムを実行(コンパイル)した場合と、コンパイル済みのオブジェクトでコンパイルした時の時間を測ってみました。

(1)GAME3

 ・インタプリタでは、パス1終了までに4分30秒、パス2終了までに10分30秒

 ・コンパイラでは、パス1終了までに約11秒、パス2終了までに約29秒

(2)GAME9

 ・インタプリタでは、パス1終了までに4分11秒、パス2終了までに9分27秒

 ・コンパイラでは、パス1終了までに約11秒、パス2終了までに約25秒

という結果でしたので、インタプリタとコンパイラの実行速度比はGAME3でおよそ22倍、GAME9でおよそ23倍となりました。

作成したGAME9インタプリタとコンパイラをGAME3のそれと一緒にOneDriveに上げておきます。(GAME3のコンパイラについては、以前のブログで公開する際に作者の了解を得てあります。)


2021年5月19日水曜日

6800用のGAMEインタプリタとコンパイラを6809に移植

 6800用のGAMEインタプリタだけでなく、コンパイラも移植してみました


動機

発注してあるプリント基板が未だに届かないので最近はソフトばかりいじっていますが、前回は6800用のTL1コンパイラを6809に移植することができましたので、その勢いで、今度はGAMEインタプリタとコンパイラの移植に挑戦してみました。

GAMEインタプリタの6809への移植は、既に1981年に藤原誠さんによる「GAME09インタプリタ」や、1984年の萩平哲さんによる「GAME-FMインタプリタ・コンパイラ」があり、いずれも実行速度や機能面で非常に優れたもので、私もインストールして使わせてもらっていました。しかし、いずれもソースは公開されておらずバイナリコードだけです。

移植するコンパイラは

今回移植しようと考えたものは、2019年5月8日のブログ「6802基板でGAME68コンパイラを走らせる」で紹介した「GAME68コンパイラ」で、松島義明さんがGAME自身で記述されたものです。

GAME自身で記述されているということは、コンパイラとしての論理構造は6800でも6809でも変わらず、コード生成の部分だけが異なっているということになります。

そして、生成されるコードは6800のバイナリであるわけですが、前回のTL1でも述べましたように、6809と6800のバイナリにはそれほど大きな違いはないので、異なっているものだけを書き換えるだけで済むのではないかと考えました。(安直ですね。)


コンパイラのランタイムルーチンを見ると


まず最初にランタイムルーチンを調べてみました。

GAMEインタプリタ内のルーチンを利用していることもあって、わずか300バイト足らずの小さなものですが、逆アセンブルしてみたところ、6809と異なっている命令はNOPとLDXのみでしたので、簡単に書き換えることができました。

しかし、インタプリタ内のルーチンを使用しているということは、実行時には6809版のインタプリタが必要ということになりますので、コンパイラより先にインタプリタの移植が必要だということになります...


インタプリタの移植が必要だった

ということで、まずインタプリタの移植に取り組むことになりました。

6800用インタプリタもTL1と同様にアセンブラソースが公開されていますので、TL1の時と同じようにスタック命令に注意しながら書き換えることで、それ程苦労せずに動作させることができました。(私の場合はハードもソフトも速さにはそれ程こだわらず、正常に動作すれば良しというスタンスですので、最適化などはほとんど行っていません。)


インタプリタの移植が済んだので

インタプリタの移植が済んで、コンパイラのランタイムルーチンが呼んでいるルーチンのアドレスが確定しましたので、GAME68自身で記述されているコンパイラの関係するアドレスを書き換えたものを作り、簡単なプログラムで生成されたコードを調べてみました。

すると、Xレジスタ関連の命令とPSH,PUL命令を書き換えただけで動くプログラムもあるではありませんか。

この結果に気を良くして、コンパイラのソースを読んでみた限りでは、コンパイラで生成される命令の中で、6800と6809とでコードが異なるものとしてはLDX, STX, INX, TAB, TBA, PSHA, PSHB, PULA, PULBの9種がありましたが、これらはバイト数が異なるものの、置き換えにはそれ程困難はなさそうです。しかし、それらに加えて一部にLDS, STSというスタック関係の命令も使われているようですので、これらについては注意が必要です。

[5月23日追記]訂正:LDS, STS命令は使われていませんでした。


GAME09コンパイラ(らしきもの)を作ってみた

とりあえず、スタック関係の命令はそのままにしておいて(GAMEのどの命令で使われるのかまだ分からないので...)その他の命令だけを置き換えたものを作成してみました。


動作環境の詳細

使用した6809ボードは前回と同じ6809/6802DualCPUボードです。


6809/6802 Dual CPUボード

メモリマップです。


メモリマップ

ソースプログラムの格納領域は、TL1コンパイラの場合と合わせて $3000 からにしています。

オリジナルのランタイムルーチンは $2100~$22BA ですが、その先頭に生成オブジェクトへのジャンプ命令(3バイト)を追加し、JMP $2100で実行できるようにしています。

それぞれのプログラムの読み込みですが、あらかじめMOT形式に変換しておいて、自作モニタの LコマンドやASSIST09の LOADコマンドでロードしています。

そのMOT形式への変換プログラムですが、前回のTL1コンパイラのソースの場合はエディタで行番号を付けずに作成したものを変換しましたが、GAMEのソースの場合は行番号が付いていますので、それをバイナリに変換して新たに格納アドレスを付加するように機能拡張しました。また、付加する行番号や格納するアドレスを指定できるようにもしました。


CvtTxtTl1Src.exe


コンパイルの実行手順

次のような手順でコンパイルを実行します。

1.モニタでGAME9インタプリタをロードする

       L GAME9EX

        拡張機能付きのGAME9が$0100からにロードされる

2.インタプリタを起動する(コールドスタートで)

        G 100

3.モニタに移動する

        >=$F800

4.ソースプログラムをロードする

        L (source file)

        ソースプログラムが $3000 からにロードされる

5.GAME9コンパイラとランタイムルーチンをロードする

        L GAME9CS

        ランタイムルーチンが$2100からに、コンパイラが $4000 からにロードされる

6.GAME9インタプリタに戻る(ホットスタートで)

        G 103

7.コンパイラをアクティブにする

        =$4000 (先頭アドレスのセット)

        ==          (末尾アドレスをサーチ)

8.コンパイルを実行する

        #=1


実行例

実行した例を示します。オリジナルではワークエリアなどいくつかの問い合わせに答えてからコンパイルが始まりますが、ソースプログラムの格納エリアなどを決め打ちしましたので、#=1ですぐにコンパイルが始まります。

実行例

コンパイルの終了後、GAME上で >=$2100 とすると生成されたオブジェクトが実行されます。


終わりに

まだ全ての6800命令を6809命令に書き換えてはいないのですが、いくつかのプログラムをコンパイルして正常に動作することを確認しました。

以前「GAME68コンパイラ」のブログを書いた際に、コンパイラの作者の松島義明さんから掲載の許可をいただいていますので、今回の6809へ書き換えたものも公開しても良いと思います。

今の時代にGAMEやTL1を使おうという奇特な方がおられるとは思えませんが、もしご希望があるようでしたら、書き換えられずにそのままになっているスタック関係の命令の書き換えが終了しましたら公開する予定です。変換プログラム CvtTxtTl1Src.exe についても同様です。

以上、私の単なる思い付きでやってみたことで、実用性はほとんどありませんが、巷間、6800と6809とはバイナリレベルの互換性が無いので云々という評価がありますが、全く異なっているわけではないので、違っている部分にだけ注意を払えばこんなこともできるというサンプルになれば幸いです。(と言っても、今どき、6800はおろか6809のプログラムですら化石時代の遺物みたいなものでしょうが...)


2019年5月8日水曜日

6802基板でGAME68コンパイラを走らせる

自作6802基板でGAME68コンパイラが動作しました


前回のブログで8080SBCでGAME80インタプリタを走らせることができたと報告しましたが、それに関連して、skyriverさんがCP/M上でGAME80コンパイラを動作させたとの連絡をいただきました。そこで、私もskyriverさんのブログを参考にしてGAME80コンパイラを走らせることができました。
中島聡さんが作られたこのGAME80コンパイラは、TK-80BSの他にもいろいろなマシンに移植されましたが、残念ながら68系にはなかなか移植されませんでした。
そんな中、ついにASCII誌1981年5月号で松島義明さんがH68用のGAME68コンパイラを発表されました。
私はGAME3を使用していたこともあり、このコンパイラを動かしたかったのですが、残念ながら当時の手作りマイコンでは動作させることはできませんでした。

しかし、現在の自作の6802基板なら可能ではないかと思い、移植してみることにしました。
現在の自作6802基板では既にGAME3が動作していますので、保存してあったASCII誌から手入力してみました。ASCII誌がない方も、作成者がブログで公開されていますので心配はありません。(後述します)

[1]必要なファイルを作成する


入力したファイルは、
・コンパイラのソース(GAME3のプログラム形式 $3E00~)
・リロケータブルサブルーチンパッケージ(バイナリ形式 $3C80~$3DAA)
・サブルーチンパッケージリロケータ(GAME3のプログラム形式 $3C00~)
の3つです。
私はこの3つを1つにまとめたファイルを作り、GAME3インタプリタと共にあらかじめ読み込ませる形で使用しています。ただし、GAME3のプログラムはメモリ中では行番号が2バイトバイナリに、行末の改行コードは$00に変換され、ファイル末には$FFが追加された形式で格納されますので、プログラムリストを予め変換しておく必要があります。
手順を下に示します。

コンパイラの作成手順

変換作業はWindows上で、Chglno.exeとCvtMotHex.exeを用いて行います。
例としてGAME3インタプリタの開発者の大西さんが用意されたサンプルであるACURVEというプログラムの処理を下に示します。


処理前のソースプログラム


Chglno.exeで変換します



処理後のソースプログラム


アドレスを指定してHEXファイルに変換して出来上がり


[2]コンパイルの手順


(1)GAME3インタプリタとGAME68CAコンパイラをメモリに読み込みます。
(2)GAME3インタプリタを起動します。
(3)ソースを読み込むアドレスを指定します。
    例 =$1500
(4)コンパイルしたいプログラムを入力します。
    手入力しても良いですが、コンパイラソースと同様に処理してあればファイル
    から読み込めます
    例 GAME3の最初の例である ACURVE
(5)コンパイラを起動します。
   最初に読み込んであるので、そのアドレス$3E00を指定するだけです。
    =$3E00 とアドレス指定して #=1 で起動します。
(6)以下はASCII誌の説明通りに進めます。
   GAME:に対しては $1500
   SUB:に対しては $2100
   STAT:に対しては$222B
   WORK:に対しては$1900
   STAC:に対しては$2080
   と入力するとコンパイルが始まります。
(7)サブルーチンを$2100からに移動します。
   =$3C00 とアドレス指定して #=1 で起動します。

[3]コンパイルしたマシン語を実行する


先頭の$2100 からがサブルーチンパッケージで、実行開始アドレスは $222B
   ですのでGAMEのダイレクトモードで >=$222B で実行できます。

ちょっと見苦しいですが、画面のテキストのコピーを下に示します。



+++OLOAD GAME3.CMD     FLEXに保存してあるファイルをメモリに
+++OLOAD GAME68CA.BIN   読み込んで
+++OLOAD ACURVE.BIN
+++

M6800 MONITOR Ver6.1     いったんモニタに戻って

>G 103             GAME3を起動(ソースが既にメモリ中にあるのでホットスタート)

*READY

:=$1500            コンパイルするプログラムのアドレスに

*READY            変更すると

:0               確かにソースが読み込まれている

   70***************************
   80*    A CURVE
   90***************************
  100 X=7 Y=0 Z=2
  110 Y=Y+Z X=X+Y
  120 ;=+Y=6 Z=-Z
  130 J=1,32
  140 $=(J=X*"*")+(J<>X*".")
  150 @=J+1 / #=110
  160**************************

*READY

:=$3E00            コンパイラのアドレスに変更して

*READY

:#=1              コンパイラを起動する

GAME:$1500          (入力)

48 BYT (10LINE)

SUB :$2100          (入力)

 END 222A

STAT:$222B          (入力)

WORK:$1900         (入力)

STAC:$2080          (入力) コンパイルが始まる

   70     222B     1500
   80     222B     151E
   90     222B     152D
  100     222B     154B
  110     223F     155A
  120     2257     1569
  130     2277     1578
  140     2287     1582
  150     22BC     159C
  160     22DC     15AD
   70     222B     1500
   80     222B     151E
   90     222B     152D
  100     222B     154B
  110     223F     155A
  120     2257     1569
2277
  130     2277     1578
  140     2287     1582
  150     22BC     159C
223F
  160     22DC     15AD
 SIZE: 177(222B-22DB)

END             正常に終了

*READY

:=$3C00           サブルーチン移動プログラムのアドレスに変更して

*READY

:#=1             実行 (資料ではここでアドレスを入力することに

                    なっているが、問い合わせてこない)

*READY            これでコンパイル&サブルーチン移動が完了

:>=$222B          できたマシン語を実行

........*.......................
............*...................
..................*.............
......................*.........
........................*.......
........................*.......
......................*.........
..................*.............
............*...................
........*.......................
......*.........................
......*.........................
........*.......................
............*...................

----------------------------------- 以上 -------------------------------------------

[4]終わりに


説明不足で良く分からないところがあったと思いますが、心配ありません。
何と、GAME68コンパイラを開発された方が、ブログで資料を公開されています。
詳しくはそちらを参照ください。
開発された方は、このコンパイラを仕事にも使われていたとのこと、スゴイです。

なお、開発された方が許可してくださいましたので、私が誌面から入力したコンパイラソース等のリストをOneDriveに公開いたします。入力ミスは多分ないと思いますので、どうぞご利用ください。また、使用したツールソフト(Chglno.exe, CvtMotHexBin.exe)も同梱しておきます。