mirror of
https://github.com/openhwgroup/cva6.git
synced 2025-04-22 05:07:21 -04:00
[WIP] Implement exception handling
This commit is contained in:
parent
00b11efc6f
commit
4d7b9a1b75
8 changed files with 121 additions and 49 deletions
|
@ -223,9 +223,9 @@ package ariane_pkg;
|
|||
localparam LD_ACCESS_FAULT = 64'h5;
|
||||
localparam ST_ADDR_MISALIGNED = 64'h6;
|
||||
localparam ST_ACCESS_FAULT = 64'h7;
|
||||
localparam ENV_CALL_UMODE = 64'h8;
|
||||
localparam ENV_CALL_SMODE = 64'h9;
|
||||
localparam ENV_CALL_MMODE = 64'hB;
|
||||
localparam ENV_CALL_UMODE = 64'h8; // environment call from user mode
|
||||
localparam ENV_CALL_SMODE = 64'h9; // environment call from supvervisor mode
|
||||
localparam ENV_CALL_MMODE = 64'hB; // environment call from machine mode
|
||||
|
||||
typedef enum logic [11:0] {
|
||||
CSR_SSTATUS = 12'h100,
|
||||
|
|
|
@ -205,6 +205,9 @@ module ariane
|
|||
logic flush_unissued_instr_ctrl_id;
|
||||
logic flush_scoreboard_ctrl_id;
|
||||
logic flush_ctrl_if;
|
||||
logic flush_ctrl_id;
|
||||
logic flush_controller_ex;
|
||||
|
||||
|
||||
// TODO: Preliminary signal assignments
|
||||
logic flush_tlb;
|
||||
|
@ -271,6 +274,7 @@ module ariane
|
|||
.decoded_instr_ack_o ( decode_ack_id_if ),
|
||||
.ex_if_i ( exception_if_id ), // exception from if
|
||||
.ready_o ( ready_id_if ),
|
||||
.priv_lvl_i ( priv_lvl ),
|
||||
// Functional Units
|
||||
.operator_o ( operator_id_ex ),
|
||||
.operand_a_o ( operand_a_id_ex ),
|
||||
|
@ -424,19 +428,15 @@ module ariane
|
|||
// ------------
|
||||
// Controller
|
||||
// ------------
|
||||
logic flush_commit_i;
|
||||
logic flush_controller_ex;
|
||||
|
||||
controller controller_i (
|
||||
.flush_bp_o ( ),
|
||||
.flush_scoreboard_o ( flush_scoreboard_ctrl_id ),
|
||||
.flush_unissued_instr_o ( flush_unissued_instr_ctrl_id ),
|
||||
.flush_if_o ( flush_ctrl_if ),
|
||||
.flush_id_o ( ),
|
||||
.flush_id_o ( flush_ctrl_id ),
|
||||
.flush_ex_o ( flush_controller_ex ),
|
||||
|
||||
.flush_ready_lsu_i ( ),
|
||||
.flush_commit_i ( flush_commit_i ),
|
||||
.ex_i ( ex_commit ),
|
||||
.flush_csr_i ( flush_csr_ctrl ),
|
||||
.resolved_branch_i ( resolved_branch ),
|
||||
.*
|
||||
|
@ -449,23 +449,23 @@ module ariane
|
|||
instruction_tracer_if tracer_if (clk_i);
|
||||
// assign instruction tracer interface
|
||||
// control signals
|
||||
assign tracer_if.rstn = rst_ni;
|
||||
assign tracer_if.rstn = rst_ni;
|
||||
assign tracer_if.flush_unissued = flush_unissued_instr_ctrl_id;
|
||||
assign tracer_if.flush = flush_controller_ex;
|
||||
// fetch
|
||||
assign tracer_if.fetch = fetch_entry_if_id;
|
||||
assign tracer_if.fetch_valid = fetch_valid_if_id;
|
||||
assign tracer_if.fetch_ack = decode_ack_id_if;
|
||||
assign tracer_if.fetch = fetch_entry_if_id;
|
||||
assign tracer_if.fetch_valid = fetch_valid_if_id;
|
||||
assign tracer_if.fetch_ack = decode_ack_id_if;
|
||||
// Issue
|
||||
assign tracer_if.issue_ack = id_stage_i.scoreboard_i.issue_ack_i;
|
||||
assign tracer_if.issue_sbe = id_stage_i.scoreboard_i.issue_instr_o;
|
||||
assign tracer_if.issue_ack = id_stage_i.scoreboard_i.issue_ack_i;
|
||||
assign tracer_if.issue_sbe = id_stage_i.scoreboard_i.issue_instr_o;
|
||||
// write-back
|
||||
assign tracer_if.waddr = waddr_a_commit_id;
|
||||
assign tracer_if.wdata = wdata_a_commit_id;
|
||||
assign tracer_if.we = we_a_commit_id;
|
||||
assign tracer_if.waddr = waddr_a_commit_id;
|
||||
assign tracer_if.wdata = wdata_a_commit_id;
|
||||
assign tracer_if.we = we_a_commit_id;
|
||||
// commit
|
||||
assign tracer_if.commit_instr = commit_instr_id_commit;
|
||||
assign tracer_if.commit_ack = commit_ack_commit_id;
|
||||
assign tracer_if.commit_instr = commit_instr_id_commit;
|
||||
assign tracer_if.commit_ack = commit_ack_commit_id;
|
||||
|
||||
program instr_tracer (instruction_tracer_if tracer_if);
|
||||
instruction_tracer it = new (tracer_if);
|
||||
|
|
|
@ -19,8 +19,8 @@
|
|||
import ariane_pkg::*;
|
||||
|
||||
module commit_stage (
|
||||
input logic clk_i, // Clock
|
||||
input logic rst_ni, // Asynchronous reset active low
|
||||
input logic clk_i, // Clock
|
||||
input logic rst_ni, // Asynchronous reset active low
|
||||
|
||||
output exception exception_o, // take exception to controller
|
||||
|
||||
|
@ -39,9 +39,9 @@ module commit_stage (
|
|||
output logic [63:0] csr_wdata_o,
|
||||
input logic [63:0] csr_rdata_i,
|
||||
input exception csr_exception_i,
|
||||
// to ex
|
||||
output logic commit_lsu_o,
|
||||
output logic commit_csr_o,
|
||||
// commit signals to ex
|
||||
output logic commit_lsu_o, // commit the pending store
|
||||
output logic commit_csr_o, // commit the pending CSR instruction
|
||||
// general control signal
|
||||
input logic [4:0] irq_enable_i
|
||||
);
|
||||
|
|
|
@ -23,30 +23,61 @@ module controller (
|
|||
input logic clk_i, // Clock
|
||||
input logic rst_ni, // Asynchronous reset active low
|
||||
|
||||
output logic flush_bp_o, // flush branch prediction data structures
|
||||
output logic flush_unissued_instr_o,
|
||||
output logic flush_scoreboard_o,
|
||||
output logic flush_if_o,
|
||||
output logic flush_id_o,
|
||||
output logic flush_ex_o,
|
||||
output logic flush_bp_o, // flush branch prediction data structures
|
||||
output logic flush_if_o, // flush the IF stage
|
||||
output logic flush_unissued_instr_o, // flush un-issued instructions of the scoreboard
|
||||
output logic flush_scoreboard_o, // flush the whole scoreboard
|
||||
output logic flush_id_o, // flush ID stage
|
||||
output logic flush_ex_o, // flush EX stage
|
||||
|
||||
input logic flush_ready_lsu_i, // we need to wait for this signal from LSU
|
||||
input logic flush_commit_i, // flush request from commit stage in
|
||||
input logic flush_csr_i,
|
||||
input branchpredict resolved_branch_i
|
||||
input exception ex_i, // we got an exception, flush the pipeline
|
||||
input branchpredict resolved_branch_i, // we got a resolved branch, check if we need to flush the front-end
|
||||
input logic flush_csr_i // we got an instruction which altered the CSR, flush the pipeline
|
||||
);
|
||||
// flush branch prediction
|
||||
assign flush_bp_o = 1'b0;
|
||||
|
||||
// ------------
|
||||
// Flush CTRL
|
||||
// ------------
|
||||
always_comb begin : flush_ctrl
|
||||
flush_if_o = 1'b0;
|
||||
flush_unissued_instr_o = 1'b0;
|
||||
flush_scoreboard_o = 1'b0;
|
||||
flush_if_o = 1'b0;
|
||||
flush_id_o = 1'b0;
|
||||
flush_ex_o = 1'b0;
|
||||
|
||||
// ------------
|
||||
// Mis-predict
|
||||
// ------------
|
||||
// flush on mispredict
|
||||
if (resolved_branch_i.is_mispredict) begin
|
||||
// flush only un-issued instructions
|
||||
flush_unissued_instr_o = 1'b1;
|
||||
// and if stage
|
||||
flush_if_o = 1'b1;
|
||||
end
|
||||
|
||||
// ------------
|
||||
// Exception
|
||||
// ------------
|
||||
if (ex_i.valid) begin
|
||||
flush_if_o = 1'b1;
|
||||
flush_scoreboard_o = 1'b1;
|
||||
flush_id_o = 1'b1;
|
||||
flush_ex_o = 1'b1;
|
||||
end
|
||||
|
||||
// ---------------------------------
|
||||
// CSR instruction with side-effect
|
||||
// ---------------------------------
|
||||
if (flush_csr_i) begin
|
||||
flush_if_o = 1'b1;
|
||||
flush_scoreboard_o = 1'b1;
|
||||
flush_id_o = 1'b1;
|
||||
flush_ex_o = 1'b1;
|
||||
end
|
||||
|
||||
end
|
||||
// flush on exception
|
||||
endmodule
|
||||
|
|
|
@ -165,6 +165,7 @@ module csr_regfile #(
|
|||
// CSR Write and update logic
|
||||
// ---------------------------
|
||||
always_comb begin : csr_update
|
||||
flush_o = 1'b0;
|
||||
update_access_exception = 1'b0;
|
||||
|
||||
priv_lvl_n = priv_lvl_q;
|
||||
|
@ -233,6 +234,8 @@ module csr_regfile #(
|
|||
CSR_MTVAL: mtval_n = csr_wdata;
|
||||
default: update_access_exception = 1'b1;
|
||||
endcase
|
||||
// TODO: this is unnecessary
|
||||
flush_o = 1'b1;
|
||||
end else begin
|
||||
update_access_exception = 1'b1;
|
||||
end
|
||||
|
|
|
@ -18,10 +18,15 @@ module decoder (
|
|||
input logic [31:0] instruction_i, // instruction from IF
|
||||
input branchpredict_sbe branch_predict_i,
|
||||
input exception ex_i, // if an exception occured in if
|
||||
input priv_lvl_t priv_lvl_i, // current privilege level
|
||||
output scoreboard_entry instruction_o, // scoreboard entry to scoreboard
|
||||
output logic is_control_flow_instr_o // this instruction will change the control flow
|
||||
);
|
||||
logic illegal_instr;
|
||||
// this instruction is an environment call (ecall), it is handled like an exception
|
||||
logic ecall;
|
||||
// this instruction is a software break-point
|
||||
logic ebreak;
|
||||
instruction instr;
|
||||
assign instr = instruction'(instruction_i);
|
||||
// --------------------
|
||||
|
@ -60,6 +65,8 @@ module decoder (
|
|||
instruction_o.is_compressed = is_compressed_i;
|
||||
instruction_o.use_zimm = 1'b0;
|
||||
instruction_o.bp = branch_predict_i;
|
||||
ecall = 1'b0;
|
||||
ebreak = 1'b0;
|
||||
|
||||
if (~ex_i.valid) begin
|
||||
case (instr.rtype.opcode)
|
||||
|
@ -70,10 +77,32 @@ module decoder (
|
|||
|
||||
unique case (instr.itype.funct3)
|
||||
3'b000: begin
|
||||
// TODO:
|
||||
// ECALL, EBREAK, SFEBCE.VM
|
||||
// MRET/SRET/URET, WFI
|
||||
illegal_instr = 1'b1;
|
||||
case (instr.itype.imm)
|
||||
// ECALL
|
||||
12'b0: ecall = 1'b1;
|
||||
// EBREAK:
|
||||
12'b1: ebreak = 1'b1;
|
||||
|
||||
// URET
|
||||
// 12'b10: ;
|
||||
|
||||
// SRET
|
||||
// 12'b100000010:;
|
||||
|
||||
// MRET
|
||||
// 12'b1100000010:;
|
||||
|
||||
// WFI
|
||||
// 12'b1_0000_0101:;
|
||||
// SFENCE.VMA
|
||||
default: begin
|
||||
// if (instr.itype.imm[11:5] == 7'b1001) begin
|
||||
//
|
||||
// end else begin
|
||||
illegal_instr = 1'b1;
|
||||
// end
|
||||
end
|
||||
endcase
|
||||
end
|
||||
// atomically swaps values in the CSR and integer register
|
||||
3'b001: begin// CSRRW
|
||||
|
@ -408,15 +437,24 @@ module decoder (
|
|||
instruction_o.valid = 1'b0;
|
||||
// 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) begin
|
||||
if (~ex_i.valid) begin
|
||||
// instructions which will throw an exception are marked as valid
|
||||
// e.g.: they can be committed anytime and do not need to wait for any functional unit
|
||||
instruction_o.valid = 1'b1;
|
||||
instruction_o.ex.valid = 1'b1;
|
||||
// we decoded an illegal exception here
|
||||
instruction_o.ex.cause = ILLEGAL_INSTR;
|
||||
// if we decoded an illegal instruction save the faulting instruction to tval
|
||||
instruction_o.ex.tval = instruction_i;
|
||||
if (illegal_instr) begin
|
||||
instruction_o.valid = 1'b1;
|
||||
instruction_o.ex.valid = 1'b1;
|
||||
// we decoded an illegal exception here
|
||||
instruction_o.ex.cause = ILLEGAL_INSTR;
|
||||
// if we decoded an illegal instruction save the faulting instruction to tval
|
||||
instruction_o.ex.tval = instruction_i;
|
||||
// we got an ecall, set the correct cause depending on the current privilege level
|
||||
end else if (ecall) begin
|
||||
case (priv_lvl_i) begin
|
||||
|
||||
endcase
|
||||
end else if (ebreak) begin
|
||||
|
||||
end
|
||||
end
|
||||
end
|
||||
endmodule
|
|
@ -35,6 +35,8 @@ module id_stage #(
|
|||
input logic fetch_entry_valid_i,
|
||||
output logic decoded_instr_ack_o,
|
||||
input exception ex_if_i, // we already got an exception in IF
|
||||
// from CSR file
|
||||
input priv_lvl_t priv_lvl_i, // current privilege level
|
||||
|
||||
output logic ready_o, // id is ready
|
||||
output fu_op operator_o,
|
||||
|
|
|
@ -21,5 +21,3 @@ add wave -noupdate -group ex_stage /core_tb/dut/ex_stage_i/*
|
|||
add wave -noupdate -group commit_stage /core_tb/dut/commit_stage_i/*
|
||||
add wave -noupdate -group csr_file /core_tb/dut/csr_regfile_i/*
|
||||
add wave -noupdate -group controller /core_tb/dut/controller_i/*
|
||||
|
||||
TreeUpdate [SetDefaultTree]
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue