
前回、前々回と浮動小数点「コープロセッサ」8087の復習を行いました。ようやく8087命令をエクササイズする準備が出来たというところです。今回は、最初の一歩というところで、8087のレジスタ・スタックに浮動小数点数をロードしてみます。メモリから、そして沢山ある定数のロード命令を使ってみます。スタックに積まれていくのよ。
※「ぐだぐだ低レベル プログラミング」投稿順indexはこちら
※実機動作確認(といってもエミュレータなんだけれども)には以下を使用させていただいております。
※オリジナルの8086+8087の組み合わせでは8086と8087の同期をとるためにWAIT命令が必用になる場合があります。後継機種ではWAIT命令が不要(演習に使用しているエミュレータQEMUでも不要)なのでWAIT命令は使用しません。メンドイし。
浮動小数点数のロード命令
浮動小数点数のロード命令は、FLDです。ひとつのニーモニックですが、
-
- メモリからスタックトップへのロード
- レジスタスタック内からスタックトップへのロード
の両方を兼ねるとともに
-
- 単精度浮動小数(32ビット)
- 倍精度浮動小数(64ビット)
- テンポラリ型浮動小数(80ビット)
を扱うことが可能デス。デスティネーションは常にスタックトップなので、ソースのみを指定すればロード可能。メモリ上のソースの精度はポインタの修飾で指示する感じっす。
一方、浮動小数計算をするときに「よく使う」定数どもを一撃でスタックトップに載せるための一群の定数ロード命令も存在します。
-
- FLD1、+1.0をロード
- FLDL2E、\( \log_2 e\)
- FLDL2T、\( \log_2 10\)
- FLDLG2、\( \log_{10} 2\)
- FLDLN2、\( \log_e 2\)
- FLDPI、π(円周率)をロード
- FLDZ、+0.0をロード
今回実験のプログラム
強力なx86用アセンブラNASM用のソースです。DS:BXから、倍精度の浮動小数値(πの略数的な数字)をロードした後、定数ロード命令を使って、内部表現でのフル桁のπと、1とゼロをロードして浮動小数スタックの内容を確認するためのものです。
segment code ..start: mov ax, data mov ds, ax mov ax, stack mov ss, ax mov sp, stacktop test: mov bx, target0 fld qword [bx] fldpi fld1 fldz fin: mov ax, 0x4c00 int 0x21 resb 2048 segment data align=16 resb 1024 * 63 target0: dq 3.141592 segment stack class=STACK align=16 resb 2048 stacktop: dw 1024 dup (0) stackend:
NASMは、dd とか dqとかのメモリ定義の疑似命令の引数として、整数だけでなくフツーに浮動小数もとれるので、そのままテキトーな浮動小数を配置できます。なお、64ビットの倍精度浮動小数へのポインタはqwordと修飾です(何度も繰り返してますが、8086のワードは16ビットなので。)
アセンブルして実行
MS-DOS互換で機能強化されているフリーなFreeDOS上、以下のステップで上記のアセンブラソース fld.asm から実行可能なオブジェクトファイルを生成して実行することができます(nasmとwatcom Cがインストール済であること。)
なお、いままで使っていた「debug」ではなく「debugx」というデバッガを使っていることにご注意ください。FreeDOSのdebugはMS-DOSのdebugに比べると遥かに強力ですが、8087のレジスタ表示は素のHEXになってしまうためです。一方 debugxは、8087のレジスタ内容を浮動小数で見せてくれます。
nasm -f obj -l fld.lst fld.asm wlink name fld.exe format dos file fld.obj debugx fld.exe
まず、いつもの通り、オブジェクトコードの逆アセンブルからです。
黄色の枠で囲った部分が、浮動小数のロード命令のつらなりです。
まずは赤枠で囲ったメモリからの浮動小数ロード命令の実行です。
上記のように8本あるレジスタスタックは実行前全てエンプティになっています。前回やったTAGの効果です。FLD命令を実行するとメモリからπの概数3.141592(2進表記のため下に数字が見えてるけど)をロードして、その時点のスタックトップST0に配置します。
debugx のrn コマンドで表示されるレジスタはスタックトップを常にST0とする相対表記のようです。よって、前のFLD命令によって持ってきた概数3.141592は緑の枠のST1に見え、スタックトップのST0に内蔵定数のパイがロードされてます。πの値は
3.14159265358979323…
なので、内蔵定数の方が、さきほどロードした概数よりも精度がいいです。あたりまえか。
その後、浮動小数の+1.0と+0.0を続けてロードしてみます。
赤枠の1、緑枠の0とロードされました。スタック上には値が4個。計算できるような気がしてきた?