Compare commits
2 Commits
9c2d15e171
...
3b10fd110e
Author | SHA1 | Date | |
---|---|---|---|
3b10fd110e | |||
1b316ead40 |
|
@ -43,7 +43,7 @@
|
||||||
|
|
||||||
alu-synth = pkgs.runCommandCC "alu-synth" {} ''
|
alu-synth = pkgs.runCommandCC "alu-synth" {} ''
|
||||||
mkdir -p "$out"
|
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" ''
|
alu-synth-view = pkgs.writeScriptBin "alu-synth-view" ''
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
set_io clk 39
|
set_io clk 39
|
||||||
set_io en 38
|
|
||||||
set_io op[0] 40
|
set_io op[0] 40
|
||||||
set_io op[1] 41
|
set_io op[1] 41
|
||||||
set_io op[2] 42
|
set_io op[2] 42
|
||||||
|
|
|
@ -27,7 +27,7 @@ struct alu_testcase {
|
||||||
uint8_t op;
|
uint8_t op;
|
||||||
|
|
||||||
// Outputs
|
// Outputs
|
||||||
uint64_t O; // {O_hi, O_lo}
|
uint32_t O;
|
||||||
std::optional<bool> overflow, zero;
|
std::optional<bool> overflow, zero;
|
||||||
|
|
||||||
std::optional<unsigned int> max_cycles;
|
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 (test.max_cycles.has_value()) {
|
||||||
if (n_cycles <= test.max_cycles) {
|
if (n_cycles <= test.max_cycles) {
|
||||||
char n_cycles_s[100];
|
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);
|
subtester.assert_eq(n_cycles_s, n_cycles, n_cycles);
|
||||||
} else {
|
} 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 == ");
|
std::string o_name("O == ");
|
||||||
o_name.append(fmt_hex(test.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, test.state->valu->O, test.O);
|
||||||
subtester.assert_eq(o_name, O, test.O);
|
|
||||||
|
|
||||||
if (test.overflow.has_value()) {
|
if (test.overflow.has_value()) {
|
||||||
if (*test.overflow)
|
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) {
|
if (DO_AUTO) {
|
||||||
Tester auto_t(&alu_t, "auto", true);
|
Tester auto_t(&alu_t, "auto", true);
|
||||||
|
|
||||||
|
@ -418,8 +373,6 @@ int main(int argc, char **argv) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#ifdef TRACE
|
#ifdef TRACE
|
||||||
state.trace->close();
|
state.trace->close();
|
||||||
#endif
|
#endif
|
||||||
|
|
133
src/alu/alu.v
133
src/alu/alu.v
|
@ -19,30 +19,20 @@ module alu(
|
||||||
input [31:0] A,
|
input [31:0] A,
|
||||||
input [31:0] B,
|
input [31:0] B,
|
||||||
input [2:0] op,
|
input [2:0] op,
|
||||||
output wire [31:0] O_lo,
|
output reg [31:0] O,
|
||||||
output wire [31:0] O_hi, // only used for OP_MUL
|
output reg Fflow,
|
||||||
output wire Fflow,
|
output reg Fzero
|
||||||
output wire Fzero
|
|
||||||
);
|
);
|
||||||
|
|
||||||
// Constants
|
// Constants
|
||||||
/* verilator lint_off UNUSEDPARAM */
|
|
||||||
localparam OP_ADD = 3'b000;
|
localparam OP_ADD = 3'b000;
|
||||||
localparam OP_SUB = 3'b001;
|
localparam OP_SUB = 3'b001;
|
||||||
localparam OP_MUL = 3'b010;
|
|
||||||
localparam OP_AND = 3'b100;
|
localparam OP_AND = 3'b100;
|
||||||
localparam OP_OR = 3'b101;
|
localparam OP_OR = 3'b101;
|
||||||
localparam OP_XOR = 3'b110;
|
localparam OP_XOR = 3'b110;
|
||||||
localparam OP_NOT = 3'b111;
|
localparam OP_NOT = 3'b111;
|
||||||
|
|
||||||
localparam ST_IDLE = 0;
|
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
|
// State
|
||||||
|
|
||||||
|
@ -53,29 +43,18 @@ assign RDY = state == ST_IDLE;
|
||||||
|
|
||||||
reg [31:0] bitwise_out;
|
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
|
// Outputs
|
||||||
|
|
||||||
assign O_lo =
|
assign O =
|
||||||
(selected_out == OUT_ADD || selected_out == OUT_SUB) ? adder_out :
|
(selected_out == OP_ADD || selected_out == OP_SUB) ? adder_out :
|
||||||
selected_out == OUT_MUL ? mult_out[31:0] :
|
|
||||||
bitwise_out;
|
bitwise_out;
|
||||||
|
|
||||||
assign O_hi =
|
|
||||||
selected_out == OUT_MUL ? mult_out[63:32] :
|
|
||||||
0;
|
|
||||||
|
|
||||||
assign Fflow =
|
assign Fflow =
|
||||||
selected_out == OUT_ADD ? adder_carry_out :
|
selected_out == OP_ADD ? adder_carry_out :
|
||||||
selected_out == OUT_SUB ? ~adder_carry_out :
|
selected_out == OP_SUB ? ~adder_carry_out :
|
||||||
selected_out == OUT_MUL ? 0 :
|
|
||||||
0;
|
0;
|
||||||
|
|
||||||
assign Fzero = ~((| O_lo) | (| O_hi));
|
assign Fzero = ~(| O);
|
||||||
|
|
||||||
// Modules
|
// Modules
|
||||||
|
|
||||||
|
@ -88,68 +67,44 @@ carry_select_adder adder(adder_A, adder_B, adder_carry_in, adder_out, adder_carr
|
||||||
// Clocking
|
// Clocking
|
||||||
|
|
||||||
always @(posedge CLK) begin
|
always @(posedge CLK) begin
|
||||||
reg [63:0] mult_out_tmp;
|
case (state)
|
||||||
|
ST_IDLE: begin
|
||||||
if (state == ST_IDLE && EN) begin
|
if (EN) begin
|
||||||
case (op)
|
case (op)
|
||||||
OP_ADD: begin
|
OP_ADD: begin
|
||||||
adder_A <= A;
|
adder_A <= A;
|
||||||
adder_B <= B;
|
adder_B <= B;
|
||||||
adder_carry_in <= 0;
|
adder_carry_in <= 0;
|
||||||
selected_out <= OUT_ADD;
|
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
|
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
|
||||||
end
|
default: $stop;
|
||||||
|
endcase
|
||||||
end
|
end
|
||||||
|
|
||||||
endmodule
|
endmodule
|
||||||
|
|
|
@ -1,11 +1,11 @@
|
||||||
// Dummy module for connecting ALU and similar things, without having to break all inputs and outputs into separate pads
|
// 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] A;
|
||||||
reg [31:0] B;
|
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
|
always @(posedge clk) begin
|
||||||
A <= A + 1;
|
A <= A + 1;
|
||||||
|
|
Loading…
Reference in New Issue
Block a user