diff --git a/dv/uvm/Makefile b/dv/uvm/Makefile index 1aaa314b..91cbf653 100644 --- a/dv/uvm/Makefile +++ b/dv/uvm/Makefile @@ -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} diff --git a/dv/uvm/env/core_ibex_dut_probe_if.sv b/dv/uvm/env/core_ibex_dut_probe_if.sv index 2119d1fe..f3503774 100644 --- a/dv/uvm/env/core_ibex_dut_probe_if.sv +++ b/dv/uvm/env/core_ibex_dut_probe_if.sv @@ -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; diff --git a/dv/uvm/riscv_dv_extension/riscv_core_setting.sv b/dv/uvm/riscv_dv_extension/riscv_core_setting.sv index 621aeeeb..8a12f88e 100644 --- a/dv/uvm/riscv_dv_extension/riscv_core_setting.sv +++ b/dv/uvm/riscv_dv_extension/riscv_core_setting.sv @@ -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) diff --git a/dv/uvm/riscv_dv_extension/testlist.yaml b/dv/uvm/riscv_dv_extension/testlist.yaml index d9a05f10..56ae3602 100644 --- a/dv/uvm/riscv_dv_extension/testlist.yaml +++ b/dv/uvm/riscv_dv_extension/testlist.yaml @@ -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 diff --git a/dv/uvm/tb/core_ibex_tb_top.sv b/dv/uvm/tb/core_ibex_tb_top.sv index f2986b64..fb8f9c27 100644 --- a/dv/uvm/tb/core_ibex_tb_top.sv +++ b/dv/uvm/tb/core_ibex_tb_top.sv @@ -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; diff --git a/dv/uvm/tests/core_ibex_test_lib.sv b/dv/uvm/tests/core_ibex_test_lib.sv index b90e1534..b466e633 100644 --- a/dv/uvm/tests/core_ibex_test_lib.sv +++ b/dv/uvm/tests/core_ibex_test_lib.sv @@ -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