Interrupt verif : Implement clear mechanism in interrupt's agent (#2527)
Some checks are pending
bender-up-to-date / bender-up-to-date (push) Waiting to run
ci / build-riscv-tests (push) Waiting to run
ci / execute-riscv64-tests (push) Blocked by required conditions
ci / execute-riscv32-tests (push) Blocked by required conditions

* INTERRUPT VERIF : Implement interrupt clear mechanism

* Interrupt Verif : Add irq_timeout to exit when we failed to write into irq_add

Also change uvm_warining to uvm_info

* Fix comment
This commit is contained in:
Jalali 2024-10-16 15:50:56 +00:00 committed by GitHub
parent 1de0da8d96
commit 7394941220
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
21 changed files with 418 additions and 289 deletions

View file

@ -175,7 +175,7 @@ class cva6_asm_program_gen_c extends riscv_asm_program_gen;
end else begin
// Push user mode GPR to kernel stack before executing exception handling, this is to avoid
// exception handling routine modify user program state unexpectedly
push_used_gpr_to_kernel_stack(status, scratch, 4, cfg_cva6.mstatus_mprv, cfg_cva6.sp, cfg_cva6.tp, instr);
push_used_gpr_to_kernel_stack(status, scratch, 3, cfg_cva6.mstatus_mprv, cfg_cva6.sp, cfg_cva6.tp, instr);
// Checking xStatus can be optional if ISS (like spike) has different implementation of
// certain fields compared with the RTL processor.
if (cfg_cva6.check_xstatus) begin
@ -187,16 +187,19 @@ class cva6_asm_program_gen_c extends riscv_asm_program_gen;
// Check if the exception is caused by an interrupt, if yes, jump to interrupt
// handler Interrupt is indicated by xCause[XLEN-1]
$sformatf("csrr x%0d, 0x%0x # %0s", cfg_cva6.gpr[0], cause, cause.name()),
$sformatf("srli x%0d, x%0d, %0d", cfg_cva6.gpr[0], cfg_cva6.gpr[0], XLEN-1),
$sformatf("bne x%0d, x0, %0s%0s_intr_handler",
cfg_cva6.gpr[0], hart_prefix(hart), mode),
$sformatf("csrr x%0d, mepc", cfg_cva6.gpr[0]),
$sformatf("lbu x%0d, 0(x%0d)", cfg_cva6.gpr[3],cfg_cva6.gpr[0]),
$sformatf("lbu x%0d, 0(x%0d)", cfg_cva6.gpr[2],cfg_cva6.gpr[0]),
$sformatf("li x%0d, 0x3", cfg_cva6.gpr[1]),
$sformatf("and x%0d, x%0d, x%0d", cfg_cva6.gpr[3], cfg_cva6.gpr[3], cfg_cva6.gpr[1]),
$sformatf("bne x%0d, x%0d, exception_handler_incr_mepc2", cfg_cva6.gpr[3], cfg_cva6.gpr[1]),
$sformatf("and x%0d, x%0d, x%0d", cfg_cva6.gpr[2], cfg_cva6.gpr[2], cfg_cva6.gpr[1]),
$sformatf("bne x%0d, x%0d, exception_handler_incr_mepc2", cfg_cva6.gpr[2], cfg_cva6.gpr[1]),
$sformatf("addi x%0d, x%0d, 2", cfg_cva6.gpr[0], cfg_cva6.gpr[0]),
str,
$sformatf("addi x%0d, x%0d, 2", cfg_cva6.gpr[0], cfg_cva6.gpr[0]),
$sformatf("csrw mepc, x%0d", cfg_cva6.gpr[0])};
pop_used_gpr_from_kernel_stack(MSTATUS, MSCRATCH, 4, cfg.mstatus_mprv, cfg.sp, cfg.tp, instr);
pop_used_gpr_from_kernel_stack(MSTATUS, MSCRATCH, 3, cfg_cva6.mstatus_mprv, cfg_cva6.sp, cfg_cva6.tp, instr);
instr.push_back("mret");
end
// The trap handler will occupy one 4KB page, it will be allocated one entry in the page table
@ -213,7 +216,49 @@ class cva6_asm_program_gen_c extends riscv_asm_program_gen;
if (cfg_cva6.mtvec_mode == VECTORED) begin
push_gpr_to_kernel_stack(status, scratch, cfg_cva6.mstatus_mprv, cfg_cva6.sp, cfg_cva6.tp, instr);
end
gen_signature_handshake(instr, CORE_STATUS, HANDLING_EXCEPTION);
//~ push_used_gpr_to_kernel_stack(status, scratch, 3, cfg_cva6.mstatus_mprv, cfg_cva6.sp, cfg_cva6.tp, instr);
instr = {instr,
// The trap is caused by an exception, read back xCAUSE, xEPC to see if these
// CSR values are set properly.
$sformatf("csrr x%0d, 0x%0x # %0s", cfg_cva6.gpr[0], epc, epc.name()),
$sformatf("csrr x%0d, 0x%0x # %0s", cfg_cva6.gpr[0], cause, cause.name()),
$sformatf("li x%0d, 0x8000000b", cfg_cva6.gpr[1]),
$sformatf("li x%0d, 0x80000007", cfg_cva6.gpr[2]),
$sformatf("beq x%0d, x%0d, ext_interrupt_handler", cfg_cva6.gpr[0], cfg_cva6.gpr[1]),
$sformatf("beq x%0d, x%0d, timer_interrupt_handler", cfg_cva6.gpr[0], cfg_cva6.gpr[2]),
$sformatf("j test_done")
};
gen_section(get_label($sformatf("%0s_intr_handler", mode), hart), instr);
instr = {};
instr = {instr,
// The trap is caused by an external interrupt, read back xIP
// Write into int_ack 0x1 value
$sformatf("csrr x%0d, 0x%0x # %0s", cfg_cva6.gpr[0], epc, ip.name()),
$sformatf("li x%0d, 0", cfg_cva6.gpr[0]),
$sformatf("addi x%0d, x%0d, 1", cfg_cva6.gpr[0], cfg_cva6.gpr[0]),
// Clean external pending interrupt
$sformatf("sw x%0d, int_ack, x%0d # %0s;",
cfg_cva6.gpr[0], cfg_cva6.gpr[1], ip.name())
};
pop_used_gpr_from_kernel_stack(MSTATUS, MSCRATCH, 3, cfg_cva6.mstatus_mprv, cfg_cva6.sp, cfg_cva6.tp, instr);
instr.push_back("mret");
gen_section(get_label($sformatf("ext_interrupt_handler"), hart), instr);
instr = {};
instr = {instr,
// The trap is caused by a timer interrupt, read back xIP
// Write into int_ack 0x2 value
$sformatf("csrr x%0d, 0x%0x # %0s", cfg_cva6.gpr[0], epc, ip.name()),
$sformatf("li x%0d, 0", cfg_cva6.gpr[0]),
$sformatf("addi x%0d, x%0d, 2", cfg_cva6.gpr[0], cfg_cva6.gpr[0]),
// Clean timer pending interrupt
$sformatf("sw x%0d, int_ack, x%0d",
cfg_cva6.gpr[0], cfg_cva6.gpr[1])
};
pop_used_gpr_from_kernel_stack(MSTATUS, MSCRATCH, 3, cfg_cva6.mstatus_mprv, cfg_cva6.sp, cfg_cva6.tp, instr);
instr.push_back("mret");
gen_section(get_label($sformatf("timer_interrupt_handler"), hart), instr);
endfunction
// Push used general purpose register to stack, this is needed before trap handling
@ -314,31 +359,31 @@ class cva6_asm_program_gen_c extends riscv_asm_program_gen;
test_result_t test_result = TEST_FAIL,
privileged_reg_t csr = MSCRATCH,
string addr_label = "");
if (cfg.require_signature_addr) begin
if (cfg_cva6.require_signature_addr) begin
string str[$];
str = {$sformatf("li x%0d, 0x%0h", cfg.gpr[1], cfg.signature_addr)};
str = {$sformatf("li x%0d, 0x%0h", cfg_cva6.gpr[1], cfg_cva6.signature_addr)};
instr = {instr, str};
case (signature_type)
// A single data word is written to the signature address.
// Bits [7:0] contain the signature_type of CORE_STATUS, and the upper
// XLEN-8 bits contain the core_status_t data.
CORE_STATUS: begin
str = {$sformatf("li x%0d, 0x%0h", cfg.gpr[0], core_status),
$sformatf("slli x%0d, x%0d, 8", cfg.gpr[0], cfg.gpr[0]),
$sformatf("addi x%0d, x%0d, 0x%0h", cfg.gpr[0],
cfg.gpr[0], signature_type),
$sformatf("sw x%0d, 0(x%0d)", cfg.gpr[0], cfg.gpr[1])};
str = {$sformatf("li x%0d, 0x%0h", cfg_cva6.gpr[0], core_status),
$sformatf("slli x%0d, x%0d, 8", cfg_cva6.gpr[0], cfg_cva6.gpr[0]),
$sformatf("addi x%0d, x%0d, 0x%0h", cfg_cva6.gpr[0],
cfg_cva6.gpr[0], signature_type),
$sformatf("sw x%0d, 0(x%0d)", cfg_cva6.gpr[0], cfg_cva6.gpr[1])};
instr = {instr, str};
end
// A single data word is written to the signature address.
// Bits [7:0] contain the signature_type of TEST_RESULT, and the upper
// XLEN-8 bits contain the test_result_t data.
TEST_RESULT: begin
str = {$sformatf("li x%0d, 0x%0h", cfg.gpr[0], test_result),
$sformatf("slli x%0d, x%0d, 8", cfg.gpr[0], cfg.gpr[0]),
$sformatf("addi x%0d, x%0d, 0x%0h", cfg.gpr[0],
cfg.gpr[0], signature_type),
$sformatf("sw x%0d, 0(x%0d)", cfg.gpr[0], cfg.gpr[1])};
str = {$sformatf("li x%0d, 0x%0h", cfg_cva6.gpr[0], test_result),
$sformatf("slli x%0d, x%0d, 8", cfg_cva6.gpr[0], cfg_cva6.gpr[0]),
$sformatf("addi x%0d, x%0d, 0x%0h", cfg_cva6.gpr[0],
cfg_cva6.gpr[0], signature_type),
$sformatf("sw x%0d, 0(x%0d)", cfg_cva6.gpr[0], cfg_cva6.gpr[1])};
instr = {instr, str};
end
// The first write to the signature address contains just the
@ -347,11 +392,11 @@ class cva6_asm_program_gen_c extends riscv_asm_program_gen;
// each writing the data contained in one GPR, starting from x0 as the
// first write, and ending with x31 as the 32nd write.
WRITE_GPR: begin
str = {$sformatf("li x%0d, 0x%0h", cfg.gpr[0], signature_type),
$sformatf("sw x%0d, 0(x%0d)", cfg.gpr[0], cfg.gpr[1])};
str = {$sformatf("li x%0d, 0x%0h", cfg_cva6.gpr[0], signature_type),
$sformatf("sw x%0d, 0(x%0d)", cfg_cva6.gpr[0], cfg_cva6.gpr[1])};
instr = {instr, str};
for(int i = 0; i < 32; i++) begin
str = {$sformatf("sw x%0x, 0(x%0d)", i, cfg.gpr[1])};
str = {$sformatf("sw x%0x, 0(x%0d)", i, cfg_cva6.gpr[1])};
instr = {instr, str};
end
end
@ -364,13 +409,13 @@ class cva6_asm_program_gen_c extends riscv_asm_program_gen;
if (!(csr inside {implemented_csr})) begin
return;
end
str = {$sformatf("li x%0d, 0x%0h", cfg.gpr[0], csr),
$sformatf("slli x%0d, x%0d, 8", cfg.gpr[0], cfg.gpr[0]),
$sformatf("addi x%0d, x%0d, 0x%0h", cfg.gpr[0],
cfg.gpr[0], signature_type),
$sformatf("sw x%0d, 0(x%0d)", cfg.gpr[0], cfg.gpr[1]),
$sformatf("csrr x%0d, 0x%0h", cfg.gpr[0], csr),
$sformatf("sw x%0d, 0(x%0d)", cfg.gpr[0], cfg.gpr[1])};
str = {$sformatf("li x%0d, 0x%0h", cfg_cva6.gpr[0], csr),
$sformatf("slli x%0d, x%0d, 8", cfg_cva6.gpr[0], cfg_cva6.gpr[0]),
$sformatf("addi x%0d, x%0d, 0x%0h", cfg_cva6.gpr[0],
cfg_cva6.gpr[0], signature_type),
$sformatf("sw x%0d, 0(x%0d)", cfg_cva6.gpr[0], cfg_cva6.gpr[1]),
$sformatf("csrr x%0d, 0x%0h", cfg_cva6.gpr[0], csr),
$sformatf("sw x%0d, 0(x%0d)", cfg_cva6.gpr[0], cfg_cva6.gpr[1])};
instr = {instr, str};
end
default: begin
@ -385,9 +430,19 @@ class cva6_asm_program_gen_c extends riscv_asm_program_gen;
instr_stream.push_back(str);
instr_stream.push_back({indent, "li gp, 1"});
instr_stream.push_back({indent, "sw gp, tohost, t5"});
instr_stream.push_back({indent, "wfi"});
instr_stream.push_back({indent, "end_of_test: j end_of_test"});
endfunction
virtual function void gen_data_page_begin(int hart);
instr_stream.push_back(".section .data");
if (hart == 0) begin
instr_stream.push_back(".align 6; .global tohost; tohost: .dword 0;");
instr_stream.push_back(".align 6; .global fromhost; fromhost: .dword 0;");
instr_stream.push_back(".align 6; .global int_ack; int_ack: .dword 0;");
end
endfunction
endclass : cva6_asm_program_gen_c
`endif // __CVA6_ASM_PROGRAM_GEN_SV__

View file

@ -19,7 +19,8 @@
// Original Author: Ayoub JALALI (ayoub.jalali@external.thalesgroup.com)
covergroup cg_interrupt(
string name
string name,
bit sw_int_supported
) with function sample (
uvma_isacov_instr_c instr
);
@ -29,6 +30,7 @@ covergroup cg_interrupt(
cp_interrupt: coverpoint instr.rvfi.name_csrs["mcause"].wdata {
bins NO_INTERRUPT = {0} iff (!instr.trap);
ignore_bins IGN_SOFTWARE_INTERRUPT = {32'h80000003} iff (!sw_int_supported);
bins MACHINE_MODE_EXTERNAL_INTERRUPT = {32'h8000000b} iff (instr.trap);
bins MACHINE_MODE_SOFTWARE_INTERRUPT = {32'h80000003} iff (instr.trap);
bins MACHINE_MODE_TIMER_INTERRUPT = {32'h80000007} iff (instr.trap);
@ -40,6 +42,7 @@ covergroup cg_interrupt(
}
cp_msie: coverpoint instr.rvfi.name_csrs["mie"].wdata[3] {
ignore_bins IGN_MSIE = {1'h1} iff (!sw_int_supported);
bins MSIE = {1'h1};
}
@ -52,6 +55,7 @@ covergroup cg_interrupt(
}
cp_msip: coverpoint instr.rvfi.name_csrs["mip"].wdata[3] {
ignore_bins IGN_MSIP = {1'h1} iff (!sw_int_supported);
bins MSIP = {1'h1};
}
@ -106,8 +110,8 @@ function void uvme_interrupt_covg_c::build_phase(uvm_phase phase);
end
if (!cfg.disable_all_csr_checks)
interrupt_cg = new("interrupt_cg");
else
interrupt_cg = new("interrupt_cg",
.sw_int_supported(cfg.sw_int_supported)); else
`uvm_warning(get_type_name(), "Interrupt coverage will not be scored since config disable_all_csr_checks is true")
mon_trn_fifo = new("mon_trn_fifo" , this);
@ -127,4 +131,3 @@ task uvme_interrupt_covg_c::run_phase(uvm_phase phase);
end
endtask : run_phase

View file

@ -12,14 +12,17 @@
`define __UVMA_INTERRUPT_COV_MODEL_SV__
covergroup cg_interrupt(
string name
string name,
int unsigned num_irq_supported
) with function
sample(uvma_interrupt_seq_item_c req_item);
option.per_instance = 1;
option.name = name;
cp_interrupt_req : coverpoint req_item.interrupt_valid;
cp_interrupt_req : coverpoint req_item.interrupt_vector {
bins INTERRUPTS[] = {[0:$]} with (item inside {[0:(2**(num_irq_supported))-1]});
}
endgroup: cg_interrupt
@ -77,15 +80,16 @@ function void uvma_interrupt_cov_model_c::build_phase(uvm_phase phase);
void'(uvm_config_db#(uvma_interrupt_cfg_c)::get(this, "", "cfg", cfg));
if (cfg == null) begin
`uvm_fatal("CFG", "Configuration handle is null")
`uvm_fatal(get_type_name(), "Configuration handle is null")
end
void'(uvm_config_db#(uvma_interrupt_cntxt_c)::get(this, "", "cntxt", cntxt));
if (cntxt == null) begin
`uvm_fatal("CNTXT", "Context handle is null")
`uvm_fatal(get_type_name(), "Context handle is null")
end
interrupt_cg = new("interrupt_cg");
interrupt_cg = new("interrupt_cg",
.num_irq_supported(cfg.num_irq_supported));
seq_item_fifo = new("seq_item_fifo", this);

View file

@ -11,25 +11,47 @@
`ifndef __UVMA_INTERRUPT_SEQ_SV__
`define __UVMA_INTERRUPT_SEQ_SV__
/**
* Abstract object from which all other Interrupt agent sequences must extend.
* Subclasses must be run on Interrupt sequencer (uvma_interrupt_sqr_c) instance.
*/
class uvma_interrupt_seq_c extends uvma_interrupt_base_seq_c;
`uvm_object_utils(uvma_interrupt_seq_c)
`uvm_declare_p_sequencer(uvma_interrupt_sqr_c)
bit [XLEN-1:0] IRQ_ACK_VALUE = 'h0;
int unsigned IRQ_TIMEOUT;
/**
* Default constructor.
*/
extern function new(string name="uvma_interrupt_seq");
extern virtual task automatic clear_irq_channel(int channel, uvma_interrupt_seq_item_c req_item);
extern virtual task body();
endclass : uvma_interrupt_seq_c
task automatic uvma_interrupt_seq_c::clear_irq_channel(int channel, uvma_interrupt_seq_item_c req_item);
IRQ_TIMEOUT = cfg.irq_timeout;
while(1) begin
IRQ_ACK_VALUE = cntxt.mem.read(cfg.irq_addr);
if (IRQ_ACK_VALUE[channel]) begin
req_item.interrupt_vector[channel] = 1'h0;
`uvm_info(get_type_name(), $sformatf("Clear interrupt channel N-%2d -> mem = 0x%x",channel, IRQ_ACK_VALUE), UVM_NONE);
IRQ_TIMEOUT = cfg.irq_timeout;
break;
end
else begin
if (IRQ_TIMEOUT == 0) begin
`uvm_fatal(get_type_name(), $sformatf("Timeout : failed to write into irq_add to clear pending interrupts"));
end
IRQ_TIMEOUT = IRQ_TIMEOUT - 1;
end
@(posedge cntxt.interrupt_vif.clk);
end
endtask : clear_irq_channel
function uvma_interrupt_seq_c::new(string name="uvma_interrupt_seq");
super.new(name);
@ -38,22 +60,47 @@ endfunction : new
task uvma_interrupt_seq_c::body();
forever begin
req_item = uvma_interrupt_seq_item_c::type_id::create("req_item");
start_item(req_item);
assert(req_item.randomize() with {
if(!cfg.enable_interrupt){
req_item.interrupt_valid == 'h0;
}
else {
req_item.irq_cntrl != UVMA_INTERRUPT_RANDOMIZE;
}
})
cfg.calc_random_req_latency();
finish_item(req_item);
end
if (cfg.enable_interrupt) begin
for (int i = 0; i < cfg.num_irq_supported; i++) begin
automatic int ii = i;
automatic uvma_interrupt_seq_item_c req_item_c;
fork begin
forever begin
// Set interrupt request per channel
req_item_c = uvma_interrupt_seq_item_c::type_id::create("req_item_c");
start_item(req_item_c);
if (!req_item_c.randomize() with {
req_item_c.interrupt_vector[ii] inside {0 , 1};
req_item_c.interrupt_channel_mask == 1<<ii;
})
`uvm_error(get_type_name(), "req_item_c.randomize() failed!")
finish_item(req_item_c);
#req_item_c.irq_set_delay;
// Clear interrupt request per channel
if (req_item_c.interrupt_vector[ii]) begin
req_item_c = uvma_interrupt_seq_item_c::type_id::create("req_item_c");
if (cfg.enable_clear_irq) begin
clear_irq_channel(ii, req_item_c);
start_item(req_item_c);
finish_item(req_item_c);
#req_item_c.irq_clear_delay;
end
else begin
req_item_c.interrupt_vector[ii] = 'h0;
start_item(req_item_c);
finish_item(req_item_c);
#req_item_c.irq_clear_delay;
end
end
end
end
join_none
end
wait fork;
end
else begin
`uvm_info(get_type_name(), $sformatf("Interrupts are disabled"), UVM_NONE);
end
endtask : body

View file

@ -17,36 +17,23 @@
*/
class uvma_interrupt_seq_item_c extends uvml_trn_seq_item_c;
rand uvma_interrupt_cntrl_enum irq_cntrl;
rand int unsigned irq_delay; // Delay before applying individual interrupt
rand int unsigned irq_time; // How many cycles take an interrupt
rand int unsigned irq_set_delay; // Delay after set individual interrupt
rand int unsigned irq_clear_delay; // Delay after clear individual interrupt
rand bit[NUM_IRQ-1:0] interrupt_valid; //the valid interrupts for the core under test
rand bit [15:0] interrupt_vector; //the vector interrupts for the core under test
rand bit [15:0] interrupt_channel_mask; //the vector interrupts for the core under test
`uvm_object_utils_begin(uvma_interrupt_seq_item_c)
`uvm_field_enum(uvma_interrupt_cntrl_enum, irq_cntrl, UVM_DEFAULT)
`uvm_field_int(irq_delay, UVM_DEFAULT)
`uvm_field_int(irq_time, UVM_DEFAULT)
`uvm_field_int(interrupt_valid, UVM_DEFAULT)
`uvm_field_int(irq_set_delay, UVM_DEFAULT)
`uvm_field_int(irq_clear_delay, UVM_DEFAULT)
`uvm_field_int(interrupt_vector, UVM_DEFAULT)
`uvm_field_int(interrupt_channel_mask, UVM_DEFAULT)
`uvm_object_utils_end
constraint default_irq_delay_c {
irq_delay inside {[150:250]};
}
constraint default_irq_time_c {
irq_time inside {[5:10]};
}
constraint irq_mode_c {
if (irq_cntrl == UVMA_INTERRUPT_ONE_BY_ONE) {
$countones(interrupt_valid) == 1;
}
if (irq_cntrl == UVMA_INTERRUPT_MORE_THAN_ONE) {
$countones(interrupt_valid) > 1;
}
irq_set_delay inside {[300: 500]};
irq_clear_delay inside {0, 25, 50};
}
/**

View file

@ -127,7 +127,7 @@ function void uvma_interrupt_agent_c::get_and_set_cntxt();
void'(uvm_config_db#(uvma_interrupt_cntxt_c)::get(this, "", "cntxt", cntxt));
if (cntxt == null) begin
`uvm_info("CNTXT", "Context handle is null; creating.", UVM_DEBUG)
`uvm_info(get_type_name(), "Context handle is null; creating.", UVM_DEBUG)
cntxt = uvma_interrupt_cntxt_c::type_id::create("cntxt");
end
uvm_config_db#(uvma_interrupt_cntxt_c)::set(this, "*", "cntxt", cntxt);
@ -138,10 +138,10 @@ endfunction : get_and_set_cntxt
function void uvma_interrupt_agent_c::retrieve_vif();
if (!uvm_config_db#(virtual uvma_interrupt_if)::get(this, "", "interrupt_vif", cntxt.interrupt_vif)) begin
`uvm_fatal("VIF", $sformatf("Could not find vif handle of type %s in uvm_config_db", $typename(cntxt.interrupt_vif)))
`uvm_fatal(get_type_name(), $sformatf("Could not find vif handle of type %s in uvm_config_db", $typename(cntxt.interrupt_vif)))
end
else begin
`uvm_info("VIF", $sformatf("Found vif handle of type %s in uvm_config_db", $typename(cntxt.interrupt_vif)), UVM_DEBUG)
`uvm_info(get_type_name(), $sformatf("Found vif handle of type %s in uvm_config_db", $typename(cntxt.interrupt_vif)), UVM_DEBUG)
end
endfunction : retrieve_vif

View file

@ -24,11 +24,17 @@ class uvma_interrupt_cfg_c extends uvm_object;
rand bit enable_interrupt;
bit interrupt_plusarg_valid;
// Interrupt request latency modes
rand uvma_interrupt_drv_req_enum drv_req_mode;
rand int unsigned drv_req_fixed_latency;
rand int unsigned drv_req_random_latency_min;
rand int unsigned drv_req_random_latency_max;
// Number of Interrupt vector supported
rand int unsigned num_irq_supported;
// Interrupt memory ack
rand bit [XLEN-1:0] irq_addr;
// enbale/disable clear mechanism
rand bit enable_clear_irq;
// Number of cycle before Timeout if the agent failed to write into irq_add
rand int unsigned irq_timeout;
`uvm_object_utils_begin(uvma_interrupt_cfg_c)
`uvm_field_int ( enabled , UVM_DEFAULT)
@ -37,10 +43,10 @@ class uvma_interrupt_cfg_c extends uvm_object;
`uvm_field_int ( trn_log_enabled , UVM_DEFAULT)
`uvm_field_int ( enable_interrupt , UVM_DEFAULT)
`uvm_field_int ( interrupt_plusarg_valid , UVM_DEFAULT)
`uvm_field_enum(uvma_interrupt_drv_req_enum, drv_req_mode , UVM_DEFAULT)
`uvm_field_int ( drv_req_fixed_latency , UVM_DEFAULT)
`uvm_field_int ( drv_req_random_latency_min , UVM_DEFAULT)
`uvm_field_int ( drv_req_random_latency_max , UVM_DEFAULT)
`uvm_field_int ( num_irq_supported , UVM_DEFAULT)
`uvm_field_int ( irq_addr , UVM_DEFAULT)
`uvm_field_int ( enable_clear_irq , UVM_DEFAULT)
`uvm_field_int ( irq_timeout , UVM_DEFAULT)
`uvm_object_utils_end
@ -53,24 +59,10 @@ class uvma_interrupt_cfg_c extends uvm_object;
}
constraint default_enable_irq_cons {
soft enable_interrupt == 0;
}
constraint default_drive_req_mode_cons {
soft drv_req_mode == UVMA_INTERRUPT_DRV_REQ_MODE_FIXED_LATENCY;
}
constraint default_fixed_req_latency_cons {
soft drv_req_fixed_latency inside {[250:300]};
}
constraint valid_random_req_latency_cons {
drv_req_random_latency_min < drv_req_random_latency_max;
}
constraint default_random_latency_cons {
soft drv_req_random_latency_min inside {[50:100]};
soft drv_req_random_latency_max inside {[150:200]};
soft enable_interrupt == 0;
soft num_irq_supported == 2;
soft enable_clear_irq == 1;
soft irq_timeout == 10_000;
}
/**
@ -78,11 +70,6 @@ class uvma_interrupt_cfg_c extends uvm_object;
*/
extern function new(string name="uvma_interrupt_cfg");
/**
* Calculate a new random gnt latency
*/
extern function int unsigned calc_random_req_latency();
endclass : uvma_interrupt_cfg_c
function uvma_interrupt_cfg_c::new(string name="uvma_interrupt_cfg");
@ -96,20 +83,4 @@ function uvma_interrupt_cfg_c::new(string name="uvma_interrupt_cfg");
endfunction : new
function int unsigned uvma_interrupt_cfg_c::calc_random_req_latency();
int unsigned req_latency;
case (drv_req_mode)
UVMA_INTERRUPT_DRV_REQ_MODE_CONSTANT : req_latency = 0;
UVMA_INTERRUPT_DRV_REQ_MODE_FIXED_LATENCY : req_latency = drv_req_fixed_latency;
UVMA_INTERRUPT_DRV_REQ_MODE_RANDOM_LATENCY: begin
req_latency = $urandom_range(drv_req_random_latency_min, drv_req_random_latency_max);
end
endcase
return req_latency;
endfunction : calc_random_req_latency
`endif // __UVMA_INTERRUPT_CFG_SV__

View file

@ -20,7 +20,13 @@ class uvma_interrupt_cntxt_c extends uvm_object;
// Handle to agent interface
virtual uvma_interrupt_if interrupt_vif;
// Handle to memory storage to check clear condition
uvml_mem_c#(MAX_ADDR_WIDTH) mem;
// Integrals
uvma_interrupt_reset_state_enum reset_state = UVMA_INTERRUPT_RESET_STATE_PRE_RESET;
// Events
uvm_event sample_cfg_e;
uvm_event sample_cntxt_e;
@ -28,6 +34,8 @@ class uvma_interrupt_cntxt_c extends uvm_object;
`uvm_object_utils_begin(uvma_interrupt_cntxt_c)
`uvm_field_event(sample_cfg_e , UVM_DEFAULT)
`uvm_field_event(sample_cntxt_e, UVM_DEFAULT)
`uvm_field_enum(uvma_interrupt_reset_state_enum, reset_state, UVM_DEFAULT)
`uvm_field_object(mem, UVM_DEFAULT)
`uvm_object_utils_end
/**
@ -35,34 +43,17 @@ class uvma_interrupt_cntxt_c extends uvm_object;
*/
extern function new(string name="uvma_interrupt_cntxt");
/**
* TODO Describe uvma_interrupt_cntxt_c::reset()
*/
extern function void reset();
endclass : uvma_interrupt_cntxt_c
`pragma protect begin
function uvma_interrupt_cntxt_c::new(string name="uvma_interrupt_cntxt");
super.new(name);
mem = uvml_mem_c#(MAX_ADDR_WIDTH)::type_id::create("mem");
sample_cfg_e = new("sample_cfg_e" );
sample_cntxt_e = new("sample_cntxt_e");
endfunction : new
function void uvma_interrupt_cntxt_c::reset();
// TODO Implement uvma_interrupt_cntxt_c::reset()
endfunction : reset
`pragma protect end
`endif // __UVMA_INTERRUPT_CNTXT_SV__

View file

@ -19,7 +19,7 @@ class uvma_interrupt_drv_c extends uvm_driver#(uvma_interrupt_seq_item_c);
uvma_interrupt_cfg_c cfg;
uvma_interrupt_cntxt_c cntxt;
uvma_interrupt_seq_item_c req_item;
uvma_interrupt_seq_item_c req_item;
`uvm_component_utils_begin(uvma_interrupt_drv_c)
`uvm_field_object(cfg , UVM_DEFAULT)
@ -43,24 +43,24 @@ class uvma_interrupt_drv_c extends uvm_driver#(uvma_interrupt_seq_item_c);
extern virtual task run_phase(uvm_phase phase);
/**
* Drives the virtual interface's (cntxt.interrupt_vif) signals using req's contents.
* Called by run_phase() while agent is in pre-reset state.
*/
extern task drv_irq(uvma_interrupt_seq_item_c req);
extern task drv_irq_pre_reset();
/**
* Assert only one interrupt each time
* Called by run_phase() while agent is in reset state.
*/
extern task assert_irq_one_by_one(uvma_interrupt_seq_item_c req);
extern task drv_irq_in_reset();
/**
* Assert one or more interrupt each time
* Called by run_phase() while agent is in post-reset state.
*/
extern task assert_irq_more(uvma_interrupt_seq_item_c req);
extern task drv_irq_post_reset(uvma_interrupt_seq_item_c req);
/**
* Randomize interrupt signal
* Assert interrupt request
*/
extern task assert_irq_randomize(uvma_interrupt_seq_item_c req);
extern task assert_irq(uvma_interrupt_seq_item_c req);
endclass : uvma_interrupt_drv_c
@ -77,13 +77,13 @@ function void uvma_interrupt_drv_c::build_phase(uvm_phase phase);
void'(uvm_config_db#(uvma_interrupt_cfg_c)::get(this, "", "cfg", cfg));
if (cfg == null) begin
`uvm_fatal("CFG", "Configuration handle is null")
`uvm_fatal(get_type_name(), "Configuration handle is null")
end
uvm_config_db#(uvma_interrupt_cfg_c)::set(this, "*", "cfg", cfg);
void'(uvm_config_db#(uvma_interrupt_cntxt_c)::get(this, "", "cntxt", cntxt));
if (cntxt == null) begin
`uvm_fatal("CNTXT", "Context handle is null")
`uvm_fatal(get_type_name(), "Context handle is null")
end
uvm_config_db#(uvma_interrupt_cntxt_c)::set(this, "*", "cntxt", cntxt);
@ -99,67 +99,61 @@ task uvma_interrupt_drv_c::run_phase(uvm_phase phase);
cntxt.interrupt_vif.irq <= 'h0;
if(!cfg.enable_interrupt) begin
`uvm_warning(get_type_name(), "Driving Interrupt reqeust is disabled");
`uvm_info(get_type_name(), "Driving Interrupt request is disabled", UVM_NONE);
return;
end
forever begin
case (cntxt.reset_state)
UVMA_INTERRUPT_RESET_STATE_PRE_RESET : drv_irq_pre_reset ();
UVMA_INTERRUPT_RESET_STATE_IN_RESET : drv_irq_in_reset ();
UVMA_INTERRUPT_RESET_STATE_POST_RESET: begin
if (cfg.enable_interrupt) begin
seq_item_port.get_next_item(req_item);
drv_irq_post_reset(req_item);
seq_item_port.item_done();
end
end
seq_item_port.get_next_item(req_item);
drv_irq(req_item);
seq_item_port.item_done();
default: `uvm_fatal(get_type_name(), $sformatf("Invalid reset_state: %0d", cntxt.reset_state))
endcase
end
endtask : run_phase
task uvma_interrupt_drv_c::drv_irq(uvma_interrupt_seq_item_c req);
task uvma_interrupt_drv_c::drv_irq_pre_reset();
cntxt.interrupt_vif.irq <= 1'b0;
@(posedge cntxt.interrupt_vif.clk);
endtask : drv_irq_pre_reset
task uvma_interrupt_drv_c::drv_irq_in_reset();
cntxt.interrupt_vif.irq <= 1'b0;
@(posedge cntxt.interrupt_vif.clk);
endtask : drv_irq_in_reset
task uvma_interrupt_drv_c::drv_irq_post_reset(uvma_interrupt_seq_item_c req);
`uvm_info(get_type_name(), $sformatf("Driving:\n%s", req.sprint()), UVM_HIGH);
case (req.irq_cntrl)
UVMA_INTERRUPT_ONE_BY_ONE: begin
assert_irq_one_by_one(req);
end
UVMA_INTERRUPT_MORE_THAN_ONE: begin
assert_irq_more(req);
end
UVMA_INTERRUPT_RANDOMIZE: begin
assert_irq_randomize(req);
end
endcase
assert_irq(req);
endtask : drv_irq
endtask : drv_irq_post_reset
task uvma_interrupt_drv_c::assert_irq_one_by_one(uvma_interrupt_seq_item_c req);
task uvma_interrupt_drv_c::assert_irq(uvma_interrupt_seq_item_c req);
#req.irq_delay;
cntxt.interrupt_vif.irq <= req.interrupt_valid;
`uvm_info(get_type_name(), $sformatf("Assert interrupt channel(s) %0b", req.interrupt_valid), UVM_HIGH)
#req.irq_time;
cntxt.interrupt_vif.irq <= 'h0;
endtask : assert_irq_one_by_one
task uvma_interrupt_drv_c::assert_irq_more(uvma_interrupt_seq_item_c req);
#req.irq_delay;
cntxt.interrupt_vif.irq <= req.interrupt_valid;
#req.irq_time;
cntxt.interrupt_vif.irq <= 'h0;
endtask : assert_irq_more
task uvma_interrupt_drv_c::assert_irq_randomize(uvma_interrupt_seq_item_c req);
repeat(5) begin
#req.irq_delay;
cntxt.interrupt_vif.irq <= req.interrupt_valid;
#req.irq_time;
for (int i = 0; i < cfg.num_irq_supported; i++) begin
if (req.interrupt_channel_mask[i] == 1) begin
cntxt.interrupt_vif.irq[i] <= req.interrupt_vector[i];
end
end
cntxt.interrupt_vif.irq <= 'h0;
cfg.calc_random_req_latency();
`uvm_info(get_type_name(), $sformatf("Assert interrupt channel(s) %0b", req.interrupt_vector), UVM_HIGH)
endtask : assert_irq_randomize
endtask : assert_irq
`endif // __UVMA_INTERRUPT_DRV_SV__

View file

@ -18,9 +18,11 @@
*/
interface uvma_interrupt_if
(
input clk,
input reset_n
);
logic [uvma_interrupt_pkg::NUM_IRQ-1:0] irq;
logic [15:0] irq;
endinterface : uvma_interrupt_if

View file

@ -22,7 +22,7 @@ class uvma_interrupt_mon_c extends uvm_monitor;
`uvm_component_utils_end
// TLM
uvm_analysis_port #(uvma_interrupt_seq_item_c) ap;
uvm_analysis_port #(uvma_interrupt_seq_item_c) ap;
/**
* Default constructor.
@ -42,73 +42,119 @@ class uvma_interrupt_mon_c extends uvm_monitor;
extern virtual task run_phase(uvm_phase phase);
/**
* Monitor interrupt
* Monitors passive_mp for asynchronous reset and updates the context's reset state.
*/
extern virtual task mon_irq();
extern task observe_reset();
/**
* Monitor pre-reset phase
*/
extern virtual task mon_irq_pre_reset();
/**
* Monitor in-reset phase
*/
extern virtual task mon_irq_in_reset();
/**
* Monitor post-reset phase
*/
extern virtual task mon_irq_post_reset();
//~ /**
//~ * Monitor interrupt
//~ */
//~ extern virtual task mon_irq();
endclass : uvma_interrupt_mon_c
/**
* Default constructor.
*/
function uvma_interrupt_mon_c::new(string name = "uvma_interrupt_mon", uvm_component parent);
super.new(name, parent);
endfunction
function uvma_interrupt_mon_c::new(string name = "uvma_interrupt_mon", uvm_component parent);
super.new(name, parent);
/**
* 1. Ensures cfg & cntxt handles are not null.
* 2. Builds ap.
*/
function void uvma_interrupt_mon_c::build_phase(uvm_phase phase);
endfunction
super.build_phase(phase);
void'(uvm_config_db#(uvma_interrupt_cntxt_c)::get(this, "", "cntxt", cntxt));
if (cntxt == null) begin
`uvm_fatal("build_phase", "monitor cntxt class failed")
end
function void uvma_interrupt_mon_c::build_phase(uvm_phase phase);
void'(uvm_config_db#(uvma_interrupt_cfg_c)::get(this, "", "cfg", cfg));
if (cfg == null) begin
`uvm_fatal("CFG", "Configuration handle is null")
end
ap = new("ap", this);
super.build_phase(phase);
endfunction
void'(uvm_config_db#(uvma_interrupt_cntxt_c)::get(this, "", "cntxt", cntxt));
if (cntxt == null) begin
`uvm_fatal(get_type_name(), "monitor cntxt class failed")
end
/**
* TODO Describe uvma_interrupt_mon_c::run_phase()
*/
task uvma_interrupt_mon_c::run_phase(uvm_phase phase);
super.run_phase(phase);
void'(uvm_config_db#(uvma_interrupt_cfg_c)::get(this, "", "cfg", cfg));
if (cfg == null) begin
`uvm_fatal(get_type_name(), "Configuration handle is null")
end
ap = new("ap", this);
endfunction
task uvma_interrupt_mon_c::run_phase(uvm_phase phase);
super.run_phase(phase);
if (cfg.enabled) begin
fork
begin
mon_irq();
observe_reset();
forever begin
case (cntxt.reset_state)
UVMA_INTERRUPT_RESET_STATE_PRE_RESET: mon_irq_pre_reset();
UVMA_INTERRUPT_RESET_STATE_IN_RESET: mon_irq_in_reset();
UVMA_INTERRUPT_RESET_STATE_POST_RESET: mon_irq_post_reset();
endcase
end
join_none
join
end
endtask: run_phase
endtask: run_phase
/**
* TODO Describe uvma_interrupt_mon_c::mon_post_reset()
*/
task uvma_interrupt_mon_c::mon_irq();
uvma_interrupt_seq_item_c irq_item;
task uvma_interrupt_mon_c::mon_irq_pre_reset();
while(1) begin
@(cntxt.interrupt_vif.irq);
@(cntxt.interrupt_vif.clk);
irq_item = uvma_interrupt_seq_item_c::type_id::create("irq_item");
irq_item.interrupt_valid = cntxt.interrupt_vif.irq;
`uvm_info(get_type_name(), $sformatf("monitor interrupt : %0d", irq_item.interrupt_valid), UVM_LOW)
ap.write(irq_item);
endtask : mon_irq_pre_reset
end
task uvma_interrupt_mon_c::mon_irq_in_reset();
endtask: mon_irq
@(cntxt.interrupt_vif.clk);
endtask : mon_irq_in_reset
task uvma_interrupt_mon_c::mon_irq_post_reset();
uvma_interrupt_seq_item_c irq_item;
while(1) begin
@(cntxt.interrupt_vif.irq);
irq_item = uvma_interrupt_seq_item_c::type_id::create("irq_item");
irq_item.interrupt_vector = cntxt.interrupt_vif.irq;
`uvm_info(get_type_name(), $sformatf("monitor interrupt : %0d", irq_item.interrupt_vector), UVM_LOW)
ap.write(irq_item);
end
endtask: mon_irq_post_reset
task uvma_interrupt_mon_c::observe_reset();
forever begin
wait (cntxt.interrupt_vif.reset_n === 0);
cntxt.reset_state = UVMA_INTERRUPT_RESET_STATE_IN_RESET;
`uvm_info(get_type_name(), $sformatf("RESET_STATE_IN_RESET"), UVM_NONE)
wait (cntxt.interrupt_vif.reset_n === 1);
cntxt.reset_state = UVMA_INTERRUPT_RESET_STATE_POST_RESET;
`uvm_info(get_type_name(), $sformatf("RESET_STATE_POST_RESET"), UVM_NONE)
end
endtask : observe_reset
`endif

View file

@ -25,11 +25,15 @@
package uvma_interrupt_pkg;
import uvm_pkg ::*;
import uvml_mem_pkg::*;
import uvml_hrtbt_pkg::*;
import uvml_trn_pkg ::*;
import uvml_logs_pkg ::*;
import uvma_isacov_pkg ::*;
import uvma_rvfi_pkg ::*;
parameter NUM_IRQ = 3;
parameter XLEN = 32;
parameter int MAX_ADDR_WIDTH = `UVMA_AXI_ADDR_MAX_WIDTH ; // subjective maximum
// Constants / Structs / Enums
`include "uvma_interrupt_constants.sv"
@ -48,7 +52,7 @@ package uvma_interrupt_pkg;
`include "uvma_interrupt_drv.sv"
`include "uvma_interrupt_sqr.sv"
`include "uvma_interrupt_agent.sv"
// Sequences
`include "uvma_interrupt_base_seq.sv"
`include "uvma_interrupt_seq.sv"

View file

@ -26,9 +26,6 @@ class uvma_interrupt_sqr_c extends uvm_sequencer#(uvma_interrupt_seq_item_c);
uvma_interrupt_cfg_c cfg;
uvma_interrupt_cntxt_c cntxt;
// Analysis port to receive
uvm_tlm_analysis_fifo #(uvma_interrupt_seq_item_c) mm_req_fifo;
`uvm_component_utils_begin(uvma_interrupt_sqr_c)
`uvm_field_object(cfg , UVM_DEFAULT)
`uvm_field_object(cntxt, UVM_DEFAULT)
@ -61,16 +58,14 @@ function void uvma_interrupt_sqr_c::build_phase(uvm_phase phase);
void'(uvm_config_db#(uvma_interrupt_cfg_c)::get(this, "", "cfg", cfg));
if (cfg == null) begin
`uvm_fatal("CFG", "Configuration handle is null")
`uvm_fatal(get_type_name(), "Configuration handle is null")
end
void'(uvm_config_db#(uvma_interrupt_cntxt_c)::get(this, "", "cntxt", cntxt));
if (cntxt == null) begin
`uvm_fatal("CNTXT", "Context handle is null")
`uvm_fatal(get_type_name(), "Context handle is null")
end
mm_req_fifo = new("mm_req_fifo", this);
endfunction : build_phase

View file

@ -10,16 +10,11 @@
`ifndef __UVMA_INTERRUPT_TDEFS_SV__
`define __UVMA_INTERRUPT_TDEFS_SV__
typedef enum {
UVMA_INTERRUPT_ONE_BY_ONE,
UVMA_INTERRUPT_MORE_THAN_ONE,
UVMA_INTERRUPT_RANDOMIZE
} uvma_interrupt_cntrl_enum;
typedef enum {
UVMA_INTERRUPT_DRV_REQ_MODE_CONSTANT,
UVMA_INTERRUPT_DRV_REQ_MODE_FIXED_LATENCY,
UVMA_INTERRUPT_DRV_REQ_MODE_RANDOM_LATENCY
} uvma_interrupt_drv_req_enum;
UVMA_INTERRUPT_RESET_STATE_PRE_RESET,
UVMA_INTERRUPT_RESET_STATE_IN_RESET,
UVMA_INTERRUPT_RESET_STATE_POST_RESET
} uvma_interrupt_reset_state_enum;
`endif // __UVMA_INTERRUPT_TDEFS_SV__

View file

@ -62,6 +62,9 @@ class uvme_cva6_cfg_c extends uvma_core_cntrl_cfg_c;
// MMU support
rand bit MmuPresent;
// Software interrupt supported
rand bit sw_int_supported;
`uvm_object_utils_begin(uvme_cva6_cfg_c)
`uvm_field_int ( enabled , UVM_DEFAULT )
`uvm_field_enum(uvm_active_passive_enum, is_active , UVM_DEFAULT )
@ -75,6 +78,7 @@ class uvme_cva6_cfg_c extends uvma_core_cntrl_cfg_c;
`uvm_field_int ( nr_pmp_entries , UVM_DEFAULT )
`uvm_field_int ( ext_zihpm_supported , UVM_DEFAULT )
`uvm_field_int ( MmuPresent , UVM_DEFAULT )
`uvm_field_int ( sw_int_supported , UVM_DEFAULT )
`uvm_field_int ( sys_clk_period , UVM_DEFAULT + UVM_DEC)
`uvm_field_int ( performance_mode , UVM_DEFAULT )
@ -124,6 +128,8 @@ class uvme_cva6_cfg_c extends uvma_core_cntrl_cfg_c;
HPDCache_supported == (RTLCVA6Cfg.DCacheType == 2);
MmuPresent == RTLCVA6Cfg.MmuPresent;
// TODO : add RTL paramater related to this field fix issue#2500
sw_int_supported == 0;
}
constraint ext_const {
@ -225,6 +231,11 @@ class uvme_cva6_cfg_c extends uvma_core_cntrl_cfg_c;
extern virtual function void read_disable_csr_check_plusargs();
/**
* Get irq_addr ack
*/
extern virtual function bit [XLEN-1:0] get_irq_addr();
endclass : uvme_cva6_cfg_c
@ -280,6 +291,25 @@ function void uvme_cva6_cfg_c::sample_parameters(uvma_core_cntrl_cntxt_c cntxt);
endfunction : sample_parameters
function bit [XLEN-1:0] uvme_cva6_cfg_c::get_irq_addr();
int unsigned IRQ_ADDR;
string binary;
if (!$value$plusargs("irq_addr=%h", IRQ_ADDR)) IRQ_ADDR = '0;
if (IRQ_ADDR == '0) begin
if (!$value$plusargs("elf_file=%s", binary)) binary = "";
if (binary != "") begin
read_elf(binary);
read_symbol("int_ack", IRQ_ADDR);
end
`uvm_info(get_type_name(), $sformatf("[IRQ] INFO: int_ack_addr: %h", IRQ_ADDR), UVM_NONE)
end
return IRQ_ADDR;
endfunction : get_irq_addr
function void uvme_cva6_cfg_c::set_unsupported_csr_mask();
super.set_unsupported_csr_mask();

View file

@ -163,7 +163,7 @@ function void uvme_cva6_env_c::build_phase(uvm_phase phase);
`uvm_fatal("CFG", "Configuration handle is null")
end
else begin
`uvm_info("CFG", $sformatf("Found configuration handle:\n%s", cfg.sprint()), UVM_DEBUG)
`uvm_info("CFG", $sformatf("Found configuration handle:\n%s", cfg.sprint()), UVM_NONE)
end
cfg.rvfi_cfg.nret = RTLCVA6Cfg.NrCommitPorts;
@ -175,7 +175,10 @@ function void uvme_cva6_env_c::build_phase(uvm_phase phase);
cntxt = uvme_cva6_cntxt_c::type_id::create("cntxt");
end
cntxt.axi_cntxt.mem = cntxt.mem;
cntxt.axi_cntxt.mem = cntxt.mem;
cntxt.interrupt_cntxt.mem = cntxt.mem;
// get irq_addr ack from CVA6 UVM env
cfg.interrupt_cfg.irq_addr = cfg.get_irq_addr();
if ($test$plusargs("tandem_enabled"))
$value$plusargs("tandem_enabled=%b",cfg.tandem_enabled);
@ -399,10 +402,10 @@ function void uvme_cva6_env_c::connect_coverage_model();
isacov_agent.monitor.ap.connect(cov_model.isa_covg.mon_trn_fifo.analysis_export);
isacov_agent.monitor.ap.connect(cov_model.illegal_covg.mon_trn_fifo.analysis_export);
isacov_agent.monitor.ap.connect(cov_model.exception_covg.mon_trn_fifo.analysis_export);
rvfi_agent.rvfi_core_ap.connect(isacov_agent.monitor.rvfi_instr_imp);
end
clknrst_agent.mon_ap.connect(cov_model.reset_export);
rvfi_agent.rvfi_core_ap.connect(isacov_agent.monitor.rvfi_instr_imp);
if(cfg.axi_cfg.cov_model_enabled) begin
axi_agent.monitor.m_axi_superset_write_rsp_packets_collected.connect(cov_model.axi_covg.uvme_axi_cov_b_resp_fifo.analysis_export);

View file

@ -58,6 +58,7 @@ package uvme_cva6_pkg;
import "DPI-C" function void read_elf(input string filename);
import "DPI-C" function byte get_section(output longint address, output longint len);
import "DPI-C" context function void read_section_sv(input longint address, inout byte buffer[]);
import "DPI-C" function byte read_symbol (input string symbol_name, inout longint unsigned address);
// Default legal opcode and funct7 for RV32I instructions
bit [6:0] legal_i_opcode[$] = '{7'b0000011,

View file

@ -303,17 +303,17 @@ function void uvme_cva6_sb_c::check_mepc(uvma_isacov_instr_c instr);
`uvm_info(get_type_name(), $sformatf("Trap is compressed ? : %h ", trap_is_compressed), UVM_DEBUG)
if (trap_is_compressed) begin
if (mepc_value != trap_pc + 'h2) begin
`uvm_warning(get_type_name(), $sformatf("BE CAREFUL -> MEPC hasn't the next instruction's PC 2"))
`uvm_info(get_type_name(), $sformatf("BE CAREFUL -> MEPC hasn't the next instruction's PC 2"), UVM_DEBUG)
end
end
else begin
if (mepc_value != trap_pc + 'h4) begin
`uvm_warning(get_type_name(), $sformatf("BE CAREFUL -> MEPC hasn't the next instruction's PC 4"))
`uvm_info(get_type_name(), $sformatf("BE CAREFUL -> MEPC hasn't the next instruction's PC 4"), UVM_DEBUG)
end
end
end
else begin
`uvm_warning(get_type_name(), $sformatf("BE CAREFUL -> MEPC still has the trap pc, this could create an infinite loop "))
`uvm_info(get_type_name(), $sformatf("BE CAREFUL -> MEPC still has the trap pc, this could create an infinite loop if the trap has been raised by an exception"), UVM_DEBUG)
end
end
end

View file

@ -72,7 +72,7 @@ module cva6_tb_wrapper import uvmt_cva6_pkg::*; #(
output logic [31:0] tb_exit_o,
output rvfi_instr_t [CVA6Cfg.NrCommitPorts-1:0] rvfi_o,
output rvfi_csr_t rvfi_csr_o,
input logic [2:0] irq_i,
input logic [15:0] irq_i,
uvma_debug_if debug_if,
uvma_axi_intf axi_slave,
uvmt_axi_switch_intf axi_switch_vif,
@ -105,8 +105,8 @@ module cva6_tb_wrapper import uvmt_cva6_pkg::*; #(
.boot_addr_i ( boot_addr_i ),//Driving the boot_addr value from the core control agent
.hart_id_i ( default_inputs_vif.hart_id ),
.irq_i ( {1'b0, irq_i[0]} ),
.ipi_i ( irq_i[1] ),
.time_irq_i ( irq_i[2] ),
.ipi_i ( 1'b0 ),
.time_irq_i ( irq_i[1] ),
.debug_req_i ( debug_if.debug_req ),
.rvfi_probes_o ( rvfi_probes ),
.cvxif_req_o ( cvxif_req ),

View file

@ -65,9 +65,10 @@ module uvmt_cva6_tb;
.rst_n(clknrst_if.reset_n)
);
uvma_interrupt_if
interrupt_vif(
);
uvma_interrupt_if interrupt_vif(
.clk(clknrst_if.clk),
.reset_n(clknrst_if.reset_n)
);
uvmt_axi_switch_intf axi_switch_vif();
uvme_cva6_core_cntrl_if core_cntrl_if();

View file

@ -28,5 +28,5 @@
- test: jump_to_zero
iterations: 1
path_var: TESTS_PATH
gcc_opts: "-static -mcmodel=medany -fvisibility=hidden -nostdlib -nostartfiles ../tests/custom/common/syscalls.c ../tests/custom/common/crt.S -I../tests/custom/env -I../tests/custom/common -T ../tests/custom/common/test.ld -lgcc"
gcc_opts: "-static -mcmodel=medany -fvisibility=hidden -nostdlib -nostartfiles ../tests/custom/common/syscalls.c ../tests/custom/common/crt.S -I../tests/custom/env -I../tests/custom/common -lgcc"
asm_tests: <path_var>/custom/interrupt/jump_to_zero.S