Multiplication implementation

main
xenia 2024-01-21 22:39:17 +01:00
parent ac3e34b2ef
commit ba09e75c57
5 changed files with 98 additions and 51 deletions

View File

@ -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" ''

View File

@ -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

View File

@ -27,7 +27,7 @@ struct alu_testcase {
uint8_t op;
// Outputs
uint32_t O;
uint64_t O; // {O_hi, O_lo}
std::optional<bool> overflow, zero;
std::optional<unsigned int> 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)

View File

@ -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

View File

@ -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;