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


16ビットマイコンボードの製作

〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜
いつか使ってみるつもりで入手してそのまま置いてあった16ビットCPUのことを思い出しました。
AMD社のAM188です。
その名の通り、CPUコアは80188互換の16ビットCPUです。
そのAM188を使った16ビットマイコンボードの製作記事です。
〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜

[第50回]



●SQR()よ、お前もか!

前々回、前回、システムプログラムをROM化した場合のCSとDSに関わる悩ましい問題について書きました。
悩んでいても仕方がありませんし、悪態をついてみてもどうなるものでもありませんから、そこはあきらめてぶつぶつ文句を言いつつプログラムを変更して対策済みのシステムROMを作成しました。

よくよく考えてみましたら、CSとDSの問題は浮動小数点計算プログラムに取り掛かるよりもずっと以前に気が付いていた問題でした。
そういうことまで忘れてしまって、「浮動小数点計算プログラムに取り掛かったところで気が付きました」などと書いたようでしたが、ボケもいいところです。
こりゃあもう何かで誤認逮捕でもされたら一巻の終わりですな。

BASICやマシン語のコマンド、命令のテーブルもしっかりROMに仕込んでありますから、そのテーブルを参照したり、エラーメッセージを表示するところでは当然セグメント変更プリフックスCS:を使っています(セグメント変更プリフィクスはCS:だけではありません。念のため書き添えておきます)。
ただコマンドや命令テーブルを参照するサブルーチンやエラーメッセージなどを表示するサブルーチンは数が限られていますから、その部分だけ対策すれば問題はありませんでした。
前々回、前回、それを問題にしたのは、参考のためにお見せしたプログラムリストにもありますように、浮動小数点計算プログラムは定数を参照している箇所が矢鱈多いので、それを対策するのが大変、と思ったからでした。
私の場合、きっとミスをするのはほぼ確定的であります。
ことに倍精度の浮動小数点計算プログラムは修正すべき箇所もハンパではない多さです。
案の定、何箇所かでミスをしてしまい、そのバグ取りに少なからぬ時間を費やしてしまいました。
そのあたりのことについては前回に書きました。
単精度も倍精度もテストして正しい結果が得られることを確認しましたし、この件はそれで終わり、のつもりだったのですが。

そういえば。
SQR()については単精度は確認したけれど、倍精度については確認したんだったっけ。
ふと気になりました。
ログなどを調べてみたところ、どうも倍精度のSQR()については未確認だったようです。
多分いいだろう、とも思ったのですが、それほど手間のかかることでもありませんから念のためテストをしてみることにしました。
そうしましたら。
なんじゃあ、これは?

    10 FOR A#=0 TO 10
    20 PRINT "a#=";A#,"sqr(a#)=";SQR(A#)
    30 NEXT A#
    40 PRINT "end"
>r.
a#=0         sqr(a#)=0
a#=1         sqr(a#)=1
a#=2         sqr(a#)=0.7165313105738165
a#=3         sqr(a#)=0.8668778997502146
a#=4         sqr(a#)=0.7165313105738301
a#=5         sqr(a#)=0.7939226578179966
a#=6         sqr(a#)=0.8668778997502312
a#=7         sqr(a#)=0.9355069850316711
a#=8         sqr(a#)=0.7165313105738438
a#=9         sqr(a#)=0.755783741455783
a#=10        sqr(a#)=0.7939226578180117
end

だめじゃないの!
SQR()よ、お前もか!
で。
またしてもバグ取りです。
次の3箇所にバグがありました。
こちらがbeforeです。

MOV SI,*FB0
CALL FDIV ;[A-1]/[A+1]
CALL APSH
MOV SI,*FAH0
CALL FMULCS;[[A-1]/[A+1]]**2

POP AX  ;シスウ
CALL INFL8
MOV SI,LN2   
CALL FMUL   


FLN2:PUSH DI
MOV SI,LGLN
CALL FMUL   
POP DI
RET

こちらがafterです。
上から5行目は直してはいけないところを直してしまっていました。
FAH0はDSにある浮動小数点演算レジスタです。

MOV SI,*FB0
CALL FDIV ;[A-1]/[A+1]
CALL APSH
MOV SI,*FAH0
CALL FMUL;[[A-1]/[A+1]]**2

POP AX  ;シスウ
CALL INFL8
MOV SI,LN2   
CALL FMULCS


FLN2:PUSH DI
MOV SI,LGLN
CALL FMULCS
POP DI
RET

そのように修正してROMを作り直して、再度テストしたところ、今度は正しく計算が行なわれました。

>/load dsqrtst.txt
    10 FOR A#=0 TO 10
    20 PRINT "a#=";A#,"sqr(a#)=";SQR(A#)
    30 NEXT A#
    40 PRINT "end"
data end
>r.
a#=0         sqr(a#)=0
a#=1         sqr(a#)=1
a#=2         sqr(a#)=1.414213562373095
a#=3         sqr(a#)=1.732050807568877
a#=4         sqr(a#)=2
a#=5         sqr(a#)=2.23606797749979
a#=6         sqr(a#)=2.449489742783178
a#=7         sqr(a#)=2.64575131106459
a#=8         sqr(a#)=2.82842712474619
a#=9         sqr(a#)=3
a#=10        sqr(a#)=3.162277660168379
end


●EX (SP),HLの代わりの命令について

[第42回]で、Z80(および8080)でEX (SP),HLの代わりの命令は、8086では
MOV BX,SP
XCHG SI,[BX]
のようにすればよい、と書きました。
そうしましたところ、その記事をお読みになった読者様から、
「この場合はBXではなくてBPを使うべきです」
とのご指摘のメールをいただきました。
全くご指摘の通りでした。

このところCSとDSについての問題について書いてきましたが、特定のレジスタとセグメントの関係はDSだけではなくてSSにもありました。
SIとDIはDSで指定するメモリ領域を示します。
ただしDIについてはある特定の命令についてはESで指定するメモリ領域を示します。
そしてBXもDSで指定するメモリ領域を示します。
AX、CX、DXはメモリアドレスを示す目的には使えません。
もうひとつ汎用レジスタがあります。
それがBPです。
しっかり確認しておくべきだったのですが、BPもSI、DI、BXと同じだろうと簡単に考えてしまったようです。
いや以前はちゃんとしっかり認識していたのかもしれませんが、なにしろ1ヶ月も経たないうちに記憶はほとんど白紙状態になってしまうものですから、なんとも申し上げられません。
あらためて確認したところ、ご指摘のとおりBPはSSで指定するメモリ領域を示すレジスタでした(他のレジスタと同様の汎用レジスタでもあります)。
そもそもBXはDSのメモリ領域を示しますからスタック領域を示す処理に使うのは誤りと言えましょう。
ここはご指摘の通り
MOV BP,SP
XCHG SI,[BP]
とすべきでした。
メールでご指摘いただいたM様、ご指摘有難うございました。

さて。
このところの8086についての記事をお読みいただいております読者の皆様の中には、「こんな面倒なCPUでは、とてもプログラムなど書けないぞお」とお思いの方もいらっしゃるかと思います。
しかし、その心配はご無用です。
ことはこのところ書いておりますように、セグメントレジスタに異なるメモリ領域を与えた場合に限って発生する問題です。
前に書きましたように、ND80KL/86ボードにAM188CPUを搭載したシステムでは、ユーザ用のプログラム領域としてND80Z3.5やND8080と同じ8000〜FFFFの範囲のRAMをアクセスするようにセグメントレジスタを設定しています。
その場合CS=DS=SS=ESには同じRAM領域を割り当てますから、このところ書いておりますような問題はユーザープログラムには発生しません。
ND80KL/86ボード用にアセンブラプログラムを書く場合には、上にも書きましたように、
1)メモリアドレスを示すレジスタとしては、AX、CX、DXは使えない
2)メモリアドレスを示すレジスタとしてはBX、SI、DI、BPが使える
というように考えていただければよいかと思います。
ND80KL/86システムの上では、8086プログラムはZ80プログラムや8080プログラムと同程度の使い易さで使えるように考えてあります。
もっともそのことは、ND80KL/86システムでは、セグメントレジスタには同じ領域しか与えることができない(そのほかのROMおよびRAM領域にはアクセスできない)、あるいは8086の高度なプログラミングはできない、ということを意味しているわけではありません。
8086プログラムについての上級者の皆様には、その制約を外して自由にプログラミングできるツールとしてND80KL/86を使い倒していただきたいと願っております。

16ビットマイコンボードの製作[第50回]
2018.7.6upload

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