Fix bug where an IRQ can fire during load/store dphase, followed by dphase bus exception.
Result was that the exception would sample the IRQ vector PC rather than the load/store instruction PC. Fix by fencing off on in-flight dphases before asserting the IRQ. This adds a cycle of jitter to IRQs, but is required for correct operation without adding a full exception-gathering pipeline.
This commit is contained in:
parent
dbc331dbb4
commit
449348f459
|
@ -5,7 +5,7 @@ The RISC-V privileged specification affords flexibility as to which CSRs are imp
|
||||||
All CSRs are 32-bit; MXLEN is fixed at 32 bits on Hazard3. All CSR addresses not listed in this section are unimplemented. Accessing an unimplemented CSR will cause an illegal instruction exception (`mcause` = 2). This includes all U-mode and S-mode CSRs.
|
All CSRs are 32-bit; MXLEN is fixed at 32 bits on Hazard3. All CSR addresses not listed in this section are unimplemented. Accessing an unimplemented CSR will cause an illegal instruction exception (`mcause` = 2). This includes all U-mode and S-mode CSRs.
|
||||||
|
|
||||||
|
|
||||||
IMPORTANT: The https://github.com/riscv/riscv-isa-manual/releases/download/Ratified-IMFDQC-and-Priv-v1.11/riscv-privileged-20190608.pdf[RISC-V Privileged Specification] should be your primary reference for writing software to run on Hazard3. This section specifies those details which are left implementation-defined by the RISC-V Privileged Specification, for sake of completeness, but portable RISC-V software should not rely on these details.
|
IMPORTANT: The https://github.com/riscv/riscv-isa-manual/releases/download/Priv-v1.12/riscv-privileged-20211203.pdf[RISC-V Privileged Specification] should be your primary reference for writing software to run on Hazard3. This section specifies those details which are left implementation-defined by the RISC-V Privileged Specification, for sake of completeness, but portable RISC-V software should not rely on these details.
|
||||||
|
|
||||||
=== Standard M-mode Identification CSRs
|
=== Standard M-mode Identification CSRs
|
||||||
|
|
||||||
|
|
|
@ -32,7 +32,7 @@ All timings are given assuming perfect bus behaviour (no downstream bus stalls).
|
||||||
| `lui rd, imm` | 1 |
|
| `lui rd, imm` | 1 |
|
||||||
| `auipc rd, imm` | 1 |
|
| `auipc rd, imm` | 1 |
|
||||||
3+| Control Transfer
|
3+| Control Transfer
|
||||||
| `jal rd, label` | 2footnote:unaligned_branch[A branch to a 32-bit instruction which is not 32-bit-aligned requires one additional cycle, because two naturally aligned bus cycles are required to fetch the target instruction.]|
|
| `jal rd, label` | 2footnote:unaligned_branch[A jump or branch to a 32-bit instruction which is not 32-bit-aligned requires one additional cycle, because two naturally aligned bus cycles are required to fetch the target instruction.]|
|
||||||
| `jalr rd, rs1, imm` | 2footnote:unaligned_branch[] |
|
| `jalr rd, rs1, imm` | 2footnote:unaligned_branch[] |
|
||||||
| `beq rs1, rs2, label`| 1 or 2footnote:unaligned_branch[] | 1 if nontaken, 2 if taken.
|
| `beq rs1, rs2, label`| 1 or 2footnote:unaligned_branch[] | 1 if nontaken, 2 if taken.
|
||||||
| `bne rs1, rs2, label`| 1 or 2footnote:unaligned_branch[] | 1 if nontaken, 2 if taken.
|
| `bne rs1, rs2, label`| 1 or 2footnote:unaligned_branch[] | 1 if nontaken, 2 if taken.
|
||||||
|
|
|
@ -1040,14 +1040,24 @@ assign trap_addr =
|
||||||
assign trap_is_irq = DEBUG_SUPPORT && (want_halt_except || want_halt_irq) ?
|
assign trap_is_irq = DEBUG_SUPPORT && (want_halt_except || want_halt_irq) ?
|
||||||
!want_halt_except : !exception_req_any;
|
!want_halt_except : !exception_req_any;
|
||||||
|
|
||||||
|
// When there is a loadstore dphase pending, we block off the IRQ trap
|
||||||
|
// request, but still assert the trap_enter_soon flag. This blocks issue of
|
||||||
|
// further load/stores which have not yet been locked into aphase, so the IRQ
|
||||||
|
// can eventually go through. It's not safe to enter an IRQ when a dphase is
|
||||||
|
// in progress, because that dphase could subsequently except, and sample the
|
||||||
|
// IRQ vector PC instead of the load/store instruction PC.
|
||||||
|
|
||||||
// delay_irq_entry also applies to IRQ-like debug entries.
|
// delay_irq_entry also applies to IRQ-like debug entries.
|
||||||
assign trap_enter_vld =
|
assign trap_enter_vld =
|
||||||
CSR_M_TRAP && (exception_req_any ||
|
CSR_M_TRAP && (exception_req_any ||
|
||||||
!delay_irq_entry && !debug_mode && irq_active) ||
|
!delay_irq_entry && !debug_mode && irq_active && !loadstore_dphase_pending) ||
|
||||||
DEBUG_SUPPORT && (
|
DEBUG_SUPPORT && (
|
||||||
(!delay_irq_entry && want_halt_irq) || want_halt_except || pending_dbg_resume);
|
(!delay_irq_entry && want_halt_irq) || want_halt_except || pending_dbg_resume);
|
||||||
|
|
||||||
assign trap_enter_soon = trap_enter_vld || (DEBUG_SUPPORT && want_halt_irq_if_no_exception);
|
assign trap_enter_soon = trap_enter_vld || (
|
||||||
|
|DEBUG_SUPPORT && want_halt_irq_if_no_exception ||
|
||||||
|
!delay_irq_entry && !debug_mode && irq_active && loadstore_dphase_pending
|
||||||
|
);
|
||||||
|
|
||||||
assign mcause_irq_next = !exception_req_any;
|
assign mcause_irq_next = !exception_req_any;
|
||||||
assign mcause_code_next = exception_req_any ? {2'h0, except} : mcause_irq_num;
|
assign mcause_code_next = exception_req_any ? {2'h0, except} : mcause_irq_num;
|
||||||
|
@ -1105,10 +1115,18 @@ always @ (posedge clk) begin
|
||||||
// and an exception by e.g. a left-behind store data phase would sample the
|
// and an exception by e.g. a left-behind store data phase would sample the
|
||||||
// wrong PC.
|
// wrong PC.
|
||||||
//
|
//
|
||||||
// - Except -> IRQ: would need to re-set mstatus.mie first
|
// - Except -> IRQ: would need to re-set mstatus.mie first, shouldn't happen
|
||||||
|
//
|
||||||
|
// Sole exclusion is mret. We can return from an interrupt/exception and take
|
||||||
|
// a new interrupt on the next cycle.
|
||||||
|
|
||||||
if ($past(trap_enter_vld && trap_enter_rdy))
|
if ($past(trap_enter_vld && trap_enter_rdy && except != EXCEPT_MRET))
|
||||||
assert(!(trap_enter_vld && trap_enter_rdy));
|
assert(!(trap_enter_vld && trap_enter_rdy));
|
||||||
|
|
||||||
|
// Just to stress that this is the the only case:
|
||||||
|
if (trap_enter_vld && trap_enter_rdy && $past(trap_enter_vld && trap_enter_rdy))
|
||||||
|
assert($past(except == EXCEPT_MRET));
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
`endif
|
`endif
|
||||||
|
|
|
@ -1,5 +1,8 @@
|
||||||
DOTF=tb.f
|
DOTF=tb.f
|
||||||
TOP=tb
|
TOP=tb
|
||||||
YOSYS_SMT_SOLVER=boolector
|
YOSYS_SMT_SOLVER=boolector
|
||||||
|
DEPTH=25
|
||||||
|
|
||||||
|
all: bmc
|
||||||
|
|
||||||
include $(SCRIPTS)/formal.mk
|
include $(SCRIPTS)/formal.mk
|
||||||
|
|
|
@ -96,7 +96,7 @@ always @ (posedge clk) if (rst_n) begin: dst_ahbl_req_properties
|
||||||
assert(src_haddr == src_addr_dph + W_DATA / 8);
|
assert(src_haddr == src_addr_dph + W_DATA / 8);
|
||||||
// No pipelining of exclusive transfers
|
// No pipelining of exclusive transfers
|
||||||
if (src_excl_dph)
|
if (src_excl_dph)
|
||||||
assert(!src_hexcl);
|
assert(!(src_hexcl && src_htrans[1]));
|
||||||
end
|
end
|
||||||
|
|
||||||
// Data phase properties:
|
// Data phase properties:
|
||||||
|
|
Loading…
Reference in New Issue