use crate::{
dma::DmaControl,
gba_cell::GbaCell,
interrupts::IrqFn,
mgba::MGBA_LOGGING_ENABLE_REQUEST,
mmio::{DMA3_SRC, IME, MGBA_LOG_ENABLE, WAITCNT},
};
const DMA_32_BIT_MEMCPY: DmaControl =
DmaControl::new().with_transfer_32bit(true).with_enabled(true);
const DMA3_OFFSET: usize = DMA3_SRC.as_usize() - 0x0400_0000;
const WAITCNT_OFFSET: usize = WAITCNT.as_usize() - 0x0400_0000;
#[cfg(target_feature = "thumb-mode")]
macro_rules! force_a32 {
($($asm_line:expr),+ $(,)?) => {
bracer::t32_with_a32_scope! {
$( concat!($asm_line, "\n") ),+ ,
}
}
}
#[cfg(not(target_feature = "thumb-mode"))]
macro_rules! force_a32 {
($($asm_line:expr),+ $(,)?) => {
concat!(
$( concat!($asm_line, "\n") ),+ ,
)
}
}
core::arch::global_asm! {
bracer::put_fn_in_section!(".text.gba_rom_header"),
".global __start",
"__start:",
force_a32!{
"b 1f",
".space 0xE0",
"1:",
"mov r12, #{mmio_base}",
"add r0, r12, #{waitcnt_offset}",
"ldr r1, ={waitcnt_setting}",
"strh r1, [r0]",
"ldr r4, =__iwram_word_copy_count",
bracer::when!(("r4" != "#0")[1] {
"add r3, r12, #{dma3_offset}",
"mov r5, #{dma3_setting}",
"ldr r0, =__iwram_start",
"ldr r2, =__iwram_position_in_rom",
"str r2, [r3]",
"str r0, [r3, #4]",
"strh r4, [r3, #8]",
"strh r5, [r3, #10]",
}),
"ldr r4, =__ewram_word_copy_count",
bracer::when!(("r4" != "#0")[1] {
"add r3, r12, #{dma3_offset}",
"mov r5, #{dma3_setting}",
"ldr r0, =__ewram_start",
"ldr r2, =__ewram_position_in_rom",
"str r2, [r3]",
"str r0, [r3, #4]",
"strh r4, [r3, #8]",
"strh r5, [r3, #10]",
}),
"ldr r4, =__bss_word_clear_count",
bracer::when!(("r4" != "#0")[1] {
"ldr r0, =__bss_start",
"mov r2, #0",
"2:",
"str r2, [r0], #4",
"subs r4, r4, #1",
"bne 2b",
}),
"ldr r1, =__runtime_irq_handler",
"str r1, [r12, #-4]",
"ldr r0, ={mgba_log_enable}",
"ldr r1, ={mgba_logging_enable_request}",
"strh r1, [r0]",
"ldr r0, =main",
"bx r0",
"swi #0",
},
mmio_base = const 0x0400_0000,
waitcnt_offset = const WAITCNT_OFFSET,
waitcnt_setting = const 0x4317 ,
dma3_offset = const DMA3_OFFSET,
dma3_setting = const DMA_32_BIT_MEMCPY.to_u16(),
mgba_log_enable = const MGBA_LOG_ENABLE.as_usize(),
mgba_logging_enable_request = const MGBA_LOGGING_ENABLE_REQUEST,
}
core::arch::global_asm! {
bracer::put_fn_in_section!(".iwram.__runtime_irq_handler"),
".global __runtime_irq_handler",
"__runtime_irq_handler:",
force_a32!{
"mov r12, 0x04000000", "ldr r0, [r12, #0x200]!", "and r0, r0, r0, LSR #16", "strh r0, [r12, #2]", "ldr r1, [r12, #-0x208]!", "orr r1, r1, r0", "strh r1, [r12]",
"ldr r12, ={RUST_IRQ_HANDLER}",
"ldr r12, [r12]",
bracer::when!(("r12" != "#0")[1] {
bracer::a32_read_spsr_to!("r3"),
bracer::a32_set_cpu_control!(System, irq_masked = true, fiq_masked = true),
"push {{r3, lr}}",
bracer::a32_fake_blx!("r12"),
"pop {{r3, lr}}",
bracer::a32_set_cpu_control!(IRQ, irq_masked = true, fiq_masked = true),
bracer::a32_write_spsr_from!("r3"),
}),
"bx lr",
},
RUST_IRQ_HANDLER = sym crate::RUST_IRQ_HANDLER,
}