エピ5 SP5030のコードを入手しました
***
エピ5 SP5030のコードを入手しました
***
BASIC言語のインタプリタであるSP5030のコードを入手しました。
それで、ですね。16進数ダンプしたり逆アセンブルして、...、BASICが動く雰囲気を感じよう(?)として見たりしたのですが。
...。BASICが動く雰囲気って、何を言っているのか意味不明ですね。
***
SP5030が起動すると画面に「READY」と表示されてカーソルが点滅するので、
10 LET A=3.14 : PRINT A
と入力してリターンキーを押すと文番号 10 の命令文がメモリに記憶されて、...RUNすればプログラムが実行される、...はずです。
逆アセンブルしたリストを見つめて、そんなことを色々と想像してみたけど。メインループの表面をなぞってるだけでは動いている感じがしない。
ほら、SFで脳みそだけの人、...サイモン博士?、...が描かれているけど、入出力をカットされても何か動いている感じだったよね。
だけどSP5030は依然として情報としてそこにあるがまま。あるがまま(グスン)。
それで動かして見たくなった、...のですよ。
***
逆アセンブルして分かったことを整理しよう。
*
カセットテープから読み出したSP5030のコードは 2F40h バイトあって、メモリの 1200h〜413Fh 番地にロードされる。
ロードが成功すると 1200h 番地にジャンプして初期化の処理が始まる。初期化処理のコードは 1200h〜124Ch 番地だと思う。
*
初期化処理では次の(1)〜(8)を行なう。
(1)3C65h 番地を 00h、3D25h 番地を 01h にする。SP5030自身を書き換えているよ!
(2)メモリテストを行う。テストする範囲は 4400h 番地から、最大で CFFFh 番地まで(RAMが48KBある機種なら末尾は CFFFh です)。テスト対象の番地に FFh を書き込んで、読み出して FFh でなければ終了。更に 00h を書き込んで、読み出して 00h でなければ終了。これを繰り返してメモリの末尾を求める。...、メモリテストは起動時にROMルーチンで行うべきだと思うけど、どうなのかな?
(3)メモリ末尾の次(RAM48KBなら D000h)を、4561h〜4562h 番地と 4563h〜4564h 番地に格納する。スタックポインタ(SPレジスタ)にも設定する。
(4)改行した後、「 * SHARP_BASIC_SP-5030」を画面表示(改行はROMの 0006h 番地のルーチンをコール、文字列の表示は 0015h 番地をコール)
(5)1826h 番地をコールして、ワークエリアを初期化
(6)1737h 番地をコールして、メモリサイズをチェック(メモリが小さすぎるとエラー)
(7)16EFh 番地をコールしてメモリサイズを10進数に変換して、これを 1355h 番地のルーチンをコールして画面表示(0009h と 0015h をコール)。続けて「BYTES」を画面表示(0015h をコール)。
(8)時計を初期化(ROMの 0033h 番地をコールして、時計を 00:00:00 に設定)
ここまでが初期化処理です。初期化が終了すると 124D 番地から始まるメインループに入り、「READY」を画面表示して、入力待ちになる。
*
1826h 番地のルーチンで初期化するワークエリアの番地と値は次の通り。
2998h: 00h
4565h: 00h
;
4632h〜4633h: 0000h :0 +
4634h〜4635h: 4808h :1
4636h〜4637h: 480Ah :2
4638h〜4639h: 480Ch :3
463Ah〜463Bh: 480Eh :4
463Ch〜463Dh: 4810h :5
463Eh〜463Fh: 4812h :6
4640h〜4641h: 4814h :7
4642h〜4643h: 4816h :8
4644h〜4645h: 4818h :9 +++
4646h〜4647h: 466Ah
4648h〜4649h: 4787h
464Ah〜464Bh: 47F0h
;
47FDh〜47FEh: 0000h
47FFh〜4800h: 0000h +++
;
4803h〜4819h: [00h]*23
今の時点では何のことなのか不明ですが後で分かると思います。きっとね!
*
1737h 番地のルーチンによるメモリサイズのチェックは、
def _1737h():
x = m[0x4644]+m[0x4645]*256 + r[BC]
if x > 0xFFFF:
MEMORY_ERROR() # EXIT
y = r[SP] - 100 - x
if y < 0:
MEMORY_ERROR() # EXIT
return y
と言った感じの処理です。
変数 m[] はメモリを表現した配列です。4644h〜4645h 番地の値は(ワークエリアの初期化で設定された)4818h です。
変数 r[] はレジスタです。ここではr[BC] とr[SP]を参照します。r[BC] は初期化でコールする際には 000Ah です。r[SP] はサブルーチンコールされているので、D000h から2バイト減って CFFEh です。
ですから、変数 x は 4818h + 000Ah = 4822h で、変数 y は CFFEh - 100 - 4822h = 8778h となります。変数 x は初期化の時点ではエラーにはならずです。変数 y は(2)のメモリテストの結果次第で(メモリが故障していると)エラーになるかもです。
でもこの判定でよいのか不思議ですね。特に x > 0xFFFF は D000h 以上ならエラーなのでは?
変数 y の値 8778h が(7)のメモリサイズとなります。10進数に変換すると 34680 です。
メモリエラーになった場合には、138Fh 番地にジャンプします。
メモリの一部を初期化して、エラーメッセージ(MEMORY ERROR)を画面表示して、メインループの先頭(124Dh 番地)にジャンプします。
メインループでは「READY」を表示してキー入力待ちになるのですが、...。メモリエラーでは状況把握して電源を切るくらいしかできないですね。
***
表示されるメッセージの文字列は次の番地にあります。
12E0: " * SHARP_BASIC_SP-5030" + 0Dh
12F7: "READY" + 0Dh
12FD: " ERROR" + 0Dh
1304: " IN" + 0Dh
1308: "SYNTAX" + 0Dh
130F: "MEMORY" + 0Dh
1316: "DATA" + 0Dh
131B: "MISMATCH" + 0Dh
1324: " BYTES" + 0Dh
132B: "BREAK" + 0Dh
1331: "16FOR" + 0Dh
1337: "16GOSUB" + 0Dh
133F: "6FN" + 0Dh
1343: "CONT" + 0Dh
1348: "FILE" + 0Dh
134D: "OVERLAY" + 0Dh
これらのうち、エラーメッセージは次の番地で DE レジスタにセットして画面表示し、("BREAK" 以外の場合)続けて " ERROR" を画面表示します。
1385: LD DE, 132Bh # BREAK
138A: LD DE, 1308h # SYNTAX
138F: LD DE, 130Fh # MEMORY
1394: LD DE, 1316h # DATA
1399: LD DE, 131Bh # MISMATCH
139E: LD DE, 1331h # 16FOR
13A3: LD DE, 1337h # 16GOSUB
13A8: LD DE, 133Fh # 6FN
13AD: LD DE, 1348h # FILE
13B2: LD DE, 134Dh # OVERLAY
13B7: LD DE, 1343h # CONT
それからプログラム実行中なら " IN" と文番号を画面表示します。プログラム実行中なら 47FFh〜4800h 番地に文番号があり、この値で判定します。
BREAK IN 100
とか、
SYNTAX ERROR IN 200
と言った感じですね。
それからメインループの先頭である 124Dh 番地にジャンプします。
***
**
*
ここまでで使用しているROMルーチンは、
0006h :改行して行頭にカーソルを移動(CR&LF)
0009h :カーソルが行頭なら何もせずにリターン。それ以外は 0006h 番にジャンプ
0015h :カーソル位置に文字列を表示。DE レジスタで文字列の先頭を指定
0033h :時計を設定
です。
*
ROMルーチン 0009h でのカーソル行頭の判定は、1194h 番地を参照します(1194h 番地が 00h なら RET)。1194h 番地はカーソル位置(のX座標)を管理しているように見えますね。
でもね。カーソル位置は 1171h 番地でX座標(横方向,0〜39)を、1172h 番地でY座標(縦方向,0〜24)を管理しているのです。
同じ情報を別々に管理するのは不自然なので 1194h 番地には 1171h とは違う意味付けがあるはずです。
調べてみると、CURSOR 命令でカーソルを移動すると、1171h にX座標(と 1172h にY座標)をセットして、1194h 番地にも 1171h と同じ値をセットします。同じ値なのです。
一方、PRINT 命令で文字列を表示すると、表示する文字数だけカーソルも移動するので 1171h も1194h も同じだけ増えます。その際に 1171h は0〜39の範囲で変化するのに対して、1194h は0〜79で変化するのです。ここが違います。
更には、ROMルーチン 0009h をコールすると、1171h と 1194h を 00h にして、(改行により画面がスクロールしないなら)1172h は、Y座標の値により 1173h〜118B 番地を参照して 00h なら+1して、00h 以外なら+2するのです。
なんと! 1194h 番地は2行分(80文字)でのカーソル位置を管理していて、そこには文脈依存な何か(1173h〜118B 番地の値)がある感じです。うーむ。謎です。この謎は後で調べましょう。
*
あとは。0033h では時計に 00 時 00 分 00 秒をセットしています。
MZ80の時計は電池でバックアップされた時計ではなくて、秒単位でカウントアップする単なるカウンタです。時刻をセットすれば時計として使えないこともないけど、電源オフしたら消えてしまう。
***
余談になりますが。
ROMルーチンはMZ80の取扱説明書に一覧と解説がありますけれど、SP5030は取説未記載のROMルーチンを使用していて、...0009h のことですが、何をするルーチンか不明でした。
これはしょうがないな、...などと放置していたのですが、未公開ルーチンを解説している雑誌記事を見つけました。
「解析 モニタSP-1002 PART1 MZの思考回路を探る」、Oh!MZ、1982年11月号、p.62-64 と p.97-108(PART2 は 1982年12月号、PART3 は 1983年1月号)
ROMの逆アセンブルリストを全掲載(!)していて、これでROMの中身が判って捗ります。
*
更に余談ですが。この記事のページが分断されているのは雑誌構成の都合かな? この頃のOh!MZは二つ折りのホチキス止めでしたので、普通紙と光沢紙が混じると、...。
***
**
*
初期化の部分を整理したけど読んでも詰まらないよね。ゴメンね。次はメインループに取り組みます。ここは少し動きがあるはずです(?)
***
間違いの指摘とか疑問とか、ご意見・ご感想とかありましたら、どうぞ感想欄に!
***
2026.1.17 加筆。
2026.2.4 微推敲。
2026.3.7 微推敲。




