Div. Design

浮動小数点除算演算


目標

減算型でいく。基数 4 の SRT でいってみたいのだが、とりあえず基数 2 で。
サイクル数は 1 + 18 ( iteration ) + 2 = 21 サイクルを目標に。 ゲートは 10000 くらいでやりたいところ。


ゲート数の見積もり : 対 STARC

Weitek 3364 は 4 進 SRT で 165,000 ゲートの 3.9 % を、 TI 8847は 8b seed Goldschmidt 法で 180,000 ゲートの 5.0 % を使用している。
乗算型除算器の方が、ゲートを食う分だけ速いらしい。


SRT 法のサーベイ

基数 2 の SRT 法は、適当に修正された被除数から出発して、部分剰余の絶対 値を常に 0.25 以上にするようなアルゴリズムである。 これによって、除数と被除数のビット数に関わらず、常に一定のビットを参照 するだけで商を求めることができる。 とりあえず 通常の SRT で作ってみることにする。


やりなおし

単精度も標的にしつつ設計してみよう。

モジュール毎の動作

module fdiv_split(in,isdouble,s,e,upf);
        input [63:0] in;
        input isdouble;
        output s; // sign 
        output [10:0] e; // biased exp ( zero adjusted )
        output [52:0] upf; // unpacked mantissa

単精度か倍精度かで主に判断する、が、ただ分割するだけではなく

  1. 指数が0 ( = 表現されている値がデノーマル又は 0 ) のときは、指数を 1 とする
  2. 仮数はアンパックする

という作業を行う。

module fdiv_encode(upf,enc,isfzero);
        input [52:0] upf;
        output [5:0] enc;
        output isfzero;

module fdiv_presft(upf,enc,n);
        input [52:0] upf;
        input [5:0] enc;
        output [53:0] n;

module fdiv_qselect_top(nb,na,po,mo,zpo,zno);
        input [53:0] nb,na; 
	// divisor , dividend (initial partial remainder) 
        output [53:0] po,mo; // partial remainder 
        output [54:0] zpo,zno; 
	// on the fly conversion

但し、最初、商は 1 で固定である。

module fdiv_premux(in0,in1,start,out);
        input [380:0] in0,in1;
        input start;
        output [380:0] out;

実行時間の大部分は商を求める繰り返し部分だが、そこに投入する入力を選択する。

module fdiv_qselect(nb,pi,mi,zpi,zni,po,mo,zpo,zno);
    input [53:0] nb; // divisor
    input [53:0] pi,mi; // plusone , minusone
    input [54:0] zpi,zni; // zpi[54],zni[54] is dummy
    output [53:0] po,mo; // partial remainder , output
    output [54:0] zpo,zno; // on-the-fly conversion

module fdiv_exception(a,b,isdouble,out,flags,istrue);
        input [63:0] a,b;
        input isdouble;
        output [63:0] out;
        output [4:0] flags; // V,O,Z,U,I
        output istrue; // output is TRUE or Don't care

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

module fdiv_adjq(p54,m54,zp54,zn54,cancel,adjq);
    input [53:0] p54,m54;
    input [54:0] zp54,zn54;
    output cancel;
    // 1bit cancellation of quotient digit
    output [54:0] adjq; // with roundbit and stickybit

module fdiv_adje(ea,eb,enca,encb,cancel,isdouble,adje,sftbit);
        input [10:0] ea,eb;
        input [5:0] enca,encb;
        input cancel;
        input isdouble;
        output [12:0] adje;
        output [12:0] sftbit;

module fdiv_postsft(adjq,sftbit,sft);
        input [54:0] adjq; // 53b + r + s
        input [12:0] sftbit;
        output [54:0] sft; 

ここでは精度については気にせず、単に右シフトを行って 55 ビットのフォー マットに収まるようにしている。

module fdiv_round(sftq,s,isdouble,rmode,roundq,carry,iex);
        input [54:0] sftq;
        input s; // sign
        input isdouble;
        input [1:0] rmode;
        output [52:0] roundq;
        output carry;
        output iex; // inexact exception flag

但し、このモジュールは内部に丸めの純粋なロジックモジュール ( fdiv_roundlogic ) を持っている。

module fdiv_roundlogic(sib,lsb,rob,stb,rmode,pone,iex);
        input sib,lsb,rob,stb;
        input [1:0] rmode; // 00:RN , 01:RZ , 10:RP , 11:RM
        output pone;
        output iex; // to inexact exception flag

module fdiv_adjall(adje,roundq,carry,isdouble,ovi,oute,outf,flags);
    input [12:0] adje;
    input [52:0] roundq;  // roundq[52] is dummy
    // rounded , but uneconomized quotient
    input carry; // carry by rounding
    input isdouble;
    input ovi; // overflow-infinity
    output [10:0] oute;
    output [52:0] outf; // uneconomized format
    output [4:0] flags;

module fdiv_rflush(s,adje,roundq,isdouble,rflush);
    input s; // sign
    input [10:0] adje; // exp
    input [52:0] roundq; // roundq [52] is dummy
    input isdouble;
    output [63:0] rflush;

module fdiv_mux(normsef,normflags,excesef,exceflags,isexcetrue,mux,muxflags);
        input [63:0] normsef,excesef; // sign , exp , mantissa
        input [4:0] normflags,exceflags;
        input isexcetrue;
        output [63:0] mux;
        output [4:0] muxflags;

合成結果 ( FDIV )

モジュール名cost prim.時間 (ns)必要 数 小計 prim.
fdiv_split 1981.8662 396
fdiv_encode 3656.9882 730
fdiv_presft 8424.3682 1684
fdiv_qselect_top 2680.7391 268
fdiv_exception 7166.7551 716
fdiv_premux 11832.4261 1183
fdiv_qselect 18945.2841 1894
fdiv_resultinf 40.7331 4
fdiv_adjq 110310.4061 1103
fdiv_adje 8319.3671 831
fdiv_postsft 23455.1351 2345
fdiv_round 4648.8601 464
fdiv_adjall 2836.9811 283
fdiv_rflush 1701.8821 170
fdiv_mux 2172.5351 217
no clock, opt area -high, opt timing -high にて合成
[ primitive cost × 必要数 ] で、
必要な primitive cost が計算できる。


特殊数の演算 (EXCEPTION path)

ここで特殊数とは、SNaN と QNaN と Inf と 0 を指し、入力に対してこれら を排他的にアサートされる 4 ビットで入力の状態を決定する。全てのビット が立っていなければ、それは通常の有限数を意味する。以下の仕様に基づいて 作る。

結果 / 例外一覧
演算種類結果例外
SNaN / SNaN
SNaN / QNaN と QNaN / SNaN
SNaN / 0 と 0 / SNaN
SNaN / Inf と Inf / SNaN
SNaN / W と W / SNaN
Inf / Inf と 0 / 0
QNaNV
QNaN / QNaN
QNaN / 0 と 0 / QNaN
QNaN / Inf と Inf / QNaN
QNaN / W と W / QNaN
QNaN-
0 / Inf と W / Inf
0 / W
符号付き 0-
Inf / 0 と Inf / W符号付き Inf -
W / 0符号付き InfZ
W / W?(W,Inf,0)?(O,U,I)
V : Invalid Operation , O : Overflow , Z : Zero Divide , U : Underflow , I : Inexcact


各ステージへの分割

各ステージに分割したモジュールのインターフェースは以下の通り。

module fdiv_1(CLK,a,b,isdouble,rmode,start,
fp,fm,fzp,fzn,fnb,fovi,frmode,fs,fea,feb,fenca,fencb,
fisdouble,fexception,fexceflags,fisexcetrue,fstart);

        input CLK;
        input [63:0] a,b;
        input isdouble;
        input [1:0] rmode;
        input start;

        output [53:0] fp,fm;
        output [54:0] fzp,fzn;
        output [53:0] fnb;
        output fovi;
        output [1:0] frmode;
        output fs;
        output [10:0] fea,feb;
        output [5:0] fenca,fencb;
        output fisdouble;
        output [63:0] fexception;
        output [4:0] fexceflags;
        output fisexcetrue;
        output fstart;

module fdiv_2(CLK,fstart,
fp,fm,fzp,fzn,fnb,fovi,frmode,fs,fea,feb,fenca,fencb,
fisdouble,fexception,fexceflags,fisexcetrue,
sp,sm,szp,szn,snb,sovi,srmode,ss,sea,seb,senca,sencb,
sisdouble,sexception,sexceflags,sisexcetrue,
dp,dm,dzp,dzn,dnb,dovi,drmode,ds,dea,deb,denca,dencb,
disdouble,dexception,dexceflags,disexcetrue);

	input CLK;
	input fstart;

	input [53:0] fp,fm;
	input [54:0] fzp,fzn;
	input [53:0] fnb;
	input fovi;
	input [1:0] frmode;
	input fs;
	input [10:0] fea,feb;
	input [5:0] fenca,fencb;
	input fisdouble;
	input [63:0] fexception;
	input [4:0] fexceflags;
	input fisexcetrue;

	input [53:0] sp,sm;
	input [54:0] szp,szn;
	input [53:0] snb;
	input sovi;
	input [1:0] srmode;
	input ss;
	input [10:0] sea,seb;
	input [5:0] senca,sencb;
	input sisdouble;
	input [63:0] sexception;
	input [4:0] sexceflags;
	input sisexcetrue;


	output [53:0] dp,dm;
	output [54:0] dzp,dzn;
	output [53:0] dnb;
	output dovi;
	output [1:0] drmode;
	output ds;
	output [10:0] dea,deb;
	output [5:0] denca,dencb;
	output disdouble;
	output [63:0] dexception;
	output [4:0] dexceflags;
	output disexcetrue;

module fdiv_3(CLK,
p,m,zp,zn,ovi,rmode,s,ea,eb,enca,encb,
isdouble,exception,exceflags,isexcetrue,
disdouble,ds,dadje,dsftq,dovi,drmode,dexception,dexceflags,disexcetrue);

	input CLK;

	input [53:0] p,m;
	input [54:0] zp,zn;
	/* input [53:0] nb; */
	input ovi;
	input [1:0] rmode;
	input s;
	input [10:0] ea,eb;
	input [5:0] enca,encb;
	input isdouble;
	input [63:0] exception;
	input [4:0] exceflags;
	input isexcetrue;

	output disdouble;
	output ds;
	output [12:0] dadje;
	output [54:0] dsftq;
	output dovi;
	output [1:0] drmode;
	output [63:0] dexception;
	output [4:0] dexceflags;
	output disexcetrue;
	
	reg disdouble;
	reg ds;
	reg [12:0] dadje;
	reg [54:0] dsftq;
	reg dovi;
	reg [1:0] drmode;
	reg [63:0] dexception;
	reg [4:0] dexceflags;
	reg disexcetrue;

module fdiv_4(
isdouble,s,adje,sftq,ovi,rmode,exception,exceflags,isexcetrue);
out,flags);
	
	input isdouble;
	input s;
	input [12:0] adje;
	input [54:0] sftq;
	input ovi;
	input [1:0] rmode;
	input [63:0] exception;
	input [4:0] exceflags;
	input isexcetrue;
	
	output [63:0] out;
	output [4:0] flags;

合成結果 ( FDIV )

モジュール名cost prim.時間 (ns)必要 数 小計 prim.
fdiv_1 624512.2521 6245
fdiv_2 1
fdiv_3 523615.3571 5236
fdiv_4 113917.4431 1139
no clock, opt area -high, opt timing -high にて合成
[ primitive cost × 必要数 ] で、
必要な primitive cost が計算できる。
最終段のみ組み合わせ回路

最終ステージが少し時間がかかりすぎているので、除算前の処理を重くして、 負荷分散させてやることが必要である ( 19971225 )


失敗基本部分の設計

モジュール毎の動作

module div_qselect(b,rsi,rci,zpi,zni,rso,rco,zpo,zno);
        input [31:0] b; // divisor
        input [31:0] rsi,rci; // sum/carry of partial remainder , input
        input [30:0] zpi,zni; // on-the-fly conversion
        output [31:0] rso,rco; // sum/carry of partial remainder , output
        output [31:0] zpo,zno;

キャリーセーブ表現の部分剰余 rsi , rci から商を判定して

  1. 次の部分剰余 rso , rci
  2. on-the-fly 変換を施した商ビット列 zpo , zno

を返す。

商の選択が少し変形していびつだが、範囲にちゃんと入るようになっている。

部分剰余 対応ビット列対応ビッ ト列
0 以上 0.11
0.10
0.01
0.00
+1 01
-0.5 以上 0 未満 1.11 0 10
-0.5 未満 1.10
1.01
1.00
-1 00
1.00 と 0.11 は、元々あってはいけないような気がする

部分剰余のアルゴリズムは

  1. qi が 1 なら、減数 B2 を除数 B の反転 ( + 1 ビット符号拡張 ) として CSA に投入し、CSA キャリーの最下位に 1 を吐く

  2. qi が 0 なら、減数 B2 を 0 にして CSA に投入し、CSA キャリーの最下位に 0 を吐く

  3. qi が -1 なら、減数 B2 を除数 B として CSA に投入し、CSA キャリーの最下位に 0 を吐く

これを表にすると

qi 減数 B2 LSBofCarry
+1 ~B 1
0 0 0
-1 B 0

となる。

また、on - the - fly 変換は具体的に以下の通り。

qi ZPi ZNi
+1{ ZPi - 1 , 1 } { ZPi - 1 , 0 }
0{ ZPi - 1 , 0 } { ZNi - 1 , 1 }
-1{ ZNi - 1 , 1 } { ZNi - 1 , 0 }

基本部分の合成結果 失敗

モジュール名cost prim.時間 (ns)必要 数 小計 prim.
div_encode 1493.3432 358
div_presft 420 3.9201 618
div_qselect_top 163 0.7391 163
div_qselect 1141 5.3731 1141
div_postsft 4913.7321 491
no clock, opt area -high, opt timing -high にて合成
[ primitive cost × 必要数 ] で、
必要な primitive cost が計算できる。


一歩前へ
僕のホームへ[Home]
研究室のページへ[Amano Lab.]
Takahiro Kawaguchi kawaguti@aa.cs.keio.ac.jp
Last modified: Nov. 9, 1997