ぐだぐだ低レベルプログラミング(214)x86(16bit)、浮動小数点数のロード

Joseph Halfmoon

前回前々回と浮動小数点「コープロセッサ」8087の復習を行いました。ようやく8087命令をエクササイズする準備が出来たというところです。今回は、最初の一歩というところで、8087のレジスタ・スタックに浮動小数点数をロードしてみます。メモリから、そして沢山ある定数のロード命令を使ってみます。スタックに積まれていくのよ。

※「ぐだぐだ低レベル プログラミング」投稿順indexはこちら

※実機動作確認(といってもエミュレータなんだけれども)には以下を使用させていただいております。

    •  Windows 11 PC (i5-1235U)
    •  Ubuntu 24.04 LTS on WSL2
    •  QEMU 8.2.2
    •  FreeDOS 1.3

※オリジナルの8086+8087の組み合わせでは8086と8087の同期をとるためにWAIT命令が必用になる場合があります。後継機種ではWAIT命令が不要(演習に使用しているエミュレータQEMUでも不要)なのでWAIT命令は使用しません。メンドイし。

浮動小数点数のロード命令

浮動小数点数のロード命令は、FLDです。ひとつのニーモニックですが、

    • メモリからスタックトップへのロード
    • レジスタスタック内からスタックトップへのロード

の両方を兼ねるとともに

    1. 単精度浮動小数(32ビット)
    2. 倍精度浮動小数(64ビット)
    3. テンポラリ型浮動小数(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

まず、いつもの通り、オブジェクトコードの逆アセンブルからです。unassemFLD_EC

黄色の枠で囲った部分が、浮動小数のロード命令のつらなりです。

まずは赤枠で囲ったメモリからの浮動小数ロード命令の実行です。FLD_EC

上記のように8本あるレジスタスタックは実行前全てエンプティになっています。前回やったTAGの効果です。FLD命令を実行するとメモリからπの概数3.141592(2進表記のため下に数字が見えてるけど)をロードして、その時点のスタックトップST0に配置します。

つづいて内蔵の定数パイをロード。FLDPI_EC

debugx のrn コマンドで表示されるレジスタはスタックトップを常にST0とする相対表記のようです。よって、前のFLD命令によって持ってきた概数3.141592は緑の枠のST1に見え、スタックトップのST0に内蔵定数のパイがロードされてます。πの値は

3.14159265358979323…

なので、内蔵定数の方が、さきほどロードした概数よりも精度がいいです。あたりまえか。

その後、浮動小数の+1.0と+0.0を続けてロードしてみます。FLD1_FLDZ_EC

赤枠の1、緑枠の0とロードされました。スタック上には値が4個。計算できるような気がしてきた?

ぐだぐだ低レベルプログラミング(213)x86(16bit)、8087のレジスタ へ戻る

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です