diff --git a/dv/uvm/env/core_ibex_env_cfg.sv b/dv/uvm/env/core_ibex_env_cfg.sv index 8e0f2c75..06f99852 100644 --- a/dv/uvm/env/core_ibex_env_cfg.sv +++ b/dv/uvm/env/core_ibex_env_cfg.sv @@ -4,7 +4,8 @@ class core_ibex_env_cfg extends uvm_object; - bit enable_irq_seq; + bit enable_irq_single_seq; + bit enable_irq_multiple_seq; bit enable_debug_seq; bit[31:0] max_interval; bit require_signature_addr; @@ -12,7 +13,8 @@ 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_seq, UVM_DEFAULT) + `uvm_field_int(enable_irq_single_seq, UVM_DEFAULT) + `uvm_field_int(enable_irq_multiple_seq, UVM_DEFAULT) `uvm_field_int(enable_debug_seq, UVM_DEFAULT) `uvm_field_int(max_interval, UVM_DEFAULT) `uvm_field_int(require_signature_addr, UVM_DEFAULT) @@ -21,7 +23,8 @@ class core_ibex_env_cfg extends uvm_object; function new(string name = ""); super.new(name); - void'($value$plusargs("enable_irq_seq=%0d", enable_irq_seq)); + void'($value$plusargs("enable_irq_single_seq=%0d", enable_irq_single_seq)); + void'($value$plusargs("enable_irq_multiple_seq=%0d", enable_irq_multiple_seq)); void'($value$plusargs("enable_debug_seq=%0d", enable_debug_seq)); void'($value$plusargs("max_interval=%0d", max_interval)); void'($value$plusargs("require_signature_addr=%0d", require_signature_addr)); diff --git a/dv/uvm/riscv_dv_extension/testlist.yaml b/dv/uvm/riscv_dv_extension/testlist.yaml index 40ce371a..f3fed04f 100644 --- a/dv/uvm/riscv_dv_extension/testlist.yaml +++ b/dv/uvm/riscv_dv_extension/testlist.yaml @@ -289,7 +289,7 @@ compare_opts: compare_final_value_only: 1 -- test: riscv_interrupt_test +- test: riscv_single_interrupt_test description: > Random instruction test with complete interrupt handling iterations: 15 @@ -302,7 +302,24 @@ rtl_test: core_ibex_debug_intr_basic_test sim_opts: > +require_signature_addr=1 - +enable_irq_seq=1 + +enable_irq_single_seq=1 + compare_opts: + compare_final_value_only: 1 + +- test: riscv_multiple_interrupt_test + description: > + Random instruction test with complete interrupt handling + iterations: 10 + gen_test: riscv_rand_instr_test + gen_opts: > + +instr_cnt=10000 + +require_signature_addr=1 + +enable_interrupt=1 + +randomize_csr=1 + rtl_test: core_ibex_debug_intr_basic_test + sim_opts: > + +require_signature_addr=1 + +enable_irq_multiple_seq=1 compare_opts: compare_final_value_only: 1 @@ -320,7 +337,7 @@ rtl_test: core_ibex_irq_wfi_test sim_opts: > +require_signature_addr=1 - +enable_irq_seq=1 + +enable_irq_single_seq=1 compare_opts: compare_final_value_only: 1 @@ -338,7 +355,7 @@ rtl_test: core_ibex_irq_csr_test sim_opts: > +require_signature_addr=1 - +enable_irq_seq=1 + +enable_irq_single_seq=1 compare_opts: compare_final_value_only: 1 diff --git a/dv/uvm/tests/core_ibex_base_test.sv b/dv/uvm/tests/core_ibex_base_test.sv index c29bce2b..2969521b 100644 --- a/dv/uvm/tests/core_ibex_base_test.sv +++ b/dv/uvm/tests/core_ibex_base_test.sv @@ -11,6 +11,7 @@ class core_ibex_base_test extends uvm_test; virtual core_ibex_csr_if csr_vif; mem_model_pkg::mem_model mem; core_ibex_vseq vseq; + bit enable_irq_seq; int unsigned timeout_in_cycles = 10000000; // 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 @@ -59,12 +60,11 @@ class core_ibex_base_test extends uvm_test; 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 + env.irq_agent.monitor.irq_port.connect(this.irq_collected_port.analysis_export); endfunction virtual task run_phase(uvm_phase phase); + enable_irq_seq = cfg.enable_irq_single_seq || cfg.enable_irq_multiple_seq; phase.raise_objection(this); run = phase; dut_vif.fetch_enable = 1'b0; diff --git a/dv/uvm/tests/core_ibex_seq_lib.sv b/dv/uvm/tests/core_ibex_seq_lib.sv index 2d6ebf53..165d1581 100644 --- a/dv/uvm/tests/core_ibex_seq_lib.sv +++ b/dv/uvm/tests/core_ibex_seq_lib.sv @@ -65,6 +65,23 @@ class core_base_seq #(type REQ = uvm_sequence_item) extends uvm_sequence#(REQ); endclass // Interrupt sequences + +class irq_raise_seq extends core_base_seq#(irq_seq_item); + + `uvm_object_utils(irq_raise_seq) + `uvm_object_new + + virtual task send_req(); + irq_seq_item irq; + irq = irq_seq_item::type_id::create($sformatf("irq_raise_single[%0d]", iteration_cnt)); + start_item(irq); + `DV_CHECK_RANDOMIZE_WITH_FATAL(irq, num_of_interrupt > 1;) + finish_item(irq); + get_response(irq); + endtask + +endclass + class irq_raise_single_seq extends core_base_seq#(irq_seq_item); `uvm_object_utils(irq_raise_single_seq) @@ -74,7 +91,7 @@ class irq_raise_single_seq extends core_base_seq#(irq_seq_item); irq_seq_item irq; irq = irq_seq_item::type_id::create($sformatf("irq_raise_single[%0d]", iteration_cnt)); start_item(irq); - `DV_CHECK_RANDOMIZE_FATAL(irq) + `DV_CHECK_RANDOMIZE_WITH_FATAL(irq, num_of_interrupt == 1;) 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 d6575e5c..bd4fb8fd 100644 --- a/dv/uvm/tests/core_ibex_test_lib.sv +++ b/dv/uvm/tests/core_ibex_test_lib.sv @@ -156,6 +156,12 @@ class core_ibex_debug_intr_basic_test extends core_ibex_base_test; bit [ibex_mem_intf_agent_pkg::DATA_WIDTH-1:0] core_init_mie; priv_lvl_e operating_mode; bit [$clog2(irq_agent_pkg::DATA_WIDTH)-1:0] irq_id; + 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; virtual task send_stimulus(); fork @@ -172,7 +178,7 @@ class core_ibex_debug_intr_basic_test extends core_ibex_base_test; end fork begin - if (cfg.enable_irq_seq) begin + if (enable_irq_seq) begin forever begin send_irq_stimulus(); end @@ -199,24 +205,20 @@ class core_ibex_debug_intr_basic_test extends core_ibex_base_test; endtask 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; + bit irq_valid; // send the interrupt - vseq.start_irq_single_seq(); + if (cfg.enable_irq_single_seq) vseq.start_irq_raise_single_seq(); + else if (cfg.enable_irq_multiple_seq) vseq.start_irq_raise_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); + // there are multiple irqs asserted at once. + irq_valid = get_max_valid_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 + // lines to avoid locking up the simulation. + if (!irq_valid) 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, @@ -224,6 +226,7 @@ class core_ibex_debug_intr_basic_test extends core_ibex_base_test; `DV_CHECK_EQ_FATAL(irq, 0, "Interrupt lines have not been dropped") return; end + `uvm_info(`gfn, $sformatf("irq: 0b%0b", irq), UVM_LOW) check_next_core_status(HANDLING_IRQ, "Core did not jump to vectored interrupt handler", 750); check_priv_mode(PRIV_LVL_M); // check mstatus @@ -263,14 +266,22 @@ class core_ibex_debug_intr_basic_test extends core_ibex_base_test; wait_ret("mret", 1000); endtask - function int get_max_irq_id(bit [irq_agent_pkg::DATA_WIDTH-1:0] irq); + function int get_max_valid_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; + // Ibex implementation of MIE does not mask NM interrupts, so need to check this separately + if (irq[irq_agent_pkg::DATA_WIDTH - 1]) begin + irq_id = irq_agent_pkg::DATA_WIDTH - 1; + return 1; + end + for (i = irq_agent_pkg::DATA_WIDTH - 2; i >= 0; i = i - 1) begin + // Ensure that irq is active and unmasked by the core + if (irq[i] == 1'b1 && core_init_mie[i] == 1'b1) begin + irq_id = i; + return 1; break; end end + return 0; endfunction virtual task check_mcause(bit irq_or_exc, bit[ibex_mem_intf_agent_pkg::DATA_WIDTH-2:0] cause); @@ -353,7 +364,7 @@ class core_ibex_directed_test extends core_ibex_debug_intr_basic_test; clk_vif.wait_clks(stimulus_delay); fork begin - if (cfg.enable_irq_seq) begin + if (enable_irq_seq) begin forever begin send_irq_stimulus(); end @@ -458,7 +469,7 @@ class core_ibex_irq_csr_test extends core_ibex_directed_test; `uvm_component_new virtual task check_stimulus(); - vseq.irq_single_seq_h.max_delay = 0; + vseq.irq_raise_seq_h.max_delay = 0; // wait for a write to mstatus - should be in init code wait(csr_vif.csr_access === 1'b1 && csr_vif.csr_addr === CSR_MSTATUS && csr_vif.csr_op != CSR_OP_READ); diff --git a/dv/uvm/tests/core_ibex_vseq.sv b/dv/uvm/tests/core_ibex_vseq.sv index 3a71d78b..5cd9ddf1 100644 --- a/dv/uvm/tests/core_ibex_vseq.sv +++ b/dv/uvm/tests/core_ibex_vseq.sv @@ -11,7 +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_raise_single_seq irq_single_seq_h; + irq_raise_seq irq_raise_seq_h; + irq_raise_single_seq irq_raise_single_seq_h; irq_drop_seq irq_drop_seq_h; debug_seq debug_seq_stress_h; debug_seq debug_seq_single_h; @@ -25,13 +26,21 @@ 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_seq) begin - irq_single_seq_h = irq_raise_single_seq::type_id::create("irq_single_seq_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; - + if (cfg.enable_irq_single_seq) begin + irq_raise_single_seq_h = irq_raise_single_seq::type_id::create("irq_single_seq_h"); + irq_raise_single_seq_h.num_of_iterations = 1; + irq_raise_single_seq_h.max_interval = 1; + irq_raise_single_seq_h.max_delay = 500; + irq_raise_single_seq_h.interval = 0; + end + if (cfg.enable_irq_multiple_seq) begin + irq_raise_seq_h = irq_raise_seq::type_id::create("irq_raise_seq_h"); + irq_raise_seq_h.num_of_iterations = 1; + irq_raise_seq_h.max_interval = 1; + irq_raise_seq_h.max_delay = 500; + irq_raise_seq_h.interval = 0; + end + if (cfg.enable_irq_single_seq || cfg.enable_irq_multiple_seq) begin 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; @@ -58,8 +67,13 @@ class core_ibex_vseq extends uvm_sequence; endtask virtual task stop(); - if (cfg.enable_irq_seq) begin - if (irq_single_seq_h.is_started) irq_single_seq_h.stop(); + if (cfg.enable_irq_single_seq) begin + if (irq_raise_single_seq_h.is_started) irq_raise_single_seq_h.stop(); + end + if (cfg.enable_irq_multiple_seq) begin + if (irq_raise_seq_h.is_started) irq_raise_seq_h.stop(); + end + if (cfg.enable_irq_single_seq || cfg.enable_irq_multiple_seq) begin if (irq_drop_seq_h.is_started) irq_drop_seq_h.stop(); end if (cfg.enable_debug_seq) begin @@ -78,8 +92,12 @@ class core_ibex_vseq extends uvm_sequence; debug_seq_single_h.start(null); endtask - virtual task start_irq_single_seq(); - irq_single_seq_h.start(p_sequencer.irq_seqr); + virtual task start_irq_raise_single_seq(); + irq_raise_single_seq_h.start(p_sequencer.irq_seqr); + endtask + + virtual task start_irq_raise_seq(); + irq_raise_seq_h.start(p_sequencer.irq_seqr); endtask virtual task start_irq_drop_seq();