mirror of
https://github.com/openhwgroup/cve2.git
synced 2025-04-22 04:57:25 -04:00
[DV] Enable user-mode in DV environment, add basic tests (#471)
Signed-off-by: Udi <udij@google.com>
This commit is contained in:
parent
103b7357f0
commit
c05634cfdf
6 changed files with 78 additions and 24 deletions
|
@ -46,6 +46,10 @@ export PRJ_DIR:= $(realpath ${DV_DIR}/../../..)
|
|||
|
||||
all: clean gen gcc_compile iss_sim compile rtl_sim post_compare
|
||||
|
||||
instr: gen gcc_compile iss_sim
|
||||
|
||||
sim: compile rtl_sim post_compare
|
||||
|
||||
clean:
|
||||
rm -rf ${OUT}
|
||||
|
||||
|
|
21
dv/uvm/env/core_ibex_dut_probe_if.sv
vendored
21
dv/uvm/env/core_ibex_dut_probe_if.sv
vendored
|
@ -4,16 +4,17 @@
|
|||
|
||||
// Interface to probe DUT internal signal
|
||||
interface core_ibex_dut_probe_if(input logic clk);
|
||||
logic reset;
|
||||
logic illegal_instr;
|
||||
logic ecall;
|
||||
logic wfi;
|
||||
logic ebreak;
|
||||
logic dret;
|
||||
logic mret;
|
||||
logic fetch_enable;
|
||||
logic core_sleep;
|
||||
logic debug_req;
|
||||
logic reset;
|
||||
logic illegal_instr;
|
||||
logic ecall;
|
||||
logic wfi;
|
||||
logic ebreak;
|
||||
logic dret;
|
||||
logic mret;
|
||||
logic fetch_enable;
|
||||
logic core_sleep;
|
||||
logic debug_req;
|
||||
ibex_pkg::priv_lvl_e priv_mode;
|
||||
|
||||
initial begin
|
||||
debug_req = 1'b0;
|
||||
|
|
|
@ -24,7 +24,7 @@ parameter int XLEN = 32;
|
|||
parameter satp_mode_t SATP_MODE = BARE;
|
||||
|
||||
// Supported Privileged mode
|
||||
privileged_mode_t supported_privileged_mode[] = {MACHINE_MODE};
|
||||
privileged_mode_t supported_privileged_mode[] = {MACHINE_MODE, USER_MODE};
|
||||
|
||||
// Unsupported instructions
|
||||
// Avoid generating these instructions in regular regression
|
||||
|
@ -83,6 +83,7 @@ parameter privileged_reg_t implemented_csr[] = {
|
|||
MCAUSE, // Machine trap cause
|
||||
MTVAL, // Machine bad address or instruction
|
||||
MIE, // Machine interrupt enable
|
||||
MIP, // Machine interrupt pending
|
||||
MCYCLE, // Machine cycle counter (lower 32 bits)
|
||||
MCYCLEH, // Machine cycle counter (upper 32 bits)
|
||||
MINSTRET, // Machine instructions retired counter (lower 32 bits)
|
||||
|
|
|
@ -210,7 +210,7 @@
|
|||
|
||||
- test: riscv_dret_test
|
||||
description: >
|
||||
Dret instructions will be inserted into M-mode code, ibex should treat these
|
||||
Dret instructions will be inserted into generated code, ibex should treat these
|
||||
like illegal instructions.
|
||||
iterations: 5
|
||||
gen_test: riscv_rand_instr_test
|
||||
|
@ -246,11 +246,11 @@
|
|||
compare_opts:
|
||||
compare_final_value_only: 1
|
||||
|
||||
- test: riscv_debug_ebreakm_test
|
||||
- test: riscv_debug_ebreakmu_test
|
||||
description: >
|
||||
dcsr.ebreakm will be set at the beginning of the test upon the first entry into the debug rom.
|
||||
From then on, every ebreak instruction should cause debug mode to be entered.
|
||||
iterations: 10
|
||||
iterations: 15
|
||||
gen_test: riscv_rand_instr_test
|
||||
gen_opts: >
|
||||
+require_signature_addr=1
|
||||
|
@ -263,7 +263,7 @@
|
|||
+instr_cnt=6000
|
||||
+randomize_csr=1
|
||||
+num_of_sub_program=0
|
||||
rtl_test: core_ibex_debug_ebreakm_test
|
||||
rtl_test: core_ibex_debug_ebreakmu_test
|
||||
sim_opts: >
|
||||
+require_signature_addr=1
|
||||
+enable_debug_single_seq=1
|
||||
|
@ -279,6 +279,7 @@
|
|||
+require_signature_addr=1
|
||||
+gen_debug_section=1
|
||||
+randomize_csr=1
|
||||
+boot_mode=m
|
||||
rtl_test: core_ibex_debug_csr_test
|
||||
sim_opts: >
|
||||
+require_signature_addr=1
|
||||
|
@ -330,6 +331,7 @@
|
|||
+require_signature_addr=1
|
||||
+enable_interrupt=1
|
||||
+randomize_csr=1
|
||||
+boot_mode=m
|
||||
rtl_test: core_ibex_irq_csr_test
|
||||
sim_opts: >
|
||||
+require_signature_addr=1
|
||||
|
@ -437,3 +439,14 @@
|
|||
gcc_opts: >
|
||||
-march=rv32im
|
||||
rtl_test: core_ibex_base_test
|
||||
|
||||
- test: riscv_user_mode_rand_test
|
||||
description: >
|
||||
User mode random instruction tes
|
||||
iterations: 10
|
||||
gen_test: riscv_instr_base_test
|
||||
gen_opts: >
|
||||
+instr_cnt=10000
|
||||
+num_of_sub_program=5
|
||||
+boot_mode=u
|
||||
rtl_test: core_ibex_base_test
|
||||
|
|
|
@ -97,6 +97,7 @@ module core_ibex_tb_top;
|
|||
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;
|
||||
assign dut_if.reset = ~rst_n;
|
||||
assign dut_if.priv_mode = dut.u_ibex_core.priv_mode_id;
|
||||
// CSR interface connections
|
||||
assign csr_if.csr_access = dut.u_ibex_core.csr_access;
|
||||
assign csr_if.csr_addr = dut.u_ibex_core.csr_addr;
|
||||
|
|
|
@ -154,6 +154,7 @@ class core_ibex_debug_intr_basic_test extends core_ibex_base_test;
|
|||
|
||||
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;
|
||||
priv_lvl_e operating_mode;
|
||||
bit [$clog2(irq_agent_pkg::DATA_WIDTH)-1:0] irq_id;
|
||||
|
||||
virtual task send_stimulus();
|
||||
|
@ -190,14 +191,13 @@ class core_ibex_debug_intr_basic_test extends core_ibex_base_test;
|
|||
virtual task wait_for_core_setup();
|
||||
wait_for_csr_write(CSR_MSTATUS, 1000);
|
||||
core_init_mstatus = signature_data;
|
||||
// capture the initial privilege mode ibex will boot into
|
||||
operating_mode = core_init_mstatus[12:11];
|
||||
wait_for_csr_write(CSR_MIE, 500);
|
||||
core_init_mie = signature_data;
|
||||
check_next_core_status(INITIALIZED, "Core initialization handshake failure", 500);
|
||||
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;
|
||||
|
@ -225,10 +225,11 @@ class core_ibex_debug_intr_basic_test extends core_ibex_base_test;
|
|||
return;
|
||||
end
|
||||
check_next_core_status(HANDLING_IRQ, "Core did not jump to vectored interrupt handler", 750);
|
||||
check_priv_mode(PRIV_LVL_M);
|
||||
// check mstatus
|
||||
wait_for_csr_write(CSR_MSTATUS, 500);
|
||||
mstatus = signature_data;
|
||||
`DV_CHECK_EQ_FATAL(mstatus[12:11], PRIV_LVL_M, "Incorrect privilege mode")
|
||||
`DV_CHECK_EQ_FATAL(mstatus[12:11], operating_mode, "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
|
||||
|
@ -267,6 +268,9 @@ class core_ibex_debug_intr_basic_test extends core_ibex_base_test;
|
|||
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);
|
||||
clk_vif.wait_clks(5);
|
||||
// after mret, ibex should switch back to original privilege mode
|
||||
check_priv_mode(operating_mode);
|
||||
endtask
|
||||
|
||||
function int get_max_irq_id(bit [irq_agent_pkg::DATA_WIDTH-1:0] irq);
|
||||
|
@ -290,6 +294,7 @@ class core_ibex_debug_intr_basic_test extends core_ibex_base_test;
|
|||
begin
|
||||
forever begin
|
||||
wait_for_core_status(IN_DEBUG_MODE);
|
||||
check_priv_mode(PRIV_LVL_M);
|
||||
wait_dret(20000);
|
||||
end
|
||||
end
|
||||
|
@ -302,6 +307,8 @@ class core_ibex_debug_intr_basic_test extends core_ibex_base_test;
|
|||
fork
|
||||
begin
|
||||
wait(dut_vif.dret === 1'b1);
|
||||
clk_vif.wait_clks(5);
|
||||
check_priv_mode(operating_mode);
|
||||
end
|
||||
begin : dret_timeout
|
||||
clk_vif.wait_clks(timeout);
|
||||
|
@ -313,6 +320,11 @@ class core_ibex_debug_intr_basic_test extends core_ibex_base_test;
|
|||
run.drop_objection(this);
|
||||
endtask
|
||||
|
||||
virtual function void check_priv_mode(priv_lvl_e mode);
|
||||
`DV_CHECK_EQ_FATAL(dut_vif.priv_mode, mode,
|
||||
"Incorrect privilege mode")
|
||||
endfunction
|
||||
|
||||
endclass
|
||||
|
||||
// Base class for directed debug and irq test scenarios
|
||||
|
@ -397,6 +409,11 @@ class core_ibex_directed_test extends core_ibex_debug_intr_basic_test;
|
|||
`DV_CHECK_EQ_FATAL(cause, signature_data[8:6], "dcsr.cause has been incorrectly updated")
|
||||
endfunction
|
||||
|
||||
virtual function void check_dcsr_prv(priv_lvl_e mode);
|
||||
`DV_CHECK_EQ_FATAL(mode, signature_data[1:0],
|
||||
"Incorrect dcsr.prv value!")
|
||||
endfunction
|
||||
|
||||
endclass
|
||||
|
||||
// Interrupt WFI test class
|
||||
|
@ -453,11 +470,13 @@ class core_ibex_debug_wfi_test extends core_ibex_directed_test;
|
|||
// - next handshake should be a notification that the core is now in debug mode
|
||||
check_next_core_status(IN_DEBUG_MODE, "Core did not jump into debug mode from WFI state",
|
||||
1000);
|
||||
check_priv_mode(PRIV_LVL_M);
|
||||
// We don't want to trigger debug stimulus for any WFI instructions encountered inside the
|
||||
// debug rom - those should act as NOP instructions - so we wait until hitting the end of the
|
||||
// debug rom.
|
||||
// We also want to check that dcsr.cause has been set correctly
|
||||
wait_for_csr_write(CSR_DCSR, 500);
|
||||
check_dcsr_prv(operating_mode);
|
||||
check_dcsr_cause(DBG_CAUSE_HALTREQ);
|
||||
wait_dret(5000);
|
||||
end
|
||||
|
@ -479,7 +498,9 @@ class core_ibex_debug_csr_test extends core_ibex_directed_test;
|
|||
vseq.start_debug_single_seq();
|
||||
check_next_core_status(IN_DEBUG_MODE, "Core did not jump into debug mode from WFI state",
|
||||
1000);
|
||||
check_priv_mode(PRIV_LVL_M);
|
||||
wait_for_csr_write(CSR_DCSR, 500);
|
||||
check_dcsr_prv(operating_mode);
|
||||
check_dcsr_cause(DBG_CAUSE_HALTREQ);
|
||||
wait_dret(5000);
|
||||
// wait for a dummy write to mie in the init code
|
||||
|
@ -488,7 +509,9 @@ class core_ibex_debug_csr_test extends core_ibex_directed_test;
|
|||
vseq.start_debug_single_seq();
|
||||
check_next_core_status(IN_DEBUG_MODE, "Core did not jump into debug mode from WFI state",
|
||||
1000);
|
||||
check_priv_mode(PRIV_LVL_M);
|
||||
wait_for_csr_write(CSR_DCSR, 500);
|
||||
check_dcsr_prv(operating_mode);
|
||||
check_dcsr_cause(DBG_CAUSE_HALTREQ);
|
||||
wait_dret(5000);
|
||||
endtask
|
||||
|
@ -531,7 +554,9 @@ class core_ibex_debug_ebreak_test extends core_ibex_directed_test;
|
|||
vseq.start_debug_single_seq();
|
||||
check_next_core_status(IN_DEBUG_MODE, "Core did not properly jump into debug mode", 1000);
|
||||
// capture the first write of dcsr
|
||||
check_priv_mode(PRIV_LVL_M);
|
||||
wait_for_csr_write(CSR_DCSR, 500);
|
||||
check_dcsr_prv(operating_mode);
|
||||
dcsr = signature_data;
|
||||
// We also want to check that dcsr.cause has been set correctly
|
||||
check_dcsr_cause(DBG_CAUSE_HALTREQ);
|
||||
|
@ -554,9 +579,9 @@ class core_ibex_debug_ebreak_test extends core_ibex_directed_test;
|
|||
endclass
|
||||
|
||||
// Debug ebreak test with dcsr.ebreak(m/s/u) set
|
||||
class core_ibex_debug_ebreakm_test extends core_ibex_directed_test;
|
||||
class core_ibex_debug_ebreakmu_test extends core_ibex_directed_test;
|
||||
|
||||
`uvm_component_utils(core_ibex_debug_ebreakm_test)
|
||||
`uvm_component_utils(core_ibex_debug_ebreakmu_test)
|
||||
`uvm_component_new
|
||||
|
||||
virtual task check_stimulus();
|
||||
|
@ -564,9 +589,11 @@ class core_ibex_debug_ebreakm_test extends core_ibex_directed_test;
|
|||
vseq.start_debug_single_seq();
|
||||
check_next_core_status(IN_DEBUG_MODE,
|
||||
"Core did not enter debug mode after debug_req stimulus", 1000);
|
||||
check_priv_mode(PRIV_LVL_M);
|
||||
// Read dcsr and verify the appropriate ebreak(m/s/u) bit has been set based on the prv field,
|
||||
// as well as the cause field
|
||||
wait_for_csr_write(CSR_DCSR, 500);
|
||||
check_dcsr_prv(operating_mode);
|
||||
check_dcsr_ebreak();
|
||||
check_dcsr_cause(DBG_CAUSE_HALTREQ);
|
||||
wait_dret(5000);
|
||||
|
@ -574,8 +601,10 @@ class core_ibex_debug_ebreakm_test extends core_ibex_directed_test;
|
|||
wait (dut_vif.ebreak === 1'b1);
|
||||
check_next_core_status(IN_DEBUG_MODE,
|
||||
"Core did not enter debug mode after execution of ebreak", 1000);
|
||||
check_priv_mode(PRIV_LVL_M);
|
||||
// Read dcsr and verify the appropriate ebreak(m/s/u) bit has been set based on the prv field
|
||||
wait_for_csr_write(CSR_DCSR, 500);
|
||||
check_dcsr_prv(operating_mode);
|
||||
check_dcsr_ebreak();
|
||||
check_dcsr_cause(DBG_CAUSE_EBREAK);
|
||||
wait_dret(5000);
|
||||
|
@ -598,20 +627,22 @@ class core_ibex_debug_single_step_test extends core_ibex_directed_test;
|
|||
vseq.start_debug_single_seq();
|
||||
check_next_core_status(IN_DEBUG_MODE,
|
||||
"Core did not enter debug mode after debug stimulus", 1000);
|
||||
check_priv_mode(PRIV_LVL_M);
|
||||
wait_for_csr_write(CSR_DPC, 500);
|
||||
ret_pc = signature_data;
|
||||
wait_for_csr_write(CSR_DSCRATCH0, 500);
|
||||
next_counter = signature_data;
|
||||
wait_for_csr_write(CSR_DCSR, 500);
|
||||
wait_for_csr_write(CSR_DCSR, 1000);
|
||||
check_dcsr_prv(operating_mode);
|
||||
check_dcsr_cause(DBG_CAUSE_HALTREQ);
|
||||
`DV_CHECK_EQ_FATAL(signature_data[1], 1'b1, "dcsr.step is not set")
|
||||
`DV_CHECK_EQ_FATAL(signature_data[2], 1'b1, "dcsr.step is not set")
|
||||
wait_dret(5000);
|
||||
wait(dut_vif.dret === 1'b1);
|
||||
// now we loop on the counter until we are done single stepping
|
||||
while (counter >= 0) begin
|
||||
counter = next_counter;
|
||||
check_next_core_status(IN_DEBUG_MODE,
|
||||
"Core did not enter debug mode after debug stimulus", 1000);
|
||||
check_priv_mode(PRIV_LVL_M);
|
||||
wait_for_csr_write(CSR_DPC, 500);
|
||||
if (signature_data - ret_pc !== 'h2 &&
|
||||
signature_data - ret_pc !== 'h4) begin
|
||||
|
@ -623,6 +654,7 @@ class core_ibex_debug_single_step_test extends core_ibex_directed_test;
|
|||
wait_for_csr_write(CSR_DSCRATCH0, 500);
|
||||
next_counter = signature_data;
|
||||
wait_for_csr_write(CSR_DCSR, 500);
|
||||
check_dcsr_prv(operating_mode);
|
||||
check_dcsr_cause(DBG_CAUSE_STEP);
|
||||
if (counter === 0) begin
|
||||
`DV_CHECK_EQ_FATAL(signature_data[2], 1'b0, "dcsr.step is set")
|
||||
|
@ -683,6 +715,7 @@ class core_ibex_mem_error_test extends core_ibex_directed_test;
|
|||
// not guaranteed to be reflected in RTL state until the next memory instruction is executed,
|
||||
// and the frequency of which is not controllable by the testbench
|
||||
check_next_core_status(HANDLING_EXCEPTION, "Core did not jump to exception handler");
|
||||
check_priv_mode(PRIV_LVL_M);
|
||||
// Next write of CORE_STATUS will be the load/store fault type
|
||||
wait_for_mem_txn(cfg.signature_addr, CORE_STATUS);
|
||||
mem_status = signature_data_q.pop_front();
|
||||
|
@ -708,6 +741,7 @@ class core_ibex_mem_error_test extends core_ibex_directed_test;
|
|||
fork : imem_fork
|
||||
begin
|
||||
check_next_core_status(HANDLING_EXCEPTION, "Core did not jump to exception handler");
|
||||
check_priv_mode(PRIV_LVL_M);
|
||||
latched_imem_err = 1'b1;
|
||||
`uvm_info(`gfn, $sformatf("latched_imem_err: 0x%0x", latched_imem_err), UVM_LOW)
|
||||
end
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue