| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250 |
- `include "lead_zero.sv"
- module lead_zeros_enc #(K=10)(in, out);
- localparam L = $clog2(K) +1;
- input wire [K-1:0] in;
- output logic [L-1:0] out;
- always_comb begin
- if(K == 10) begin
- casez (in)
- 10'b00000_00000 :out = 4'd10;
- 10'b00000_0000? :out = 4'd9;
- 10'b00000_000?? :out = 4'd8;
- 10'b00000_00??? :out = 4'd7;
- 10'b00000_0???? :out = 4'd6;
- 10'b00000_????? :out = 4'd5;
- 10'b0000?_????? :out = 4'd4;
- 10'b000??_????? :out = 4'd3;
- 10'b00???_????? :out = 4'd2;
- 10'b0????_????? :out = 4'd1;
- default : out = 4'd0;
- endcase
- end
- else if (K == 23) begin
- casez (in)
- 23'b000_00000_00000_00000_00000 :out = 5'd23;
- 23'b000_00000_00000_00000_0000? :out = 5'd22;
- 23'b000_00000_00000_00000_000?? :out = 5'd21;
- 23'b000_00000_00000_00000_00??? :out = 5'd20;
- 23'b000_00000_00000_00000_0???? :out = 5'd19;
- 23'b000_00000_00000_00000_????? :out = 5'd18;
- 23'b000_00000_00000_0000?_????? :out = 5'd17;
- 23'b000_00000_00000_000??_????? :out = 5'd16;
- 23'b000_00000_00000_00???_????? :out = 5'd15;
- 23'b000_00000_00000_0????_????? :out = 5'd14;
- 23'b000_00000_00000_?????_????? :out = 5'd13;
- 23'b000_00000_0000?_?????_????? :out = 5'd12;
- 23'b000_00000_000??_?????_????? :out = 5'd11;
- 23'b000_00000_00???_?????_????? :out = 5'd10;
- 23'b000_00000_0????_?????_????? :out = 5'd9;
- 23'b000_00000_?????_?????_????? :out = 5'd8;
- 23'b000_0000?_?????_?????_????? :out = 5'd7;
- 23'b000_000??_?????_?????_????? :out = 5'd6;
- 23'b000_00???_?????_?????_????? :out = 5'd5;
- 23'b000_0????_?????_?????_????? :out = 5'd4;
- 23'b000_?????_?????_?????_????? :out = 5'd3;
- 23'b00?_?????_?????_?????_????? :out = 5'd2;
- 23'b0??_?????_?????_?????_????? :out = 5'd1;
- default : out = 5'd0;
- endcase
- end
- end
- endmodule : lead_zeros_enc
- module fp_mult #(parameter N=16, M=5)(input_a, input_b, output_z, clk, reset);
- localparam K=N-M-1; // Size of mantissa
- localparam L=$clog2(10); // Size of shifting representation
- input logic [N-1:0] input_a, input_b;
- input logic clk, reset;
- output logic [N-1:0] output_z;
- // ====================
- // Stage 0 store input
- // ====================
- reg [M-1:0] a_e0, b_e0;
- reg [K-1:0] a_m0, b_m0;
- reg a_s0, b_s0;
- always_ff @(posedge clk) begin
- {a_s0, a_e0, a_m0} <= input_a;
- {b_s0, b_e0, b_m0} <= input_b;
- end
- // ====================
- // Stage 1 denormalise0
- // ====================
- reg [M-1:0] a_e1, b_e1;
- reg [K-1:0] a_m1, b_m1;
- reg z_s1;
- // leading zeros
- wire [L-1:0] a_z1w, b_z1w;
- reg [L-1:0] a_z1, b_z1;
- lead_zeros_enc #(.K(K)) lz_a1(a_m1, a_z1w);
- lead_zeros_enc #(.K(K)) lz_b1(b_m1, b_z1w);
- always_ff @(posedge clk) begin
- z_s1 <= a_s0 ^ b_s0; // We don't need to track and propagate signs
- {a_e1, a_m1} <= {a_e0, a_m0};
- {b_e1, b_m1} <= {b_e0, b_m0};
- a_z1 <= a_z1w;
- b_z1 <= b_z1w;
- end
- // ====================
- // Stage 2 denormalise1
- // ====================
- reg [M-1:0] a_e2, b_e2;
- reg [K-1:0] a_m2, b_m2;
- reg z_s2;
- always_ff @(posedge clk) begin
- a_e2 <= a_e1 - a_z1;
- a_m2 <= a_m1 << a_z1;
- b_e2 <= b_e1 - b_z1;
- b_m2 <= b_m1 << b_z1;
- z_s2 <= z_s1;
- end
- // ====================
- // Stage 3 product
- // ====================
- reg z_s3;
- reg [M-1:0] z_e3;
- reg [K*2-1:0] z_p3; // product is double mantissa
- always_ff @(posedge clk) begin
- z_e3 <= a_e2 + b_e2 + 1;
- z_p3 <= a_m2 * b_m2;
- z_s3 <= z_s2;
- end
- // ====================
- // Stage 4 unpack/normalise0
- // ====================
- reg z_s4;
- reg [M-1:0] z_e4;
- reg [K-1:0] z_m4;
- reg [1:0] z_bits4; // guard and round_bit
- reg z_sticky4;
- wire [K-1:0] p3;
- // leading zeros
- wire [3:0] z_z4w;
- reg [3:0] z_z4;
- assign p3 = z_p3[K*2-1:K];
- lead_zeros_enc #(.K(K)) lz_p3(p3, z_z4w);
- always_ff @(posedge clk) begin
- z_m4 <= p3;
- z_bits4 <= z_p3[K:K-2];
- z_sticky4 <= z_p3[K-2:0] != 0;
- z_z4 <= z_z4w;
- z_e4 <= z_e3;
- z_s4 <= z_s3;
- end
- // ====================
- // Stage 5 normalise1
- // ====================
- reg z_s5;
- reg [M-1:0] z_e5;
- reg [K-1:0] z_m5;
- reg [1:0] z_bits5; // guard and round_bit
- reg z_sticky5;
- always_ff @(posedge clk) begin
- z_e5 <= z_e4 - z_z4;
- z_m5 <= z_m4 << z_z4;
- case (z_z4)
- 4'd0: begin
- z_bits5 <= z_bits4;
- end
- 4'd1: begin
- z_m5[0] <= z_bits4[0];
- z_bits5 <= {z_bits4[1], 1'b0};
- end
- 4'd2: begin
- z_m5[1-:2] <= z_bits4; // ?
- z_bits5 <= 2'b00;
- end
- default : begin
- z_m5[z_z4-1-:2] <= z_bits4; // ?
- z_bits5 <= 2'b00;
- end
- endcase
- z_sticky5 <= z_sticky4;
- z_s5 <= z_s4;
- end
- // ====================
- // Stage 6 normalise2
- // ====================
- reg z_s6;
- reg [M-1:0] z_e6;
- reg [K-1:0] z_m6;
- reg [1:0] z_bits6;
- reg z_sticky6;
- always_ff @(posedge clk) begin
- // TODO: Fix this stage
- // if ($signed(z_e5) < -126) begin
- // shift6 <= $signed(z_e5) -126;
- // end else begin
- // shift6 <= 0;
- // end
- z_s6 <= z_s5;
- z_e6 <= z_e5;
- z_m6 <= z_m5;
- z_bits6 <= z_bits5;
- z_sticky6 <= z_sticky5;
- end
- // ====================
- // Stage 7 round
- // ====================
- reg z_s7;
- reg [M-1:0] z_e7;
- reg [K-1:0] z_m7;
- always_ff @(posedge clk) begin
- if (z_bits6[0] && (z_bits6[1] | z_sticky6 | z_m6[0])) begin
- z_m7 <= z_m6 + 1;
- // TODO: Check for all 1s
- end else begin
- z_m7 <= z_m6;
- end
- z_e7 <= z_e6;
- z_s7 <= z_s6;
- end
- // ====================
- // Stage 8 pack
- // ====================
- // This stage is skipped as it checks for overflow
- always_comb output_z = {z_s7, z_e7, z_m7};
- endmodule : fp_mult
|