Created
August 23, 2020 15:18
-
-
Save Wren6991/f08c14bbcb759f4a76fd81c9aee47879 to your computer and use it in GitHub Desktop.
hazard5_alu CXXRTL repro
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
read_verilog hazard5_alu.v hazard5_shift_barrel.v | |
write_cxxrtl foo.cpp |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
module hazard5_alu #( | |
parameter W_DATA = 32 | |
) ( | |
input wire [3:0] aluop, | |
input wire [W_DATA-1:0] op_a, | |
input wire [W_DATA-1:0] op_b, | |
output reg [W_DATA-1:0] result, | |
output wire [W_DATA-1:0] result_add, // for load/stores | |
output wire cmp | |
); | |
`include "hazard5_ops.vh" | |
function msb; | |
input [W_DATA-1:0] x; | |
begin | |
msb = x[W_DATA-1]; | |
end | |
endfunction | |
wire sub = aluop != ALUOP_ADD; | |
wire [W_DATA-1:0] sum = op_a + (op_b ^ {W_DATA{sub}}) + sub; | |
wire [W_DATA-1:0] op_xor = op_a ^ op_b; | |
wire lt = msb(op_a) == msb(op_b) ? msb(sum) : | |
aluop == ALUOP_LTU ? msb(op_b) : | |
msb(op_a) ; | |
assign cmp = aluop == ALUOP_SUB ? |op_xor : lt; | |
assign result_add = sum; | |
wire [W_DATA-1:0] shift_dout; | |
reg shift_right_nleft; | |
reg shift_arith; | |
hazard5_shift_barrel #( | |
.W_DATA(W_DATA), | |
.W_SHAMT(5) | |
) shifter ( | |
.din(op_a), | |
.shamt(op_b[4:0]), | |
.right_nleft(shift_right_nleft), | |
.arith(shift_arith), | |
.dout(shift_dout) | |
); | |
// We can implement all bitwise ops with 1 LUT4/bit total, since each result bit | |
// uses only two operand bits. Much better than feeding each into main mux tree. | |
reg [W_DATA-1:0] bitwise; | |
always @ (*) begin: bitwise_ops | |
case (aluop[1:0]) | |
ALUOP_AND[1:0]: bitwise = op_a & op_b; | |
ALUOP_OR[1:0]: bitwise = op_a | op_b; | |
default: bitwise = op_a ^ op_b; | |
endcase | |
end | |
always @ (*) begin | |
shift_right_nleft = 1'b0; | |
shift_arith = 1'b0; | |
case (aluop) | |
ALUOP_ADD: begin result = sum; end | |
ALUOP_SUB: begin result = sum; end | |
ALUOP_LT: begin result = {{W_DATA-1{1'b0}}, lt}; end | |
ALUOP_LTU: begin result = {{W_DATA-1{1'b0}}, lt}; end | |
ALUOP_SRL: begin shift_right_nleft = 1'b1; result = shift_dout; end | |
ALUOP_SRA: begin shift_right_nleft = 1'b1; shift_arith = 1'b1; result = shift_dout; end | |
ALUOP_SLL: begin result = shift_dout; end | |
default: begin result = bitwise; end | |
endcase | |
end | |
`ifdef FORMAL | |
`ifndef RISCV_FORMAL | |
// Really we're just interested in the shifts and comparisons, as these are | |
// the nontrivial ones. However, easier to test everything! | |
wire clk; | |
always @ (posedge clk) begin | |
case(aluop) | |
default: begin end | |
ALUOP_ADD: assert(result == op_a + op_b); | |
ALUOP_SUB: assert(result == op_a - op_b); | |
ALUOP_LT: assert(result == $signed(op_a) < $signed(op_b)); | |
ALUOP_LTU: assert(result == op_a < op_b); | |
ALUOP_AND: assert(result == (op_a & op_b)); | |
ALUOP_OR: assert(result == (op_a | op_b)); | |
ALUOP_XOR: assert(result == (op_a ^ op_b)); | |
ALUOP_SRL: assert(result == op_a >> op_b[4:0]); | |
ALUOP_SRA: assert($signed(result) == $signed(op_a) >>> $signed(op_b[4:0])); | |
ALUOP_SLL: assert(result == op_a << op_b[4:0]); | |
endcase | |
end | |
`endif | |
`endif | |
endmodule |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
localparam W_ALUOP = 4; | |
localparam W_ALUSRC = 2; | |
localparam W_MEMOP = 4; | |
localparam W_BCOND = 2; | |
// ALU operation selectors | |
localparam ALUOP_ADD = 4'h0; | |
localparam ALUOP_SUB = 4'h1; | |
localparam ALUOP_LT = 4'h2; | |
localparam ALUOP_LTU = 4'h4; | |
localparam ALUOP_AND = 4'h6; | |
localparam ALUOP_OR = 4'h7; | |
localparam ALUOP_XOR = 4'h8; | |
localparam ALUOP_SRL = 4'h9; | |
localparam ALUOP_SRA = 4'ha; | |
localparam ALUOP_SLL = 4'hb; | |
localparam ALUOP_MULDIV = 4'hc; | |
// Parameters to control ALU input muxes. Bypass mux paths are | |
// controlled by X, so D has no parameters to choose these. | |
localparam ALUSRCA_RS1 = 2'h0; | |
localparam ALUSRCA_PC = 2'h1; | |
localparam ALUSRCB_RS2 = 2'h0; | |
localparam ALUSRCB_IMM = 2'h1; | |
localparam MEMOP_LW = 4'h0; | |
localparam MEMOP_LH = 4'h1; | |
localparam MEMOP_LB = 4'h2; | |
localparam MEMOP_LHU = 4'h3; | |
localparam MEMOP_LBU = 4'h4; | |
localparam MEMOP_SW = 4'h5; | |
localparam MEMOP_SH = 4'h6; | |
localparam MEMOP_SB = 4'h7; | |
localparam MEMOP_NONE = 4'h8; | |
localparam BCOND_NEVER = 2'h0; | |
localparam BCOND_ALWAYS = 2'h1; | |
localparam BCOND_ZERO = 2'h2; | |
localparam BCOND_NZERO = 2'h3; | |
// CSR access types | |
localparam CSR_WTYPE_W = 2'h0; | |
localparam CSR_WTYPE_S = 2'h1; | |
localparam CSR_WTYPE_C = 2'h2; | |
// Exceptional condition signals which travel alongside (or instead of) | |
// instructions in the pipeline. These are speculative and can be flushed | |
// on e.g. branch mispredict | |
localparam W_EXCEPT = 3; | |
localparam EXCEPT_NONE = 3'h0; | |
localparam EXCEPT_ECALL = 3'h1; | |
localparam EXCEPT_EBREAK = 3'h2; | |
localparam EXCEPT_MRET = 3'h3; // separate, but handled similarly | |
localparam EXCEPT_INSTR_ILLEGAL = 3'h4; | |
localparam EXCEPT_INSTR_MISALIGN = 3'h5; | |
localparam EXCEPT_INSTR_FAULT = 3'h6; | |
// Operations for M extension (these are just instr[14:12]) | |
localparam W_MULOP = 3; | |
localparam M_OP_MUL = 3'h0; | |
localparam M_OP_MULH = 3'h1; | |
localparam M_OP_MULHSU = 3'h2; | |
localparam M_OP_MULHU = 3'h3; | |
localparam M_OP_DIV = 3'h4; | |
localparam M_OP_DIVU = 3'h5; | |
localparam M_OP_REM = 3'h6; | |
localparam M_OP_REMU = 3'h7; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
module hazard5_shift_barrel #( | |
parameter W_DATA = 32, | |
parameter W_SHAMT = 5 | |
) ( | |
input wire [W_DATA-1:0] din, | |
input wire [W_SHAMT-1:0] shamt, | |
input wire right_nleft, | |
input wire arith, | |
output reg [W_DATA-1:0] dout | |
); | |
integer i; | |
reg [W_DATA-1:0] din_rev; | |
reg [W_DATA-1:0] shift_accum; | |
wire sext = arith && din_rev[0]; // haha | |
always @ (*) begin | |
for (i = 0; i < W_DATA; i = i + 1) | |
din_rev[i] = right_nleft ? din[W_DATA - 1 - i] : din[i]; | |
end | |
always @ (*) begin | |
shift_accum = din_rev; | |
for (i = 0; i < W_SHAMT; i = i + 1) begin | |
if (shamt[i]) begin | |
shift_accum = (shift_accum << (1 << i)) | | |
({W_DATA{sext}} & ~({W_DATA{1'b1}} << (1 << i))); | |
end | |
end | |
end | |
always @ (*) begin | |
for (i = 0; i < W_DATA; i = i + 1) | |
dout[i] = right_nleft ? shift_accum[W_DATA - 1 - i] : shift_accum[i]; | |
end | |
`ifdef FORMAL | |
always @ (*) begin | |
if (right_nleft && arith) begin: asr | |
assert($signed(dout) == $signed(din) >>> $signed(shamt)); | |
end else if (right_nleft && !arith) begin | |
assert(dout == din >> shamt); | |
end else if (!right_nleft && !arith) begin | |
assert(dout == din << shamt); | |
end | |
end | |
`endif | |
endmodule |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment