ワンボードマイコンをつくろう!(パソコンの原点はここから始まった)
TK80ソフトコンパチブル!8080、Z80マシン語からBASICまでこれ1台でこなせます
当記事は2009年11月から「TTLでCPUをつくろう!」というタイトルの もとにほとんど毎日連載をしてきたものを再編集したものです。 2011.7.1
前へ
次へ
目次へ戻る
ホームページトップへ戻る
☆ND80ZVでBASICを(2)
ND80ZVに搭載予定のBASICはハンパではありません。
浮動小数点演算をこなし、さらに三角関数、対数計算までできるのです。
しかも、倍精度での演算もできてしまいます。

[第64回]

●SIN、COS、TAN(倍精度)

前回はZ80BASICの三角関数の機能を紹介しました。
その前には、SQR(平方根)関数を倍精度演算でもご紹介いたしましたので、すると三角関数はどうなの?
という疑問を持たれたかもしれません。
ええ。
三角関数も倍精度で計算させることができるのです。

そこで、今回は倍精度の三角関数の計算についてご紹介申し上げてまいりますけれど、せっかくの機会ですので、前回の単精度実数型の三角関数のサンプルプログラムを倍精度に直しながら、Z80BASICのいろいろな編集機能についてもあわせてご紹介してまいりたいと思います。

実際の作業の過程をログファイルでお見せします。

logfile nd80zlog\07110749.txt open

ND80ZVに接続しました
0001 0000 - z1000 00C3 - *** nd80z3 basic ****
>h.
TEXT 8004-8198
ヘンスウ DFFB-DFFF
>.
     5 ON ERROR GOTO *ERR
    10 PRINT "rad","sin","cos","tan"
    20 A=0:A$="0":GOSUB *SAN
    30 A=PI/6:A$="pai/6":GOSUB *SAN
    40 A=PI/4:A$="pai/4":GOSUB *SAN
    50 A=PI/3:A$="pai/3":GOSUB *SAN
    60 A=PI/2:A$="pai/2":GOSUB *SAN
    70 A=PI:A$="pai":GOSUB *SAN
    80 A=PI*1.5:A$="1.5pai":GOSUB *SAN
    90 A=PI*2:A$="2pai":GOSUB *SAN
   100 STOP 
   110 *SAN
   120 PRINT A$,SIN(A),COS(A),TAN(A)
   130 RETURN 
   190 *ERR
   200 PRINT "***"
   210 RESUME  NEXT

ND80ZVはメモリ(RAM)をボタン電池でバックアップしていますから、 電源を切ってもそれまでに入力したプログラムやデータは消えないで保持されています。
BASICのプログラムは、BASICの起動時には見かけ上はクリアされたようになっていますがHELPコマンドで復活させることができます。
でも、今回はよく見ますと、helpではなくて、h.と入力しています。

●コマンド、命令の省略形

そうなのです。
Z80BASICは、コマンドやBASICの命令に省略形が使えるのです。
省略形は最後に .(ピリオド)をつけて使います。

h.はhelpと入力したのと同じ結果を得ることができます。

その下では、なんと . だけを入力しています。
listコマンドはコマンドテーブルの先頭に置いてあるため、綴りを全て省略した場合、listコマンドが選択されます。

●SLコマンドとXLコマンド

SLはsearch letter、つまり文字列の検索コマンドです。
XLはexchange letter、文字列の置き換えコマンドです。
こういう機能が使えると、プログラムの変数を一括して置き換えたりするときになかなか便利です。

今回は実数型の計算を倍精度実数型に変更しますから、実数型変数のAを倍精度実数型変数のA#に置き換えます。
このときに、ただAと指定すると、Aを含む文字列のすべてが対象になってしまいますから、工夫が必要です。

それからいきなりXLコマンドで不用意に置き換えてしまうと、置き換えてはならないところまで置き換えてしまって、めちゃくちゃになってしまう、ということにもなりかねません。
まずは慎重を期して、SLコマンドで探りを入れてみます。

ただのAではなくて、A=でサーチしてみました。

>sl a=
    20 A=0:A$="0":GOSUB *SAN
    30 A=PI/6:A$="pai/6":GOSUB *SAN
    40 A=PI/4:A$="pai/4":GOSUB *SAN
    50 A=PI/3:A$="pai/3":GOSUB *SAN
    60 A=PI/2:A$="pai/2":GOSUB *SAN
    70 A=PI:A$="pai":GOSUB *SAN
    80 A=PI*1.5:A$="1.5pai":GOSUB *SAN
    90 A=PI*2:A$="2pai":GOSUB *SAN

うまい具合に検出してくれたようです。
それではいよいよ本番です。
XLコマンドで、A=をA#=に置き換えます。

>xl a=,a#=
    20 A=0:A$="0":GOSUB *SAN
    30 A=PI/6:A$="pai/6":GOSUB *SAN
    40 A=PI/4:A$="pai/4":GOSUB *SAN
    50 A=PI/3:A$="pai/3":GOSUB *SAN
    60 A=PI/2:A$="pai/2":GOSUB *SAN
    70 A=PI:A$="pai":GOSUB *SAN
    80 A=PI*1.5:A$="1.5pai":GOSUB *SAN
    90 A=PI*2:A$="2pai":GOSUB *SAN

表示されたリストは置き換える前のものなので、これで本当に置き換えられたのかどうかは、わからないのですけれど、リスト表示された行は置き換えられたことを示していますから、多分大丈夫です。
あとでLISTコマンドで確認してみることにしましょう。

置き換えが必要なところはほかにもあります。
そうです。
肝心の三角関数の( )の中もAからA#にしなければ、何にもなりません。

ここもまずSLコマンドで確認してみます。
今度は、A)でサーチしてみました。

>sl a)
   120 PRINT A$,SIN(A),COS(A),TAN(A)

対象になるのは、この1行だけのようです。
それでは、XLコマンドで置き換えてみます。
A)をA#)に置き換えます。

>xl a),a#)
   120 PRINT A$,SIN(A),COS(A),TAN(A)
   120 PRINT A$,SIN(A),COS(A),TAN(A)
   120 PRINT A$,SIN(A),COS(A),TAN(A)

SLコマンドでは1行表示されただけでしたが、XLコマンドでは同じ行が3回表示されました。
XLコマンドは置き換えを行うごとに、その行を表示します。
行番号120には置き換えの必要なところが3箇所ありますから、それで3回表示がおこなわれたのです。

どのように置き換えられたか、LISTコマンドで表示してみましょう。

>list
     5 ON ERROR GOTO *ERR
    10 PRINT "rad","sin","cos","tan"
    20 A#=0:A$="0":GOSUB *SAN
    30 A#=PI/6:A$="pai/6":GOSUB *SAN
    40 A#=PI/4:A$="pai/4":GOSUB *SAN
    50 A#=PI/3:A$="pai/3":GOSUB *SAN
    60 A#=PI/2:A$="pai/2":GOSUB *SAN
    70 A#=PI:A$="pai":GOSUB *SAN
    80 A#=PI*1.5:A$="1.5pai":GOSUB *SAN
    90 A#=PI*2:A$="2pai":GOSUB *SAN
   100 STOP 
   110 *SAN
   120 PRINT A$,SIN(A#),COS(A#),TAN(A#)
   130 RETURN 
   190 *ERR
   200 PRINT "***"
   210 RESUME  NEXT

どうやらうまく置き換えが行われたようです。

ところで。
Z80BASICでは、プログラムはもとのテキストイメージのままではなくて、コマンドや変数名などを中間コードに置き換えてメモリに格納します、という説明を、以前にいたしました。
すると、いったいSLやXLで文字列をどのように検索したり、置き換えたりしているのか、疑問になりませんでしょうか?

実は、SLコマンドやXLコマンドでは、BASICの1行ごとに、中間コードを一旦もとのテキストイメージに復元しながら検索を行っているのです。
簡単な文字列比較などではありません。
裏ではなかなかに複雑なプログラムが実行されているのです。

では実行してみましょう。

>run
rad          sin          cos          tan
0            0            1            0
***
pai/6        0            -1           0
***
pai/4        0            -1           0
***
pai/3        0            -1           0
***
pai/2        0            -1           0
***
pai          0            -1           0
***
1.5pai       0            -1           0
***
2pai         0            -1           0

break in 100

あれ?
なんだか様子がおかしいです。
よく見ると、***が表示されています。
ON ERROR GOTO文が実行されているようです。
でも、このままでは、何のエラーなのかわかりません。
ON ERROR GOTO文をコメント文にしておいてもう一度実行してみましょう。
[注記]行の先頭に ’ をつけると、その行はコメント行になって、実行には関係なくなります。

>list
     5 ON ERROR GOTO *ERR
    10 PRINT "rad","sin","cos","tan"
    20 A#=0:A$="0":GOSUB *SAN
    30 A#=PI/6:A$="pai/6":GOSUB *SAN
    40 A#=PI/4:A$="pai/4":GOSUB *SAN
    50 A#=PI/3:A$="pai/3":GOSUB *SAN
    60 A#=PI/2:A$="pai/2":GOSUB *SAN
    70 A#=PI:A$="pai":GOSUB *SAN
    80 A#=PI*1.5:A$="1.5pai":GOSUB *SAN
    90 A#=PI*2:A$="2pai":GOSUB *SAN
   100 STOP 
   110 *SAN
   120 PRINT A$,SIN(A#),COS(A#),TAN(A#)
   130 RETURN 
   190 *ERR
   200 PRINT "***"
   210 RESUME  NEXT 
>     5'ON ERROR GOTO *ERR

[10.7.12注記]
このようにログで見ていますと、行番号5の文をあらためて入力しているように見えてしまいますが、実際に行っている作業では、スクリーンエディタを使って上のlistコマンドで表示された行番号5の位置までカーソルを移動して、そこで ’ だけを入力して、その入力を確定するために[Enter]を入力しています。

スクリーンエディタは入力したキーの通りのデータを渡すのではなくて、[Enter]を入力したときに、その行に表示されている通りのデータを渡すように作られています。
つまり画面に表示されている文字データは全て「活きて」いて、いつでも[Enter]を入力すれば、そのときカーソルが置かれている行の表示データが、「そのときキーから入力されたデータ」になるのです(スクリーンエディタについては[第53回]をご参照ください)。

ですから、すでに画面に表示されている行番号5のところにカーソルを移動して、そこで ’ だけを入力しても、そのあとその行位置で[Enter]キーを押すと、このログにありますように、 ’ が追加された行番号5の文全体がキーボードから入力されたのと同じ結果になるのです。
このような機能は、今日ではnotepadやWordでごく当たり前のように使っていますから、

これがスクリーンエディタです。どうです。すごいでしょう。

などと言いましても、ふうん。それが、どうしたの?
で終わってしまいそうですけれど、実際に普通のDOSプロンプト画面で、ちょっとキー入力操作をして、それと比べていただければ、その違いをわかっていただけることと思います。

そのように言いますからには、このスクリーンエディタもWindowsに備わっている機能などではなくて、私が自分で作ったプログラムです。
ええ。
WinAPIなど全く使っておりませんです。
ごく普通のC++の入出力関数、getch()とかprintf()を使って、そのような動作をさせているのです。

私はC++の達人などではなくて、もうごくごく初心者でありますから、そんなややこしい特殊な関数とかテクニックとかは全く使っておりません(*)。
皆様もひとつ挑戦してみられたら、いかがでしょうか?

(*追記の追記です)
実はこのスクリーンエディタは、その昔、オリジナルのZ80CPUマシーン(もちろんBASICです)で動作していたものを、DOSプロンプトで動作するようにC++で書き直したものなのです。
つまり、スクリーンエディタの動作は、もともとZ80のマシン語レベルで記述可能なものだったのです。

(追記の追記の追記です)
ああ。
そうでした。
このスクリーンエディタは、当社のZBK開発セットに附属しておりますものをもとにして、今回ND80ZV用に書き直したものでありますが、そもそも現在のZBK開発セットをWindowsXPに対応するためにUSBバージョンとする以前は、Windows95、Windows98で、パラレルポート(プリンタポート)接続で使っておりましたものがもとになっております。
そのパラレルポートバージョンのスクリーンエディタは8086アセンブラで書いております。
まあ、Z80のマシン語で記述できるものならば、当然8086のアセンブラでも書けて当たり前なのですが、そういうことをすっかり忘れてしまっておりました。
[10.7.12追記ここまで]

>run
rad          sin          cos          tan
0            0            1            0

ERR: 9 
    30 A#=PI/6:A$="pai/6":GOSUB *SAN

ON ERROR GOTO文をコメントアウトしておいて、再実行してみましたら。
ERR:9が表示されました。
文法に合わない式がある、というメッセージです。

ああ。
時間が無くなってしまいました。
説明の途中ですけれど、本日はここまでといたします。
CPUをつくろう!第549回(2010.7.11upload)を再編集

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

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