-
Notifications
You must be signed in to change notification settings - Fork 53
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Fix for issue #507 #655
Fix for issue #507 #655
Changes from 2 commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -75,6 +75,7 @@ module cv32e40x_controller_fsm import cv32e40x_pkg::*; | |
// From LSU (WB) | ||
input mpu_status_e lsu_mpu_status_wb_i, // MPU status (WB timing) | ||
input logic data_stall_wb_i, // WB stalled by LSU | ||
input logic lsu_valid_wb_i, // LSU instruction in WB is valid | ||
|
||
input logic lsu_busy_i, // LSU is busy with outstanding transfers | ||
input logic lsu_interruptible_i, // LSU can be interrupted | ||
|
@@ -228,6 +229,9 @@ module cv32e40x_controller_fsm import cv32e40x_pkg::*; | |
logic sequence_in_progress_id; | ||
logic id_stage_haltable; | ||
|
||
// Flag that is high during the cycle after an LSU instruction finishes in WB | ||
logic interrupt_blanking_q; | ||
|
||
assign sequence_interruptible = !sequence_in_progress_wb; | ||
|
||
assign id_stage_haltable = !sequence_in_progress_id; | ||
|
@@ -440,10 +444,10 @@ module cv32e40x_controller_fsm import cv32e40x_pkg::*; | |
// Once the first part of a table jump has finished in WB, we are not allowed to take interrupts before the last part finishes. This can be detected when the last | ||
// part of a table jump is in either EX or WB. | ||
|
||
assign interrupt_allowed = lsu_interruptible_i && debug_interruptible && !fencei_ongoing && !xif_in_wb && sequence_interruptible; | ||
assign interrupt_allowed = lsu_interruptible_i && debug_interruptible && !fencei_ongoing && !xif_in_wb && sequence_interruptible && !interrupt_blanking_q; | ||
|
||
// Allowing NMI's follow the same rule as regular interrupts. | ||
assign nmi_allowed = interrupt_allowed; | ||
// Allowing NMI's follow the same rule as regular interrupts, except we don't need to regard blanking of NMIs after a load/store. | ||
assign nmi_allowed = lsu_interruptible_i && debug_interruptible && !fencei_ongoing && !xif_in_wb && sequence_interruptible; | ||
|
||
// Do not allow interrupts if in debug mode, or single stepping without dcsr.stepie set. | ||
assign debug_interruptible = !(debug_mode_q || (dcsr_i.step && !dcsr_i.stepie)); | ||
|
@@ -521,7 +525,7 @@ module cv32e40x_controller_fsm import cv32e40x_pkg::*; | |
// Sequences: If we need to halt for debug or interrupt not allowed due to a sequence, we must check if we can | ||
// actually halt the ID stage or not. Halting the same sequence that causes *_allowed to go to 0 | ||
// may cause a deadlock. | ||
ctrl_fsm_o.halt_id = ctrl_byp_i.jalr_stall || ctrl_byp_i.load_stall || ctrl_byp_i.csr_stall || ctrl_byp_i.wfi_stall || ctrl_byp_i.mnxti_stall || | ||
ctrl_fsm_o.halt_id = ctrl_byp_i.jalr_stall || ctrl_byp_i.load_stall || ctrl_byp_i.csr_stall || ctrl_byp_i.wfi_stall || ctrl_byp_i.mnxti_stall_id || | ||
(((pending_interrupt && !interrupt_allowed) || (pending_nmi && !nmi_allowed) || (pending_nmi_early)) && debug_interruptible && id_stage_haltable) || | ||
(pending_debug && !debug_allowed && id_stage_haltable); | ||
|
||
|
@@ -530,7 +534,7 @@ module cv32e40x_controller_fsm import cv32e40x_pkg::*; | |
// Also halting EX if an offloaded instruction in WB may cause an exception, such that a following offloaded | ||
// instruction can correctly receive commit_kill. | ||
// Halting EX when an instruction in WB may cause an interrupt to become pending. | ||
ctrl_fsm_o.halt_ex = ctrl_byp_i.minstret_stall || ctrl_byp_i.xif_exception_stall || ctrl_byp_i.irq_enable_stall; | ||
ctrl_fsm_o.halt_ex = ctrl_byp_i.minstret_stall || ctrl_byp_i.xif_exception_stall || ctrl_byp_i.irq_enable_stall || ctrl_byp_i.mnxti_stall_ex; | ||
ctrl_fsm_o.halt_wb = 1'b0; | ||
|
||
// By default no stages are killed | ||
|
@@ -1020,6 +1024,18 @@ module cv32e40x_controller_fsm import cv32e40x_pkg::*; | |
end | ||
end | ||
|
||
// Flop used to track LSU instructions in WB. High in the cycle after an LSU instruction | ||
// leaves WB. | ||
// Used for disregarding interrupts one cycle after a load/store to make sure the | ||
// interrupt controller propagates the inputs through its flops. | ||
always_ff @(posedge clk, negedge rst_n) begin | ||
if (rst_n == 1'b0) begin | ||
interrupt_blanking_q <= 1'b0; | ||
end else begin | ||
interrupt_blanking_q <= ex_wb_pipe_i.instr_valid && ex_wb_pipe_i.lsu_en && lsu_valid_wb_i; | ||
end | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Is the use of lsu_valid_wb_i even needed? Can you check if it is SEC clean to remove it? (Interrupting WB while waiting for an rvalid should not be allowed anyway) There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It is in fact not needed, we are SEC clean without it. Removed. |
||
end | ||
|
||
// Flops for fencei handshake request | ||
always_ff @(posedge clk, negedge rst_n) begin | ||
if (rst_n == 1'b0) begin | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -1204,7 +1204,8 @@ typedef struct packed { | |
logic load_stall; // Stall due to load operation | ||
logic csr_stall; | ||
logic wfi_stall; | ||
logic mnxti_stall; // Stall due to mnxti CSR access in EX | ||
logic mnxti_stall_id; // Stall ID due to mnxti CSR access in EX | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Rename There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Fixed |
||
logic mnxti_stall_ex; // Stall EX due to LSU instruction in WB | ||
logic minstret_stall; // Stall due to minstret/h read in EX | ||
logic deassert_we; // Deassert write enable and special insn bits | ||
logic id_stage_abort; // Same signal as deassert_we, with better name for use in the controller. | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,76 @@ | ||
// Copyright 2022 Silicon Labs, Inc. | ||
// | ||
// This file, and derivatives thereof are licensed under the | ||
// Solderpad License, Version 2.0 (the "License"). | ||
// | ||
// Use of this file means you agree to the terms and conditions | ||
// of the license and are in full compliance with the License. | ||
// | ||
// You may obtain a copy of the License at: | ||
// | ||
// https://solderpad.org/licenses/SHL-2.0/ | ||
// | ||
// Unless required by applicable law or agreed to in writing, software | ||
// and hardware implementations thereof distributed under the License | ||
// is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS | ||
// OF ANY KIND, EITHER EXPRESSED OR IMPLIED. | ||
// | ||
// See the License for the specific language governing permissions and | ||
// limitations under the License. | ||
|
||
//////////////////////////////////////////////////////////////////////////////// | ||
// Engineer: Øystein Knauserud - [email protected] // | ||
// // | ||
// Design Name: cv32e40x_clic_int_controller_sva // | ||
// Project Name: CV32E40X // | ||
// Language: SystemVerilog // | ||
// // | ||
// Description: Assertions reltated to the CLIC interrupt controller // | ||
// // | ||
//////////////////////////////////////////////////////////////////////////////// | ||
|
||
module cv32e40x_clic_int_controller_sva | ||
import uvm_pkg::*; | ||
import cv32e40x_pkg::*; | ||
( | ||
input logic clk, | ||
input logic rst_n, | ||
|
||
input logic irq_req_ctrl_o, | ||
input logic clic_irq_q, | ||
input logic [7:0] clic_irq_level_q, | ||
|
||
input logic ctrl_pending_interrupt, | ||
input logic ctrl_interrupt_allowed, | ||
|
||
input ctrl_fsm_t ctrl_fsm, | ||
input dcsr_t dcsr | ||
|
||
); | ||
|
||
|
||
// Check that a pending interrupt is taken as soon as possible after being enabled | ||
property p_clic_enable; | ||
@(posedge clk) disable iff (!rst_n) | ||
( !irq_req_ctrl_o | ||
##1 | ||
irq_req_ctrl_o && $stable(clic_irq_q) && $stable(clic_irq_level_q) && !(ctrl_fsm.debug_mode || (dcsr.step && !dcsr.stepie)) | ||
|-> (ctrl_pending_interrupt && ctrl_interrupt_allowed)); | ||
endproperty; | ||
|
||
a_clic_enable: assert property(p_clic_enable) | ||
else `uvm_error("core", "Interrupt not taken soon enough after enabling"); | ||
|
||
// Check a pending interrupt that is disabled is actually not taken | ||
property p_clic_disable; | ||
@(posedge clk) disable iff (!rst_n) | ||
( irq_req_ctrl_o | ||
##1 | ||
!irq_req_ctrl_o && $stable(clic_irq_q) && $stable(clic_irq_level_q) | ||
|-> !(ctrl_pending_interrupt && ctrl_interrupt_allowed)); | ||
endproperty; | ||
|
||
a_clic_disable: assert property(p_clic_disable) | ||
else `uvm_error("core", "Interrupt taken after disabling"); | ||
endmodule // cv32e40x_cs_registers_sva | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -72,24 +72,21 @@ module cv32e40x_core_sva | |
input logic data_req_o, | ||
input logic data_we_o, | ||
input logic [5:0] data_atop_o, | ||
input logic data_rvalid_i, | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Is this signal still used? If not, then remove There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Removed |
||
|
||
// probed controller signals | ||
input logic ctrl_debug_mode_n, | ||
input logic ctrl_pending_debug, | ||
input logic ctrl_debug_allowed, | ||
input logic ctrl_interrupt_allowed, | ||
input logic ctrl_pending_interrupt, | ||
input ctrl_state_e ctrl_fsm_ns, | ||
input ctrl_byp_t ctrl_byp, | ||
input logic ctrl_pending_nmi, | ||
// probed cs_registers signals | ||
// probed cs_registers signals | ||
input logic [31:0] cs_registers_mie_q, | ||
input logic [31:0] cs_registers_mepc_n, | ||
input mcause_t cs_registers_csr_cause_i, // From controller | ||
input mcause_t cs_registers_mcause_q, // From cs_registers, flopped mcause | ||
input mstatus_t cs_registers_mstatus_q, | ||
input logic clic_irq_q, | ||
input logic [7:0] clic_irq_level_q); | ||
input mstatus_t cs_registers_mstatus_q); | ||
|
||
if (SMCLIC) begin | ||
property p_clic_mie_tieoff; | ||
|
@@ -484,31 +481,7 @@ end | |
a_tbljmp_stall: assert property(p_tbljmp_stall) | ||
else `uvm_error("core", "Table jump not stalled while CSR is written"); | ||
|
||
if (SMCLIC) begin | ||
// Check that a pending interrupt is taken as soon as possible after being enabled | ||
property p_clic_enable; | ||
@(posedge clk) disable iff (!rst_ni) | ||
( !irq_req_ctrl | ||
##1 | ||
irq_req_ctrl && $stable(clic_irq_q) && $stable(clic_irq_level_q) && !(ctrl_fsm.debug_mode || (dcsr.step && !dcsr.stepie)) | ||
|-> (ctrl_pending_interrupt && ctrl_interrupt_allowed)); | ||
endproperty; | ||
|
||
a_clic_enable: assert property(p_clic_enable) | ||
else `uvm_error("core", "Interrupt not taken soon enough after enabling"); | ||
|
||
// Check a pending interrupt that is disabled is actually not taken | ||
property p_clic_disable; | ||
@(posedge clk) disable iff (!rst_ni) | ||
( irq_req_ctrl | ||
##1 | ||
!irq_req_ctrl && $stable(clic_irq_q) && $stable(clic_irq_level_q) | ||
|-> !(ctrl_pending_interrupt && ctrl_interrupt_allowed)); | ||
endproperty; | ||
|
||
a_clic_disable: assert property(p_clic_disable) | ||
else `uvm_error("core", "Interrupt taken after disabling"); | ||
end else begin | ||
if (!SMCLIC) begin | ||
// Check that a pending interrupt is taken as soon as possible after being enabled | ||
property p_mip_mie_write_enable; | ||
@(posedge clk) disable iff (!rst_ni) | ||
|
@@ -533,5 +506,18 @@ end else begin | |
a_mip_mie_write_disable: assert property(p_mip_mie_write_disable) | ||
else `uvm_error("core", "Interrupt taken after disabling"); | ||
end | ||
|
||
// Clearing external interrupts via a store instruction causes irq_i to go low the next cycle. | ||
// The interrupt controller uses flopped versions of irq_i, and thus we need to disregard interrupts | ||
// for one cycle after an rvalid has been observed. | ||
property p_no_irq_after_lsu; | ||
@(posedge clk) disable iff (!rst_ni) | ||
( wb_valid && ex_wb_pipe.lsu_en && ex_wb_pipe.instr_valid | ||
|=> | ||
!ctrl_interrupt_allowed); | ||
endproperty; | ||
|
||
a_no_irq_after_lsu: assert property(p_no_irq_after_lsu) | ||
else `uvm_error("core", "Interrupt taken after disabling"); | ||
endmodule // cv32e40x_core_sva | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would prefer the following renaming as _id, _ex postfixes are normally used to indicate signal timing:
mnxti_stall_id -> mnxti_id_stall
mnxti_stall_ex -> mnxti_ex_stall
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed