mirror of
https://github.com/openhwgroup/cva6.git
synced 2025-04-24 06:07:19 -04:00
WIP: Improve interrupt handling
This commit is contained in:
parent
6b74faa0d3
commit
940a586873
3 changed files with 64 additions and 50 deletions
|
@ -20,34 +20,34 @@ import ariane_pkg::*;
|
|||
|
||||
module commit_stage (
|
||||
input logic clk_i,
|
||||
input logic halt_i, // request to halt the core
|
||||
input logic halt_i, // request to halt the core
|
||||
|
||||
output exception exception_o, // take exception to controller
|
||||
output exception exception_o, // take exception to controller
|
||||
|
||||
// from scoreboard
|
||||
input scoreboard_entry commit_instr_i,
|
||||
output logic commit_ack_o,
|
||||
input scoreboard_entry commit_instr_i, // the instruction we want to commit
|
||||
output logic commit_ack_o, // acknowledge that we are indeed committing
|
||||
|
||||
// to register file
|
||||
output logic[4:0] waddr_a_o,
|
||||
output logic[63:0] wdata_a_o,
|
||||
output logic we_a_o,
|
||||
output logic[4:0] waddr_a_o, // register file write address
|
||||
output logic[63:0] wdata_a_o, // register file write data
|
||||
output logic we_a_o, // register file write enable
|
||||
|
||||
// to CSR file and PC Gen (because on certain CSR instructions we'll need to flush the whole pipeline)
|
||||
output logic [63:0] pc_o,
|
||||
// to/from CSR file
|
||||
output fu_op csr_op_o,
|
||||
output logic [63:0] csr_wdata_o,
|
||||
input logic [63:0] csr_rdata_i,
|
||||
input exception csr_exception_i,
|
||||
output fu_op csr_op_o, // decoded CSR operation
|
||||
output logic [63:0] csr_wdata_o, // data to write to CSR
|
||||
input logic [63:0] csr_rdata_i, // data to read from CSR
|
||||
input exception csr_exception_i, // exception or interrupt occurred in CSR stage (the same as commit)
|
||||
// commit signals to ex
|
||||
output logic commit_lsu_o, // commit the pending store
|
||||
input logic commit_lsu_ready_i,
|
||||
input logic no_st_pending_i, // there is no store pending
|
||||
output logic commit_csr_o, // commit the pending CSR instruction
|
||||
output logic fence_i_o, // flush icache and pipeline
|
||||
output logic fence_o, // flush dcache and pipeline
|
||||
output logic sfence_vma_o // flush TLBs and pipeline
|
||||
output logic commit_lsu_o, // commit the pending store
|
||||
input logic commit_lsu_ready_i, // commit buffer of LSU is ready
|
||||
input logic no_st_pending_i, // there is no store pending
|
||||
output logic commit_csr_o, // commit the pending CSR instruction
|
||||
output logic fence_i_o, // flush I$ and pipeline
|
||||
output logic fence_o, // flush D$ and pipeline
|
||||
output logic sfence_vma_o // flush TLBs and pipeline
|
||||
);
|
||||
|
||||
assign waddr_a_o = commit_instr_i.rd;
|
||||
|
@ -152,38 +152,41 @@ module commit_stage (
|
|||
exception_o.valid = 1'b0;
|
||||
exception_o.cause = 64'b0;
|
||||
exception_o.tval = 64'b0;
|
||||
// check for CSR exception
|
||||
if (csr_exception_i.valid && !csr_exception_i.cause[63]) begin
|
||||
exception_o = csr_exception_i;
|
||||
// if no earlier exception happened the commit instruction will still contain
|
||||
// the instruction data from the ID stage. If a earlier exception happened we don't care
|
||||
// as we will overwrite it anyway in the next IF bl
|
||||
exception_o.tval = commit_instr_i.ex.tval;
|
||||
end
|
||||
// but we give precedence to exceptions which happened earlier
|
||||
if (commit_instr_i.ex.valid) begin
|
||||
exception_o = commit_instr_i.ex;
|
||||
end
|
||||
// check for CSR interrupts (e.g.: normal interrupts which get triggered here)
|
||||
// by putting interrupts here we give them precedence over any other exception
|
||||
if (csr_exception_i.valid && csr_exception_i.cause[63]) begin
|
||||
exception_o = csr_exception_i;
|
||||
exception_o.tval = commit_instr_i.ex.tval;
|
||||
// we need a valid instruction in the commit stage, otherwise we might loose the PC in case of interrupts as they
|
||||
// can happen anywhere in the execution flow and might just happen between two legal instructions - the PC would then
|
||||
// be outdated. The solution here is to defer any exception/interrupt until we get a valid PC again (from where we cane
|
||||
// resume execution afterwards).
|
||||
if (commit_instr_i.valid) begin
|
||||
// ------------------------
|
||||
// check for CSR exception
|
||||
// ------------------------
|
||||
if (csr_exception_i.valid && !csr_exception_i.cause[63]) begin
|
||||
exception_o = csr_exception_i;
|
||||
// if no earlier exception happened the commit instruction will still contain
|
||||
// the instruction data from the ID stage. If a earlier exception happened we don't care
|
||||
// as we will overwrite it anyway in the next IF bl
|
||||
exception_o.tval = commit_instr_i.ex.tval;
|
||||
end
|
||||
// ------------------------
|
||||
// Earlier Exceptions
|
||||
// ------------------------
|
||||
// but we give precedence to exceptions which happened earlier
|
||||
if (commit_instr_i.ex.valid) begin
|
||||
exception_o = commit_instr_i.ex;
|
||||
end
|
||||
// ------------------------
|
||||
// Interrupts
|
||||
// ------------------------
|
||||
// check for CSR interrupts (e.g.: normal interrupts which get triggered here)
|
||||
// by putting interrupts here we give them precedence over any other exception
|
||||
if (csr_exception_i.valid && csr_exception_i.cause[63]) begin
|
||||
exception_o = csr_exception_i;
|
||||
exception_o.tval = commit_instr_i.ex.tval;
|
||||
end
|
||||
end
|
||||
// If we halted the processor don't take any exceptions
|
||||
if (halt_i) begin
|
||||
exception_o.valid = 1'b0;
|
||||
end
|
||||
end
|
||||
//-------------
|
||||
// Assertions
|
||||
//-------------
|
||||
`ifndef SYNTHESIS
|
||||
`ifndef VERILATOR
|
||||
// there should never be a grant when there was no request
|
||||
assert property (
|
||||
@(posedge clk_i) (we_a_o) |-> !$isunknown(wdata_a_o[7:0]) )
|
||||
else $warning("You are committing unknown values to the register file");
|
||||
`endif
|
||||
`endif
|
||||
endmodule
|
||||
|
|
|
@ -391,9 +391,9 @@ module csr_regfile #(
|
|||
|
||||
ld_st_priv_lvl_o = (mstatus_q.mprv) ? mstatus_q.mpp : priv_lvl_o;
|
||||
en_ld_st_translation_o = en_ld_st_translation_q;
|
||||
// -----------------------
|
||||
// Return from Exception
|
||||
// -----------------------
|
||||
// ------------------------------
|
||||
// Return from Environment
|
||||
// ------------------------------
|
||||
// When executing an xRET instruction, supposing xPP holds the value y, xIE is set to xPIE; the privilege
|
||||
// mode is changed to y; xPIE is set to 1; and xPP is set to U
|
||||
if (mret) begin
|
||||
|
@ -663,4 +663,16 @@ module csr_regfile #(
|
|||
wfi_q <= wfi_n;
|
||||
end
|
||||
end
|
||||
|
||||
//-------------
|
||||
// Assertions
|
||||
//-------------
|
||||
`ifndef SYNTHESIS
|
||||
`ifndef VERILATOR
|
||||
// check that eret and ex are never valid together
|
||||
assert property (
|
||||
@(posedge clk_i) !(eret_i && ex_valid_i))
|
||||
else $warning("eret and exception should never be valid at the same time");
|
||||
`endif
|
||||
`endif
|
||||
endmodule
|
||||
|
|
|
@ -186,5 +186,4 @@ module pcgen_stage (
|
|||
resolved_branch_q <= resolved_branch_i;
|
||||
end
|
||||
end
|
||||
|
||||
endmodule
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue