Compare commits
4 Commits
3b10fd110e
...
9c2d15e171
Author | SHA1 | Date | |
---|---|---|---|
9c2d15e171 | |||
ba09e75c57 | |||
ac3e34b2ef | |||
14cf222a6c |
|
@ -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" ''
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
@ -94,17 +94,18 @@ 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) (actually %d)", test.max_cycles, n_cycles);
|
||||
snprintf(n_cycles_s, sizeof n_cycles_s, "Finished within %d cycle(s) (was: %d)", 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, test.max_cycles);
|
||||
subtester.assert_eq("Finished within correct number of cycles", n_cycles, max_cycles);
|
||||
}
|
||||
}
|
||||
|
||||
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)
|
||||
|
@ -280,6 +281,50 @@ 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);
|
||||
|
||||
|
@ -373,6 +418,8 @@ int main(int argc, char **argv) {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#ifdef TRACE
|
||||
state.trace->close();
|
||||
#endif
|
||||
|
|
|
@ -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
|
||||
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 <= OP_ADD;
|
||||
selected_out <= OUT_ADD;
|
||||
end
|
||||
OP_SUB: begin
|
||||
adder_A <= A;
|
||||
adder_B <= ~B;
|
||||
adder_carry_in <= 1;
|
||||
selected_out <= OP_SUB;
|
||||
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 <= OP_AND;
|
||||
selected_out <= OUT_BW;
|
||||
end
|
||||
OP_OR: begin
|
||||
bitwise_out <= A | B;
|
||||
selected_out <= OP_OR;
|
||||
selected_out <= OUT_BW;
|
||||
end
|
||||
OP_XOR: begin
|
||||
bitwise_out <= A ^ B;
|
||||
selected_out <= OP_XOR;
|
||||
selected_out <= OUT_BW;
|
||||
end
|
||||
OP_NOT: begin
|
||||
bitwise_out <= ~A;
|
||||
selected_out <= OP_NOT;
|
||||
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
|
||||
|
|
|
@ -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;
|
||||
|
|
Loading…
Reference in New Issue
Block a user