From b003dc950fa0c961ef5316a93cc098b38f0ad1e8 Mon Sep 17 00:00:00 2001 From: Michel Heily Date: Sat, 17 Oct 2020 17:00:02 -0700 Subject: [PATCH] core: Implement bios read protection when CPU is not executing from bios. Fixes #109 Fixes #106 Fixes MegaMan email menu freezing and probably some more games Former-commit-id: ed37520f2bc732b07334261dfe3d23cccf3fc04c Former-commit-id: d7f206b0f405ffe09a3b36d90268f1d683a64cea --- core/src/arm7tdmi/cpu.rs | 6 ++- core/src/bios.rs | 77 ++++++++++++++++++++++++++++++++++++ core/src/debugger/command.rs | 4 +- core/src/gba.rs | 17 ++++---- core/src/lib.rs | 1 + core/src/sysbus.rs | 36 ++++++++++++++--- 6 files changed, 124 insertions(+), 17 deletions(-) create mode 100644 core/src/bios.rs diff --git a/core/src/arm7tdmi/cpu.rs b/core/src/arm7tdmi/cpu.rs index febb28d..8d2c9d4 100644 --- a/core/src/arm7tdmi/cpu.rs +++ b/core/src/arm7tdmi/cpu.rs @@ -4,7 +4,7 @@ pub use super::exception::Exception; use super::{arm::ArmCond, psr::RegPSR, Addr, CpuMode, CpuState}; -use crate::util::Shared; +use crate::util::{Shared, WeakPointer}; use super::memory::{MemoryAccess, MemoryInterface}; use MemoryAccess::*; @@ -148,6 +148,10 @@ impl Core { } } + pub fn weak_ptr(&mut self) -> WeakPointer> { + WeakPointer::new(self as *mut Core) + } + pub fn from_saved_state(bus: Shared, state: SavedCpuState) -> Core { Core { bus, diff --git a/core/src/bios.rs b/core/src/bios.rs new file mode 100644 index 0000000..022cfff --- /dev/null +++ b/core/src/bios.rs @@ -0,0 +1,77 @@ +use super::arm7tdmi; +use super::bus::{Addr, Bus, DebugRead}; +use super::util::WeakPointer; +use super::SysBus; + +/// Struct representing the sytem ROM +#[derive(Clone)] +pub struct Bios { + /// Underlying memory + rom: Box<[u8]>, + /// Last read value + last_opcode: u32, + /// Arm pointer - used only to read the PC register + arm_core: WeakPointer>, +} + +impl Bios { + pub fn new(bios_rom: Box<[u8]>) -> Bios { + Bios { + rom: bios_rom, + last_opcode: 0xe129f000, // the opcode at [00DCh+8] + arm_core: WeakPointer::default(), + } + } + + pub(super) fn connect_arm_core(&mut self, arm_ptr: WeakPointer>) { + self.arm_core = arm_ptr; + } + + #[inline] + fn read_allowed(&self) -> bool { + self.arm_core.pc < 0x4000 + } +} + +/// Impl of Bus trait for Bios +impl Bus for Bios { + #[inline] + fn read_32(&mut self, addr: Addr) -> u32 { + if self.read_allowed() { + let value = self.rom.read_32(addr); + // 32-bit read from bios is most probably an opcode fetch + self.last_opcode = value; + value + } else { + self.last_opcode + } + } + #[inline] + fn read_16(&mut self, addr: Addr) -> u16 { + if self.read_allowed() { + self.rom.read_16(addr) as u16 + } else { + (self.last_opcode >> ((addr & 2) << 3)) as u16 + } + } + + #[inline] + fn read_8(&mut self, addr: Addr) -> u8 { + if self.read_allowed() { + self.rom.read_8(addr) + } else { + (self.last_opcode >> ((addr & 3) << 3)) as u8 + } + } + + #[inline] + fn write_8(&mut self, _addr: Addr, _value: u8) { + // The bios is RO + } +} + +impl DebugRead for Bios { + fn debug_read_8(&mut self, addr: Addr) -> u8 { + self.rom[addr as usize] + } +} diff --git a/core/src/debugger/command.rs b/core/src/debugger/command.rs index 574b987..0677794 100644 --- a/core/src/debugger/command.rs +++ b/core/src/debugger/command.rs @@ -113,9 +113,9 @@ impl Debugger { GpioInfo => println!("GPIO: {:#?}", self.gba.sysbus.cartridge.get_gpio()), Step(count) => { for _ in 0..count { - self.gba.cpu.step(); + self.gba.step_debugger(); while self.gba.cpu.last_executed.is_none() { - self.gba.cpu.step(); + self.gba.step_debugger(); } if let Some(last_executed) = &self.gba.cpu.last_executed { let pc = last_executed.get_pc(); diff --git a/core/src/gba.rs b/core/src/gba.rs index 2d78148..359b1a4 100644 --- a/core/src/gba.rs +++ b/core/src/gba.rs @@ -113,7 +113,7 @@ impl GameBoyAdvance { interrupt_flags: interrupt_flags, }; - gba.sysbus.created(); + gba.sysbus.init(gba.cpu.weak_ptr()); gba } @@ -136,7 +136,7 @@ impl GameBoyAdvance { io_devs.connect_irq(interrupts.clone()); io_devs.gpu.set_scheduler(scheduler.clone()); io_devs.sound.set_scheduler(scheduler.clone()); - let sysbus = Shared::new(SysBus::new_with_memories( + let mut sysbus = Shared::new(SysBus::new_with_memories( scheduler.clone(), io_devs.clone(), cartridge, @@ -144,11 +144,13 @@ impl GameBoyAdvance { decoded.ewram, decoded.iwram, )); - let arm7tdmi = Box::new(arm7tdmi::Core::from_saved_state( + let mut arm7tdmi = Box::new(arm7tdmi::Core::from_saved_state( sysbus.clone(), decoded.cpu_state, )); + sysbus.init(arm7tdmi.weak_ptr()); + Ok(GameBoyAdvance { cpu: arm7tdmi, sysbus: sysbus, @@ -197,7 +199,7 @@ impl GameBoyAdvance { self.sysbus.set_scheduler(self.scheduler.clone()); self.sysbus.set_io_devices(self.io_devs.clone()); self.sysbus.cartridge.update_from(decoded.cartridge); - self.sysbus.created(); + self.sysbus.init(self.cpu.weak_ptr()); Ok(()) } @@ -354,14 +356,13 @@ impl GameBoyAdvance { self.dma_step(); // Run the CPU - let _cycles = self.scheduler.measure_cycles(|| { - self.cpu_step(); - }); + self.cpu_step(); let breakpoint = self.check_breakpoint(); + let mut _running = true; while let Some((event, cycles_late)) = self.scheduler.pop_pending_event() { - self.handle_event(event, cycles_late, &mut running); + self.handle_event(event, cycles_late, &mut _running); } breakpoint diff --git a/core/src/lib.rs b/core/src/lib.rs index f695d20..25bb1a6 100644 --- a/core/src/lib.rs +++ b/core/src/lib.rs @@ -36,6 +36,7 @@ use std::fmt; #[macro_use] pub mod util; pub mod arm7tdmi; +mod bios; pub mod cartridge; pub mod disass; pub mod gpu; diff --git a/core/src/sysbus.rs b/core/src/sysbus.rs index f1fa97c..897071f 100644 --- a/core/src/sysbus.rs +++ b/core/src/sysbus.rs @@ -1,6 +1,8 @@ use serde::{Deserialize, Serialize}; +use super::arm7tdmi; use super::arm7tdmi::memory::*; +use super::bios::Bios; use super::bus::*; use super::cartridge::Cartridge; use super::dma::DmaNotifer; @@ -142,8 +144,9 @@ impl CycleLookupTables { pub struct SysBus { pub io: Shared, scheduler: Shared, + arm_core: WeakPointer>, - bios: BoxedMemory, + bios: Bios, ewram: Box<[u8]>, iwram: Box<[u8]>, pub cartridge: Cartridge, @@ -171,9 +174,10 @@ impl SysBus { SysBus { io, scheduler, + arm_core: WeakPointer::default(), cartridge, - bios: bios_rom, + bios: Bios::new(bios_rom), ewram, iwram, cycle_luts: luts, @@ -217,7 +221,9 @@ impl SysBus { } /// must be called whenever this object is instanciated - pub fn created(&mut self) { + pub fn init(&mut self, arm_core: WeakPointer>) { + self.arm_core = arm_core.clone(); + self.bios.connect_arm_core(arm_core.clone()); let ptr = SysBusPtr::new(self as *mut SysBus); // HACK self.io.set_sysbus_ptr(ptr.clone()); @@ -261,7 +267,13 @@ impl Bus for SysBus { #[inline] fn read_32(&mut self, addr: Addr) -> u32 { match addr & 0xff000000 { - BIOS_ADDR => self.bios.read_32(addr), + BIOS_ADDR => { + if addr <= 0x3ffc { + self.bios.read_32(addr) + } else { + 0 // TODO open-bus + } + } EWRAM_ADDR => self.ewram.read_32(addr & 0x3_fffc), IWRAM_ADDR => self.iwram.read_32(addr & 0x7ffc), IOMEM_ADDR => { @@ -288,7 +300,13 @@ impl Bus for SysBus { #[inline] fn read_16(&mut self, addr: Addr) -> u16 { match addr & 0xff000000 { - BIOS_ADDR => self.bios.read_16(addr), + BIOS_ADDR => { + if addr <= 0x3ffe { + self.bios.read_16(addr) + } else { + 0 // TODO open-bus + } + } EWRAM_ADDR => self.ewram.read_16(addr & 0x3_fffe), IWRAM_ADDR => self.iwram.read_16(addr & 0x7ffe), IOMEM_ADDR => { @@ -315,7 +333,13 @@ impl Bus for SysBus { #[inline] fn read_8(&mut self, addr: Addr) -> u8 { match addr & 0xff000000 { - BIOS_ADDR => self.bios.read_8(addr), + BIOS_ADDR => { + if addr <= 0x3fff { + self.bios.read_8(addr) + } else { + 0 // TODO open-bus + } + } EWRAM_ADDR => self.ewram.read_8(addr & 0x3_ffff), IWRAM_ADDR => self.iwram.read_8(addr & 0x7fff), IOMEM_ADDR => {