adds mgba logging support.

This commit is contained in:
Lokathor 2022-09-27 17:57:09 -06:00
parent b05938faf4
commit 546b6e782e
5 changed files with 95 additions and 4 deletions

View file

@ -2,10 +2,17 @@
#![no_main]
#![feature(isa_attribute)]
use gba::prelude::*;
use core::fmt::Write;
use gba::{
mgba::{MgbaBufferedLogger, MgbaMessageLevel},
prelude::*,
};
#[panic_handler]
fn panic_handler(_: &core::panic::PanicInfo) -> ! {
fn panic_handler(info: &core::panic::PanicInfo) -> ! {
if let Ok(mut logger) = MgbaBufferedLogger::try_new(MgbaMessageLevel::Fatal) {
write!(logger, "{info}").ok();
}
loop {}
}
@ -26,6 +33,10 @@ extern "C" fn main() -> ! {
IE.write(IrqBits::VBLANK);
IME.write(true);
if let Ok(mut logger) = MgbaBufferedLogger::try_new(MgbaMessageLevel::Debug) {
writeln!(logger, "hello!").ok();
}
DISPCNT.write(DisplayControl::new().with_show_bg0(true));
loop {

View file

@ -4,7 +4,8 @@ use crate::{
dma::DmaControl,
gba_cell::GbaCell,
interrupts::IrqFn,
mmio::{DMA3_SRC, IME},
mgba::MGBA_LOGGING_ENABLE_REQUEST,
mmio::{DMA3_SRC, IME, MGBA_LOG_ENABLE},
};
/// Builds an assembly string that puts the contained code in the section
@ -235,6 +236,11 @@ unsafe extern "C" fn __start() -> ! {
"ldr r1, ={runtime_irq_handler}",
"str r1, [r12, #-4]",
/* ask for mGBA logging to be enabled. This should be harmless if we're not using mgba. */
"ldr r0, ={mgba_log_enable}",
"ldr r1, ={mgba_logging_enable_request}",
"str r1, [r0]",
/* call to rust main */
"ldr r0, =main",
"bx r0",
@ -246,6 +252,8 @@ unsafe extern "C" fn __start() -> ! {
dma3_offset = const DMA3_OFFSET,
dma3_setting = const DMA_32_BIT_MEMCPY.to_u16(),
runtime_irq_handler = sym runtime_irq_handler,
mgba_log_enable = const MGBA_LOG_ENABLE.as_usize(),
mgba_logging_enable_request = const MGBA_LOGGING_ENABLE_REQUEST,
options(noreturn)
)
}

View file

@ -12,6 +12,7 @@ pub mod dma;
pub mod gba_cell;
pub mod interrupts;
pub mod keys;
pub mod mgba;
pub mod mmio;
pub mod prelude;
pub mod sound;

65
src/mgba.rs Normal file
View file

@ -0,0 +1,65 @@
use crate::mmio::{MGBA_LOG_BUFFER, MGBA_LOG_ENABLE, MGBA_LOG_SEND};
pub const MGBA_LOGGING_ENABLE_REQUEST: u16 = 0xC0DE;
pub const MGBA_LOGGING_ENABLE_RESPONSE: u16 = 0x1DEA;
#[derive(Debug, Default, Clone, Copy, PartialEq, Eq)]
#[repr(u16)]
pub enum MgbaMessageLevel {
/// Warning! This causes mGBA to halt emulation!
Fatal = 0x100,
Error = 0x101,
Warning = 0x102,
Info = 0x103,
#[default]
Debug = 0x104,
}
/// Returns if mGBA logging is possible.
#[inline]
pub fn mgba_logging_available() -> bool {
// the `__start` function writes the request, so here we just check success.
MGBA_LOG_ENABLE.read() == MGBA_LOGGING_ENABLE_RESPONSE
}
pub struct MgbaBufferedLogger {
byte_count: u8,
pub message_level: MgbaMessageLevel,
}
impl MgbaBufferedLogger {
pub fn try_new(message_level: MgbaMessageLevel) -> Result<Self, ()> {
if mgba_logging_available() {
Ok(Self { byte_count: 0, message_level })
} else {
Err(())
}
}
fn flush(&mut self) {
MGBA_LOG_SEND.write(self.message_level);
self.byte_count = 0;
}
}
impl Drop for MgbaBufferedLogger {
fn drop(&mut self) {
if self.byte_count != 0 {
self.flush();
}
}
}
impl core::fmt::Write for MgbaBufferedLogger {
fn write_str(&mut self, s: &str) -> core::fmt::Result {
for b in s.as_bytes().iter().copied() {
if b == b'\n' {
self.flush();
} else {
MGBA_LOG_BUFFER.index(self.byte_count as usize).write(b);
if self.byte_count == u8::MAX {
self.flush();
} else {
self.byte_count += 1;
}
}
}
Ok(())
}
}

View file

@ -38,7 +38,7 @@ use crate::{
sound::{
SweepControl, TonePattern, ToneFrequency, WaveBank, WaveLenVolume, WaveFrequency, NoiseLenEnvelope, NoiseFrequency, LeftRightVolume, SoundMix, SoundEnable, SoundBias
},
timers::TimerControl, keys::{KeyInput, KeyControl},
timers::TimerControl, keys::{KeyInput, KeyControl}, mgba::MgbaMessageLevel,
};
// Note(Lokathor): This macro lets us stick each address at the start of the
@ -198,6 +198,12 @@ def_mmio!(0x0400_0202 = IF: VolAddress<IrqBits, Safe, Safe>; "Interrupts Flagged
def_mmio!(0x0400_0204 = WAITCNT: VolAddress<u16, Safe, Unsafe>; "Wait state control for interfacing with the ROM (can make reading the ROM give garbage when it's mis-configured)");
def_mmio!(0x0400_0208 = IME: VolAddress<bool, Safe, Safe>; "Interrupt Master Enable: Allows turning on/off all interrupts with a single access.");
// mGBA Debugging Console
def_mmio!(0x04FF_F600 = MGBA_LOG_BUFFER: VolBlock<u8, Safe, Safe, 256>; "The buffer to put logging messages into.\n\nThe first 0 in the buffer is the end of each message.");
def_mmio!(0x04FF_F700 = MGBA_LOG_SEND: VolAddress<MgbaMessageLevel, (), Safe>; "Write to this each time you want to reset a message (it also resets the buffer).");
def_mmio!(0x04FF_F780 = MGBA_LOG_ENABLE: VolAddress<u16, Safe, Safe>; "Allows you to attempt to activate mGBA logging.");
// Palette RAM (PALRAM)
def_mmio!(0x0500_0000 = BACKDROP_COLOR: VolAddress<Color, Safe, Safe>; "Color that's shown when no BG or OBJ draws to a pixel");