|
@@ -156,69 +156,156 @@ module floating_product #(parameter N=16, M=4)(input_1, input_2, product, clk, r
|
|
|
input logic [N-1:0] input_1, input_2;
|
|
input logic [N-1:0] input_1, input_2;
|
|
|
input logic clk, reset;
|
|
input logic clk, reset;
|
|
|
output logic [N-1:0] product;
|
|
output logic [N-1:0] product;
|
|
|
-
|
|
|
|
|
|
|
+
|
|
|
|
|
+ logic [2*N-1:0] D0 [7:0];
|
|
|
|
|
+ logic [2*N-1:0] Q0 [7:0];
|
|
|
|
|
+ logic [2*N-1:0] Q1 [7:0];
|
|
|
|
|
+ logic [2*N-1:0] Q2 [7:0];
|
|
|
|
|
+
|
|
|
|
|
+ always_comb
|
|
|
|
|
+ begin
|
|
|
|
|
+ D0[0][N-1:0] = input_1;
|
|
|
|
|
+ D0[1][N-1:0] = input_2;
|
|
|
|
|
+ D0[2] = 0; // product (output)
|
|
|
|
|
+ D0[3] = 0; // multiple for multiplying the mantissa
|
|
|
|
|
+ D0[4] = 0; // flag for return NaN
|
|
|
|
|
+ D0[5] = 0; // flag for return infinity
|
|
|
|
|
+ D0[6] = 0; // flag for return zero
|
|
|
|
|
+ D0[7][N-3-M:0] = input_1[N-3-M:0]; // for storing the mantissa of input 1
|
|
|
|
|
+ end
|
|
|
// sign_x = x[N-1]
|
|
// sign_x = x[N-1]
|
|
|
// exponent_x = x[N-2:N-2-M]
|
|
// exponent_x = x[N-2:N-2-M]
|
|
|
// mantissa_x = x[N-3-M:0]
|
|
// mantissa_x = x[N-3-M:0]
|
|
|
-
|
|
|
|
|
- logic [N-2:N-2-M] sum;
|
|
|
|
|
- logic [2*(N-3-M):0] mult;
|
|
|
|
|
- logic [2*(N-3-M):0] D0 [4:0];
|
|
|
|
|
- logic [2*(N-3-M):0] Q0 [4:0];
|
|
|
|
|
- logic [2*(N-3-M):0] Q1 [4:0];
|
|
|
|
|
- logic [2*(N-3-M):0] Q2 [4:0];
|
|
|
|
|
|
|
|
|
|
- // First pipeline stage
|
|
|
|
|
|
|
+ pipe #(.N(2*N-1), .K(7)) pipe0(.clk(clk), .reset(reset), .D(D0), .Q(Q0));
|
|
|
|
|
+
|
|
|
always_comb
|
|
always_comb
|
|
|
|
|
+ begin
|
|
|
|
|
+ // if input_1 or input_2 is NaN then return NaN
|
|
|
|
|
+ if ((Q0[0][N-2:N-2-M] == (1<<M) && Q0[0][N-3-M:0] != 0) || (Q1[0][N-2:N-2-M] == (1<<M) && Q1[0][N-3-M:0] != 0))
|
|
|
begin
|
|
begin
|
|
|
- D0[0] = input_1;
|
|
|
|
|
- D0[1] = input_2;
|
|
|
|
|
- D0[2] = 0; // product
|
|
|
|
|
- D0[3] = 0; // sum
|
|
|
|
|
- D0[4] = 0; // mult
|
|
|
|
|
|
|
+ Q0[2][N-1] = 1;
|
|
|
|
|
+ Q0[2][N-2:N-2-M] = (1 << (M+1)) - 1;
|
|
|
|
|
+ Q0[2][N-3-M] = 1;
|
|
|
|
|
+ Q0[2][N-4-M:0] = 0;
|
|
|
|
|
+ Q0[4][0] = 1;
|
|
|
end
|
|
end
|
|
|
-
|
|
|
|
|
- pipe#(.N(2*(N-3-M)), .K(4)) pipe0(.clk(clk), .reset(reset), .D(D0), .Q(Q0));
|
|
|
|
|
-
|
|
|
|
|
- // We have assigned an {M+1} bit exponent so we must have a 2^{M} offset
|
|
|
|
|
- assign Q0[3] = Q0[0][N-2:N-2-M] + Q0[1][N-2:N-2-M];
|
|
|
|
|
- assign Q0[2][N-2:N-2-M] = Q0[3] - (1'b1 << M) + 2;
|
|
|
|
|
|
|
+ // if input 1 is infinity then return infinity
|
|
|
|
|
+ else if (Q0[0][N-2:N-2-M] == (1<<M))
|
|
|
|
|
+ begin
|
|
|
|
|
+ Q0[2][N-1] = Q0[0][N-1] ^ Q0[1][N-1];
|
|
|
|
|
+ Q0[2][N-2:N-2-M] = (1 << (M+1)) - 1;
|
|
|
|
|
+ Q0[2][N-3-M:0] = 0;
|
|
|
|
|
+ Q0[5] = 1;
|
|
|
|
|
+ // if input 2 is zero then return NaN
|
|
|
|
|
+ if (($signed(Q0[1][N-2:N-2-M]) == (-1*((1<<M)-1))) && (Q0[1][N-3-M:0] == 0))
|
|
|
|
|
+ begin
|
|
|
|
|
+ Q0[2][N-1] = 1;
|
|
|
|
|
+ Q0[2][N-2:N-2-M] = (1 << (M+1)) - 1;
|
|
|
|
|
+ Q0[2][N-3-M] = 1;
|
|
|
|
|
+ Q0[2][N-4-M:0] = 0;
|
|
|
|
|
+ Q0[4][0] = 1;
|
|
|
|
|
+ end
|
|
|
|
|
+ end
|
|
|
|
|
+ // if input 2 is infinity then return infinity
|
|
|
|
|
+ else if (Q0[1][N-2:N-2-M] == (1<<M))
|
|
|
|
|
+ begin
|
|
|
|
|
+ Q0[2][N-1] = Q0[0][N-1] ^ Q0[1][N-1];
|
|
|
|
|
+ Q0[2][N-2:N-2-M] = (1 << (M+1)) - 1;
|
|
|
|
|
+ Q0[2][N-3-M:0] = 0;
|
|
|
|
|
+ Q0[5][0] = 1;
|
|
|
|
|
+ // if input 1 is zero then return NaN
|
|
|
|
|
+ if (($signed(Q0[0][N-2:N-2-M]) == (-1*((1<<M)-1))) && (Q0[0][N-3-M:0] == 0))
|
|
|
|
|
+ begin
|
|
|
|
|
+ Q0[2][N-1] = 1;
|
|
|
|
|
+ Q0[2][N-2:N-2-M] = (1 << (M+1)) - 1;
|
|
|
|
|
+ Q0[2][N-3-M] = 1;
|
|
|
|
|
+ Q0[2][N-4-M:0] = 0;
|
|
|
|
|
+ Q0[4][0] = 1;
|
|
|
|
|
+ end
|
|
|
|
|
+ end
|
|
|
|
|
+ // if input 1 is zero then return zero
|
|
|
|
|
+ else if (($signed(Q0[0][N-2:N-2-M]) == (-1*((1<<M)-1))) && (Q0[0][N-3-M:0] == 0))
|
|
|
|
|
+ begin
|
|
|
|
|
+ Q0[2][N-1] = Q0[0][N-1] ^ Q0[1][N-1];
|
|
|
|
|
+ Q0[2][N-2:N-2-M] = 0;
|
|
|
|
|
+ Q0[2][N-3-M:0] = 0;
|
|
|
|
|
+ Q0[6][0] = 1;
|
|
|
|
|
+ end
|
|
|
|
|
+ // if input 2 is zero then return zero
|
|
|
|
|
+ else if (($signed(Q0[1][N-2:N-2-M]) == (-1*((1<<M)-1))) && (Q0[1][N-3-M:0] == 0))
|
|
|
|
|
+ begin
|
|
|
|
|
+ Q0[2][N-1] = Q0[0][N-1] ^ Q0[1][N-1];
|
|
|
|
|
+ Q0[2][N-2:N-2-M] = 0;
|
|
|
|
|
+ Q0[2][N-3-M:0] = 0;
|
|
|
|
|
+ Q0[6][0] = 1;
|
|
|
|
|
+ end
|
|
|
|
|
+ end
|
|
|
|
|
+
|
|
|
|
|
+ pipe #(.N(2*N-1), .K(7)) pipe1(.clk(clk), .reset(reset), .D(Q0), .Q(Q1));
|
|
|
|
|
|
|
|
- // Second pipeline stage
|
|
|
|
|
- pipe#(.N(2*(N-3-M)), .K(4)) pipe1(.clk(clk), .reset(reset), .D(Q0), .Q(Q1));
|
|
|
|
|
-
|
|
|
|
|
always_comb
|
|
always_comb
|
|
|
|
|
+ begin
|
|
|
|
|
+ // If none of the return flags have been triggered
|
|
|
|
|
+ if ((Q1[4][0] && Q1[5][0] && Q1[6][0]) != 1)
|
|
|
begin
|
|
begin
|
|
|
- // Setting the mantissa of the output
|
|
|
|
|
- Q1[4] = Q1[0][N-3-M:0] * Q1[1][N-3-M:0];
|
|
|
|
|
- if (Q1[4][N-3-M]) Q1[2][N-3-M:0] = Q1[4][2*(N-3-M):2*(N-3-M)-9];
|
|
|
|
|
- else Q1[2][N-3-M:0] = Q1[4][2*(N-3-M):2*(N-3-M)-9] << 1;
|
|
|
|
|
- Q1[2][N-1] = Q1[0][N-1] ^ Q1[1][N-1];
|
|
|
|
|
|
|
+ // if msb of input 1 mantissa is not 1 then shift left by 1 and reduce exponent by 1
|
|
|
|
|
+ if (Q1[0][N-3-M] != 1)
|
|
|
|
|
+ begin
|
|
|
|
|
+ Q1[0][N-3-M:0] = Q1[0][N-3-M:0] << 1;
|
|
|
|
|
+ Q1[0][N-2:N-2-M] = Q1[0][N-2:N-2-M] - 1;
|
|
|
|
|
+ end
|
|
|
|
|
+ // if msb of input 2 mantissa is not 1 then shift left by 1 and reduce exponent by 1
|
|
|
|
|
+ if (Q1[1][N-3-M] != 1)
|
|
|
|
|
+ begin
|
|
|
|
|
+ Q1[1][N-3-M:0] = Q1[1][N-3-M:0] << 1;
|
|
|
|
|
+ Q1[1][N-2:N-2-M] = Q1[1][N-2:N-2-M] - 1;
|
|
|
|
|
+ end
|
|
|
|
|
+ Q1[2][N-1] = Q1[2][N-1] ^ Q1[2][N-1]; // ouput sign = input_1 sign xor input_2 sign
|
|
|
|
|
+ Q1[2][N-2:N-2-M] = Q1[0][N-2:N-2-M] + Q1[1][N-2:N-2-M] - (1<<M); // out exp = in1 exp + in2 exp - 2**M
|
|
|
|
|
+ // multiplying mantissa
|
|
|
|
|
+ for (int i = 0; i<N-2-M; i++)
|
|
|
|
|
+ begin
|
|
|
|
|
+ // multiplying each digit of input 2 by all of input 1 shifting the bits left each time and adding result to the array
|
|
|
|
|
+ if (Q1[1][i] == 1)
|
|
|
|
|
+ begin
|
|
|
|
|
+ Q1[3] = Q1[3] +(Q1[7]<<i);
|
|
|
|
|
+ end
|
|
|
|
|
+ else
|
|
|
|
|
+ begin
|
|
|
|
|
+ Q1[3] = Q1[3] + 0;
|
|
|
|
|
+ end
|
|
|
|
|
+ end
|
|
|
|
|
+ // Assigning the top set of bits to the mantissa of the output
|
|
|
|
|
+ Q1[2][N-3-M:0] = Q1[3][2*N-1:2*N-1-N-3-M];
|
|
|
end
|
|
end
|
|
|
|
|
+ end
|
|
|
|
|
|
|
|
- //Final Pipeline stage
|
|
|
|
|
- pipe#(.N(2*N-3-M), .K(4)) pipe2(.clk(clk), .reset(reset), .D(Q1), .Q(Q2));
|
|
|
|
|
|
|
+ pipe #(.N(2*N-1), .K(7)) pipe2(.clk(clk), .reset(reset), .D(Q1), .Q(Q2));
|
|
|
assign product = Q2[2][N-1:0];
|
|
assign product = Q2[2][N-1:0];
|
|
|
|
|
+
|
|
|
endmodule : floating_product
|
|
endmodule : floating_product
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
-module pipe #(parameter N=16)(clk, reset, Q, D);
|
|
|
|
|
|
|
+module pipe #(parameter N, K)(clk, reset, Q, D);
|
|
|
input logic clk, reset;
|
|
input logic clk, reset;
|
|
|
- input logic [N-1:0] D;
|
|
|
|
|
- output reg [N-1:0] Q;
|
|
|
|
|
- reg [N-1:0] in_pipe;
|
|
|
|
|
-
|
|
|
|
|
- always @(posedge clk or negedge reset)
|
|
|
|
|
- begin
|
|
|
|
|
- if(reset) in_pipe = 0;
|
|
|
|
|
- else in_pipe = D;
|
|
|
|
|
- end
|
|
|
|
|
|
|
+ input logic [N:0] D [K:0];
|
|
|
|
|
+ output reg [N:0] Q [K:0];
|
|
|
|
|
+ reg [N:0] in_pipe [K:0];
|
|
|
|
|
|
|
|
- always @(posedge clk or negedge reset)
|
|
|
|
|
|
|
+ always_ff @(posedge clk or negedge reset)
|
|
|
begin
|
|
begin
|
|
|
- if(reset) Q = 0;
|
|
|
|
|
- else Q = in_pipe;
|
|
|
|
|
|
|
+ if(reset)
|
|
|
|
|
+ begin
|
|
|
|
|
+ in_pipe <= '{default:0};
|
|
|
|
|
+ Q <= '{default:0};
|
|
|
|
|
+ end
|
|
|
|
|
+ else
|
|
|
|
|
+ begin
|
|
|
|
|
+ in_pipe <= D;
|
|
|
|
|
+ Q <= in_pipe;
|
|
|
|
|
+ end
|
|
|
end
|
|
end
|
|
|
endmodule : pipe
|
|
endmodule : pipe
|
|
|
|
|
|
|
@@ -228,22 +315,37 @@ module floating_tb;
|
|
|
reg reset, clk;
|
|
reg reset, clk;
|
|
|
logic [15:0] input_a, input_b, result_add, result_mult;
|
|
logic [15:0] input_a, input_b, result_add, result_mult;
|
|
|
logic [4:0] diff;
|
|
logic [4:0] diff;
|
|
|
|
|
+ logic [15:0] expected_add, expected_mult;
|
|
|
|
|
|
|
|
- floating_add adder1(.input_1(input_a), .input_2(input_b), .sum(result_add), .diff(diff));
|
|
|
|
|
-
|
|
|
|
|
- floating_product multiplier1(.input_1(input_a), .input_2(input_b), .product(result_mult));
|
|
|
|
|
|
|
+ floating_add adder1(.input_1(input_a), .input_2(input_b), .sum(result_add), .diff(diff), .clk(clk), .reset(reset));
|
|
|
|
|
|
|
|
|
|
+ floating_product multiplier1(.input_1(input_a), .input_2(input_b), .product(result_mult), .clk(clk), .reset(reset));
|
|
|
|
|
+
|
|
|
|
|
+ initial forever #5 clk = ~clk;
|
|
|
|
|
+ localparam PIPELINES = 3;
|
|
|
|
|
|
|
|
reg [15:0] test_mem [29:0][3:0];
|
|
reg [15:0] test_mem [29:0][3:0];
|
|
|
|
|
|
|
|
- initial $readmemh("../../scripts/fp16_test.hex", test_mem);
|
|
|
|
|
-
|
|
|
|
|
|
|
+ initial $readmemh("scripts/fp16_test.hex", test_mem);
|
|
|
|
|
|
|
|
initial begin
|
|
initial begin
|
|
|
static int num_err = 0;
|
|
static int num_err = 0;
|
|
|
static int num_tests = $size(test_mem) * 2;
|
|
static int num_tests = $size(test_mem) * 2;
|
|
|
|
|
|
|
|
- for (int i=0; i < $size(test_mem); i++) begin
|
|
|
|
|
|
|
+ clk = 0;
|
|
|
|
|
+ reset = 1;
|
|
|
|
|
+
|
|
|
|
|
+ #15;
|
|
|
|
|
+ reset = 0;
|
|
|
|
|
+
|
|
|
|
|
+ expected_add = 0;
|
|
|
|
|
+ expected_mult = 0;
|
|
|
|
|
+
|
|
|
|
|
+ for (int i=0; i < $size(test_mem)+PIPELINES; i++) begin
|
|
|
|
|
+ if(i >= PIPELINES) begin
|
|
|
|
|
+ expected_add = test_mem[i-PIPELINES][2];
|
|
|
|
|
+ expected_mult = test_mem[i-PIPELINES][3];
|
|
|
|
|
+ end
|
|
|
input_a = test_mem[i][0];
|
|
input_a = test_mem[i][0];
|
|
|
input_b = test_mem[i][1];
|
|
input_b = test_mem[i][1];
|
|
|
|
|
|
|
@@ -260,7 +362,10 @@ module floating_tb;
|
|
|
num_err = num_err + 1;
|
|
num_err = num_err + 1;
|
|
|
end
|
|
end
|
|
|
|
|
|
|
|
- end
|
|
|
|
|
|
|
+ end
|
|
|
|
|
+ expected_add = 0;
|
|
|
|
|
+ expected_mult = 0;
|
|
|
|
|
+ #50;
|
|
|
$display("Passed %d of %d tests", num_tests-num_err, num_tests);
|
|
$display("Passed %d of %d tests", num_tests-num_err, num_tests);
|
|
|
$finish();
|
|
$finish();
|
|
|
end
|
|
end
|