From ba09e75c5777ad0a1a63b3018ed21d19d0e0cd29 Mon Sep 17 00:00:00 2001 From: xenia Date: Sun, 21 Jan 2024 22:39:17 +0100 Subject: [PATCH] Multiplication implementation --- flake.nix | 2 +- fpga-files/rot.pcf | 1 + simulation/test_alu.cpp | 5 +- src/alu/alu.v | 135 ++++++++++++++++++++++++++-------------- src/topmost.v | 6 +- 5 files changed, 98 insertions(+), 51 deletions(-) diff --git a/flake.nix b/flake.nix index 1bf38be..1499f0e 100644 --- a/flake.nix +++ b/flake.nix @@ -43,7 +43,7 @@ alu-synth = pkgs.runCommandCC "alu-synth" {} '' mkdir -p "$out" - find ${./src} -name '*.v' -exec ${yosys}/bin/yosys -Q -p "synth_ice40 -top topmost -json $out/synth.json -dsp" {} + + find ${./src} -name '*.v' -exec ${yosys}/bin/yosys -f ' -sv' -Q -p "synth_ice40 -top topmost -json $out/synth.json -dsp" {} + ''; alu-synth-view = pkgs.writeScriptBin "alu-synth-view" '' diff --git a/fpga-files/rot.pcf b/fpga-files/rot.pcf index 3424530..2119542 100644 --- a/fpga-files/rot.pcf +++ b/fpga-files/rot.pcf @@ -1,4 +1,5 @@ set_io clk 39 +set_io en 38 set_io op[0] 40 set_io op[1] 41 set_io op[2] 42 diff --git a/simulation/test_alu.cpp b/simulation/test_alu.cpp index 5cb0cac..c068d07 100644 --- a/simulation/test_alu.cpp +++ b/simulation/test_alu.cpp @@ -27,7 +27,7 @@ struct alu_testcase { uint8_t op; // Outputs - uint32_t O; + uint64_t O; // {O_hi, O_lo} std::optional overflow, zero; std::optional max_cycles; @@ -104,7 +104,8 @@ void test_op(Tester *tester, alu_testcase test) { std::string o_name("O == "); o_name.append(fmt_hex(test.O)); - subtester.assert_eq(o_name, test.state->valu->O, test.O); + uint64_t O = (((uint64_t) test.state->valu->O_hi) << 32) | (uint64_t) test.state->valu->O_lo; + subtester.assert_eq(o_name, O, test.O); if (test.overflow.has_value()) { if (*test.overflow) diff --git a/src/alu/alu.v b/src/alu/alu.v index 0535a16..800288c 100644 --- a/src/alu/alu.v +++ b/src/alu/alu.v @@ -19,20 +19,30 @@ module alu( input [31:0] A, input [31:0] B, input [2:0] op, - output reg [31:0] O, - output reg Fflow, - output reg Fzero + output wire [31:0] O_lo, + output wire [31:0] O_hi, // only used for OP_MUL + output wire Fflow, + output wire Fzero ); // Constants +/* verilator lint_off UNUSEDPARAM */ localparam OP_ADD = 3'b000; localparam OP_SUB = 3'b001; +localparam OP_MUL = 3'b010; localparam OP_AND = 3'b100; localparam OP_OR = 3'b101; localparam OP_XOR = 3'b110; localparam OP_NOT = 3'b111; localparam ST_IDLE = 0; +localparam ST_MULTIPLY_START = 1; +localparam ST_MULTIPLY_END = 32; + +localparam OUT_ADD = 0; +localparam OUT_SUB = 1; +localparam OUT_BW = 2; +localparam OUT_MUL = 3; // State @@ -43,18 +53,29 @@ assign RDY = state == ST_IDLE; reg [31:0] bitwise_out; +// Multiplication + +reg [63:0] mult_out; +reg [31:0] factorA, factorB; // factorA is static, factorB is shifted each cycle + // Outputs -assign O = - (selected_out == OP_ADD || selected_out == OP_SUB) ? adder_out : +assign O_lo = + (selected_out == OUT_ADD || selected_out == OUT_SUB) ? adder_out : + selected_out == OUT_MUL ? mult_out[31:0] : bitwise_out; -assign Fflow = - selected_out == OP_ADD ? adder_carry_out : - selected_out == OP_SUB ? ~adder_carry_out : +assign O_hi = + selected_out == OUT_MUL ? mult_out[63:32] : 0; -assign Fzero = ~(| O); +assign Fflow = + selected_out == OUT_ADD ? adder_carry_out : + selected_out == OUT_SUB ? ~adder_carry_out : + selected_out == OUT_MUL ? 0 : + 0; + +assign Fzero = ~((| O_lo) | (| O_hi)); // Modules @@ -67,44 +88,68 @@ carry_select_adder adder(adder_A, adder_B, adder_carry_in, adder_out, adder_carr // Clocking always @(posedge CLK) begin - case (state) - ST_IDLE: begin - if (EN) begin - case (op) - OP_ADD: begin - adder_A <= A; - adder_B <= B; - adder_carry_in <= 0; - selected_out <= OP_ADD; - end - OP_SUB: begin - adder_A <= A; - adder_B <= ~B; - adder_carry_in <= 1; - selected_out <= OP_SUB; - end - OP_AND: begin - bitwise_out <= A & B; - selected_out <= OP_AND; - end - OP_OR: begin - bitwise_out <= A | B; - selected_out <= OP_OR; - end - OP_XOR: begin - bitwise_out <= A ^ B; - selected_out <= OP_XOR; - end - OP_NOT: begin - bitwise_out <= ~A; - selected_out <= OP_NOT; - end - default: begin end // TODO: this should be $stop in verilator, no-op in synthesis - endcase + reg [63:0] mult_out_tmp; + + if (state == ST_IDLE && EN) begin + case (op) + OP_ADD: begin + adder_A <= A; + adder_B <= B; + adder_carry_in <= 0; + selected_out <= OUT_ADD; end + OP_SUB: begin + adder_A <= A; + adder_B <= ~B; + adder_carry_in <= 1; + selected_out <= OUT_SUB; + end + OP_MUL: begin + factorA <= A; + factorB <= B; + mult_out <= 0; + adder_A <= 0; + adder_B <= A; + adder_carry_in <= 0; + state <= ST_MULTIPLY_START; + selected_out <= OUT_MUL; + end + OP_AND: begin + bitwise_out <= A & B; + selected_out <= OUT_BW; + end + OP_OR: begin + bitwise_out <= A | B; + selected_out <= OUT_BW; + end + OP_XOR: begin + bitwise_out <= A ^ B; + selected_out <= OUT_BW; + end + OP_NOT: begin + bitwise_out <= ~A; + selected_out <= OUT_BW; + end + default: begin end // TODO: this should be $stop in verilator, no-op in synthesis + endcase + end + + if (state >= ST_MULTIPLY_START && state <= ST_MULTIPLY_END) begin + mult_out_tmp = { + factorB[0] ? {adder_carry_out, adder_out} : {1'b0, mult_out[63:32]}, + mult_out[31:1] + }; + mult_out <= mult_out_tmp; + + factorB <= {1'b0, factorB[31:1]}; + adder_A <= {mult_out_tmp[63:32]}; + adder_B <= factorA; + if (state < ST_MULTIPLY_END) begin + state <= state + 1; + end else begin + state <= ST_IDLE; end - default: $stop; - endcase + end end endmodule diff --git a/src/topmost.v b/src/topmost.v index 107a902..fbc5301 100644 --- a/src/topmost.v +++ b/src/topmost.v @@ -1,11 +1,11 @@ // Dummy module for connecting ALU and similar things, without having to break all inputs and outputs into separate pads -module topmost(input clk, input [2:0] op, output xor_reduce); +module topmost(input clk, input en, input [2:0] op, output xor_reduce); reg [31:0] A; reg [31:0] B; -wire [31:0] O; +wire [63:0] O; -alu alu(.A(A), .B(B), .op(op), .O(O), .Fflow(), .Fzero()); +alu alu(.CLK(clk), .EN(en), .A(A), .B(B), .op(op), .O_lo(O[31:0]), .O_hi(O[63:32]), .Fflow(), .Fzero()); always @(posedge clk) begin A <= A + 1;