mirror of
https://github.com/lowRISC/ibex.git
synced 2025-04-22 04:47:25 -04:00
[DV] Enable sending multiple interrupts at once (#519)
This commit is contained in:
parent
c246a2aeb9
commit
5d66a865cd
6 changed files with 107 additions and 41 deletions
9
dv/uvm/env/core_ibex_env_cfg.sv
vendored
9
dv/uvm/env/core_ibex_env_cfg.sv
vendored
|
@ -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));
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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();
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue