16ビットマイコンボードの製作
〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜
いつか使ってみるつもりで入手してそのまま置いてあった16ビットCPUのことを思い出しました。
AMD社のAM188です。
その名の通り、CPUコアは80188互換の16ビットCPUです。
そのAM188を使った16ビットマイコンボードの製作記事です。
〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜
[第44回]
●√2、√3問題の解決(2)
また間が空いてしまいました。
このところ連日8086版BASICプログラムの仕上げ作業にかかっています。
もうかなり完成に近づいているのですが、まだバグが残っていて、それを退治するのに丸1日かかってしまったりします。
結局ホームページの更新は後回しになってしまいます。
どうか気長なおつきあいをお願いいたします。
それで前回の続き、平方根のプログラムについてです。
平方根に限らず、SINもCOSも繰り返し演算によって解を得ています。
昔の人が考案した近似式による解法です。
平方根の解法についても近似式があるはずですが、実はそれは使っていません。
なにしろ近似式なるものの計算はなかなかに大変なプログラムを書かなければなりません。
多少時間がかかっても、できれば同じ近似式を使い回しにしたいところです。
自慢じゃありませんが(と書きつつしっかり自慢です)当ZB3BASICの浮動小数点計算プログラムはハンパではありません。
SIN、COSは言うに及ばす、自然対数LNも指数関数EXP(eX)も備えています。
対数なんて高校の時以来だよお、とおっしゃる方も多いのでは。
多分高校ではもう少し分かり易い常用対数LOGが主体で習われたのでは?
もちろんZB3BASICにはLOG関数もあります。
常用対数は10が底ですが、自然対数はeが底です。
そこで先ほどの話の続きに戻ります。
どうせLNもEXPも組み込んであるのだから、それを利用して平方根も計算してしまおう、という考えです。
素直に平方根の近似解を得るよりは少し回りくどくなりますが、それだけトータルとしてのシステムプログラムは短くて済みます。
平方根の計算式
Y=√Z は
Y=Z0.5 と書くことができます。
そこで両辺の対数をとると
LN(Y)=LN(Z0.5)と書けます。
これは
LN(Y)=0.5 x LN(Z)と変形できますから、これで指数の0.5が乗数になりました。
さらにZは浮動小数点プログラムではA x 2n の形に変形して計算を行なっています。
Aは仮数部(0.5<=A<1)でnは指数部です。
ということは
LN(Y)=0.5 x LN(A x 2n) ですから
LN(Y)=0.5 x (LN(A)+ n x LN(2)) という式になります。
ここでLN(2)は定数としてプログラム内に置いていますから、式の右辺はLN(A)を計算すればよいことになります。
そこでLN関数プログラムにAを与えれば、式の右辺が求まります。
それをBとします。
LN(Y)=B です。
この式は指数を使うと
eB=Y と書けますから
結局EXP(B)を計算すれば、平方根Yが求まることになります。
なかなかに面倒ですね。
しかしプログラムとしては、
置数の仮数部Aに対して
CALL FNC_LN を実行し、その結果に指数部nとLN2を掛けたものを加算して、それを1/2倍し、その結果に対して
CALL FNC_EXP を実行すればよいので、それほど面倒なプログラムにはなりません。
ということで前回のテストプログラムを実行した結果が下の画像です。
こちらはZ80プログラムです。
4行目、5行目よりも上(大半はスクロールして見えません)はLN関数でそこから下はEXP関数です。
こちらは8086プログラムです。
Z80の上から3行目に8086とは異なる値が表示されていますが、これはうっかりして8086プログラムとは別のところにレジスタ表示ルーチンを挿入してしまったためで、8086プログラムに異常があるということではありません。
その上の値は8086では末尾がC2に対してZ80ではC0になっていますが、ここも前回書いた事情で末尾の1〜2ビットの相違は想定内です。
問題は上から5行目の値です。
倍精度浮動小数点レジスタの仮数部は7バイト長で左が下位側、右が上位側です。
下位側2バイトがZ80では02 00なのに対して8086では00 80になっています。
これを分かり易い左側が上位で右側を下位の並びに置き換えると
Z80の 0002に対して8086では 8000という値になります。
これはめちゃめちゃおかしいです。
この部分にバグがありそうです。
念のためにその値の前後にブレークポイントを設けて少しずつ実行しながら演算レジスタの値を確認してみました。
F1F7〜F1FFが倍精度浮動小数点レジスタ(DFA)です。
F0D0〜も参照していますが、そこは気にしないでください。
最後のPC=799Fで、下位2バイトに00 80が現れました。
ここはワークレジスタとして使っている、BX、AH、SI、DI、BPの値をDFAに戻しているところです。
本来はDFAの下位2バイトにはBPの値が入るべきところです。
おお!
多分BPの代わりにBXの値が入っている、らしい。
PC=799Fは下のプログラム部分です。
[01565] 7989 BE750A FEX2:MOV SI,LN2 [01566] 798C E8C0F7 CALL FDIVCS <714F> [01567] 798F BED0F0 MOV SI,*FB0 [01568] 7992 E82EFB CALL APUT <74C3> [01569] 7995 E8A400 CALL INTA <7A3C> [01570] 7998 50 PUSH AX [01571] 7999 BED0F0 MOV SI,*FB0 [01572] 799C E839F7 CALL FSUB <70D8> [01573] 799F 8036FFF180 XOR [*FAH8]B,80 [01574] 79A4 BE750A MOV SI,LN2 |
その前のCALL FSUBがおかしい(らしい)。
で、FSUBの終わりのところです。
FSUB(減算)は形を変えてFADD(加算ルーチン)を使っています。
[00437] ;;;FADD [00438] 6FC4 E8CDFF FADDCS:CALL HLRBCS <6F94> [00439] 6FC7 EB0490 JMP FADD2 <6FCD> [00440] 6FCA E8E3FF FADD:CALL HLRB <6FB0> [00441] 6FCD E812FF FADD2:CALL TAZR <6EE2> [00442] 6FD0 7515 JNZ RBFA2 <6FE7> [00443] ;;;RB TO FA [00444] 6FD2 891EF7F1 RBFA:MOV [*FAH0],BX [00445] 6FD6 893EF9F1 MOV [*FAH2],DI [00446] 6FDA 8936FBF1 MOV [*FAH4],SI [00447] 6FDE 8826FDF1 MOV [*FAH6],AH [00448] 6FE2 891EFEF1 MOV [*FAH7],BX [00449] 6FE6 C3 RET |
とうとうみつけました。
MOV [*FAH0],BX は MOV [*FAH0],BP の間違いでした。
むむ。
お恥ずかしいプログラムミスでありました。
そのように修正いたしました。
[00435] ;;;FADD [00436] 6FC4 E8CDFF FADDCS:CALL HLRBCS <6F94> [00437] 6FC7 EB0490 JMP FADD2 <6FCD> [00438] 6FCA E8E3FF FADD:CALL HLRB <6FB0> [00439] 6FCD E812FF FADD2:CALL TAZR <6EE2> [00440] 6FD0 7515 JNZ RBFA2 <6FE7> [00441] ;;;RB TO FA [00442] 6FD2 892EF7F1 RBFA:MOV [*FAH0],BP [00443] 6FD6 893EF9F1 MOV [*FAH2],DI [00444] 6FDA 8936FBF1 MOV [*FAH4],SI [00445] 6FDE 8826FDF1 MOV [*FAH6],AH [00446] 6FE2 891EFEF1 MOV [*FAH7],BX [00447] 6FE6 C3 RET |
[第41回]を開いて、その上にコマンドプロンプト画面を置いて実行しました。
ちょっと分かりづらい画面になってしまいました。
右側のコマンドプロンプト画面がプログラム修正後のテスト画面です。
やっと、√2、√3がまともになりました。
これにて一件落着です。
ことほど左様にバグ取りはなかなかに大変で、手間のかかる作業です。
16ビットマイコンボードの製作[第44回]
2018.6.29upload
前へ
次へ
ホームページトップへ戻る