diff --git a/dv/uvm/common/ibex_mem_intf_agent/ibex_mem_intf_monitor.sv b/dv/uvm/common/ibex_mem_intf_agent/ibex_mem_intf_monitor.sv index 10a2b9b3..8383e07d 100644 --- a/dv/uvm/common/ibex_mem_intf_agent/ibex_mem_intf_monitor.sv +++ b/dv/uvm/common/ibex_mem_intf_agent/ibex_mem_intf_monitor.sv @@ -29,12 +29,25 @@ class ibex_mem_intf_monitor extends uvm_monitor; virtual task run_phase(uvm_phase phase); wait(vif.reset === 1'b0); - fork - collect_address_phase(); - collect_data_phase(); - join + forever begin + fork : check_mem_intf + collect_address_phase(); + collect_data_phase(); + wait(vif.reset === 1'b1); + join_any + // Will only reach this point when mid-test reset is asserted + disable check_mem_intf; + handle_reset(); + end endtask : run_phase + virtual protected task handle_reset(); + ibex_mem_intf_seq_item mailbox_result; + // Clear the mailbox of any content + while (collect_data_queue.try_get(mailbox_result)); + wait(vif.reset === 1'b0); + endtask + virtual protected task collect_address_phase(); ibex_mem_intf_seq_item trans_collected; forever begin diff --git a/dv/uvm/common/ibex_mem_intf_agent/ibex_mem_intf_slave_agent.sv b/dv/uvm/common/ibex_mem_intf_agent/ibex_mem_intf_slave_agent.sv index 080198ac..d491fce0 100644 --- a/dv/uvm/common/ibex_mem_intf_agent/ibex_mem_intf_slave_agent.sv +++ b/dv/uvm/common/ibex_mem_intf_agent/ibex_mem_intf_slave_agent.sv @@ -32,4 +32,8 @@ class ibex_mem_intf_slave_agent extends uvm_agent; end endfunction : connect_phase + function void reset(); + sequencer.reset(); + endfunction + endclass : ibex_mem_intf_slave_agent diff --git a/dv/uvm/common/ibex_mem_intf_agent/ibex_mem_intf_slave_driver.sv b/dv/uvm/common/ibex_mem_intf_agent/ibex_mem_intf_slave_driver.sv index 49c76e0f..58520fef 100644 --- a/dv/uvm/common/ibex_mem_intf_agent/ibex_mem_intf_slave_driver.sv +++ b/dv/uvm/common/ibex_mem_intf_agent/ibex_mem_intf_slave_driver.sv @@ -27,12 +27,34 @@ class ibex_mem_intf_slave_driver extends uvm_driver #(ibex_mem_intf_seq_item); virtual task run_phase(uvm_phase phase); reset_signals(); - fork - send_grant(); - join_none - get_and_drive(); + wait(vif.reset === 1'b0); + forever begin + fork : drive_stimulus + send_grant(); + get_and_drive(); + wait(vif.reset === 1'b1); + join_any + // Will only be reached after mid-test reset + disable drive_stimulus; + handle_reset(); + end endtask : run_phase + virtual protected task handle_reset(); + ibex_mem_intf_seq_item req; + // Clear mailbox + while (rdata_queue.try_get(req)); + // Clear seq_item_port + do begin + seq_item_port.try_next_item(req); + if (req != null) begin + seq_item_port.item_done(); + end + end while (req != null); + reset_signals(); + wait(vif.reset === 1'b0); + endtask + virtual protected task reset_signals(); vif.rvalid <= 1'b0; vif.grant <= 1'b0; @@ -41,20 +63,24 @@ class ibex_mem_intf_slave_driver extends uvm_driver #(ibex_mem_intf_seq_item); endtask : reset_signals virtual protected task get_and_drive(); - @(negedge vif.reset); + wait(vif.reset === 1'b0); fork - forever begin - ibex_mem_intf_seq_item req, req_c; - @(posedge vif.clock); - seq_item_port.get_next_item(req); - $cast(req_c, req.clone()); - if(~vif.reset) begin - rdata_queue.put(req_c); + begin + forever begin + ibex_mem_intf_seq_item req, req_c; + @(posedge vif.clock); + seq_item_port.get_next_item(req); + $cast(req_c, req.clone()); + if(~vif.reset) begin + rdata_queue.put(req_c); + end + seq_item_port.item_done(); end - seq_item_port.item_done(); end - send_read_data(); - join_none + begin + send_read_data(); + end + join endtask : get_and_drive virtual protected task send_grant(); diff --git a/dv/uvm/common/ibex_mem_intf_agent/ibex_mem_intf_slave_sequencer.sv b/dv/uvm/common/ibex_mem_intf_agent/ibex_mem_intf_slave_sequencer.sv index 2a9f5c05..093496bd 100644 --- a/dv/uvm/common/ibex_mem_intf_agent/ibex_mem_intf_slave_sequencer.sv +++ b/dv/uvm/common/ibex_mem_intf_agent/ibex_mem_intf_slave_sequencer.sv @@ -18,4 +18,9 @@ class ibex_mem_intf_slave_sequencer extends uvm_sequencer #(ibex_mem_intf_seq_it addr_ph_port = new("addr_ph_port_sequencer", this); endfunction : new + // On reset, empty the tlm fifo + function void reset(); + addr_ph_port.flush(); + endfunction + endclass : ibex_mem_intf_slave_sequencer diff --git a/dv/uvm/common/irq_agent/irq_master_driver.sv b/dv/uvm/common/irq_agent/irq_master_driver.sv index 89709c68..defcde9d 100644 --- a/dv/uvm/common/irq_agent/irq_master_driver.sv +++ b/dv/uvm/common/irq_agent/irq_master_driver.sv @@ -18,14 +18,32 @@ class irq_master_driver extends uvm_driver #(irq_seq_item); endfunction: build_phase virtual task run_phase(uvm_phase phase); - fork - get_and_drive(); - reset_signals(); - join + reset_signals(); + forever begin + fork : drive_irq + get_and_drive(); + wait(vif.reset === 1'b1); + join_any + // Will only reach here on mid-test reset + disable drive_irq; + handle_reset(); + end endtask : run_phase + virtual protected task handle_reset(); + irq_seq_item req; + // Clear seq_item_port + do begin + seq_item_port.try_next_item(req); + if (req != null) begin + seq_item_port.item_done(); + end + end while (req != null); + reset_signals(); + endtask + virtual protected task get_and_drive(); - @(negedge vif.reset); + wait(vif.reset === 1'b0); forever begin seq_item_port.try_next_item(req); if (req != null) begin diff --git a/dv/uvm/common/irq_agent/irq_monitor.sv b/dv/uvm/common/irq_agent/irq_monitor.sv index d4c53620..639140dd 100644 --- a/dv/uvm/common/irq_agent/irq_monitor.sv +++ b/dv/uvm/common/irq_agent/irq_monitor.sv @@ -22,7 +22,15 @@ class irq_monitor extends uvm_monitor; endfunction: build_phase virtual task run_phase(uvm_phase phase); - collect_irq(); + forever begin + wait(vif.reset === 1'b0); + fork : monitor_irq + collect_irq(); + wait(vif.reset === 1'b1); + join_any + // Will only reach here on mid-test reset + disable monitor_irq; + end endtask : run_phase // We know that for Ibex, any given interrupt stimulus will be asserted until the core signals the diff --git a/dv/uvm/common/utils/clk_if.sv b/dv/uvm/common/utils/clk_if.sv index 0f64db45..d5a59306 100644 --- a/dv/uvm/common/utils/clk_if.sv +++ b/dv/uvm/common/utils/clk_if.sv @@ -8,7 +8,11 @@ // //------------------------------------------------------------------------------ -interface clk_if(input logic clk); +interface clk_if(inout clk, + inout rst_n); + + logic clk_o; + logic rst_no; clocking cb @(posedge clk); endclocking @@ -26,4 +30,28 @@ interface clk_if(input logic clk); repeat (num_clks) @cbn; endtask + // generate mid-test reset + task reset(); + rst_no = 1'b0; + wait_clks(100); + rst_no = 1'b1; + endtask + + // generate clock + initial begin + clk_o = 1'b0; + forever begin + #10 clk_o = ~clk_o; + end + end + + // generate initial reset + initial begin + reset(); + end + + // Interface assignments + assign clk = clk_o; + assign rst_n = rst_no; + endinterface diff --git a/dv/uvm/env/core_ibex_dut_probe_if.sv b/dv/uvm/env/core_ibex_dut_probe_if.sv index efa9ff30..2119d1fe 100644 --- a/dv/uvm/env/core_ibex_dut_probe_if.sv +++ b/dv/uvm/env/core_ibex_dut_probe_if.sv @@ -4,6 +4,7 @@ // Interface to probe DUT internal signal interface core_ibex_dut_probe_if(input logic clk); + logic reset; logic illegal_instr; logic ecall; logic wfi; @@ -13,4 +14,9 @@ interface core_ibex_dut_probe_if(input logic clk); logic fetch_enable; logic core_sleep; logic debug_req; + + initial begin + debug_req = 1'b0; + end + endinterface diff --git a/dv/uvm/env/core_ibex_env.sv b/dv/uvm/env/core_ibex_env.sv index 3e20b3d9..11c027ba 100644 --- a/dv/uvm/env/core_ibex_env.sv +++ b/dv/uvm/env/core_ibex_env.sv @@ -37,4 +37,9 @@ class core_ibex_env extends uvm_env; vseqr.irq_seqr = irq_agent.sequencer; endfunction : connect_phase + function void reset(); + data_if_slave_agent.reset(); + instr_if_slave_agent.reset(); + endfunction + endclass diff --git a/dv/uvm/riscv_dv_extension/testlist.yaml b/dv/uvm/riscv_dv_extension/testlist.yaml index 82a63147..297296c9 100644 --- a/dv/uvm/riscv_dv_extension/testlist.yaml +++ b/dv/uvm/riscv_dv_extension/testlist.yaml @@ -340,3 +340,16 @@ compare_opts: compare_final_value_only: 1 verbose: 1 + +- test: riscv_reset_test + description: > + Randomly reset the core once in the middle of program execution + iterations: 10 + gen_test: riscv_rand_instr_test + gen_opts: > + +instr_cnt=10000 + +num_of_sub_program=5 + rtl_test: core_ibex_reset_test + compare_opts: + compare_final_value_only: 1 + verbose: 1 diff --git a/dv/uvm/tb/core_ibex_tb_top.sv b/dv/uvm/tb/core_ibex_tb_top.sv index 9d8b0648..8b1fb9ba 100644 --- a/dv/uvm/tb/core_ibex_tb_top.sv +++ b/dv/uvm/tb/core_ibex_tb_top.sv @@ -7,11 +7,11 @@ module core_ibex_tb_top; import uvm_pkg::*; import core_ibex_test_pkg::*; - logic clk; - logic rst_n; + wire clk; + wire rst_n; logic fetch_enable; - clk_if ibex_clk_if(.clk(clk)); + clk_if ibex_clk_if(.clk(clk), .rst_n(rst_n)); irq_if irq_vif(); ibex_mem_intf data_mem_vif(); ibex_mem_intf instr_mem_vif(); @@ -94,6 +94,7 @@ module core_ibex_tb_top; assign dut_if.dret = dut.u_ibex_core.id_stage_i.dret_insn_dec; assign dut_if.mret = dut.u_ibex_core.id_stage_i.mret_insn_dec; assign dut_if.core_sleep = dut.u_ibex_core.core_sleep_o; + assign dut_if.reset = ~rst_n; initial begin @@ -106,20 +107,4 @@ module core_ibex_tb_top; run_test(); end - // Generate clk - initial begin - clk = 1'b0; - forever begin - #10 clk = ~clk; - end - end - - // Generate reset - initial begin - rst_n = 1'b0; - repeat(100) @(posedge clk); - rst_n = 1'b1; - dut_if.debug_req = 1'b0; - end - endmodule diff --git a/dv/uvm/tests/core_ibex_test_lib.sv b/dv/uvm/tests/core_ibex_test_lib.sv index c3c0b0de..551a8e56 100644 --- a/dv/uvm/tests/core_ibex_test_lib.sv +++ b/dv/uvm/tests/core_ibex_test_lib.sv @@ -31,6 +31,37 @@ class core_ibex_csr_test extends core_ibex_base_test; endclass +// Reset test +class core_ibex_reset_test extends core_ibex_base_test; + + `uvm_component_utils(core_ibex_reset_test) + `uvm_component_new + + virtual task send_stimulus(); + vseq.start(env.vseqr); + // Mid-test reset is possible in a wide range of times + clk_vif.wait_clks($urandom_range(20000, 200000)); + fork + begin + dut_vif.fetch_enable = 1'b0; + clk_vif.reset(); + end + begin + clk_vif.wait_clks(1); + // Flush FIFOs + item_collected_port.flush(); + irq_collected_port.flush(); + // Reset testbench state + env.reset(); + load_binary_to_mem(); + end + join + // Assert fetch_enable to have the core start executing from boot address + dut_vif.fetch_enable = 1'b1; + endtask + +endclass + // Performance counter test class class core_ibex_perf_test extends core_ibex_base_test;