229 lines
8.4 KiB
Systemverilog
229 lines
8.4 KiB
Systemverilog
`include "VX_define.vh"
|
|
|
|
module VX_alu_unit #(
|
|
parameter CORE_ID = 0
|
|
) (
|
|
input wire clk,
|
|
input wire reset,
|
|
|
|
// Inputs
|
|
VX_alu_req_if.slave alu_req_if,
|
|
|
|
// Outputs
|
|
VX_branch_ctl_if.master branch_ctl_if,
|
|
VX_commit_if.master alu_commit_if
|
|
);
|
|
|
|
`UNUSED_PARAM (CORE_ID)
|
|
|
|
reg [`NUM_THREADS-1:0][31:0] alu_result;
|
|
wire [`NUM_THREADS-1:0][31:0] add_result;
|
|
wire [`NUM_THREADS-1:0][32:0] sub_result;
|
|
wire [`NUM_THREADS-1:0][31:0] shr_result;
|
|
reg [`NUM_THREADS-1:0][31:0] msc_result;
|
|
|
|
wire ready_in;
|
|
|
|
`UNUSED_VAR (alu_req_if.op_mod)
|
|
wire is_br_op = `INST_ALU_IS_BR(alu_req_if.op_mod);
|
|
wire [`INST_ALU_BITS-1:0] alu_op = `INST_ALU_BITS'(alu_req_if.op_type);
|
|
wire [`INST_BR_BITS-1:0] br_op = `INST_BR_BITS'(alu_req_if.op_type);
|
|
wire alu_signed = `INST_ALU_SIGNED(alu_op);
|
|
wire [1:0] alu_op_class = `INST_ALU_OP_CLASS(alu_op);
|
|
wire is_sub = (alu_op == `INST_ALU_SUB);
|
|
|
|
wire [`NUM_THREADS-1:0][31:0] alu_in1 = alu_req_if.rs1_data;
|
|
wire [`NUM_THREADS-1:0][31:0] alu_in2 = alu_req_if.rs2_data;
|
|
|
|
wire [`NUM_THREADS-1:0][31:0] alu_in1_PC = alu_req_if.use_PC ? {`NUM_THREADS{alu_req_if.PC}} : alu_in1;
|
|
wire [`NUM_THREADS-1:0][31:0] alu_in2_imm = alu_req_if.use_imm ? {`NUM_THREADS{alu_req_if.imm}} : alu_in2;
|
|
wire [`NUM_THREADS-1:0][31:0] alu_in2_less = (alu_req_if.use_imm && ~is_br_op) ? {`NUM_THREADS{alu_req_if.imm}} : alu_in2;
|
|
|
|
for (genvar i = 0; i < `NUM_THREADS; i++) begin
|
|
assign add_result[i] = alu_in1_PC[i] + alu_in2_imm[i];
|
|
end
|
|
|
|
for (genvar i = 0; i < `NUM_THREADS; i++) begin
|
|
wire [32:0] sub_in1 = {alu_signed & alu_in1[i][31], alu_in1[i]};
|
|
wire [32:0] sub_in2 = {alu_signed & alu_in2_less[i][31], alu_in2_less[i]};
|
|
assign sub_result[i] = sub_in1 - sub_in2;
|
|
end
|
|
|
|
for (genvar i = 0; i < `NUM_THREADS; i++) begin
|
|
wire [32:0] shr_in1 = {alu_signed & alu_in1[i][31], alu_in1[i]};
|
|
assign shr_result[i] = 32'($signed(shr_in1) >>> alu_in2_imm[i][4:0]);
|
|
end
|
|
|
|
for (genvar i = 0; i < `NUM_THREADS; i++) begin
|
|
always @(*) begin
|
|
case (alu_op)
|
|
`INST_ALU_AND: msc_result[i] = alu_in1[i] & alu_in2_imm[i];
|
|
`INST_ALU_OR: msc_result[i] = alu_in1[i] | alu_in2_imm[i];
|
|
`INST_ALU_XOR: msc_result[i] = alu_in1[i] ^ alu_in2_imm[i];
|
|
//`INST_ALU_SLL,
|
|
default: msc_result[i] = alu_in1[i] << alu_in2_imm[i][4:0];
|
|
endcase
|
|
end
|
|
end
|
|
|
|
for (genvar i = 0; i < `NUM_THREADS; i++) begin
|
|
always @(*) begin
|
|
case (alu_op_class)
|
|
2'b00: alu_result[i] = add_result[i]; // ADD, LUI, AUIPC
|
|
2'b01: alu_result[i] = {31'b0, sub_result[i][32]}; // SLTU, SLT
|
|
2'b10: alu_result[i] = is_sub ? sub_result[i][31:0] // SUB
|
|
: shr_result[i]; // SRL, SRA
|
|
// 2'b11,
|
|
default: alu_result[i] = msc_result[i]; // AND, OR, XOR, SLL
|
|
endcase
|
|
end
|
|
end
|
|
|
|
// branch
|
|
|
|
wire is_jal = is_br_op && (br_op == `INST_BR_JAL || br_op == `INST_BR_JALR);
|
|
wire [`NUM_THREADS-1:0][31:0] alu_jal_result = is_jal ? {`NUM_THREADS{alu_req_if.next_PC}} : alu_result;
|
|
|
|
wire [31:0] br_dest = add_result[alu_req_if.tid];
|
|
wire [32:0] cmp_result = sub_result[alu_req_if.tid];
|
|
|
|
wire is_less = cmp_result[32];
|
|
wire is_equal = ~(| cmp_result[31:0]);
|
|
|
|
// output
|
|
|
|
wire alu_valid_in;
|
|
wire alu_ready_in;
|
|
wire alu_valid_out;
|
|
wire alu_ready_out;
|
|
wire [`NW_BITS-1:0] alu_wid;
|
|
wire [`NUM_THREADS-1:0] alu_tmask;
|
|
wire [31:0] alu_PC;
|
|
wire [`NR_BITS-1:0] alu_rd;
|
|
wire alu_wb;
|
|
wire [`NUM_THREADS-1:0][31:0] alu_data;
|
|
|
|
wire [`INST_BR_BITS-1:0] br_op_r;
|
|
wire [31:0] br_dest_r;
|
|
wire is_less_r;
|
|
wire is_equal_r;
|
|
wire is_br_op_r;
|
|
|
|
assign alu_ready_in = alu_ready_out || ~alu_valid_out;
|
|
|
|
VX_pipe_register #(
|
|
.DATAW (1 + `NW_BITS + `NUM_THREADS + 32 + `NR_BITS + 1 + (`NUM_THREADS * 32) + 1 + `INST_BR_BITS + 1 + 1 + 32),
|
|
.RESETW (1)
|
|
) pipe_reg (
|
|
.clk (clk),
|
|
.reset (reset),
|
|
.enable (alu_ready_in),
|
|
.data_in ({alu_valid_in, alu_req_if.wid, alu_req_if.tmask, alu_req_if.PC, alu_req_if.rd, alu_req_if.wb, alu_jal_result, is_br_op, br_op, is_less, is_equal, br_dest}),
|
|
.data_out ({alu_valid_out, alu_wid, alu_tmask, alu_PC, alu_rd, alu_wb, alu_data, is_br_op_r, br_op_r, is_less_r, is_equal_r, br_dest_r})
|
|
);
|
|
|
|
`UNUSED_VAR (br_op_r)
|
|
wire br_neg = `INST_BR_NEG(br_op_r);
|
|
wire br_less = `INST_BR_LESS(br_op_r);
|
|
wire br_static = `INST_BR_STATIC(br_op_r);
|
|
|
|
assign branch_ctl_if.valid = alu_valid_out && alu_ready_out && is_br_op_r;
|
|
assign branch_ctl_if.taken = ((br_less ? is_less_r : is_equal_r) ^ br_neg) | br_static;
|
|
assign branch_ctl_if.wid = alu_wid;
|
|
assign branch_ctl_if.dest = br_dest_r;
|
|
|
|
`ifdef EXT_M_ENABLE
|
|
|
|
wire mul_valid_in;
|
|
wire mul_ready_in;
|
|
wire mul_valid_out;
|
|
wire mul_ready_out;
|
|
wire [`NW_BITS-1:0] mul_wid;
|
|
wire [`NUM_THREADS-1:0] mul_tmask;
|
|
wire [31:0] mul_PC;
|
|
wire [`NR_BITS-1:0] mul_rd;
|
|
wire mul_wb;
|
|
wire [`NUM_THREADS-1:0][31:0] mul_data;
|
|
|
|
wire [`INST_MUL_BITS-1:0] mul_op = `INST_MUL_BITS'(alu_req_if.op_type);
|
|
|
|
VX_muldiv muldiv (
|
|
.clk (clk),
|
|
.reset (reset),
|
|
|
|
// Inputs
|
|
.alu_op (mul_op),
|
|
.wid_in (alu_req_if.wid),
|
|
.tmask_in (alu_req_if.tmask),
|
|
.PC_in (alu_req_if.PC),
|
|
.rd_in (alu_req_if.rd),
|
|
.wb_in (alu_req_if.wb),
|
|
.alu_in1 (alu_req_if.rs1_data),
|
|
.alu_in2 (alu_req_if.rs2_data),
|
|
|
|
// Outputs
|
|
.wid_out (mul_wid),
|
|
.tmask_out (mul_tmask),
|
|
.PC_out (mul_PC),
|
|
.rd_out (mul_rd),
|
|
.wb_out (mul_wb),
|
|
.data_out (mul_data),
|
|
|
|
// handshake
|
|
.valid_in (mul_valid_in),
|
|
.ready_in (mul_ready_in),
|
|
.valid_out (mul_valid_out),
|
|
.ready_out (mul_ready_out)
|
|
);
|
|
|
|
wire is_mul_op = `INST_ALU_IS_MUL(alu_req_if.op_mod);
|
|
|
|
assign ready_in = is_mul_op ? mul_ready_in : alu_ready_in;
|
|
|
|
assign alu_valid_in = alu_req_if.valid && ~is_mul_op;
|
|
assign mul_valid_in = alu_req_if.valid && is_mul_op;
|
|
|
|
assign alu_commit_if.valid = alu_valid_out || mul_valid_out;
|
|
assign alu_commit_if.wid = alu_valid_out ? alu_wid : mul_wid;
|
|
assign alu_commit_if.tmask = alu_valid_out ? alu_tmask : mul_tmask;
|
|
assign alu_commit_if.PC = alu_valid_out ? alu_PC : mul_PC;
|
|
assign alu_commit_if.rd = alu_valid_out ? alu_rd : mul_rd;
|
|
assign alu_commit_if.wb = alu_valid_out ? alu_wb : mul_wb;
|
|
assign alu_commit_if.data = alu_valid_out ? alu_data : mul_data;
|
|
|
|
assign alu_ready_out = alu_commit_if.ready;
|
|
assign mul_ready_out = alu_commit_if.ready & ~alu_valid_out; // ALU takes priority
|
|
|
|
`else
|
|
|
|
assign ready_in = alu_ready_in;
|
|
|
|
assign alu_valid_in = alu_req_if.valid;
|
|
|
|
assign alu_commit_if.valid = alu_valid_out;
|
|
assign alu_commit_if.wid = alu_wid;
|
|
assign alu_commit_if.tmask = alu_tmask;
|
|
assign alu_commit_if.PC = alu_PC;
|
|
assign alu_commit_if.rd = alu_rd;
|
|
assign alu_commit_if.wb = alu_wb;
|
|
assign alu_commit_if.data = alu_data;
|
|
|
|
assign alu_ready_out = alu_commit_if.ready;
|
|
|
|
`endif
|
|
|
|
assign alu_commit_if.eop = 1'b1;
|
|
|
|
// can accept new request?
|
|
assign alu_req_if.ready = ready_in;
|
|
|
|
`ifdef DBG_PRINT_PIPELINE
|
|
always @(posedge clk) begin
|
|
if (branch_ctl_if.valid) begin
|
|
dpi_trace("%d: core%0d-branch: wid=%0d, PC=%0h, taken=%b, dest=%0h\n",
|
|
$time, CORE_ID, branch_ctl_if.wid, alu_commit_if.PC, branch_ctl_if.taken, branch_ctl_if.dest);
|
|
end
|
|
end
|
|
`endif
|
|
|
|
endmodule |