use crate::config::BackendKind;
use crate::config::Config;
use crate::tests::support::builder::instruction::InstructionBuilder;
use crate::tests::support::harness::TestContext;
const T0: u32 = 5;
const A0: u32 = 10;
const PROGRAM_BASE: u64 = 0x8000_0000;
const LINES: u64 = 16;
const LINE_BYTES: u64 = 64;
fn program() -> Vec<u32> {
let i = InstructionBuilder::new;
let mut program =
vec![i().lui(A0, 0x1).build(), i().auipc(T0, 0).build(), i().add(A0, A0, T0).build()];
for line in 0..LINES {
program.push(i().ld(T0, A0, (line * LINE_BYTES) as i32).build());
}
program.push(i().jal(0, 0).build());
program
}
fn cycles_to_finish(bus_width: u64) -> u64 {
let mut config = Config::default();
config.pipeline.backend = BackendKind::OutOfOrder;
config.pipeline.width = 4;
config.cache.l1_d.enabled = true;
config.memory.simple_bandwidth_gib_s = 1e6;
config.system.bus_width = bus_width;
config.system.console = crate::config::Console::Quiet;
let program = program();
let mut ctx = TestContext::new_with_config(&config).load_program(PROGRAM_BASE, &program);
let all_but_spin = program.len() as u64 - 1;
let mut cycles = 0;
while ctx.sim.state.harts[0].instructions_retired < all_but_spin && cycles < 100_000 {
ctx.run(1);
cycles += 1;
}
assert!(cycles < 100_000, "every load retired");
cycles
}
#[test]
fn line_fills_queue_on_the_bus_for_their_transfer_time() {
let wide = cycles_to_finish(64);
let narrow = cycles_to_finish(8);
let extra_transfers = (LINES - 1) * 7;
assert!(
narrow >= wide + extra_transfers,
"narrow bus cost {} cycles over {wide}",
narrow - wide
);
}