mirror of
https://github.com/openhwgroup/cva6.git
synced 2025-04-22 21:27:10 -04:00
Make branch unit a standalone functional unit
This commit is contained in:
parent
4d11e98b82
commit
618767d789
7 changed files with 97 additions and 87 deletions
|
@ -17,7 +17,7 @@ package ariane_pkg;
|
|||
localparam NR_SB_ENTRIES = 4; // number of scoreboard entries
|
||||
localparam TRANS_ID_BITS = $clog2(NR_SB_ENTRIES); // depending on the number of scoreboard entries we need that many bits
|
||||
// to uniquely identify the entry in the scoreboard
|
||||
localparam NR_WB_PORTS = 3;
|
||||
localparam NR_WB_PORTS = 4;
|
||||
localparam ASID_WIDTH = 1;
|
||||
localparam ISA_CODE = (1 << 2) // C - Compressed extension
|
||||
| (1 << 8) // I - RV32I/64I/128I base ISA
|
||||
|
|
|
@ -122,7 +122,6 @@ module ariane
|
|||
fu_op operator_id_ex;
|
||||
logic [63:0] operand_a_id_ex;
|
||||
logic [63:0] operand_b_id_ex;
|
||||
logic [63:0] operand_c_id_ex;
|
||||
logic [63:0] pc_id_ex;
|
||||
logic is_compressed_instr_id_ex;
|
||||
// ALU
|
||||
|
@ -133,7 +132,13 @@ module ariane
|
|||
logic [63:0] alu_result_ex_id;
|
||||
exception alu_exception_ex_id;
|
||||
// Branches and Jumps
|
||||
logic branch_ready_ex_id;
|
||||
logic [TRANS_ID_BITS-1:0] branch_trans_id_ex_id;
|
||||
logic [63:0] branch_result_ex_id;
|
||||
exception branch_exception_ex_id;
|
||||
logic branch_valid_ex_id;
|
||||
logic branch_valid_id_ex;
|
||||
|
||||
branchpredict_sbe branch_predict_id_ex;
|
||||
logic resolve_branch_ex_id;
|
||||
// LSU
|
||||
|
@ -280,7 +285,6 @@ module ariane
|
|||
.operator_o ( operator_id_ex ),
|
||||
.operand_a_o ( operand_a_id_ex ),
|
||||
.operand_b_o ( operand_b_id_ex ),
|
||||
.operand_c_o ( operand_c_id_ex ),
|
||||
.imm_o ( imm_id_ex ),
|
||||
.trans_id_o ( trans_id_id_ex ),
|
||||
.pc_o ( pc_id_ex ),
|
||||
|
@ -289,6 +293,7 @@ module ariane
|
|||
.alu_ready_i ( alu_ready_ex_id ),
|
||||
.alu_valid_o ( alu_valid_id_ex ),
|
||||
// Branches and Jumps
|
||||
.branch_ready_i ( branch_ready_ex_id ),
|
||||
.branch_valid_o ( branch_valid_id_ex ), // branch is valid
|
||||
.branch_predict_o ( branch_predict_id_ex ), // branch predict to ex
|
||||
.resolve_branch_i ( resolve_branch_ex_id ), // in order to resolve the branch
|
||||
|
@ -302,10 +307,10 @@ module ariane
|
|||
.csr_ready_i ( csr_ready_ex_id ),
|
||||
.csr_valid_o ( csr_valid_id_ex ),
|
||||
|
||||
.trans_id_i ( {alu_trans_id_ex_id, lsu_trans_id_ex_id, csr_trans_id_ex_id }),
|
||||
.wdata_i ( {alu_result_ex_id, lsu_result_ex_id, csr_result_ex_id }),
|
||||
.ex_ex_i ( {alu_exception_ex_id, lsu_exception_ex_id, {$bits(exception){1'b0}} }),
|
||||
.wb_valid_i ( {alu_valid_ex_id, lsu_valid_ex_id, csr_valid_ex_id }),
|
||||
.trans_id_i ( {alu_trans_id_ex_id, lsu_trans_id_ex_id, branch_trans_id_ex_id, csr_trans_id_ex_id }),
|
||||
.wdata_i ( {alu_result_ex_id, lsu_result_ex_id, branch_result_ex_id, csr_result_ex_id }),
|
||||
.ex_ex_i ( {{$bits(exception){1'b0}}, lsu_exception_ex_id, branch_exception_ex_id, {$bits(exception){1'b0}} }),
|
||||
.wb_valid_i ( {alu_valid_ex_id, lsu_valid_ex_id, branch_valid_ex_id, csr_valid_ex_id }),
|
||||
|
||||
.waddr_a_i ( waddr_a_commit_id ),
|
||||
.wdata_a_i ( wdata_a_commit_id ),
|
||||
|
@ -325,7 +330,6 @@ module ariane
|
|||
.operator_i ( operator_id_ex ),
|
||||
.operand_a_i ( operand_a_id_ex ),
|
||||
.operand_b_i ( operand_b_id_ex ),
|
||||
.operand_c_i ( operand_c_id_ex ),
|
||||
.imm_i ( imm_id_ex ),
|
||||
.trans_id_i ( trans_id_id_ex ),
|
||||
.pc_i ( pc_id_ex ),
|
||||
|
@ -336,9 +340,14 @@ module ariane
|
|||
.alu_result_o ( alu_result_ex_id ),
|
||||
.alu_trans_id_o ( alu_trans_id_ex_id ),
|
||||
.alu_valid_o ( alu_valid_ex_id ),
|
||||
.alu_exception_o ( alu_exception_ex_id ),
|
||||
.alu_exception_o ( ),
|
||||
// Branches and Jumps
|
||||
.branch_ready_o ( branch_ready_ex_id ),
|
||||
.branch_valid_o ( branch_valid_ex_id ),
|
||||
.branch_valid_i ( branch_valid_id_ex ),
|
||||
.branch_trans_id_o ( branch_trans_id_ex_id ),
|
||||
.branch_result_o ( branch_result_ex_id ),
|
||||
.branch_exception_o ( branch_exception_ex_id ),
|
||||
.branch_predict_i ( branch_predict_id_ex ), // branch predict to ex
|
||||
.resolved_branch_o ( resolved_branch ),
|
||||
.resolve_branch_o ( resolve_branch_ex_id ),
|
||||
|
|
|
@ -20,26 +20,34 @@
|
|||
import ariane_pkg::*;
|
||||
|
||||
module branch_unit (
|
||||
input fu_op operator_i,
|
||||
input logic [63:0] operand_a_i,
|
||||
input logic [63:0] operand_b_i,
|
||||
input logic [63:0] operand_c_i,
|
||||
input logic [63:0] imm_i,
|
||||
input logic [63:0] pc_i,
|
||||
input logic is_compressed_instr_i,
|
||||
input logic fu_valid_i, // any functional unit is valid, check that there is no accidental mis-predict
|
||||
input logic valid_i,
|
||||
input logic [TRANS_ID_BITS-1:0] trans_id_i,
|
||||
input fu_op operator_i, // comparison operation to perform
|
||||
input logic [63:0] operand_a_i, // contains content of RS 1
|
||||
input logic [63:0] operand_b_i, // contains content of RS 2
|
||||
input logic [63:0] imm_i, // immediate to add to PC
|
||||
input logic [63:0] pc_i, // PC of instruction
|
||||
input logic is_compressed_instr_i,
|
||||
input logic fu_valid_i, // any functional unit is valid, check that there is no accidental mis-predict
|
||||
input logic branch_valid_i,
|
||||
output logic branch_ready_o,
|
||||
output logic branch_valid_o,
|
||||
output logic [63:0] branch_result_o,
|
||||
output logic [TRANS_ID_BITS-1:0] branch_trans_id_o,
|
||||
|
||||
input branchpredict_sbe branch_predict_i, // this is the address we predicted
|
||||
output branchpredict resolved_branch_o, // this is the actual address we are targeting
|
||||
output logic resolve_branch_o, // to ID to clear that we resolved the branch and we can
|
||||
// accept new entries to the scoreboard
|
||||
output exception branch_ex_o // branch exception out
|
||||
input branchpredict_sbe branch_predict_i, // this is the address we predicted
|
||||
output branchpredict resolved_branch_o, // this is the actual address we are targeting
|
||||
output logic resolve_branch_o, // to ID to clear that we resolved the branch and we can
|
||||
// accept new entries to the scoreboard
|
||||
output exception branch_exception_o // branch exception out
|
||||
);
|
||||
logic [63:0] target_address;
|
||||
logic [63:0] next_pc;
|
||||
logic comparison_result; // result of comparison
|
||||
logic sgn; // sign extend
|
||||
// branches are single cycle at the moment, feed-through the control signals
|
||||
assign branch_trans_id_o = trans_id_i;
|
||||
assign branch_valid_o = branch_valid_i;
|
||||
assign branch_ready_o = 1'b1; // we are always ready
|
||||
|
||||
always_comb begin : branch_resolve
|
||||
// by default e.g.: when this is a jump, the branch is taken
|
||||
|
@ -66,16 +74,18 @@ module branch_unit (
|
|||
resolved_branch_o.pc = 64'b0;
|
||||
resolved_branch_o.target_address = 64'b0;
|
||||
resolved_branch_o.is_taken = 1'b0;
|
||||
resolved_branch_o.valid = valid_i;
|
||||
resolved_branch_o.valid = branch_valid_i;
|
||||
resolved_branch_o.is_mispredict = 1'b0;
|
||||
resolved_branch_o.is_lower_16 = 1'b0;
|
||||
resolve_branch_o = 1'b0;
|
||||
// calculate next PC, depending on whether the instruction is compressed or not this may be different
|
||||
next_pc = pc_i + ((is_compressed_instr_i) ? 64'h2 : 64'h4);
|
||||
// calculate target address simple 64 bit addition
|
||||
target_address = $unsigned($signed(operand_c_i) + $signed(imm_i));
|
||||
target_address = $unsigned($signed(pc_i) + $signed(imm_i));
|
||||
// if we need to put the branch target address in a destination register, output it here to WB
|
||||
branch_result_o = target_address;
|
||||
|
||||
if (valid_i) begin
|
||||
if (branch_valid_i) begin
|
||||
// save PC - we need this to get the target row in the branch target buffer
|
||||
// we play this trick with the branch instruction which wraps a byte boundary:
|
||||
// |---------- Place the prediction on this PC
|
||||
|
@ -118,11 +128,11 @@ module branch_unit (
|
|||
// use ALU exception signal for storing instruction fetch exceptions if
|
||||
// the target address is not aligned to a 2 byte boundary
|
||||
always_comb begin : exception_handling
|
||||
branch_ex_o.cause = INSTR_ADDR_MISALIGNED;
|
||||
branch_ex_o.valid = 1'b0;
|
||||
branch_ex_o.tval = pc_i;
|
||||
branch_exception_o.cause = INSTR_ADDR_MISALIGNED;
|
||||
branch_exception_o.valid = 1'b0;
|
||||
branch_exception_o.tval = pc_i;
|
||||
// only throw exception if this is indeed a branch
|
||||
if (valid_i && target_address[0] != 1'b0)
|
||||
branch_ex_o.valid = 1'b1;
|
||||
if (branch_valid_i && target_address[0] != 1'b0)
|
||||
branch_exception_o.valid = 1'b1;
|
||||
end
|
||||
endmodule
|
|
@ -362,18 +362,14 @@ module decoder (
|
|||
// Jump and link register
|
||||
OPCODE_JALR: begin
|
||||
instruction_o.fu = CTRL_FLOW;
|
||||
instruction_o.op = JALR;
|
||||
imm_select = UIMM;
|
||||
instruction_o.use_pc = 1'b1;
|
||||
instruction_o.rd = instr.itype.rd;
|
||||
is_control_flow_instr_o = 1'b1;
|
||||
end
|
||||
// Jump and link
|
||||
OPCODE_JAL: begin
|
||||
instruction_o.fu = CTRL_FLOW;
|
||||
instruction_o.op = JAL;
|
||||
imm_select = JIMM;
|
||||
instruction_o.use_pc = 1'b1;
|
||||
instruction_o.rd = instr.utype.rd;
|
||||
is_control_flow_instr_o = 1'b1;
|
||||
end
|
||||
|
|
|
@ -30,7 +30,6 @@ module ex_stage #(
|
|||
input fu_op operator_i,
|
||||
input logic [63:0] operand_a_i,
|
||||
input logic [63:0] operand_b_i,
|
||||
input logic [63:0] operand_c_i,
|
||||
input logic [63:0] imm_i,
|
||||
input logic [TRANS_ID_BITS-1:0] trans_id_i,
|
||||
input logic [63:0] pc_i, // PC of current instruction
|
||||
|
@ -44,8 +43,14 @@ module ex_stage #(
|
|||
output logic [TRANS_ID_BITS-1:0] alu_trans_id_o, // ID of scoreboard entry at which to write back
|
||||
output exception alu_exception_o,
|
||||
// Branches and Jumps
|
||||
output logic branch_ready_o,
|
||||
input logic branch_valid_i, // we are using the branch unit
|
||||
output logic branch_valid_o, // the calculated branch target is valid
|
||||
output logic [63:0] branch_result_o, // branch target address out
|
||||
input branchpredict_sbe branch_predict_i, // branch prediction in
|
||||
output logic [TRANS_ID_BITS-1:0] branch_trans_id_o,
|
||||
output exception branch_exception_o, // branch unit detected an exception
|
||||
|
||||
output branchpredict resolved_branch_o, // the branch engine uses the write back from the ALU
|
||||
output logic resolve_branch_o, // to ID signaling that we resolved the branch
|
||||
// LSU
|
||||
|
@ -116,8 +121,6 @@ module ex_stage #(
|
|||
// --------------------
|
||||
branch_unit branch_unit_i (
|
||||
.fu_valid_i ( alu_valid_i | lsu_valid_i | csr_valid_i ), // any functional unit is valid, check that there is no accidental mis-predict
|
||||
.valid_i ( branch_valid_i ),
|
||||
.branch_ex_o ( alu_exception_o ), // we use the ALU exception WB for the branch exception
|
||||
.*
|
||||
);
|
||||
|
||||
|
|
|
@ -42,7 +42,6 @@ module id_stage #(
|
|||
output fu_op operator_o,
|
||||
output logic [63:0] operand_a_o,
|
||||
output logic [63:0] operand_b_o,
|
||||
output logic [63:0] operand_c_o,
|
||||
output logic [63:0] imm_o,
|
||||
output logic [TRANS_ID_BITS-1:0] trans_id_o,
|
||||
output logic [63:0] pc_o,
|
||||
|
@ -50,16 +49,18 @@ module id_stage #(
|
|||
|
||||
input logic alu_ready_i,
|
||||
output logic alu_valid_o,
|
||||
output logic branch_valid_o, // use branch prediction unit
|
||||
// ex just resolved our predicted branch, we are ready to accept new requests
|
||||
input logic resolve_branch_i,
|
||||
|
||||
input logic lsu_ready_i,
|
||||
output logic lsu_valid_o,
|
||||
// branch prediction
|
||||
input logic branch_ready_i,
|
||||
output logic branch_valid_o, // use branch prediction unit
|
||||
output branchpredict_sbe branch_predict_o,
|
||||
|
||||
input logic mult_ready_i,
|
||||
output logic mult_valid_o, // Branch predict Out
|
||||
output branchpredict_sbe branch_predict_o,
|
||||
|
||||
input logic csr_ready_i,
|
||||
output logic csr_valid_o,
|
||||
|
|
|
@ -43,7 +43,6 @@ module issue_read_operands (
|
|||
output fu_op operator_o,
|
||||
output logic [63:0] operand_a_o,
|
||||
output logic [63:0] operand_b_o,
|
||||
output logic [63:0] operand_c_o,
|
||||
output logic [63:0] imm_o, // output immediate for the LSU
|
||||
output logic [TRANS_ID_BITS-1:0] trans_id_o,
|
||||
output logic [63:0] pc_o,
|
||||
|
@ -52,6 +51,7 @@ module issue_read_operands (
|
|||
input logic alu_ready_i, // FU is ready
|
||||
output logic alu_valid_o, // Output is valid
|
||||
// Branches and Jumps
|
||||
input logic branch_ready_i,
|
||||
output logic branch_valid_o, // this is a valid branch instruction
|
||||
output branchpredict_sbe branch_predict_o,
|
||||
// LSU
|
||||
|
@ -75,7 +75,6 @@ module issue_read_operands (
|
|||
// output flipflop (ID <-> EX)
|
||||
logic [63:0] operand_a_n, operand_a_q,
|
||||
operand_b_n, operand_b_q,
|
||||
operand_c_n, operand_c_q,
|
||||
imm_n, imm_q;
|
||||
|
||||
logic alu_valid_n, alu_valid_q;
|
||||
|
@ -93,7 +92,6 @@ module issue_read_operands (
|
|||
// ID <-> EX registers
|
||||
assign operand_a_o = operand_a_q;
|
||||
assign operand_b_o = operand_b_q;
|
||||
assign operand_c_o = operand_c_q;
|
||||
assign fu_o = fu_q;
|
||||
assign operator_o = operator_q;
|
||||
assign alu_valid_o = alu_valid_q;
|
||||
|
@ -148,9 +146,10 @@ module issue_read_operands (
|
|||
unique case (issue_instr_i.fu)
|
||||
NONE:
|
||||
fu_busy = 1'b0;
|
||||
ALU, CTRL_FLOW: // control flow instruction also need the ALU
|
||||
// and they are always ready if the ALU is ready
|
||||
ALU:
|
||||
fu_busy = ~alu_ready_i;
|
||||
CTRL_FLOW:
|
||||
fu_busy = ~branch_ready_i;
|
||||
MULT:
|
||||
fu_busy = ~mult_ready_i;
|
||||
LOAD, STORE:
|
||||
|
@ -201,8 +200,6 @@ module issue_read_operands (
|
|||
// default is regfile
|
||||
operand_a_n = operand_a_regfile;
|
||||
operand_b_n = operand_b_regfile;
|
||||
// set PC as default operand c
|
||||
operand_c_n = issue_instr_i.pc;
|
||||
// immediates are the third operands in the store case
|
||||
imm_n = issue_instr_i.result;
|
||||
trans_id_n = issue_instr_i.trans_id;
|
||||
|
@ -227,34 +224,34 @@ module issue_read_operands (
|
|||
// zero extend operand a
|
||||
operand_a_n = {52'b0, issue_instr_i.rs1};
|
||||
end
|
||||
// or is it an immediate (including PC), this is not the case for a store
|
||||
if (issue_instr_i.use_imm && (issue_instr_i.fu != STORE)) begin
|
||||
// or is it an immediate (including PC), this is not the case for a store and control flow instructions
|
||||
if (issue_instr_i.use_imm && (issue_instr_i.fu != STORE) && (issue_instr_i.fu != CTRL_FLOW)) begin
|
||||
operand_b_n = issue_instr_i.result;
|
||||
end
|
||||
// special assignments in the JAL and JALR case
|
||||
case (issue_instr_i.op)
|
||||
// re-write the operator since
|
||||
// we need the ALU for addition
|
||||
JAL: begin
|
||||
operator_n = ADD;
|
||||
// output 4 as operand b as we
|
||||
// need to save PC + 4 or in case of a compressed instruction PC + 4
|
||||
operand_b_n = (issue_instr_i.is_compressed) ? 64'h2 : 64'h4;
|
||||
end
|
||||
// // special assignments in the JAL and JALR case
|
||||
// case (issue_instr_i.op)
|
||||
// // re-write the operator since
|
||||
// // we need the ALU for addition
|
||||
// JAL: begin
|
||||
// operator_n = ADD;
|
||||
// // output 4 as operand b as we
|
||||
// // need to save PC + 4 or in case of a compressed instruction PC + 4
|
||||
// operand_b_n = (issue_instr_i.is_compressed) ? 64'h2 : 64'h4;
|
||||
// end
|
||||
|
||||
JALR: begin
|
||||
operator_n = ADD;
|
||||
// output 4 as operand b as we
|
||||
// need to save PC + 4 or in case of a compressed instruction PC + 4
|
||||
operand_b_n = (issue_instr_i.is_compressed) ? 64'h2 : 64'h4;
|
||||
// get RS1 as operand C
|
||||
operand_c_n = operand_a_regfile;
|
||||
// forward rs1
|
||||
if (forward_rs1) begin
|
||||
operand_c_n = rs1_i;
|
||||
end
|
||||
end
|
||||
endcase
|
||||
// JALR: begin
|
||||
// operator_n = ADD;
|
||||
// // output 4 as operand b as we
|
||||
// // need to save PC + 4 or in case of a compressed instruction PC + 4
|
||||
// operand_b_n = (issue_instr_i.is_compressed) ? 64'h2 : 64'h4;
|
||||
// // get RS1 as operand C
|
||||
// operand_c_n = operand_a_regfile;
|
||||
// // forward rs1
|
||||
// if (forward_rs1) begin
|
||||
// operand_c_n = rs1_i;
|
||||
// end
|
||||
// end
|
||||
// endcase
|
||||
end
|
||||
// FU select, assert the correct valid out signal (in the next cycle)
|
||||
always_comb begin : unit_valid
|
||||
|
@ -269,20 +266,16 @@ module issue_read_operands (
|
|||
if (~issue_instr_i.ex.valid && issue_instr_valid_i && issue_ack_o) begin
|
||||
case (issue_instr_i.fu)
|
||||
ALU:
|
||||
alu_valid_n = 1'b1;
|
||||
MULT:
|
||||
mult_valid_n = 1'b1;
|
||||
LOAD, STORE:
|
||||
lsu_valid_n = 1'b1;
|
||||
CSR:
|
||||
csr_valid_n = 1'b1;
|
||||
CTRL_FLOW: begin
|
||||
alu_valid_n = 1'b1;
|
||||
CTRL_FLOW:
|
||||
branch_valid_n = 1'b1;
|
||||
end
|
||||
default: begin
|
||||
|
||||
end
|
||||
MULT:
|
||||
mult_valid_n = 1'b1;
|
||||
LOAD, STORE:
|
||||
lsu_valid_n = 1'b1;
|
||||
CSR:
|
||||
csr_valid_n = 1'b1;
|
||||
default:;
|
||||
endcase
|
||||
end
|
||||
// if we got a flush request, de-assert the valid flag, otherwise we will start this
|
||||
|
@ -326,7 +319,6 @@ module issue_read_operands (
|
|||
if(~rst_ni) begin
|
||||
operand_a_q <= '{default: 0};
|
||||
operand_b_q <= '{default: 0};
|
||||
operand_c_q <= '{default: 0};
|
||||
imm_q <= 64'b0;
|
||||
alu_valid_q <= 1'b0;
|
||||
branch_valid_q <= 1'b0;
|
||||
|
@ -342,7 +334,6 @@ module issue_read_operands (
|
|||
end else begin
|
||||
operand_a_q <= operand_a_n;
|
||||
operand_b_q <= operand_b_n;
|
||||
operand_c_q <= operand_c_n;
|
||||
imm_q <= imm_n;
|
||||
alu_valid_q <= alu_valid_n;
|
||||
branch_valid_q <= branch_valid_n;
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue