JR-300エミュレータの開発その3

JR-300エミュレータのお話、第3弾!(^o^)

 

なんとなく3日分ずつ書いていたけれど、意図したわけではないぞ!

長すぎず短すぎず…という感じで調整したら、たまたま3日分になってるだけw

濃ゆい内容になったら2日分とかになったりするからね!

 

(この開発ブログの中では)JR-300を解析し始めて丸6日経つわけですが、すでに解析しつつエミュレータの開発をしつつという感じの流れとなっている。

本当は解析が目的だったはずだけど、なんとなくエミュレータも目的となっている。

まぁいいか…(^^;;

 

今の状態は、テキスト画面がスクロールしない限りはBASICコマンドの実行が出来る。

スクロールしようとするとサブCPU側のコマンドがないという理由で停止する状態。

 

2022/11/15(火)

テキスト画面がスクロールしようとするとおかしくなる現象を調べる前に、まずは画面クリア(BASICのCLS命令)の実装について調べてみる事にした。

 

BASICのCLS命令は3つのオプション(0,1,2)を持つ。

CLS 0と2でテキスト画面をクリアするサブコマンドが発行される。
CLS 1の時には、そもそもサブコマンドが発行されない。

 

テキスト画面のクリアにはサブCPUコマンド0x02が呼び出される。

パラメータは7つ!7つは多いなー(T-T)

頑張って調査してたところ、クリア開始のXY座標、クリアするバイト数があるのは分かった(のちに画面の横幅(WIDTH)を切り替える機能のある事が判明する)。

 

CLS 1がグラフィック画面のクリアだとすれば、(まだ未知の)サブCPUコマンドが発行されそうな気がするけれど…それが発行されないという事は、もしかしたらグラフィックを使用する宣言コマンドなどがあるのかも知れない。


この問題の解決は簡単ではなさそうなので後に残すしか無いけれど、後々になって大きな問題が発生しそうで怖い…(T-T)

 

無事に画面クリアが出来るようになったので、次はBS(BackSpace)の処理を入れる。
BASIC上で文字を打ち間違えると指が勝手にBSを押してしまうのだけど、そのたびにエミュレータが止まってしまうので効率が悪すぎる(^^;

 

BSを押すと、サブコマンド0x15が発行される。
パラメータの数が5つあるけれど、それぞれの意味が……わからん。
パラメータ3と4に座標が入っているようなので、その場所をクリアするコードを追加。
見た感じはそれっぽく動作するようになったが、このコマンドの応用例が出てこないとなんとも言えん…(-_-;

 

さて……今回の本丸である、スクロールの処理を見ていく。
現状ではサブコマンドが発行されているのは確認しているけれど、そこでプログラムを停止させていたので詳細は不明。
試しにスクロールさせてデバッグログを見ると、かなりの数のサブコマンドが発行されている…なんなのこれ(T-T)

 

詳しく見ていくと、サブコマンド0x15が大量に発行されている。
[15: 00 01 00 00 28]
[15: 00 02 00 01 28]
[15: 00 03 00 02 28]
[15: 00 04 00 03 28]
  :

あ、なんとなく分かった!
サブコマンド0x15は、テキスト画面のコピーコマンドだ!
転送元X,Y座標、転送先X,Y座標、転送バイト数 みたいだ!(^-^)

 

え、こんなん一気に80x24の領域を1行上にコピーしたらいいやん…と思ったが、最後の転送バイト数が1バイトしかない。
これだと最適化が面倒なので24回もコマンド発行しちゃうのもわからないでもない。
先輩が作ったサブコマンドシステムに「サイズを2バイトにしましょう」と意見できず、そのまま無理に実装した感じが見え隠れ(妄想)

 

24回サブコマンドを発行してメモリコピーをした後、最下行をサブコマンド0x02でクリアする。
[02: 01 00 00 00 18 28 00]

 

おそらく、01は(今は)無視、不明、不明、X座標(0x00)、Y座標(0x18)、そして0x0028がクリアするバイト数。
あれ?こっちはサイズ指定が2バイトだ。
きっと先輩自身がCLSコマンドを作り、1バイトでは困ったので2バイトへ拡張し(略

 

これでスクロールが出来……ん??……中途半端に出来た!?
あれ??なんで??
リターンキーを無駄押しして強制的にするスクロールは問題ないけれど、コマンド実行の結果によるスクロール(LISTとかRUNした結果)が変になる!
そもそもメインCPUからスクロールの要請が来てない…orz

 

え?それって……文字を表示した結果、スクロールが必要になったらサブCPU側が勝手にスクロールさせるって事??
メインCPUにも知らせずにスクロールって、そんな忖度ある??(T-T)

 

仕方がないのでサブCPU側の処理で改行の必要性が出た時スクロールさせてみた。
そしたらLIST、RUNの結果が正しく表示された!

えー…メインCPU側が全部管理するとかじゃないんだ…これは難しい(^^;

 

あと、作業の過程で気がついたけれど、カーソルのY座標の扱いが混沌としてる。
メインCPU側からアクセスされる時は0〜24の値を取るけれど、表示に関する部分では1〜25の値を取るようだ。
ものすごく分かりづらい!!
これはこの先も問題を引き起こしそうなので、頭に叩き込んでおかねば…。


WIDTH80と40に切り替わらない問題を見る。
WIDTH 80と打ち込んでみると、サブコマンド0x16が呼び出されていた。
BASICインタプリタの起動時にも呼び出されてた事から、サブコマンド0x16はスクリーン関連の初期化か、またはサブCPU全体の初期化と見ている。

 

WIDTH 40、WIDTH 80と何度か打ち込んでいると、1つめのパラメータに変化がある事が分かった。
このパラメータを見て横幅を変えてみたところ、表示が切り替わった!
でもスクリーンは初期化しないといけないのね、なるほど。

なぜかカーソルの位置はメインCPU側で戻してくれてるようで、サブCPU側への初期化命令は出ていない。
なんか中途半端感のある不思議な仕様だ…(^^;

 

BASICのコマンドを1つずつ調べていってるけれど、特殊なもの(BOOTとかTIME$などのクロック系)は後回しにしている。

処理自体がZ80側で完結するタイプの命令(文字列操作など)は問題なく動いてる。

テキスト画面への出力についても、ある程度動いてきたと思って大丈夫そうだ!

マンデルブロ集合のBASICプログラムも無事に動いた!

ここにきてようやく「BASICの主要命令は動いてそうだ」と思えるようになってきたので、明日はついにグラフィックにチャレンジするぞ!

 

2022/11/16(水)

今日からおそらく鬼門になるであろう、グラフィックス周りを解析&実装していく。

予想としては、サブCPU側のコマンドが増えるんだろうな…と想像。

 

まずは基本中の基本、画面へドット打ちをしてみる!

……しーん…
あれ?サブCPU側に何も反応が来ない…。
あれ?あれれ??これは一体??(@_@;;

 

てっきりサブCPU側にコマンドが発行されると思っていたのだが…。

予想されるのは、グラフィックモードがONになっていない、またはグラフィックはZ80側で処理してる…とかかなぁ…。

しかたないので、BASICコマンドが実行される部分を追いかけてみる。

 

中間言語に変換されたBASICプログラムは、メモリの0x0D00から格納されている事が分かったので、ここのデータが参照される流れを捕まえる。
その結果、中間コード0x81(NEW)〜0xD9(AUX)までの実行アドレスが分かった。

 

そしてPSET本体は0xD49Bからプログラムが始まる。
このアドレスを元に逆アセンブラリストを追いかけるのスタート!(T^T)

 

未知なるマシンJR-300のBASICとは言え、中身は普通のインタプリタのはずだ。

プログラムの流れはある程度承知しているはずなんだけど、ジャンプテーブルを多用するコードであっちへ飛びこっちへ飛び、とにかく解析しづらい…


まだシステムコール(0xC595からのファンクション群)の使い方をちゃんと把握していないおかげもあって、同じプログラムを何度も何度も見る羽目に。

 

でも……そのおかげもあり、グラフィック画面の横幅640ドットと320ドットを識別するワークエリアを見つける事が出来た。

問題は、そのワークエリアを書き込みしているコードが見つからず、いまだモードを切り替えるBASICコマンドが分からない事だ…orz

 

PSETが実行されると、指定された座標とカラーの範囲をチェックした後、パラメータをセットしつつシステムコール0x20を呼び出す。


分かってきたのは、VRAMのアドレスは[B:0000h]、[R:4000h]、[G:8000h]と3プレーンあること(これは想像に難しくない)、

ドットのデータがMSB...LSBの並び(PC-9801PC-8801FM-7など)ではなく、LSB...MSB(MZ-80Bなど)になっている事(のちにコレは間違ってると気づく)、
そして恐ろしい事が……アドレス指定がビットの並びが反転している!


例えば、VRAMのアドレス0x1234(0001_0010:0011_0100b)は、0x482C(0100_1000:0010_1100)に変換されて使用される。
これは……今までに見たことがないタイプの変態さんだ!!(@_@;;

 

テキストVRAMがサブCPUっぽいモノの先にあったので、てっきりグラフィックもサブCPU側にあると思っていたけれど…解析してみると、どうやらコントローラの先にありそうな雰囲気。

テキストVRAM系にアクセスする際には共有メモリを使ってパラメータを受け渡していたが、グラフィックはI/Oポート経由でアクセスをする。

 

しかも点(ドット)を1つ打つだけで39回もアクセスが入る。これはドットを描画するための最低限のアクセスの回数であり、実際にはコントローラのBUSY信号を見たりするのでもっと増える。

 

ちょっと試した感じではBASICのCIRCLE命令を実行すると、おびただしい数のPSETが発行されている感じ、LINEはアクセス少なめ、PAINTも数は多いけれどそこまでじゃない。

ということは、直線補間ハードが入っている可能性もある?!
うむむ、これは楽しみだ!(^-^)

 

2022/11/17(木)
引き続きグラフィックコマンドを調べている。

 

1つのドットを打つために、似たようなI/Oアクセスが3セット分されている事から、3プレーン同時書き込み機能はないらしい。

 

1つの点を描画するだけで39回のI/Oアクセスがある。
え?なぜそんなに???
グラフィック画面のCLS命令とか、LINE命令とかどうなっちゃうの??と思い、軽く調査してみたところ、CLSでは90回、LINEでは60回で済んでいた。

やっぱり描画支援ハードが存在するって事かな…事だよね??(^-^)

8bit機ではFM-77AVに直線補間が載ってた気がする(日立S1も?)けれど、ここに来てJR-300も載っていた可能性が出てきた!これは萌える!(^o^)/

 

PSET処理のI/Oアクセスを見てみると、大きく分けて同じようなアクセスがRGB分3回ある。それぞれのプレーンに11回ずつ。

もう少し細かく見ていくと、コマンドと思われるアクセスが1プレーンで5つ、パラメータらしきものが6つあった。

 

PSETのパラメータを変えて何度も何度もテストをして、どのようにI/Oアクセスが変わっていくのかを見ていく。

すると、ドットのON/OFF、VRAMのアドレスとビットパターンが見えてきた。
しかもアドレスは昨日解析したビットパターンを反転してのご指定だ!

 

このアドレスの反転指定は何か事情があるんだと思うけど、解析をしていてこの数値を見てもピンとくるものがない。


例えば0x3E80とくれば「VRAMのサイズかな?」とか、0xC8と来れば「10進数の200だから縦のドット数?」とか、何かしらピンとくるものがあるんだけど、0x7C01の数値をみても脳内で0x3E80に変換出来たりはしない。いちいち値を変換しないといけないので、どうしても解析に時間がかかっちゃう(T-T)

 

解析にものすごく手間取ったものの、なんとか点が打てるようになった!
むしろスクリーンに描画させるのに手間取ってしまった!(単なるバグw

 

そういえば、昨日書いていたドットのMSBが逆転している件は、私の解析ミスだった!
PC-8801とかと同様、MSBが左に来ている仕様でした!!

 

PSET命令が動くようになったら、同時にCIRCLE命令も動くようになった。

ということは、CIRCLE命令はBASIC内部でドットに分解して描画してるって事なんだね。さすがにハードウェアでの円弧描画機能などは載ってないか(^^;

 

初代M1 Macのフルスピードで動かしているというのに、円を描画しているところが見えるほどの速度だ!
これ…実機だとどのくらいの速度だったんだろうか…(-_-;;

 

ちなみにPSETを200回、CIRCLEを30回描いた時のI/Oアクセスの総数は50万回以上!
……とても効率が良いとは言えないだろう(T-T)

 

このアドレスのビットを上下逆転しなければならない仕様は、逆アセンブラリストを見ていた時に気がつくことができた。
なぜ反転させているのか、その時は意味がわからなかったけど、その反転されたデータがI/Oに出てきた時、さっき見たデータだ!と気がつけたw

これに気がつけなければグラフィックの解析は難しかっただろう。


これって…本体の基板を設計した時に、間違えてバスを逆転させて繋げちゃったとか、そういう理由???
またはI/Oの先はシリアルで繋がってて、その順番の関係とか???
どっちにしても現状ではプログラムで律儀に反転させてるのがもったいない…

256バイトの反転テーブルを持っても良かったと思うぞ…(^^;;

きっと先輩から省メモリをきつく言われてて、気の弱い後輩は(以下略

 

絵が出てくるとテンション上がるね!(^-^)

 

ではまた次回!(^-^)ノ