[DV] Enable user-mode in DV environment, add basic tests (#471)

Signed-off-by: Udi <udij@google.com>
This commit is contained in:
udinator 2019-11-14 16:11:32 -08:00 committed by GitHub
parent 103b7357f0
commit c05634cfdf
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
6 changed files with 78 additions and 24 deletions

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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