use crate::common::PhysAddr;
use crate::config::BackendKind;
use crate::config::Config;
use crate::tests::support::builder::instruction::InstructionBuilder;
use crate::tests::support::harness::TestContext;
const PROGRAM_BASE: u64 = 0x8000_0000;
const HANDLER: u64 = PROGRAM_BASE + 0x100;
const DATA: u64 = PROGRAM_BASE + 0x200;
const A1: u32 = 11;
const A2: u32 = 12;
const A3: u32 = 13;
const T0: u32 = 5;
const MSTATUS: u32 = 0x300;
const MCAUSE: u32 = 0x342;
const MTVAL: u32 = 0x343;
const ILLEGAL_INSTRUCTION: u64 = 2;
const FSW_FT0_A1: u32 = 0x0005_A027;
fn program() -> Vec<u32> {
let i = InstructionBuilder::new;
vec![
i().lui(T0, 0x6).build(),
i().csrrc(0, MSTATUS, T0).build(),
i().auipc(A1, 0).build(),
i().addi(A1, A1, (DATA - PROGRAM_BASE - 8) as i32).build(),
i().addi(A3, 0, 7).build(),
FSW_FT0_A1,
i().jal(0, 0).build(),
]
}
fn handler() -> Vec<u32> {
let i = InstructionBuilder::new;
vec![i().csrrs(A2, MCAUSE, 0).build(), i().csrrs(A3, MTVAL, 0).build(), i().jal(0, 0).build()]
}
fn store_program(ctx: &mut TestContext, base: u64, program: &[u32]) {
for (i, word) in program.iter().enumerate() {
ctx.sim.probe_mem_store(PhysAddr::new(base + (i as u64) * 4), u64::from(*word), 4);
}
}
fn run(backend: BackendKind) -> (u64, u64, u64) {
let mut config = Config::default();
config.pipeline.backend = backend;
config.pipeline.width = 4;
config.system.console = crate::config::Console::Quiet;
let mut ctx = TestContext::new_with_config(&config).load_program(PROGRAM_BASE, &program());
store_program(&mut ctx, HANDLER, &handler());
ctx.sim.probe_mem_store(PhysAddr::new(DATA), 0x1234_5678, 4);
ctx.sim.state.harts[0].csrs.mtvec = HANDLER;
ctx.sim.state.direct_mode = false;
ctx.sim.sync_arch_regs();
ctx.run(500);
let memory = ctx.sim.probe_mem_load(PhysAddr::new(DATA), 4);
(ctx.get_reg(A2 as usize), ctx.get_reg(A3 as usize), memory)
}
fn check(backend: BackendKind) {
let (mcause, mtval, memory) = run(backend);
assert_eq!(mcause, ILLEGAL_INSTRUCTION, "{backend:?}: the FS=0 fault is the one taken");
assert_eq!(mtval, FSW_FT0_A1 as u64, "{backend:?}: tval holds the illegal instruction");
assert_eq!(memory, 0x1234_5678, "{backend:?}: the store never reached memory");
}
#[test]
fn an_fp_store_with_fs_off_takes_the_illegal_instruction_fault_inorder() {
check(BackendKind::InOrder);
}
#[test]
fn an_fp_store_with_fs_off_takes_the_illegal_instruction_fault_o3() {
check(BackendKind::OutOfOrder);
}