mirror of
https://github.com/italicsjenga/gba.git
synced 2025-02-02 12:46:40 +11:00
adds mgba logging support.
This commit is contained in:
parent
b05938faf4
commit
546b6e782e
5 changed files with 95 additions and 4 deletions
|
@ -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 {
|
||||
|
|
|
@ -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)
|
||||
)
|
||||
}
|
||||
|
|
|
@ -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
65
src/mgba.rs
Normal 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(())
|
||||
}
|
||||
}
|
|
@ -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");
|
||||
|
|
Loading…
Add table
Reference in a new issue