`default_nettype none
module sort2
#( int w = 30,
int k = 16,
int exp = 5,
int sig = k - exp - 1 )
( output uwire logic [w-1:0] x0, x1,
input uwire logic [w-1:0] a0, a1 );
uwire ci = signed'(a0[k-1:0]) <= signed'(a1[k-1:0]);
uwire [k + exp + 1 -1:0] a0f, a1f, z0, z1;
uwire [7:0] s0, s1, sc0, sc1;
CW_fp_i2flt #( .isize( k ), .sig_width( k ), .exp_width( exp ) )
itoflt0( .a(a0[k-1:0]), .rnd( 3'b0 ), .z( a0f ), .status(sc0) );
CW_fp_i2flt #( .isize( k ), .sig_width( k ), .exp_width( exp ) )
itoflt1( .a(a1[k-1:0]), .rnd( 3'b0 ), .z( a1f ), .status(sc1) );
uwire altb, aeqb, agtb, who_knows;
uwire [k + exp + 1 -1:0] a0ff = a0[k-1:0] << ( k - sig );
localparam logic [k-sig-1:0] pad = 0;
uwire [k + exp + 1 -1:0] a1ff = { a1[k-1:0], pad };
CW_fp_cmp #( .sig_width(k), .exp_width(exp) )
cmp0( .a( a0[k] ? a0ff : a0f ),
.b( a1[k] ? a1ff : a1f ), .altb( altb ), .aeqb( aeqb ),
.unordered( who_knows ),
.agtb( agtb ), .zctr( 1'b0 ), .status0(s1), .status1(s0),
.z0(z0), .z1(z1) );
uwire cf = altb || aeqb;
uwire c = a0[k] || a1[k] ? cf : ci;
mux2 #(w) m0( x0, c, a1, a0);
mux2 #(w) m1( x1, c, a0, a1);
endmodule
module mux2
#( int w = 4 )
( output uwire [w-1:0] x,
input uwire select,
input uwire [w-1:0] a0, a1 );
assign x = select ? a1 : a0;
endmodule
cadence
module testbench;
var bit s[3];
testbench_size #(32,16,6) t1(s[1],s[0]);
testbench_size #(24,14,5) t2(s[2],s[1]);
initial begin
s[0] = 1;
wait( s[2] );
$write("\nAll done.\n");
end
endmodule
module testbench_size
#( int w = 30,
int k = 16,
int exp = 6,
int sig_width = k - exp - 1 )
( output var bit done, input var bit start );
localparam int s_pos = k - 1;
localparam int exp_hi = s_pos - 1;
localparam int exp_lo = s_pos - exp;
localparam int sig_hi = exp_lo - 1;
localparam int bias = ( 1 << exp - 1 ) - 1;
localparam int exp_i_max = bias + k - 1;
localparam int exp_max = ( 1 << exp ) - 2;
localparam int exp_range_ini = exp_i_max - bias;
localparam int exp_range_gti = exp_max - exp_i_max - 1;
function real fp_to_val(input logic [k-1:0] a);
fp_to_val =
a[exp_hi:0] == 0 ? 0.0 :
( ( 1.0 + a[sig_hi:0] / real'( 1 << sig_width ) )
* 2 ** ( 0.0 + a[exp_hi:exp_lo]-bias )
* ( a[s_pos] ? -1 : 1 ) );
endfunction
localparam int num_tests = 3000000;
localparam int test_ff_start = num_tests / 3;
localparam int test_if_start = test_ff_start * 2;
uwire [w-1:0] x0, x1;
logic [w-1:0] a[2];
sort2 #(w,k,exp,sig_width) s2(x0,x1, a[0], a[1]);
initial begin
automatic int err_count[string] = '{"ii":0, "ff":0, "if":0 };
automatic logic [1:0][w-1:0] tests[$];
case ( k )
14: begin
tests.push_back('h2a823); tests.push_back('h77b7e);
end
16: begin
tests.push_back('hdc641209); tests.push_back('ha0935641);
end
endcase
wait( start );
$write("Starting testbench for w=%0d, k=%0d, exp=%0d sig width=%0d...\n",
w, k, exp, exp_lo);
for ( int i=0; i<num_tests; i++ ) begin
automatic logic [k-1:0] i_1_mask = 1 << {$random} % k;
automatic string test_type =
i < test_ff_start ? "ii" :
i < test_if_start ? "ff" : "if";
bit fp[2];
real val[2];
bit swap;
logic [w-1:0] shadow_x0, shadow_x1;
for ( int j=0; j<2; j++ )
fp[j] = test_type == "ff" || test_type == "if" && ( (i+j) & 1 );
for ( int j=0; j<2; j++ ) begin
automatic int fp_sz = fp[j] ? {$random} % 4 : 4;
a[j][w-1:0] = {$random};
a[j][k] = fp[j];
case ( fp_sz )
0: a[j][exp_hi:0] = 0;
1: a[j][exp_hi:exp_lo] = 1 + {$random} % bias;
2: a[j][exp_hi:exp_lo] = bias + {$random} % exp_range_ini;
3: a[j][exp_hi:exp_lo] = exp_i_max + {$random} % exp_range_gti;
default:; endcase
end
if ( a[0][k] && a[1][k] && a[1][exp_hi:0] ) begin
if ( {$random} & 1 ) a[0][exp_hi:exp_lo] = a[1][exp_hi:exp_lo];
if ( {$random} & 1 ) a[0][sig_hi:0] = a[1][sig_hi:0];
end
if ( !a[0][k] && !a[1][k] ) begin
case ( {$random} % 6 )
0: a[1][k-1:0] = a[0][k-1:0] - 1;
1: a[1][k-1:0] = a[0][k-1:0] + 1;
2: a[1][k-1:0] = a[0][k-1:0] - 2;
3: a[1][k-1:0] = a[0][k-1:0] + 2;
4: begin a[0][k-1:0] &= i_1_mask; a[1][k-1:0] &= i_1_mask; end
default:;
endcase
end
if ( a[0][k] != a[1][k] ) begin
automatic int opt = {$random} % 32;
casex ( opt )
'h0xxx: if ( a[0][k] ) a[1][k-1:0] = fp_to_val(a[0])+opt[2:0]-4;
'h1xxx: if ( a[1][k] ) a[0][k-1:0] = fp_to_val(a[1])+opt[2:0]-4;
endcase
end
if ( tests.size() ) begin
a[0] = tests.pop_front();
a[1] = tests.pop_front();
end
case ( {a[0][k], a[1][k] } )
'b00: test_type = "ii";
'b11: test_type = "ff";
default: test_type = "if";
endcase
for ( int j=0; j<2; j++ )
val[j] = a[j][k] ? fp_to_val(a[j]) : signed'(a[j][s_pos:0]);
swap = val[0] > val[1];
{ shadow_x0, shadow_x1 } = { a[swap], a[1-swap] };
#1;
if ( shadow_x0 !== x0 || shadow_x1 !== x1 ) begin
err_count[test_type]++;
if ( err_count[test_type] > 5 ) continue;
$write
("Test %s %4d, error (x0,x1): (%h,%h) != (%h,%h) correct.\n",
test_type, i,
x0, x1, shadow_x0, shadow_x1);
for ( int j=0; j<2; j++ )
$write(" a%1d: data %h, key %12.5f = %s %s\n",
j, a[j][w-1:k], val[j], a[j][k] ? "FP " : "INT",
a[j][k] ?
$sformatf("s %b exp %0d-%0d=%0d sig 'h%h",
a[j][s_pos],
a[j][exp_hi:exp_lo], bias,
signed'({1'b0,a[j][exp_hi:exp_lo]}) - bias,
a[j][sig_hi:0])
: $sformatf("'h%h",a[j][k-1:0]));
$write(" To re-run paste: tests.push_back('h%h); tests.push_back('h%h);\n",
a[0],a[1]);
end
end
$write("Done with %0d tests for k=%0d, exp=%0d:", num_tests,k,exp);
foreach ( err_count[et] )
$write(" %0d %s errs,", err_count[et], et);
$write("\n");
done = 1;
end
endmodule
cadence
`default_nettype wire
`include "/apps/linux/cadence/GENUS191/share/synth/lib/chipware/sim/verilog/CW/CW_fp_add.v"