Make branch unit a standalone functional unit

This commit is contained in:
Florian Zaruba 2017-06-03 16:08:11 +02:00
parent 4d11e98b82
commit 618767d789
7 changed files with 97 additions and 87 deletions

View file

@ -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

View file

@ -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 ),

View file

@ -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

View file

@ -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

View file

@ -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
.*
);

View file

@ -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,

View file

@ -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;