diff --git a/dv/uvm/env/core_ibex_env_pkg.sv b/dv/uvm/env/core_ibex_env_pkg.sv index c8b69db1..63ee6310 100644 --- a/dv/uvm/env/core_ibex_env_pkg.sv +++ b/dv/uvm/env/core_ibex_env_pkg.sv @@ -7,6 +7,7 @@ // --------------------------------------------- `include "core_ibex_dut_probe_if.sv" +`include "core_ibex_rvfi_if.sv" package core_ibex_env_pkg; diff --git a/dv/uvm/env/core_ibex_rvfi_if.sv b/dv/uvm/env/core_ibex_rvfi_if.sv new file mode 100644 index 00000000..1515adfd --- /dev/null +++ b/dv/uvm/env/core_ibex_rvfi_if.sv @@ -0,0 +1,27 @@ +// Copyright lowRISC contributors. +// Licensed under the Apache License, Version 2.0, see LICENSE for details. +// SPDX-License-Identifier: Apache-2.0 + +// Interface to probe Ibex RVFI interface +interface core_ibex_rvfi_if(input logic clk); + logic valid; + logic [63:0] order; + logic [31:0] insn; + logic trap; + logic halt; + logic intr; + logic [1:0] mode; + logic [4:0] rs1_addr; + logic [4:0] rs2_addr; + logic [31:0] rs1_rdata; + logic [31:0] rs2_rdata; + logic [4:0] rd_addr; + logic [31:0] rd_wdata; + logic [31:0] pc_rdata; + logic [31:0] pc_wdata; + logic [31:0] mem_addr; + logic [3:0] mem_rmask; + logic [3:0] mem_wmask; + logic [31:0] mem_rdata; + logic [31:0] mem_wdata; +endinterface diff --git a/dv/uvm/tb/core_ibex_tb_top.sv b/dv/uvm/tb/core_ibex_tb_top.sv index 17c99dde..9d8b0648 100644 --- a/dv/uvm/tb/core_ibex_tb_top.sv +++ b/dv/uvm/tb/core_ibex_tb_top.sv @@ -20,6 +20,9 @@ module core_ibex_tb_top; // DUT probe interface core_ibex_dut_probe_if dut_if(.clk(clk)); + // RVFI interface + core_ibex_rvfi_if rvfi_if(.clk(clk)); + // TODO(taliu) Resolve the tied-off ports ibex_core_tracing #(.DmHaltAddr(`BOOT_ADDR + 'h0), .DmExceptionAddr(`BOOT_ADDR + 'h4)) dut ( @@ -46,40 +49,57 @@ module core_ibex_tb_top; ); // Data load/store vif connection - assign data_mem_vif.clock = clk; - assign data_mem_vif.reset = ~rst_n; - assign data_mem_vif.request = dut.data_req_o; - assign data_mem_vif.we = dut.data_we_o; - assign data_mem_vif.be = dut.data_be_o; - assign data_mem_vif.addr = dut.data_addr_o; - assign data_mem_vif.wdata = dut.data_wdata_o; + assign data_mem_vif.clock = clk; + assign data_mem_vif.reset = ~rst_n; + assign data_mem_vif.request = dut.data_req_o; + assign data_mem_vif.we = dut.data_we_o; + assign data_mem_vif.be = dut.data_be_o; + assign data_mem_vif.addr = dut.data_addr_o; + assign data_mem_vif.wdata = dut.data_wdata_o; // Instruction fetch vif connnection - assign instr_mem_vif.clock = clk; - assign instr_mem_vif.reset = ~rst_n; - assign instr_mem_vif.request = dut.instr_req_o; - assign instr_mem_vif.we = 0; - assign instr_mem_vif.be = 0; - assign instr_mem_vif.wdata = 0; - assign instr_mem_vif.addr = dut.instr_addr_o; - - initial begin - // IRQ interface - force irq_vif.clock = clk; - force irq_vif.reset = ~rst_n; - end - - assign dut_if.ecall = dut.u_ibex_core.id_stage_i.ecall_insn_dec; - assign dut_if.wfi = dut.u_ibex_core.id_stage_i.wfi_insn_dec; - assign dut_if.ebreak = dut.u_ibex_core.id_stage_i.ebrk_insn; - assign dut_if.illegal_instr = dut.u_ibex_core.id_stage_i.illegal_insn_dec; - assign dut_if.dret = dut.u_ibex_core.id_stage_i.dret_insn_dec; - 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 instr_mem_vif.clock = clk; + assign instr_mem_vif.reset = ~rst_n; + assign instr_mem_vif.request = dut.instr_req_o; + assign instr_mem_vif.we = 0; + assign instr_mem_vif.be = 0; + assign instr_mem_vif.wdata = 0; + assign instr_mem_vif.addr = dut.instr_addr_o; + // RVFI interface connections + assign rvfi_if.valid = dut.rvfi_valid; + assign rvfi_if.order = dut.rvfi_order; + assign rvfi_if.insn = dut.rvfi_insn; + assign rvfi_if.trap = dut.rvfi_trap; + assign rvfi_if.intr = dut.rvfi_intr; + assign rvfi_if.mode = dut.rvfi_mode; + assign rvfi_if.rs1_addr = dut.rvfi_rs1_addr; + assign rvfi_if.rs2_addr = dut.rvfi_rs2_addr; + assign rvfi_if.rs1_rdata = dut.rvfi_rs1_rdata; + assign rvfi_if.rs2_rdata = dut.rvfi_rs2_rdata; + assign rvfi_if.rd_addr = dut.rvfi_rd_addr; + assign rvfi_if.rd_wdata = dut.rvfi_rd_wdata; + assign rvfi_if.pc_rdata = dut.rvfi_pc_rdata; + assign rvfi_if_pc_wdata = dut.rvfi_pc_wdata; + assign rvfi_if.mem_addr = dut.rvfi_mem_addr; + assign rvfi_if.mem_rmask = dut.rvfi_mem_rmask; + assign rvfi_if.mem_rdata = dut.rvfi_mem_rdata; + assign rvfi_if.mem_wdata = dut.rvfi_mem_wdata; + // Irq interface connections + assign irq_vif.clock = clk; + assign irq_vif.reset = ~rst_n; + // Dut_if interface connections + assign dut_if.ecall = dut.u_ibex_core.id_stage_i.ecall_insn_dec; + assign dut_if.wfi = dut.u_ibex_core.id_stage_i.wfi_insn_dec; + assign dut_if.ebreak = dut.u_ibex_core.id_stage_i.ebrk_insn; + assign dut_if.illegal_instr = dut.u_ibex_core.id_stage_i.illegal_insn_dec; + assign dut_if.dret = dut.u_ibex_core.id_stage_i.dret_insn_dec; + 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; initial begin uvm_config_db#(virtual clk_if)::set(null, "*", "clk_if", ibex_clk_if); uvm_config_db#(virtual core_ibex_dut_probe_if)::set(null, "*", "dut_if", dut_if); + uvm_config_db#(virtual core_ibex_rvfi_if)::set(null, "*", "rvfi_if", rvfi_if); uvm_config_db#(virtual ibex_mem_intf)::set(null, "*data_if_slave*", "vif", data_mem_vif); uvm_config_db#(virtual ibex_mem_intf)::set(null, "*instr_if_slave*", "vif", instr_mem_vif); uvm_config_db#(virtual irq_if)::set(null, "*", "vif", irq_vif); diff --git a/dv/uvm/tests/core_ibex_base_test.sv b/dv/uvm/tests/core_ibex_base_test.sv index 12dab868..d313eb17 100644 --- a/dv/uvm/tests/core_ibex_base_test.sv +++ b/dv/uvm/tests/core_ibex_base_test.sv @@ -172,9 +172,7 @@ class core_ibex_base_test extends uvm_test; virtual task check_next_core_status(core_status_t core_status, string error_msg = ""); wait_for_mem_txn(cfg.signature_addr, CORE_STATUS); signature_data = signature_data_q.pop_front(); - if (signature_data != core_status) begin - `uvm_error(`gfn, error_msg) - end + `DV_CHECK_EQ_FATAL(signature_data, core_status, error_msg); endtask // Waits for a write to the address of the specified CSR and retrieves the csr data diff --git a/dv/uvm/tests/core_ibex_test_lib.sv b/dv/uvm/tests/core_ibex_test_lib.sv index c862792c..239b7381 100644 --- a/dv/uvm/tests/core_ibex_test_lib.sv +++ b/dv/uvm/tests/core_ibex_test_lib.sv @@ -388,52 +388,59 @@ class core_ibex_mem_error_test extends core_ibex_directed_test; int err_delay; // check memory error inputs and verify that core jumps to correct exception handler + // TODO(udinator) - add checks for the RVFI interface virtual task check_stimulus(); forever begin while (!vseq.data_intf_seq.get_error_synch()) begin clk_vif.wait_clks(1); end vseq.data_intf_seq.inject_error(); + `uvm_info(`gfn, "Injected dmem error", UVM_LOW) // Dmem interface error could be either a load or store operation - fork - begin - fork - check_mem_fault(LOAD_FAULT_EXCEPTION, EXC_CAUSE_LOAD_ACCESS_FAULT); - check_mem_fault(STORE_FAULT_EXCEPTION, EXC_CAUSE_STORE_ACCESS_FAULT); - join_any - disable fork; - end - join + check_mem_fault(1'b1); // Random delay before injecting instruction fetch fault - `DV_CHECK_STD_RANDOMIZE_WITH_FATAL(err_delay, err_delay inside { [5:100] };) + `DV_CHECK_STD_RANDOMIZE_WITH_FATAL(err_delay, err_delay inside { [25:100] };) clk_vif.wait_clks(err_delay); while (!vseq.instr_intf_seq.get_error_synch()) begin clk_vif.wait_clks(1); end - `uvm_info(`gfn, $sformatf("vseq.instr_intf_seq.error_synch: 0x%0x", vseq.instr_intf_seq.get_error_synch()), UVM_LOW) + `uvm_info(`gfn, "Injecting imem fault", UVM_LOW) vseq.instr_intf_seq.inject_error(); - `uvm_info(`gfn, $sformatf("vseq.instr_intf_seq.enable_error: 0x%0x", vseq.instr_intf_seq.enable_error), UVM_LOW) - check_mem_fault(INSTR_FAULT_EXCEPTION, EXC_CAUSE_INSTR_ACCESS_FAULT); + check_mem_fault(1'b0); // Random delay before injecting this series of errors again `DV_CHECK_STD_RANDOMIZE_WITH_FATAL(err_delay, err_delay inside { [250:750] };) clk_vif.wait_clks(err_delay); end endtask - virtual task check_mem_fault(core_status_t fault_type, ibex_pkg::exc_cause_e exc_type); + virtual task check_mem_fault(bit imem_or_dmem); bit[ibex_mem_intf_agent_pkg::DATA_WIDTH-1:0] mcause; - forever begin - wait_for_core_status(HANDLING_EXCEPTION); - wait_for_core_status(fault_type); - wait_for_csr_write(CSR_MCAUSE); - mcause = signature_data; - `DV_CHECK_EQ_FATAL(mcause[ibex_mem_intf_agent_pkg::DATA_WIDTH-1], 1'b0, - "mcause interrupt is not set to 1'b0") - `DV_CHECK_EQ_FATAL(mcause[ibex_mem_intf_agent_pkg::DATA_WIDTH-2:0], - exc_type, - "mcause.exception_code is encoding the wrong exception type") - wait(dut_vif.mret === 1'b1); + core_status_t mem_status; + ibex_pkg::exc_cause_e exc_type; + check_next_core_status(HANDLING_EXCEPTION, "Core did not jump to exception handler"); + if (imem_or_dmem) begin + // 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(); + if (mem_status == LOAD_FAULT_EXCEPTION) begin + exc_type = EXC_CAUSE_LOAD_ACCESS_FAULT; + end else if (mem_status == STORE_FAULT_EXCEPTION) begin + exc_type = EXC_CAUSE_STORE_ACCESS_FAULT; + end + `uvm_info(`gfn, $sformatf("0x%0x", exc_type), UVM_LOW) + end else begin + check_next_core_status(INSTR_FAULT_EXCEPTION, "Core did not register correct memory fault type"); + exc_type = EXC_CAUSE_INSTR_ACCESS_FAULT; end + wait_for_csr_write(CSR_MCAUSE); + mcause = signature_data; + `DV_CHECK_EQ_FATAL(mcause[ibex_mem_intf_agent_pkg::DATA_WIDTH-1], 1'b0, + "mcause interrupt is not set to 1'b0") + `DV_CHECK_EQ_FATAL(mcause[ibex_mem_intf_agent_pkg::DATA_WIDTH-2:0], + exc_type, + "mcause.exception_code is encoding the wrong exception type") + wait(dut_vif.mret === 1'b1); + `uvm_info(`gfn, "exiting mem fault checker", UVM_LOW) endtask endclass