
前回は8087の浮動小数加算命令を練習、これで加減乗除はバッチリかと思えば、「演算順序」の問題もあり。某国の小学校のようにスカラーの乗算に順序を求めることは流石にないです。減算、除算のときだけです。オペランドの表記法のルールと相まって慣れないとハマります。それもこれもスタック・アーキテクチャのせい?知らんけど。
※「ぐだぐだ低レベル プログラミング」投稿順indexはこちら
※実機動作確認(といってもエミュレータなんだけれども)には以下を使用させていただいております。
※オリジナルの8086+8087の組み合わせでは8086と8087の同期をとるためにWAIT命令が必用になる場合があります。後継機種ではWAIT命令が不要(演習に使用しているエミュレータQEMUでも不要)なのでWAIT命令は使用しません。メンドイし。
浮動小数の加減乗除命令
合計12のニーモニックが浮動小数の加減乗除に割り当てられております。こんな感じね。
Operation | FADD | FSUB | FMUL | FDIV |
---|---|---|---|---|
NRM | FADD | FSUB | FMUL | FDIV |
NRM,w/POP | FADDP | FSUBP | FMULP | FDIVP |
REV | — | FSUBR | — | FDIVR |
REV,w/POP | — | FSUBRP | — | FDIVRP |
前回、ニーモニックの末尾に「P」がつくのはPOPの意味で、スタックから要素を一つポップして、スタックが縮小するのだと説明しました。
今回新たに登場するのが「R」です。リバースのRぞなもし。通常の引き算、割り算の場合、順序あり。引き算であればどっちからドッチを引くのかで結果が異なりますな。オペランド2つを明示してあれば、ディスティネーション(兼第1ソース)引く(第2)ソースでありますが、この順序をひっくり返すためのRです。
分かった、というのは多分早とちりっす。ここに以下のアセンブラ表記上のお約束が存在します。
明示オペランドの無いFSUBはスタックがポップされる
なんとオペランド無で記述された「FSUB」は、「FSUBP ST(1), ST」と同じ意味となるのでした。実はこのルールはFSUBだけでなく、他の加減乗除命令どもにあまねく適用されます。オペランドを明示しないと必ずレジスタスタックは一つ短くなるのでした。その上のデスティネーションST(1)ね。そしてこのルールのため、FSUBやFDIVの場合の演算順序が反転しているようにも見えます。コマケー表記の話なんだが、知らないとビックリだよ。以下で実例登場するのでよ~く順序をお確かめくだされや。
今回実験のプログラム
加減乗除とタイトルに掲げつつ、上記の「演算順序とスタックポップ」問題を確認するため、減算を4通りで練習しているだけのコードです。強力なx86用アセンブラNASM用のソースです。インテル式とはオペランドの表記法など微妙に異なってます。そのソースが以下に。
segment code ..start: mov ax, data mov ds, ax mov ax, stack mov ss, ax mov sp, stacktop test: fld1 mov bx, src1 fld dword [bx] fsub st0, st1 fsubp fld1 fld dword [bx] fsubr st0, st1 fsubrp fin: mov ax, 0x4c00 int 0x21 resb 2048 segment data align=16 resb 1024 * 63 src1: dd 7.5 segment stack class=STACK align=16 resb 2048 stacktop: dw 1024 dup (0) stackend:
アセンブルして実行
MS-DOS互換で機能強化されているフリーなFreeDOS上、以下のステップで上記のアセンブラソース fsub.asm から実行可能なオブジェクトファイルを生成して実行することができます(nasmとwatcom Cがインストール済であること。)
なお、FreeDOS付属の「debugx」デバッガは、8087のレジスタ内容を浮動小数で見せてくれます。
nasm -f obj -l fsub.lst fsub.asm wlink name fsub.exe format dos file fsub.obj debugx fsub.exe
まずは「R」なしのFSUBから。緑枠が引かれる数、黄色枠が引く数で一番下の赤枠が引いた結果です。
次は「R」なしのFSUBPです。緑枠が引かれる数、黄色枠が引く数で一番下の赤枠が引いた結果です。例の「ルール」によって演算の順序が逆転しているように見えないこともない。おっと。
今度は「R」付のFSUBPです。ただしオペランドを記述。上記の緑枠が引かれる数、黄色枠が引く数で一番下の赤枠が引いた結果です。こちらはフツーにリバース演算。
最後は「R」と「P」付のFSUBRPです。オペランド無。またまたルール発動。緑枠が引かれる数、黄色枠が引く数で一番下の赤枠が引いた結果です。こちらはリバースのリバースで普通な順番に見えないこともない。
引き算の順序に翻弄されるとは、トホホ。