スキップしてメイン コンテンツに移動

SBC6809モドキを作ろうとしたら、MZ-6809が出来ていた件 その4

 GAME-CCのやらかしバグについて

まず、問題のファイルは ランタイムパッケージに相当する 「gamecc.asm」の中の

W82            RMB        6+1            ; DIVIDE BINDEC/WORK
;            FCB        0

この箇所、これ gamecc.asmの終わりの方の、ほとんどRMBの並んでる中、ただ1バイト分 0をメモリに書き込んでる。
そこだけピンポイントで0格納するようにHEXファイルが生成されれば無駄もないんだが、
アセンブラの種類によっては前後のRMBブロックもゼロフィルして無駄に大きなHEXファイルになる。
W82は6バイト確保だったのを7バイト確保にしてFCBを消したんだが、一見これでも 動作はする。
メモリというものが、電源入れた直後に全てゼロになる前提なら。今回のエミュはそうはいかない。
メモリの確保イコールゼロで初期化まではやっていない。実機でもSRAMにしろDRAMにしろ電源投入直後は電気的には不確定なのが通常で
ROMから起動したモニタがメモリをゼロフィルしてメモリの正常動作を確認するのが一般的な初期動作になる。
これまでにテストで使ったlinux上のエミュはメモリのゼロフィルが当たり前だったのが災いした形になる。
この6バイトは、数値の左詰め表示のための結果格納バッファで符号のための1バイト、1から32767までの5桁を入れる5バイトの合計6バイトになる。
そして、GAMEの内部処理では文字列は0終端の集合として扱って表示しているので、数値文字列の終わりのための0を入れる7バイト目が必要になる。
これを端折ったため、maze.hexのオブジェクトのエスケープシーケンスでカーソル位置指定する計算式で
結果が正しく出されずに謎文字列の羅列が爆発するバグにエミュレータ作成初期に悩まされた。
BYNDECルーチンのリターン直前に W82+7の位置に0を書き込むコードを挿入して回避するように修正。
エミュレータ側も、起動時にメモリのゼロフィルを入れて対応している。

すでに生成済みのオブジェクトを再アセンブルはしていないので気になる場合は各自で再アセンブルすれば
修正版のgamecc.asmを組み込んで修正版の実行オブジェクトが手に入る。コンパイラ自体には今のところ問題はないと思う。

次にExBasROMについて しめて5400行ちょいの アセンブラソースなんだが、その全ての行に丁寧なコメントが入ってる。
実に有り難いことだ、だが80系のアセンブラに慣れてしまった頭には
ラベルとOPコードの境目は「:」、コメントは 「;」で始める という 暗黙の掟みたいなのがある。
モトローラのアセンブラにはそれがほぼ無い。すべて スペースかTABで区切り 記述する位置で判別しているらしい。
それが全てのアセンブラに通用すればよいのだが、そうは行かない。
エミュレータ6809に内蔵のアセンブラはこのソースを無加工でアセンブルする。
しかも破綻なく、オリジナルのHEXファイルと同じバイナリになるレベルでできる。
エミュレータ内蔵のアセンブラで十分ではと? 思われるかもしれないが、
これも常用には不向きな難点がある例えば条件付きマクロなどが使えないとか、HEXファイルは出せてもBINは出せないとか
飽くまでも、エミュレータの補助機能だから過度な期待はしないほうが良い。
メインに使ってるasm6809はOPコード、オペランドの後ろの文字列をオペランドの延長の文字列と誤認識する。
OPコードだけで済むインヘレント命令に余計なオペランドがあるとエラーが大量に吐かれる。
またLABEL+4/2 なんて式を オペランドに記述すると 4/2を先に処理して、「LABEL+2」の結果がオペランドとして出される。
だから この手の式を見つけては(LABEL+4)/2のような形に変えてやる必要がある。
また、LDA LABEL のような場合、LABELがダイレクトページにあるかを判別しないので エクステンド命令に展開される。
ダイレクトページ内のバッファや変数を扱う命令に全てダイレクトだと指示する「>」を付加する必要がある。
第一段階はこの作業を、5400行全て見ながらやった。
答え合わせのできるHEXファイルが用意されてるので、
それと同じオブジェクトバイナリができるようにアセンブラソースを修正していけば良いだけ。
言葉としては簡単だが、地味で単調な作業を5400行分手作業でやるのはかなりキツイ。
答え合わせのやり方も、インテルHEXファイルもアセンブラ毎に表現に微妙に違いがあって、
単純にHEXファイルをdiffにかけて お終いとは行かない。
一旦 HEXファイルを BINファイルにして それをxxdでHEXダンプして 共通の形にしてからdiffにかける。
これを 延々と繰り返して 最終的には違うのはファイルネームだけって結果が出るまでやる。
ここまでが第一段階で 次からが ExBasROMのバグ取りの話になる。

DB7E 9F71             LA093     STX  <TOPRAM         ;SAVE ABSOLUTE TOP OF RAM
DB80 9F27                       STX  <MEMSIZ         ;SAVE TOP OF STRING SPACE
DB82 9F23                       STX  <STRTAB         ;SAVE START OF STRING VARIABLES
DB84 3089FF38                   LEAX -200,X         ;CLEAR 200 - DEFAULT STRING SPACE TO 200 BYTES
DB88 9F21                       STX  <FRETOP         ;SAVE START OF STRING SPACE
DB8A 1F14                       TFR  X,S            ;PUT STACK THERE
DB8C 8EDBD3                     LDX  #LA10D         ;POINT X TO ROM SOURCE DATA
DB8F CE0076                     LDU  #LPTCFW        ;POINT U TO RAM DESTINATION
DB92 C612                       LDB  #18            ;MOVE 18 BYTES
DB94 BDDCB3                     JSR  LA59A          ;MOVE 18 BYTES FROM ROM TO RAM
DB97 CE00A7                     LDU  #IRQVEC        ;POINT U TO NEXT RAM DESTINATION
DB9A C60E                       LDB  #14             ;MOVE 4 MORE BYTES
                                                                                      ;move 4 bug , move 14 ok? by nikohon
DB9C BDDCB3                     JSR  LA59A          ;MOVE 4 BYTES FROM ROM TO RAM
DB9F 8639                       LDA  #$39
DBA1 97F0                       STA  <LINHDR-1       ;PUT RTS IN LINHDR-1
DBA3 BDDFC0                     JSR  LAD19          ;G0 DO A -NEW-

BASICの初期起動時に ROM上のリセットベクタやルーチンの一部をRAMエリアにコピーしているんだが
オリジナルのままだとDBE5からの4バイト転送になるが割り込みベクタ2件(JMP命令も含むのでこれだけで6バイト)だけでも 不足する。
乱数のシード値なども転送する必要があるようなので、全部で14バイト転送させることにした。

L907C     PSHS A              ;PUSH A CHARACTER ONTO THE STACK
          LDA  ,X+            ;GET NEXT CHARACTER FROM BUFFER
          CMPA #'-'           ;MINUS SIGN?
          BEQ  L907C          ;YES
          CMPA #'+'           ;PLUS SIGN?
          BEQ  L907C          ;YES
          CMPA #'$'           ;DOLLAR SIGN? ;$'$'           ;DOLLAR SIGN?
          BEQ  L907C          ;YES
          CMPA #'0'           ;ZERO?
          BNE  L909E          ;NO - ERROR
          LDA  $01,X          ;GET CHARACTER FOLLOWING ZERO
          BSR  L90AA          ;CLEAR CARRY IF NUMERIC
          BLO  L909E          ;BRANCH IF NOT A NUMERIC CHARACTER - ERROR

CMPA #'$'のところ 元は $'$' なんだが 前後の脈絡から イミディエイト命令に変更している。
この辺りはExBasROMにだけ残ってるUSING命令の部分らしく 滅多に使われないので 誰も気づいてないのかも?

ここまでが 元からのExBasROMのバグ修正で この後は 私がやった修正や機能追加などの話。
今回のエミュレータ作成の影響で気づいた点で、フルメモリ全域RAM状態の中でExBasROMを走らせると
状況によっては自分で自分を書き換えて破壊する可能性があること。

コールドスタートさせると まずRAMとして使える領域を探すためにあるポイントから前方にメモリの書き換えチェックを始める。
BASIC9のコールドスタート部分
BACDST    LDX        #PROGST+1    ;POINT X TO CLEAR 1ST 1K OF RAM
LA077    *
        cmpx #1    ;
        beq 0f    ;0fはローカルラベル0を前方参照せよと指示している意味
        CLR        ,--X        ;MOVE POINTER DOWN TWO-CLEAR BYTE
        LEAX    1,X            ;ADVANCE POINTER ONE
        BNE        LA077        ;KEEP GOING IF NOT AT BOTTOM OF PAGE 0
0        LDX        #PROGST        ;SET TO START OF PROGRAM SPACE
        CLR        ,X+            ;CLEAR 1ST BYTE OF BASIC PROGRAM
        STX        <TXTTAB        ;BEGINNING OF BASIC PROGRAM
LA084    *
        LDA        2,X            ;LOOK FOR END OF MEMORY
        COMA                ;* COMPLEMENT IT AND PUT IT BACK
        STA        2,X            ;* INTO SYSTEM MEMORY
        CMPA    2,X            ;IS IT RAM?
        BNE        LA093        ;BRANCH IF NOT (ROM, BAD RAM OR NO RAM)
        LEAX    1,X            ;MOVE POINTER UP ONE
        cmpx #ramend    ;
        bhs LA093

        COM        1,X            ;RE-COMPLEMENT TO RESTORE BYTE
        BRA        LA084        ;KEEP LOOKING FOR END OF RAM
ExBasROMのコールドスタート部分
BACDST    LDX  #PROGST+1      ;POINT X TO CLEAR 1ST 1K OF RAM
LA077     CLR  ,--X           ;MOVE POINTER DOWN TWO-CLEAR BYTE
          LEAX 1,X            ;ADVANCE POINTER ONE
          BNE  LA077          ;KEEP GOING IF NOT AT BOTTOM OF PAGE 0
          LDX  #PROGST        ;SET TO START OF PROGRAM SPACE
          CLR  ,X+            ;CLEAR 1ST BYTE OF BASIC PROGRAM
          STX  <TXTTAB         ;BEGINNING OF BASIC PROGRAM
LA084     LDA  2,X            ;LOOK FOR END OF MEMORY
          COMA                ;* COMPLEMENT IT AND PUT IT BACK
          STA  2,X            ;* INTO SYSTEM MEMORY
          CMPA 2,X            ;IS IT RAM?
          BNE  LA093          ;BRANCH IF NOT (ROM, BAD RAM OR NO RAM)
          LEAX 1,X            ;MOVE POINTER UP ONE
          cmpx #ramend
          beq LA093
          COM  1,X            ;RE-COMPLEMENT TO RESTORE BYTE
          BRA  LA084          ;KEEP LOOKING FOR END OF RAM
LA093     STX  <TOPRAM         ;SAVE ABSOLUTE TOP OF RAM
          STX  <MEMSIZ         ;SAVE TOP OF STRING SPACE
          STX  <STRTAB         ;SAVE START OF STRING VARIABLES
          LEAX -200,X         ;CLEAR 200 - DEFAULT STRING SPACE TO 200 BYTES
          STX  <FRETOP         ;SAVE START OF STRING SPACE
LA093    STX        <TOPRAM        ;SAVE ABSOLUTE TOP OF RAM
        STX        <MEMSIZ        ;SAVE TOP OF STRING SPACE
        STX        <STRTAB        ;SAVE START OF STRING VARIABLES

BASIC9では、前方探索でポインタが1になったら 次の段階に移るようになっているが 
ExBasROMには それが無い ROMが載ったシステムなら それに反応して次の段階に移る。
だが、全域がRAMの場合 際限なく繰り返す。0を超えてマイナスになったときに切り上げるようだが 
その時には 0xffffのリセットベクタの後半を破壊した後になる。

        LEAX    1,X            ;ADVANCE POINTER ONE
        BNE        LA077
のBNEはBRA としても 結果は同じになるかもしれない。(BRAに書き換えても 問題なく動作した確認済み)

その後、メモリを後方に向かって同様に書き換え可能か探索する。これもROMに到達して 書き換え不能まで繰り返される。
今回のケースだと、BASIC本体の格納エリアより前にACIAのポートがあるので 
そこで書き換えた値と違うということでROMとみなされBASIC本体の破壊を免れている。

次に引っかかったのが、BASICが使えるメモリ残量が知りたくて PRINT MEM とかしたら、
OV error だか SN error だったかでまともに動作しない。基準にしてるオリジナルのHEXでは問題ない。
自分の今持ってる ExBasROMのソースに不備があるのは確か、徹底して調べて判ったのが2点
冒頭に出した、LABEL+4/2の形式のオペランドに含まれる算術式の解釈問題、
これによりコマンドや関数のジャンプベクタの引き出しが間違っていて見当違いのアドレスに飛んでいた。

もう一点は、
01EE                  STRBUF  RMB     41      ;STRING BUFFER
これで、あきらかにDPの範囲外なのに、オペランドにSTRBUFがあるところで 「>STRBUF」としてた
当然、0x01eeじゃなく、0x00eeのメモリを参照してることになる。
これも奇跡的に 問題が表面化すること無く済んでて気が付かなかった。

最後の問題は、tek4010にグラフを表示させるプログラムをCTRL+Cで強制中断させた後に
キー入力ができなくなる問題に遭遇、よくよく見ると 改行が効かないだけで他は入力できている。
これは、BASICのPRINT文が持ってる問題で80文字くらいを連続で改行なしでprintしようとすると
BASICが勝手に0x0d,0x0aのコードを挿入する問題を抱えている。
tek4010のグラフ表示コードの最中に0x0d,0x0aを入れても 改行とは認識されず。グラフ表記構文の破綻を起こす。
BASICのソースに細工するとtek4010以外でのprint文に支障が出る可能性もあるので
エミュレータ側でこれを吸収することにしている。その影響で tek4010のグラフ表示中に中断すると
0x0d,0x0aを無視する状態のままで中断が入ると画面表示がおかしくなる。
そこで、BREAKのメッセージの頭に 0x1f(tek4010のグラフモード終了コード)を挿入した。
このコード自体は画面に出るコードじゃないので通常状態でも画面が乱れることはない。

異常の過程を経て、SBC6809改 程度の扱いのモノは形になったので 次回にでも アーカイブにして公開する予定。
その際に、付属のツール類の説明などもしようと考えている。今回扱った BASICのアセンブラソース類もそこに含める予定。

コメント

このブログの人気の投稿

screen コマンドでの コピーペースト転送の実現について

 以前、GAME言語のあれこれについての中で、GAME80ICなどでZ80-MBC2とのscreenコマンドでのシリアル接続中にソーステキストのコピーペースト転送ができない事に触れていたが、単に使ってる環境に依存した所謂「おまかん」なのだが、回避したければ、素直にwindowsで使うか 若しくは linuxでもwine上でteratermを使えば済む話ではある。だが、我が家に於いては普段使いにできるwindows機など無い。棚の奥を探せばwin7の入った古PCが有るとは思うがボードマイコンとの接続の為だけに引っ張り出してきたいとまでは思わない。そこで ふと考えるにteratermにあってscreenやcu,minicomにないものはと、teratermには、テキスト転送中に行単位、文字単位でミリセカンドのディレイを挟む設定がある。対してlinux系のシリアル接続コマンドにそういった類のモノを知らない(単に自分が知らないだけの可能性もある) 。そこで、duckduckgo検索のサービスである「Duck.AI」に聞いてみた。自分の思いついた革新的なアイデアは大概は先人が既に思いついてる当たり前過ぎるモノというのはいつもの事であっさりと解決策を教えてくれた。

一部の関西の人にしか通じないネタ

たぶん「30年モノ」くらいだと思う?  拡大 値札に注目! ちなみに、ATMEGA32へのファーム書込用のアダプタを作るのに使用。

GAME言語 あれこれ

 MZ-700用にSDカードからMZTファイルの読み書きが出来る基板を入手して以降、MZ用のインタープリタやコンパイラの打ち込みをやってた延長でZ80-MBC2上のCPMで動作するGAMEインタープリタとコンパイラをいくつか発見。GAME-MZは国会図書館のコピーサービスで当時のアスキー誌の記事を入手済で打ち込みMZT化は済んでいるが動作の確認はしてない。 CP/M-80で動作するGAME80言語を3点ほど紹介する。 まず、動作環境は実機としては8Mhz動作のZ80-MBC2にXMODEMでPCからのファイル転送 PC側はFedora40の端末から「screen」コマンドでの接続、比較用に同じくFedora40の端末上で動作するCPMエミュレータ2種類。エミュレータで動作確認がとれたモノを実機に転送して最終動作させてみる流れ。    skyriverさんのGameOnCpm80 端末のエミュレータ上ではコピーペーストによるソースの転送もできるが ファイル読み書き用のコマンドが組み込まれているので、なぜか実機の方ではコピペに転送が出来ないのでありがたい。コンパイラも組み込まれているのでインタプリタで実行確認後、コンパイルもできる。 難点は、コンパイルの際にソース格納アドレスやデータエリア、オブジェクト格納エリアの指定をする必要がある。GAME-MZでもコンパイルの際は普通に必要な事ではあるが、自分の頭の中でシステムのメモリマップを把握しておくのが意外と面倒くさい。 コンパイルで 出来たオブジェクトをCOMファイルにするのにDDTなんかの別ツールでメモリ上に残ってるデータをCOMファイルとして保存するしかない。 COMファイル化とかを視野に入れずインタープリト、コンパイル、実行だけなら使いやすくお薦め。   ファイル操作コマンド例 files ファイル一覧表示 :\\ *.g 拡張子 .g のファイルの表示      \\のみ、\\ *.* での表示は出ない模様(単に自分の使い方が悪いだけかも?)  save(¥>FileName)とload(¥<FileName) 詳細は https://piclabo.blog.ss-blog.jp/CPM80GameCompiler...