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 DATA: u64 = PROGRAM_BASE + 0x400;
const A0: u32 = 10;
const A1: u32 = 11;
const A2: u32 = 12;
fn program(offset: i32) -> Vec<u32> {
let i = InstructionBuilder::new;
vec![
i().auipc(A0, 0).build(),
i().addi(A0, A0, (DATA - PROGRAM_BASE) as i32).build(),
i().lui(A2, 0x12345).build(),
i().ld(A1, A0, offset).build(),
i().sd(A0, A2, offset + 64).build(),
i().jal(0, 0).build(),
]
}
fn run(backend: BackendKind, offset: i32) -> (u64, u64) {
let mut config = Config::default();
config.pipeline.backend = backend;
config.cache.l1_d.enabled = true;
config.system.console = crate::config::Console::Quiet;
let mut ctx =
TestContext::new_with_config(&config).load_program(PROGRAM_BASE, &program(offset));
ctx.sim.probe_mem_store(PhysAddr::new(DATA + offset as u64), 0x1817_1615_1413_1211, 8);
ctx.run(300);
let paths = &ctx.sim.state.cores[0].units.l1_d_cache.stat_paths;
let stats = &ctx.sim.state.stats;
let accesses = stats.get(paths.hits).unwrap_or(0.0) + stats.get(paths.misses).unwrap_or(0.0);
(ctx.get_reg(A1 as usize), accesses as u64)
}
fn check(backend: BackendKind) {
let (within, accesses_within) = run(backend, 8);
let (crossing, accesses_crossing) = run(backend, 60);
assert_eq!(within, 0x1817_1615_1413_1211, "{backend:?}: aligned load value");
assert_eq!(crossing, 0x1817_1615_1413_1211, "{backend:?}: crossing load value");
assert_eq!(
accesses_crossing,
accesses_within + 2,
"{backend:?}: the crossing load and the crossing store each cost one more L1D access"
);
}
#[test]
fn a_line_straddling_access_costs_two_cache_accesses_inorder() {
check(BackendKind::InOrder);
}
#[test]
fn a_line_straddling_access_costs_two_cache_accesses_o3() {
check(BackendKind::OutOfOrder);
}