ぐだぐだ低レベルプログラミング(234)x86(16bit)、続、FPU制御命令

Joseph Halfmoon

前回、8087数値演算コープロセッサの制御命令の一覧を掲げました。全部を一気に説明するつもりが、ほんの一部の命令を説明したところで力尽きてました。今回は残りの制御命令を端から見ていきたいと思います。ううむ、アセンブラの実習はまたまた次回に見送りだな。なかなか「低レベル」練習に戻れませぬ。

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

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

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

前回は、8087系FPUの environment と state をセーブ、レストアする命令を調べておわってました。 今回はその残りね。

FINIT/FNINIT

8087系FPUの「レジスタファイル」がフツーの汎用レジスタと異なるのは、

    • スタック構造でレジスタ間に順番がつけられている
    • レジスタの値がバリッドな数値なのかそれ以外のものなのか識別されている

そのため「レジスタファイル」を一体不可分のものとして出し入れする命令があることを前回調べました。そういう点では、セーブするものはないけれども、初期状態に戻して~ということはままありそうです。そんなときに使うのが、FINITとFNINITです。2文字目にN付とそうでないものの2種類があり、その違いを前回やってますが、基本的な機能は同じです。フラグ共やTAG共を初期化(デフォルト値、RESET時と同じ)して、「いつもの」状態に戻してくれるのがこの命令です。これを使うとレジスタスタック上で続けてきた計算内容は全て失われるので心して使わんと。

FWAIT

頭文字に「F」がついているので、8087FPU命令のような顔をしてますが、実は8086側で処理される命令っす。通常、8087での計算結果を8086が知るには、8087がその結果をメモリに書きこんでくれないとなりません。8087側で長い計算のあとその結果のメモリへの書き込みが出来ていない期間、8086側を「待たせる」ために使うのがFWAIT命令デス。

本件については、以下の過去回で8086と8087間の待ち合わせのハードについて説明しています。

ぐだぐだ低レベルプログラミング(212)x86(16bit)、WAITとESCAPE命令

その際、CPU側の命令として

WAIT

という命令が登場しましたが、ここで登場するFWAITと「同じ」命令です。でもWAITと綴るのと、FWAITと綴るのでアセンブラ(インテル純正ASM86では。 NASMはどうなんだろうか?調べてないよう)からの処遇が異なるのです。闇深い? 端的に言うとアプリケーション・プログラマは

WAIT

と書くな、ということみたいです。FWAITはいいみたい。これは8087のソフトウエアエミュレータを使うときのための配慮らしいです。アセンブラはWAIT書くと実在するWAIT命令として常にオブジェクトに書きこむということみたい。8087が実在しない(ソフトウエアでエミュレーション)なのにWAITしてしまうと、存在しない8087からの8086TESTピンへのREADY信号を待ってしまう(無限ループ)となる危険があると。一方、FWAITと書くと、アセンブラが良い塩梅に配慮してくれて、実機用なら実体のあるWAIT命令、エミュレータ用なら空命令にしてくれるみたい。便利ね~。

でもま、モノホンの8087を使っているのでなければ、FWAIT自体使うことがない筈なので、結局、無用の長物?黒歴史?

FNOP

FNOPはその名のとおり、8087のNOP(ノーオペレーション)です。CPUのNOP同様、「その実体は、実は」という命令あり。FNOPの実体は、スタックトップをスタックトップにストアする命令です。

FINCSTP、FDECSTP、FFREE

8087のレジスタスタックは8段しかありません。それを超えたらどうするの?という問いかけへのお答えが、ここで扱う3つの命令です。

    • FFREE、対象のレジスタを「空」にする(タグ操作)
    • FINCSTP、レジスタスタックのスタックポインタのインクリメント
    • FDECSTP、レジスタスタックのスタックポインタのデクリメント

各レジスタの内容自体はロード/ストア命令でメモリとやり取りできるので、スタックが不足したらメモリに書き出す、そして元に戻すといった操作は可能ですが、バリッドな値(やNaNやデノーマル数)が入ったままだと望まぬ挙動となる可能性もあり。そこでFFREEという命令で「空」にすることができます。

また、スタックポインタの値もFINCSTP、FDECSTPで操作できるので、これら3命令を使ってプログラマの方でレジスタスタックの「仮想化」頑張ってね、という感じっす。ハードウエアは8本しかないけれども、プログラマが頑張れば無限だ、と。ホントか?

FLDCW、FSTCW/FNSTCW

CW=CONTROL WORDです。過去回でやったとおり、各種の制御フラグを集めた16ビット・レジスタです。この値は、FSTCWまたはFNSTCW命令により16ビット幅のメモリに格納でき、また、FLDCW命令でメモリからロードできます。丸めの精度を制御したいとか、例外をマスクしたいとか希望があったらコレね。

FSTSW/FNSTSW

SW=STATUS WORDです。FPUのステータスを保持している16ビット・レジスタです。CWと対称に思えますが、そんなことはありません。ステータスに書き込むとか行儀の悪いことはしないよね、ということでSWへのロード命令は無いみたい。しかし「その代わり」にCPUのAXレジスタへの書き込みが可能です。過去回で使ってしまいましたが、これによりFPUのステータスフラグをAX経由、SAHF命令でCPUのFlagsに反映させるという荒業が可能です。これでFPUの結果を反映したプログラムの分岐も可能。

FCLEX/FNCLEX、FDISI/FNDISI、FENI/FNENI

8087の場合、「8087の検出した例外」は、フツーに8259割り込みコントローラを経由して8086に通知されます。8086からしたら、ペリフェラル共の割り込みと変わりませぬ。その割り込み発出の許可、不許可はCWの中のフラグで制御、それを上げ下げするのが

    • FDISI/FNDISI
    • FENI/FNENI

であります。

一方、上記の割り込みの元となる浮動小数点例外には、6種の要因あり、それぞれに例外発生のフラグと例外の許可(あるいはマスク)フラグが存在します。例外発生フラグ6個を一気にクリアするのが

FCLEX/FNCLEX

です。なお、8087でのハードウエアの副作用?として、FCLEXは割り込み線(8259へ行くやつ)をクリアした上に、8086に「BUSYだよ~」と言っていたらそれも取り下げてくれるみたい。CPU側がWAITの呪縛で止まっていたら外れる?ホントか?

ぐだぐだ低レベルプログラミング(233)x86(16bit)、FPU制御命令 へ戻る

コメントを残す

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