エピ9.1 プログラムをLOADしたいのです
***
エピ9.1 プログラムをLOADしたいのです
***
メインループでプログラムを1文ごとに入力することはできるのですが。...とても遅いのです。変換1と変換2があってね。遅いのです。変換2なんて意味不明で。こいつは不要か! ...、と思っていたら LIST 命令で使われていてブロックできず。
速やかにプログラムを入力するにはLOADするしかなさそうな感じです。なんとかプログラムをLOADしたいのです。
***
直接実行命令文 "LOAD" の中間コードは 91h で、その分岐先は 2A15h 番地です。
2A15h 番地以降を逆アセンブルして見てみたところ、4049h 番地と 4069h 番地のルーチンをコールしていて、ここからROMルーチンをコール...、と三階層になっていることが分かりました。
でもね。ROMのコードだけでも LOAD できるはずで、実際にSP5030はROMのコードでロードしているのですから、4049h 番地などのルーチンがある意味が不明確。
SP5030内にROMと同等なコード(4049h 〜)を用意して、"LOAD" 命令ではこちらを使用しつつ、要所でROMルーチンをコールしてるのです。モザイク状態というか、どうなっているのか判りかねる感じがします。
*
まぁ、全部を解読すればよいのですけどね。
*
そう思って、
2A15h ←→ 4049h, 4069h ←→ ROM
と行きつ戻りつして、プログラムをLOADしようとしたら迷子になってしまいました。わずか3階層の迷宮なのにトホホなことです。ランクFの冒険者かよ!
これではダメなので一旦SP5030から離れて、ROMだけのLOAD処理に注目することにします。
***
**
*
電源オンすると 0000h から実行開始して、ジャンプ命令で 004Ah 番地に行きます。
004Ah 番地では、スタックポインタを設定したり、初期化処理をして、
と画面表示して、016Bh 番地にジャンプして 119Dh 番地を FFh(キー入力時の音をオフ)にした後、ROMのメインループである 0082h〜00CEh のコードに行き、入力待ちになります。
ここでは LOAD や GOTO などの数個のコマンドが実行できるのみです。メモリ編集など気の利いた機能はなくて寂しいです。
*
LOAD コマンドを入力すると 00CFh 番地にジャンプします。
00CFh 番地からのコードは単純で、
・04D8h をコール
・"LOADING" +ファイル名(10F1h〜)を表示
・04F8h をコール
・1106h 番地の値が 1200h 以上ならそこにジャンプ
です。04D8h のルーチンでファイル名等の 128 バイトをロードして、04F8h のルーチンでプログラム本体をロードするのでしょう。
SP5030をロードすると自動的に実行開始するのは、1106h 番地に設定があるからなのですね。
*
04D8h のルーチンも、04F8h のルーチンも単純です。
04D8h では
DE = D2CCh
BC = 0080h
HL = 10F0h
と設定した後、06B2h, 065Eh, 0510h を順にコールします。
04F8h では
DE = D253h
BC = 1102h 番地の値
HL = 1104h 番地の値
と設定して 06B2h, 065Eh, 0510h をコールします。値が違うだけで、処理は同じですね。
ここで、BC はロードするデータのサイズ(バイト数)、HL はデータの格納先です。DE は後で分かります。
つまり、ファイル名などの 128 バイトは 10F0h〜 にロードされて、10F1h〜 がファイル名、1102h はサイズ、1104h はロード先、1106h は実行番地!
***
06B2h, 065Eh, 0510h の3つを順番に見ていきます。
*
1つ目の 06B2h ではカセットテープレコーダの状態を調べます。
具体的にはモータの回転の有無を E002h 番地のビット4で取得します。
MZ80のカセットテープレコーダは、Play ボタンが押下されるとモータが回転するのですが、ソフトウェアからモータの回転停止や回転再開を制御できるのです。Play ボタンが押下されていて、回転状態の時にモータは回転します。
モータが回転中なら、そのままリターンします。回転していないときは回転再開をしてみて、回転したらリターンです。
モータの停止/回転の制御をしても回転を開始しない場合には Play ボタンが押下されていないので、"↓ PLAY " と表示して、Play ボタンの押下を待ちます。なお、SAVE の場合(D = D7h)は "↓ RECORD. PLAY" と表示します。
モータの回転を検出できたらリターンです。ブレークキーが押された場合もリターンします。
*
次の 065Eh ではデータの始まりを検出します。
カセットテープレコーダからの信号が 0 => 1 => 0 と変化したら、これが1ビット分のデータです。変化する時間の短長により「0」と「1」を判定します。
E = CCh なら 40 個の「1」と 40 個の「0」の連続を待ちます。E = 53h なら各々 20 個の待ちです。
「1」の連続をカウントして途中で「0」が来たらやり直し。「1」が 40個(20個)連続したら次は「0」の連続をカウント。途中で「1」が出たら最初からやり直しです。「0」が 40個(20個)連続したらカウントは終了です。
その次に 0=>1 検出をしたらリターンです。
*
0=>1 検出や「1」や「0」の判定については、この後でね。
*
3つ目の 0510h ではデータ本体を読み取ってメモリに格納します。
・最初の「0」は読み飛ばします。
・1197h 番地をゼロクリアします。
・BC バイト分を読み取ります。
・0624h 番地をコールして1バイト取得します。
・次を8回繰り返します。
・・・0=>1 検出したら1ビットを読み取ります。
・・・ビットが「1」なら 1197h 番地に1加算します。
・0=>1 検出したらリターンします。
・1バイトをメモリに格納します。
・更に2バイトを読み取り、1197h 番地と比較します。
・一致した場合は、0700h 番地をコールして、
・カセットテープを停止してリターンします。
・一致しない場合は、2つ目のデータのロードを試みます。
リターン時に、
A=00h なら正常
A=01h ならチェックサムエラー
A=02h ならブレークキー
です。
データの後には2バイトのチェックサムがあって、その値は(バイト毎の値の合計ではなくて)データ中の1の個数でした!
それと、1バイト分で9ビットあって、その最初のビットが「1」固定だと思っていたんですけど。「1」固定なのは最後のビットなのかな。
***
「1」や「0」の判定方法についてです。
MZ80ではカセットテープからの信号を E002h 番地のビット5で取得します。テープレコーダの磁気ヘッドの出力をオペアンプで処理した値がビット5で得られます。
このビット5を監視して、0→1に変化したらリターンするのが 0601h 番地のルーチンです。監視を開始したときに1だったら0になるのを待って、次に1がきたらリターンです。
波形からビットの「1」「0」を判定する処理は、0601h と 0760h のルーチンを使って次のようにします。0760h 番地のルーチンは時間待ち用です。
CALL 0601h # 0=>1
CALL 0760h # Wait
CALL 0760h # Wait
CALL 0760h # Wait
LD A, (E002h)
AND 20h
JP Z, nnnnh # "0" の場合
あるいは
JP NZ, nnnnh # "1" の場合
E002h のビット5が0→1に変化してから一定時間待って、その後の値で「0」か「1」かを判定するのです。これは波長を調べるのと同じですね。
0760h 番地のルーチンによる待ち時間は、
・CALL 命令 17 ステート
・LD 命令 7 ステート
・DEC 命令 4 と JP 命令 10 の計 14 ステートを 13 回ループ
・RET 命令 10 ステート
で、合計 17+7+14*13+10 = 216 ステート。これを3回コールするので 216*3 = 648 ステート分を待ちます。
あ、あとこれに 0601h のルーチンの0→1検出遅延がプラスされます。えとー、
・検出遅延は(最大で)AND,JP,LD,AND,JP,LD の 4+10+7+4+10+7 = 42 ステート
・検出後の遅延は AND,JP,RET で 4+10+10 = 24 ステート
つまり、最小 648+24 = 672 ステート、最大 648+42+24 = 714 ステート です。MZ80のクロックは2MHzですから1ステート = 0.5 μs です。ステート数を時間にすると 336 〜 357 μs ですね。
ボイスレコーダで録音したデータを見ると、
350 μs 前後は上下の2つに分かれていて、赤(=1)と青(=0)と良い感じで判定できます。
ボイスレコーダの波形は幾らかブレていますが、実機はオペアンプで処理しているのでもっと良好だろうと思います。
*
ループ回数(の定数)を調整するのではなくて、3回コールして時間待ちするって、泥臭いけど良く有ることですね(笑)。
SYNC, SYNC, SYNC とかさ。
***
**
*
ROMの LOAD コマンドによるプログラムのロードを解読しました。
ファイル名等のデータは 128 バイトで確定して、チェックサムの算出方法も判明しました。
2つあるデータの扱いは、1つ目をロードしてチェックサムが一致すればそこで終了。チェックサムが不一致なら2つ目をロードするです。
ファイル名の後の6バイト(サイズ・ロード先・実行番地)なんですけど、機械語のプログラムの場合はそのままの意味のようですが(、...と言うかROMがそのまま処理する)、BASIC言語のプログラムの場合は違いますね。サイズの意味は同じですけど。
ロード先は(ほとんどは 4806h ですが)5106h や 5006h の場合があります。各1つですが 1200h, 3400h, 5800h, 5B00h, 71BDh もありました。
実行番地は 0000h です。プログラムの実行はSP5030が管理します。
もしも実行番地が 0000h でなかったら。ROMルーチンの LOAD コマンドではデータの属性をチェックしていないし、自動実行を抑止する手段も見当たらないので、実行番地がセットされているBASICのプログラムをロードしたら暴走するね。
でもSP5030ごとプログラムを保存して、"RUN" 命令の分岐先を実行番地にすれば、自動実行できるのかな。初期化処理は、...初期化処理で設定したメモリも含めて保存すれば行けそうな感じはする。
ゲームだと。プログラムのロード後に自動的にスタートしたらよいよね。SP5030を含めて販売するのはライセンスが必要でしょうけど。
***
間違いの指摘とか疑問とか、ご意見・ご感想とかありましたら、どうぞ感想欄に!
***
2026.2.1 推敲
2026.2.3 改題、推敲
2026.2.7 推敲
2026.2.15 微推敲
2026.3.19 微推敲
2026.4.2 推敲
2026.4.5 エピタイ修正と微推敲
2026.7.19 エピタイ修正と微推敲




