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
This commit is contained in:
parent
1ca261e5c7
commit
b003dc950f
|
@ -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<I: MemoryInterface> Core<I> {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn weak_ptr(&mut self) -> WeakPointer<Core<I>> {
|
||||
WeakPointer::new(self as *mut Core<I>)
|
||||
}
|
||||
|
||||
pub fn from_saved_state(bus: Shared<I>, state: SavedCpuState) -> Core<I> {
|
||||
Core {
|
||||
bus,
|
||||
|
|
77
core/src/bios.rs
Normal file
77
core/src/bios.rs
Normal file
|
@ -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<arm7tdmi::Core<SysBus>>,
|
||||
}
|
||||
|
||||
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<arm7tdmi::Core<SysBus>>) {
|
||||
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]
|
||||
}
|
||||
}
|
|
@ -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();
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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<IoDevices>,
|
||||
scheduler: Shared<Scheduler>,
|
||||
arm_core: WeakPointer<arm7tdmi::Core<SysBus>>,
|
||||
|
||||
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<arm7tdmi::Core<SysBus>>) {
|
||||
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 => {
|
||||
|
|
Reference in a new issue