mirror of
https://github.com/openhwgroup/cva6.git
synced 2025-04-22 05:07:21 -04:00
Complete exception wiring and issuing exceptions
Exceptions are passed through by the issue stage. They count as valid instructions which are already ready for commit.
This commit is contained in:
parent
b757641a49
commit
749762650f
7 changed files with 117 additions and 99 deletions
|
@ -36,7 +36,7 @@ package ariane_pkg;
|
|||
} misspredict;
|
||||
|
||||
typedef enum logic[3:0] {
|
||||
NONE, LSU, ALU, MULT, CSR
|
||||
NONE, LSU, ALU, MULT
|
||||
} fu_t;
|
||||
|
||||
localparam EXC_OFF_RST = 8'h80;
|
||||
|
@ -139,13 +139,6 @@ package ariane_pkg;
|
|||
localparam OPCODE_AUIPC = 7'h17;
|
||||
localparam OPCODE_LUI = 7'h37;
|
||||
|
||||
// --------------------
|
||||
// Immediate select
|
||||
// --------------------
|
||||
typedef enum logic[3:0] {
|
||||
NOIMM, PCIMM, IIMM, SIMM, BIMM, UIMM, JIMM
|
||||
} imm_sel_t;
|
||||
|
||||
// --------------------
|
||||
// Privilege Spec
|
||||
// --------------------
|
||||
|
|
|
@ -118,6 +118,8 @@ module ariane
|
|||
logic [0:0] asid_i;
|
||||
logic flush_tlb_i;
|
||||
|
||||
logic lsu_exception;
|
||||
|
||||
assign id_ready_i = 1'b1;
|
||||
assign halt_if_i = 1'b0;
|
||||
|
||||
|
@ -158,7 +160,7 @@ module ariane
|
|||
.instruction_valid_i ( instr_valid_id_o ),
|
||||
.is_compressed_i ( is_compressed_id_o ),
|
||||
.pc_if_i ( pc_if_o ), // PC from if
|
||||
.ex_i ( exception_if ), // exception from if
|
||||
.ex_if_i ( exception_if ), // exception from if
|
||||
.ready_o ( ready_o ),
|
||||
.operator_o ( operator_o ),
|
||||
.operand_a_o ( operand_a_o ),
|
||||
|
@ -173,6 +175,7 @@ module ariane
|
|||
.mult_valid_o ( ),
|
||||
.trans_id_i ( {alu_trans_id, lsu_trans_id} ),
|
||||
.wdata_i ( {alu_result, lsu_result} ),
|
||||
.ex_ex_i ( {'b0, lsu_exception } ),
|
||||
.wb_valid_i ( {alu_valid_o, lsu_valid_o} ),
|
||||
|
||||
.waddr_a_i ( waddr_a_i ),
|
||||
|
@ -184,29 +187,29 @@ module ariane
|
|||
);
|
||||
|
||||
ex_stage ex_stage_i (
|
||||
.clk_i ( clk_i ),
|
||||
.rst_ni ( rst_n ),
|
||||
.flush_i ( 1'b0 ),
|
||||
.operator_i ( operator_o ),
|
||||
.operand_a_i ( operand_a_o ),
|
||||
.operand_b_i ( operand_b_o ),
|
||||
.imm_i ( imm_o ),
|
||||
.trans_id_i ( trans_id_o ),
|
||||
.comparison_result_o ( comparison_result_o ),
|
||||
.clk_i ( clk_i ),
|
||||
.rst_ni ( rst_n ),
|
||||
.flush_i ( 1'b0 ),
|
||||
.operator_i ( operator_o ),
|
||||
.operand_a_i ( operand_a_o ),
|
||||
.operand_b_i ( operand_b_o ),
|
||||
.imm_i ( imm_o ),
|
||||
.trans_id_i ( trans_id_o ),
|
||||
.comparison_result_o ( comparison_result_o ),
|
||||
|
||||
.alu_ready_o ( alu_ready_i ),
|
||||
.alu_valid_i ( alu_valid_i ),
|
||||
.alu_result_o ( alu_result ),
|
||||
.alu_trans_id_o ( alu_trans_id ),
|
||||
.alu_valid_o ( alu_valid_o ),
|
||||
|
||||
.lsu_ready_o ( lsu_ready_o ),
|
||||
.lsu_valid_i ( lsu_valid_i ),
|
||||
.lsu_result_o ( lsu_result ),
|
||||
.lsu_trans_id_o ( lsu_trans_id ),
|
||||
.lsu_valid_o ( lsu_valid_o ),
|
||||
.lsu_commit_i ( ),
|
||||
.alu_ready_o ( alu_ready_i ),
|
||||
.alu_valid_i ( alu_valid_i ),
|
||||
.alu_result_o ( alu_result ),
|
||||
.alu_trans_id_o ( alu_trans_id ),
|
||||
.alu_valid_o ( alu_valid_o ),
|
||||
|
||||
.lsu_ready_o ( lsu_ready_o ),
|
||||
.lsu_valid_i ( lsu_valid_i ),
|
||||
.lsu_result_o ( lsu_result ),
|
||||
.lsu_trans_id_o ( lsu_trans_id ),
|
||||
.lsu_valid_o ( lsu_valid_o ),
|
||||
.lsu_commit_i ( ),
|
||||
.lsu_exception_o ( lsu_exception ),
|
||||
// memory management
|
||||
.enable_translation_i ( 1'b0 ), // from CSR
|
||||
.fetch_req_i ( fetch_req_i ),
|
||||
|
@ -222,8 +225,8 @@ module ariane
|
|||
.asid_i ( asid_i ), // from CSR
|
||||
.flush_tlb_i ( flush_tlb_i ),
|
||||
|
||||
.mult_ready_o ( mult_ready_o ),
|
||||
.mult_valid_i ( mult_valid_i ),
|
||||
.mult_ready_o ( mult_ready_o ),
|
||||
.mult_valid_i ( mult_valid_i ),
|
||||
.*
|
||||
);
|
||||
|
||||
|
|
|
@ -22,7 +22,12 @@ module decoder (
|
|||
);
|
||||
instruction instr;
|
||||
assign instr = instruction'(instruction_i);
|
||||
imm_sel_t imm_select;
|
||||
// --------------------
|
||||
// Immediate select
|
||||
// --------------------
|
||||
enum logic[3:0] {
|
||||
NOIMM, PCIMM, IIMM, SIMM, BIMM, UIMM, JIMM
|
||||
} imm_select;
|
||||
|
||||
logic [63:0] imm_i_type;
|
||||
logic [63:0] imm_iz_type;
|
||||
|
@ -304,14 +309,17 @@ module decoder (
|
|||
end
|
||||
endcase
|
||||
end
|
||||
|
||||
// --------------------------------
|
||||
// Exception handling
|
||||
// --------------------------------
|
||||
always_comb begin : exception_handling
|
||||
instruction_o.ex = ex_i;
|
||||
|
||||
// look if we didn't already get an exception in any previous
|
||||
// stage - we should not overwrite it as we retain order regarding the exception
|
||||
if (~ex_i.valid && illegal_instr_o) begin
|
||||
instruction_o.ex.valid = 1'b1;
|
||||
// we decoded an illegal exception here
|
||||
instruction_o.ex.cause = ILLEGAL_INSTR;
|
||||
end
|
||||
end
|
||||
|
|
|
@ -46,6 +46,7 @@ module ex_stage #(
|
|||
output logic [63:0] lsu_result_o,
|
||||
output logic [TRANS_ID_BITS-1:0] lsu_trans_id_o,
|
||||
input logic lsu_commit_i,
|
||||
output exception lsu_exception_o,
|
||||
// memory management
|
||||
input logic enable_translation_i,
|
||||
input logic fetch_req_i,
|
||||
|
@ -100,11 +101,8 @@ module ex_stage #(
|
|||
// Multiplication
|
||||
|
||||
// Load-Store Unit
|
||||
exception lsu_exception_o;
|
||||
|
||||
lsu i_lsu (
|
||||
.lsu_trans_id_i ( trans_id_i ),
|
||||
.lsu_exception_o ( lsu_exception_o ), // TODO: exception
|
||||
.commit_i ( lsu_commit_i ),
|
||||
.*
|
||||
);
|
||||
|
|
107
src/id_stage.sv
107
src/id_stage.sv
|
@ -24,8 +24,9 @@ module id_stage #(
|
|||
input logic instruction_valid_i,
|
||||
input logic is_compressed_i,
|
||||
input logic [63:0] pc_if_i,
|
||||
input exception ex_i,
|
||||
output logic ready_o, // id is ready
|
||||
input exception ex_if_i, // we already got an exception in IF
|
||||
|
||||
output logic ready_o, // id is ready
|
||||
output fu_op operator_o,
|
||||
output logic [63:0] operand_a_o,
|
||||
output logic [63:0] operand_b_o,
|
||||
|
@ -43,6 +44,7 @@ module id_stage #(
|
|||
// write back port
|
||||
input logic [NR_WB_PORTS-1:0][TRANS_ID_BITS-1:0] trans_id_i,
|
||||
input logic [NR_WB_PORTS-1:0][63:0] wdata_i,
|
||||
input exception [NR_WB_PORTS-1:0] ex_ex_i, // exception from execute stage
|
||||
input logic [NR_WB_PORTS-1:0] wb_valid_i,
|
||||
// commit port
|
||||
input logic[4:0] waddr_a_i,
|
||||
|
@ -78,7 +80,7 @@ module id_stage #(
|
|||
.pc_i ( pc_if_i ),
|
||||
.is_compressed_i ( is_compressed_i ),
|
||||
.instruction_i ( instruction_i ),
|
||||
.ex_i ( ex_i ),
|
||||
.ex_i ( ex_if_i ),
|
||||
.instruction_o ( decoded_instr_i ),
|
||||
.illegal_instr_o ( illegal_instr_o )
|
||||
);
|
||||
|
@ -89,59 +91,60 @@ module id_stage #(
|
|||
)
|
||||
scoreboard_i
|
||||
(
|
||||
.clk_i (clk_i ),
|
||||
.rst_ni (rst_ni ),
|
||||
.full_o (full_o ),
|
||||
.flush_i (flush_i ),
|
||||
.rd_clobber_o (rd_clobber_o ),
|
||||
.rs1_i (rs1_i ),
|
||||
.rs1_o (rs1_o ),
|
||||
.rs1_valid_o (rs1_valid_o ),
|
||||
.rs2_i (rs2_i ),
|
||||
.rs2_o (rs2_o ),
|
||||
.rs2_valid_o (rs2_valid_o ),
|
||||
.commit_instr_o (commit_instr_o ),
|
||||
.commit_ack_i (commit_ack_i ),
|
||||
.decoded_instr_i (decoded_instr_i ),
|
||||
.decoded_instr_valid_i (instruction_valid_i ),
|
||||
.issue_instr_o (issue_instr_o ),
|
||||
.issue_instr_valid_o (issue_instr_valid_o ),
|
||||
.issue_ack_i (issue_ack_i ),
|
||||
.trans_id_i (trans_id_i ),
|
||||
.wdata_i (wdata_i ),
|
||||
.wb_valid_i (wb_valid_i )
|
||||
.clk_i ( clk_i ),
|
||||
.rst_ni ( rst_ni ),
|
||||
.full_o ( full_o ),
|
||||
.flush_i ( flush_i ),
|
||||
.rd_clobber_o ( rd_clobber_o ),
|
||||
.rs1_i ( rs1_i ),
|
||||
.rs1_o ( rs1_o ),
|
||||
.rs1_valid_o ( rs1_valid_o ),
|
||||
.rs2_i ( rs2_i ),
|
||||
.rs2_o ( rs2_o ),
|
||||
.rs2_valid_o ( rs2_valid_o ),
|
||||
.commit_instr_o ( commit_instr_o ),
|
||||
.commit_ack_i ( commit_ack_i ),
|
||||
.decoded_instr_i ( decoded_instr_i ),
|
||||
.decoded_instr_valid_i ( instruction_valid_i ),
|
||||
.issue_instr_o ( issue_instr_o ),
|
||||
.issue_instr_valid_o ( issue_instr_valid_o ),
|
||||
.issue_ack_i ( issue_ack_i ),
|
||||
.trans_id_i ( trans_id_i ),
|
||||
.wdata_i ( wdata_i ),
|
||||
.ex_i ( ex_ex_i ),
|
||||
.wb_valid_i ( wb_valid_i )
|
||||
);
|
||||
|
||||
|
||||
issue_read_operands issue_read_operands_i (
|
||||
.clk_i (clk_i ),
|
||||
.rst_ni (rst_ni ),
|
||||
.flush_i (flush_i ),
|
||||
.test_en_i (test_en_i ),
|
||||
.issue_instr_i (issue_instr_o ),
|
||||
.issue_instr_valid_i (issue_instr_valid_o),
|
||||
.issue_ack_o (issue_ack_i ),
|
||||
.rs1_o (rs1_i ),
|
||||
.rs1_i (rs1_o ),
|
||||
.rs1_valid_i (rs1_valid_o ),
|
||||
.rs2_o (rs2_i ),
|
||||
.rs2_i (rs2_o ),
|
||||
.rs2_valid_i (rs2_valid_o ),
|
||||
.rd_clobber_i (rd_clobber_o ),
|
||||
.operator_o (operator_o ),
|
||||
.operand_a_o (operand_a_o ),
|
||||
.operand_b_o (operand_b_o ),
|
||||
.imm_o (imm_o ),
|
||||
.trans_id_o (trans_id_o ),
|
||||
.alu_ready_i (alu_ready_i ),
|
||||
.alu_valid_o (alu_valid_o ),
|
||||
.lsu_ready_i (lsu_ready_i ),
|
||||
.lsu_valid_o (lsu_valid_o ),
|
||||
.mult_ready_i (mult_ready_i ),
|
||||
.mult_valid_o (mult_valid_o ),
|
||||
.waddr_a_i (waddr_a_i ),
|
||||
.wdata_a_i (wdata_a_i ),
|
||||
.we_a_i (we_a_i )
|
||||
.clk_i ( clk_i ),
|
||||
.rst_ni ( rst_ni ),
|
||||
.flush_i ( flush_i ),
|
||||
.test_en_i ( test_en_i ),
|
||||
.issue_instr_i ( issue_instr_o ),
|
||||
.issue_instr_valid_i ( issue_instr_valid_o),
|
||||
.issue_ack_o ( issue_ack_i ),
|
||||
.rs1_o ( rs1_i ),
|
||||
.rs1_i ( rs1_o ),
|
||||
.rs1_valid_i ( rs1_valid_o ),
|
||||
.rs2_o ( rs2_i ),
|
||||
.rs2_i ( rs2_o ),
|
||||
.rs2_valid_i ( rs2_valid_o ),
|
||||
.rd_clobber_i ( rd_clobber_o ),
|
||||
.operator_o ( operator_o ),
|
||||
.operand_a_o ( operand_a_o ),
|
||||
.operand_b_o ( operand_b_o ),
|
||||
.imm_o ( imm_o ),
|
||||
.trans_id_o ( trans_id_o ),
|
||||
.alu_ready_i ( alu_ready_i ),
|
||||
.alu_valid_o ( alu_valid_o ),
|
||||
.lsu_ready_i ( lsu_ready_i ),
|
||||
.lsu_valid_o ( lsu_valid_o ),
|
||||
.mult_ready_i ( mult_ready_i ),
|
||||
.mult_valid_o ( mult_valid_o ),
|
||||
.waddr_a_i ( waddr_a_i ),
|
||||
.wdata_a_i ( wdata_a_i ),
|
||||
.we_a_i ( we_a_i )
|
||||
);
|
||||
|
||||
endmodule
|
|
@ -44,8 +44,6 @@ module issue_read_operands (
|
|||
// MULT
|
||||
input logic mult_ready_i, // FU is ready
|
||||
output logic mult_valid_o, // Output is valid
|
||||
// Forward port
|
||||
|
||||
// commit port
|
||||
input logic [4:0] waddr_a_i,
|
||||
input logic [63:0] wdata_a_i,
|
||||
|
@ -81,10 +79,24 @@ module issue_read_operands (
|
|||
issue_ack_o = 1'b0;
|
||||
// check that we didn't stall, that the instruction we got is valid
|
||||
// and that the functional unit we need is not busy
|
||||
if (~stall && issue_instr_valid_i && ~fu_busy) begin
|
||||
// check that the corresponding functional unit is not busy
|
||||
// no other instruction has the same destination register -> fetch the instruction
|
||||
if (rd_clobber_i[issue_instr_i.rd] == NONE) begin
|
||||
if (issue_instr_valid_i) begin
|
||||
if (~stall && ~fu_busy) begin
|
||||
// check that the corresponding functional unit is not busy
|
||||
// no other instruction has the same destination register -> fetch the instruction
|
||||
if (rd_clobber_i[issue_instr_i.rd] == NONE) begin
|
||||
issue_ack_o = 1'b1;
|
||||
end
|
||||
end
|
||||
// we can also issue the instruction under the following two circumstances:
|
||||
// we can do this even if we are stalled or no functional unit is ready (as we don't need one)
|
||||
// the decoder needs to make sure that the instruction is marked as valid when it does not
|
||||
// need any functional unit or if an exception occurred previous to the execute stage.
|
||||
// 1. we already got an exception
|
||||
if (issue_instr_i.ex.valid) begin
|
||||
issue_ack_o = 1'b1;
|
||||
end
|
||||
// 2. it is an instruction which does not need any functional unit
|
||||
if (issue_instr_i.fu == NONE) begin
|
||||
issue_ack_o = 1'b1;
|
||||
end
|
||||
end
|
||||
|
@ -101,8 +113,6 @@ module issue_read_operands (
|
|||
fu_busy = ~mult_ready_i;
|
||||
LSU:
|
||||
fu_busy = ~lsu_ready_i;
|
||||
CSR:
|
||||
fu_busy = 1'b0;
|
||||
default:
|
||||
fu_busy = 1'b0;
|
||||
endcase
|
||||
|
|
|
@ -46,6 +46,7 @@ module scoreboard #(
|
|||
// write-back port
|
||||
input logic [NR_WB_PORTS-1:0][TRANS_ID_BITS-1:0] trans_id_i, // transaction ID at which to write the result back
|
||||
input logic [NR_WB_PORTS-1:0][63:0] wdata_i, // write data in
|
||||
input exception [NR_WB_PORTS-1:0] ex_i, // exception from a functional unit (e.g.: ld/st exception, divide by zero)
|
||||
input logic [NR_WB_PORTS-1:0] wb_valid_i // data in is valid
|
||||
);
|
||||
localparam BITS_ENTRIES = $clog2(NR_ENTRIES);
|
||||
|
@ -135,13 +136,14 @@ always_comb begin : read_operands
|
|||
end
|
||||
|
||||
// provide a direct combinational path from WB a.k.a forwarding
|
||||
// make sure that we are not forwarding a result that got an exception
|
||||
for (int j = 0; j < NR_WB_PORTS; j++) begin
|
||||
if (mem_q[trans_id_i[j]].rd == rs1_i && wb_valid_i[j]) begin
|
||||
if (mem_q[trans_id_i[j]].rd == rs1_i && wb_valid_i[j] && ~ex_i[j].valid) begin
|
||||
rs1_o = wdata_i[j];
|
||||
rs1_valid_o = wb_valid_i[j];
|
||||
break;
|
||||
end
|
||||
if (mem_q[trans_id_i[j]].rd == rs2_i && wb_valid_i[j]) begin
|
||||
if (mem_q[trans_id_i[j]].rd == rs2_i && wb_valid_i[j] && ~ex_i[j].valid) begin
|
||||
rs2_o = wdata_i[j];
|
||||
rs2_valid_o = wb_valid_i[j];
|
||||
break;
|
||||
|
@ -177,6 +179,7 @@ always_comb begin : push_instruction_and_wb
|
|||
if (mem_q[i].trans_id == trans_id_i[j]) begin
|
||||
mem_n[i].valid = 1'b1;
|
||||
mem_n[i].result = wdata_i[j];
|
||||
mem_n[i].ex = ex_i[j];
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue