use crate::config::BackendKind;
use crate::config::Config;
use crate::tests::support::builder::instruction::InstructionBuilder;
use crate::tests::support::harness::TestContext;
const RAM_BASE: u64 = 0x8000_0000;
const RAM_SIZE: usize = 0x4000;
const X31: u32 = 31;
const LINE_BYTES: usize = 64;
const LINES: usize = 8;
const INSTS_PER_LINE: usize = LINE_BYTES / 4;
const WIDTH: usize = 4;
const I_CACHE_LATENCY: u64 = 8;
fn straight_line_program() -> Vec<u32> {
let mut program = vec![InstructionBuilder::new().nop().build(); LINES * INSTS_PER_LINE];
let last = program.len() - 1;
program[last - 1] = InstructionBuilder::new().addi(X31, 0, 1).build();
program[last] = InstructionBuilder::new().jal(0, 0).build();
program
}
fn cycles_to_marker(backend: BackendKind) -> u64 {
let mut config = Config::default();
config.pipeline.backend = backend;
config.pipeline.width = WIDTH;
config.cache.l1_i.enabled = true;
config.cache.l1_i.line_bytes = LINE_BYTES;
config.cache.l1_i.latency = I_CACHE_LATENCY;
let mut tc = TestContext::new_with_config(&config)
.with_memory(RAM_SIZE, RAM_BASE)
.load_program(RAM_BASE, &straight_line_program());
let mut cycles = 0;
while tc.get_reg(X31 as usize) != 1 {
tc.run(1);
cycles += 1;
assert!(cycles < 10_000, "program never reached its marker");
}
cycles
}
fn assert_same_line_groups_skip_the_icache(backend: BackendKind) {
let groups = (LINES * INSTS_PER_LINE) / WIDTH;
let per_group_bound = groups as u64 * (I_CACHE_LATENCY + 1);
let cycles = cycles_to_marker(backend);
assert!(
cycles < per_group_bound,
"{cycles} cycles: every group paid the I-cache latency (bound {per_group_bound})"
);
}
#[test]
fn in_order_same_line_groups_skip_the_icache() {
assert_same_line_groups_skip_the_icache(BackendKind::InOrder);
}
#[test]
fn out_of_order_same_line_groups_skip_the_icache() {
assert_same_line_groups_skip_the_icache(BackendKind::OutOfOrder);
}