ベーシックマスターのソフトウェア(8)BASICプログラム領域の謎を解く

BASICMASTER, 昔のパソコン

以下、ベーシックマスターのハードウェア(2)グラフィック画面のアドレスの続きなのだが、ソフトウェアの話になる。

先の記事では、グラフィック画面の開始アドレスやBASICプログラムの格納開始アドレスが、資料によっては$0A00と書かれていると書いた。実装では$0900なので、誤った情報が書かれているわけだ。

別件で資料を調べていたら、bit臨時増刊「パーソナル・コンピュータの使い方」でも、BASIC領域は$0A00-$7FFFと書かれていた。

bit増刊記事はベーシックマスターレベル2を対象としている。1980年1月出版なので、記事が書かれたのはMB-6881L2IIが出る直前だと思われる。

bit臨時増刊「パーソナル・コンピュータの使い方」 p.244 より引用


L2 BASICのSIZEコマンド

bit増刊の記事ではフリーエリアが30208バイト(32KB実装時)と書かれていたので、実機のSIZEコマンドで確認してみた。$A00と$900の違いでサイズは変わるはずだし。

PROGRAM=$0A00になっていて、REMAIN=42495 ($AFFF-$0A00)である。POKE 8,$7Fとして32KBに偽装するとREMAIN=30207である。1バイト違うけど、ほぼ記事通り。

ここでも$0A00なのか! (なんで今まで気がつかなかったんだ、俺?)




マニュアルにも$0A00開始と書かれている。以下の記述はL2IIのマニュアルからの引用だが、Jr.でも同じである。

「ベーシックマスターレベル2II 取扱説明書」p.40 より引用



SIZEコマンドのPROGRAMで表示される値よりも前の部分(上図のプログラムエリア)には、ダイレクトコマンドのワークも含まれる。

以下、L2IIマニュアルより引用(Jr.のマニュアルではp.135)。

「ベーシックマスターレベル2II 取扱説明書」p.117 より引用


SIZEコマンドの内部

L2II/Jr.のL2 BASICのソースを見ると以下のようになっている。L2用でもロジックは一緒である。

BASICの格納アドレスの末尾(basic_tail)に$FBを足した結果をPROGRAMとして表示している。

VARIABLEは変数領域の先頭で、電源ON/NEWの直後はメモリ末尾を指している。

REMAIN(残りメモリ領域)を計算するときは、calc_REMAIN($BC6B)を実行している。これは確保済みの変数領域の先頭アドレスからBASICプログラム末尾のアドレスを引いて、さらに$00FBを引いた結果を返すルーチンである。

このルーチン(calc_REMAIN)は変数領域を確保する時にも使われていて、結果が負であれば MEMORY FULL ERROR になる。


SIZE    JSR     ZBD63                    ;BC45: BD BD 63       '..c'
        LDX     #mPROGRAM                ;BC48: CE BC 7C       '..|'
        BSR     ZBC20                    ;BC4B: 8D D3          '..'
        LDX     basic_tail               ;BC4D: DE 78          '.x'
        LDAB    #$FB                     ;BC4F: C6 FB          '..'
        JSR     ADDIXB                   ;BC51: BD F0 03       '...'
        BSR     ZBCA1                    ;BC54: 8D 4B          '.K'
        LDX     #mVARIABLE               ;BC56: CE BC 89       '...'
        BSR     ZBC20                    ;BC59: 8D C5          '..'
        LDX     variable_area_top        ;BC5B: DE 7A          '.z'
        BSR     ZBCA1                    ;BC5D: 8D 42          '.B'
        LDX     #mREMAIN                 ;BC5F: CE BC 96       '...'
        BSR     ZBC20                    ;BC62: 8D BC          '..'
        BSR     calc_REMAIN              ;BC64: 8D 05          '..'
        BSR     outAccAB_dec             ;BC66: 8D 9F          '..'
ZBC68   JMP     ZB04B                    ;BC68: 7E B0 4B       '~.K'
calc_REMAIN LDAA    variable_area_top        ;BC6B: 96 7A          '.z'
        LDAB    M007B                    ;BC6D: D6 7B          '.{'
        SUBB    #$FB                     ;BC6F: C0 FB          '..'
        SBCA    #$00                     ;BC71: 82 00          '..'
        SUBB    M0079                    ;BC73: D0 79          '.y'
        SBCA    basic_tail               ;BC75: 92 78          '.x'
        BCC     ZBC7B                    ;BC77: 24 02          '$.'
        CLRA                             ;BC79: 4F             'O'
        CLRB                             ;BC7A: 5F             '_'
ZBC7B   RTS                              ;BC7B: 39             '9'

電源投入後の$0900-の状態を見てみると、FF FF 05 17 0D 00 00 05 15 0D が入っている。

この時のbasic tailは$0905で、FF FF 05 17 0D の次を指している。つまりNEW直後でも5バイトは使われている。$0905に$FBを足すと$0A00になる。

L2II BASICの中間言語として読むと、"65535 END" になる。FFFFは行番号、05は行長(5バイト)、17がEND、0Dは行末である。

この5バイトはLISTコマンドでも見えない。プログラム末尾にENDを書いていないプログラムを救うために番兵(sentinel)として配置されているのだろう。

その後ろの 00 00 05 15 0D は MONコマンドを入力した残骸である。ダイレクトコマンド実行時は、BASICプログラム以降の領域に中間コードを入れてそれを実行している。

L1 BASICのSIZEコマンド

ちなみにL1 BASICの場合は、こう説明されていたようだ(マニュアルが入手できていないので、雑誌記事から引用)。

S=で示されているアドレスは、BASICプログラムの最終番地である。ユーザーが使えるのは S+1以降。

ダイレクトコマンドのワーク領域は$540-にあり、BASICプログラムは$5C0-から入っている。番兵のENDと行末が9バイト使うので、起動直後はS=$05C8となる。

電子展望 1978年9月号 「日立ベーシックマスター活用のキーポイント」 p.41 から引用


SIZEコマンドのPROGRAMの意味

ここまで書いて思ったのだが、SIZEコマンドのPROGRAMの表示は「BASICプログラムの末尾+1」ではなく、「機械語プログラムが使って良いアドレスの先頭」を意味しているように思える。


L1 BASICでは、Sの次のアドレスから 機械語プログラムを入れることができた。

ダイレクトコマンドで使う領域がBASICプログラム領域より若い番地にあるので、プログラム最終アドレスをそのまま表示しても困らない。

利用者は最終アドレス+1以降を使えば良い。


ところが L2 BASICでは、ダイレクトコマンドはワーク領域として、BASICプログラム末尾以降を使う。

最終アドレスをそのまま表示したのでは、利用者がどこから機械語プログラムを入れて良いかわからない。

ダイレクトコマンドが使う分だけ、後ろにずらす必要がある。

この時点で意味合いが「機械語プログラムが使って良いアドレスの先頭」になっている。意味が変わったので、表示もS=ではなく PROGRAM= になったのかもしれない。

そして、SIZEコマンドの表示がPROGRAMであることで、この数値はBASICプログラム開始アドレスとして誤解され、そのようにマニュアルにも記載され、後々の混乱を招いたのかもしれない。

SIZEコマンドのマージン($FB)の意味

では、どれだけ後ろにずらせばいいのだろうか?


マージンとしては、見えないENDの5バイト+ダイレクトコマンドの最大長であれば良い。

ダイレクトコマンドとして入力できる文字数は1行79文字だが、これを中間言語に変換したときにはバイト数が増える場合がある。

たぶん、最大になるのは ? 1,1,1,1,1…1,1 (1が39個)のときで、$09CBまで使われる。

(数値は中間コードでは4バイトになる。","が38個で各1バイト、?は内部コードで1バイト。さらに行番号と行サイズと行末がつく。39*4 + 38 + 1 + 3 = 237バイト。見えないENDが5バイト、合計242バイト。$0900 + 242 = $09cc が空き領域の先頭になる)

マージンとしては$cb以上なら何バイトでもいいはずだが、NEW直後にキリのいいアドレス($0A00)を表示するために選ばれた値が$FBかもしれない。

余談

変数確保時のマージン計算はunsignedで行われていて、正しく確保できるのだけど、実際に配列参照を行うと $8000をまたぐ部分でおかしくなる。

下記のプログラムを64KB実装のJr.で実行すると、ERROR 17になる。実行前に POKE 8,$7F として RAM末を$7FFFに変更すると、問題なく実行できる。

エラー時のIは1544、配列先頭アドレスは$61D8なので、参照アドレスは$8000である($61D8+5*1544=$8000)。


10 DIM A(4000)
20 FOR I=1 TO 4000
30 LET A(I)=$1234
40 NEXT I


日立アセンブラも64KB実装では動かないバージョンがあったし、アドレスの扱い難しいですね。
(実際 C言語でもアドレス計算でハマることはありますし)。

資料

  • bit臨時増刊「パーソナル・コンピュータの使い方」 「ベーシックマスター」 pp.239-254
  • インターフェース1980年2月号 「ベーシックマスター拡張・汎用ラボオート装置の制作」 pp.61-88 (レベルIIの一部回路図)
  • インターフェース1980年6月号 「ベーシックマスター用高解像度カラーグラフィック装置の制作」 pp.122-134
  • インターフェース1981年5月号 「ベーシックマスター・レベルIIの回路図解剖」 pp.165-177 (MB6881の全回路図)
  • I/O 1982年3月号 「ベーシックマスターJr.全回路図集」pp.198,291-299
  • I/O 1982年4月号 「Jr.カラーアダプタ[全回路図公開]/アセンブラ」 pp.304-306
  • I/O 1982年5月号 pp.337-347 「Jr.カラーアダプタ・グラフィック・ユーティリティ」
  • ベーシックマスター活用研究 : Level 3,Jr – 国立国会図書館デジタルコレクションpp.95-
  • テクノポリス 1982年10月号記事「ゲームのためのマシン語講座」pp.145-150
  • 月刊RAM 1982年2月号 「ベーシックマスターJr.の可能性を探る」pp.74-80 の図1メモリマップ(p.76)
  • BMUG会報 1982年7月号P.10
  • BMUG会報 1983年5月号P.3
  • BMUG会報 1984年12月号 P.4