Skip to content

Commit 8e852d2

Browse files
committed
[dv] Fix iside error notification to cosim
When a writeback exception occurs when the instruction in ID/EX has seen an instruction fetch error we need to ensure that error doesn't get notified to cosim. This requires watching for a writeback exception and removing the latest iside error from the queue if needed.
1 parent b399c7c commit 8e852d2

File tree

3 files changed

+68
-19
lines changed

3 files changed

+68
-19
lines changed

dv/uvm/core_ibex/common/ibex_cosim_agent/ibex_cosim_scoreboard.sv

Lines changed: 65 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -17,9 +17,11 @@ class ibex_cosim_scoreboard extends uvm_scoreboard;
1717
uvm_tlm_analysis_fifo #(ibex_ifetch_seq_item) ifetch_port;
1818
uvm_tlm_analysis_fifo #(ibex_ifetch_pmp_seq_item) ifetch_pmp_port;
1919

20-
virtual core_ibex_instr_monitor_if instr_vif;
20+
virtual core_ibex_instr_monitor_if instr_vif;
21+
virtual core_ibex_dut_probe_if dut_vif;
2122

2223
uvm_event reset_e;
24+
uvm_event check_inserted_iside_error_e;
2325

2426
bit failed_iside_accesses [bit[31:0]];
2527
bit iside_pmp_failure [bit[31:0]];
@@ -36,13 +38,14 @@ class ibex_cosim_scoreboard extends uvm_scoreboard;
3638
function new(string name="", uvm_component parent=null);
3739
super.new(name, parent);
3840

39-
rvfi_port = new("rvfi_port", this);
40-
dmem_port = new("dmem_port", this);
41-
imem_port = new("imem_port", this);
42-
ifetch_port = new("ifetch_port", this);
43-
ifetch_pmp_port = new("ifetch_pmp_port", this);
44-
cosim_handle = null;
45-
reset_e = new();
41+
rvfi_port = new("rvfi_port", this);
42+
dmem_port = new("dmem_port", this);
43+
imem_port = new("imem_port", this);
44+
ifetch_port = new("ifetch_port", this);
45+
ifetch_pmp_port = new("ifetch_pmp_port", this);
46+
cosim_handle = null;
47+
reset_e = new();
48+
check_inserted_iside_error_e = new();
4649
endfunction
4750

4851
function void build_phase(uvm_phase phase);
@@ -57,6 +60,11 @@ class ibex_cosim_scoreboard extends uvm_scoreboard;
5760
`uvm_fatal(`gfn, "Cannot get instr_monitor_if")
5861
end
5962

63+
if (!uvm_config_db#(virtual core_ibex_dut_probe_if)::get(null, "", "dut_if",
64+
dut_vif)) begin
65+
`uvm_fatal(`gfn, "Cannot get dut_probe_if")
66+
end
67+
6068
init_cosim();
6169
endfunction : build_phase
6270

@@ -86,6 +94,7 @@ class ibex_cosim_scoreboard extends uvm_scoreboard;
8694
run_cosim_rvfi();
8795
run_cosim_dmem();
8896
run_cosim_imem_errors();
97+
run_cosim_prune_imem_errors();
8998
if (cfg.probe_imem_for_errs) begin
9099
run_cosim_imem();
91100
end else begin
@@ -107,17 +116,19 @@ class ibex_cosim_scoreboard extends uvm_scoreboard;
107116
forever begin
108117
rvfi_port.get(rvfi_instr);
109118

110-
// Remove entries from iside_error_queue where the instruction never reaches the RVFI
111-
// interface because it was flushed.
112-
while (iside_error_queue.size() > 0 && iside_error_queue[0].order < rvfi_instr.order) begin
113-
iside_error_queue.pop_front();
114-
end
119+
if (iside_error_queue.size() > 0) begin
120+
// Remove entries from iside_error_queue where the instruction never reaches the RVFI
121+
// interface because it was flushed.
122+
while (iside_error_queue.size() > 0 && iside_error_queue[0].order < rvfi_instr.order) begin
123+
iside_error_queue.pop_front();
124+
end
115125

116-
// Check if the top of the iside_error_queue relates to the current RVFI instruction. If so
117-
// notify the cosim environment of an instruction error.
118-
if (iside_error_queue.size() !=0 && iside_error_queue[0].order == rvfi_instr.order) begin
119-
riscv_cosim_set_iside_error(cosim_handle, iside_error_queue[0].addr);
120-
iside_error_queue.pop_front();
126+
// Check if the top of the iside_error_queue relates to the current RVFI instruction. If so
127+
// notify the cosim environment of an instruction error.
128+
if (iside_error_queue.size() !=0 && iside_error_queue[0].order == rvfi_instr.order) begin
129+
riscv_cosim_set_iside_error(cosim_handle, iside_error_queue[0].addr);
130+
iside_error_queue.pop_front();
131+
end
121132
end
122133

123134
riscv_cosim_set_nmi(cosim_handle, rvfi_instr.nmi);
@@ -242,6 +253,16 @@ class ibex_cosim_scoreboard extends uvm_scoreboard;
242253
wait (instr_vif.instr_cb.valid_id &&
243254
instr_vif.instr_cb.instr_new_id &&
244255
latest_order != instr_vif.instr_cb.rvfi_order_id);
256+
257+
latest_order = instr_vif.instr_cb.rvfi_order_id;
258+
259+
if (dut_vif.dut_cb.wb_exception)
260+
// If an exception in writeback occurs the instruction in ID will be flushed and hence not
261+
// produce an iside error so skip the rest of the loop. A writeback exception may occur
262+
// after this cycle before the instruction in ID moves out of the ID stage. The
263+
// `run_cosim_prune_imem_errors` task deals with this case.
264+
continue;
265+
245266
// Determine if the instruction comes from an address that has seen an error that wasn't a PMP
246267
// error (the icache records both PMP errors and fetch errors with the same error bits). If a
247268
// fetch error was seen add the instruction order ID and address to iside_error_queue.
@@ -252,6 +273,7 @@ class ibex_cosim_scoreboard extends uvm_scoreboard;
252273
begin
253274
iside_error_queue.push_back('{order : instr_vif.instr_cb.rvfi_order_id,
254275
addr : aligned_addr});
276+
check_inserted_iside_error_e.trigger();
255277
end else if (!instr_vif.instr_cb.is_compressed_id &&
256278
(instr_vif.instr_cb.pc_id & 32'h3) != 0 &&
257279
failed_iside_accesses.exists(aligned_next_addr) &&
@@ -261,12 +283,36 @@ class ibex_cosim_scoreboard extends uvm_scoreboard;
261283
// side of the boundary
262284
iside_error_queue.push_back('{order : instr_vif.instr_cb.rvfi_order_id,
263285
addr : aligned_next_addr});
286+
check_inserted_iside_error_e.trigger();
264287
end
265288

266-
latest_order = instr_vif.instr_cb.rvfi_order_id;
267289
end
268290
endtask: run_cosim_imem_errors;
269291

292+
task run_cosim_prune_imem_errors();
293+
// Errors are added to the iside error queue the first cycle the instruction that sees the error
294+
// is in the ID stage. Cycles following this the writeback stage may cause an exception flushing
295+
// the ID stage so the iside error never occurs. When this happens we need to pop the new iside
296+
// error off the queue.
297+
forever begin
298+
// Wait until the `run_cosim_imem_errors` task notifies us it's added a error to the queue
299+
check_inserted_iside_error_e.wait_ptrigger();
300+
// Wait for the next clock
301+
@(instr_vif.instr_cb);
302+
// Wait for a new instruction or a writeback exception. When a new instruction has entered the
303+
// ID stage and we haven't seen a writeback exception we know the instruction associated with the
304+
// error just added to the queue isn't getting flushed.
305+
wait (instr_vif.instr_cb.instr_new_id || dut_vif.dut_cb.wb_exception);
306+
307+
if (!instr_vif.instr_cb.instr_new_id && dut_vif.dut_cb.wb_exception) begin
308+
// If we hit a writeback exception without seeing a new instruction then the newly added
309+
// error relates to an instruction just flushed from the ID stage so pop it from the
310+
// queue.
311+
iside_error_queue.pop_back();
312+
end
313+
end
314+
endtask: run_cosim_prune_imem_errors
315+
270316
function string get_cosim_error_str();
271317
string error = "Cosim mismatch ";
272318
for (int i = 0; i < riscv_cosim_get_num_errors(cosim_handle); ++i) begin

dv/uvm/core_ibex/env/core_ibex_dut_probe_if.sv

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ interface core_ibex_dut_probe_if(input logic clk);
3838
logic irq_exc_seen;
3939
logic csr_save_cause;
4040
ibex_pkg::exc_cause_t exc_cause;
41+
logic wb_exception;
4142

4243
always @(posedge clk or posedge reset) begin
4344
if (reset) begin
@@ -81,6 +82,7 @@ interface core_ibex_dut_probe_if(input logic clk);
8182
input rf_rd_b_wb_match;
8283
input sync_exc_seen;
8384
input irq_exc_seen;
85+
input wb_exception;
8486
endclocking
8587

8688
initial begin

dv/uvm/core_ibex/tb/core_ibex_tb_top.sv

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -232,6 +232,7 @@ module core_ibex_tb_top;
232232
assign dut_if.sync_exc_seen = dut.u_ibex_top.u_ibex_core.cs_registers_i.cpuctrlsts_part_q.sync_exc_seen;
233233
assign dut_if.csr_save_cause = dut.u_ibex_top.u_ibex_core.csr_save_cause;
234234
assign dut_if.exc_cause = dut.u_ibex_top.u_ibex_core.exc_cause;
235+
assign dut_if.wb_exception = dut.u_ibex_top.u_ibex_core.id_stage_i.wb_exception;
235236
// Instruction monitor connections
236237
assign instr_monitor_if.reset = ~rst_n;
237238
assign instr_monitor_if.valid_id = dut.u_ibex_top.u_ibex_core.id_stage_i.instr_valid_i;

0 commit comments

Comments
 (0)