2020.8.7
前へ
次へ
ホームページトップへ戻る

[新連載]復活!TINY BASIC
〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜
すべてはここからはじまりました。
中日電工も。
40年前を振り返りつつ新連載です。
〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜



[第58回]


●FORプログラム(3)

前回の続きです。



さて。
皆様。
コード3Eの意味がおわかりになりましたでしょうか。

こういう場合には、もしコード3Eがなかったらどうなるか、を考えてみると答えに近付くことができると思います。
すると。
アドレス0231のDAD Bが実行されることになります(FR7:)。
この直前のHLにはSPの値が入っています。
「このときSPで示すメモリアドレスにはPUSHAでスタックに保存したひとつ前のLOPVARの値が入っています。」
と前回書きました。
BCレジスタには000A(=10)が入っています。
そこでDAD Bを実行するとHLは現在のSPから10バイト深い位置のアドレスになります。
スタックに退避されるFOR変数領域は10バイトです。
現在のSPのアドレスに+10バイトを加算したアドレスには「もうひとつ前のFOR変数領域」が退避されているはずです。
0232〜023Bでは最初にそのアドレスの値(「もうひとつ前」のLOPVARの値)が0かどうかをチェックします。
0ならはそれよりも前に退避されているFOR変数領域はないことになりますから、FOR文を終了して次の命令の実行に進むためにFR8:にジャンプします。
FR8:ではLHLD LOPPTを実行します。
LOPPTにはFOR文の次のメモリアドレスが入れられています。
XCHGでそれをDEレジスタに移し換えたあと、RST 6を実行します。
RST 6は[第12回]で少しだけ説明をしました。
そこでCALLされているFINについては[第23回]で説明をしていますので参照願います。

スタックに保存されているLOPVARの値が0ではなかった場合にはその値(HLが示すメモリの値とHL−1が示すメモリの値)をD、Eと比較します。
DEには現在のLOPVARの値が入っています。
一致したときは0243以降が実行されます。
その内容については後で説明をすることにします。
一致しなかったときにはFR7:に戻ってHLにBCが加算され、さらに前に退避されたFOR変数領域のチェックをすることになります。

さてここまでのプログラムの流れはごく自然のように思えます。
結局のところコード3Eはなくても何も問題はないのではないか?
ところがそれが大有りなのです。

もう一度説明の最初のところを再記します。
アドレス0231のDAD Bが実行されることになります(FR7:)。
この直前のHLにはSPの値が入っています。
「このときSPで示すメモリアドレスにはPUSHAでスタックに保存したひとつ前のLOPVARの値が入っています。」
と前回書きました。

前回はそれに続けて下のように書きました。
「まずはその値と今回のLOPVARの値(DEに入っています)とを比較して、一致、不一致の判定をします。」

そうなのです。
DAD Bを実行する直前のHL=SPが示すメモリには、「ひとつ前」のLOPVARの値が入っているので、まずはその値が0なのかどうか、そしてDEと一致するかどうかを確認しなければならないのです。
ところがそこでDAD Bを実行してしまうと、その作業が行なわれないまま「もうひとつ前」のLOPVARの確認が行なわれることになってしまいます。
つまり、一回目の確認作業のときには、DAD Bを実行せずに、そのときのHLの値のままで、アドレス0232以降のプログラムを実行する必要があります。
普通はこういう場合には以下のようにプログラムします。

      DAD SP
      JMP FR72
FR7:DAD B
FR72:MOV A,M

これならわかりやすいプログラムになります。
しかしそのようにすると新たに追加するJMP命令のために3バイト余分にメモリを消費してしまいます。
何回も書いていますように当時はROMもRAMも高価でした。
多少わかりやすさを犠牲にしてでも1バイトでも短いプログラムになるようにしたい、とおそらくTINY BASICの作者は考えたのではないかと推察します。
ちなみに1980年当時、秋葉原で2KBのROM2708は2500円だったと記憶しています。
TINY BASICプログラムは0000〜0768です。
当時の雑誌に掲載されたTINY BASICプログラムは、その記事によると2KBのROM2708に書き込まれて動作したと書かれています。
2KBの終わりは07FFですから、残りはわずか152バイトです。
そのことから考えると1バイト、2バイトを短縮するために通常はやらないような工夫までして努力したのではと思われます。
あるいは、当時のプログラマの常識として、常により短いプログラムを書くことを一番にする、というようなことがあったのかもしれません。
本当のところはどうであったのか、それはよくわかりませんが、とにかくTINY BASICのプログラムには、そうでも考えないと納得できないようなところが随所に見られます。

本題に戻ります。
上記の仮定に基けば、ここでは追加しなければならないJMP命令を使わないで、DAD Bを「ジャンプ」することを考えることになります。
そこでコード3Eの登場です。
前回書きましたようにコード3EはMVI A,nのマシン語コードです。
しかしここでMVI A,nを使う意味はない、ということは前回に書きました。
なぜならその直後にMOV A,Mが実行されるため、その前に実行されるMVI A,nは全くの無駄作業になってしまうからです。
確かに一見すると無駄なのですが、しかし実のところ無駄などでは全くありません。

DAD B(コード09)の前に3Eを置くことで、それはMVI A,nという命令になります。
マシン語コードとともに記すと下のようになります。

0230 3E09 MVI A,09
0232 7E   MOV A,M

コード09が本来のDAD BではなくてMVI A,nのオペランドにされることで、命令としては実行されないことになります。
確かに1バイト余分に消費しますがJMPの3バイトに比べると2バイト少ないプログラムサイズでJMPを使う場合と全く同じ結果が得られます。
さすが。
熟練の技であります。

が。
メモリもハードディスクも大容量のものが安価に供給されるようになり、CPUの速度も当時とは比べ物にならないほど超高速になった今日においては、余程特殊な場合を除いては1バイト、2バイトを削減するためにアセンブラでプログラムすることにはほとんど意味がなくなってしまいました。
マシン語にすればわずか数十ステップで済むようなプログラムを巨大なCコンパイラによって数十キロバイトのプログラムとして生成するほうが簡単でよいという時代になってしまいました。
今更8080のプログラムテクニックを学んだとて、一体何になるの?
という声が聞こえそうです。

うーん。
返答に窮するのでありますが。

ま。
そう難しく考えないで。
知識欲。好奇心。
過ぎ去った青春を懐かしんで。
等々。
肩の力を抜いて行きましょう。

と。
そのように書いたのでありますが。
何だか3Eのところの説明に、つい力が入り過ぎてしまったようです。
うっかりして、アドレス0243から後ろの部分の説明をまだしていませんでした。
でも今回は時間がなくなってしまいましたので、0243から後ろについては次回に書くことにいたします。

復活!TINY BASIC[第58回]
2020.8.7upload

前へ
次へ
ホームページトップへ戻る