├── README.md ├── doc └── R5FP.odp ├── rtl ├── R5FP_add_mul.v ├── R5FP_div.v ├── R5FP_inc.vh ├── R5FP_postproc.v └── R5FP_sqrt.v └── tb ├── tb_R5_float_add.v ├── tb_R5_float_div32.v ├── tb_R5_float_div64.v ├── tb_R5_float_mul.v └── tb_R5_float_sqrt.v /README.md: -------------------------------------------------------------------------------- 1 | # RISCV-FPU 2 | 3 | This project is aiming to design necessary floating-piont components for implementing RISCV processors. 4 | 5 | These components need to be tweaked for different implementations. I provide them just as reference designs. They have better PPA than the Berkeley hard-float and synopsys DesignWare. 6 | 7 | 8 | -------------------------------------------------------------------------------- /doc/R5FP.odp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jm2000/RISCV-FPU/6419663f6f8db0c5bda129b0f2576cd9ccd1a3be/doc/R5FP.odp -------------------------------------------------------------------------------- /rtl/R5FP_add_mul.v: -------------------------------------------------------------------------------- 1 | 2 | `include "R5FP_inc.vh" 3 | 4 | `define DEBUG $display 5 | 6 | module R5FP_add #( 7 | parameter EXP_W=5, 8 | parameter SIG_W=10) ( 9 | input [EXP_W+SIG_W:0] a, b, 10 | input [2:0] rnd, 11 | output reg [7:0] status, 12 | output [EXP_W+SIG_W:0] z); 13 | 14 | wire sign, isNaN, isINF, useA, useB, isZero0, newNaN; 15 | R5FP_add_special_cases #( 16 | .EXP_W(EXP_W), 17 | .SIG_W(SIG_W)) sp ( 18 | .a(a), .b(b), 19 | .sign(sign), .isNaN(isNaN), .newNaN(newNaN), .isINF(isINF), .useA(useA), .useB(useB), .isZero(isZero0)); 20 | 21 | wire [2:0] GRT; 22 | wire [EXP_W+SIG_W:0] z_tmp; 23 | reg [EXP_W+SIG_W:0] z_tmp2; 24 | wire isZero; 25 | R5FP_add_core #( 26 | .EXP_W(EXP_W), 27 | .SIG_W(SIG_W)) add ( 28 | .a(a), .b(b), .GRT(GRT), .isZero(isZero), .z(z_tmp)); 29 | 30 | reg [6:0] status_tmp; 31 | always @(*) begin 32 | status_tmp=0; 33 | status_tmp[`IS_NAN]=isNaN; 34 | status_tmp[`IS_INF]=isINF; 35 | status_tmp[`IS_ZERO]=isZero0; 36 | if(isNaN||isINF) status_tmp[`SIGN]=sign; 37 | if(useA==0&&useB==0) begin 38 | status_tmp[`STICKY]=GRT[0]; 39 | status_tmp[`IS_ZERO]=isZero; 40 | end 41 | if(isNaN) begin 42 | z_tmp2[SIG_W-1:0]=({SIG_W{useA}}&a[SIG_W-1:0])|({SIG_W{useB}}&b[SIG_W-1:0]); 43 | if(newNaN) z_tmp2[0]=1; 44 | end 45 | else begin 46 | if(useA) z_tmp2=a; 47 | else if(useB) z_tmp2=b; 48 | else z_tmp2=z_tmp; 49 | end 50 | end 51 | 52 | reg [EXP_W-1:0] zExp_tmp,tailZeroCnt; 53 | always @(*) begin 54 | tailZeroCnt=0; 55 | zExp_tmp=z_tmp2[EXP_W-1+SIG_W:SIG_W]; 56 | if(zExp_tmp>=`EXP_DENORMAL_MIN(EXP_W-1,SIG_W) && zExp_tmp<=`EXP_DENORMAL_MAX(EXP_W-1)) begin 57 | tailZeroCnt=1+(`EXP_DENORMAL_MAX(EXP_W-1)-zExp_tmp); 58 | end 59 | //$display("Here2 status_tmp:%b z_tmp2:%b isZero0:%b isNaN:%b isINF:%b useA:%b useB:%b zExp_tmp:%b %b %b", status_tmp,z_tmp2,isZero0,isNaN,isINF,useA,useB,zExp_tmp,`EXP_DENORMAL_MIN(EXP_W-1,SIG_W),`EXP_DENORMAL_MAX(EXP_W-1)); 60 | end 61 | R5FP_postproc #( 62 | .I_SIG_W(SIG_W+4), 63 | .SIG_W(SIG_W), 64 | .EXP_W(EXP_W)) pp ( 65 | .aExp(z_tmp2[EXP_W+SIG_W-1:SIG_W]), 66 | .aStatus(status_tmp), 67 | .aSig({2'b01, z_tmp2[SIG_W-1:0], (useA==0&&useB==0)? GRT[2:1] : 2'b00}), 68 | .tailZeroCnt(tailZeroCnt), 69 | .rnd(rnd), 70 | .aSign(z_tmp2[EXP_W+SIG_W]), 71 | .z(z), 72 | .status(status)); 73 | 74 | endmodule 75 | 76 | module R5FP_add_special_cases #( 77 | parameter EXP_W=5, 78 | parameter SIG_W=10) ( 79 | input [EXP_W+SIG_W:0] a, b, 80 | output reg sign, isNaN, newNaN, isINF, useA, useB, isZero); 81 | 82 | localparam E_MAX=((1<>shiftCnt; 155 | if(extraShift) res=res>>1; 156 | shiftRightJam={res,(smallerSig&~mask)!=0}; 157 | endfunction 158 | 159 | reg signed [EXP_W:0] expDiff; 160 | reg signed [EXP_W:0] lzCount,shiftCnt; 161 | reg extraShift, sameSign; 162 | reg [1:0] opType; 163 | reg [SIG_W+3:0] largerSig, smallerSig, smallerSigSh, smallerSigSh1; 164 | reg [SIG_W+3:0] zSigExt; 165 | parameter [1:0] NORMAL_ADD=0; 166 | parameter [1:0] NORMAL_SUB=1; 167 | parameter [1:0] SPECIAL_SUB=2; 168 | 169 | always @(*) begin 170 | lzCount=0; 171 | isZero=0; 172 | extraShift=1'b0; 173 | shiftCnt=0; 174 | expDiff=aExp-bExp; 175 | sameSign=(aSign==bSign); 176 | opType=sameSign? NORMAL_ADD : NORMAL_SUB; 177 | if(expDiff==0) begin 178 | zExp=aExp; 179 | if(aSig>bSig) begin 180 | largerSig=aSig; 181 | smallerSig=bSig; 182 | zSign=aSign; 183 | end 184 | else begin 185 | largerSig=bSig; 186 | smallerSig=aSig; 187 | zSign=bSign; 188 | end 189 | end 190 | else if(expDiff>0) begin //a is bigger 191 | zExp=aExp; 192 | zSign=aSign; 193 | largerSig=aSig; 194 | smallerSig=bSig; 195 | shiftCnt=expDiff; 196 | end 197 | else begin //b is bigger 198 | zExp=bExp; 199 | zSign=bSign; 200 | largerSig=bSig; 201 | smallerSig=aSig; 202 | shiftCnt=~expDiff; 203 | extraShift=1'b1; 204 | end 205 | if(!sameSign) begin 206 | smallerSigSh1=(expDiff==0)? smallerSig : smallerSig>>1; 207 | lzCount=DWF_lza(largerSig[SIG_W+2:2], smallerSigSh1[SIG_W+2:2]); 208 | if(expDiff==1||expDiff==-1||expDiff==0) opType=SPECIAL_SUB; 209 | end 210 | 211 | {smallerSigSh,sticky}=shiftRightJam(smallerSig, shiftCnt, extraShift); 212 | //`DEBUG("Here3.1 a:%b b:%b smallerSig:%b (%b) smallerSigSh:%b sticky:%b",a,b,smallerSig,shiftCnt,smallerSigSh,sticky); 213 | if(sameSign) zSigExt=largerSig+smallerSigSh; 214 | else zSigExt=largerSig-smallerSigSh-sticky; 215 | 216 | if(opType==NORMAL_ADD) begin 217 | if(zSigExt[SIG_W+3]==1'b1) begin 218 | sticky=sticky|zSigExt[0]; 219 | zSigExt=zSigExt>>1; 220 | zExp=zExp+1; 221 | end 222 | end 223 | else if(opType==NORMAL_SUB) begin 224 | if(zSigExt[SIG_W+2]==1'b0) begin 225 | zSigExt=zSigExt<<1; 226 | zExp=zExp-1; 227 | end 228 | end 229 | else if(zSigExt==0) begin 230 | zExp=0; 231 | isZero=1; 232 | end 233 | else begin 234 | zSigExt=zSigExt<=`EXP_DENORMAL_MIN(EXP_W-1,SIG_W) && zExp_tmp<=`EXP_DENORMAL_MAX(EXP_W-1)) begin 295 | tailZeroCnt=1+(`EXP_DENORMAL_MAX(EXP_W-1)-zExp_tmp); 296 | end 297 | //`DEBUG("Here7 tailZeroCnt:%b zExp_tmp:%b %b %b",tailZeroCnt,zExp_tmp,`EXP_DENORMAL_MIN(EXP_W-1,SIG_W),`EXP_DENORMAL_MAX(EXP_W-1)); 298 | end 299 | R5FP_postproc #( 300 | .I_SIG_W(SIG_W*2+1+2), 301 | //.I_EXP_W(EXP_W+1), 302 | .SIG_W(SIG_W), 303 | .EXP_W(EXP_W)) pp ( 304 | .aExp(zExp_tmp), 305 | .aStatus(status_tmp), 306 | .aSig({2'b01, z_tmp2[SIG_W*2:0]}), 307 | .tailZeroCnt(tailZeroCnt), 308 | .rnd(rnd), 309 | .aSign(z_tmp2[EXP_W+SIG_W*2+1]), 310 | .z(z), 311 | .status(status)); 312 | 313 | endmodule 314 | 315 | 316 | module R5FP_mul_special_cases #( 317 | parameter EXP_W=5, 318 | parameter SIG_W=10) ( 319 | input [EXP_W+SIG_W:0] a, b, 320 | output reg sign, isNaN, newNaN, isINF, isZero, useA, useB); 321 | 322 | localparam E_MAX=((1<`EXP_NORMAL_MAX(EXP_W-1)) zExp=`EXP_NORMAL_MAX(EXP_W-1)+1; 403 | 404 | if(zSigExt[SIG_W*2+1]!=1'b1) begin 405 | $display("zSigExt has wrong leading 1 bit!!"); 406 | end 407 | zSig=zSigExt[SIG_W*2:0]; 408 | end 409 | 410 | endmodule 411 | 412 | 413 | module R5FP_postproc #( 414 | parameter I_SIG_W=25, 415 | parameter SIG_W=23, 416 | parameter EXP_W=9) ( 417 | input [EXP_W-1:0] aExp, 418 | input [7-1:0] aStatus, 419 | input [I_SIG_W-1:0] aSig, 420 | input [2:0] rnd, 421 | input aSign, 422 | input [EXP_W-1:0] tailZeroCnt, 423 | output reg [SIG_W+EXP_W:0] z, 424 | output reg [7:0] status); 425 | 426 | `define FUNC_POSTPROC func_postproc 427 | `include "R5FP_postproc.v" 428 | `undef FUNC_POSTPROC 429 | 430 | always @(*) begin 431 | func_postproc( 432 | .aExp(aExp), 433 | .aStatus(aStatus), 434 | .aSig(aSig), 435 | .rnd(rnd), 436 | .aSign(aSign), 437 | .tailZeroCnt(tailZeroCnt), 438 | .z(z), 439 | .status(status)); 440 | end 441 | endmodule 442 | 443 | module R5FP_fp2fp_expand #( 444 | parameter SIG_W=10, 445 | parameter EXP_W=5, 446 | parameter SIG_W_INCR=1, 447 | parameter EXP_W_INCR=1) ( 448 | input [SIG_W+EXP_W:0] a, 449 | output reg [SIG_W+SIG_W_INCR+EXP_W+EXP_W_INCR:0] z); 450 | 451 | localparam SIG_W_O=SIG_W_INCR+SIG_W; 452 | localparam EXP_W_O=EXP_W_INCR+EXP_W; 453 | always @(*) begin 454 | z[SIG_W_O+EXP_W_O]=a[SIG_W+EXP_W]; 455 | z[SIG_W_O-1:0]={a[SIG_W-1:0], {SIG_W_INCR{1'b0}}}; 456 | if(a[SIG_W+EXP_W-1:SIG_W]=={EXP_W{1'b1}}) begin 457 | z[SIG_W_O+EXP_W_O-1:SIG_W_O] = {EXP_W_O{1'b1}}; 458 | end 459 | else if(a[SIG_W+EXP_W-1:SIG_W]=={EXP_W{1'b0}}) begin 460 | z[SIG_W_O+EXP_W_O-1:SIG_W_O] = 0; 461 | end 462 | else begin 463 | z[SIG_W_O+EXP_W_O-1:SIG_W_O] = a[SIG_W+EXP_W-1:SIG_W] + ( (1<=`EXP_DENORMAL_MIN(EXP_W,SIG_W)&&aExp<=`EXP_DENORMAL_MAX(EXP_W)) begin 536 | shCount=1+(`EXP_DENORMAL_MAX(EXP_W)-aExp); 537 | zSig={1'b1,aSig}>>shCount; 538 | zExp=0; 539 | end 540 | //$display("Here4: zSig:%b shCount:%b aExp:%b zExp:%b %b %b",zSig,shCount,aExp,zExp,`EXP_DENORMAL_MIN(EXP_W,SIG_W),`EXP_DENORMAL_MAX(EXP_W)); 541 | end 542 | 543 | endmodule 544 | 545 | `undef DEBUG 546 | -------------------------------------------------------------------------------- /rtl/R5FP_div.v: -------------------------------------------------------------------------------- 1 | 2 | `include "R5FP_inc.vh" 3 | 4 | `define FLOAT33_DEFAULT_NAN 'h1FFC00000 5 | `define FLOAT65_DEFAULT_NAN bits65'(65'h1FFF8000000000000) 6 | 7 | typedef logic unsigned [63:0] float64; 8 | typedef logic unsigned [31:0] float32; 9 | typedef logic unsigned [64:0] bits65; 10 | typedef logic unsigned [63:0] bits64; 11 | typedef logic unsigned [32:0] bits33; 12 | typedef logic unsigned [31:0] bits32; 13 | typedef logic unsigned [15:0] bits16; 14 | typedef logic signed [31:0] sbits32; 15 | typedef logic signed [63:0] sbits64; 16 | typedef logic signed [31:0] int32; 17 | typedef logic signed [63:0] int64; 18 | typedef logic signed [15:0] int16; 19 | typedef logic signed [7:0] int8; 20 | typedef logic flag; 21 | 22 | typedef enum logic { 23 | FLOAT_TININESS_AFTER_ROUNDING = 0, 24 | FLOAT_TININESS_BEFORE_ROUNDING = 1 25 | } float_detect_tininess_t; 26 | 27 | //`define RND_NEAREST_EVEN 3'b000 28 | //`define RND_TO_ZERO 3'b001 29 | //`define RND_UP 3'b010 30 | //`define RND_DOWN 3'b011 31 | typedef enum logic [2:0] { 32 | FLOAT_ROUND_NEAREST_EVEN = 0, 33 | FLOAT_ROUND_DOWN = 3, 34 | FLOAT_ROUND_UP = 2, 35 | FLOAT_ROUND_TO_ZERO = 1, 36 | FLOAT_ROUND_NEAREST_UP = 4, 37 | FLOAT_ROUND_FROM_ZERO = 5 38 | } float_rounding_mode_t; 39 | 40 | 41 | typedef logic [5:0] float_exception_flags_t; 42 | const logic [5:0] FLOAT_FLAG_INVALID = 1; 43 | const logic [5:0] FLOAT_FLAG_DIVBYZERO = 4; 44 | const logic [5:0] FLOAT_FLAG_OVERFLOW = 8; 45 | const logic [5:0] FLOAT_FLAG_UNDERFLOW = 16; 46 | const logic [5:0] FLOAT_FLAG_INEXACT = 32; 47 | 48 | typedef struct packed { 49 | float_detect_tininess_t float_detect_tininess; 50 | float_rounding_mode_t float_rounding_mode; 51 | float_exception_flags_t float_exception_flags; 52 | } float_ctrl_t; 53 | 54 | 55 | function automatic logic [64:0] sub_sub (bits64 base, bits64 sub1, bits64 sub2); 56 | //return base-sub1-sub2; 57 | bits64 add1=~sub1; 58 | bits64 add2=~sub2; 59 | bits64 c=( (base&add1) | (base&add2) | (add1&add2) ); 60 | bits64 v=( base^add1^add2 ); 61 | logic [64:0] result=(c<<1)+v+2; 62 | return result; 63 | 64 | endfunction 65 | 66 | function automatic void div64_iter(output bits64 quotient_o, remainder_o, input bits64 quotient, remainder, subtractor, result_mask, src_mask); 67 | bits64 remainder_tmp1, remainder_tmp2; 68 | bits64 quotient_tmp1, quotient_tmp2; 69 | flag level1_select, level2_select; 70 | logic [64:0] sub_sub_out; 71 | remainder &= src_mask; 72 | subtractor &= src_mask; 73 | if( remainder>=(subtractor<<1) && (subtractor>>63)==0 ) begin 74 | level1_select=1; 75 | remainder_tmp1 = (remainder-(subtractor<<1)); //one adder 76 | quotient_tmp1 = (quotient|(result_mask<<1)); 77 | end 78 | else begin 79 | level1_select=0; 80 | remainder_tmp1 = remainder; 81 | quotient_tmp1 = quotient; 82 | end 83 | 84 | sub_sub_out=sub_sub(remainder,(subtractor<<1),subtractor); //one adder 85 | // level2_select==(remainder_tmp1>=subtractor)) 86 | if(level1_select==1'b1) begin 87 | level2_select=~sub_sub_out[64]; 88 | end 89 | else begin 90 | level2_select=(remainder>=subtractor); 91 | end 92 | 93 | if(level2_select!=(remainder_tmp1>=subtractor)) begin 94 | $display("error!"); 95 | $finish(2); 96 | end 97 | 98 | if(level2_select) begin 99 | //remainder_tmp2 = (remainder_tmp1-subtractor); 100 | if(level1_select) remainder_tmp2 = sub_sub_out[63:0]; 101 | else remainder_tmp2 = remainder-subtractor; //one adder 102 | quotient_tmp2 = (quotient_tmp1|result_mask); 103 | end 104 | else begin 105 | remainder_tmp2 = remainder_tmp1; 106 | quotient_tmp2 = quotient_tmp1; 107 | end 108 | 109 | remainder_o = remainder_tmp2; 110 | quotient_o = quotient_tmp2; 111 | endfunction 112 | 113 | 114 | function automatic flag float64_is_nan( float64 a ); 115 | return ( bits64'( 64'hFFE0000000000000 ) < bits64'( a<<1 ) ); 116 | endfunction 117 | 118 | 119 | function automatic flag float64_is_signaling_nan( float64 a ); 120 | return 121 | ( ( ( a>>51 ) & 'hFFF ) == 'hFFE ) 122 | && ( a & bits64'( 64'h0007FFFFFFFFFFFF ) ); 123 | endfunction 124 | 125 | function automatic float64 propagateFloat65NaN( bits65 a, bits65 b, input float_ctrl_t fctrl, output float_ctrl_t fctrl_o ); 126 | return propagateFloat64NaN( {a[64],a[62:0]}, {b[64],b[62:0]}, fctrl, fctrl_o ); 127 | endfunction 128 | 129 | function automatic float64 propagateFloat64NaN( float64 a, float64 b, input float_ctrl_t fctrl, output float_ctrl_t fctrl_o ); 130 | flag aIsNaN, aIsSignalingNaN, bIsNaN, bIsSignalingNaN; 131 | fctrl_o=fctrl; 132 | 133 | aIsNaN = float64_is_nan( a ); 134 | aIsSignalingNaN = float64_is_signaling_nan( a ); 135 | bIsNaN = float64_is_nan( b ); 136 | bIsSignalingNaN = float64_is_signaling_nan( b ); 137 | a |= bits64'( 64'h0008000000000000 ); 138 | b |= bits64'( 64'h0008000000000000 ); 139 | if ( aIsSignalingNaN | bIsSignalingNaN ) fctrl_o.float_exception_flags |=( FLOAT_FLAG_INVALID ); 140 | if ( aIsSignalingNaN ) begin 141 | if ( bIsSignalingNaN ) begin 142 | if ( bits64'( a<<1 ) < bits64'( b<<1 ) ) return b; 143 | if ( bits64'( b<<1 ) < bits64'( a<<1 ) ) return a; 144 | return ( a < b ) ? a : b; 145 | end 146 | return bIsNaN ? b : a; 147 | end 148 | else if ( aIsNaN ) begin 149 | if ( bIsSignalingNaN | ! bIsNaN ) return a; 150 | if ( bits64'( a<<1 ) < bits64'( b<<1 ) ) return b; 151 | if ( bits64'( b<<1 ) < bits64'( a<<1 ) ) return a; 152 | return ( a < b ) ? a : b; 153 | end 154 | else begin 155 | return b; 156 | end 157 | endfunction 158 | 159 | 160 | function automatic bits64 extractFloat65Frac( bits65 a ); 161 | return a & bits64'( 64'h000FFFFFFFFFFFFF ); 162 | endfunction 163 | 164 | function automatic int16 extractFloat65Exp( bits65 a ); 165 | return ( a>>52 ) & 'hFFF; 166 | endfunction 167 | 168 | function automatic flag extractFloat65Sign( bits65 a ); 169 | return a[64]; 170 | endfunction 171 | 172 | 173 | 174 | function automatic bits65 float65_div_prepare( bits65 a, bits65 b, output bits64 aSig,bSig, 175 | int16 aExp,bExp, flag aSign,bSign,zSign,got_result, input float_ctrl_t fctrl, output float_ctrl_t fctrl_o ); 176 | bits64 result; 177 | aSig = extractFloat65Frac( a ); 178 | aExp = extractFloat65Exp( a ); 179 | aSign = extractFloat65Sign( a ); 180 | bSig = extractFloat65Frac( b ); 181 | bExp = extractFloat65Exp( b ); 182 | bSign = extractFloat65Sign( b ); 183 | 184 | fctrl_o=fctrl; 185 | got_result=1'b1; 186 | zSign = aSign ^ bSign; 187 | if ( aExp == 16'hFFF ) begin 188 | if ( aSig ) begin 189 | result = propagateFloat65NaN( a, b, fctrl_o, fctrl_o ); 190 | return {result[63],1'b1,result[62:0]}; 191 | end 192 | if ( bExp == 16'hFFF ) begin 193 | if ( bSig ) begin 194 | result = propagateFloat65NaN( a, b, fctrl_o, fctrl_o ); 195 | return {result[63],1'b1,result[62:0]}; 196 | end 197 | fctrl_o.float_exception_flags |=( FLOAT_FLAG_INVALID ); 198 | return `FLOAT65_DEFAULT_NAN; 199 | end 200 | return {zSign, {12{1'b1}}, 52'b0}; 201 | end 202 | if ( bExp == 16'hFFF ) begin 203 | if ( bSig ) begin 204 | result = propagateFloat65NaN( a, b, fctrl_o, fctrl_o ); 205 | return {result[63],1'b1,result[62:0]}; 206 | end 207 | return {zSign, {12{1'b0}}, 52'b0}; 208 | end 209 | if ( bExp == 0 ) begin 210 | if( bSig ==0 ) begin 211 | if({aExp,aSig}==0) begin 212 | fctrl_o.float_exception_flags |=( FLOAT_FLAG_INVALID ); 213 | return `FLOAT65_DEFAULT_NAN; 214 | end 215 | else begin 216 | fctrl_o.float_exception_flags |=( FLOAT_FLAG_DIVBYZERO ); 217 | return {1'b0,64'hFFF0000000000000}; 218 | end 219 | end 220 | else begin 221 | assert(0); 222 | end 223 | end 224 | if ( aExp == 0 ) begin 225 | if( aSig ==0 ) begin 226 | return {zSign, {12{1'b0}}, 52'b0}; 227 | end 228 | else begin 229 | assert(0); 230 | end 231 | end 232 | got_result=1'b0; 233 | return 0; 234 | endfunction 235 | 236 | 237 | 238 | module R5FP_div128by64_unsigned_seq (input logic clk,rst_n, strobe_in, is_single_in, logic [63:0] dividend_in, divisor_in, 239 | output logic valid_out, logic [63:0] quotient_out, remainder_out); 240 | logic [63:0] quotient_r,remainder_r,dividend_r, divisor_r, subtractor_r, result_mask_r, 241 | quotient ,remainder ,dividend , divisor , subtractor , result_mask ; 242 | logic is_single_r, valid_r, 243 | is_single , valid; 244 | logic [6:0] iter_count_r, 245 | iter_count; 246 | 247 | typedef enum logic { 248 | ITER, IDLE 249 | } state_t; 250 | state_t state_r, state; 251 | 252 | always_ff @(posedge clk or negedge rst_n) begin 253 | if(!rst_n) begin 254 | valid_r<=1'b0; 255 | state_r<=IDLE; 256 | end 257 | else begin 258 | valid_r<=valid; 259 | state_r<=state; 260 | end 261 | end 262 | always_ff @(posedge clk) begin 263 | quotient_r<=quotient; 264 | remainder_r<=remainder; 265 | divisor_r<=divisor; 266 | dividend_r<=dividend; 267 | is_single_r<=is_single; 268 | subtractor_r<=subtractor; 269 | result_mask_r<=result_mask; 270 | iter_count_r<=iter_count; 271 | end 272 | 273 | 274 | always_comb begin 275 | quotient=quotient_r; 276 | remainder=remainder_r; 277 | divisor=divisor_r; 278 | dividend=dividend_r; 279 | valid=valid_r; 280 | is_single=is_single_r; 281 | subtractor=subtractor_r; 282 | result_mask=result_mask_r; 283 | iter_count=iter_count_r; 284 | valid=valid_r; 285 | state=state_r; 286 | 287 | case(state_r) 288 | ITER: begin 289 | if(iter_count_r>=29) begin 290 | valid=1'b1; 291 | state=IDLE; 292 | end 293 | else begin 294 | div64_iter(quotient, remainder, quotient, remainder, subtractor_r, result_mask_r, {64{1'b1}}<<6); 295 | //$display("quotient: %x", quotient); 296 | remainder <<= 2; 297 | result_mask = (result_mask_r>>2); 298 | iter_count = iter_count_r+1; 299 | end 300 | end 301 | IDLE: begin 302 | if(strobe_in) begin 303 | dividend=dividend_in; 304 | divisor=divisor_in; 305 | valid=1'b0; 306 | quotient=0; 307 | remainder=dividend; 308 | subtractor=divisor; 309 | result_mask={1'b1,{63{1'b0}}}; 310 | is_single=is_single_in; 311 | if(is_single) begin 312 | iter_count=16; 313 | end 314 | else begin 315 | iter_count=0; 316 | end 317 | state=ITER; 318 | end 319 | end 320 | endcase 321 | 322 | //$display(" %s -> %s ", state_r.name(), state.name() ); 323 | end 324 | 325 | assign valid_out=valid_r; 326 | assign quotient_out=quotient_r; 327 | assign remainder_out=remainder_r; 328 | 329 | endmodule 330 | 331 | module R5FP_div_seq(input logic clk, rst_n, strobe_in, is_single_in, bits65 a_in, bits65 b_in, float_ctrl_t fctrl_in, 332 | output bits65 result_out, float_ctrl_t fctrl_out, logic valid_out ); 333 | flag aSign, bSign, zSign, zSign_r, got_result, sub_strobe_in, sub_valid_out; 334 | flag is_single_r, is_single; 335 | int16 aExp, bExp, zExp; 336 | int16 aExp_r, bExp_r, zExp_r; 337 | bits65 a,b; 338 | bits64 aSig, bSig, zSig, zSigFast, rem1; 339 | bits65 a_r,b_r; 340 | bits64 aSig_r, bSig_r, zSig_r, zSigFast_r; 341 | bits65 result, result_r; 342 | flag valid, valid_r; 343 | float_ctrl_t fctrl,fctrl_r; 344 | 345 | bits64 dividend_in, divisor_in; 346 | bits64 quotient_out, remainder_out; 347 | int16 expOut; 348 | logic[7:0] statusOut; 349 | logic [12-1:0] tailZeroCnt; 350 | logic[6:0] aStatus; 351 | 352 | parameter I_SIG_W=63; 353 | parameter SIG_W=52; 354 | parameter EXP_W=12; 355 | `define FUNC_POSTPROC func_postproc 356 | `include "R5FP_postproc.v" 357 | `undef FUNC_POSTPROC 358 | 359 | 360 | R5FP_div128by64_unsigned_seq U_div128by64_unsigned_seq (.strobe_in(sub_strobe_in), .is_single_in(is_single), 361 | .valid_out(sub_valid_out), .*); 362 | 363 | typedef enum logic [2:0] { 364 | PREPROC0, PREPROC1, WAIT, POSTPROC, IDLE 365 | } state_t; 366 | state_t state_r, state; 367 | 368 | always_ff @(posedge clk or negedge rst_n) begin 369 | if(!rst_n) begin 370 | valid_r<=1'b0; 371 | state_r<=IDLE; 372 | end 373 | else begin 374 | valid_r<=valid; 375 | state_r<=state; 376 | end 377 | end 378 | always_ff @(posedge clk) begin 379 | a_r<=a; 380 | b_r<=b; 381 | is_single_r<=is_single; 382 | zSign_r<=zSign; 383 | aExp_r<=aExp; 384 | bExp_r<=bExp; 385 | zExp_r<=zExp; 386 | aSig_r<=aSig; 387 | bSig_r<=bSig; 388 | zSig_r<=zSig; 389 | zSigFast_r<=zSigFast; 390 | result_r<=result; 391 | fctrl_r<=fctrl; 392 | end 393 | 394 | always_comb begin 395 | a=a_r; 396 | b=b_r; 397 | zSign=zSign_r; 398 | aExp=aExp_r; 399 | bExp=bExp_r; 400 | zExp=zExp_r; 401 | aSig=aSig_r; 402 | bSig=bSig_r; 403 | zSig=zSig_r; 404 | zSigFast=zSigFast_r; 405 | result=result_r; 406 | valid=valid_r; 407 | fctrl=fctrl_r; 408 | is_single=is_single_r; 409 | state=state_r; 410 | 411 | sub_strobe_in=1'b0; 412 | dividend_in='bx; 413 | divisor_in='bx; 414 | 415 | case(state_r) 416 | PREPROC0: begin 417 | result=float65_div_prepare(a_r, b_r, aSig,bSig, aExp,bExp, aSign,bSign,zSign,got_result, fctrl, fctrl); 418 | if(got_result) begin 419 | state=IDLE; 420 | valid=1'b1; 421 | end 422 | else begin 423 | state=state_r.next(); 424 | end 425 | end 426 | PREPROC1: begin 427 | zExp = aExp_r - bExp_r + 16'h3FD; 428 | aSig = ( aSig_r | 64'h0010000000000000 )<<10; 429 | bSig = ( bSig_r | 64'h0010000000000000 )<<11; 430 | //$display("PREPROC1: aSig:%b bSig:%b",aSig,bSig); 431 | if ( bSig <= ( aSig*2 ) ) begin 432 | aSig >>= 1; 433 | zExp=zExp+1; 434 | end 435 | sub_strobe_in=1'b1; 436 | dividend_in=aSig; 437 | divisor_in=bSig>>2; 438 | state=state_r.next(); 439 | end 440 | WAIT: begin 441 | zSig=quotient_out>>1; 442 | rem1=remainder_out; 443 | zSig |= ( rem1 != 0 ); 444 | 445 | //$display("WAIT: zSig:%b rem1:%b",zSig,rem1); 446 | if(sub_valid_out) state=state_r.next(); 447 | end 448 | POSTPROC: begin 449 | expOut=zExp_r+{10{1'b1}}+2; 450 | 451 | if(is_single_r) begin 452 | if(expOut<=`EXP_DENORMAL_MIN_X(EXP_W,8,SIG_W)-2) 453 | expOut=`EXP_DENORMAL_MIN_X(EXP_W,8,SIG_W)-2; 454 | if(expOut>=`EXP_NORMAL_MAX_X(EXP_W,8)+1) 455 | expOut=`EXP_NORMAL_MAX_X(EXP_W,8)+1; 456 | tailZeroCnt=29; 457 | if(expOut>=`EXP_DENORMAL_MIN_X(EXP_W,8,SIG_W) && expOut<=`EXP_DENORMAL_MAX_X(EXP_W,8)) begin 458 | tailZeroCnt=29+1+(`EXP_DENORMAL_MAX_X(EXP_W,8)-expOut); 459 | end 460 | //$display("zExp_r:%d expOut:%d zSig_r:%b-%h tailZeroCnt:%d %d %d", zExp_r,expOut, zSig_r[63:62], zSig_r[61:0], tailZeroCnt,`EXP_DENORMAL_MIN_X(EXP_W,8,SIG_W),`EXP_DENORMAL_MAX_X(EXP_W,8)); 461 | end 462 | else begin 463 | if(expOut<=`EXP_DENORMAL_MIN(EXP_W-1,SIG_W)-2) 464 | expOut=`EXP_DENORMAL_MIN(EXP_W-1,SIG_W)-2; 465 | if(expOut>=`EXP_NORMAL_MAX(EXP_W-1)+1) 466 | expOut=`EXP_NORMAL_MAX(EXP_W-1)+1; 467 | tailZeroCnt=0; 468 | if(expOut>=`EXP_DENORMAL_MIN(EXP_W-1,SIG_W) && expOut<=`EXP_DENORMAL_MAX(EXP_W-1)) begin 469 | tailZeroCnt=1+(`EXP_DENORMAL_MAX(EXP_W-1)-expOut); 470 | end 471 | //$display("zExp_r:%d expOut:%h zSig_r:%b-%h tailZeroCnt:%d %d %d", zExp_r,expOut, zSig_r[63:62], zSig_r[61:0], tailZeroCnt,`EXP_DENORMAL_MIN(EXP_W-1,SIG_W),`EXP_DENORMAL_MAX(EXP_W-1)); 472 | end 473 | 474 | aStatus=0; 475 | aStatus[`STICKY]=zSig_r[0]; 476 | func_postproc( 477 | .aExp(expOut[11:0]), 478 | .aStatus(aStatus), 479 | .aSig(zSig_r[63:1]), 480 | .rnd(fctrl.float_rounding_mode), 481 | .aSign(zSign_r), 482 | .tailZeroCnt(tailZeroCnt), 483 | .z(result), 484 | .status(statusOut)); 485 | //if(statusOut[`Z_IS_INF]) fctrl.float_exception_flags|=FLOAT_FLAG_OVERFLOW; 486 | //if(statusOut[`Z_TINY]) fctrl.float_exception_flags|=FLOAT_FLAG_UNDERFLOW; 487 | if(statusOut[`Z_INEXACT]) fctrl.float_exception_flags|=FLOAT_FLAG_INEXACT; 488 | 489 | valid=1'b1; 490 | state=state_r.next(); 491 | end 492 | IDLE: begin 493 | if(strobe_in) begin 494 | a=a_in; 495 | b=b_in; 496 | fctrl=fctrl_in; 497 | is_single=is_single_in; 498 | valid=1'b0; 499 | state=PREPROC0; 500 | end 501 | end 502 | endcase 503 | 504 | //$display(" %s (%x) => %s (%x) ", state_r.name(), result_r, state.name(), result ); 505 | end 506 | 507 | assign valid_out=valid_r; 508 | assign result_out=result_r; 509 | assign fctrl_out=fctrl_r; 510 | 511 | endmodule 512 | 513 | module R5FP_fp65_to_fp33 (input [64:0] a, input [2:0] rnd, output [32:0] z); 514 | wire aSign; 515 | wire [11:0] aExp; 516 | wire [51:0] aSig; 517 | assign {aSign,aExp,aSig}=a; 518 | 519 | reg useMinValue; 520 | reg signed [12:0] zExp; 521 | reg [22:0] zSig; 522 | assign z={aSign,zExp[8:0],zSig}; 523 | 524 | always @(*) begin 525 | useMinValue=0; 526 | if(aExp==0) begin 527 | zExp=0; 528 | zSig=0; 529 | end 530 | else if(aExp=={12{1'b1}}) begin 531 | zExp = {9{1'b1}}; 532 | zSig=aSig[51:51-22]; 533 | end 534 | else begin 535 | zSig=aSig[51:51-22]; 536 | zExp = aExp - (1<<12)/2 + (1<<9)/2; 537 | //$display("HereH0 zExp:%b aExp:%b %b %b",zExp,aExp,`EXP_DENORMAL_MIN(8,23),`EXP_NORMAL_MAX(9)); 538 | if(zExp>`EXP_NORMAL_MAX(8)) begin 539 | if (rnd==FLOAT_ROUND_TO_ZERO || (rnd==FLOAT_ROUND_DOWN && !aSign) || (rnd==FLOAT_ROUND_UP && aSign) ) begin 540 | zExp = `EXP_NORMAL_MAX(8); 541 | zSig = {23{1'b1}}; 542 | end 543 | else begin 544 | zExp = {9{1'b1}}; 545 | zSig = 0; 546 | end 547 | end 548 | else if(zExp<`EXP_DENORMAL_MIN(8,23)) begin 549 | //if( rnd==FLOAT_ROUND_NEAREST_UP && zExp==`EXP_DENORMAL_MIN(8,23)-1 && !needShift ) 550 | // useMinValue=1; 551 | if( rnd==FLOAT_ROUND_FROM_ZERO || (rnd==FLOAT_ROUND_DOWN && aSign) || (rnd==FLOAT_ROUND_UP && !aSign) ) 552 | useMinValue=1; 553 | if(useMinValue) begin 554 | zExp=`EXP_DENORMAL_MIN(8,23); 555 | zSig=1; 556 | end 557 | else begin 558 | zExp=0; 559 | zSig=0; 560 | end 561 | end 562 | //$display("HereH zExp:%b aExp:%b",zExp,aExp); 563 | end 564 | end 565 | 566 | endmodule 567 | 568 | -------------------------------------------------------------------------------- /rtl/R5FP_inc.vh: -------------------------------------------------------------------------------- 1 | 2 | `ifndef R5FP_INC 3 | `define R5FP_INC 4 | 5 | //000 RNE Round to Nearest, ties to Even 6 | //001 RTZ Round towards Zero 7 | //010 RDN Round Down (towards −1) 8 | //011 RUP Round Up (towards +1) 9 | //100 RMM Round to Nearest, ties to Max Magnitude 10 | 11 | 12 | `define RND_NEAREST_EVEN 3'b000 13 | `define RND_TO_ZERO 3'b001 14 | `define RND_UP 3'b010 15 | `define RND_DOWN 3'b011 16 | `define RND_NEAREST_UP 3'b100 17 | `define RND_FROM_ZERO 3'b101 18 | 19 | 20 | `define IS_1SCMPL 6 21 | `define TailSameAsLSB 5 22 | `define SIGN 4 23 | `define STICKY 3 24 | `define IS_NAN 2 25 | `define IS_INF 1 26 | `define IS_ZERO 0 27 | 28 | `define Z_IS_ZERO 0 29 | `define Z_IS_INF 1 30 | `define Z_INVALID 2 31 | `define Z_TINY 3 32 | `define Z_HUGE 4 33 | `define Z_INEXACT 5 34 | `define Z_HUGE_INT 6 35 | `define Z_DIV_BY_0 7 36 | 37 | `define EXP_DENORMAL_MIN(e,s) ((1<<((e)-1))+1-(s)) 38 | `define EXP_DENORMAL_MAX(e) (1<<((e)-1)) 39 | `define EXP_NORMAL_MIN(e) ((1<<((e)-1))+1) 40 | `define EXP_NORMAL_MAX(e) ((1<<((e)-1))+((1<<(e))-2)) 41 | 42 | `define EXP_DENORMAL_MIN_X(large,small,s) (((1<<(large-1))-(1<<(small-1)))+1-(s)) 43 | `define EXP_DENORMAL_MAX_X(large,small) ((1<<(large-1))-(1<<(small-1))) 44 | `define EXP_NORMAL_MIN_X(large,small) (((1<<(large-1))-(1<<(small-1)))+1) 45 | `define EXP_NORMAL_MAX_X(large,small) (((1<<(large-1))-(1<<(small-1)))+(1<<(small))-2) 46 | 47 | function automatic logic getRoundCarry( input [2:0] rnd_i, input sig_sign, 48 | input guard_bit,round_bit,sticky); 49 | begin 50 | logic round = 0; 51 | if ($time > 0) begin 52 | case (rnd_i) 53 | `RND_NEAREST_EVEN: begin 54 | round = round_bit&(guard_bit|sticky); 55 | end 56 | `RND_TO_ZERO: begin 57 | round = 0; 58 | end 59 | `RND_UP: begin 60 | round = ~sig_sign & (round_bit|sticky); 61 | end 62 | `RND_DOWN: begin 63 | round = sig_sign & (round_bit|sticky); 64 | end 65 | `RND_NEAREST_UP: begin 66 | round = round_bit; 67 | end 68 | `RND_FROM_ZERO: begin 69 | round = round_bit|sticky; 70 | end 71 | default: $display("Unkown rounding mode!\n"); 72 | endcase 73 | end 74 | return round; 75 | end 76 | endfunction 77 | 78 | `endif 79 | 80 | -------------------------------------------------------------------------------- /rtl/R5FP_postproc.v: -------------------------------------------------------------------------------- 1 | 2 | `define DEBUG $display 3 | 4 | function void `FUNC_POSTPROC( 5 | input [EXP_W-1:0] aExp, 6 | input [7-1:0] aStatus, 7 | input [I_SIG_W-1:0] aSig, 8 | input [2:0] rnd, 9 | input aSign, 10 | input [EXP_W-1:0] tailZeroCnt, 11 | output reg [SIG_W+EXP_W:0] z, 12 | output reg [7:0] status); 13 | 14 | reg [EXP_W+2:0] aExpExt; 15 | reg signed [I_SIG_W:0] aSig2; 16 | reg [SIG_W-1:0] zeroSig; 17 | reg [SIG_W-1:0] oneSig; 18 | reg [EXP_W-1:0] zeroExp; 19 | reg [EXP_W-1:0] allOnesExp; 20 | reg [I_SIG_W+SIG_W:0] aSig3,rnd_bits,aSig3Tail,aSig4; 21 | reg [SIG_W-1:0] mask; 22 | reg sticky, round_bit, guard_bit; 23 | reg [EXP_W-1:0] oneExp; 24 | reg [SIG_W-1:0] zSig; 25 | integer i; 26 | reg roundCarry,needShift,useMinValue; 27 | // variable initialization 28 | zeroSig = 0; 29 | oneSig = 0; 30 | oneSig[0] = 1'b1; 31 | zeroExp = 0; 32 | allOnesExp = ~0; 33 | status = 0; 34 | oneExp = 1; 35 | aSig3 = 0; 36 | z = 0; 37 | rnd_bits = 0; 38 | mask = 0; 39 | useMinValue=0; 40 | 41 | status = 0; 42 | status[`Z_IS_ZERO] = aStatus[`IS_ZERO]; 43 | status[`Z_IS_INF] = aStatus[`IS_INF]; 44 | status[`Z_INVALID] = aStatus[`IS_NAN]; 45 | status[`Z_INEXACT] = aStatus[`STICKY]; 46 | 47 | if(aSig[I_SIG_W-1:I_SIG_W-2]!=2'b01) begin 48 | $display("Error! leading two bits of aSig is not 01!!"); 49 | end 50 | aSig2 = {2'b01,aSig[I_SIG_W-3:0],1'b0}; 51 | if (status[`Z_IS_ZERO] || status[`Z_IS_INF] || status[`Z_INVALID]) begin 52 | if (status[`Z_IS_ZERO] == 1 && status[`Z_INVALID] == 0) begin 53 | if (status[`Z_INEXACT] == 1) begin 54 | if ((rnd == `RND_DOWN && aStatus[`SIGN] == 1) || 55 | (rnd == `RND_UP && aStatus[`SIGN] == 0) || 56 | rnd == `RND_FROM_ZERO) begin 57 | z = {aStatus[`SIGN], zeroExp, oneSig}; 58 | status[`Z_IS_ZERO] = 1'b0; 59 | status[`Z_TINY] = 0; 60 | //`DEBUG("HereJ"); 61 | end 62 | else begin 63 | z = {aStatus[`SIGN], zeroExp, zeroSig}; 64 | status[`Z_IS_ZERO] = 1'b1; 65 | status[`Z_TINY] = 1'b1; 66 | //`DEBUG("HereI"); 67 | end 68 | end 69 | else begin 70 | z = {aStatus[`SIGN], zeroExp, zeroSig}; 71 | //`DEBUG("HereH"); 72 | end 73 | end 74 | 75 | if (status[`Z_INVALID] == 1'b1) begin 76 | status = {8{1'b0}}; 77 | status[`Z_IS_INF] = 1'b0; 78 | status[`Z_INVALID] = 1'b1; 79 | z = {aSign, allOnesExp, aSig[I_SIG_W-3:I_SIG_W-SIG_W-2]}; 80 | //`DEBUG("HereG aSign:%b",aSign); 81 | end 82 | else if (status[`Z_IS_INF] == 1'b1) begin 83 | z = {aStatus[`SIGN], allOnesExp, zeroSig}; 84 | status[`Z_IS_ZERO] = 1'b0; 85 | status[`Z_INEXACT] = 1'b0; 86 | //`DEBUG("HereF"); 87 | end 88 | end 89 | else begin 90 | sticky = status[`Z_INEXACT]; 91 | aExpExt = $unsigned(aExp); 92 | 93 | aSig3 = aSig2 << SIG_W; 94 | 95 | aSig3Tail=aSig3>>tailZeroCnt; 96 | sticky = (|aSig3Tail[I_SIG_W-1-1-1:0]) || sticky; 97 | round_bit = aSig3Tail[I_SIG_W-1-1]; 98 | guard_bit = aSig3Tail[I_SIG_W-1]; 99 | //`DEBUG("Here5 aSig:%b aSig2:%b aSig3:%b tailZeroCnt:%d aSig3Tail:%b sticky:%b aSig3Tail[I_SIG_W-1-1-1:0]:%b guard_bit:%b round_bit:%b", aSig,aSig2,aSig3,tailZeroCnt,aSig3Tail, sticky, aSig3Tail[I_SIG_W-1-1-1:0],guard_bit,round_bit); 100 | 101 | roundCarry = getRoundCarry(rnd, aSign, guard_bit, round_bit, sticky); 102 | rnd_bits[0] = roundCarry; 103 | rnd_bits = rnd_bits<<(I_SIG_W-1); 104 | rnd_bits = rnd_bits<> 1; 115 | end 116 | zSig=aSig4[I_SIG_W+SIG_W-2:I_SIG_W-1]; 117 | 118 | if (((aExpExt==0) && ((sticky == 1'b1) || (aSig2 != 0))) || 119 | ((aExpExt==1) && (aSig4[I_SIG_W+SIG_W:I_SIG_W+SIG_W-1]==0)&& 120 | ((sticky == 1'b1) || (aSig2 != 0)))) begin 121 | status[`Z_INEXACT] = 1'b1; 122 | if ((rnd == `RND_DOWN && aSign == 1) || 123 | (rnd == `RND_UP && aSign == 0) || 124 | rnd == `RND_FROM_ZERO) begin 125 | status[`Z_IS_ZERO] = 1'b0; 126 | status[`Z_TINY] = 1'b0; 127 | z = {aSign, zeroExp, oneSig}; 128 | //`DEBUG("HereE"); 129 | end 130 | else begin 131 | status[`Z_IS_ZERO] = 1'b1; 132 | status[`Z_TINY] = 1'b1; 133 | z = {aSign, zeroExp, zeroSig}; 134 | //`DEBUG("HereD status:%b aStatus:%b",status,aStatus); 135 | end 136 | end 137 | else begin 138 | status[`Z_INEXACT] = status[`Z_INEXACT]|round_bit|sticky; 139 | if(aExpExt<`EXP_DENORMAL_MIN(EXP_W-1,SIG_W)) begin 140 | //`DEBUG("HereC0 aExpExt%b %b sticky:%b asig3:%b",aExpExt,`EXP_DENORMAL_MIN(EXP_W-1,SIG_W), sticky,aSig3[I_SIG_W+SIG_W-2:0]); 141 | if( rnd==`RND_NEAREST_EVEN && aExpExt==`EXP_DENORMAL_MIN(EXP_W-1,SIG_W)-1 && aSig3[I_SIG_W+SIG_W-2:0]!=0 && !needShift) 142 | useMinValue=1; 143 | if( rnd==`RND_NEAREST_UP && aExpExt==`EXP_DENORMAL_MIN(EXP_W-1,SIG_W)-1 && !needShift ) 144 | useMinValue=1; 145 | if( rnd==`RND_FROM_ZERO || (rnd==`RND_DOWN && aSign) || (rnd==`RND_UP && !aSign) ) 146 | useMinValue=1; 147 | 148 | if(useMinValue) begin 149 | status[`Z_INEXACT] = 1'b1; 150 | status[`Z_TINY] = 1'b1; 151 | status[`Z_IS_ZERO] = 1'b0; 152 | aExpExt=`EXP_DENORMAL_MIN(EXP_W-1,SIG_W); 153 | z = {aSign, aExpExt[EXP_W-1:0], oneSig}; 154 | end 155 | else begin 156 | status[`Z_INEXACT] = 1'b1; 157 | status[`Z_TINY] = 1'b1; 158 | status[`Z_IS_ZERO] = 1'b1; 159 | z = {aSign, zeroExp, zeroSig}; 160 | end 161 | //`DEBUG("HereC aExpExt%b %b asig4: %b %b",aExpExt,`EXP_DENORMAL_MIN(EXP_W-1,SIG_W),aSig4[I_SIG_W+SIG_W-1], aSig4[I_SIG_W+SIG_W-2:0]); 162 | end 163 | else if(aExpExt>`EXP_NORMAL_MAX(EXP_W-1)) begin 164 | if(/*aExpExt==`EXP_NORMAL_MAX(EXP_W-1)+1 && zSig==0 &&*/ 165 | (rnd==`RND_TO_ZERO || (rnd==`RND_DOWN && !aSign) || (rnd==`RND_UP && aSign) ) ) begin 166 | status[`Z_INEXACT] = 1'b1; 167 | status[`Z_HUGE] = 1'b1; 168 | aExpExt=`EXP_NORMAL_MAX(EXP_W-1); 169 | z = {aSign, aExpExt[EXP_W-1:0], {SIG_W{1'b1}} }; 170 | end 171 | else begin 172 | status[`Z_INEXACT] = 1'b1; 173 | status[`Z_IS_INF] = 1'b1; 174 | status[`Z_HUGE] = 1'b1; 175 | z = {aSign, {EXP_W{1'b1}}, zeroSig}; 176 | //`DEBUG("HereB aExpExt%b %b zSig:%b status:%b",aExpExt,`EXP_NORMAL_MAX(EXP_W-1), zSig, status); 177 | end 178 | end 179 | else begin 180 | zSig=zSig&mask; 181 | z = {aSign,aExpExt[EXP_W-1:0],zSig}; 182 | //`DEBUG("HereA z:%b round_bit:%b sticky:%b aExpExt:%b %b mask:%b aSig3:%b zSig:%b ", z,round_bit,sticky, aExpExt,`EXP_DENORMAL_MIN(EXP_W-1,SIG_W),mask,aSig3,zSig); 183 | `ifdef FORCE_DW_MULT_BEHAVIOR 184 | if(aExpExt<=`EXP_DENORMAL_MAX(EXP_W-1)) status[`Z_TINY] = 1'b1; 185 | `endif 186 | end 187 | end 188 | end 189 | //`DEBUG("Here z:%b aExp:%b aSig:%b aExpExt:%b aSig3:%b aStatus:%b",z,aExp,aSig,aExpExt,aSig3,aStatus); 190 | //`DEBUG("Here %b %b %b %b",`EXP_DENORMAL_MIN(EXP_W-1,SIG_W),`EXP_DENORMAL_MAX(EXP_W-1),`EXP_NORMAL_MIN(EXP_W-1),`EXP_NORMAL_MAX(EXP_W-1)); 191 | 192 | endfunction 193 | 194 | `undef DEBUG 195 | 196 | -------------------------------------------------------------------------------- /rtl/R5FP_sqrt.v: -------------------------------------------------------------------------------- 1 | 2 | `include "R5FP_inc.vh" 3 | 4 | module R5FP_int_sqrt #(parameter W=32) (input [W-1:0] num_in, 5 | input clk,reset,strobe, output logic complete, 6 | output logic [W-1:0] res, rem, 7 | output logic rem_s); 8 | logic[W-1:0] b,b0,num; 9 | logic[W:0] aBar; 10 | logic bPulsResHigh; 11 | 12 | assign b0=({2'b01,{(W-2){1'b0}}}>>2); 13 | 14 | logic finished; 15 | always_ff @(posedge clk) begin 16 | if(reset) begin 17 | finished<=0; 18 | end 19 | else if(strobe) begin 20 | finished<=1'b0; 21 | end 22 | else if(!finished) begin 23 | finished<=((b>>1)==0); 24 | end 25 | end 26 | always_ff @(posedge clk) begin 27 | if(reset) begin 28 | complete<=0; 29 | end 30 | else if(complete) begin 31 | complete<=1'b0; 32 | end 33 | else if(!finished) begin 34 | complete<=((b>>1)==0); 35 | end 36 | end 37 | always_ff @(posedge clk) begin 38 | //$display("num:%b res:%b b:%b finished:%b",num,res,b,finished); 39 | if(strobe) begin 40 | if(num_in[W-1:W-3]!==3'bxxx) begin 41 | assert(num_in[W-1:W-3]==3'b001||num_in[W-1:W-4]==4'b0001) else begin 42 | $display("num_in: %b",num_in); 43 | $finish(); 44 | end 45 | end 46 | res<=0; 47 | num<=num_in; 48 | if(b>num) begin 49 | b<=b0>>2; 50 | end 51 | else begin 52 | b<=b0; 53 | end 54 | end 55 | else if(!finished) begin 56 | logic[W-1:0] num0,res0; 57 | logic[W:0] a,a0; 58 | a0=({1'b0,num[W-1:0]}- 59 | {1'b0,res[W-1:0]+b[W-1:0]}); 60 | a=~(~{1'b0,num[W-1:0]}+1'b1+{(W+1){1'b1}}+ 61 | {1'b0,res[W-1:0]+b[W-1:0]}); 62 | assert(a===a0) else begin 63 | $display("%b_%b",num[W-1],{num[W-2:W/4],{(W/4){1'b0}}}); 64 | $display("%b_%b",res[W-1],{res[W-2:W/4],{(W/4){1'b0}}}); 65 | $display("%b_%b", b[W-1],{ b[W-2:W/4],{(W/4){1'b0}}}); 66 | $display(" a:%b \na0:%b \nnum:%b \nres:%b \n b:%b",a,a0,num,res,b); 67 | $finish(); 68 | end 69 | if(a[W-1]==1'b0) begin //num>=res+b 70 | num0=a[W-1:0]; // num-=res+b; 71 | res0=((res>>1)|b); 72 | end 73 | else begin 74 | num0=num; 75 | res0=res>>1; 76 | end 77 | b<=b>>1; 78 | res<=res0<<1; 79 | num<=num0<<1; 80 | rem_s<=a[W-1]; 81 | end 82 | end 83 | 84 | assign rem=num; 85 | 86 | endmodule 87 | 88 | module R5FP_sqrt_seq #(parameter SIG_W=23, parameter EXP_W=8) ( 89 | input [SIG_W+EXP_W:0] a_in, input [2:0] rnd_in, 90 | input clk, reset, strobe, output reg complete, ready, 91 | output reg [SIG_W+EXP_W:0] z, output reg [7:0] status); 92 | 93 | logic[SIG_W+EXP_W:0] a; 94 | logic[2:0] rnd; 95 | logic strobe_r; 96 | always_ff @(posedge clk) begin 97 | if(reset) begin 98 | a<=0; 99 | rnd<=0; 100 | end 101 | else if(strobe) begin 102 | a<=a_in; 103 | rnd<=rnd_in; 104 | end 105 | strobe_r<=strobe; 106 | end 107 | typedef enum {IDLE, WAIT, OUTPUT} state_t; 108 | state_t state_r; 109 | wire isqrtComplete; 110 | logic isZero,isInf,isNAN,isZero_r,isInf_r,isNAN_r; 111 | 112 | always_ff @(posedge clk) begin 113 | //`DEBUG("state_r:%b isZero:%b isInf:%b isNAN:%b ready:%b complete:%b strobe:%b",state_r,isZero,isInf,isNAN,ready,complete,strobe); 114 | if(reset) begin 115 | state_r<=IDLE; 116 | end 117 | else begin 118 | case(state_r) 119 | IDLE: begin 120 | if(strobe_r) begin 121 | state_r<=( ({isZero,isInf,isNAN}==0)? WAIT : OUTPUT ); 122 | end 123 | end 124 | WAIT: begin 125 | if(isqrtComplete) state_r<=OUTPUT; 126 | end 127 | OUTPUT: begin 128 | state_r<=IDLE; 129 | end 130 | endcase 131 | end 132 | end 133 | 134 | logic[SIG_W+3:0] sigA,sigZ,sigA_r; 135 | logic[SIG_W+4:0] res,rem,res_r,res_sh,rem_r; 136 | logic rem_s; 137 | logic[EXP_W+1:0] expA,expZ,expZ0,expZ_r; 138 | logic[SIG_W+EXP_W:0] z_pre; 139 | logic[SIG_W-1:0] s0,s; 140 | logic [7:0] status_pre; 141 | 142 | function void prepare(); 143 | expA=a[EXP_W-1+SIG_W:SIG_W]; 144 | s0=a[SIG_W-1:0]; 145 | 146 | s=s0; 147 | assert(expA!=0); 148 | 149 | if(expA==0&&s0[SIG_W-1]==1'b1) begin 150 | s=s<<1; 151 | expA=1; 152 | sigA={3'b001,s,1'b0}; 153 | //`DEBUG("Here2 s:%b sigA:%b",s,sigA); 154 | end 155 | else begin 156 | if(expA[0]==1'b0) begin 157 | expA=expA+1; 158 | sigA={3'b001,s,1'b0}; 159 | end 160 | else begin 161 | expA=expA+2; 162 | sigA={4'b0001,s}; 163 | end 164 | end 165 | expZ=((expA - {EXP_W-1{1'b1}})>>1)+{EXP_W-1{1'b1}}-1; 166 | isZero=(a[EXP_W-1+SIG_W:0]==0); 167 | isInf=((&a[EXP_W-1+SIG_W:SIG_W])==1 && a[SIG_W-1:0]==0); 168 | isNAN=((&a[EXP_W-1+SIG_W:SIG_W])==1 && a[SIG_W-1:0]!=0); 169 | //`DEBUG("here2 isInf:%b isNAN:%b a:%b.%b",isInf,isNAN, a[EXP_W-1+SIG_W:SIG_W], a[SIG_W-1:0]); 170 | endfunction 171 | 172 | always_comb begin 173 | prepare(); 174 | end 175 | 176 | //always_ff @(negedge clk) begin 177 | // $display("sigA:%b expZ:%b a:%b strobe_r:%b state_r:%b ready:%b complete:%b",sigA,expZ,a,strobe_r,state_r[2:0],ready,complete); 178 | //end 179 | always_ff @(posedge clk) begin 180 | if(strobe_r) begin 181 | //$display("HERE sigA:%b expZ:%b a:%b strobe_r:",sigA,expZ,a,strobe_r); 182 | expZ_r<=expZ; 183 | sigA_r<=sigA; 184 | isZero_r<=isZero; 185 | isInf_r<=isInf; 186 | isNAN_r<=isNAN; 187 | end 188 | end 189 | 190 | logic isqrtStrobe; 191 | always @(posedge clk) begin 192 | if(reset) begin 193 | isqrtStrobe<=1'b0; 194 | end 195 | else if(isqrtStrobe) begin 196 | isqrtStrobe<=1'b0; 197 | end 198 | else if(state_r==IDLE&&strobe_r) begin 199 | isqrtStrobe<=1'b1; 200 | end 201 | end 202 | R5FP_int_sqrt #(.W(SIG_W+5)) isqrt (.num_in({sigA_r,1'b0}), .res(res), .rem(rem), .rem_s(rem_s), 203 | .clk(clk), .reset(reset), .strobe(isqrtStrobe), .complete(isqrtComplete)); 204 | always_ff @(posedge clk) begin 205 | if(state_r==WAIT&&isqrtComplete) begin 206 | //`DEBUG("HERE2 sigA_r:%b res:%b rem:%b rem_s:%b res*res:%b res*res+rem:%b a:%b complete:%b",sigA_r,res,rem,rem_s, {{SIG_W+5{1'b0}},res}*{{SIG_W+5{1'b0}},res}, {{SIG_W+5{1'b0}},res}*{{SIG_W+5{1'b0}},res}+rem,a,complete); 207 | res_r<=res; 208 | rem_r<=rem; 209 | end 210 | end 211 | 212 | reg [6:0] status_tmp; 213 | always @(*) begin 214 | status_tmp=0; 215 | status_tmp[`STICKY]=(rem_r!=0); 216 | res_sh=res_r; 217 | if(res_sh[SIG_W+3]==0) res_sh=res_sh<<1; 218 | end 219 | R5FP_postproc #( 220 | .I_SIG_W(SIG_W+5), 221 | .SIG_W(SIG_W), 222 | .EXP_W(EXP_W)) pp ( 223 | .aStatus(status_tmp), 224 | .aSign(1'b0), 225 | .aExp({1'b1, {EXP_W-1{1'b0}}}), 226 | .aSig(res_sh), 227 | .tailZeroCnt({EXP_W{1'b0}}), 228 | .rnd(rnd), 229 | .z(z_pre), 230 | .status(status_pre)); 231 | 232 | always_comb begin 233 | expZ0=expZ_r; 234 | if(rnd==`RND_UP||rnd==`RND_FROM_ZERO) begin 235 | expZ0=expZ0+z_pre[SIG_W]; 236 | end 237 | z={1'b0,expZ0[EXP_W-1:0],z_pre[SIG_W-1:0]}; 238 | status=0; 239 | status[`Z_INEXACT]=status_pre[`Z_INEXACT]; 240 | if(rnd==`RND_NEAREST_EVEN) begin 241 | if(rem_r) status[`Z_IS_ZERO]=1'b0; 242 | end 243 | 244 | if(isZero_r) begin //zero 245 | z=0; 246 | status=8'b00000001; 247 | end 248 | else if(isInf_r) begin //Infinity 249 | z=a; 250 | status=0; 251 | status[`Z_IS_INF]=1'b1; 252 | end 253 | else if(isNAN_r) begin //NAN 254 | z={1'b1, {EXP_W-1{1'b1}}, {SIG_W-1{1'b0}}, 1'b1}; 255 | status=0; 256 | status[`Z_INVALID]=1'b1; 257 | end 258 | end 259 | 260 | always_ff @(posedge clk) begin 261 | if(reset) begin 262 | ready<=1'b1; 263 | end 264 | else if(strobe) begin 265 | ready<=1'b0; 266 | end 267 | else if(state_r==OUTPUT) begin 268 | ready<=1'b1; 269 | end 270 | end 271 | always_ff @(posedge clk) begin 272 | if(reset) begin 273 | complete<=1'b0; 274 | end 275 | else if(state_r==OUTPUT) begin 276 | complete<=1'b0; 277 | end 278 | else if(state_r==WAIT&&isqrtComplete) begin 279 | complete<=1'b1; 280 | //$display("HERE3 sigA_r:%b res:%b rem:%b a:%b complete:%b",sigA_r,res,rem,a,complete); 281 | end 282 | end 283 | 284 | endmodule 285 | -------------------------------------------------------------------------------- /tb/tb_R5_float_add.v: -------------------------------------------------------------------------------- 1 | 2 | `include "R5FP_inc.vh" 3 | 4 | module R5FP_add_wrap #( 5 | parameter EXP_W=5, 6 | parameter SIG_W=10) ( 7 | input [EXP_W+SIG_W:0] a, b, 8 | input [2:0] rnd, 9 | output reg [7:0] status, 10 | output [EXP_W+SIG_W:0] z); 11 | 12 | wire [EXP_W+SIG_W+1:0] ax, bx, zx; 13 | 14 | R5FP_exp_incr #( 15 | .SIG_W(SIG_W), 16 | .EXP_W(EXP_W)) a_i (.a(a), .z(ax)); 17 | R5FP_exp_incr #( 18 | .SIG_W(SIG_W), 19 | .EXP_W(EXP_W)) b_i (.a(b), .z(bx)); 20 | 21 | R5FP_add #( 22 | .SIG_W(SIG_W), 23 | .EXP_W(EXP_W+1)) add (.a(ax), .b(bx), .rnd(rnd), .status(status), .z(zx)); 24 | 25 | R5FP_exp_decr #( 26 | .SIG_W(SIG_W), 27 | .EXP_W(EXP_W)) z_d (.a(zx), .z(z)); 28 | 29 | endmodule 30 | 31 | /////////////////////////////////////////////////////////////////// 32 | module tb_fp_add; 33 | 34 | parameter ClockPeriod=2000; 35 | reg clk,reset; 36 | initial begin 37 | clk=0; 38 | forever begin 39 | #(ClockPeriod/2) 40 | clk=~clk; 41 | end 42 | end 43 | 44 | 45 | parameter EXP_W=5; 46 | parameter SIG_W=6; 47 | parameter [2:0] ROUND=`RM; 48 | 49 | logic aSign; 50 | logic bSign; 51 | logic ySign; 52 | logic z0Sign; 53 | logic [SIG_W-1:0] aSig; 54 | logic [SIG_W-1:0] bSig; 55 | logic [SIG_W-1:0] ySig; 56 | logic [SIG_W-1:0] z0Sig; 57 | logic [EXP_W-1:0] aExp; 58 | logic [EXP_W-1:0] bExp; 59 | logic [EXP_W-1:0] yExp; 60 | logic [EXP_W-1:0] z0Exp; 61 | wire [7:0] s0,yS; 62 | wire [EXP_W+SIG_W:0] a={aSign,aExp,aSig}; 63 | wire [EXP_W+SIG_W:0] b={bSign,bExp,bSig}; 64 | 65 | DW_fp_add #( 66 | .sig_width(SIG_W), 67 | .exp_width(EXP_W), 68 | .ieee_compliance(1)) R (.a(a), .b(b), .rnd(ROUND), .z({z0Sign,z0Exp,z0Sig}), .status(s0)); 69 | 70 | R5FP_add_wrap #( 71 | .EXP_W(EXP_W), 72 | .SIG_W(SIG_W)) I ( 73 | .a(a), .b(b), .rnd(ROUND), .z({ySign,yExp,ySig}), .status(yS)); 74 | 75 | reg stop; 76 | initial begin 77 | stop=1'b0; 78 | {aSign,aExp,aSig}=32'b0; 79 | {bSign,bExp,bSig}=32'b0; 80 | end 81 | always @(negedge clk) begin 82 | if(stop) begin 83 | $display("All Done"); 84 | $finish(); 85 | end 86 | if((&a)==1 && (&b)==1) stop<=1'b1; 87 | if((&a)==1) begin 88 | {aExp,aSign,aSig}=0; 89 | {bExp,bSign,bSig}={bExp,bSign,bSig}+1; 90 | $display("Now b: %b.%b.%b",bExp,bSign,bSig); 91 | end 92 | else begin 93 | {aExp,aSign,aSig}={aExp,aSign,aSig}+1; 94 | end 95 | //$display("Now a: %b.%b.%b (b: %b.%b.%b)",aExp,aSign,aSig, bExp,bSign,bSig); 96 | end 97 | 98 | always @(posedge clk) begin 99 | //$display("Now a: %b.%b.%b b: %b.%b.%b", aSign,aExp,aSig, bSign,bExp,bSig); 100 | reg pass; 101 | pass={z0Sign,z0Exp,z0Sig}=={ySign,yExp,ySig}||{z0Exp,z0Sig,yExp,ySig}==0; 102 | if((&z0Exp)==1&&(&yExp)==1&&z0Sig!=0&&ySig!=0) pass=1; 103 | if(s0!=yS) pass=0; 104 | if(pass) begin 105 | //$display("Pass"); 106 | //$display("Pass a: %b.%b.%b b: %b.%b.%b z0:%b.%b.%b y:%b.%b.%b", aSign,aExp,aSig, bSign,bExp,bSig, z0Sign,z0Exp,z0Sig, ySign,yExp,ySig); 107 | //$display("Pass ax: %b.%b.%b bx: %b.%b.%b zx: %b.%b.%b", I.ax[EXP_W+SIG_W+1],I.ax[EXP_W+SIG_W:SIG_W],I.ax[SIG_W-1:0], I.bx[EXP_W+SIG_W+1],I.bx[EXP_W+SIG_W:SIG_W],I.bx[SIG_W-1:0], I.zx[EXP_W+SIG_W+1],I.zx[EXP_W+SIG_W:SIG_W],I.zx[SIG_W-1:0]); 108 | //$display("Pass s0: %b yS:%b", s0, yS); 109 | end 110 | else begin 111 | $display("a: %b.%b.%b b: %b.%b.%b z0:%b.%b.%b y:%b.%b.%b", aSign,aExp,aSig, bSign,bExp,bSig, z0Sign,z0Exp,z0Sig, ySign,yExp,ySig); 112 | $display("ax: %b.%b.%b bx: %b.%b.%b zx: %b.%b.%b", I.ax[EXP_W+SIG_W+1],I.ax[EXP_W+SIG_W:SIG_W],I.ax[SIG_W-1:0], I.bx[EXP_W+SIG_W+1],I.bx[EXP_W+SIG_W:SIG_W],I.bx[SIG_W-1:0], I.zx[EXP_W+SIG_W+1],I.zx[EXP_W+SIG_W:SIG_W],I.zx[SIG_W-1:0]); 113 | $display("s0: %b yS:%b", s0, yS); 114 | $finish(); 115 | end 116 | end 117 | 118 | endmodule 119 | 120 | -------------------------------------------------------------------------------- /tb/tb_R5_float_div32.v: -------------------------------------------------------------------------------- 1 | 2 | `include "R5FP_div.v" 3 | function automatic int16 extractFloat32Exp( float32 a ); 4 | return ( a>>23 ) & 'hFF; 5 | endfunction 6 | 7 | module test_div_float (); 8 | 9 | logic clk, rst_n, strobe_in; 10 | bits64 a32Ref_in, b32Ref_in; 11 | bits33 aRef_in, bRef_in; 12 | bits65 a_in, b_in; 13 | float_ctrl_t fctrl_in; 14 | bits64 result_right; 15 | bits65 result_out; 16 | bits33 result33; 17 | bits32 result; 18 | float_ctrl_t fctrl_out; 19 | float_ctrl_t fctrl_tmp; 20 | logic valid_out; 21 | int test_counter; 22 | int tiny, round; 23 | integer fd; 24 | float_exception_flags_t flags_right; 25 | 26 | R5FP_exp_incr #( 27 | .SIG_W(23), 28 | .EXP_W(8)) a_incr (.a(a32Ref_in[31:0]), .z(aRef_in)); 29 | R5FP_exp_incr #( 30 | .SIG_W(23), 31 | .EXP_W(8)) b_incr (.a(b32Ref_in[31:0]), .z(bRef_in)); 32 | 33 | R5FP_fp2fp_expand #( 34 | .SIG_W(23), 35 | .EXP_W(9), 36 | .SIG_W_INCR(29), 37 | .EXP_W_INCR(3)) a_x (.a(aRef_in), .z(a_in)); 38 | R5FP_fp2fp_expand #( 39 | .SIG_W(23), 40 | .EXP_W(9), 41 | .SIG_W_INCR(29), 42 | .EXP_W_INCR(3)) b_x (.a(bRef_in), .z(b_in)); 43 | 44 | R5FP_div_seq U_float_div_seq (.is_single_in(1'b1), .*); 45 | 46 | R5FP_fp65_to_fp33 fp65to33 (.rnd(fctrl_in.float_rounding_mode), .a(result_out), .z(result33)); 47 | 48 | R5FP_exp_decr #( 49 | .SIG_W(23), 50 | .EXP_W(8)) U_decr (.a(result33), .z(result)); 51 | 52 | initial begin 53 | fd = $fopen("../test_cases/test_case_float32_div_L2.txt", "r"); 54 | 55 | $display("Now start..."); 56 | test_counter=0; 57 | clk=0; 58 | rst_n=1; 59 | strobe_in=1'b0; 60 | #3 61 | rst_n=0; 62 | #3 63 | rst_n=1; 64 | #3 65 | clk=1; 66 | #3 67 | forever begin 68 | #10 69 | clk = ~clk; 70 | end 71 | end 72 | 73 | reg finish_loop,ok; 74 | float_ctrl_t fctrl_imp; 75 | always @(negedge clk) begin 76 | //if(test_counter>100*10000) $finish(2); 77 | if(test_counter%10000==0) $display("test_counter: %d", test_counter); 78 | if(test_counter>0 && valid_out) begin 79 | fctrl_imp=fctrl_out; 80 | fctrl_imp.float_exception_flags[5:3]=0; //TODO 81 | flags_right[5:3]=0; //TODO 82 | ok=(result_right==result && flags_right==fctrl_imp.float_exception_flags); 83 | if(result_right[30:23]==8'hFF && result[30:23]==8'hFF) ok=1'b1; //TODO 84 | if(!ok) begin 85 | $display("tiny:%d round:%d, a:%b-%h-%h b:%b-%h-%h resRight:%b.%h.%h flagRight:%b : result_out:%b.%h.%h -> result33:%b.%h.%h -> result:%b.%h.%h flag:%b", tiny, round, 86 | a_in[64],a_in[63:52],a_in[51:0], 87 | b_in[64],b_in[63:52],b_in[51:0], 88 | result_right[31],result_right[30:23],result_right[22:0],flags_right, 89 | result_out[64],result_out[63:52],result_out[51:0], 90 | result33[32],result33[31:23],result[22:0], 91 | result[31],result[30:23],result[22:0], 92 | fctrl_imp.float_exception_flags); 93 | $finish(2); 94 | end 95 | else begin 96 | //$display("PASS! %d %d, %h %h %h %h : %h %h", tiny, round, a_in,b_in,result_right,flags_right, result, fctrl_imp.float_exception_flags); 97 | end 98 | end 99 | if(strobe_in==1'b1) strobe_in=1'b0; 100 | if(test_counter==0 || valid_out) begin 101 | $fscanf(fd, "%d %d %h %h %h %h", tiny, round, a32Ref_in, b32Ref_in, result_right, flags_right); 102 | //$display("Read: a:%b.%h.%h b:%b.%h.%h", a32Ref_in[31],a32Ref_in[30:23],a32Ref_in[22:0], b32Ref_in[31],b32Ref_in[30:23],b32Ref_in[22:0]); 103 | if(tiny==0) fctrl_in.float_detect_tininess=FLOAT_TININESS_AFTER_ROUNDING; 104 | if(tiny==1) fctrl_in.float_detect_tininess=FLOAT_TININESS_BEFORE_ROUNDING; 105 | if(tiny==100) begin 106 | $display("File finished!"); 107 | $finish(); 108 | end 109 | if(round==0) fctrl_in.float_rounding_mode=FLOAT_ROUND_NEAREST_EVEN; 110 | if(round==1) fctrl_in.float_rounding_mode=FLOAT_ROUND_DOWN; 111 | if(round==2) fctrl_in.float_rounding_mode=FLOAT_ROUND_UP; 112 | if(round==3) fctrl_in.float_rounding_mode=FLOAT_ROUND_TO_ZERO; 113 | fctrl_in.float_exception_flags=0; 114 | test_counter=test_counter+1; 115 | strobe_in=1'b1; 116 | //fctrl_tmp=fctrl_in; 117 | //float64_div(a_in, b_in, fctrl_in); 118 | end 119 | end 120 | 121 | endmodule 122 | 123 | 124 | 125 | -------------------------------------------------------------------------------- /tb/tb_R5_float_div64.v: -------------------------------------------------------------------------------- 1 | 2 | `include "R5FP_div.v" 3 | function automatic int16 extractFloat32Exp( float32 a ); 4 | return ( a>>23 ) & 'hFF; 5 | endfunction 6 | 7 | module test_div_float (); 8 | 9 | logic clk, rst_n, strobe_in; 10 | bits64 aRef_in, bRef_in; 11 | bits65 a_in, b_in; 12 | float_ctrl_t fctrl_in; 13 | bits64 result, result_right; 14 | bits65 result_out; 15 | float_ctrl_t fctrl_out; 16 | float_ctrl_t fctrl_tmp; 17 | logic valid_out; 18 | int test_counter; 19 | int tiny, round; 20 | integer fd; 21 | float_exception_flags_t flags_right; 22 | 23 | R5FP_exp_incr #( 24 | .SIG_W(52), 25 | .EXP_W(11)) a_incr (.a(aRef_in), .z(a_in)); 26 | 27 | R5FP_exp_incr #( 28 | .SIG_W(52), 29 | .EXP_W(11)) b_incr (.a(bRef_in), .z(b_in)); 30 | 31 | 32 | R5FP_div_seq U_float_div_seq (.is_single_in(1'b0), .*); 33 | 34 | R5FP_exp_decr #( 35 | .SIG_W(52), 36 | .EXP_W(11)) U_decr (.a(result_out), .z(result)); 37 | 38 | initial begin 39 | fd = $fopen("../test_cases/test_case_float64_div_L2.txt", "r"); 40 | 41 | $display("Now start..."); 42 | test_counter=0; 43 | clk=0; 44 | rst_n=1; 45 | strobe_in=1'b0; 46 | #3 47 | rst_n=0; 48 | #3 49 | rst_n=1; 50 | #3 51 | clk=1; 52 | #3 53 | forever begin 54 | #10 55 | clk = ~clk; 56 | end 57 | end 58 | 59 | reg finish_loop,ok; 60 | float_ctrl_t fctrl_imp; 61 | always @(negedge clk) begin 62 | //if(test_counter>100*10000) $finish(2); 63 | if(test_counter%10000==0) $display("test_counter: %d", test_counter); 64 | if(test_counter>0 && valid_out) begin 65 | fctrl_imp=fctrl_out; 66 | fctrl_imp.float_exception_flags[4:3]=0; //TODO 67 | flags_right[4:3]=0; //TODO 68 | ok=(result_right==result && flags_right==fctrl_imp.float_exception_flags); 69 | if(result_right[62:52]==11'h7FF && result[62:52]==11'h7FF) ok=1'b1; //TODO 70 | if(!ok) begin 71 | $display("tiny:%d round:%d, a:%b-%h-%h b:%b-%h-%h resRight:%b.%h.%h flagRight:%b : result:%b.%h.%h(%b.%h.%h) flag:%b", tiny, round, 72 | a_in[63],a_in[62:52],a_in[51:0], 73 | b_in[63],b_in[62:52],b_in[51:0], 74 | result_right[63],result_right[62:52],result_right[51:0],flags_right, 75 | result[63],result[62:52],result[51:0], 76 | result_out[64],result_out[63:52],result_out[51:0], 77 | fctrl_imp.float_exception_flags); 78 | $finish(2); 79 | end 80 | else begin 81 | //$display("PASS! %d %d, %h %h %h %h : %h %h", tiny, round, a_in,b_in,result_right,flags_right, result, fctrl_imp.float_exception_flags); 82 | end 83 | end 84 | if(strobe_in==1'b1) strobe_in=1'b0; 85 | if(test_counter==0 || valid_out) begin 86 | $fscanf(fd, "%d %d %h %h %h %h", tiny, round, aRef_in, bRef_in, result_right, flags_right); 87 | //finish_loop=0; 88 | //while (!finish_loop) begin 89 | // $fscanf(fd, "%d %d %h %h %h %h", tiny, round, aRef_in, bRef_in, result_right, flags_right); 90 | // finish_loop=1; 91 | // if(extractFloat32Exp(aRef_in)==0&&is_single) finish_loop=0; 92 | // else if(extractFloat64Exp(aRef_in)==0&&!is_single) finish_loop=0; 93 | // else if(extractFloat32Exp(bRef_in)==0&&is_single) finish_loop=0; 94 | // else if(extractFloat64Exp(bRef_in)==0&&!is_single) finish_loop=0; 95 | //end 96 | if(tiny==0) fctrl_in.float_detect_tininess=FLOAT_TININESS_AFTER_ROUNDING; 97 | if(tiny==1) fctrl_in.float_detect_tininess=FLOAT_TININESS_BEFORE_ROUNDING; 98 | if(tiny==100) begin 99 | $display("File finished!"); 100 | $finish(); 101 | end 102 | if(round==0) fctrl_in.float_rounding_mode=FLOAT_ROUND_NEAREST_EVEN; 103 | if(round==1) fctrl_in.float_rounding_mode=FLOAT_ROUND_DOWN; 104 | if(round==2) fctrl_in.float_rounding_mode=FLOAT_ROUND_UP; 105 | if(round==3) fctrl_in.float_rounding_mode=FLOAT_ROUND_TO_ZERO; 106 | fctrl_in.float_exception_flags=0; 107 | test_counter=test_counter+1; 108 | strobe_in=1'b1; 109 | //fctrl_tmp=fctrl_in; 110 | //float64_div(a_in, b_in, fctrl_in); 111 | end 112 | end 113 | 114 | endmodule 115 | 116 | 117 | 118 | -------------------------------------------------------------------------------- /tb/tb_R5_float_mul.v: -------------------------------------------------------------------------------- 1 | 2 | `include "R5FP_inc.vh" 3 | 4 | module R5FP_mul_wrap #( 5 | parameter EXP_W=5, 6 | parameter SIG_W=10) ( 7 | input [EXP_W+SIG_W:0] a, b, 8 | input [2:0] rnd, 9 | output reg [7:0] status, 10 | output [EXP_W+SIG_W:0] z); 11 | 12 | wire [EXP_W+SIG_W+1:0] ax, bx, zx; 13 | 14 | R5FP_exp_incr #( 15 | .SIG_W(SIG_W), 16 | .EXP_W(EXP_W)) a_i (.a(a), .z(ax)); 17 | R5FP_exp_incr #( 18 | .SIG_W(SIG_W), 19 | .EXP_W(EXP_W)) b_i (.a(b), .z(bx)); 20 | 21 | R5FP_mul #( 22 | .SIG_W(SIG_W), 23 | .EXP_W(EXP_W+1)) mul (.a(ax), .b(bx), .rnd(rnd), .status(status), .z(zx)); 24 | 25 | R5FP_exp_decr #( 26 | .SIG_W(SIG_W), 27 | .EXP_W(EXP_W)) z_d (.a(zx), .z(z)); 28 | 29 | endmodule 30 | 31 | /////////////////////////////////////////////////////////////////// 32 | module tb_fp_mul; 33 | 34 | parameter ClockPeriod=2000; 35 | reg clk,reset; 36 | initial begin 37 | clk=0; 38 | forever begin 39 | #(ClockPeriod/2) 40 | clk=~clk; 41 | end 42 | end 43 | 44 | 45 | parameter EXP_W=5; 46 | parameter SIG_W=6; 47 | parameter [2:0] ROUND=`RM; 48 | 49 | logic aSign; 50 | logic bSign; 51 | logic ySign; 52 | logic z0Sign; 53 | logic [SIG_W-1:0] aSig; 54 | logic [SIG_W-1:0] bSig; 55 | logic [SIG_W-1:0] ySig; 56 | logic [SIG_W-1:0] z0Sig; 57 | logic [EXP_W-1:0] aExp; 58 | logic [EXP_W-1:0] bExp; 59 | logic [EXP_W-1:0] yExp; 60 | logic [EXP_W-1:0] z0Exp; 61 | wire [7:0] s0,yS; 62 | wire [EXP_W+SIG_W:0] a={aSign,aExp,aSig}; 63 | wire [EXP_W+SIG_W:0] b={bSign,bExp,bSig}; 64 | 65 | DW_fp_mult #( 66 | .sig_width(SIG_W), 67 | .exp_width(EXP_W), 68 | .ieee_compliance(1)) R (.a(a), .b(b), .rnd(ROUND), .z({z0Sign,z0Exp,z0Sig}), .status(s0)); 69 | 70 | R5FP_mul_wrap #( 71 | .EXP_W(EXP_W), 72 | .SIG_W(SIG_W)) I ( 73 | .a(a), .b(b), .rnd(ROUND), .z({ySign,yExp,ySig}), .status(yS)); 74 | 75 | reg stop; 76 | initial begin 77 | stop=1'b0; 78 | {aSign,aExp,aSig}=32'b0; 79 | {bSign,bExp,bSig}=32'b0; 80 | end 81 | always @(negedge clk) begin 82 | if(stop) begin 83 | $display("All Done"); 84 | $finish(); 85 | end 86 | if((&a)==1 && (&b)==1) stop<=1'b1; 87 | if((&a)==1) begin 88 | {aExp,aSign,aSig}=0; 89 | {bExp,bSign,bSig}={bExp,bSign,bSig}+1; 90 | $display("Now b: %b.%b.%b",bExp,bSign,bSig); 91 | end 92 | else begin 93 | {aExp,aSign,aSig}={aExp,aSign,aSig}+1; 94 | end 95 | //$display("Now a: %b.%b.%b (b: %b.%b.%b)",aExp,aSign,aSig, bExp,bSign,bSig); 96 | end 97 | 98 | always @(posedge clk) begin 99 | //$display("Now a: %b.%b.%b b: %b.%b.%b", aSign,aExp,aSig, bSign,bExp,bSig); 100 | reg pass; 101 | pass={z0Sign,z0Exp,z0Sig}=={ySign,yExp,ySig}||{z0Exp,z0Sig,yExp,ySig}==0; 102 | if((&z0Exp)==1&&(&yExp)==1&&z0Sig!=0&&ySig!=0) pass=1; 103 | if(s0!=yS) pass=0; 104 | if(pass) begin 105 | //$display("Pass"); 106 | //$display("Pass a: %b.%b.%b b: %b.%b.%b z0:%b.%b.%b y:%b.%b.%b", aSign,aExp,aSig, bSign,bExp,bSig, z0Sign,z0Exp,z0Sig, ySign,yExp,ySig); 107 | //$display("Pass ax: %b.%b.%b bx: %b.%b.%b zx: %b.%b.%b", I.ax[EXP_W+SIG_W+1],I.ax[EXP_W+SIG_W:SIG_W],I.ax[SIG_W-1:0], I.bx[EXP_W+SIG_W+1],I.bx[EXP_W+SIG_W:SIG_W],I.bx[SIG_W-1:0], I.zx[EXP_W+SIG_W+1],I.zx[EXP_W+SIG_W:SIG_W],I.zx[SIG_W-1:0]); 108 | //$display("Pass s0: %b yS:%b", s0, yS); 109 | end 110 | else begin 111 | $display("a: %b.%b.%b b: %b.%b.%b z0:%b.%b.%b y:%b.%b.%b", aSign,aExp,aSig, bSign,bExp,bSig, z0Sign,z0Exp,z0Sig, ySign,yExp,ySig); 112 | $display("ax: %b.%b.%b bx: %b.%b.%b zx: %b.%b.%b", I.ax[EXP_W+SIG_W+1],I.ax[EXP_W+SIG_W:SIG_W],I.ax[SIG_W-1:0], I.bx[EXP_W+SIG_W+1],I.bx[EXP_W+SIG_W:SIG_W],I.bx[SIG_W-1:0], I.zx[EXP_W+SIG_W+1],I.zx[EXP_W+SIG_W:SIG_W],I.zx[SIG_W-1:0]); 113 | $display("s0: %b yS:%b", s0, yS); 114 | $finish(); 115 | end 116 | end 117 | 118 | endmodule 119 | 120 | 121 | -------------------------------------------------------------------------------- /tb/tb_R5_float_sqrt.v: -------------------------------------------------------------------------------- 1 | 2 | module R5FP_sqrt_seq_wrap #( 3 | parameter EXP_W=5, 4 | parameter SIG_W=6) ( 5 | input [EXP_W+SIG_W:0] a, 6 | input [2:0] rnd, 7 | output [7:0] status, 8 | output [EXP_W+SIG_W:0] z, 9 | input clk,reset,strobe, 10 | output ready, complete); 11 | 12 | wire [EXP_W+SIG_W+1:0] ax,zx; 13 | 14 | R5FP_exp_incr #( 15 | .SIG_W(SIG_W), 16 | .EXP_W(EXP_W)) a_i (.a(a), .z(ax)); 17 | 18 | R5FP_sqrt_seq #(.SIG_W(SIG_W), .EXP_W(EXP_W+1)) sqrt (.a_in(ax), .rnd_in(rnd), 19 | .clk(clk), .reset(reset), .strobe(strobe), .complete(complete), .ready(ready), 20 | .z(zx), .status(status)); 21 | 22 | R5FP_exp_decr #( 23 | .SIG_W(SIG_W), 24 | .EXP_W(EXP_W)) z_d (.a(zx), .z(z)); 25 | 26 | endmodule 27 | 28 | 29 | module tb_R5FP_sqrt; 30 | parameter ClockPeriod=10; 31 | parameter SIG_W=7; 32 | parameter EXP_W=7; 33 | parameter [2:0] rnd=`RND_MODE; 34 | bit clk,reset,strobe,complete,ready,strobe_r; 35 | 36 | bit[SIG_W+EXP_W:0] a; 37 | const bit[SIG_W+EXP_W:0] startVal=({1'b0,{EXP_W{1'b0}},{SIG_W{1'b0}}}); 38 | const bit[SIG_W+EXP_W:0] endVal={1'b0,{EXP_W{1'b1}}, {SIG_W{1'b1}}}; 39 | 40 | typedef struct packed { 41 | logic[SIG_W+EXP_W:0] a; 42 | logic[SIG_W+EXP_W:0] z; 43 | logic[7:0] status; 44 | } result_t; 45 | result_t resQ[$]; 46 | 47 | initial begin 48 | strobe=1'b0; 49 | a=startVal; 50 | reset=1'b1; 51 | #25 52 | reset=1'b0; 53 | end 54 | initial begin 55 | clk=1'b0; 56 | #1 57 | forever clk=#(ClockPeriod/2)~clk; 58 | end 59 | wire #1 clk_delayed=clk; 60 | 61 | logic[SIG_W+EXP_W:0] z0,z1; 62 | logic[7:0] status0,status1; 63 | 64 | DW_fp_sqrt #(.sig_width(SIG_W), .exp_width(EXP_W), .ieee_compliance(1)) r ( 65 | .a(a), .rnd(rnd), .z(z0), .status(status0)); 66 | 67 | always @(posedge clk_delayed) begin 68 | if(strobe) begin 69 | strobe<=1'b0; 70 | end 71 | else if(reset==1'b0&&ready==1'b1&&$urandom()%2==0) begin 72 | if(a%100000==0) $display(a); 73 | a<=a+1; 74 | if(a==endVal) begin 75 | $display("All Done"); 76 | $finish(); 77 | end 78 | strobe<=1'b1; 79 | end 80 | strobe_r<=strobe; 81 | if(strobe_r) begin 82 | result_t res; 83 | res.a=a; 84 | res.z=z0; 85 | res.status=status0; 86 | //$display("PUSH: a:%b z:%b status:%b",a,z0,status0); 87 | resQ.push_back(res); 88 | end 89 | end 90 | 91 | R5FP_sqrt_seq_wrap #(.SIG_W(SIG_W), .EXP_W(EXP_W)) i (.a(a), .rnd(rnd), 92 | .clk(clk), .reset(reset), .strobe(strobe), .complete(complete), .ready(ready), 93 | .z(z1), .status(status1)); 94 | 95 | logic cmpOK; 96 | always_ff @(negedge clk) begin 97 | if(complete) begin 98 | result_t res; 99 | res=resQ.pop_front(); 100 | //$display("POP: a:%b z:%b status:%b",res.a,res.z,res.status); 101 | if(res.a==endVal) $finish(); 102 | cmpOK=(res.z==z1&&res.status==status1); 103 | if(cmpOK) $display("Pass! %b", res.a); 104 | assert(cmpOK) else begin 105 | $display("z0:%b_%b a:%b_%b",res.z[EXP_W-1+SIG_W:SIG_W],res.z[SIG_W-1:0],res.a[EXP_W-1+SIG_W:SIG_W], res.a[SIG_W-1:0]); 106 | $display("z1:%b_%b",z1[EXP_W-1+SIG_W:SIG_W],z1[SIG_W-1:0]); 107 | $display("status0 %b",res.status); 108 | $display("status1 %b",status1); 109 | $finish(); 110 | end 111 | end 112 | end 113 | 114 | endmodule 115 | 116 | --------------------------------------------------------------------------------