/// =================== Unsigned, Fixed Point ========================= module std_fp_add #( parameter WIDTH = 32, parameter INT_WIDTH = 16, parameter FRAC_WIDTH = 16 ) ( input logic [WIDTH-1:0] left, input logic [WIDTH-1:0] right, output logic [WIDTH-1:0] out ); assign out = left + right; endmodule module std_fp_sub #( parameter WIDTH = 32, parameter INT_WIDTH = 16, parameter FRAC_WIDTH = 16 ) ( input logic [WIDTH-1:0] left, input logic [WIDTH-1:0] right, output logic [WIDTH-1:0] out ); assign out = left - right; endmodule module std_fp_mult_pipe #( parameter WIDTH = 32, parameter INT_WIDTH = 16, parameter FRAC_WIDTH = 16 ) ( input logic [WIDTH-1:0] left, input logic [WIDTH-1:0] right, input logic go, input logic clk, output logic [WIDTH-1:0] out, output logic done ); logic [WIDTH-1:0] rtmp; logic [WIDTH-1:0] ltmp; logic [(WIDTH << 1) - 1:0] out_tmp; reg done_buf[1:0]; always_ff @(posedge clk) begin if (go) begin rtmp <= right; ltmp <= left; out_tmp <= ltmp * rtmp; out <= out_tmp[(WIDTH << 1) - INT_WIDTH - 1 : WIDTH - INT_WIDTH]; done <= done_buf[1]; done_buf[0] <= 1'b1; done_buf[1] <= done_buf[0]; end else begin rtmp <= 0; ltmp <= 0; out_tmp <= 0; out <= 0; done <= 0; done_buf[0] <= 0; done_buf[1] <= 0; end end endmodule /* verilator lint_off WIDTH */ module std_fp_div_pipe #( parameter WIDTH = 32, parameter INT_WIDTH = 16, parameter FRAC_WIDTH = 16 ) ( input logic go, input logic clk, input logic [WIDTH-1:0] left, input logic [WIDTH-1:0] right, output logic [WIDTH-1:0] out_remainder, output logic [WIDTH-1:0] out_quotient, output logic done ); localparam ITERATIONS = WIDTH + FRAC_WIDTH; logic [WIDTH-1:0] quotient, quotient_next; logic [WIDTH:0] acc, acc_next; logic [$clog2(ITERATIONS)-1:0] idx; logic start, running, finished; assign start = go && !running; assign finished = running && (idx == ITERATIONS - 1); always_comb begin if (acc >= {1'b0, right}) begin acc_next = acc - right; {acc_next, quotient_next} = {acc_next[WIDTH-1:0], quotient, 1'b1}; end else begin {acc_next, quotient_next} = {acc, quotient} << 1; end end always_ff @(posedge clk) begin if (!go) begin running <= 0; done <= 0; out_remainder <= 0; out_quotient <= 0; end else if (start && left == 0) begin out_remainder <= 0; out_quotient <= 0; done <= 1; end if (start) begin running <= 1; done <= 0; idx <= 0; {acc, quotient} <= {{WIDTH{1'b0}}, left, 1'b0}; out_quotient <= 0; out_remainder <= left; end else if (finished) begin running <= 0; done <= 1; out_quotient <= quotient_next; end else begin idx <= idx + 1; acc <= acc_next; quotient <= quotient_next; if (right <= out_remainder) begin out_remainder <= out_remainder - right; end end end endmodule module std_fp_gt #( parameter WIDTH = 32, parameter INT_WIDTH = 16, parameter FRAC_WIDTH = 16 ) ( input logic [WIDTH-1:0] left, input logic [WIDTH-1:0] right, output logic out ); assign out = left > right; endmodule module std_fp_add_dwidth #( parameter WIDTH1 = 32, parameter WIDTH2 = 32, parameter INT_WIDTH1 = 16, parameter FRAC_WIDTH1 = 16, parameter INT_WIDTH2 = 12, parameter FRAC_WIDTH2 = 20, parameter OUT_WIDTH = 36 ) ( input logic [ WIDTH1-1:0] left, input logic [ WIDTH2-1:0] right, output logic [OUT_WIDTH-1:0] out ); localparam BIG_INT = (INT_WIDTH1 >= INT_WIDTH2) ? INT_WIDTH1 : INT_WIDTH2; localparam BIG_FRACT = (FRAC_WIDTH1 >= FRAC_WIDTH2) ? FRAC_WIDTH1 : FRAC_WIDTH2; if (BIG_INT + BIG_FRACT != OUT_WIDTH) $error("std_fp_add_dwidth: Given output width not equal to computed output width"); logic [INT_WIDTH1-1:0] left_int; logic [INT_WIDTH2-1:0] right_int; logic [FRAC_WIDTH1-1:0] left_fract; logic [FRAC_WIDTH2-1:0] right_fract; logic [BIG_INT-1:0] mod_right_int; logic [BIG_FRACT-1:0] mod_left_fract; logic [BIG_INT-1:0] whole_int; logic [BIG_FRACT-1:0] whole_fract; assign {left_int, left_fract} = left; assign {right_int, right_fract} = right; assign mod_left_fract = left_fract * (2 ** (FRAC_WIDTH2 - FRAC_WIDTH1)); always_comb begin if ((mod_left_fract + right_fract) >= 2 ** FRAC_WIDTH2) begin whole_int = left_int + right_int + 1; whole_fract = mod_left_fract + right_fract - 2 ** FRAC_WIDTH2; end else begin whole_int = left_int + right_int; whole_fract = mod_left_fract + right_fract; end end assign out = {whole_int, whole_fract}; endmodule /// =================== Signed, Fixed Point ========================= module std_fp_sadd #( parameter WIDTH = 32, parameter INT_WIDTH = 16, parameter FRAC_WIDTH = 16 ) ( input signed [WIDTH-1:0] left, input signed [WIDTH-1:0] right, output signed [WIDTH-1:0] out ); assign out = $signed(left + right); endmodule module std_fp_ssub #( parameter WIDTH = 32, parameter INT_WIDTH = 16, parameter FRAC_WIDTH = 16 ) ( input signed [WIDTH-1:0] left, input signed [WIDTH-1:0] right, output signed [WIDTH-1:0] out ); assign out = $signed(left - right); endmodule module std_fp_smult_pipe #( parameter WIDTH = 32, parameter INT_WIDTH = 16, parameter FRAC_WIDTH = 16 ) ( input signed [WIDTH-1:0] left, input signed [WIDTH-1:0] right, input logic go, input logic clk, output logic signed [WIDTH-1:0] out, output logic done ); logic signed [WIDTH-1:0] ltmp; logic signed [WIDTH-1:0] rtmp; logic signed [(WIDTH << 1) - 1:0] out_tmp; reg done_buf[1:0]; always_ff @(posedge clk) begin if (go) begin ltmp <= left; rtmp <= right; // Sign extend by the first bit for the operands. out_tmp <= $signed( { {WIDTH{ltmp[WIDTH-1]}}, ltmp} * { {WIDTH{rtmp[WIDTH-1]}}, rtmp} ); out <= out_tmp[(WIDTH << 1) - INT_WIDTH - 1: WIDTH - INT_WIDTH]; done <= done_buf[1]; done_buf[0] <= 1'b1; done_buf[1] <= done_buf[0]; end else begin rtmp <= 0; ltmp <= 0; out_tmp <= 0; out <= 0; done <= 0; done_buf[0] <= 0; done_buf[1] <= 0; end end endmodule module std_fp_sdiv_pipe #( parameter WIDTH = 32, parameter INT_WIDTH = 16, parameter FRAC_WIDTH = 16 ) ( input clk, input go, input signed [WIDTH-1:0] left, input signed [WIDTH-1:0] right, output signed [WIDTH-1:0] out_quotient, output signed [WIDTH-1:0] out_remainder, output logic done ); logic signed [WIDTH-1:0] left_abs; logic signed [WIDTH-1:0] right_abs; logic signed [WIDTH-1:0] comp_out_q; logic signed [WIDTH-1:0] comp_out_r; assign right_abs = right[WIDTH-1] ? -right : right; assign left_abs = left[WIDTH-1] ? -left : left; assign out_quotient = left[WIDTH-1] ^ right[WIDTH-1] ? -comp_out_q : comp_out_q; assign out_remainder = (left[WIDTH-1] && comp_out_r) ? $signed(right - comp_out_r) : comp_out_r; std_fp_div_pipe #( .WIDTH(WIDTH), .INT_WIDTH(INT_WIDTH), .FRAC_WIDTH(FRAC_WIDTH) ) comp ( .clk(clk), .done(done), .go(go), .left(left_abs), .right(right_abs), .out_quotient(comp_out_q), .out_remainder(comp_out_r) ); endmodule module std_fp_sadd_dwidth #( parameter WIDTH1 = 32, parameter WIDTH2 = 32, parameter INT_WIDTH1 = 16, parameter FRAC_WIDTH1 = 16, parameter INT_WIDTH2 = 12, parameter FRAC_WIDTH2 = 20, parameter OUT_WIDTH = 36 ) ( input logic [ WIDTH1-1:0] left, input logic [ WIDTH2-1:0] right, output logic [OUT_WIDTH-1:0] out ); logic signed [INT_WIDTH1-1:0] left_int; logic signed [INT_WIDTH2-1:0] right_int; logic [FRAC_WIDTH1-1:0] left_fract; logic [FRAC_WIDTH2-1:0] right_fract; localparam BIG_INT = (INT_WIDTH1 >= INT_WIDTH2) ? INT_WIDTH1 : INT_WIDTH2; localparam BIG_FRACT = (FRAC_WIDTH1 >= FRAC_WIDTH2) ? FRAC_WIDTH1 : FRAC_WIDTH2; logic [BIG_INT-1:0] mod_right_int; logic [BIG_FRACT-1:0] mod_left_fract; logic [BIG_INT-1:0] whole_int; logic [BIG_FRACT-1:0] whole_fract; assign {left_int, left_fract} = left; assign {right_int, right_fract} = right; assign mod_left_fract = left_fract * (2 ** (FRAC_WIDTH2 - FRAC_WIDTH1)); always_comb begin if ((mod_left_fract + right_fract) >= 2 ** FRAC_WIDTH2) begin whole_int = $signed(left_int + right_int + 1); whole_fract = mod_left_fract + right_fract - 2 ** FRAC_WIDTH2; end else begin whole_int = $signed(left_int + right_int); whole_fract = mod_left_fract + right_fract; end end assign out = {whole_int, whole_fract}; endmodule module std_fp_sgt #( parameter WIDTH = 32, parameter INT_WIDTH = 16, parameter FRAC_WIDTH = 16 ) ( input logic signed [WIDTH-1:0] left, input logic signed [WIDTH-1:0] right, output logic signed out ); assign out = $signed(left > right); endmodule module std_fp_slt #( parameter WIDTH = 32, parameter INT_WIDTH = 16, parameter FRAC_WIDTH = 16 ) ( input logic signed [WIDTH-1:0] left, input logic signed [WIDTH-1:0] right, output logic signed out ); assign out = $signed(left < right); endmodule /// =================== Unsigned, Bitnum ========================= module std_mult_pipe #( parameter WIDTH = 32 ) ( input logic [WIDTH-1:0] left, input logic [WIDTH-1:0] right, input logic go, input logic clk, output logic [WIDTH-1:0] out, output logic done ); std_fp_mult_pipe #( .WIDTH(WIDTH), .INT_WIDTH(WIDTH), .FRAC_WIDTH(0) ) comp ( .clk(clk), .done(done), .go(go), .left(left), .right(right), .out(out) ); endmodule module std_div_pipe #( parameter WIDTH = 32 ) ( input clk, input go, input [WIDTH-1:0] left, input [WIDTH-1:0] right, output logic [WIDTH-1:0] out_remainder, output logic [WIDTH-1:0] out_quotient, output logic done ); logic [WIDTH-1:0] dividend; logic [(WIDTH-1)*2:0] divisor; logic [WIDTH-1:0] quotient; logic [WIDTH-1:0] quotient_msk; logic start, running, finished; assign start = go && !running; assign finished = !quotient_msk && running; always_ff @(posedge clk) begin if (!go) begin running <= 0; done <= 0; out_remainder <= 0; out_quotient <= 0; end else if (start && left == 0) begin out_remainder <= 0; out_quotient <= 0; done <= 1; end if (start) begin running <= 1; dividend <= left; divisor <= right << WIDTH - 1; quotient <= 0; quotient_msk <= 1 << WIDTH - 1; end else if (finished) begin running <= 0; done <= 1; out_remainder <= dividend; out_quotient <= quotient; end else begin if (divisor <= dividend) begin dividend <= dividend - divisor; quotient <= quotient | quotient_msk; end divisor <= divisor >> 1; quotient_msk <= quotient_msk >> 1; end end `ifdef VERILATOR // Simulation self test against unsynthesizable implementation. always @(posedge clk) begin if (finished && dividend != $unsigned(left % right)) $error( "\nstd_div_pipe (Remainder): Computed and golden outputs do not match!\n", "left: %0d", $unsigned(left), " right: %0d\n", $unsigned(right), "expected: %0d", $unsigned(left % right), " computed: %0d", $unsigned(dividend) ); if (finished && quotient != $unsigned(left / right)) $error( "\nstd_div_pipe (Quotient): Computed and golden outputs do not match!\n", "left: %0d", $unsigned(left), " right: %0d\n", $unsigned(right), "expected: %0d", $unsigned(left / right), " computed: %0d", $unsigned(quotient) ); end `endif endmodule /// =================== Signed, Bitnum ========================= module std_sadd #( parameter WIDTH = 32 ) ( input signed [WIDTH-1:0] left, input signed [WIDTH-1:0] right, output signed [WIDTH-1:0] out ); assign out = $signed(left + right); endmodule module std_ssub #( parameter WIDTH = 32 ) ( input signed [WIDTH-1:0] left, input signed [WIDTH-1:0] right, output signed [WIDTH-1:0] out ); assign out = $signed(left - right); endmodule module std_smult_pipe #( parameter WIDTH = 32 ) ( input logic go, input logic clk, input signed [WIDTH-1:0] left, input signed [WIDTH-1:0] right, output logic signed [WIDTH-1:0] out, output logic done ); std_fp_smult_pipe #( .WIDTH(WIDTH), .INT_WIDTH(WIDTH), .FRAC_WIDTH(0) ) comp ( .clk(clk), .done(done), .go(go), .left(left), .right(right), .out(out) ); endmodule /* verilator lint_off WIDTH */ module std_sdiv_pipe #( parameter WIDTH = 32 ) ( input clk, input go, input signed [WIDTH-1:0] left, input signed [WIDTH-1:0] right, output signed [WIDTH-1:0] out_quotient, output signed [WIDTH-1:0] out_remainder, output logic done ); logic signed [WIDTH-1:0] left_abs, right_abs, comp_out_q, comp_out_r; logic different_signs; assign right_abs = right[WIDTH-1] ? -right : right; assign left_abs = left[WIDTH-1] ? -left : left; assign different_signs = left[WIDTH-1] ^ right[WIDTH-1]; assign out_quotient = different_signs ? -comp_out_q : comp_out_q; assign out_remainder = (left[WIDTH-1] && comp_out_r) ? $signed(right - comp_out_r) : comp_out_r; std_div_pipe #( .WIDTH(WIDTH) ) comp ( .clk(clk), .done(done), .go(go), .left(left_abs), .right(right_abs), .out_quotient(comp_out_q), .out_remainder(comp_out_r) ); `ifdef VERILATOR // Simulation self test against unsynthesizable implementation. always @(posedge clk) begin if (done && out_quotient != $signed(left / right)) $error( "\nstd_sdiv_pipe (Quotient): Computed and golden outputs do not match!\n", "left: %0d", left, " right: %0d\n", right, "expected: %0d", $signed(left / right), " computed: %0d", $signed(out_quotient) ); if (done && out_remainder != $signed(((left % right) + right) % right)) $error( "\nstd_sdiv_pipe (Remainder): Computed and golden outputs do not match!\n", "left: %0d", left, " right: %0d\n", right, "expected: %0d", $signed(((left % right) + right) % right), " computed: %0d", $signed(out_remainder) ); end `endif endmodule module std_sgt #( parameter WIDTH = 32 ) ( input signed [WIDTH-1:0] left, input signed [WIDTH-1:0] right, output signed out ); assign out = $signed(left > right); endmodule module std_slt #( parameter WIDTH = 32 ) ( input signed [WIDTH-1:0] left, input signed [WIDTH-1:0] right, output signed out ); assign out = $signed(left < right); endmodule module std_seq #( parameter WIDTH = 32 ) ( input signed [WIDTH-1:0] left, input signed [WIDTH-1:0] right, output signed out ); assign out = $signed(left == right); endmodule module std_sneq #( parameter WIDTH = 32 ) ( input signed [WIDTH-1:0] left, input signed [WIDTH-1:0] right, output signed out ); assign out = $signed(left != right); endmodule module std_sge #( parameter WIDTH = 32 ) ( input signed [WIDTH-1:0] left, input signed [WIDTH-1:0] right, output signed out ); assign out = $signed(left >= right); endmodule module std_sle #( parameter WIDTH = 32 ) ( input signed [WIDTH-1:0] left, input signed [WIDTH-1:0] right, output signed out ); assign out = $signed(left <= right); endmodule module std_slsh #( parameter WIDTH = 32 ) ( input signed [WIDTH-1:0] left, input signed [WIDTH-1:0] right, output signed [WIDTH-1:0] out ); assign out = left <<< right; endmodule module std_srsh #( parameter WIDTH = 32 ) ( input signed [WIDTH-1:0] left, input signed [WIDTH-1:0] right, output signed [WIDTH-1:0] out ); assign out = left >>> right; endmodule