Compare commits

..

2 Commits

Author SHA1 Message Date
3b10fd110e Don't warn on BLKSEQ 2024-01-21 20:50:47 +01:00
1b316ead40 Make ALU synchronous, generate and view traces 2024-01-21 20:50:22 +01:00
5 changed files with 52 additions and 145 deletions

View File

@ -43,7 +43,7 @@
alu-synth = pkgs.runCommandCC "alu-synth" {} ''
mkdir -p "$out"
find ${./src} -name '*.v' -exec ${yosys}/bin/yosys -f ' -sv' -Q -p "synth_ice40 -top topmost -json $out/synth.json -dsp" {} +
find ${./src} -name '*.v' -exec ${yosys}/bin/yosys -Q -p "synth_ice40 -top topmost -json $out/synth.json -dsp" {} +
'';
alu-synth-view = pkgs.writeScriptBin "alu-synth-view" ''

View File

@ -1,5 +1,4 @@
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
uint64_t O; // {O_hi, O_lo}
uint32_t O;
std::optional<bool> overflow, zero;
std::optional<unsigned int> max_cycles;
@ -94,18 +94,17 @@ void test_op(Tester *tester, alu_testcase test) {
if (test.max_cycles.has_value()) {
if (n_cycles <= test.max_cycles) {
char n_cycles_s[100];
snprintf(n_cycles_s, sizeof n_cycles_s, "Finished within %d cycle(s) (was: %d)", max_cycles, n_cycles);
snprintf(n_cycles_s, sizeof n_cycles_s, "Finished within %d cycle(s) (actually %d)", test.max_cycles, n_cycles);
subtester.assert_eq(n_cycles_s, n_cycles, n_cycles);
} else {
subtester.assert_eq("Finished within correct number of cycles", n_cycles, max_cycles);
subtester.assert_eq("Finished within correct number of cycles", n_cycles, test.max_cycles);
}
}
std::string o_name("O == ");
o_name.append(fmt_hex(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);
subtester.assert_eq(o_name, test.state->valu->O, test.O);
if (test.overflow.has_value()) {
if (*test.overflow)
@ -281,50 +280,6 @@ int main(int argc, char **argv) {
});
}
{
Tester mul_t(&alu_t, "mul", true);
test_op(&mul_t, {
.state = &state,
.name = "0x55*0x1",
.A = 0x55, .B = 0x1, .op = 0b010,
.O = 0x55,
.max_cycles = 33,
});
test_op(&mul_t, {
.state = &state,
.name = "0x1*0x55",
.A = 0x1, .B = 0x55, .op = 0b010,
.O = 0x55,
.max_cycles = 33,
});
test_op(&mul_t, {
.state = &state,
.name = "0x5*0x5",
.A = 0x5, .B = 0x5, .op = 0b010,
.O = 0x19,
.max_cycles = 33,
});
test_op(&mul_t, {
.state = &state,
.name = "0x21*0x37",
.A = 0x21, .B = 0x37, .op = 0b010,
.O = 0x717,
.max_cycles = 33,
});
test_op(&mul_t, {
.state = &state,
.name = "0x12345678*0x87654321",
.A = 0x12345678, .B = 0x87654321, .op = 0b010,
.O = 0x9a0cd0570b88d78,
.max_cycles = 33,
});
}
if (DO_AUTO) {
Tester auto_t(&alu_t, "auto", true);
@ -418,8 +373,6 @@ int main(int argc, char **argv) {
}
}
}
#ifdef TRACE
state.trace->close();
#endif

View File

@ -19,30 +19,20 @@ module alu(
input [31:0] A,
input [31:0] B,
input [2:0] op,
output wire [31:0] O_lo,
output wire [31:0] O_hi, // only used for OP_MUL
output wire Fflow,
output wire Fzero
output reg [31:0] O,
output reg Fflow,
output reg 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
@ -53,29 +43,18 @@ 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_lo =
(selected_out == OUT_ADD || selected_out == OUT_SUB) ? adder_out :
selected_out == OUT_MUL ? mult_out[31:0] :
assign O =
(selected_out == OP_ADD || selected_out == OP_SUB) ? adder_out :
bitwise_out;
assign O_hi =
selected_out == OUT_MUL ? mult_out[63:32] :
0;
assign Fflow =
selected_out == OUT_ADD ? adder_carry_out :
selected_out == OUT_SUB ? ~adder_carry_out :
selected_out == OUT_MUL ? 0 :
selected_out == OP_ADD ? adder_carry_out :
selected_out == OP_SUB ? ~adder_carry_out :
0;
assign Fzero = ~((| O_lo) | (| O_hi));
assign Fzero = ~(| O);
// Modules
@ -88,68 +67,44 @@ carry_select_adder adder(adder_A, adder_B, adder_carry_in, adder_out, adder_carr
// Clocking
always @(posedge CLK) begin
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;
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
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
end
default: $stop;
endcase
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 en, input [2:0] op, output xor_reduce);
module topmost(input clk, input [2:0] op, output xor_reduce);
reg [31:0] A;
reg [31:0] B;
wire [63:0] O;
wire [31:0] O;
alu alu(.CLK(clk), .EN(en), .A(A), .B(B), .op(op), .O_lo(O[31:0]), .O_hi(O[63:32]), .Fflow(), .Fzero());
alu alu(.A(A), .B(B), .op(op), .O(O), .Fflow(), .Fzero());
always @(posedge clk) begin
A <= A + 1;