From fb32b9a67138db18a892ebe3a96321b498a6da71 Mon Sep 17 00:00:00 2001 From: Michel Heily Date: Sat, 24 Oct 2020 05:54:31 -0700 Subject: [PATCH] core: Implement mGBA log support. It's quite an handy way to log messages from ROMs, so I thought it'd be nice to add it. Former-commit-id: 6869bdb58cfa883ac1ca6832f0bbeeab0edcf552 Former-commit-id: 89d7d826c7a906bbb68f9f4305bb92cd50bb2296 --- core/src/iodev.rs | 27 +++++++++--- core/src/lib.rs | 1 + core/src/mgba_debug.rs | 95 ++++++++++++++++++++++++++++++++++++++++++ core/src/sysbus.rs | 14 +++---- 4 files changed, 124 insertions(+), 13 deletions(-) create mode 100644 core/src/mgba_debug.rs diff --git a/core/src/iodev.rs b/core/src/iodev.rs index 748cea0..d150cde 100644 --- a/core/src/iodev.rs +++ b/core/src/iodev.rs @@ -6,6 +6,7 @@ use super::gpu::regs::WindowFlags; use super::gpu::*; use super::interrupt::{InterruptConnect, InterruptController, SharedInterruptFlags}; use super::keypad; +use super::mgba_debug::DebugPort; use super::sched::{SchedulerConnect, SharedScheduler}; use super::sound::SoundController; use super::sysbus::SysBusPtr; @@ -33,6 +34,7 @@ pub struct IoDevices { pub post_boot_flag: bool, pub waitcnt: WaitControl, // TODO also implement 4000800 pub haltcnt: HaltState, + pub debug: DebugPort, // HACK // my ownership design sucks @@ -59,6 +61,7 @@ impl IoDevices { haltcnt: HaltState::Running, keyinput: keypad::KEYINPUT_ALL_RELEASED, waitcnt: WaitControl(0), + debug: DebugPort::new(), sysbus_ptr: Default::default(), } @@ -91,9 +94,10 @@ impl Bus for IoDevices { fn read_16(&mut self, addr: Addr) -> u16 { let io = self; let io_addr = addr + IO_BASE; - if addr > 0x0800 { - return 0; - } + // if addr > 0x0800 { + // return 0; + // } + match io_addr { REG_DISPCNT => io.gpu.dispcnt.0, REG_DISPSTAT => io.gpu.dispstat.0, @@ -133,6 +137,8 @@ impl Bus for IoDevices { REG_HALTCNT => 0, REG_KEYINPUT => io.keyinput as u16, + x if DebugPort::is_debug_access(x) => io.debug.read(io_addr), + _ => { trace!( "Unimplemented read from {:x} {}", @@ -155,9 +161,9 @@ impl Bus for IoDevices { fn write_16(&mut self, addr: Addr, value: u16) { let mut io = self; - if addr > 0x0800 { - return; - } + // if addr > 0x0800 { + // return; + // } let io_addr = addr + IO_BASE; macro_rules! write_reference_point { @@ -276,6 +282,8 @@ impl Bus for IoDevices { } } + x if DebugPort::is_debug_access(x) => io.debug.write(io_addr, value), + _ => { trace!( "Unimplemented write to {:x} {}", @@ -446,6 +454,10 @@ pub mod consts { pub const REG_IME: Addr = 0x0400_0208; // 2 R/W Interrupt Master Enable Register pub const REG_POSTFLG: Addr = 0x0400_0300; // 1 R/W Undocumented - Post Boot Flag pub const REG_HALTCNT: Addr = 0x0400_0301; // 1 W Undocumented - Power Down Control + + pub const REG_DEBUG_STRING: Addr = 0x04FF_F600; + pub const REG_DEBUG_FLAGS: Addr = 0x04FF_F700; + pub const REG_DEBUG_ENABLE: Addr = 0x04FF_F780; } pub fn io_reg_string(addr: u32) -> &'static str { @@ -554,6 +566,9 @@ pub fn io_reg_string(addr: u32) -> &'static str { REG_IME => "REG_IME", REG_POSTFLG => "REG_POSTFLG", REG_HALTCNT => "REG_HALTCNT", + REG_DEBUG_STRING => "REG_DEBUG_STRING", + REG_DEBUG_FLAGS => "REG_DEBUG_FLAGS", + REG_DEBUG_ENABLE => "REG_DEBUG_ENABLE", _ => "UNKNOWN", } } diff --git a/core/src/lib.rs b/core/src/lib.rs index 25bb1a6..cb6c00e 100644 --- a/core/src/lib.rs +++ b/core/src/lib.rs @@ -55,6 +55,7 @@ pub mod dma; pub mod keypad; pub mod timer; pub use bus::*; +mod mgba_debug; pub(crate) mod overrides; #[cfg(feature = "gdb")] diff --git a/core/src/mgba_debug.rs b/core/src/mgba_debug.rs new file mode 100644 index 0000000..1c5820a --- /dev/null +++ b/core/src/mgba_debug.rs @@ -0,0 +1,95 @@ +/// mGBA 0.8.1 Debug peripheral support +use std::str; + +use log::log; +use log::Level; + +use super::iodev::consts::{REG_DEBUG_ENABLE, REG_DEBUG_FLAGS, REG_DEBUG_STRING}; +pub const DEBUG_STRING_SIZE: usize = 0x100; + +#[derive(Clone, Serialize, Deserialize)] +pub struct DebugPort { + enable: bool, + flags: DebugFlags, + debug_string: Box<[u8]>, +} + +impl DebugPort { + pub fn new() -> DebugPort { + DebugPort { + enable: false, + flags: DebugFlags(0), + debug_string: vec![0; DEBUG_STRING_SIZE].into_boxed_slice(), + } + } + + #[inline] + pub fn is_debug_access(x: u32) -> bool { + x == REG_DEBUG_ENABLE + || x == REG_DEBUG_FLAGS + || (x >= REG_DEBUG_STRING && x <= REG_DEBUG_STRING + (DEBUG_STRING_SIZE as u32)) + } + + pub fn read(&self, addr: u32) -> u16 { + match addr { + REG_DEBUG_ENABLE => { + if self.enable { + 0x1DEA + } else { + 0 + } + } + _ => 0, + } + } + + pub fn write(&mut self, addr: u32, value: u16) { + match addr { + REG_DEBUG_ENABLE => self.enable = value == 0xC0DE, + REG_DEBUG_FLAGS => { + if self.enable { + self.flags.0 = value; + self.debug(); + } + } + x if x >= REG_DEBUG_STRING && x <= REG_DEBUG_STRING + (DEBUG_STRING_SIZE as u32) => { + let index = (addr - REG_DEBUG_STRING) as usize; + self.debug_string[index] = (value & 0xff) as u8; + self.debug_string[index + 1] = (value >> 8) as u8; + } + _ => unreachable!(), + } + } + + fn debug(&mut self) { + if self.flags.send() { + let message = str::from_utf8(&self.debug_string) + .expect("Failed to parse log message to valid utf8"); + + let level: Level = match self.flags.level() { + 0 | 1 => Level::Error, + 2 => Level::Warn, + 3 => Level::Info, + 4 => Level::Debug, + _ => panic!("invalid log level"), + }; + + log!(level, "[mGBA mLOG]: {}", message); + + for i in self.debug_string.iter_mut() { + *i = 0; + } + + self.flags.set_send(false); + } + } +} + +bitfield! { + #[derive(Clone, Serialize, Deserialize)] + pub struct DebugFlags(u16); + impl Debug; + u16; + pub into usize, level, _: 3, 0; + pub send, set_send: 8; +} diff --git a/core/src/sysbus.rs b/core/src/sysbus.rs index 870945a..afa13f0 100644 --- a/core/src/sysbus.rs +++ b/core/src/sysbus.rs @@ -325,7 +325,7 @@ impl Bus for SysBus { let addr = if addr & 0xfffc == 0x8000 { 0x800 } else { - addr & 0x7fc + addr & 0x00fffffc }; self.io.read_32(addr) } @@ -355,7 +355,7 @@ impl Bus for SysBus { let addr = if addr & 0xfffe == 0x8000 { 0x800 } else { - addr & 0x7fe + addr & 0x00fffffe }; self.io.read_16(addr) } @@ -385,7 +385,7 @@ impl Bus for SysBus { let addr = if addr & 0xffff == 0x8000 { 0x800 } else { - addr & 0x7ff + addr & 0x00ffffff }; self.io.read_8(addr) } @@ -409,7 +409,7 @@ impl Bus for SysBus { let addr = if addr & 0xfffc == 0x8000 { 0x800 } else { - addr & 0x7fc + addr & 0x00fffffc }; self.io.write_32(addr, value) } @@ -434,7 +434,7 @@ impl Bus for SysBus { let addr = if addr & 0xfffe == 0x8000 { 0x800 } else { - addr & 0x7fe + addr & 0x00fffffe }; self.io.write_16(addr, value) } @@ -459,7 +459,7 @@ impl Bus for SysBus { let addr = if addr & 0xffff == 0x8000 { 0x800 } else { - addr & 0x7ff + addr & 0x00ffffff }; self.io.write_8(addr, value) } @@ -485,7 +485,7 @@ impl DebugRead for SysBus { let addr = if addr & 0xffff == 0x8000 { 0x800 } else { - addr & 0x7ff + addr & 0x00ffffff }; self.io.debug_read_8(addr) }