[DV] Enable sending multiple interrupts at once (#519)

This commit is contained in:
udinator 2019-12-16 13:15:12 -08:00 committed by GitHub
parent c246a2aeb9
commit 5d66a865cd
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
6 changed files with 107 additions and 41 deletions

View file

@ -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));

View file

@ -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

View file

@ -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;

View file

@ -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

View file

@ -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);

View file

@ -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();