So-net無料ブログ作成
English Version

3チップ構成Pic24CPMマイコン(その7)GAMEコンパイラ [Z80]

 ネットで久々にGAME言語ネタを見つけた^^ので平成最後のカキコはGAME言語ネタです。
 Old68funさんが6809 / 6800とFLEXのブログで書かれている「SBC8080でGAME80がようやく動作」の記事です。TK-80BS用のGAME80インタプリタをSBC8080上で動かされています。

 TK-80BSと言えば中島さんにより開発されたGAME80コンパイラが発表された環境であり、Jun's Homepageの「GAME80コンパイラ解説 (2003/08/05)」に解説とともにソースが掲載されています。

 久々にGAMEコンパイラを動かしてみたいものですねぇ^^

 最初にGAME80をCP/M-80に移植してみました。GAMEインタプリタ自体はコンソール入出力関連の処理をハード環境に合わせて変更すれば動作するのでCP/M-80用に先頭にコールドスタートへのジャンプ命令を追加し、末尾にコンソール関連の処理を追加しました。使用した環境はマイクロソフトのMACRO80/LINK80です。
 全体をリロケートしなかったのは上記のコンパイラを動かしてみたかったからです。

GAMEインタプリタのCP/M-80へのインプリメント
;******************************** ; GAME interpreter ; TK-80BS version on CP/M-80 ; 2019/05/01 ;******************************** 8600 PRGST EQU 8600H ; program start addres CBFF RAMEND EQU 0CBFFH ; for CP/M-80 64K 001B K_STOP EQU 01BH ; stop key 0020 K_PAUSE EQU ' ' ; pause key 8E00 SRCSTA EQU 08E00H ; sorce start addres 8DC4 STACK2 EQU 08DC4H ; second stack 8D42 Y8D42 EQU 08D42H 8D46 Y8D46 EQU 08D46H 8D4A Y8D4A EQU 08D4AH 8D4B Y8D4B EQU 08D4BH 8D4E Y8D4E EQU 08D4EH 8D50 Y8D50 EQU 08D50H 8D52 Y8D52 EQU 08D52H 8D58 Y8D58 EQU 08D58H 8D5A Y8D5A EQU 08D5AH 8D68 Y8D68 EQU 08D68H 8D6A Y8D6A EQU 08D6AH 8D70 Y8D70 EQU 08D70H 8D72 Y8D72 EQU 08D72H 8D74 Y8D74 EQU 08D74H 8D76 Y8D76 EQU 08D76H 8D77 Y8D77 EQU 08D77H 8D7E Y8D7E EQU 08D7EH 8D88 Y8D88 EQU 08D88H 8D8A Y8D8A EQU 08D8AH .Z80 0000' ASEG ORG 00100H 0100 C3 8600 JP START ORG PRGST 8600 C3 8606 START: JP A8606 ; cold start 8603 C3 8611 JP A8611 ; hot start ; 8606 21 8E00 A8606: LD HL,SRCSTA 8609 22 8D7E LD (Y8D7E),HL 860C 22 8D50 LD (Y8D50),HL 860F 36 FF LD (HL),0FFH 8611 21 CBFF A8611: LD HL,RAMEND 8614 22 8D58 LD (Y8D58),HL   ~~~ 途中省略 ~~~ 8C7B C2 8C4E JP NZ,A8C4E 8C7E 36 00 LD (HL),000H 8C80 21 8D8A LD HL,Y8D8A 8C83 3E 0D A8C83: LD A,00DH 8C85 CD 8C99 CALL PUTCH 8C88 3E 0A LD A,00AH 8C8A C3 8C99 JP PUTCH ; 8C8D 0D 0A 2A 52 T8C8D: DB 0DH,0AH,'*READY',00H 8C91 45 41 44 59 8C95 00 ;*** added by skyriver 2019/04/30 *** 8C96 CD 8CA7 GETCH: CALL CONIN 8C99 C3 8CB1 PUTCH: JP CONOUT 8C9C E5 KBHIT: PUSH HL 8C9D D5 PUSH DE 8C9E 1E 03 LD E,03H ; CONST 8CA0 CD 8CBE CALL GOBIOS 8CA3 0F RRCA ; if exist then set carry 8CA4 D1 POP DE 8CA5 E1 POP HL 8CA6 C9 RET 8CA7 E5 CONIN: PUSH HL 8CA8 D5 PUSH DE 8CA9 1E 06 LD E,06H ; CONIN 8CAB CD 8CBE CALL GOBIOS 8CAE D1 POP DE 8CAF E1 POP HL 8CB0 C9 RET 8CB1 E5 CONOUT: PUSH HL 8CB2 D5 PUSH DE 8CB3 F5 PUSH AF 8CB4 1E 09 LD E,09H ; CONOUT 8CB6 4F LD C,A 8CB7 CD 8CBE CALL GOBIOS 8CBA F1 POP AF 8CBB D1 POP DE 8CBC E1 POP HL 8CBD C9 RET 8CBE 2A 0001 GOBIOS: LD HL,(0001H) ;WBOOT addres 8CC1 16 00 LD D,0 8CC3 19 ADD HL,DE 8CC4 E9 JP (HL) END

★2019/04/30
 連続表示中にスペースでポーズできなかったので修正
 オリジナルは'!'キーで中断ですが、ESCで中断するように変更
★2019/05/01
 コール先やワークのアドレスをラベル名に変更


 GAME80インタプリタがCP/M-80上で動いたので上記のGAME80コンパイラの解説ブログページからコンパイラのソースを頂いて動かしてみます。
 ブログにも「リストは昔に記事を読んで打ち込んだもので、実行して確認していません。ミスがあるかもしれませんが、その場合はご容赦下さい。」と書かれているように実際に動かそうとすると数ヶ所修正が必要です(手元にエンサイクロペディアアスキーの該当ページのコピーがあったので突合チェックした)。
 オリジナルとの差分を以下にメモしておきます。

No.修正箇所
1 225 ?(5)=V .=5 ??=A .=5 ??=G /
2 3270 ;=H="+" #=3300
3 3410 ;=G:0)="=" G=G+1 !=4000 H=$FA #=3600
4 5620 A:0)=$CD A=A+3 A(-1)=A A:0)=$D5 A=A+1


 これで何十年かぶりにGAMEコンパイラのコンパイルぶりを見れる(私が当時動かしていたのはTRS-80用のGAME-Z80を自作マイコンに移植したものだったのでTK-80BSのGAMEは初体験)と思いきやコンパイルしたコードが全く動きません・・・
 コンパイラのソースを確認したところ、文字列出力部で$FA52をコールしているコードを生成しています。
 そこで1文字出力ルーチンを使ったループ処理のコードを生成するように変更し、機種依存性を無くしました。

オリジナル 2410 @=(G:I-1)=""") A(0)=A+I
2420 G=G+I A=A+I A:0)=$3E
2430 A:1)=I-2 A:2)=$32 A=A+5 A(-1)=$847A
2440 A:0)=$21 A=A+3 A(-1)=Q
2445 A:0)=$22 A=A+3 A(-1)=$847B
2450 A:0)=$CD A=A+3 A(-1)=$FA52
2460 #=700
変更後 2410 @=(G:I-1)=""") A(0)=A+I
2420 G=G+I A=A+I A:0)=$06
2430 A:1)=I-2 A:2)=$21 A=A+3
2432 A(0)=Q A(1)=$CD7E A(2)=$8C99
2433 A(3)=$0523 A=A+11 A:-3)=$C2 A(-1)=A-9
2460 #=700


 ソースを見ると生成するコードが何となく判ると思いますが、文字列生成処理のコンパイル結果を確認してみます。
 サンプルソースとしては単に"Hello"と出力するだけのものを使用しました。

文字列出力処理のコンパイル例
:0 10 "Hello" *READY :=$8E00 *READY :#=1 GAME PROGRAM FROM:$B000 START ADRRESS:$4000 WORK AREA FROM:$100 10 4000 B000 10 4000 B000 PROGRAM SIZE: 25(4000-4018) END *READY :>=0 b>


 0x4000以降にコンパイルされたコードが書かれているので、一旦GAMEを抜けてCP/Mのディバッガ(ZSID)を起動し、確認しました。
 ZSIDDはZSIDに小文字シンボル対応や1行ダンプ等のパッチをあてたものです。

生成されたコード
b>a:zsidd ZSID VERS 1.4 #l4000,4018 4000 JP 4008 4003 LD C,B 4004 LD H,L 4005 LD L,H 4006 LD L,H 4007 LD L,A 4008 LD B,05 400A LD HL,4003 400D LD A,(HL) 400E CALL 8C99 4011 INC HL 4012 DEC B 4013 JP NZ,400D 4016 JP 8603 4019 #d4000 4000: C3 08 40 48 65 6C 6C 6F 06 05 21 03 40 7E CD 99 ..@Hello..!.@~.. 4010: 8C 23 05 C2 0D 40 C3 03 86 00 00 00 00 00 00 00 .#...@.......... 4020: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 4030: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 4040: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 4050: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 4060: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 4070: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 4080: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 4090: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 40A0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ #


 想定通りのコードが生成されていますね。当然実行結果もokでした。
 当初の目的であるGAMEコンパイラをインタプリタ動作でコンパイラ自身をコンパイルし、コンパイルされたコンパイラで更にコンパイラをコンパイルすることも問題なくできました(^^)/

 GAME言語のインタプリタやコンパイラのソースを公開していいか判らないのでCP/M-80に移植したバイナリだけ置いておきます。
 冒頭で紹介したブログと本ブログを参照すれば、CP/M環境でGAMEコンパイラのセルフコンパイル(通常とは違う意味での「セルフ」)まで試せると思います。

  • GameOnCpm80_20190518_003.zip
    ★2019/05/18 Ver0.03
     コンパイル時の表示をGAME-Z80版のように見易くした
    ★2019/05/09 Ver0.02
     スペースキーでのポーズ及びESCでのブレーク時にエコーバックしないようにした
    ★2019/05/06 Ver0.01
     コンパイラを0200H~に包括した( >=$200 でコンパイラ起動)
     版数特定ができるようにVer付きオープニングメッセージを表示するようにした
    ★2019/05/04
     起動時にGAME本体を8600Hへ転送するようにして起動時間短縮
    ★2019/05/01
     コンソール関連処理を2バイト軽量化しました(機能的には変わらず)


★2019/04/30 追記
 twitterにポストした動画付きコメントを貼り付けておきます。


★2019/05/02 追記
 コメントに書いたように文字列出力処理部のコンパイルでインタプリタ内の'\0'で終端された文字列の出力処理である0x8785を呼び出すようにして生成コードを短縮し、更にキーチェックだけを行う長さゼロの文字列出力 "" に対応してみました。

 GAMEコンパイラの修正箇所は下記になります。ソース自体も短くなりました。

オリジナル 2300 A:0)=$C3 A=A+1 I=2
2400 Q=A+2 @ A:I)=G:I-1) I=I+1
2410 @=(G:I-1)=""") A(0)=A+I
2420 G=G+I A=A+I A:0)=$3E
2430 A:1)=I-2 A:2)=$32 A=A+5 A(-1)=$847A
2440 A:0)=$21 A=A+3 A(-1)=Q
2445 A:0)=$22 A=A+3 A(-1)=$847B
2450 A:0)=$CD A=A+3 A(-1)=$FA52
2460 #=700
変更後 2300 A:0)=$C3 Q=A+1 A=A+2
2400 @ G=G+1 A=A+1 A:0)=G:0) @=(G:0)=""")
2410 G=G+1 A(0)=$2100 A(1)=Q+2 Q(0)=A+1
2420 A=A+7 A:-3)=$CD A(-1)=$8785
2460 #=700


 それではコンパイル結果を確認してみます。

コンパイル結果確認
*READY :=$B000 *READY :&=0 *READY :10 "Hello" :20 "" :0 10 "Hello" 20 "" *READY :=$8E00 *READY :#=1 GAME PROGRAM FROM:$B000 START ADRRESS:$4000 WORK AREA FROM:$100 10 4000 B000 20 400F B00B 10 4000 B000 20 400F B00B PROGRAM SIZE: 28(4000-401B) END *READY :>=$4000 Hello *READY :>=0 b>a:zsidd ZSID VERS 1.4 #l4000,401b 4000 JP 4009 4003 LD C,B 4004 LD H,L 4005 LD L,H 4006 LD L,H 4007 LD L,A 4008 NOP 4009 LD HL,4003 400C CALL 8785 400F JP 4013 4012 NOP 4013 LD HL,4012 4016 CALL 8785 4019 JP 8603 401C #d4000,401f 4000: C3 09 40 48 65 6C 6C 6F 00 21 03 40 CD 85 87 C3 ..@Hello.!.@.... 4010: 13 40 00 21 12 40 CD 85 87 C3 03 86 00 00 00 00 .@.!.@.......... #g0 b>


 想定通りですね^^
 GAMEコンパイラはコンパイラ自身をコンパイルし、拡張していけるのでマイコン環境でC言語等の開発環境が無かった時代にブートストラップ方式で言語仕様を拡張することでいくつかのコンパイラが作られました。独自言語が色々出てきて楽しい時代でしたね。


★2019/05/03 追記
 インタープリタ ⇒ インタプリタ に変更


★2019/05/03 追記
 CP/MでGAME言語が動くようになったので以前、「PIC24FJ64GAでGAME言語(その5)」で記載した迷路生成/探索のプログラムを動かしてみました。

GAME80ではPIC24FJ版GAMEとの相違点として
  • &(AND)演算子が無い
  • 配列のインデックス部で計算ができない配列が参照できない※1
  • 乱数 'N の範囲が0~N-1ではなく、1~Nである
  • タイマ管理変数の '¥' が無い

等がありましたが容易に移植できました。
★2019/05/03 追記 {
※1 インデックス部で計算はできるようです。下記の事象が発生しました。
W=B:P+D(Z)) ⇒ NG
C=D(Z) W=B:P+C) ⇒ OK
★2019/05/09 追記 {配列値評価時に8D70HにHLレジスタを保存しているため}
}
 ソースを以下に貼りました。TeraTermのWindowサイズは80カラム×32行で動かしてください(と言ってもTeraTerm接続で動くCP/M-80環境を持っている人は希少だとは思いますが)。

Maze for GAME80
1' Maze for GAME80 2019/05/03 by skyriver 2 S=78 T=30 #=100 8' move cursor 9 Y=P/S X=%(0) 10 $=$1B "[" ?=Y+1 ";" ?=X+1 "H" ] 18' set wall 19 Y=P/S X=%(0) 20 B:Y*S+X)=8 ] 29' wait 30 C=1,100 "" @=C+1 ] 100 D=&+1 B=D+8 '=157 102 D(0)=1 D(1)=S D(2)=-1 D(3)=-S U=S*T-1 110 @ 119' create maze 120 I=S*T @ I=I-1 B:I)=0 @=(I=0) 130 Y=0,T 140 X=0 !=20 150 @=Y+1 160 X=0,S 170 Y=0 !=20 Y=T !=20 180 @=X+1 190 G=2,T-2 200 F=2,S-2 210 X=F Y=G !=20 P=S*G+F 220 @ R=P+D('(4-(G>2))-1) @=(B:R)=0) 230 P=R !=19 240 @=F+2 250 @=G+2 259' display maze 260 $=$1B "[2J" X=0 Y=0 !=10 $=$1B "[36m" 270 Y=0,T 280 X=0,S 290 Z=" " ;=B:Y*S+X) Z="#" 300 $=Z 310 @=X+1 320 / 330 @=Y+1 340 $=$1B "[m" 350 X=S-1 Y=T-1 !=10 $="@" 360 !=30 369' explore 370 P=S+1 Z=0 380 @ 390 !=9 "+" $=8 Z=%((Z+2)/4) 400 @ "" 410 Z=%((Z+1)/4) R=P+D(Z) 420 @=(B:R)<8) 430 P=R B:P)=B:P)+1 440 !=30 450 @=(P=U) 459' best route 460 $=$1B "[43m" P=S+1 470 @ 480 !=9 "+" $=8 490 N=0 E=8 500 Z=0,3 510 C=P+D(Z) W=B:C) 520 ;=(W>0)*(W<E) E=W N=Z 530 @=Z+1 540 B:P)=7 P=P+D(N) 550 !=30 560 @=(P=U) 570 $=$1B "[m" 580 @=(0)


 参考にtwitterにポストした動画付きコメントを貼ります。


★2019/05/10 追記
 GAME80のソースのリナンバプログラムを作ったので貼っておきます。
 GAME68等でも動作すると思います。

renumber for GAME80
1' renumber for GAME Ver0.03 2019/05/11 by skyriver 2 "src address " S=? 3 "dst address " D=? 4 "line start " B=? 5 "line step " E=? 6 Z=&+1 TBL=Z+6 7 P=S IDX=0 8 @ 9 TBL(IDX)=P:0)*256+P:1) IDX=IDX+1 ;=%(IDX/10)=0 "*" 10 P=P+2 @ P=P+1 @=(P:-1)=0) 11 @=(P:0)>=$F0) 12 P=S IDX=0 13 @ 14 NEW=E*IDX+B 15 D:0)=NEW/256 D:1)=NEW D=D+2 P=P+2 16 / ?(5)=TBL(IDX) " :" ?(5)=NEW 17 ;=P:0)<>" " @ D:0)=P:0) D=D+1 P=P+1 @=(P:0)=0) 18 @ 19 ;=(P:0)=""")*(P:1)=""")*(P:2)=""") D:0)=""" D=D+1 P=P+1 20 ;=(P:0)=""") @ D:0)=P:0) D=D+1 P=P+1 @=(P:0)=""") 21 ;=(P:0)="#")+(P:0)="!") !=30 22 D:0)=P:0) 23 D=D+1 P=P+1 24 @=(P:-1)=0) 25 IDX=IDX+1 26 @=(P:0)>=$F0) 27 D:0)=P:0) 28 #=-1 29' goto,gosub 30 ;=(P:1)<>"=")+(P:2)="-") ] 31 D:0)=P:0) D:1)="=" D=D+2 P=P+2 32 LINE=0 @ LINE=LINE*10+(P:0)-"0") P=P+1 @=((P:0)<"0")+(P:0)>"9")) 33 " " $=D:-2) "=" ?=LINE " -> " 34 F=-1 @ F=F+1 @=(TBL(F)>=LINE) 35 LINE=E*F+B X=Z-1 ?=LINE 36 @ X=X+1 LINE=LINE/10 X:0)=%(0)+"0" @=(LINE=0) 37 @ D:0)=X:0) D=D+1 X=X-1 @=(X<Z) 38 ]

★2019/05/11 追記
 Ver 0.03 """処理部簡略化
 Ver 0.02 行短縮しました

[TOP] [ 前へ ] 連載記事 [ 次へ ]
nice!(2)  コメント(9) 
共通テーマ:趣味・カルチャー

nice! 2

コメント 9

skyriver

CP/M版GAMEを修正しました。
・連続表示中にポーズできなかった問題を修正(スペースキーでポーズ)
・中断キーを’!’からESCに変更
by skyriver (2019-05-01 00:30) 

skyriver

 コンパイラが生成するコードで文字列出力処理について1文字出力処理を使ったループ処理を生成するようにしましたがインタープリタ内の 0x8785 が'\0'で終端された文字列出力処理部でポーズや中断キーチェック機能も付いているので、ここをコールするようなコードを生成した方がいいですね。コードが短くなるし、ポーズ等のチェックも入るようになる。

8785 AF XRA A
8786 47 MOV B,A
8787 7E MOV A,M
8788 23 INX H
8789 B8 CMP B
878A CA 8793 JZ 8793H
878D CD 8C99 CALL PUTCH ;8C99H
8790 C3 8787 JMP 8787H
8793 CD 8C9C CALL KBHIT ;8C9CH
8796 D0 RNC
8797 CD 8C96 CALL GETCH ;8C96H
879A FE 1B CPI K_STOP
879C CA 8617 JZ 8617H
879F FE 20 CPI K_PAUSE
87A1 C0 RNZ
87A2 C3 8C96 JMP GETCH ;8C96H

by skyriver (2019-05-01 09:15) 

skyriver

 文字列表示のコンパイルコードについて、長さ0の文字列表示 "" のためには最初にカウンタがゼロか確認すべきですが、 ”” はコンパイル時にエラーになります。
 GAME-Z80版のGAMEコンパイラは ”” に対応していたと記憶しています。""はキーセンスのためにループ内でよく使っていたはず。
by skyriver (2019-05-01 15:52) 

skyriver

 コメントで書いた文字列出力部のコンパイルが気になったので頭の体操として生成コードの短縮化と長さゼロの文字列に対応するようコンパイラを変更しました。
by skyriver (2019-05-02 23:35) 

skyriver

 CP/Mで起動時にGAME本体を8600Hへ転送するようにして起動時間を高速化しました。

by skyriver (2019-05-04 08:34) 

skyriver

 起動のたびにコンパイラをコンパイルするのは面倒なので0x0200~にコンパイラを包括しました。コマンド名もgamecに変更しました。

by skyriver (2019-05-06 11:20) 

skyriver

 起動時のメモリマップは下記のようになっているので
1)作成したGAMEソースのコンパイル結果を$0200に上書き
 この時、$0200からのコンパイラは使えません
2)下記のコマンドで起動時のジャンプ先をコンパイル結果に変更してGAMEから抜ける。
A=$011B A:0)=$02 >=0
3)下記のコマンドでセーブすると作成したGAMEソースのコンパイル結果を実行する自作のCP/Mコマンドを作成できます。
save 34 hoge.com

[起動時のメモリマップ]
0200-1b23 : compiler
1C00-22FF : interpretter

by skyriver (2019-05-06 15:33) 

skyriver

 CP/M-80用GAME80のVer0.02でスペースキー、ESCによるポーズ、ブレーク時にエコーバックしないようにしました。

by skyriver (2019-05-10 00:01) 

skyriver

GAMEソースの行番号をリナンバするプログラムを追記しました。

by skyriver (2019-05-10 23:48) 

コメントを書く

お名前:
URL:
コメント:
画像認証:
下の画像に表示されている文字を入力してください。