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 2a48b9d8..e57803dd 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 @@ -10,6 +10,9 @@ class ibex_mem_intf_slave_driver extends uvm_driver #(ibex_mem_intf_seq_item); protected virtual ibex_mem_intf vif; + int unsigned min_grant_delay = 0; + int unsigned max_grant_delay = 10; + `uvm_component_utils(ibex_mem_intf_slave_driver) `uvm_component_new @@ -55,15 +58,20 @@ class ibex_mem_intf_slave_driver extends uvm_driver #(ibex_mem_intf_seq_item); join_none endtask : get_and_drive - // TODO(udinator) - this direct send_grant logic is temporary until instruction fetch protocol - // issue is clarified (https://github.com/lowRISC/ibex/pull/293). After resolution, will re-add - // random delays insertion before driving grant to the ibex core. virtual protected task send_grant(); int gnt_delay; forever begin while(vif.request !== 1'b1) begin @(negedge vif.clock); end + std::randomize(gnt_delay) with { + gnt_delay dist { + min_grant_delay :/ 1, + [min_grant_delay+1 : max_grant_delay-1] :/ 1, + max_grant_delay :/ 1 + }; + }; + repeat(gnt_delay) @(negedge vif.clock); if(~vif.reset) begin vif.grant = 1'b1; @(negedge vif.clock); diff --git a/dv/uvm/common/irq_agent/irq_master_driver.sv b/dv/uvm/common/irq_agent/irq_master_driver.sv index 23ad25a6..6911e55b 100644 --- a/dv/uvm/common/irq_agent/irq_master_driver.sv +++ b/dv/uvm/common/irq_agent/irq_master_driver.sv @@ -52,11 +52,6 @@ class irq_master_driver extends uvm_driver #(irq_seq_item); vif.irq_external <= trans.irq_external; vif.irq_fast <= trans.irq_fast; vif.irq_nm <= trans.irq_nm; - // We hold the interrupt high for two cycles as Ibex is level sensitive, - // so this guarantees that Ibex will respond appropriately to the - // interrupt - repeat (2) @(posedge vif.clock); - drive_reset_value(); endtask : drive_seq_item task drive_reset_value(); diff --git a/dv/uvm/common/irq_agent/irq_monitor.sv b/dv/uvm/common/irq_agent/irq_monitor.sv index f3332f37..d4c53620 100644 --- a/dv/uvm/common/irq_agent/irq_monitor.sv +++ b/dv/uvm/common/irq_agent/irq_monitor.sv @@ -25,11 +25,23 @@ class irq_monitor extends uvm_monitor; collect_irq(); endtask : run_phase + // We know that for Ibex, any given interrupt stimulus will be asserted until the core signals the + // testbench that it has finished handling, and this stimulus will not change until the testbench + // receives the signal, at which point it will drop. + // Given this, as well as how the interrupt handshakes are designed, sending an irq_seq_item every + // cycle is not useful at all. + // In order to not send unnecessary sequence items, but to also send enough information that the + // testbench can handle nested interrupt scenarios, the monitor will send out a sequence + // item every time the interrupt lines change. virtual protected task collect_irq(); irq_seq_item irq; + bit[DATA_WIDTH-1:0] stored_irq_val = '0; + bit[DATA_WIDTH-1:0] current_irq = '0; forever begin - if (|{vif.irq_software, vif.irq_timer, vif.irq_external, - vif.irq_fast, vif.irq_nm}) begin + current_irq = {vif.irq_nm, vif.irq_fast, 4'b0, vif.irq_external, 3'b0, + vif.irq_timer, 3'b0, vif.irq_software, 3'b0}; + if (current_irq !== stored_irq_val) begin + stored_irq_val = current_irq; irq = irq_seq_item::type_id::create("irq"); irq.irq_software = vif.irq_software; irq.irq_timer = vif.irq_timer; diff --git a/dv/uvm/common/irq_agent/irq_seq_item.sv b/dv/uvm/common/irq_agent/irq_seq_item.sv index 771fa032..ccc99bcc 100644 --- a/dv/uvm/common/irq_agent/irq_seq_item.sv +++ b/dv/uvm/common/irq_agent/irq_seq_item.sv @@ -12,7 +12,7 @@ class irq_seq_item extends uvm_sequence_item; rand int num_of_interrupt; constraint num_of_interrupt_c { - num_of_interrupt inside {[1:19]}; + num_of_interrupt inside {[0:DATA_WIDTH-1]}; $countones({irq_software, irq_timer, irq_external, irq_fast, irq_nm}) == num_of_interrupt; } diff --git a/dv/uvm/env/core_ibex_dut_probe_if.sv b/dv/uvm/env/core_ibex_dut_probe_if.sv index 48fa34cd..efa9ff30 100644 --- a/dv/uvm/env/core_ibex_dut_probe_if.sv +++ b/dv/uvm/env/core_ibex_dut_probe_if.sv @@ -11,5 +11,6 @@ interface core_ibex_dut_probe_if(input logic clk); logic dret; logic mret; logic fetch_enable; + logic core_sleep; logic debug_req; endinterface diff --git a/dv/uvm/env/core_ibex_env.sv b/dv/uvm/env/core_ibex_env.sv index 58af2973..f2b04f10 100644 --- a/dv/uvm/env/core_ibex_env.sv +++ b/dv/uvm/env/core_ibex_env.sv @@ -25,7 +25,7 @@ class core_ibex_env extends uvm_env; create("data_if_slave_agent", this); instr_if_slave_agent = ibex_mem_intf_slave_agent::type_id:: create("instr_if_slave_agent", this); - if (cfg.enable_irq_stress_seq || cfg.enable_irq_single_seq) begin + if (cfg.enable_irq_seq) begin irq_agent = irq_master_agent::type_id::create("irq_agent", this); end // Create virtual sequencer @@ -36,7 +36,7 @@ class core_ibex_env extends uvm_env; super.connect_phase(phase); vseqr.data_if_seqr = data_if_slave_agent.sequencer; vseqr.instr_if_seqr = instr_if_slave_agent.sequencer; - if (cfg.enable_irq_stress_seq || cfg.enable_irq_single_seq) begin + if (cfg.enable_irq_seq) begin vseqr.irq_seqr = irq_agent.sequencer; end endfunction : connect_phase diff --git a/dv/uvm/env/core_ibex_env_cfg.sv b/dv/uvm/env/core_ibex_env_cfg.sv index 388bc247..988de600 100644 --- a/dv/uvm/env/core_ibex_env_cfg.sv +++ b/dv/uvm/env/core_ibex_env_cfg.sv @@ -4,8 +4,7 @@ class core_ibex_env_cfg extends uvm_object; - bit enable_irq_stress_seq; - bit enable_irq_single_seq; + bit enable_irq_seq; bit enable_debug_stress_seq; bit enable_debug_single_seq; bit[31:0] max_interval; @@ -13,8 +12,7 @@ class core_ibex_env_cfg extends uvm_object; bit[31:0] signature_addr; `uvm_object_utils_begin(core_ibex_env_cfg) - `uvm_field_int(enable_irq_stress_seq, UVM_DEFAULT) - `uvm_field_int(enable_irq_single_seq, UVM_DEFAULT) + `uvm_field_int(enable_irq_seq, UVM_DEFAULT) `uvm_field_int(enable_debug_single_seq, UVM_DEFAULT) `uvm_field_int(enable_debug_stress_seq, UVM_DEFAULT) `uvm_field_int(max_interval, UVM_DEFAULT) @@ -24,8 +22,7 @@ class core_ibex_env_cfg extends uvm_object; function new(string name = ""); super.new(name); - void'($value$plusargs("enable_irq_stress_seq=%0d", enable_irq_stress_seq)); - void'($value$plusargs("enable_irq_single_seq=%0d", enable_irq_single_seq)); + void'($value$plusargs("enable_irq_seq=%0d", enable_irq_seq)); void'($value$plusargs("enable_debug_stress_seq=%0d", enable_debug_stress_seq)); void'($value$plusargs("enable_debug_single_seq=%0d", enable_debug_single_seq)); void'($value$plusargs("max_interval=%0d", max_interval)); diff --git a/dv/uvm/riscv_dv_extension/riscv_core_setting.sv b/dv/uvm/riscv_dv_extension/riscv_core_setting.sv index fc8d572f..656acb76 100644 --- a/dv/uvm/riscv_dv_extension/riscv_core_setting.sv +++ b/dv/uvm/riscv_dv_extension/riscv_core_setting.sv @@ -37,6 +37,10 @@ riscv_instr_group_t supported_isa[$] = {RV32I, RV32M, RV32C}; // Interrupt mode support mtvec_mode_t supported_interrupt_mode[$] = {VECTORED}; +// The number of interrupt vectors to be generated, only used if VECTORED interrupt mode is +// supported +int max_interrupt_vector_num = 32; + // Debug mode support bit support_debug_mode = 1; @@ -46,8 +50,6 @@ bit support_umode_trap = 0; // Support sfence.vma instruction bit support_sfence = 0; -int max_interrupt_vector_num = 32; - //----------------------------------------------------------------------------- // Kernel section setting, used by supervisor mode programs //----------------------------------------------------------------------------- diff --git a/dv/uvm/riscv_dv_extension/testlist.yaml b/dv/uvm/riscv_dv_extension/testlist.yaml index cdb4c5aa..b02597ed 100644 --- a/dv/uvm/riscv_dv_extension/testlist.yaml +++ b/dv/uvm/riscv_dv_extension/testlist.yaml @@ -201,16 +201,6 @@ sim_opts: > +require_signature_addr=1 -- test: riscv_ebreak_test - description: > - Ebreak instructions will be inserted into the M mode code, ibex should handle them normally. - iterations: 5 - gen_test: riscv_rand_instr_test - gen_opts: > - +no_ebreak=0 - +instr_cnt=6000 - rtl_test: core_ibex_base_test - - test: riscv_debug_ebreak_test description: > A directed ebreak sequence will be inserted into the debug rom, upon encountering it, @@ -259,14 +249,15 @@ - test: riscv_interrupt_test description: > Random instruction test with complete interrupt handling - iterations: 0 + iterations: 10 gen_test: riscv_rand_instr_test gen_opts: > +require_signature_addr=1 + +enable_interrupt=1 rtl_test: core_ibex_debug_intr_basic_test sim_opts: > +require_signature_addr=1 - +enable_irq_stress_seq=1 + +enable_irq_seq=1 compare_opts: compare_final_value_only: 1 diff --git a/dv/uvm/sim.py b/dv/uvm/sim.py index ad5fa69f..50e7dbaf 100644 --- a/dv/uvm/sim.py +++ b/dv/uvm/sim.py @@ -143,6 +143,7 @@ def rtl_sim(sim_cmd, test_list, output_dir, bin_dir, lsf_cmd, seed, opts): rand_seed = get_seed(seed) test_sim_cmd = re.sub("", str(rand_seed), sim_cmd) if "sim_opts" in test: + test_sim_cmd += ' ' test_sim_cmd += test['sim_opts'] sim_dir = output_dir + ("/%s.%d" %(test['test'], i)) run_cmd(("mkdir -p %s" % sim_dir)) diff --git a/dv/uvm/tb/core_ibex_tb_top.sv b/dv/uvm/tb/core_ibex_tb_top.sv index 251ea864..9a3c8745 100644 --- a/dv/uvm/tb/core_ibex_tb_top.sv +++ b/dv/uvm/tb/core_ibex_tb_top.sv @@ -68,11 +68,12 @@ module core_ibex_tb_top; force irq_vif.reset = ~rst_n; end - assign dut_if.ecall = dut.u_ibex_core.id_stage_i.ecall_insn_dec; - assign dut_if.wfi = dut.u_ibex_core.id_stage_i.wfi_insn_dec; - assign dut_if.ebreak = dut.u_ibex_core.id_stage_i.ebrk_insn; - 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.ecall = dut.u_ibex_core.id_stage_i.ecall_insn_dec; + assign dut_if.wfi = dut.u_ibex_core.id_stage_i.wfi_insn_dec; + assign dut_if.ebreak = dut.u_ibex_core.id_stage_i.ebrk_insn; + 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; initial begin diff --git a/dv/uvm/tests/core_ibex_base_test.sv b/dv/uvm/tests/core_ibex_base_test.sv index 54cd2793..bef84643 100644 --- a/dv/uvm/tests/core_ibex_base_test.sv +++ b/dv/uvm/tests/core_ibex_base_test.sv @@ -10,7 +10,6 @@ class core_ibex_base_test extends uvm_test; virtual core_ibex_dut_probe_if dut_vif; mem_model_pkg::mem_model mem; core_ibex_vseq vseq; - irq_seq irq_seq_h; int unsigned timeout_in_cycles = 3000000; // If no signature_addr handshake functionality is desired between the testbench and the generated // code, the test will wait for the specifield number of cycles before starting stimulus @@ -19,6 +18,7 @@ class core_ibex_base_test extends uvm_test; bit[ibex_mem_intf_agent_pkg::DATA_WIDTH-1:0] signature_data_q[$]; bit[ibex_mem_intf_agent_pkg::DATA_WIDTH-1:0] signature_data; uvm_tlm_analysis_fifo #(ibex_mem_intf_seq_item) item_collected_port; + uvm_tlm_analysis_fifo #(irq_seq_item) irq_collected_port; `uvm_component_utils(core_ibex_base_test) @@ -28,6 +28,7 @@ class core_ibex_base_test extends uvm_test; ibex_report_server = new(); uvm_report_server::set_server(ibex_report_server); item_collected_port = new("item_collected_port_test", this); + irq_collected_port = new("irq_collected_port_test", this); endfunction virtual function void build_phase(uvm_phase phase); @@ -52,6 +53,9 @@ class core_ibex_base_test extends uvm_test; virtual function void connect_phase(uvm_phase phase); super.connect_phase(phase); env.data_if_slave_agent.monitor.item_collected_port.connect(this.item_collected_port.analysis_export); + if (cfg.enable_irq_seq) begin + env.irq_agent.monitor.irq_port.connect(this.irq_collected_port.analysis_export); + end endfunction virtual task run_phase(uvm_phase phase); @@ -165,7 +169,7 @@ class core_ibex_base_test extends uvm_test; // Gets the next CORE_STATUS signature write and compares it against the provided core_status // type, throws uvm_error on mismatch - virtual task check_next_core_status(core_status_t core_status, error_msg=""); + virtual task check_next_core_status(core_status_t core_status, string error_msg=""); wait_for_mem_txn(cfg.signature_addr, CORE_STATUS); signature_data = signature_data_q.pop_front(); if (signature_data != core_status) begin diff --git a/dv/uvm/tests/core_ibex_seq_lib.sv b/dv/uvm/tests/core_ibex_seq_lib.sv index 0170a475..60e70216 100644 --- a/dv/uvm/tests/core_ibex_seq_lib.sv +++ b/dv/uvm/tests/core_ibex_seq_lib.sv @@ -61,17 +61,38 @@ class core_base_seq #(type REQ = uvm_sequence_item) extends uvm_sequence#(REQ); endclass -// Interrupt sequence -class irq_seq extends core_base_seq#(irq_seq_item); +// Interrupt sequences +class irq_raise_single_seq extends core_base_seq#(irq_seq_item); - `uvm_object_utils(irq_seq) + `uvm_object_utils(irq_raise_single_seq) `uvm_object_new virtual task send_req(); irq_seq_item irq; - irq = irq_seq_item::type_id::create($sformatf("irq[%0d]", iteration_cnt)); + irq = irq_seq_item::type_id::create($sformatf("irq_raise_single[%0d]", iteration_cnt)); start_item(irq); - `DV_CHECK_RANDOMIZE_FATAL(irq) + // TODO(udinator) - constrain irq_timer to 0 for now due to timer interrupt causing spike + // simulator to trap to irq handler + `DV_CHECK_RANDOMIZE_WITH_FATAL(irq, irq_timer==0;) + finish_item(irq); + get_response(irq); + endtask + +endclass + +// Irq sequence to deassert all interrupt lines, since Ibex interrupts are level sensitive +class irq_drop_seq extends core_base_seq#(irq_seq_item); + + `uvm_object_utils(irq_drop_seq) + `uvm_object_new + + // TODO(udinator) - for nested interrupt tests, test scenarios where a random number of interrupts + // are dropped + virtual task send_req(); + irq_seq_item irq; + irq = irq_seq_item::type_id::create($sformatf("irq_drop[%0d]", iteration_cnt)); + start_item(irq); + `DV_CHECK_RANDOMIZE_WITH_FATAL(irq, num_of_interrupt == 0;) finish_item(irq); get_response(irq); endtask diff --git a/dv/uvm/tests/core_ibex_test_lib.sv b/dv/uvm/tests/core_ibex_test_lib.sv index c306e5b2..a149c4e7 100644 --- a/dv/uvm/tests/core_ibex_test_lib.sv +++ b/dv/uvm/tests/core_ibex_test_lib.sv @@ -37,6 +37,10 @@ class core_ibex_debug_intr_basic_test extends core_ibex_base_test; `uvm_component_utils(core_ibex_debug_intr_basic_test) `uvm_component_new + bit [ibex_mem_intf_agent_pkg::DATA_WIDTH-1:0] core_init_mstatus; + bit [ibex_mem_intf_agent_pkg::DATA_WIDTH-1:0] core_init_mie; + bit [$clog2(irq_agent_pkg::DATA_WIDTH)-1:0] irq_id; + virtual task send_stimulus(); fork begin @@ -44,7 +48,7 @@ class core_ibex_debug_intr_basic_test extends core_ibex_base_test; end begin if (cfg.require_signature_addr) begin - wait_for_core_status(INITIALIZED); + wait_for_core_setup(); end else begin // If no signature_addr functionality is desired, then the test will simply wait for an // adequate number of cycles @@ -52,13 +56,15 @@ class core_ibex_debug_intr_basic_test extends core_ibex_base_test; end fork begin - if (cfg.enable_irq_stress_seq) begin - vseq.start_irq_stress_seq(); + if (cfg.enable_irq_seq) begin + forever begin + send_irq_stimulus(); + end end end begin if (cfg.enable_debug_stress_seq) begin - vseq.start_debug_stress_seq(); + send_debug_stimulus(); end end join_none @@ -66,10 +72,119 @@ class core_ibex_debug_intr_basic_test extends core_ibex_base_test; join_none endtask + virtual task wait_for_core_setup(); + wait_for_csr_write(CSR_MSTATUS); + core_init_mstatus = signature_data; + wait_for_csr_write(CSR_MIE); + core_init_mie = signature_data; + check_next_core_status(INITIALIZED, "Core initialization handshake failure"); + endtask + + // TODO(udi) - much of this checking logic is based on the current design only implementing + // MACHINE_MODE, the checking will have to be modified once USER_MODE is implemented and merged, + // e.g. need to also check mideleg for correct privilege mode context switch + virtual task send_irq_stimulus(); + irq_seq_item irq_txn; + bit [irq_agent_pkg::DATA_WIDTH-1:0] irq; + bit [ibex_mem_intf_agent_pkg::DATA_WIDTH-1:0] mstatus; + bit [ibex_mem_intf_agent_pkg::DATA_WIDTH-1:0] mcause; + bit [ibex_mem_intf_agent_pkg::DATA_WIDTH-1:0] mip; + bit [ibex_mem_intf_agent_pkg::DATA_WIDTH-1:0] mie; + // send the interrupt + vseq.start_irq_single_seq(); + irq_collected_port.get(irq_txn); + irq = {irq_txn.irq_nm, irq_txn.irq_fast, 4'b0, irq_txn.irq_external, 3'b0, + irq_txn.irq_timer, 3'b0, irq_txn.irq_software, 3'b0}; + // Get the bit position of the highest priority interrupt - ibex will only handle this one if + // there are multiple irqs asserted at once + irq_id = get_max_irq_id(irq); + // If the interrupt is maskable, and the corresponding bit in MIE is not set, skip the next + // checks, as it means the interrupt in question is not enabled by Ibex, and drop the interrupt + // lines to avoid locking up the simulation + if (!irq_txn.irq_nm && !core_init_mie[irq_id]) begin + vseq.start_irq_drop_seq(); + irq_collected_port.get(irq_txn); + irq = {irq_txn.irq_nm, irq_txn.irq_fast, 4'b0, irq_txn.irq_external, 3'b0, + irq_txn.irq_timer, 3'b0, irq_txn.irq_software, 3'b0}; + `DV_CHECK_EQ_FATAL(irq, 0, "Interrupt lines have not been dropped") + return; + end + check_next_core_status(HANDLING_IRQ, "Core did not jump to vectored interrupt handler"); + // check mstatus + wait_for_csr_write(CSR_MSTATUS); + mstatus = signature_data; + `DV_CHECK_EQ_FATAL(mstatus[12:11], PRIV_LVL_M, "Incorrect privilege mode") + `DV_CHECK_EQ_FATAL(mstatus[7], 1'b1, "mstatus.mpie was not set to 1'b1 after entering handler") + `DV_CHECK_EQ_FATAL(mstatus[3], 1'b0, "mstatus.mie was not set to 1'b0 after entering handler") + // check mcause against the interrupt id + wait_for_csr_write(CSR_MCAUSE); + mcause = signature_data; + // check that mcause.interrupt is set + `DV_CHECK_EQ_FATAL(mcause[ibex_mem_intf_agent_pkg::DATA_WIDTH-1], 1'b1, + "mcause.interrupt is not set to 1'b1") + // check that mcause.exception_code matches the current interrupt's ID + `DV_CHECK_EQ_FATAL(mcause[ibex_mem_intf_agent_pkg::DATA_WIDTH-2:0], irq_id, + "mcause.exception_code is encoding the wrong interrupt type") + // Wait for MIE and MIP to be written regardless of what interrupt ibex is dealing with, to + // prevent the case where MIP/MIE stays at 0 due to a nonmaskable interrupt, which will falsely + // trigger the following call of check_next_core_status() + wait_for_csr_write(CSR_MIE); + mie = signature_data; + wait_for_csr_write(CSR_MIP); + mip = signature_data; + // only check mip, and mie if the interrupt is not irq_nm, as Ibex's implementation of MIP and + // MIE CSRs do not contain a bit for irq_nm + if (!irq_txn.irq_nm) begin + // check that the proper bit in MIE is high + `DV_CHECK_EQ_FATAL(mie[irq_id], 1'b1, + $sformatf("mie[%0d] is not set, but core responded to corresponding interrupt", irq_id)) + // check that the proper bit in MIP is high + `DV_CHECK_EQ_FATAL(mip[irq_id], 1'b1, + $sformatf("mip[%0d] is not set, but core responded to corresponding interrupt", irq_id)) + end + // As Ibex interrupts are level sensitive, core must write to memory mapped address to + // indicate that irq stimulus be dropped + check_next_core_status(FINISHED_IRQ, "Core did not signal end of interrupt properly"); + // Will receive irq_seq_item indicating that lines have been dropped + vseq.start_irq_drop_seq(); + irq_collected_port.get(irq_txn); + irq = {irq_txn.irq_nm, irq_txn.irq_fast, 4'b0, irq_txn.irq_external, 3'b0, + irq_txn.irq_timer, 3'b0, irq_txn.irq_software, 3'b0}; + `DV_CHECK_EQ_FATAL(irq, 0, "Interrupt lines have not been dropped") + wait (dut_vif.mret === 1'b1); + endtask + + function int get_max_irq_id(bit [irq_agent_pkg::DATA_WIDTH-1:0] irq); + int i; + for (i = irq_agent_pkg::DATA_WIDTH-1; i >= 0; i = i - 1) begin + if (irq[i] === 1'b1) begin + return i; + break; + end + end + endfunction + + // Basic debug stimulus check for Ibex for debug stimulus stress tests: check that Ibex enters + // debug mode properly after stimulus is sent and then check that a dret is encountered signifying + // the end of debug mode. + virtual task send_debug_stimulus(); + fork + begin + vseq.start_debug_stress_seq(); + end + begin + forever begin + check_next_core_status(IN_DEBUG_MODE, "Core did not enter debug mode properly"); + wait(dut_vif.dret === 1'b1); + end + end + join_none + endtask + endclass // Base class for directed debug and irq test scenarios -class core_ibex_directed_test extends core_ibex_base_test; +class core_ibex_directed_test extends core_ibex_debug_intr_basic_test; `uvm_component_utils(core_ibex_directed_test) `uvm_component_new @@ -84,20 +199,22 @@ class core_ibex_directed_test extends core_ibex_base_test; clk_vif.wait_clks(stimulus_delay); fork begin - if (cfg.enable_irq_stress_seq) begin - vseq.start_irq_stress_seq(); + if (cfg.enable_irq_seq) begin + forever begin + send_irq_stimulus(); + end end end begin if (cfg.enable_debug_stress_seq) begin - vseq.start_debug_stress_seq(); + send_debug_stimulus(); end end join_none end else begin // Wait for core initialization before starting the stimulus check loop - first write // to signature address is guaranteed to be core initialization info - check_next_core_status(INITIALIZED, "Core initialization handshake failure"); + wait_for_core_setup(); // Should be extended by derived classes. // DO NOT use this test class directly. check_stimulus(); diff --git a/dv/uvm/tests/core_ibex_vseq.sv b/dv/uvm/tests/core_ibex_vseq.sv index 53ccc750..2a754c65 100644 --- a/dv/uvm/tests/core_ibex_vseq.sv +++ b/dv/uvm/tests/core_ibex_vseq.sv @@ -11,8 +11,8 @@ class core_ibex_vseq extends uvm_sequence; ibex_mem_intf_slave_seq instr_intf_seq; ibex_mem_intf_slave_seq data_intf_seq; mem_model_pkg::mem_model mem; - irq_seq irq_seq_stress_h; - irq_seq irq_seq_single_h; + irq_raise_single_seq irq_single_seq_h; + irq_drop_seq irq_drop_seq_h; debug_seq debug_seq_stress_h; debug_seq debug_seq_single_h; core_ibex_env_cfg cfg; @@ -25,17 +25,18 @@ class core_ibex_vseq extends uvm_sequence; virtual task body(); instr_intf_seq = ibex_mem_intf_slave_seq::type_id::create("instr_intf_seq"); data_intf_seq = ibex_mem_intf_slave_seq::type_id::create("data_intf_seq"); - if (cfg.enable_irq_stress_seq) begin - irq_seq_stress_h = irq_seq::type_id::create("irq_seq_stress_h"); - irq_seq_stress_h.max_interval = cfg.max_interval; - end - if (cfg.enable_irq_single_seq) begin - irq_seq_single_h = irq_seq::type_id::create("irq_seq_single_h"); - irq_seq_single_h.num_of_iterations = 1; - irq_seq_single_h.max_interval = 1; - irq_seq_single_h.max_delay = 1; - irq_seq_single_h.interval.rand_mode(0); - irq_seq_single_h.interval = 0; + if (cfg.enable_irq_seq) begin + irq_single_seq_h = irq_raise_single_seq::type_id::create("irq_seq_single_h"); + irq_single_seq_h.num_of_iterations = 1; + irq_single_seq_h.max_interval = 1; + irq_single_seq_h.max_delay = 500; + irq_single_seq_h.interval = 0; + + irq_drop_seq_h = irq_drop_seq::type_id::create("irq_drop_seq_h"); + irq_drop_seq_h.num_of_iterations = 1; + irq_drop_seq_h.max_interval = 1; + irq_drop_seq_h.max_delay = 1; + irq_drop_seq_h.interval = 0; end if (cfg.enable_debug_stress_seq) begin debug_seq_stress_h = debug_seq::type_id::create("debug_seq_stress_h"); @@ -58,11 +59,9 @@ class core_ibex_vseq extends uvm_sequence; endtask virtual task stop(); - if (cfg.enable_irq_stress_seq) begin - irq_seq_stress_h.stop(); - end - if (cfg.enable_irq_single_seq) begin - irq_seq_single_h.stop(); + if (cfg.enable_irq_seq) begin + irq_single_seq_h.stop(); + irq_drop_seq_h.stop(); end if (cfg.enable_debug_stress_seq) begin debug_seq_stress_h.stop(); @@ -82,12 +81,12 @@ class core_ibex_vseq extends uvm_sequence; debug_seq_single_h.start(null); endtask - virtual task start_irq_stress_seq(); - irq_seq_stress_h.start(p_sequencer.irq_seqr); + virtual task start_irq_single_seq(); + irq_single_seq_h.start(p_sequencer.irq_seqr); endtask - virtual task start_irq_single_seq(); - irq_seq_single_h.start(p_sequencer.irq_seqr); + virtual task start_irq_drop_seq(); + irq_drop_seq_h.start(p_sequencer.irq_seqr); endtask endclass