6800の分岐命令とインタプリタ(ベーシックマスター開発 その31)

BASICMASTER, 昔のパソコン

MC6800の分岐命令が面倒臭いのは6800の分岐命令(ベーシックマスター開発 その30) | ず@沖縄で書いた。

MC6800でなくても、CPUの扱えるレジスタ長を超えると大小比較は面倒くさくなる。

その面倒臭さを当時のインタプリタはどう扱っていたかを、書き残しておく。

NAKAMOZU Tiny BASIC

比較演算子を構文解析し、下記の数値に置き換える。電大版TinyBASICも同様の処理を行なっている。


EX11    ORAB    #1              ; 比較論理演算
        FCB     $8C             ;  チェック
EX12    ORAB    #2
        FCB     $8C             ; 結果AccB
EX13    ORAB    #4              ; >  0000 0001
        INX                     ; =  0000 0010
        FCB     $C1             ; <  0000 0100
EX14    CLR B                   ; >= 0000 0011
        BSR     PKUP            ; <= 0000 0110
        CMP A   #'>'            ; <> 0000 0101
        BEQ     EX11
        CMP A   #'='
        BEQ     EX12
        CMP A   #'<'
        BEQ     EX13
        CLR A
        RTS

次に右式-左式を行って、立ったフラグと上記の数値を比較して分岐する。結果は1か0である。

左-右ではなく、右-左なのはインタプリタが素直に左から解釈しているから。左を計算してPSHして、右を計算してTSX/SUBA 1,X/SBCB 0,Xで計算を行なっている。

(NAKAMOZU/電大Tinyは上位バイトがB,下位バイトがAなので、見慣れないとびっくりする)

引き算が左-右ではなく、右-左になっていて逆なので前回記事の分岐表をひっくり返す必要がある。


EXPR    BSR     EX1
        BSR     EX14            ; 論理演算チェック
        TST B
        BEQ     RTN8
        PSH B
        BSR     EX1
        JSR     CPUL            ; 演算(再帰的)
        LDX     CSP             ; BAは後の数
        SUB A   1,X             ; 比較
        SBC B   0,X             ; 後-前
        PUL B
        BLT     LT              ; 論理演算
        BGT     GT
        TST A
        BEQ     EQ
GT      ASR B
EQ      ASR B
LT      AND B   #1
        STA B   1,X
        CLR     0,X

単に比較する場合と比べて 実行時間は多くかかるが、そもそもインタプリタなので字句解析や構文解析に多大な時間がかかっている。

メモリの節約と実行時間のどちらを取るかの判断で、メモリ節約を選んだのだろう。メモリの1バイトは血の1バイト。

GAME言語

構文解析中に関係演算子が見つかったら、左式-右式を計算して 0 or 1 を返している。左-右なので、前回記事の表の通りに分岐命令を書けば良い。

NTB/電大 Tiny BASICよりメモリは食うが、高速である。


LT	PULA
LESS	BSR	SUB
	BLT	TRUE
FALSE	CLRA
	CLRB
	RTS


FALSEで分岐するかTRUEで分岐するか

2バイトが一致しないことの比較(!=)をして、0か1を返すサブルーチンを考えよう。

メモリを節約することを考えると、引き算して一致した場合は0になるのでこれをそのままFalseとして返すと良い。するとコードはこうなる。


	SUBB	下位バイト
	SBCA	上位バイト
	BNE	True
	TSTB
	BNE	True
	RTS			// ここに来る時は AccA,B==0 なのでそのままFalseとして返す
True	LDAB	#1
	CLRA
	RTS

論理を逆転して、一致しなければラベルに分岐、一致してTの場合はスルーして通り抜けるようなコードになる。

では、全パターンそれでうまくいくかというとそうではない。一致の比較だと、抜けてきた時にAccAB=0なので、これを利用したい。するとこうなる。

True1,2を分けているのは、2番目のBNEで分岐したときはAccA==0なので、Bだけクリアすれば良いから。

この場合は、スルーした時がTになる。


	SUBB	下位バイト
	SBCA	上位バイト
	BNE	True1
	TSTB
	BNE	True2
	INCB			// ここに来る時は AccA,B==0 なので、+1して返す
	RTS			
True1	CLRA
True2	CLRB
	RTS

比較の条件によって、最適なパターンが異なるので非常にややこしいです。

メモリを節約したい場合は、実行時間を考えずにTrue/Falseの分岐先を作ってそこに分岐すればOKです。KUMAJIRIのK-CPUはそのパターン。