fix(memory): ignore emulated writes to mapped BIOS

This commit is contained in:
0xrsydn 2026-10-07 03:31:33 +07:00
commit a0516de748
16 changed files with 462 additions and 34 deletions

View file

@ -22,6 +22,8 @@ mod arithmetic;
mod bit_unpack;
#[path = "bios/boot_video.rs"]
mod boot_video;
#[path = "bios/copy_bus.rs"]
mod copy_bus;
#[path = "bios/differential.rs"]
mod differential;
#[path = "bios/huffman.rs"]

View file

@ -0,0 +1,51 @@
//! Copy services execute real bus accesses, including ignored BIOS destinations.
use super::*;
#[test]
fn copy_and_fill_to_bios_return_without_modifying_firmware() {
for thumb in [false, true] {
for (service, width) in [(0x0b, 0), (0x0b, 1 << 26), (0x0c, 0)] {
for fill in [0, 1 << 24] {
let (mut machine, return_pc) = call(service, thumb, [SOURCE, 0, 28 | width | fill]);
for index in 0..32 {
machine
.memory_mut()
.write32(SOURCE + index * 4, 0x1234_abcd ^ index)
.unwrap();
}
let before = machine.cpu().clone();
let cycles = machine.cycles();
finish(&mut machine, return_pc);
assert_eq!(&machine.cpu().registers()[..15], &before.registers()[..15]);
assert_eq!(machine.cpu().cpsr(), before.cpsr());
assert!(machine.cycles() > cycles);
for (address, expected) in bios::image().into_iter().enumerate() {
assert_eq!(machine.memory().read8(address as u32).unwrap(), expected);
}
assert_eq!(
machine.memory_mut().write16(0, 0),
Err(MemoryError::ReadOnly(0))
);
}
}
}
}
#[test]
fn ignored_bios_destination_does_not_bypass_invalid_source_reads() {
for service in [0x0b, 0x0c] {
let (mut machine, _) = call(service, true, [0x0e00_0000, 0, 1]);
let error = (0..200)
.find_map(|_| machine.step().err())
.expect("source read must still fail");
assert_eq!(
error,
MachineError::Cpu(CpuError::Memory(MemoryError::Unmapped(0x0e00_0000)))
);
let cpu = machine.cpu().clone();
let cycles = machine.cycles();
assert_eq!(machine.step(), Err(error));
assert_eq!(machine.cpu(), &cpu);
assert_eq!(machine.cycles(), cycles);
}
}

View file

@ -436,14 +436,14 @@ fn dma_reset_disables_channels_and_clears_write_only_address_and_count_latches()
);
m.memory_mut().write16(base + 10, 0).unwrap();
m.memory_mut().write32(base, SOURCE).unwrap();
m.memory_mut().write32(SOURCE, MARKER).unwrap();
m.memory_mut().write32(DEST, !MARKER).unwrap();
let vector = m.memory().read32(0).unwrap();
m.memory_mut().write16(base + 10, 0x8000).unwrap();
assert_eq!(
m.step(),
Err(MachineError::Dma(DmaError::Memory {
channel,
error: MemoryError::ReadOnly(0)
}))
);
assert_eq!(m.step().unwrap(), StepKind::Dma { channel });
// The reset destination is BIOS: discard the transfer, not into stale DEST.
assert_eq!(m.memory().read32(0).unwrap(), vector);
assert_eq!(m.memory().read32(DEST).unwrap(), !MARKER);
m.memory_mut().write16(base + 10, 0).unwrap();
m.memory_mut().write32(base + 4, DEST).unwrap();
m.memory_mut().write32(SOURCE, MARKER).unwrap();