2026-08-19

「LBUF EQU VTOP+0037H」が0036Hではない謎

共立出版の『マイクロコンピュータのプログラミング』に掲載された東大版Palo Alto Tiny BASICについて調査しています。アセンブラで書かれたプログラムの先頭では、以下のようにメモリ配置が定義されています。

;  MEMORY MAP
ITOP   EQU   0000H
ISIZE  EQU   0800H
LTOP   EQU   1000H
VTOP   EQU   5000H
LBUF   EQU   VTOP+0037H        ;0037H?
LBFSZ  EQU   80
MSTK   EQU   LBUF+LBFSZ
TMSTK  EQU   MSTK+30        ;30?
STACK  EQU   6000H

 

本文では「図3 メモリマップ」として説明されています。VTOPとLBUFの間は「変数エリア」になっています。Tiny BASICですから、プログラムで使える変数は「A」~「Z」と配列「@」の27個に制限されています。また変数に格納できるのは16ビット整数だけです。つまり27種類×2バイト=54バイトあれば良い計算になります。これは、16進数ならば0036Hです。

 

ところがLBUFは、「VTOP+0037H」として定義されています。何故「0036H」ではないのでしょうか。プログラムを解析してみると、ロジックの都合ではないかと思われます。

 

LBUFからLBFSZ(=80)は、「行バッファ」です。キー入力される文字列を格納する領域です。この処理は、次のようになっています。

EDITR: MVI   A,'>'
       CALL  GETL
       PUSH  D
       LXI   D,LBUF
       CALL  GINT
       CALL  SKPBL
       MOV   A,H
       ORA   L
       POP   B
       JZ    KWCPR
INSRT: DCX   D
       MOV   A,H
       STAX  D
       DCX   D
       MOV   A,L
       STAX  D

 

GETLルーチンで入力された文字列は、先頭に数字があるかをGINTルーチンで判断しています。つまり「10 PRINT A」のように入力すると、先頭の数字をバイナリに変換し、数字文字列と置き換えます。また空白も取り除くので、入力された行は、「<0A><00>PRINT A」としてメモリ上に置かれることになります。数字文字列をバイナリに変換した結果を格納しているのが、INSRTで始まる処理です。

 

このようなロジックになっているので、現代的な書き方であるインデントを使用としても、全て取り除かれてしまいます。「10         PRINT A」のように空白を入れても、内部構造は「<0A><00>PRINT A」になります。さらに当時の厳しいメモリ事情の為なのか、Tiny Trekのプログラムでわかるように、意味がとおるなら空白文字を省くことができます。つまり「10PRINT A」としてもエラーではありません。

 

ここで考えなければならないのは、数字文字列をバイナリに変換して格納している点です。バイナリは16bitなので、2バイト必要です。数字文字列が「10」であったり、例え一桁であったとしても「1 PRINT A」のように空白が入っていれば、2文字あるので、16bitのバイナリを格納することができます。ところが「1PRINT A」のような記述を認めているので、数字文字列が1文字しかない場合、16bitのバイナリを格納するには領域が不足してしまうのです。プログラムでは例外処理がありません。どうしているかというと、LBUFの直前にある「変数エリア」に踏み込んでしまうのです。これが「0036H」ではなくて「0037H」になっている理由と思われます。

 

試しに「LBUF EQU VTOP+0036H」としてアセンブルしたプログラムで実験してみました。変数「Z」に何か値を代入しておいて、「1PRINT Z」を入力すると、変数「Z」の値が変わってしまいました。やはり変数「Z」の領域を壊してしまうのです。

 

こうならないようにするため、あえて「LBUF EQU VTOP+0037H」として1バイト分ずらして領域を確保しているのですが、極めて技巧的です。 

0 件のコメント:

コメントを投稿