HWDigSys-II/sim/multiplication.sv

155 lines
7.6 KiB
Systemverilog

//////
// Please consider this function a black box. DO NOT try to copy any part of this function in your code.
//////
function [31:0] multiplication (string round, logic [31:0] a, logic [31:0] b);
bit [31:0] result;
// Convert every denormal in zero
if(a[30:23] == '0) a[22:0] = '0;
if(b[30:23] == '0) b[22:0] = '0;
if(a[30:23] == '1) a[22:0] = '0;
if(b[30:23] == '1) b[22:0] = '0;
// If (a is inf or NaN) or (b is inf or NaN) => Result Inf
if((a[30:23] == '1 && b[30:23] == '0) || (a[30:23] == '0 && b[30:23] == '1)) result = {1'b0, {8{1'b1}}, {23{1'b0}}};
else begin
result = $shortrealtobits($bitstoshortreal(a) * $bitstoshortreal(b));
case (round)
//IEEE_NEAR ROUNDING
"IEEE_near": begin
if(result[30:23] == '1) result[22:0] = '0;
if(result[30:23] == '0) result[22:0] = '0;
end
//IEEE_ZERO ROUNDING
"IEEE_zero": begin
//Round towards zero instead if rounded up and positive
if($bitstoshortreal(result) > ($bitstoshortreal(a) * $bitstoshortreal(b)))
begin
if($bitstoshortreal(result) > 0)
begin
result = result - 1;
end
end
//Round towards zero instead if rounded down and negative
if($bitstoshortreal(result) < ($bitstoshortreal(a) * $bitstoshortreal(b)))
begin
if($bitstoshortreal(result) < 0)
begin
result = result - 1;
end
end
if(result[30:23] == '0) result[22:0] = '0;
end
//AWAY_ZERO ROUNDING
"away_zero": begin
//Check if the result is denormal and round to minNormal
if((result[30:23] == '0 && result[22:0] != '0) || (a[30:23] != '0 && b[30:23] != '0 && result[30:23] == '0 && result[22:0] == '0)) begin
result = {result[31], {7{1'b0}}, 1'b1, {23{1'b0}}};
end
else begin
//Round away from zero instead if rounded up and negative
if($bitstoshortreal(result) > ($bitstoshortreal(a) * $bitstoshortreal(b)))
begin
if($bitstoshortreal(result) < 0)
begin
result = result + 1;
end
end
//Round away from zero instead if rounded down and positive
if($bitstoshortreal(result) < ($bitstoshortreal(a) * $bitstoshortreal(b)))
begin
if($bitstoshortreal(result) > 0)
begin
result = result + 1;
end
end
end
if(result[30:23] == '1) result[22:0] = '0;
end
//IEEE_PINF ROUNDING
"IEEE_pinf": begin
//Check if the result is denormal and round to minNormal, but only for positives
if((result[31] == 0 && result[30:23] == '0 && result[22:0] != '0) || (result[31] == 0 && a[30:23] != '0 && b[30:23] != '0 && result[30:23] == '0 && result[22:0] == '0)) begin
result = {{8{1'b0}}, 1'b1, {23{1'b0}}};
end
else begin
//Round towards positive infinity instead if rounded down and positive
if($bitstoshortreal(result) < ($bitstoshortreal(a) * $bitstoshortreal(b)))
begin
if($bitstoshortreal(result) > 0)
begin
result = result + 1;
end
end
//Round towards positive infinity instead if rounded down and negative
if($bitstoshortreal(result) < ($bitstoshortreal(a) * $bitstoshortreal(b)))
begin
if($bitstoshortreal(result) < 0)
begin
result = result - 1;
end
end
end
if(result[30:23] == '0) result[22:0] = '0;
end
//IEEE_NINF ROUNDING
"IEEE_ninf": begin
//Check if the result is denormal and round to minNormal, but only for negatives
if((result[31] == 1 && result[30:23] == '0 && result[22:0] != '0) || (result[31] == 1 && a[30:23] != '0 && b[30:23] != '0 && result[30:23] == '0 && result[22:0] == '0)) begin
result = {1'b1, {7{1'b0}}, 1'b1, {23{1'b0}}};
end
else begin
//Round towards negative infinity instead if rounded up and positive
if($bitstoshortreal(result) > ($bitstoshortreal(a) * $bitstoshortreal(b)))
begin
if($bitstoshortreal(result) > 0)
begin
result = result - 1;
end
end
//Round towards negative infinity instead if rounded up and negative
if($bitstoshortreal(result) > ($bitstoshortreal(a) * $bitstoshortreal(b)))
begin
if($bitstoshortreal(result) < 0)
begin
result = result + 1;
end
end
end
if(result[30:23] == '0) result[22:0] = '0;
end
//NEAR_UP ROUNDING
"near_up": begin
//Round towards positive infinity if rounded down, negative and in the middle
if(($bitstoshortreal(result) < ($bitstoshortreal(a) * $bitstoshortreal(b))))
begin
if(($bitstoshortreal(result) - ($bitstoshortreal(a) * $bitstoshortreal(b))) == (($bitstoshortreal(a) * $bitstoshortreal(b)) - $bitstoshortreal(result-1)))
begin
if($bitstoshortreal(result) < 0)
begin
result = result - 1;
end
end
end
//Round towards positive infinity if rounded down, positive and in the middle
if(($bitstoshortreal(result) < ($bitstoshortreal(a) * $bitstoshortreal(b))))
begin
if(($bitstoshortreal(result+1) - ($bitstoshortreal(a) * $bitstoshortreal(b))) == (($bitstoshortreal(a) * $bitstoshortreal(b)) - $bitstoshortreal(result)))
begin
if($bitstoshortreal(result) > 0)
begin
result = result + 1;
end
end
end
if(result[30:23] == '1) result[22:0] = '0;
if(result[30:23] == '0) result[22:0] = '0;
end
endcase
end
return result;
endfunction