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
This commit is contained in:
parent
b28fc3108f
commit
fb32b9a671
|
@ -6,6 +6,7 @@ use super::gpu::regs::WindowFlags;
|
||||||
use super::gpu::*;
|
use super::gpu::*;
|
||||||
use super::interrupt::{InterruptConnect, InterruptController, SharedInterruptFlags};
|
use super::interrupt::{InterruptConnect, InterruptController, SharedInterruptFlags};
|
||||||
use super::keypad;
|
use super::keypad;
|
||||||
|
use super::mgba_debug::DebugPort;
|
||||||
use super::sched::{SchedulerConnect, SharedScheduler};
|
use super::sched::{SchedulerConnect, SharedScheduler};
|
||||||
use super::sound::SoundController;
|
use super::sound::SoundController;
|
||||||
use super::sysbus::SysBusPtr;
|
use super::sysbus::SysBusPtr;
|
||||||
|
@ -33,6 +34,7 @@ pub struct IoDevices {
|
||||||
pub post_boot_flag: bool,
|
pub post_boot_flag: bool,
|
||||||
pub waitcnt: WaitControl, // TODO also implement 4000800
|
pub waitcnt: WaitControl, // TODO also implement 4000800
|
||||||
pub haltcnt: HaltState,
|
pub haltcnt: HaltState,
|
||||||
|
pub debug: DebugPort,
|
||||||
|
|
||||||
// HACK
|
// HACK
|
||||||
// my ownership design sucks
|
// my ownership design sucks
|
||||||
|
@ -59,6 +61,7 @@ impl IoDevices {
|
||||||
haltcnt: HaltState::Running,
|
haltcnt: HaltState::Running,
|
||||||
keyinput: keypad::KEYINPUT_ALL_RELEASED,
|
keyinput: keypad::KEYINPUT_ALL_RELEASED,
|
||||||
waitcnt: WaitControl(0),
|
waitcnt: WaitControl(0),
|
||||||
|
debug: DebugPort::new(),
|
||||||
|
|
||||||
sysbus_ptr: Default::default(),
|
sysbus_ptr: Default::default(),
|
||||||
}
|
}
|
||||||
|
@ -91,9 +94,10 @@ impl Bus for IoDevices {
|
||||||
fn read_16(&mut self, addr: Addr) -> u16 {
|
fn read_16(&mut self, addr: Addr) -> u16 {
|
||||||
let io = self;
|
let io = self;
|
||||||
let io_addr = addr + IO_BASE;
|
let io_addr = addr + IO_BASE;
|
||||||
if addr > 0x0800 {
|
// if addr > 0x0800 {
|
||||||
return 0;
|
// return 0;
|
||||||
}
|
// }
|
||||||
|
|
||||||
match io_addr {
|
match io_addr {
|
||||||
REG_DISPCNT => io.gpu.dispcnt.0,
|
REG_DISPCNT => io.gpu.dispcnt.0,
|
||||||
REG_DISPSTAT => io.gpu.dispstat.0,
|
REG_DISPSTAT => io.gpu.dispstat.0,
|
||||||
|
@ -133,6 +137,8 @@ impl Bus for IoDevices {
|
||||||
REG_HALTCNT => 0,
|
REG_HALTCNT => 0,
|
||||||
REG_KEYINPUT => io.keyinput as u16,
|
REG_KEYINPUT => io.keyinput as u16,
|
||||||
|
|
||||||
|
x if DebugPort::is_debug_access(x) => io.debug.read(io_addr),
|
||||||
|
|
||||||
_ => {
|
_ => {
|
||||||
trace!(
|
trace!(
|
||||||
"Unimplemented read from {:x} {}",
|
"Unimplemented read from {:x} {}",
|
||||||
|
@ -155,9 +161,9 @@ impl Bus for IoDevices {
|
||||||
|
|
||||||
fn write_16(&mut self, addr: Addr, value: u16) {
|
fn write_16(&mut self, addr: Addr, value: u16) {
|
||||||
let mut io = self;
|
let mut io = self;
|
||||||
if addr > 0x0800 {
|
// if addr > 0x0800 {
|
||||||
return;
|
// return;
|
||||||
}
|
// }
|
||||||
let io_addr = addr + IO_BASE;
|
let io_addr = addr + IO_BASE;
|
||||||
|
|
||||||
macro_rules! write_reference_point {
|
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!(
|
trace!(
|
||||||
"Unimplemented write to {:x} {}",
|
"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_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_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_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 {
|
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_IME => "REG_IME",
|
||||||
REG_POSTFLG => "REG_POSTFLG",
|
REG_POSTFLG => "REG_POSTFLG",
|
||||||
REG_HALTCNT => "REG_HALTCNT",
|
REG_HALTCNT => "REG_HALTCNT",
|
||||||
|
REG_DEBUG_STRING => "REG_DEBUG_STRING",
|
||||||
|
REG_DEBUG_FLAGS => "REG_DEBUG_FLAGS",
|
||||||
|
REG_DEBUG_ENABLE => "REG_DEBUG_ENABLE",
|
||||||
_ => "UNKNOWN",
|
_ => "UNKNOWN",
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -55,6 +55,7 @@ pub mod dma;
|
||||||
pub mod keypad;
|
pub mod keypad;
|
||||||
pub mod timer;
|
pub mod timer;
|
||||||
pub use bus::*;
|
pub use bus::*;
|
||||||
|
mod mgba_debug;
|
||||||
pub(crate) mod overrides;
|
pub(crate) mod overrides;
|
||||||
|
|
||||||
#[cfg(feature = "gdb")]
|
#[cfg(feature = "gdb")]
|
||||||
|
|
95
core/src/mgba_debug.rs
Normal file
95
core/src/mgba_debug.rs
Normal file
|
@ -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;
|
||||||
|
}
|
|
@ -325,7 +325,7 @@ impl Bus for SysBus {
|
||||||
let addr = if addr & 0xfffc == 0x8000 {
|
let addr = if addr & 0xfffc == 0x8000 {
|
||||||
0x800
|
0x800
|
||||||
} else {
|
} else {
|
||||||
addr & 0x7fc
|
addr & 0x00fffffc
|
||||||
};
|
};
|
||||||
self.io.read_32(addr)
|
self.io.read_32(addr)
|
||||||
}
|
}
|
||||||
|
@ -355,7 +355,7 @@ impl Bus for SysBus {
|
||||||
let addr = if addr & 0xfffe == 0x8000 {
|
let addr = if addr & 0xfffe == 0x8000 {
|
||||||
0x800
|
0x800
|
||||||
} else {
|
} else {
|
||||||
addr & 0x7fe
|
addr & 0x00fffffe
|
||||||
};
|
};
|
||||||
self.io.read_16(addr)
|
self.io.read_16(addr)
|
||||||
}
|
}
|
||||||
|
@ -385,7 +385,7 @@ impl Bus for SysBus {
|
||||||
let addr = if addr & 0xffff == 0x8000 {
|
let addr = if addr & 0xffff == 0x8000 {
|
||||||
0x800
|
0x800
|
||||||
} else {
|
} else {
|
||||||
addr & 0x7ff
|
addr & 0x00ffffff
|
||||||
};
|
};
|
||||||
self.io.read_8(addr)
|
self.io.read_8(addr)
|
||||||
}
|
}
|
||||||
|
@ -409,7 +409,7 @@ impl Bus for SysBus {
|
||||||
let addr = if addr & 0xfffc == 0x8000 {
|
let addr = if addr & 0xfffc == 0x8000 {
|
||||||
0x800
|
0x800
|
||||||
} else {
|
} else {
|
||||||
addr & 0x7fc
|
addr & 0x00fffffc
|
||||||
};
|
};
|
||||||
self.io.write_32(addr, value)
|
self.io.write_32(addr, value)
|
||||||
}
|
}
|
||||||
|
@ -434,7 +434,7 @@ impl Bus for SysBus {
|
||||||
let addr = if addr & 0xfffe == 0x8000 {
|
let addr = if addr & 0xfffe == 0x8000 {
|
||||||
0x800
|
0x800
|
||||||
} else {
|
} else {
|
||||||
addr & 0x7fe
|
addr & 0x00fffffe
|
||||||
};
|
};
|
||||||
self.io.write_16(addr, value)
|
self.io.write_16(addr, value)
|
||||||
}
|
}
|
||||||
|
@ -459,7 +459,7 @@ impl Bus for SysBus {
|
||||||
let addr = if addr & 0xffff == 0x8000 {
|
let addr = if addr & 0xffff == 0x8000 {
|
||||||
0x800
|
0x800
|
||||||
} else {
|
} else {
|
||||||
addr & 0x7ff
|
addr & 0x00ffffff
|
||||||
};
|
};
|
||||||
self.io.write_8(addr, value)
|
self.io.write_8(addr, value)
|
||||||
}
|
}
|
||||||
|
@ -485,7 +485,7 @@ impl DebugRead for SysBus {
|
||||||
let addr = if addr & 0xffff == 0x8000 {
|
let addr = if addr & 0xffff == 0x8000 {
|
||||||
0x800
|
0x800
|
||||||
} else {
|
} else {
|
||||||
addr & 0x7ff
|
addr & 0x00ffffff
|
||||||
};
|
};
|
||||||
self.io.debug_read_8(addr)
|
self.io.debug_read_8(addr)
|
||||||
}
|
}
|
||||||
|
|
Reference in a new issue