mirror of
https://github.com/lowRISC/ibex.git
synced 2025-04-22 04:47:25 -04:00
Fix memory error test logic (#344)
This commit is contained in:
parent
83d2185c9b
commit
717bf1ae02
5 changed files with 109 additions and 56 deletions
1
dv/uvm/env/core_ibex_env_pkg.sv
vendored
1
dv/uvm/env/core_ibex_env_pkg.sv
vendored
|
@ -7,6 +7,7 @@
|
|||
// ---------------------------------------------
|
||||
|
||||
`include "core_ibex_dut_probe_if.sv"
|
||||
`include "core_ibex_rvfi_if.sv"
|
||||
|
||||
package core_ibex_env_pkg;
|
||||
|
||||
|
|
27
dv/uvm/env/core_ibex_rvfi_if.sv
vendored
Normal file
27
dv/uvm/env/core_ibex_rvfi_if.sv
vendored
Normal file
|
@ -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
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue