
このところ8087浮動小数点コープロセッサの「メンドイ」話が続いてます。前回は丸めとか無限大の制御とかメンドイ奴らの説明で終わってました。今回は、ラスボス?例外の登場です。例外そのものもいろいろな種類があってメンドイのですが、それ以前に、例外がCPUの8086へと伝わる経路もまたメンドイです。8087は自立してるし。
※「ぐだぐだ低レベル プログラミング」投稿順indexはこちら
例外の伝達経路
まず、最初に申し上げないとならないのは、8087とその後継のFPUの中では初代の8087が特殊だ、ということです。ソフトウエア的な見た目は後継機種との互換性が高いので、これはハード的な意味です。
過去回でも申し上げましたが、8087は、CPUである8086とは自立した「コープロセッサ」です。なんとなれば、一時的にCPUのバスの制御権をさし止めて、8087自身がバスを制御してメモリとやりとりできるのです。8087をコープロセッサとして「つきあえる」プロセッサの主なところは以下の4つです。
-
- 8086
- 8088
- 80186
- 80188
上記の4種CPUに対しては8087が一手にコプロのお役割を果たします。
一方、後継のFPU、80287(80286の御供)、80387(80386の御供)の2機種に関しては、8087同様の「CPUとは別チップ」ではあるものの、自立性は大きく制限され、メモリとのやりとりなどは80286なり80386なりのCPU側が制御することになってます。FPUは浮動小数点計算を高速に行うばかりのIO装置に転落?してます。
さらに言えば80486プロセッサ以降では、CPUチップ内部にFPU機能は取り込まれてしまうので、CPU内の1演算回路にさらに落ちぶれて?ます。
以上のように3段階あるFPUとCPUの関係により、例外の伝達方法は以下のように異なってます。
-
- 初代の8087と8086の例外の接続では80系の標準的な割り込みコントローラ8259を介してINTR接続する(なお、80186/80188では外部の8259ではなく内蔵割り込みコントローラを介する)
- 80287と80387の場合、FPU専用端子があるので、それを使ってFPU例外を伝える
- 486以降のプロセッサはFPUを内蔵するので外部経由でFPU例外を伝える必要は無くなった
まあ物理的な配線は異なるものの、8087(とその後継)側で発生したFPU例外をCPU側に伝達することは出来る、とご理解くだされ。
FPU例外の発生タイミング
FPU例外そのものを検出するのは8087側ですが、8086と8087はFPU命令の実行を始めるときは「ランデブー」しているものの、8087が計算している横で8086は勝手にプログラムを進めています。よって8087が例外を検出した時点で、8086はもう先に行っている可能性が高いデス。よってFPUからの割り込みが発生しても「割り込まれた命令」はFPU例外発生の原因となった命令とは異なる筈。そこで過去回でちょっと出てきた以下の8087内蔵レジスタが活躍するわけです。例外ポインタね。
ここを見れば、どこの番地におかれたどんなFPU命令(ESC命令)が、どこの番地におかれたデータを処理したときに例外が発生したのか分かります。後はプログラマ様の方でよしなに、という感じっす。
例外の種類
ここに来てようやく、8087のステータスワードの下6ビットとコントロールワードの下6ビットのフラグ共が登場します。
ステータスワードのビットの方は、6種の例外のそれぞれの発生を知らせるフラグです。一方コントロールワードのビットを使うと、対応関係にあるフラグをマスクすることができるようになってます。
上記のエクセプション・ポインタが1個しかないことから分かる通り、8087は同時に例外を1個しかハンドルできません。よって複数の例外フラグが同時に上がるようなことがあっても「優先順位」の高い1個だけが8259に伝達されます。さらに言えば、8259がインタラプト・リクエスト信号をCPUに伝えても、CPU側で割り込み不許可にしていたら伝わりません。キビシー。
さて6種に例外は下のビットから以下の通りです。
-
- IE、不法操作
- DE、非正規数
- ZE、ゼロ割り算
- OE、オーバーフロー
- UE、アンダーフロー
- PE、桁落ち
1は、サポートされてない形式(過去回で疑似ナンタラとかやりましたな)を計算しようとしたとか、「静かでない」NaNを計算しようとしたとか、無限大とゼロを掛けようとしたとか、どうしてよいか8087も困るよ、という場合みたいです。
2は、正規化されたフォーマットでない「小さい数(非正規数)」を使って計算を続けるか否かの制御に使えるようです。非正規化数なんて精度落ちるからダメじゃんというときはマスクせず例外に落とします。いやいや頑張って計算続けてね、というときはマスクするといいみたいです。
3は、いわゆるゼロ割り算ですが、FDIV以外でもいくつか発生する命令があるみたい。奥が深いのう。
4は、計算結果が「ストアしきれない」ほどデカイぞ~、という場合に発生するみたいです。とりあえずマスクしておくと、前回でてきた「丸めモード」により無限大になったり、表現可能な最大の(正負)数になるみたい。ここでもいろいろメンドくてコマケールールがあり。
5は、結果が求める形式より「小さい」ときに発生するみたいです。これをマスクすると「非正規化数」が現れてきて、漸進的アンダーフローが実現できるみたい。
6の精度例外は、5のアンダフローとも関係ありで、計算結果が精度の劣化を生じたときにおこるらしいです。今の計算不正確だったよ、と。まあ多少の事は気にしない子はマスクしておけと。いいのか?
当然、計算前の状態に遡及できるかとか、指数部の「再バイアス」とかメンドイルールが目白推しです。これまた浮動小数素人老人にはキツイよ。あらえっさっさ、とくらあ。