forked from Github_Repos/cvw
280 lines
14 KiB
Systemverilog
280 lines
14 KiB
Systemverilog
|
|
`include "wally-config.vh"
|
|
`define PATH "../../../../tests/fp/vectors/"
|
|
|
|
string tests[] = '{
|
|
"f16_mulAdd_rne.tv",
|
|
"f16_mulAdd_rz.tv",
|
|
"f16_mulAdd_ru.tv",
|
|
"f16_mulAdd_rd.tv",
|
|
"f16_mulAdd_rnm.tv",
|
|
"f32_mulAdd_rne.tv",
|
|
"f32_mulAdd_rz.tv",
|
|
"f32_mulAdd_ru.tv",
|
|
"f32_mulAdd_rd.tv",
|
|
"f32_mulAdd_rnm.tv",
|
|
"f64_mulAdd_rne.tv",
|
|
"f64_mulAdd_rz.tv",
|
|
"f64_mulAdd_ru.tv",
|
|
"f64_mulAdd_rd.tv",
|
|
"f64_mulAdd_rnm.tv",
|
|
"f128_mulAdd_rne.tv",
|
|
"f128_mulAdd_rz.tv",
|
|
"f128_mulAdd_ru.tv",
|
|
"f128_mulAdd_rd.tv",
|
|
"f128_mulAdd_rnm.tv"
|
|
};
|
|
|
|
// steps to run FMA tests
|
|
// 1) create test vectors in riscv-wally/tests/fp with: ./run-all.sh
|
|
// 2) go to riscv-wally/pipelined/testbench/fp/tests
|
|
// 3) run ./sim-wally-batch
|
|
|
|
module fmatestbench();
|
|
|
|
logic clk;
|
|
logic [31:0] errors=0;
|
|
logic [31:0] vectornum=0;
|
|
logic [`FLEN*4+7+4+4:0] testvectors[6133248:0];
|
|
int i = `ZFH_SUPPORTED ? 0 : `F_SUPPORTED ? 5 : `D_SUPPORTED ? 10 : 15; // set i to the first test that is run
|
|
|
|
logic [`FLEN-1:0] X, Y, Z; // inputs read from TestFloat
|
|
logic [`FLEN-1:0] ans; // result from TestFloat
|
|
logic [7:0] flags; // flags read form testfloat
|
|
logic [2:0] FrmE; // rounding mode
|
|
logic [`FPSIZES/3:0] FmtE; // format - 10 = half, 00 = single, 01 = double, 11 = quad
|
|
logic [3:0] FrmRead; // rounding mode read from testfloat
|
|
logic [3:0] FmtRead; // format read from testfloat
|
|
logic [`FLEN-1:0] FMAResM; // FMA's outputed result
|
|
logic [4:0] FMAFlgM; // FMA's outputed flags
|
|
logic [2:0] FOpCtrlE; // which opperation
|
|
logic wnan; // is the outputed result NaN
|
|
logic ansnan; // is the correct answer NaN
|
|
|
|
// signals needed to connect modules
|
|
logic [`NE+1:0] ProdExpE;
|
|
logic AddendStickyE;
|
|
logic KillProdE;
|
|
logic XSgnE, YSgnE, ZSgnE;
|
|
logic [`NE-1:0] XExpE, YExpE, ZExpE;
|
|
logic [`NF:0] XManE, YManE, ZManE;
|
|
logic XNormE;
|
|
logic XExpMaxE;
|
|
logic XNaNE, YNaNE, ZNaNE;
|
|
logic XSNaNE, YSNaNE, ZSNaNE;
|
|
logic XDenormE, YDenormE, ZDenormE;
|
|
logic XInfE, YInfE, ZInfE;
|
|
logic XZeroE, YZeroE, ZZeroE;
|
|
logic YExpMaxE, ZExpMaxE, Mult;
|
|
logic [3*`NF+5:0] SumE;
|
|
logic InvZE;
|
|
logic NegSumE;
|
|
logic ZSgnEffE;
|
|
logic PSgnE;
|
|
logic [$clog2(3*`NF+7)-1:0] NormCntE;
|
|
|
|
|
|
assign FOpCtrlE = 3'b0; // set to 0 because test float only tests fMADD
|
|
assign Mult = 1'b0; // set to zero because not testing multiplication
|
|
|
|
// check if the calculated result or correct answer is NaN
|
|
always_comb begin
|
|
case (FmtRead)
|
|
4'b11: begin // quad
|
|
assign ansnan = &ans[`FLEN-2:`NF]&(|ans[`NF-1:0]);
|
|
assign wnan = &FMAResM[`FLEN-2:`NF]&(|FMAResM[`NF-1:0]);
|
|
|
|
end
|
|
4'b01: begin // double
|
|
assign ansnan = &ans[`LEN1-2:`NF1]&(|ans[`NF1-1:0]);
|
|
assign wnan = &FMAResM[`LEN1-2:`NF1]&(|FMAResM[`NF1-1:0]);
|
|
|
|
end
|
|
4'b00: begin // single
|
|
assign ansnan = &ans[`LEN2-2:`NF2]&(|ans[`NF2-1:0]);
|
|
assign wnan = &FMAResM[`LEN2-2:`NF2]&(|FMAResM[`NF2-1:0]);
|
|
end
|
|
4'b10: begin // half
|
|
assign ansnan = &ans[`H_LEN-2:`H_NF]&(|ans[`H_NF-1:0]);
|
|
assign wnan = &FMAResM[`H_LEN-2:`H_NF]&(|FMAResM[`H_NF-1:0]);
|
|
end
|
|
endcase
|
|
end
|
|
|
|
// instantiate devices under test
|
|
unpack unpack(.X, .Y, .Z, .FmtE, .FOpCtrlE, .XSgnE, .YSgnE, .ZSgnE, .XExpE, .YExpE, .ZExpE,
|
|
.XManE, .YManE, .ZManE, .XNormE, .XNaNE, .YNaNE, .ZNaNE, .XSNaNE, .YSNaNE, .ZSNaNE,
|
|
.XDenormE, .YDenormE, .ZDenormE, .XZeroE, .YZeroE, .ZZeroE, .XInfE, .YInfE, .ZInfE,
|
|
.XExpMaxE);
|
|
fma1 fma1(.XSgnE, .YSgnE, .ZSgnE, .XExpE, .YExpE, .ZExpE, .XManE, .YManE, .ZManE,
|
|
.XDenormE, .YDenormE, .ZDenormE, .XZeroE, .YZeroE, .ZZeroE,
|
|
.FOpCtrlE, .FmtE, .SumE, .NegSumE, .InvZE, .NormCntE, .ZSgnEffE, .PSgnE,
|
|
.ProdExpE, .AddendStickyE, .KillProdE);
|
|
fma2 fma2(.XSgnM(XSgnE), .YSgnM(YSgnE), .XExpM(XExpE), .YExpM(YExpE), .ZExpM(ZExpE), .XManM(XManE), .YManM(YManE), .ZManM(ZManE),
|
|
.XNaNM(XNaNE), .YNaNM(YNaNE), .ZNaNM(ZNaNE), .XZeroM(XZeroE), .YZeroM(YZeroE), .ZZeroM(ZZeroE), .XInfM(XInfE), .YInfM(YInfE), .ZInfM(ZInfE),
|
|
.XSNaNM(XSNaNE), .YSNaNM(YSNaNE), .ZSNaNM(ZSNaNE), .KillProdM(KillProdE), .AddendStickyM(AddendStickyE), .ProdExpM(ProdExpE),
|
|
.SumM(SumE), .NegSumM(NegSumE), .InvZM(InvZE), .NormCntM(NormCntE), .ZSgnEffM(ZSgnEffE), .PSgnM(PSgnE), .FmtM(FmtE), .FrmM(FrmE),
|
|
.FMAFlgM, .FMAResM, .Mult);
|
|
|
|
|
|
// produce clock
|
|
always begin
|
|
clk = 1; #5; clk = 0; #5;
|
|
end
|
|
|
|
// Read first test
|
|
initial begin
|
|
$display("\n\nRunning %s vectors", tests[i]);
|
|
$readmemh({`PATH, tests[i]}, testvectors);
|
|
end
|
|
|
|
// apply test vectors on rising edge of clk
|
|
always @(posedge clk) begin
|
|
#1;
|
|
flags = testvectors[vectornum][15:8];
|
|
FrmRead = testvectors[vectornum][7:4];
|
|
FmtRead = testvectors[vectornum][3:0];
|
|
if (FmtRead==4'b11 & `Q_SUPPORTED) begin // quad
|
|
X = testvectors[vectornum][16+4*(`Q_LEN)-1:16+3*(`Q_LEN)];
|
|
Y = testvectors[vectornum][16+3*(`Q_LEN)-1:16+2*(`Q_LEN)];
|
|
Z = testvectors[vectornum][16+2*(`Q_LEN)-1:16+`Q_LEN];
|
|
ans = testvectors[vectornum][16+(`Q_LEN-1):16];
|
|
end
|
|
else if (FmtRead==4'b01 & `D_SUPPORTED) begin // double
|
|
X = {{`FLEN-`D_LEN{1'b1}}, testvectors[vectornum][16+4*(`D_LEN)-1:16+3*(`D_LEN)]};
|
|
Y = {{`FLEN-`D_LEN{1'b1}}, testvectors[vectornum][16+3*(`D_LEN)-1:16+2*(`D_LEN)]};
|
|
Z = {{`FLEN-`D_LEN{1'b1}}, testvectors[vectornum][16+2*(`D_LEN)-1:16+`D_LEN]};
|
|
ans = {{`FLEN-`D_LEN{1'b1}}, testvectors[vectornum][16+(`D_LEN-1):16]};
|
|
end
|
|
else if (FmtRead==4'b00 & `F_SUPPORTED) begin // single
|
|
X = {{`FLEN-`S_LEN{1'b1}}, testvectors[vectornum][16+4*(`S_LEN)-1:16+3*(`S_LEN)]};
|
|
Y = {{`FLEN-`S_LEN{1'b1}}, testvectors[vectornum][16+3*(`S_LEN)-1:16+2*(`S_LEN)]};
|
|
Z = {{`FLEN-`S_LEN{1'b1}}, testvectors[vectornum][16+2*(`S_LEN)-1:16+`S_LEN]};
|
|
ans = {{`FLEN-`S_LEN{1'b1}}, testvectors[vectornum][16+(`S_LEN-1):16]};
|
|
end
|
|
else if (FmtRead==4'b10 & `ZFH_SUPPORTED) begin // half
|
|
X = {{`FLEN-`H_LEN{1'b1}}, testvectors[vectornum][16+4*(`H_LEN)-1:16+3*(`H_LEN)]};
|
|
Y = {{`FLEN-`H_LEN{1'b1}}, testvectors[vectornum][16+3*(`H_LEN)-1:16+2*(`H_LEN)]};
|
|
Z = {{`FLEN-`H_LEN{1'b1}}, testvectors[vectornum][16+2*(`H_LEN)-1:16+`H_LEN]};
|
|
ans = {{`FLEN-`H_LEN{1'b1}}, testvectors[vectornum][16+(`H_LEN-1):16]};
|
|
end
|
|
else begin
|
|
X = {`FLEN{1'bx}};
|
|
Y = {`FLEN{1'bx}};
|
|
Z = {`FLEN{1'bx}};
|
|
ans = {`FLEN{1'bx}};
|
|
end
|
|
|
|
// trim format and rounding mode to appropriate size
|
|
if (`FPSIZES <= 2) FmtE = FmtRead === `FMT; // rewrite format if 2 or less floating formats are supported
|
|
else FmtE = FmtRead[1:0];
|
|
FrmE = FrmRead[2:0];
|
|
end
|
|
|
|
// check results on falling edge of clk
|
|
always @(negedge clk) begin
|
|
// quad
|
|
if((FmtRead==4'b11) & ~((FMAFlgM === flags[4:0]) | (FMAResM === ans) | (wnan & (FMAResM[`FLEN-2:0] === ans[`FLEN-2:0] | (XNaNE&(FMAResM[`FLEN-2:0] === {X[`FLEN-2:`NF],1'b1,X[`NF-2:0]})) | (YNaNE&(FMAResM[`FLEN-2:0] === {Y[`FLEN-2:`NF],1'b1,Y[`NF-2:0]})) | (ZNaNE&(FMAResM[`FLEN-2:0] === {Z[`FLEN-2:`NF],1'b1,Z[`NF-2:0]})))))) begin
|
|
$display( "%h %h %h %h %h %h %h Wrong ",X,Y, Z, FMAResM, ans, FMAFlgM, flags);
|
|
if(XDenormE) $display( "xdenorm ");
|
|
if(YDenormE) $display( "ydenorm ");
|
|
if(ZDenormE) $display( "zdenorm ");
|
|
if(FMAFlgM[4] !== 0) $display( "invld ");
|
|
if(FMAFlgM[2] !== 0) $display( "ovrflw ");
|
|
if(FMAFlgM[1] !== 0) $display( "unflw ");
|
|
if(FMAResM[`FLEN] && FMAResM[`FLEN-2:`NF] === {`NE{1'b1}} && FMAResM[`NF-1:0] === 0) $display( "FMAResM=-inf ");
|
|
if(~FMAResM[`FLEN] && FMAResM[`FLEN-2:`NF] === {`NE{1'b1}} && FMAResM[`NF-1:0] === 0) $display( "FMAResM=+inf ");
|
|
if(FMAResM[`FLEN-2:`NF] === {`NE{1'b1}} && FMAResM[`NF-1:0] !== 0 && ~FMAResM[`NF-1]) $display( "FMAResM=sigNaN ");
|
|
if(FMAResM[`FLEN-2:`NF] === {`NE{1'b1}} && FMAResM[`NF-1:0] !== 0 && FMAResM[`NF-1]) $display( "FMAResM=qutNaN ");
|
|
if(ans[`FLEN] && ans[`FLEN-2:`NF] === {`NE{1'b1}} && ans[`NF-1:0] === 0) $display( "ans=-inf ");
|
|
if(~ans[`FLEN] && ans[`FLEN-2:`NF] === {`NE{1'b1}} && ans[`NF-1:0] === 0) $display( "ans=+inf ");
|
|
if(ans[`FLEN-2:`NF] === {`NE{1'b1}} && ans[`NF-1:0] !== 0 && ~ans[`NF-1]) $display( "ans=sigNaN ");
|
|
if(ans[`FLEN-2:`NF] === {`NE{1'b1}} && ans[`NF-1:0] !== 0 && ans[`NF-1]) $display( "ans=qutNaN ");
|
|
errors = errors + 1;
|
|
if (errors === 1) $stop;
|
|
end
|
|
// double
|
|
if((FmtRead==4'b01) & ~((FMAFlgM === flags[4:0]) | (FMAResM === ans) | (wnan & (FMAResM[`D_LEN-2:0] === ans[`D_LEN-2:0] | (XNaNE&(FMAResM[`D_LEN-2:0] === {X[`D_LEN-2:`D_NF],1'b1,X[`D_NF-2:0]})) | (YNaNE&(FMAResM[`D_LEN-2:0] === {Y[`D_LEN-2:`D_NF],1'b1,Y[`D_NF-2:0]})) | (ZNaNE&(FMAResM[`D_LEN-2:0] === {Z[`D_LEN-2:`D_NF],1'b1,Z[`D_NF-2:0]})))))) begin
|
|
$display( "%h %h %h %h %h %h %h Wrong ",X,Y, Z, FMAResM, ans, FMAFlgM, flags);
|
|
if(~(|X[30:23]) && |X[22:0]) $display( "xdenorm ");
|
|
if(~(|Y[30:23]) && |Y[22:0]) $display( "ydenorm ");
|
|
if(~(|Z[30:23]) && |Z[22:0]) $display( "zdenorm ");
|
|
if(FMAFlgM[4] !== 0) $display( "invld ");
|
|
if(FMAFlgM[2] !== 0) $display( "ovrflw ");
|
|
if(FMAFlgM[1] !== 0) $display( "unflw ");
|
|
if(&FMAResM[30:23] && |FMAResM[22:0] && ~FMAResM[22]) $display( "FMAResM=sigNaN ");
|
|
if(&FMAResM[30:23] && |FMAResM[22:0] && FMAResM[22] ) $display( "FMAResM=qutNaN ");
|
|
if(&ans[30:23] && |ans[22:0] && ~ans[22] ) $display( "ans=sigNaN ");
|
|
if(&ans[30:23] && |ans[22:0] && ans[22]) $display( "ans=qutNaN ");
|
|
errors = errors + 1;
|
|
if (errors === 1) $stop;
|
|
end
|
|
// single
|
|
if((FmtRead==4'b00) & ~((FMAFlgM === flags[4:0]) | (FMAResM === ans) | (wnan & (FMAResM[`S_LEN-2:0] === ans[`S_LEN-2:0] | (XNaNE&(FMAResM[`S_LEN-2:0] === {X[`S_LEN-2:`S_NF],1'b1,X[`S_NF-2:0]})) | (YNaNE&(FMAResM[`S_LEN-2:0] === {Y[`S_LEN-2:`S_NF],1'b1,Y[`S_NF-2:0]})) | (ZNaNE&(FMAResM[`S_LEN-2:0] === {Z[`S_LEN-2:`S_NF],1'b1,Z[`S_NF-2:0]})))))) begin
|
|
$display( "%h %h %h %h %h %h %h Wrong ",X,Y, Z, FMAResM, ans, FMAFlgM, flags);
|
|
if(~(|X[30:23]) && |X[22:0]) $display( "xdenorm ");
|
|
if(~(|Y[30:23]) && |Y[22:0]) $display( "ydenorm ");
|
|
if(~(|Z[30:23]) && |Z[22:0]) $display( "zdenorm ");
|
|
if(FMAFlgM[4] !== 0) $display( "invld ");
|
|
if(FMAFlgM[2] !== 0) $display( "ovrflw ");
|
|
if(FMAFlgM[1] !== 0) $display( "unflw ");
|
|
if(&FMAResM[30:23] && |FMAResM[22:0] && ~FMAResM[22]) $display( "FMAResM=sigNaN ");
|
|
if(&FMAResM[30:23] && |FMAResM[22:0] && FMAResM[22] ) $display( "FMAResM=qutNaN ");
|
|
if(&ans[30:23] && |ans[22:0] && ~ans[22] ) $display( "ans=sigNaN ");
|
|
if(&ans[30:23] && |ans[22:0] && ans[22]) $display( "ans=qutNaN ");
|
|
errors = errors + 1;
|
|
if (errors === 1) $stop;
|
|
end
|
|
// half
|
|
if((FmtRead==4'b01) & ~((FMAFlgM === flags[4:0]) | (FMAResM === ans) | (wnan & (FMAResM[`H_LEN-2:0] === ans[`H_LEN-2:0] | (XNaNE&(FMAResM[`H_LEN-2:0] === {X[`H_LEN-2:`H_NF],1'b1,X[`H_NF-2:0]})) | (YNaNE&(FMAResM[`H_LEN-2:0] === {Y[`H_LEN-2:`H_NF],1'b1,Y[`H_NF-2:0]})) | (ZNaNE&(FMAResM[`H_LEN-2:0] === {Z[`H_LEN-2:`H_NF],1'b1,Z[`H_NF-2:0]})))))) begin
|
|
$display( "%h %h %h %h %h %h %h Wrong ",X,Y, Z, FMAResM, ans, FMAFlgM, flags);
|
|
if(~(|X[30:23]) && |X[22:0]) $display( "xdenorm ");
|
|
if(~(|Y[30:23]) && |Y[22:0]) $display( "ydenorm ");
|
|
if(~(|Z[30:23]) && |Z[22:0]) $display( "zdenorm ");
|
|
if(FMAFlgM[4] !== 0) $display( "invld ");
|
|
if(FMAFlgM[2] !== 0) $display( "ovrflw ");
|
|
if(FMAFlgM[1] !== 0) $display( "unflw ");
|
|
if(&FMAResM[30:23] && |FMAResM[22:0] && ~FMAResM[22]) $display( "FMAResM=sigNaN ");
|
|
if(&FMAResM[30:23] && |FMAResM[22:0] && FMAResM[22] ) $display( "FMAResM=qutNaN ");
|
|
if(&ans[30:23] && |ans[22:0] && ~ans[22] ) $display( "ans=sigNaN ");
|
|
if(&ans[30:23] && |ans[22:0] && ans[22]) $display( "ans=qutNaN ");
|
|
errors = errors + 1;
|
|
if (errors === 1) $stop;
|
|
end
|
|
|
|
// if ( vectornum === 3165862) $stop; // uncomment for specific test
|
|
vectornum = vectornum + 1; // increment test
|
|
if (testvectors[vectornum][0] === 1'bx) begin // if reached the end of file
|
|
if (errors) begin // if there were errors
|
|
$display("%s completed with %d tests and %d errors", tests[i], vectornum, errors);
|
|
$stop;
|
|
end
|
|
else begin // if no errors
|
|
if(tests[i] === "") begin // if no more tests
|
|
$display("\nAll tests completed with %d errors\n", errors);
|
|
$stop;
|
|
end
|
|
|
|
$display("%s completed successfully with %d tests and %d errors (across all tests)\n", tests[i], vectornum, errors);
|
|
|
|
// increment tests - skip some precisions if needed
|
|
if ((i === 4 & ~`F_SUPPORTED) | (i === 9 & ~`D_SUPPORTED) | (i === 14 & ~`Q_SUPPORTED)) i = i+5;
|
|
if ((i === 9 & ~`D_SUPPORTED) | (i === 14 & ~`Q_SUPPORTED)) i = i+5;
|
|
if ((i === 14 & ~`Q_SUPPORTED)) i = i+5;
|
|
i = i+1;
|
|
|
|
// if no more tests - finish
|
|
if(tests[i] === "") begin
|
|
$display("\nAll tests completed with %d errors\n", errors);
|
|
$stop;
|
|
end
|
|
|
|
// read next files
|
|
$display("Running %s vectors", tests[i]);
|
|
$readmemh({`PATH, tests[i]}, testvectors);
|
|
vectornum = 0;
|
|
end
|
|
end
|
|
end
|
|
endmodule
|