昔地元の青山堂(ねじめ正一著「風の棲む町」のモデル)という書店で購入したZ80マイコンプログラミングテクニック(電波新聞社 1980年刊)という本を久しぶりに開いてみました。当時マイコン雑誌にゲームを発表していた人たちが参考文献としてあげていたので購入した記憶がありますが、あまりしっかり読んではいなかったです。当時かなりのベストセラーだったと思います。
この本は前半は命令の説明とサンプルプログラムで構成されていて、後半は固定・浮動小数点演算パッケージで構成されています。
前半はハンドアセンブルを対象にした説明になっています。この本の作者はCP/M環境を使っていますが、当時CP/M環境を持っているユーザはごく一部でそのような読者をターゲットにしても成立しなかったのではないかと思います。
後半の固定・浮動小数点演算パッケージはCP/M上のMacro-80で作られていて、ハンドアセンブルの人は自力でリロケートしてつかうことになっています。アドレスの変換は面倒で、おそらくほとんど試されてなかったのではないかと思われます。
その証拠に私の持ってる本は第4版なのですが、DFLTのP176の01CEと01D0の間に抜けがあります。
浮動小数点のプログラムは現在標準的に使われている2のべき乗ではなく16のべき乗で作られているようです。
16のべき乗は内部処理で使われ、JIS形式(文字列)では10のべき乗で表現されます。
浮動小数点のコードは可変長になっていますが、デフォルトは8バイトで、7バイトの仮数部と6ビットの乗数部とそれぞれの符号が1ビットになります。仮数部のビットの並びが後のほうが先頭になっているようです。昔はいろいろな実装があって楽しいですね。
たとえば2の内部データは
00 00 00 00 00 00 20 41
のようになります。
手元にはいま、Windows 7のノートしかないので、秀丸でこのパッケージの最低限の四則演算(ASUB1,ASUB2,ROUND,JTOD,DTOJ,DFLT)を写経してみました。
抜けがあるDMLT(掛け算)には他にもバグがありデバッグして修正しました。抜けはプリントしたものを切り貼りしたときにできたものと思われますが、タイポは何らかの理由でオリジナルのファイルが使えず、打ち直しをしたためではないかと思われます。
追記:DSINの中にもループでBCをPUSH,POPしなければいけないところが抜けて無限ループになっていました。
確認のためZ80のエミュレーターを探してみたのですがYAZSはcygwinが必要でめんどうだったので、SIMHを使うことにしました。
大湯健介さんのページが大変参考になりました。
ただ、二つ勘違いがあり、一つは文字列出力のサンプルコードはZilogニモニックでもIntelニモニックでも同じバイナリになると思います。またcpm2の設定でCPUがZ80になっているのでZ80固有の命令も実行できます。
以前書いたようにCP/Mの開発にはいくつかの方法がありますが、Windows環境のほうがエディタが使いやすいのでクロスで開発することにします。アセンブラはzmacを使ってみました。オリジナルのコードはMacro-80でそれぞれオブジェクトにしてLink-80でリンクしているのですが、zmacはrelは作れますが、~~リンクするすべがないので、一つのファイルにできるように変数名を微妙に変えてみました。~~いろいろ調べてみたところLink-80相当のリンカーが用意されていたので、ファイルはできるだけいじらずにアセンブリして、これを使ってリンクするようにしてみました。
C:\Z80>zmac\zmac --rel test2.txt
C:\Z80>zmac\zmac --rel asub1.txt
C:\Z80>zmac\zmac --rel asub2.txt
C:\Z80>zmac\zmac --rel round.txt
C:\Z80>zmac\zmac --rel jtod.txt
C:\Z80>zmac\zmac --rel dtoj.txt
C:\Z80>zmac\zmac --rel dflt.txt
C:\Z80>ld80\ldl80 -P 100 -D 100 -o test2.hex zout\test2.rel zout\asub1.rel zout\asub2.rel zout\round.rel zout\jtod.rel zout\dtoj.rel zout\dflt.rel
オープンソースで出回っているクロスアセンブラではzmacが一番Macro-80に近いのではないでしょうか。違いはEXTERNALがEXTERNやシンボルのTが予約されている、Mが使えないくらいでした。
Macro-80のマニュアルを見るとEXTERNALはEXTやEXTERNでも使えるようになっていました。
ライブラリのプログラムでマクロを使ったものがあるのですが、ハンドアセンブラのためにインラインで展開しているにもかかわらず、なぜかマクロが残っていて、とっても見ずらいです。私が写経しているものはマクロは消してあります。
出来上がったhexファイルをaltairz80のcpm2のrコマンドで読み込みloadコマンドでコマンドにして実行してみました。
Altair 8800 (Z80) simulator V3.9-0 build 1625 (scp created Feb 10 2013 at 09:37:
45 with gcc 4.2.4)
sim> do cpm2
64K CP/M Version 2.2 (SIMH ALTAIR 8800, BIOS V1.27, 2 HD, 02-May-2009)
A>i:
I>r test2.hex
READ V-2.25 (19-May-14) SIMH Interface V004
Read from "TEST2.HEX" and write to "TEST2.HEX".
Previous file of same name deleted.
5.75kB written.
I>load test2
FIRST ADDRESS 0100
LAST ADDRESS 0A36
BYTES READ 0937
RECORDS WRITTEN 13
I>test2
3.3333333D 02
1.0100000D 02
-2.0900000D 02
1.3200000D-01
2.2011000D 02
I>
TEST1は文字列から8バイトの浮動小数点のデータにしてまた文字列に戻しています。
TEST2は足し算のテストです。
浮動小数点のライブラリには平方根やサインのプログラムもあります。一通り写経してリポジトリに追加してあります。
DABS - 浮動小数点数の絶対値
DATAN - 逆正接関数
DCOS - 余弦関数
DEXP - 指数関数
DFIX - 浮動小数点数の小数点以下の切捨
DFLT - 浮動小数点数四則<8バイト長>
DLOG - 対数関数
DMOD - 浮動小数点数の剰余
DSGN - 浮動小数点数の符号
DSIN - 正弦関数
DSQRT - 平方根
DTOJ - 浮動小数点数からJISコードへの変換
JTOD - JISコードから浮動小数点数への変換
DSIN,DCOS,DATANの引数はラジアンで、DEXP,DLOGの底はeです。
DSINはテイラー級数展開を用いていて、DCOSは$\frac{pai}{2}$を足してDSINに送っています。
MBASICのsinなどの関数は単精度ですが、このライブラリは倍精度で計算できます。
DATANはWindowsの電卓ではRadにしてInv -> tanで確認できます。
テストプログラムの結果はこんな感じです。
ATANはちょっとずれています。アルゴリズムからくる誤差なのかもしれません。 引数が$-\frac{pai}{2}$ - $\frac{pai}{2}$の間であれば大丈夫なようです。
tan()は$\frac{sin()}{cos()}$で計算できます。