ワンボードマイコンをつくろう!(パソコンの原点はここから始まった)
TK80ソフトコンパチブル!8080、Z80マシン語からBASICまでこれ1台でこなせます
当記事は2009年11月から「TTLでCPUをつくろう!」というタイトルの もとにほとんど毎日連載をしてきたものを再編集したものです。 2011.7.4
前へ
次へ
目次へ戻る
ホームページトップへ戻る
☆整数BASICコンパイラ
ND80ZVには浮動小数点計算のできるBASIC機能が搭載されていて、パソコンとUSB接続した環境で使うことができます。
ND80ZVに搭載されているBASICはインタプリタですが、それとは別にND80ZVには整数BASICコンパイラも附属しています。

[第83回]

●整数BASICコンパイラ(SBASIC)の続きです

今回も前回に続いてSBASICについてのお話です。
前回はI/Oポートにパルスを出力する簡単なプログラムを、機械語(マシン語)、Z80BASICインタプリタ、そしてSBASICコンパイラでそれぞれ作って、実行した結果をオシロスコープで見てみました。

一番短い幅のパルスを出力する、といった意味合いのプログラムでしたから、それはそれなりに意味のあるプログラムですけれど、余りに簡単すぎました。
とにかくOUT文とGOTO文しかありませんから、これではBASICのありがたみもちょっと実感できそうにありません。

そこで今回はもう少し、といっても本当に少しだけなのですが、長いプログラムを作って、前回と同じようにオシロスコープで見て比較してみたいと思います。

前回と同じように、まずはZ80BASICです。

    10 OUT $83,$80
    20 A%=100
    30 B%=0
    40 OUT $80,0
    50 B%=B%+1:IF B%<=A% GOTO 50
    60 B%=0
    70 OUT $80,1
    80 B%=B%+1:IF B%<=A% GOTO 80
    90 GOTO 30

今回はパルスに幅を持たせました。
最初はB%=0からスタートして、1ずつ加算して、B%=100になるまで、100回加算を繰り返します。
B%=100になったら82C55のAポートのビット0出力を反転し、またB%=0からスタートして、B%=100になるまで、100回加算を繰り返します。
B%=100になったら、また82C55のAポートのビット0出力を反転し、これを繰り返します。

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

出力がH、Lの間にそれぞれ加算(B%=B%+1)と比較(IF)とGOTO文を100回繰り返しています。その実行時間は約130msecです。

今度は機械語(マシン語)のプログラムです。
前回は16進数の命令コードをダイレクトに入力しましたが、今回は数値の比較を行うところがありますから、Z80アセンブラを使うことにしました。

アセンブラのソースプログラムです。
メモ帳(notepad)で書きました。

;ASMTEST2 10.8.17
	ORG $8050
	VAP=$F440
	VBP=$F442
;
	LD A,80
	OUT (83),A
LOOP0:OUT (80),A
	LD DE,(VBP)
LOOP1:LD HL,(VAP)
	OR A
	INC DE
	SBC HL,DE
	JP NZ,LOOP1
	INC A
	JP LOOP0

今回のプログラムは、Z80BASICのサブルーチンとして書きました。
もっとも、この機械語プログラムの中でずっとループし続けますから、BASICプログラムにはリターンしませんけれど。
BASICのメインプログラムからA%の値とB%の値をもらいます。
Z80BASICは整数型の変数A%〜Z%、文字型の変数A$〜H$を固定したメモリエリアに置いています。
A%はF440、B%はF442にあります。
A%〜Z%、A$〜H$のアドレスはいつも同じアドレスになっていますから、それらの変数の値を、BASICプログラムから機械語のサブルーチンに渡したり、その逆に機械語サブルーチンで処理した結果を、それらの変数エリアに書き込むことで、結果をBASICのメインプログラムに渡すことができます。

プログラムはDEレジスタの値を+1(インクリメント)して、その結果をHLレジスタの値と比較しています。
Z80には16ビットの数を比較する命令はありませんから、DEとHLとの比較を行うのに、減算命令SBC HL,DEを利用しています。
その前にあるOR AはSBC HL,DEでキャーリーを引いてしまわないようにするために、キャリーをクリアする目的で使っています。

Z80アセンブラ(ZASM.COM)でアセンブルして機械語(マシン語)のバイナリファイルを作成します。


Z80BASICを起動して、バイナリファイルをロードします。

NEWコマンドはBASICプログラムを格納する開始アドレスを指定するコマンドです。
Z80BASICが起動した直後は、BASICプログラムの格納開始アドレスは8004になります。
今回は機械語のプログラムを8050から実行開始するように書きましたから、そのプログラムのロードするエリアを確保するために、NEW,8100を実行しています。
BASICのメインプログラムはA%とB%の値を定義して、機械語サブルーチンコール命令USR()を実行するだけのプログラムです。
USR()命令の()の中には機械語サブルーチンのエントリアドレス(スタートするアドレス)を指定します。

実行結果です。

100回の加算(インクリメント)と比較(減算)とジャンプ命令の実行時間は0.8msecほどです。

そして、次はSBASICです。

'SBASIC TEST2 10/8/17
	ORG=$8004
	OUT $83,$80
*LOOP:B%=0
	OUT $80,0
*LOOP1:B%=B%+1:IF B%<=A% GOTO *LOOP1
	B%=0
	OUT $80,1
*LOOP2:B%=B%+1:IF B%<=A% GOTO *LOOP2
	GOTO *LOOP

BASICインタプリタのプログラムとほとんど同じです。

SBASICコンパイラで機械語のバイナリファイルを作成します。

前回と同じように、コンパイルの結果作成されたバイナリファイルsbtest2.binを逆アセンブラZDAS.COMで逆アセンブルしてみました。

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

8004 218300         LD HL,$0083
8007 4D             LD C,L
8008 218000         LD HL,$0080
800B ED69           OUT (C),L
800D 210000         LD HL,$0000
8010 2242F4         LD ($F442),HL
8013 218000         LD HL,$0080
8016 4D             LD C,L
8017 210000         LD HL,$0000
801A ED69           OUT (C),L
801C 2A42F4         LD HL,($F442)
801F E5             PUSH HL
8020 210100         LD HL,$0001
8023 D1             POP DE
8024 CD643E         CALL $3E64
8027 2242F4         LD ($F442),HL
802A 2A42F4         LD HL,($F442)
802D E5             PUSH HL
802E 2A40F4         LD HL,($F440)
8031 D1             POP DE
8032 B7             OR A
8033 ED52           SBC HL,DE
8035 CB7C           BIT 7,H
8037 210100         LD HL,$0001
803A 2803           JR Z,03
803C 2D             DEC L
803D 1802           JR 02
803F 7D             LD A,L
8040 B7             OR A
8041 C21C80         JP NZ,$801C
8044 210000         LD HL,$0000
8047 2242F4         LD ($F442),HL
804A 218000         LD HL,$0080
804D 4D             LD C,L
804E 210100         LD HL,$0001
8051 ED69           OUT (C),L
8053 2A42F4         LD HL,($F442)
8056 E5             PUSH HL
8057 210100         LD HL,$0001
805A D1             POP DE
805B CD643E         CALL $3E64
805E 2242F4         LD ($F442),HL
8061 2A42F4         LD HL,($F442)
8064 E5             PUSH HL
8065 2A40F4         LD HL,($F440)
8068 D1             POP DE
8069 B7             OR A
806A ED52           SBC HL,DE
806C CB7C           BIT 7,H
806E 210100         LD HL,$0001
8071 2803           JR Z,03
8073 2D             DEC L
8074 1802           JR 02
8076 7D             LD A,L
8077 B7             OR A
8078 C25380         JP NZ,$8053
807B C30D80         JP $800D
807E C9             RET

ソースプログラムは短いものでしたが、コンパイルの結果作成された機械語のプログラムはこんなに長いものになりました。

SBASICコンパイラでバイナリファイルとともに作成されたsbtest2.wkファイルです。

0000 'SBASIC TEST2 10/8/17
0000 	ORG=$8004
8004 	OUT $83,$80
800D *LOOP:800D B%=0
8013 	OUT $80,0
801C *LOOP1:801C B%=B%+1:802A IF B%<=A% GOTO *LOOP1
8044 	B%=0
804A 	OUT $80,1
8053 *LOOP2:8053 B%=B%+1:8061 IF B%<=A% GOTO *LOOP2
807B 	GOTO *LOOP
807E 

SBASICコンパイラで作成された、機械語のバイナリファイルは、Z80BASICを起動してから、/LDコマンドでメモリにロードします。

さきほどの機械語サブルーチンと同様に今回コンパイルの結果作成された機械語のプログラムもBASICプログラムのサブルーチンとして実行します。
機械語サブルーチンは通常のBASICプログラムが開始される8004にロードされましたが、さきほどの機械語サブルーチンのテストのときに、BASICプログラムは8100から作成して、それがそのまま残っていますから、今回の機械語プログラムを8004からロードしても、BASICプログラムは破壊されずにちゃんと残っています。

実行した結果です。

最初のBASICインタプリタのプログラムと同じように、100回の加算と比較とGOTOが実行されていますが、4.4msecほどです。
アセンブラで作成した機械語のプログラムは0.8msecでしたから、それよりは遅いのですけれど、インタプリタのプログラムは130msecでしたから、それと比較すれば、桁違いに速い、ということが言えます。
CPUをつくろう!第585回(2010.8.17upload)を再編集


ワンボードマイコンをつくろう![第83回]
2011.7.4upload

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