標準TTLだけ(!)でCPUをつくろう!(組立てキットです!)
(ホントは74HC、CMOSなんだけど…)
[第584回]

●整数BASICコンパイラ(SBASIC)

昨日はホームページの更新ができませんでした。
お盆ですので、お墓参りにも行きましたので、それも理由のひとつなのですが、実はいいかげんにしておかなければ、と思いつつ、ND80ZV組立キットの附属ソフトウェアにもうひとつ追加したいものがありましたので、その動作テストなどをしておりましたら、時間がなくなってしまいました。

何を隠そう、それはBASICコンパイラなのです。
もっとも整数演算のみに限定した、smallなBASICなのですけれど。
それでSBASICです。

ND80ZVの各種説明書もまだ全然手付かずの状態で、こんなことばかりしていてはいけないのですけれど。
でも、ほんとにもうこれだけでとりあえずの作業としては終了、のつもりです。
あとは、それこそ大急ぎで説明書の作業を終えなければなりません。

現在、組立説明書だけは完了しています。
確認してみましたら、1ヶ月前に完了しておりました。
先月7月17日に、その組立説明書に間違いがないことを確認するために、組立説明書を見ながらサンプルとして実際に1セットを組立しましてから、もう1ヶ月が経ってしまいました。

その間ずっと、附属ソフトウェアの作業をしていたのです。
それもやっと終わりに近付きました。
残りの説明書の作業を片付けつつ、ホームページの更新作業も進めていきたいと思います。

そこで、今回は、整数BASICコンパイラのお話です。

●機械語とアセンブラとコンパイラとインタプリタ

ご存知のようにTK80は機械語(マシン語)しか扱えません。
プログラムは、レアな16進コードのまま入力します。
ND80ZVも基本的な機能としては、TK80と同じです。
ボード上のキーから16進コードを入力して、それを7segmentLEDに表示させながら、プログラムの入力、デバッグ、実行まで行います。

機械語コードを直接入力するという方法は、簡単なプログラムならばそういう方法でもなんとかなるのですけれど、大きなプログラムには不向きです。
ND80ZVはUSB(HID)でWindowsパソコンと接続して、リモート+Z80BASICシステムを実行させることができます。

ND80ZV組立キットの附属ソフトウェアとして、Z80アセンブラも付ける予定ですから、少し大きなプログラムなら、Z80アセンブラを利用して、プログラムを作成することもできます。
アセンブラを使えば、機械語で直接プログラムを書くことに比べれば、その能率は飛躍的に向上します。
しかし、アセンブラでのプログラミングは、基本的には機械語のプログラミングと同じ技術レベルを必要とします。

Z80の機械語命令の働きが理解できなければ、アセンブラを使ったとしてもまともに動作するプログラムを書くことはできません。
機械語のプログラムやアセンブラでのプログラムに比べれば、BASICでのプログラムははるかに容易です。
機械語のプログラムでは、1回で、正しく動作するプログラムを書くことは難しくて、結果としてハングアップや暴走をしてしまうことは、ありがちなことです。

しかしBASICでのプログラムでは暴走やハングアップをしてしまうことは、まれです。
あきらかな文法的なミスはエラーメッセージによって知ることができます。
また簡単に直して再実行することも手軽にできますから、その扱いやすさは、機械語の比ではありませんし、アセンブラに比較しても、BASICの簡便さは、比べ物になりません。

それではBASICには欠点はないのか、と言いますと、BASIC、ことにZ80BASICのようなインタプリタの最大の弱点は、その実行速度です。
BASICインタプリタは遅いのです。
そりゃあもちろん、人間が考えたり、計算したりするよりは、はるかに速く実行できますが、機械語のプログラムとは比較できないほど遅いのです。
特にZ80BASICはいろいろな機能をいっぱい詰め込んでしまいましたので、それだけ余計に遅いのです。

しかし中には、そんなにあれこれいろんな機能は必要無いし、整数の計算のみができればいいので、もう少し速くできるといいのだが、という用途もあると思います。

そこで、機械語プログラムほどは速くできないけれど、Z80BASICインタプリタよりは速い、整数演算限定のBASICコンパイラを用意しました。
計算できる値は、16ビットの整数に限られます。
−32768〜+32767の範囲の整数と0しか扱えません。
整数型変数と整数型の一次元配列が使えます。
計算は、+−*/記号による加減乗除で()の使用もできます。
文字変数、文字定数の使用や、PRINT文も使用できます。

SBASICのソースプログラムはメモ帳などのテキストエディタで作成します。
その後、SBASICコンパイラによって、機械語のバイナリファイルを作成します。

ソースプログラムの作成やコンパイル作業は、Windowsパソコン上で行います。
そのときは、ND80ZVをUSB(HID)で接続しておく必要はありません。
しかしSBASICでのコンパイルの結果作成される機械語のバイナリファイルは、必要に応じて、ND80ZVのシステムROM内のBASICルーチンをCALLするようにプログラムされますから、ND80ZVをUSB(HID)でWindowsパソコンと接続して、Z80BASICを起動したうえで、ND80ZVのRAMエリアにロードして実行する必要があります。
たとえCPUがZ80であったとしても、ND80ZV以外のシステムでは、SBASICでコンパイルした後のバイナリファイルのプログラムを実行させることはできません。

●簡単なテストプログラムを作って実行してみました

おもに実行速度を比較できるように、同じ動作を、機械語のプログラムやZ80BASICでも作って動作させてみました。
まずはもっとも簡単なパルス出力プログラムです。
これはZ80BASICです。

    10 OUT $83,$80
    20 OUT $80,0
    30 OUT $80,1
    40 GOTO 20

82C55のAポートのbit0からLとHを交互に出力しています。
最初のOUT $83,$80はA〜Cポートの向きを出力に設定するためのコントロールワードの出力です。

プログラムの実行結果です。

パルス幅は0.5msecほどです。
Hの方が少し長いのは、GOTO 20の実行時間も加わっているからです。
Z80BASICインタプリタでは、これよりも短いパルスを出力することはできません。

今度は同じことを、機械語で書いて実行してみました。

簡単なプログラムですから、Z80アセンブラは使わないで、CM(chenge memory)コマンドを使って機械語の命令コードをダイレクトに書き込んでJPコマンドで実行しました。
アセンブラのニーモニックで表記すると以下のようになります。
8004 3E80    LD A,80
8006 D383    OUT (83),A
8008 D380    OUT (80),A
800A 3C      INC A
800B C30880  JP $8008

あれ?
違ってますねえ?
今、気がつきました。
CMコマンドで書いたプログラムはOUT命令(D380)がダブッています。
間違いではありませんけど、それだけ実行時間が余分にかかります。

実行結果です。

OUT命令がダブッていてもこの速さです。
パルス幅は5μsecほどですから、BASICプログラムに比べて100倍の速さです。
さすが機械語プログラムです。

うう。
やっぱりみっともないですから、プログラムを書き直して、もう一度写真も撮り直すことに致しました。


こちらが実行結果です。

おお。さらに速くなりました。
OUTとINCとJPを繰り返し実行していますから、その実行時間はそれぞれの命令の実行クロック数から計算で求めることができます。
OUTは11、INCは4、JPは10クロックですから合計25クロックです。CPUクロックは6MHzですから、25/6=4.17μsecです。
ぴったり合っています。

そしてこれがSBASICのソースプログラムです。
メモ帳(notepad)で書きました。

'SBASIC TEST1 10/8/16
        ORG=$8004
	OUT $83,$80
*LOOP:OUT $80,0
	OUT $80,1
	GOTO *LOOP

SBASIC.COMを実行して、SBTEST1.TXTをコンパイルします。
まだチェック中ですから、バージョンを示す_6がついて、SBASIC_6.COMになっています。

コンパイルの結果、バイナリファイルsbtest1.binと情報ファイルsbtest1.wkが作成されました。
参考までに、どのようなバイナリファイルができたのか、Z80逆アセンブラZDAS.COMでsbtest1.binを逆アセンブルしてみました。
あ、と。開始アドレス8004を与えることを忘れていました。
8004をつけてやり直しました。

ZDASによって逆アセンブルしてできたリストです。

8004 218300         LD HL,$0083
8007 4D             LD C,L
8008 218000         LD HL,$0080
800B ED69           OUT (C),L
800D 218000         LD HL,$0080
8010 4D             LD C,L
8011 210000         LD HL,$0000
8014 ED69           OUT (C),L
8016 218000         LD HL,$0080
8019 4D             LD C,L
801A 210100         LD HL,$0001
801D ED69           OUT (C),L
801F C30D80         JP $800D
8022 C9             RET

なんだかまわりくどいことをやっていますが、これはコンパイラが整数値を、16ビットの値として、まずHLレジスタに格納するように働くためにこうなってしまうのです。

さきほどのSBASICコンパイラの実行でバイナリファイルと一緒に作成された、sbtest1.wkの内容も見てみましょう。

0000 'SBASIC TEST1 10/8/16
0000    ORG=$8004
8004 	OUT $83,$80
800D *LOOP:800D OUT $80,0
8016 	OUT $80,1
801F 	GOTO *LOOP
8022 

このリストと、上の逆アセンブラリストを付き合わせてみることで、コンパイラがもとのBASICの命令をどのように機械語の命令に翻訳したのかを知ることができます。

SBASICコンパイラで作成されたバイナリファイルはND80ZVにロードしてから実行します。



実行結果です。


Hが8μsecでLが6μsecです。
機械語コードをダイレクトに入力して作成したプログラムに比べれば、実行時間は遅くなってしまいますが、それでもBASICインタプリタに比べれば驚異的な実行速度です。
2010.8.16upload

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