Add./Sub. Desgin

浮動小数点加算演算

マックス書きかけ。

To Do After Bachelor Thesis

Tininess のポリシーを After Rounding から Before Rounding に変更する。 そして、バグ取り。


特殊数の演算 (EXCEPTION path)

卒論直前にやっただけあって、変更の必要無し。

ここで特殊数とは、SNaN と QNaN と Inf と 0 を指し、入力に対してこれら が排他的にアサートされる 4 ビットで入力の状態を決定する。入力オペラン ドは 2 つなので、この部分は 8 ビットで構成される。加減算の場合は更に有 限数である 2 数の絶対値が等しい有限数かどうかを判断するビット 1 ビット を立てて、計 9 ビットで構成される。各 4 ビットについて、全てのビットが 立っていなければ、それは通常の有限数を意味する。以下の仕様に基づいて作 る。

結果 / 例外一覧
演算種類結果例外
SNaN ± SNaN
SNaN ± QNaN と QNaN ± SNaN
SNaN ± 0 と 0 ± SNaN
SNaN ± Inf と Inf ± SNaN
SNaN ± W と W ± SNaN
(+Inf) + (-Inf) と (+Inf) - (+Inf)
(-Inf) + (+Inf) と (-Inf) - (-Inf)
QNaNV
QNaN ± QNaN
QNaN ± 0 と 0 ± QNaN
QNaN ± Inf と Inf ± QNaN
QNaN ± W と W ± QNaN
QNaN-
(+Inf) + (+Inf) と (+Inf) - (-Inf)
(+Inf) + W と (+Inf) - W
W + (+Inf) と W - (-Inf)
(+Inf) + 0 と (+Inf) - 0
0 + (+Inf) と 0 - (-Inf)
+Inf -
(-Inf) - (+Inf) と (-Inf) + (-Inf)
(-Inf) + W と (-Inf) - W
W - (+Inf) と W + (-Inf)
(-Inf) + 0 と (-Inf) - 0
0 - (+Inf) と 0 + (-Inf)
-Inf -
W + 0 と W - 0
0 + W
( + ) W-
0 - W- W-
(+0) + (+0) と (+0) - (-0) +0-
(+0) + (-0) と (+0) - (+0)
(-0) + (+0) と (-0) - (-0)
(+A) - (+A) と (+A) + (-A)
(-A) - (-A) と (-A) + (+A)
RN,RZ,RP なら +0
RM なら -0
-
(-0) + (-0) と (-0) - (+0) -0-
(+A) + (+A) と (+A) - (-A)
(-A) - (+A) と (-A) + (-A)
W + Z と W - Z
?(W,Inf,0)?(O,U,I)
V : Invalid Operation , O : Overflow , Z : Zero Divide , U : Underflow , I : Inexcact

W , Zは、どちらも非ゼロの有限な、絶対値の異なる ( 符号付きの ) 値とす る。また、非ゼロの有限数値の絶対値を A と書いている。そして、 2 つの有 限数のオペランドの絶対値が等しいときは、W や Z ではなく A を用いて判断 を行い、A を用いるときは必ず符号をつけて書いている。ややこしいので注意。

なお、合成結果は 1707 ゲートの 10.099 ns


fp_adder トップレベル階層のモジュール

浮動小数点加減算のトップ階層はモジュール fp_adder であり、その構成モジュー ルは以下の通り。

fadd_1 を構成するモジュール
モジュール名クロック下位階層 ゲート数 クリティカルパス[ns]
fadd_112,50118.069
fadd_25,53017.090
fadd_3不要2,785 7.705

つまんない。各ステージ毎にモジュールを割ってあるだけ。第3ステージだけ は、このまま上位階層のマルチプレクサを通してからラッチをかけるため、 組み合わせ回路になっている。他はラッチ込みの合成結果。


fadd_1 階層のモジュール

fadd_1 を構成するモジュール
モジュール名クロック下位階層 ゲート数 クリティカルパス[ns]
fadd_split不要1981.866
fadd_exception不要158710.573
fadd_far_13458(嘘)14.461(嘘)
fadd_clo_1354111.135


fadd_2 階層のモジュール

fadd_2 を構成するモジュール
モジュール名クロック下位階層 ゲート数 クリティカルパス[ns]
fadd_split不要1981.866
fadd_exception不要158710.573
fadd_far_13458(嘘)14.461(嘘)
fadd_clo_1354111.135


fadd_3 階層のモジュール

fadd_3 を構成するモジュール
モジュール名クロック下位階層 ゲート数 クリティカルパス[ns]
fadd_split不要1981.866
fadd_exception不要158710.573
fadd_far_13458(嘘)14.461(嘘)
fadd_clo_1354111.135

module add_expdiff(ea,eb,ls,df,be,eq);
        input [10:0] ea,eb;
        output ls; // less : ea < eb 
        output [10:0] df; // diff : abs(ea-eb)
        output [10:0] be; // larger exp of ea,eb 
        output eq; // equal : ea = eb

入力オペランドの指数部 ea , eb を入力として
  1. 指数の大小 ( ea < eb なら ls 、 ea = eb なら eq を立てる )
  2. 指数の差の絶対値 ( diff )
  3. 大きい方の指数の値 ( be )
を返す。

module add_unpack(allorea,alloreb,fa,fb,upfa,upfb);
        input allorea,alloreb;
        input [51:0] fa,fb;
        output [52:0] upfa,upfb; // unpacked fa/fb

デノーマルの際、普通にアンパックを行うと、一番左に 0 を 1 ビット挿入す るが、ここでは、一番右に 0 を挿入している。後でシフタにかける際、この 部分がちゃんと調整されて出力される。


近い値同士の減算回路 : CLOSE path

まず、デノーマルの時の指数の値は、Emin - 1 ( = 0 ) ではなく、Emin ( = 1 ) として考えることにする。
そして、例外パスはとりあえず無視して、このパスが取り扱うのは

である。また、後者の条件を満すものは、指数の差が 1 のときだけなので ( = 指数の差が 2 以上の場合、桁落ちは 2 ビット以上起こらないので ) と、( 等価に ) 置き換えることができる。 しかし、ここで少し条件を変更して と、CLOSE のカバーする範囲を広げてしまうことにした。これによって、FAR path では、減算によって、正規化数からデノーマルに落ちるというケースを 考える必要が無くなる。
( 指数の差が 2 以上のときは、桁落ちが高々 1 ビットまでで、大きい方の指 数を 1 だけ引いたところで、差が 2 以上あるので、その値はデノーマルには ならない )

担当パート ( 例外パスを除く )
桁落ちビット数指数の差 ( ※ )実効命令担当
-( don't care ) ADD ( 1 )FAR
( don't care )
0
2 以上
1
SUB ( 0 )FAR
1以上
( don't care )
1
0
SUB ( 0 )CLOSE
※デノーマルの指数は Emin としたとき

ちなみに、この条件の変更によって、Emin の正規化数とデノーマルの減 算で、桁落ちをするものもカバーする必要が生じた。 ( あたりまえ )

条件毎に、問題点を洗ってみる。

  1. 指数の差が 0 で、かつ正規化数同士の減算

    今のところ問題無し。

  2. 指数の差が 0 で、かつデノーマル同士の減算

    この時点では、アンパック回路を FAR path のそれと分離して、単純な回路を組むことに メリットがある。 ( ここまで単純だともはやモジュールにする価値がない )
    つまり正規化数同士の時と、小数点の位置を変更しない方がいいような気がする。

  3. 指数の差が 1 で、かつ正規化数同士の減算

    小数点を固定すれば、問題無いように見える。

    この後、判断しなければならないのが、桁落ちがあったかどうかである。もし も桁落ちが起きなければ、丸めの必要性が生じるため、CLOSE path では手に 負えない。

  4. 指数の差が 1 で、一方が最小指数の正規化数で、一方がデノーマルの時

    問題なさそう。むしろこれは指数の差が 0 のカテゴリに組み入れるべ きではないか? ( = 結果に関わらず CLOSE path を採用する )
    というのは、この場合、常に丸めの必要が無いからである。

なぜこれまで悩んでいたのだろう?なんなんだいったい

各モジュールについて

module add_clo_comparexp(ea,eb,eq,og,ol,be);
        input [10:0] ea,eb;
        output eq; // equal : ea2 = eb2
        output og; // one greater : ea2 = eb2 + 1 
        output ol; // one lesser  : eb2 = ea2 + 1
        output [10:0] be; // bigger exp of ea,eb

入力の指数 EA , EB から

  1. eq ( EQual ) : 等しいかどうか
  2. og ( One Greater ) : EA が EB より 1 だけ大きいか
  3. ol ( One Lesser ) : EB が EA より 1 だけ小さいか
  4. be ( Bigger Exp ) : EA , EB の内、大きい方
を返す。既に書いたように、EA , EB はデノーマルのとき、 1 とみなして比 較を行っている。 実際には、それを EA2 , EB2 として一旦変換してから比較している。

module add_clo_adder(upfa,upfb,sa,ndga,ndgb,odga,odgb);
        input [52:0] upfa,upfb; // unpacked FA/FB
        input sa; // sign of FA
        output [54:0] ndga,ndgb,odga,odgb; 
        // No/One-Differnce, Greater-FA/FB  with sign ( MSB )

アンパックした仮数 ( upfa , upfb ) を元に、ビットシフトの有無と仮数の 絶対値の大小を予想して 4 通りの減算出力を返す。具体的には

を計算して、後で選択する。そしてそれと同時に、 4 通りの各々について符 号は一意に決まってしまうため、ついでに出力の MSB を符号ビットとしてい る。

符号について

CLOSE において、返す符号は以下の通り。

MSBofNDGAeqogolSign
( don't care )001! SA
( don't care )010SA
0
1
100SA
! SA

MSBofNDGA は、桁が同じで、fa > fb と仮定したときの減算結果 NDGA の MSB で、SA は入力 A の符号である。

なお、減算の結果が 0 になってしまった場合、符号は丸めモード等も考慮し たものになり、上記の表は適用されない。
( この場合は取り扱いがややこしいので、Exception path で処理することに している )

ここで問題が一つ発生。

指数が、最低の値とデノーマルの場合、つまりそれは Emin と Emin - 1 ( 修 正して Emin となる ) のときなのだが、そのとき上表ではうまくいかない。
( 最小指数とデノーマルとの減算で、桁落ちが無い場合に正しくない )

いろいろ対応手段は考えられるのだが、どこかで必ず帳尻を合わせなければい けないもののようなので、ここで調節してしまう。

真理値表に、仮数の MSB である MSBofFA と MSBofFB を加えて修正する。

ついでに、並列に計算した 4 通りの減算の結果のどれを選択すればいいかも 書いておく。

MSBofNDGAMSBofFAMSBofFBeqogolSignSelect
( don't care )( don't care )( don't care )001! SAODGB
( don't care )( don't care )( don't care )010SAODGA
( don't care )10100SANDGA
( don't care )01100! SANDGB
0
1
00100SA
! SA
NDGA
NDGB
0
1
11100SA
! SA
NDGA
NDGB

ここで気づく。符号の選択と、4 つの減算結果選択は、独立に行うべきではない。 4 通りの計算をした時点で、符号が決まっているので、4 通りの計算を行った ときに符号ビットを追加して、計算を選択すれば、符号も同時に計算される。

仮定した減算結果と符号の対応は以下の通り。これで結果を選択すれば正しい 符号も一緒に得ることができる。

SubtractSign
NDGASA
NDGB~SA
ODGASA
ODGB~SA

つまり、手順としては

  1. 指数の差と仮数の大小を予測して、NDGA , NDGB , ODGA , ODGB の 4 通りの減算をする。一緒に符号も計算する
  2. その裏で、指数の差を計算して eq , og , ol を求める
  3. MSBofNDGA , MSBofFA , MSBofFB , eq , og , ol を制御信号として 4 通りの答えのうち 1 つを選択する。すると正しい符号もおまけで選択される
となる。上記 2 表に基づいて

module add_clo_mux(ndga,ndgb,odga,odgb,msbfa,msbfb,og,ol,sc,fc);
        input [54:0] ndga,ndgb,odga,odgb; // MSB is signbit
        input msbfa,msbfb; // MSBofFA , MSBofFB
        input og,ol; // equal is not needed by using don't care
        output sc; // sign of result
        output [53:0] fc; // mantissa of result

を設計する。入力に指数が同じかどうかという信号 eq が無いが、これは、 og = ol = 0 のときは eq が立っていると仮定して計算しているためである。
( 本当に eq だったかどうかは、次の add_clo_valid で判断する )

module add_clo_valid(msbfc,og,ol,eq,ecmd,valid);
        input msbfc; // MSB of FC
        input og,ol,eq; 
        input ecmd; //  effective command ( sub : 0 , add : 1 )
        output valid; // this calc is valid / invalid

CLOSE path がカバーするオペランドの範囲は前述の通りだが、 add_clo_valid は、具体的にそれを判断する回路。改めてその条件を書けば

  1. 実効演算 ecmd ( Effective CoMmanD ) が減算であること
    ( あたりまえだが見逃すと悲惨 )

  2. add_clo_comparexp の出力 eq が立っている
    もしくは、 og , ol のどちらかが立っていて、そのとき桁落ちがあったとき。

    桁落ちがあるということは、減算結果の MSB ( MSBofFC ) が 0 ということ。
    なお、 MSB が 1 でも LSB が 0 なら、丸めを行う必要がなく、 CLOSE パスでも カバーは可能である。もし FAR で何かが起きたら使うことにするが、今のところは LSB は使わないことにする。
    ( また、eq のときは、MSBofFC = 1 となるときもある ( デノーマル絡み ) が、しかし LSBofFC は必ず 0 になることに注意 )

となる。真理値表は以下の通り。

MSBofFCog | oleqecmd CloseValid
( don't care )( don't care )( don't care ) 1 0
( don't care )( don't care )1 0 1
( don't care ) 0 0 0 0
0 1 0 0 1
1 1 0 0 0
ecmd は有効演算で、sub なら 0 で、add なら 1

module add_clo_encode(in,encode);
        input [53:0] in;
        output [5:0] encode;

ただのエンコーダ。この出力を用いて、デノーマルに落ちたときも考慮した、 シフト数を計算する。

module add_clo_adjexp(be,encode,ec,shift);
        input [10:0] be; // Bigger Exp
        input [5:0] encode; // encoded value
        output [10:0] ec; // result exp ( denormal -> ec = 0 )
        output [5:0] shift; // shift bit

指数 be ( Bigger Exp ) とモジュール add_clo_encode の出力 encode から、 調節した指数 ec と最終段でシフトすべきビット数 shift を計算する。 なお、初段の add_clo_comparexp で、デノーマルのときの指数部の値を Emin ( = 1 ) に修正したが、ここでまたデノーマルの場合は Emin - 1 ( = 0 ) に 戻す。
be と encode の差で判断する

be - encodeecshift
1 以上 be - encode encode
0 以下 0 be - 1

module add_clo_shift(in,shift,out);
        input [53:0] in;
        input [5:0] shift;
        output [53:0] out;

入力 54 ビットのうち実際に使用するのは、 out[52:1] の 52 ビット ( けち 表現 ) で、MSB と LSB は使用しない。何も考えずに切り捨てているだけなの で、他がきちんとしていないとここでバグる。
( もっとも、MSB を underflow の判断に使っているが )

また、CLOSE path とは直接関係無いが、EXCEPTION path と、CLOSE pathのど ちらの結果を使用するかをこの段階で決定してしまう。この段階で行う根拠は

EXCEPTION path の実行時間 < CLOSE path の実行時間 < FAR path の実行時間

という仮定に基づいている。即ち、この段階では FAR path の計算は 終了していないという仮定である。

module add_clo_excorclo(
excvalid,se,ee,fe,ive,ofe,ufe,iee,
sc,ec,fc,ufc,
so,eo,fo,ivo,ofo,ufo,ieo);

    input excvalid;
    input se;
    input [10:0] ee;
    input [51:0] fe; // economized expression
    input ive,ofe,ufe,iee;
    // invalid , pverflow , underflow , inexact flag

    input sc;
    input [10:0] ec;
    input [51:0] fc; // economized expression
    input ufc;
    // invalid , pverflow , underflow , inexact flag

    output so;
    output [10:0] eo;
    output [51:0] fo; // economized expression
    output ivo,ofo,ufo,ieo;
    // invalid , pverflow , underflow , inexact flag
以下の表に従うように解の選択をする。EXCEPTION path が有効かどうかを示 しているビット ExcValid は、最優先権を持ち、続いて CLOSE path が優先権 を持つ。そのどちらも無効であったときに初めて FAR path が有効と認めるこ とができる。

最終解の選択表 ( EXCEPTION or CLOSE )
ExcValidCloValidSelected
1( don't care )Exception path
01CLOSE path
00FAR path

実際には、ExcValid が 1 なら EXCEPTION path の答えを返し。 そうでなければ CLOSE path の値を返す

CLOSE path の合成結果

モジュール名cost prim.時間 (ns)必要数 小計 prim.
add_clo_comparexp 481 5.9351 481
add_clo_adder 2848 8.8881 2848
add_clo_mux 370 2.3041 370
(ここまでの
組み合わせ回路 )
3518 10.7141 3518
add_clo_valid 4 0.9881 4
add_clo_encode 371 7.2531 371
add_clo_adjexp 247 5.9111 247
add_clo_shift 804 4.7821 804
(ここまでの
組み合わせ回路 )
5122 27.9151 5122
add_clo_excorclo 2091.9931 209
no clock, opt area -high, opt timing -high にて合成
[ primitive cost × 必要数 ] で、
必要な primitive cost が計算できる。


桁合わせシフトが必要な演算 : FAR path

ここでも、デノーマルの時の指数は Emin ( = 1 ) として考える。

カバーする範囲は、CLOSE path 以外のもの全て ( 例外パスも当然除く )。 具体的には

である。

各モジュールについて
module add_far_comparexp(ea,eb,be,df,ls);
        input [10:0] ea,eb;
        output [10:0] be; // bigger exp
        output [10:0] df; // difference : abs( ea - eb ) 
        output ls; // less : ea < eb 

入力である 2 つの指数部の値 ea , eb から

  1. 2 つのうち、大きい方の値 be ( Bigger Exponent field )
  2. 差の絶対値 df ( Difference )
  3. ea < eb のときに 1 を返す ls ( Less )
を計算する。( CLOSE path と違って、eq は多分使わないと思う )
CLOSE path 同様、デノーマルのときの指数部の値は Emin - 1 ( = 0 ) ではなく、 Emin ( = 1 ) として扱い、be も、それを返す。

と思ったら、問題発生

デノーマルを完全に Emin として扱うと、仮数の大小がはっきりしているにも かかわらずわからなくなってしまうケースが発生する。 FAR path の減算は、仮数の絶対値の大小 が完全に保証されている必要があるが、入力に Emin と Emin - 1 が入ってき たときに、次で説明する仮数のスワッパで正しさが保証されなくなる。
( そもそも、Emin - 1 -> Emin に写像変換しているため、持っている情報量 が落ちている )

これに対処するため、比較作業 ( ls の計算 ) だけについては、デノーマル でも変換することなく比較をして、 be と df に関しては、Emin - 1 を Emin に変換したとみなして計算することにする。

と思ったら、やっぱり必要ない

まずい部分は実は全部 CLOSE path がカバーしている範囲だった。でも速度的 に問題ないのでこのままにしておく。( というか戻したらむしろ遅くなった )

CLOSE path の add_clo_comparexp と、全く同じ働きをする同名の信号がある が、今のところ別々に作っている。あまりメリットは無いが、めんどくさいの で分けてある。楽。

module add_far_swapper(upfa,upfb,ls,sa,ecmd,fx,fy,sc);
        input [52:0] upfa,upfb;
	input ls; // less : ea < eb
        input sa; // sign of input A
	input ecmd; 
        // effective command = sa^sb^cmd ( sub : 0 , add : 1 )
	output [52:0] fx,fy;
	output sc; // sign of result

モジュール add_far_comparexp の出力 ls を用いて、アンパックした指数を スワップする。スワップされた値は fx , fy となる。

この fx と fy は、シフト後は、絶対値において fx > fy を保証するもので ある。但し 1 つ例外があって、指数フィールドの値が同じ場合はどちらが大 きいのかわからないので fx > fy は保証できない。しかし正確な大小がわか らないまま計算を続けると困るのは減算のみで、加算については、桁合わせさ えちゃんとやっておけばよい。そして減算については、そのような事態 ( 指 数が同じで fx > fy が保証されない : ハマる ) になるのは、実は全て CLOSE path の仕事で、こちらの担当ではないため、どうでもよい。

また、結果の符号 sc もついでに出力し、以下の表のように動作する。

ls ecmd sc
( don't care ) 1 sa
0 0 sa
1 0 ~sa

module add_far_shift(fx,fy,df,ecmd,sfx,sfy,rob,stb);
        input [52:0] fx,fy; // fx , fy
        input [10:0] df; // exp difference 
        input ecmd; // effective command ( sub : 0 )

        output [53:0] sfx,sfy; // shifted fx , fy
        output rob;
        output stb;

ただのシフタ + スティッキービットの検出。次の段で、この結果を加算器に 投入するのだが、加算減算に関わらずビット操作をしないでそのままつっこめ るようにここで工夫してみる。そのためには大きい方の仮数も手を加えなけれ ばいけないのだが、どうせクリティカルパスの裏での作業なので、めんどくさ いだけでとりたてて問題は無い。

演算器にかける前の、仮数の処理について

FAR path においては

  1. 桁上がりが 0 か 1 の加算 ( 全部の加算がこれに入る。あたりまえ )
  2. 桁落ちが 0 か 1 の減算 ( 正確には、指数の差が 1 で桁落ちの無い減 算および指数の差が 2 以上の全ての減算で、桁落ちが 1 でも指数の差が 0 や 1 だとそれは担当外になる )

が正しくできればよい。これを全て固定小数点で計算させるのは、生理的に抵 抗がある。ので、場合分けをして、加減算器に投入する際、少し加工する。

この辺に、設計のしわが全部寄ってしまっている。 やはり失敗かも。
加算と減算の 2 通りという大まかな加工を行い、更に細分化した場合分け等 は考えない。

  1. 減算

    FAR path では、桁落ちが最大 1 ビットのものまで考えている。下位の桁に保 護ビットを 1 ビット付加して 54 ビットで計算を行う。これで 1 ビット桁落 ちしたときにも丸めのための情報が十分得られる

         5         4         3         2         1         0
      321098765432109876543210987654321098765432109876543210
    
      aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa0
    - bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbG R S
      ------------------------------------------------------
       ccccccccccccccccccccccccccccccccccccccccccccccccccccc R S
    

         5         4         3         2         1         0
      321098765432109876543210987654321098765432109876543210
    
      aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa0
    - bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbG R S
      ------------------------------------------------------
      cccccccccccccccccccccccccccccccccccccccccccccccccccccR' S'
    

    なお、ボロー ( 後述 ) については後で考える。

  2. 加算

    桁上がりこそすれ、桁落ちすることがないために保護ビットをつける必要がな い。そのため、 53 ビットでいいのだが、どうせ減算が 54 ビット使用するの で、アンパックした仮数の MSB に 0 を付加して 54 ビットにしてしまう。

         5         4         3         2         1         0
      321098765432109876543210987654321098765432109876543210
    
      0aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
    + 0bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb R S
      ------------------------------------------------------
       ccccccccccccccccccccccccccccccccccccccccccccccccccccc R S
    

         5         4         3         2         1         0
      321098765432109876543210987654321098765432109876543210
    
      0aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
    + 0bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb R S
      ------------------------------------------------------
      cccccccccccccccccccccccccccccccccccccccccccccccccccccR' S'
    

結局、有効演算が加算である場合には、右シフトを 1 ビット余分に入れれば よい。このときの問題は、指数の差が Emax + 1 ( ビット列がオール 1 ) の ときの加算で、 Emax + 1 + 1 ビットシフトさせるようにシフタに指示するの だが、ビット列が全て 1 のときに 1 を加えると結果は 0 になり、シフタに は 0 ビットシフトをするような指令がでてしまう。しかしこれは、差が Emax + 1 のときは、∞か NaN なので、EXCEPTION path に任せてしまっているので、 影響は無いはずである。

module add_far_adder(x,y,roi,sti,ecmd,c0,c1,c2,roo,sto,br);
        input [53:0] x,y;
        input roi,sti; // roundbit in , stickybit in
        input ecmd;
        output [53:0] c0,c1,c2;
        output roo,sto; // roundbit out , stickybit out
        output br; // borrow bit

加減算モジュール。このとき並列に 3 つの計算を行う。加算なら

  1. X + Y
  2. X + Y + 1
  3. X + Y + 2
を、減算なら
  1. X + ~Y ( = X - Y - 1 )
  2. X + ~Y + 1 ( = X - Y )
  3. X + ~Y + 2 ( = X - Y + 1 )
を計算して、桁落ち / 桁上がり、丸めの結果に応じて選択する。

丸めという操作は、絶対値的には増えることはあっても減ることはないのに、 減算で ( X - Y - 1 ) という 1 だけ少ない値を計算させているのは、減算に ボロー ( borrow ) という概念を導入しているからである。

ボローについて

ボローとは、 54 ビットの減算器に引っかかっていない丸めビットとスティッ キービットを考慮したときに表われるものである。

丸めビットとスティッキービットのうち、少なくともどちらかのビットが立っ ている場合、被減算数から 1 を借りてきて、結果を調整する必要がある。
( どちらのビットも立っていない場合は、被演算数からは、何も借りなくてよい )

例えば、54 ビットの減算 ( A - B = C ) を考える。丸めビットとスティッキー ビットを R , S と書き、今、 R と S を無視して上位ビットの減算を行い、R , S をスルーさせて結果を出したとすると

  aaa.....aa0 
- bbb.....bbb R S
  -----------
  ccc.....ccc R S

となる。 R = S = 0 ならば、演算結果である c のビット列にはなんら影響は ないが、もし R = 0 , S = 1 だったときは、実際に 56 ビットに拡張して計 算すると、上位 54 ビットは、もはや C とは違う値のはずである。( その値 を仮に D とする )

  aaa.....aa0 0 0
- bbb.....bbb 0 1
  ----------- ---
  ddd.....ddd 1 1 

このとき、54 ビット減算器の LSB の桁で「ボロー」が発生していて、その借 りのせいで、ビット列 d は、ビット列 c よりも 1 だけ小さい値になってい る。そして丸めビットとスティッキービットも ( 0 , 1 ) から ( 1 , 1 ) に 変化している。つまり A - B - 1 が D の答えである。 これが、 3 通りの 減算で、 X - Y - 1 を計算している理由である。

結局、ボローに関する操作は

  1. ボローがあるかどうか
  2. ボローによって、丸めビットとスティッキービットがどのように変化したか
を知ればよい。 ボローが起きたかどうかを知るボロービットは具体的に
R | S
で表現される。

丸めビットとスティッキービットの変換は

RSR'S'
0000
0111
1010
1101

となる。ここまでを加減算器 add_far_adder の内部で、54 ビット加減算と並 列に行う。当然、ボローの処理は、有効演算が減算のときのみ行い、加算のときは、 そのままスルーさせる。

module add_far_round(fz_53,fz_1,fz_0,roin,stin,sib,rmode,pone,ie);
        input fz_53,fz_1,fz_0; // result of ADD/SUB [53],[1],[0]
        input roin,stin; // roundbit , stickybit
        input sib; // signbit of result
        input [1:0] rmode; // roundmode   00:RN , 01:RZ , 10:RP , 11:RM
        output pone; // plus one :  ROUND or NOT ROUND
	output ie; // inexact flag
このモジュールは、 X + Y と X + Y + 1 の 2 通りの両方について、投機的 に丸めを行うために用意されている。即ちこのモジュールは 2 つ用意する。

また、このモジュールは、丸めを実際に行う ( = 加算器で +1 する ) わけで はなく、 あくまで +1 するかどうか ( 出力 pone : Plus ONE )を判定する回 路である。 +1 するかどうかがわかったら、適切に切上げ ( 実は +1 のとき と、 +2 のときがある ) された解を選択するだけでよい。

また、不正確の例外フラグ InExact も出力する ( これも後のモジュール add_far_mux1 で選択される )

ところで、ここまでのプロセスを行うことで、A + B , A + B + 1 , A + B + 2 の 3 通りを計算するだけで本当に、ボローと桁落ち ( 桁上がり ) と丸め を考慮した全ての組み合わせを満たしているかどうかについて考える。

加算の場合と減算の場合の 2 つに分けて考えるが、共通の方針は以下の 2 点 である。

  1. 減算の場合

    減算については、ボローの有無と桁落ちの有無,、そして丸めによる切上げの 有無が選択の基準となる。

    ボローが無い場合は、丸めの判断を行う回路は A - B = A + ~B + 1 である。 反対にボローがあるときの丸めは A - B - 1 = A + ~B で行う必要がある。そ して更に、丸めによる切上げがあるかどうかで最終的な解を選択する。

  2. 加算の場合

    加算は減算の場合と異なり、ボローのような丸めを判断すべき選択を行う必要 がなく、桁上がりの有無と丸めによる切上げの有無の 2 つのみがパラメータ となる。

    丸めの判断は、全て A + B の結果を用いる。

    以上により、A + B , A + B + 1 , A + B + 2 で全ての場合を包括しているこ とが説明できた。この選択作業を実現したのが、モジュール add_far_mux1 で ある。

module add_far_mux1(msbc0,msbc1,pone0,pone1,ie0,ie1,br,ecmd,c0e,c1e,c2e,ief);
        input msbc0,msbc1; // MSB of C0 , C1
        input pone0,pone1; // PlusOne of C0 , C1 ( result of Roundlogic )
	input ie0,ie1; // inexact0,1
        input br; // borrow
        input ecmd; // sub : 0 , add : 1
        output c0e,c1e,c2e; // C0,1,2 Enable
	output ief; // inexact FAR path

3 つの加減算結果 C0 , C1 , C2 の中から以下の表に基づいて 1 つを選ぶた めの ( 冗長な ) 信号を吐く。各々の信号 C0E , C1E , C2E は、排他的にア サートされる。

MSBofC0 PlusOne0MSBofC1PlusOne1 BorrowecmdSelect備考
d 0 dd d1C0加算
切捨て
0 1 dd d1C1加算
切上げ
桁上無
1 1 dd d1C2加算
切上げ
桁上有
d dd0 00C1減算
借り無
切捨て
d d01 00( 不可能 )減算
借り無
切上 げ
桁落有
d d11 00C2減算
借り無
切上げ
桁落無
d 0dd 10C0減算
借り有
切捨て
0 1dd 10C1減算
借り有
切上げ
桁落有
1 1dd 10C2減算
借り有
切上げ
桁落無
d は ( don't care ) の意

また、各々 add_far_round で計算した不正確のフラグも選択する。

不正確フラグの選択
BorrowECmdSelected
x1InExact_0
1
0
0InExaqct_0
InExact_1

オーバーフローやアンダーフロー等も考慮した上での指数の調節を行うには、 まずオーバーフローの際の返り値を、丸めモードと結果の符号から判定しなけ ればならない。

module add_far_resultinfty(rmode,sc,ovi);
        input [1:0] rmode; // roundmode
        input sc;  // sign of result
        output ovi;

乗算器でも同じ動作をするモジュールを用いている。結果がオーバフローした ら即 INF を返すというわけではなく、丸めモードによっては表現できる有限 数の中で最大値を返す場合もある。

加減算器に投入する前のスワップの出力である結果の符号 sc と丸めモードを 用いて、オーバーフロー時に、INF を結果とするかどうかを判定するビット OVI を返す。

この操作は、加減算と並列に行うことができる。

オーバーフロー時における、丸めモード、符号と返り値
丸めモードSCOVI
RN ( 00 ) ( don't care ) 1
RZ ( 01 ) ( don't care ) 0
RP ( 10 )0
1
1
0
RM( 11 )0
1
0
1

module add_far_adjexp(be,ecmd,fc,ovi,ae,of,uf);
    input [10:0] be; // Bigger Exp ( from 
    input ecmd; // effective cmd. SUB:0 , ADD:1
    input [53:0] fc; //  FC = FA + FB
    input ovi; // output infinity as a result  if overflow
    output [10:0] ae; // adjusted exponent
    output [52:0] af; // uneconomized 53bit out
    output of,uf;

基本的には、浮動小数点加減算演算結果の指数は 2 つの入力オペランドのう ち大きい方の指数であるが、桁落ち等により、指数の調節が必要となる。

指数を調節しなければならない要因は 5 つある。

  1. 加算演算の桁上がりによる指数のインクリメント
  2. 加算演算の桁上がり ( インクリメント ) に伴うオーバーフローによる指 数の Emax + 1 への固定
  3. デノーマル同士の加算演算において、桁が上がらないことによるアンダーフロー
  4. 減算演算の桁落ちによる指数のデクリメント
  5. 減算演算の桁落ち ( デクリメント ) に伴うアンダーフロー ( デノーマ ル ) による指数の Emin - 1 への固定

更にオーバーフロー時には、Emax + 1 に指数を固定するのか Emax に固定するのかを モジュール add_far_resultinfty の出力 OVI から判断する必要がある。

なお、最後の要因であるデノーマルに落ちるやつは、実は CLOSE path の担当 であり、FAR path では無視しても構わないはずである。 しかし万が一を考えて、とりあえず実装してある。

3 番目の条件は、すっかり忘れていたもので、指数の修正には、加算結果の MSB だけではなく、もう 1 ビットだけ下位のビットが更に必要となる。こい つのおかげでだいぶ表が汚くなった。

桁上がり、オーバーフロー、桁落ち、アンダーフローを考慮した指数の調整
OVIMSBsFCECmdBEAdjustExp 例外
1
0
1x1Emax Emax + 1 ( = BE + 1 )
Emax ( = BE )
OFlow
x0x1Emax Emax ( = BE )-
x1x
0x
1Emin + 1 〜
Emax - 1
BE + 1
BE
-
x11
10
1Emin Emin + 1 ( = BE + 1 )-
x011Emin Emin ( BE )-
x001Emin Emin - 1 ( BE - 1 )UFlow
x1x
0x
0Emin + 1 〜
Emax
BE
BE - 1
-
x1x0EminEmin ( = BE ) -
x0x0EminEmin - 1 ( BE - 1 )
[CLOSE path]
UFlow
BE は、2 つの入力オペランドの指数のうち、大きい方
( 但し、デノーマルのときは BE = Emin となるように調節してある )

CLOSE path の担当、INF を返すところ、加算のデノーマルを除いて加減算の 動作は、対称になっている。

更にこの時点で、オーバーフロー等も含めた、特殊な仮数の値を採用するかどうかも 決まってしまうので、ついでに選択してしまう。 ( AF とする )

上表と違って、MSBofFC の 1 ビットだけあればよいことに注意。

オーバーフロー、アンダーフローを考慮した仮数の選択
OVIMSBofFCECmdBEAdjustedF
1
0
11EmaxALL 0
ALL 1
x11Emin 〜
Emax -1
FC[53:1]
x01xFC[52:0]
x1
0
0Emin + 1 〜
Emax
FC[53:1]
FC[52:0]
xx0EminFC[53:1]
FC は実際に加減算を行った仮数で、54 ビット

module add_far_mux2(
sc,ec,fc,ivc,ofc,ufc,iec,valec,
sf,ef_0,ef_1,ef_2,c0,c1,c2,c0e,c1e,c2e,off_0,off_1,off_2,uff_0,uff_1,uff_2,ief,
so,eo,fo,ivo,ofo,ufo,ieo);

        input sc; // sign of CLOSE
        input [10:0] ec; // exponenent of CLOSE path
        input [51:0] fc; // mantissa of CLOSE path
        input ivc,ofc,ufc,iec; // invalid , overflow , underflow , inexact
        input valec; // VALid EXCEPTION / CLOSE path

        input sf; // sign of FAR path
        input [10:0] ef_0,ef_1,ef_2; // exponenent of FAR path
        input [51:0] c0,c1,c2; 
        // mantissa of FAR path ( economize expression )
        input c0e,c1e,c2e;
        input off_0,off_1,off_2,uff_0,uff_1,uff_2,ief;
        // invalid , overflow , underflow and inexact(already determined)

        output so;
        output [10:0] eo;
        output [51:0] fo;
        output ivo,ofo,ufo,ieo;

最終の仮数、指数、フラグを選択する。add_far_mux1 はイネーブルの信号だ けだったが、add_far_mux2 では実際に選択を行う。 実際の回路は、複数段のマルチプレクサになるはず。

例外パスの信号もここで選択してしまうことにする。選択する信号の種類は、

  1. 符号 ( 1b )
  2. 指数 ( 11b )
  3. 仮数 ( economized , 52b )
  4. 例外フラグ ( Zero Divide を除いた 4b )
の 68 ビットである。これを 1 セットとして、EXCEPTION / CLOSE , FAR の 2 セッ トについて選択を行う。

最終解の選択表 ( 再掲 )
ExValidCloValidSelected
1( don't care )Exception path
01CLOSE path
00FAR path

EXCEPTIO path か CLOSE path かのどちらかということについては、既に選択 されているものとする。

その前の段階において、更に FAR path の内部の 3 通りに結着をつけるため の、仮数の選択を行う。

FAR path の解の選択
C0EC1EC2EFarF
100C0
010C1
001C2
C0E , C1E , C2E は、モジュール add_far_mux1 の出力

又、各パスで起こり得る例外は以下の通り。

参考 : 加減算演算での例外
パス例外
ExceptionIV , OF , OF with IEX , UF?
CLOSEUF
FAROF with IEX , UF , IEX
EXCEPTION path のフラグのとりかたには検討の余地がある
( or のとりかた )

結果が 0 のときにアンダーフローはだすのか?
出すっぽいので出しておく。
( しかし NonZero とか規格書に書いてあったような )

FAR path のオーバーフローは、必ず InExact になるように設定してある。

FAR path の合成結果

モジュール名cost prim.時間 (ns)必要 数 小計 prim.
add_far_comparexp 460 6.1921 460
add_far_swapper 336 2.9401 336
add_far_shift 3223 6.4281 3223
(ここまでの
組み合わせ回路)
385212.62613852
add_far_adder 2358 12.3961 2358
add_far_round 20 1.3312 40
add_far_mux1 16 1.2091 16
add_far_resultinfty 4 0.7331 4
add_far_adjexp 5124.3883 1536
add_far_mux24393.0271 439
no clock, opt area -high, opt timing -high にて合成
[ primitive cost × 必要数 ] で、
必要な primitive cost が計算できる。


初期の設計 ( かなり使えない )

計算を 3 つのパスに分解する

加減算をする際、

の 3 つの要素は、独立ではなく、互いに深く関係している。 桁合わせとは、加減算器に投入する桁がずれるのだから、演算の精度をあげな くては計算ができない。 それを丸めで精度を落とすと考えれば、桁合わせの左シフトが無いときは、丸 めを行う必要がないので、左シフトと丸めの必要性は、セットで( = 全く同じ として )考えてよい。
また、桁落ちが大きくなるのは、近い数同士の減算という条件があるのは明らかである。 そして近い数というのは、桁合わせのシフトが無いということとだいたい同じ (この曖昧さが曲者)なので。左シフトと右シフトが必要な条件は、排反的であるといえる。

ここまでわかっているのだから、これら 3 つを逐次的にやるのは、もったいない。 という考えに基いて、パスの分割を行う。 しかしこの条件だけでなく、無限大・NaN・デノーマルの問題もあるので、一 言で、ずばっとパスの分割定義を言うことができない。悩みの種。

パスの名前が、他の論文を参考にしてそれをそのまま使っていて、 その名前が最近ズレてて困っている。 http://sather.tutkie.tut.ac.jp/Doc-Ja/sather1_1/specification/ieee.html
オペランドとしての加減算と、実質の加減算

演算対象であるオペランド A , B の大小や符号次第では、命令として受け取った 加減算命令の種類が変化することがある。 アルゴリズムによって、多少根回しが異なるが、まず、常に | A | > | B | 、 A op B の計算を行うときのことを考える。

A の符号B の符号命令実効命令
++ADDADD
+-ADDSUB
-+ADDSUB
--ADDADD
++SUBSUB
+-SUBADD
-+SUBADD
--SUBSUB

表で見るまでもなく、一言で言ってしまえば、2 つのオペランドの符号が異な れば、演算の種類 (加算 / 減算) は反転する。つまり、演算の種類 (加算 / 減算) を 1 ビット値 command で表現しているとすると、実効演算は以下の通 りとなる。

(effective command) = (command) xor (Sign A) xor (Sign B)

また、上記の場合は結果の符号はAの符号となるが、当然、必ず第 1 オペランドの方が大きいというわけではない。 前表同様、絶対値の大きなオペランドを A、小さいオペランドを B とし、演算の記号は 実効演算とする。

演算結果の符号
A + BSign A
A - BSign A
B + ASign B
B - ASign ~B

更に、常に | A | > | B | という条件は、実装上の都合で、指数の大きさ が同じときに、必ずしも成立しない。
まだとちゅう

大規模な正規化シフトを必要しない演算 (FAR path)

以下のようなステップで演算を行う。
  1. けち表現を展開する ( unpack52 )

    52ビットを53ビットにふくらます操作。 正規化数か、デノーマルかで、けちってある最上位ビットに 1 を詰めるか 0 を詰めるかを決める。普通はそれでよいのだが、桁合わせ右シフト等の都合で、 少し変則的なアンパックを行う。 通常は
    	if(exp == 0)
    		return( { 1'b0, significand } );
    		          ~~~~~~~~~~~~~~~~~
    	else
    		return( { 1'b1, significand } );
    
    なのだが、実際は、このようにしている。
    	if(exp == 0)
    		return( { significand, 1'b0 } );
    		          ~~~~~~~~~~~~~~~~~
    	else
    		return( { 1'b1, significand } );
    
    デノーマルがオペランドに存在するとき、その指数フィールドは 0 にもかか らわず、実際に示しているのは、exp = 1 と同じ指数である。( エクセス 127 なので、本当に表現しているのは -126 ) そのため、正規化数とデノーマルとの間で、指数の差を計算すると、実際の指 数の差よりも、必ず 1 だけ大きな値になってしまう。この 1 のずれは、桁合 わせの際に 1 ビット余分に右シフトしてしまうことになる。それを防止する ために、あらかじめ 1 ビット左にシフトさせてあるのが、上記のルーチンで ある。これによって、余分な 1 ビット右シフトをそのままにしておいても、 結果的に相殺することができる。(それ以外にも、ロジックが簡単になるとい う理由から、この方法を採用している。確か、デノーマル同士の加算の時に、威力を発揮したはず。)

  2. 指数の差をとる ( sub11 )

    ただの減算器ではなく を返す働きをする。

  3. 必要ならスワップする ( swap53 )

    指数の差の結果 ( less ) に基づいて、スワップをするかどうか判定する。 但し、仮数まで比較を行わないため、指数の差が 0 のときは、正確なスワッ プ / 減算計算ができない。 (ちなみに、デノーマルは別として、指数の差が 0 の減算は必ず 1 ビット以 上桁落ちするので、この条件下のものは全て CLOSE にまわす)

  4. 指数の差だけ、小さい方の仮数を右にシフトする ( rsft53 )

    単なるバレルシフタであるが、注意すべきは、正規化数における最小の指数フィー ルドと、デノーマルの指数フィールドの差は 1 であるにもかかわらず、実際 には、双方の指数が示す値は同じ EMIN であるということである。 これに対処するため、指数の差をとる際、指数フィールドが 0 ならば、1 に 無理矢理直して差をとるという方法が単純だが、あえて今回は、差をそのまま にして、けち表現を展開するときにバイアスをかけて対処している。この方が、 後々都合がよい。( ステップ 1. のアンパックを参照)

  5. 並列加減算器に投入する ( compoundadder54 )

    実効命令の種類はあらかじめ計算しておき、 加算命令の場合は の 3 つを計算し、減算命令の場合は、 の 3 つを計算する。この結果は、丸めモード等の条件に従って選択される。

  6. 指数、仮数フィールドの調整 ( postadj )

    加算による桁の繰り上がり / 減算による桁落ちの有無を調べ、指数フィール ドの調整をする。(繰り上がり / 桁落ちを調べるのは双方 1 ビットまで)
    加算の結果が∞になる場合もサポートする。 ちなみに正規化数からデノーマルに落ちるのはサポートする必要がない。

  7. 並列に計算、調整した結果を、条件に従い選択する。( faraddlogic, farsublogic, select3to1 )

    減算はボロー (borrow, 後述) の有無と丸めの有無を調べ、 加算は桁の繰り上がりの有無と丸めの有無を調べる。


演算が正確な減算 (CLOSE path)

こちらのパスには、丸めを行う回路が一切ついていない。丸めが必要な減算は、 全て FAR path にまわす必要がある。 アンパックのように、FAR path と全く重複する部分については、同一モジュー ルを利用している。
  1. けち表現を展開する ( unpack52 )

    52ビットを53ビットにふくらます操作で、FAR path と全く同じモジュールを使う。 この変則的なアンパックのせいで、CLOSE path については害を被っており、後で adjustment というパラメータを生む原因となっている。(しかし、FAR path と同様の恩恵も受けていて、正規化数とデノーマルの両方を扱うには、結局ど こかで無理をしなければいけないのかもしれない)

  2. 指数の差をとる ( sub11 )

    差を取る、というよりも、さしあたって、差があるのかどうかという値 ( equal ) だけに注目する。その値によって、加算器の動作が変化する。 指数に差があれば、その差は 1 であるとして、計算を続けてしまっている。 差が 2 以上ある場合は、FAR path に任せてこちらは選択されないので、 いい加減な答えを出してしまって構わない。

  3. 加算器にかける ( paradder53 )

    FAR path でも問題になったように、指数の差だけとっている場合には、差が 0 のときに、必ず大きい方から小さい方を引いて、結果が正の値になるように しておく、ということが保証できない。 そこで、2 数 A, B の減算については という 2 つの値を並列に計算させておき、結果が正の方を選ぶ。 また、指数の差が 0 でないときには と計算させて、後で選択させている。
    ( 実は、後者の方、あまり意味がない。正確に差を出して、どちらが正しいの かを調べてから 1 つだけ計算しても、さほど時間はかからない )

    最後に、本当に差が 1 かどうかを判定する回路を、さっぱり作り忘れている。 かなり重要。

  4. 並列に計算した結果のうち 1 つを選択する ( selectclose )

    計算の結果と、指数の差の計算結果を用いて、 paradder53 の出力結果のうち 1 つを選択する

  5. CLOSE path を採用するかどうかを決める ( pathselectionlogic )

    今行っている計算が、正式な解として採用されるかどうか調べる。
    差が 1 かどうかを判定する回路はここに入れること。

  6. 正規化シフトに何ビット必要なのかをエンコードする ( encode54 )

    加減算と並列にエンコードできるとよいのだが、その方法が現在不明。

  7. 指数、仮数の最終調整 ( postadjclose )

    デノーマルに落ちたときの対処もここで行う。

  8. 正規化シフトを実際に行う ( lsft53 )




    特殊数の演算 (EXCEPTION path)

    A - B という減算は、 A + ( -B ) という加算におきかえて考える。

    X op Y Y = 0Y = WY = ∞Y = NaN
    X = 0(iii)(ii)(i)
    X = W(ii)(i)
    X = ∞(ii)(ii)(ii)(i)
    X = NaN(i)(i)(i)(i)

    但し、以下の説明では、(i),(ii),(iii) の順番で評価を行う必要がある。 (例外の強い順)
    また、(iii)においては、更に、オペランドの値に限らず、減算の結果が 0 に なるものも担当する。

    (i) NaNをオペランドとする演算
    Signalising NaN / Quiet NaN とかの関係は今は、あまり考えていない。

    X = NaN ?Y = NaN ?結果
    00d (担当外)
    01Y
    10X
    11X
    IsTruePath : (X==NaN) | (Y==NaN)

    (ii) ∞をオペランドとする加減算
    他に書いてあるのを見ると、こんな感じになっている。

    X = ∞ ?Y = ∞ ?実効命令 = ADD ?結果
    00dd (担当外)
    010{Sign ~X,∞}
    011{Sign X,∞}
    10d{Sign X,∞}
    110 NaN
    111{Sign X,∞}
    IsTruePath : (X==∞) | (Y==∞)

    これで、少しひっかかるのが、例えば、+∞ - 1.0 のような演算のときである。 この表では、+∞を返すことになる。こんな調子で、∞の界付近で、うろうろ加減算をすると、 おかしな答えになるはず。(サポートしている範囲ぎりぎりでうろうろしてい ることがもうダメなのであるが)
    ソフトがなんとかしてくれると期待する。

    (iii) 0 同士の加減算と、結果が 0 になる減算
    +0 と -0 の 2 種類を取る。

    +0 を とるのは
    1. オペランドが両方とも +0
      +0 - ( -0 ) は、これに含まれるはず。
    2. それ以外のオペランドの組み合わせで、丸めモードが RN,RP,RZ のとき
    のときで、-0 をとるのは
    1. オペランドが両方とも -0
      -0 - ( +0 ) は、これに含まれるはず。
    2. それ以外のオペランドの組み合わせで、丸めモードが RM のとき
    のときである。0 同士の演算でなくとも、結果が 0 になるような減算 (2つの 値が等しいときの減算) も、この法則に従うはずなので、それも考慮する。実 装の方から考えると、真理値表は以下の通り。なお、今回の設計では、 {RN,RZ,RP,RM} = {00,01,10,11} である。

    | X | = | Y | ?実効命令 = ADD ?X = 0 ?Rmode = RM ?結果
    111d X
    110d d (担当外)
    10d0 +0
    10d1 -0
    0ddd d (担当外)
    d : do not care


    自分が担当であるかどうかのビット IsTruePath は

    (|X|==|Y|) & ( (EffectCmd==SUB) | (X==0) )

    となる。


    埒があかん

    浅学非才の身、規格を調べながらやっていると、完璧にはまることがわかったので、確実に使 うと思われるモジュールを作る。モジュールに分割することで多少回路がだぶ りそうな予感がするが目をつぶる。当然、今までのアルゴリズムを利用する。

    さしあたって必要なのは、∞ / NaN を含まない回路で、オーバーフローの処理を考えないものを作る。
    一歩前へ
    僕のホームへ[Home]
    研究室のページへ[Amano Lab.]
    Takahiro Kawaguchi kawaguti@aa.cs.keio.ac.jp
    Last modified: March 17, 1998