Skip to content

Commit

Permalink
get the correct runtime handler code from the 0.12 branch; the bug wa…
Browse files Browse the repository at this point in the history
…s that we need to go back to IRQ mode (not SVC mode) when finishing up the IRQ handler (which should have been obvious).
  • Loading branch information
Lokathor committed Aug 28, 2024
1 parent 73d1dde commit aa656a5
Showing 1 changed file with 25 additions and 39 deletions.
64 changes: 25 additions & 39 deletions src/asm_runtime.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,6 @@ 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 IME_OFFSET: usize = IME.as_usize() - 0x0400_0000;
const WAITCNT_OFFSET: usize = WAITCNT.as_usize() - 0x0400_0000;

// Proc-macros can't see the target being built for, so we use this declarative
Expand Down Expand Up @@ -125,56 +124,43 @@ core::arch::global_asm! {
mgba_logging_enable_request = const MGBA_LOGGING_ENABLE_REQUEST,
}

// This handler DOES NOT allow nested interrupts at this time.
core::arch::global_asm! {
bracer::put_fn_in_section!(".text.gba_rom_header"),
".global __runtime_irq_handler",
// On Entry: r0 = 0x0400_0000 (mmio_base)
// We're allowed to use the usual C ABI registers.
"__runtime_irq_handler:",

force_a32!{
/* swap IME off, user can turn it back on if they want */
"add r12, r0, #{ime_offset}",
"mov r3, #0",
"swp r3, r3, [r12]",

/* Read/Update IE and IF */
"ldr r0, [r12, #-8]",
"and r0, r0, r0, LSR #16",
"strh r0, [r12, #-6]",

/* Read/Update BIOS_IF */
"sub r2, r12, #(0x208+8)",
"ldrh r1, [r2]",
"orr r1, r1, r0",
"strh r1, [r2]",

/* Call the Rust fn pointer (if set), using System mode */
"ldr r1, ={RUST_IRQ_HANDLER}",
"ldr r1, [r1]",
bracer::when!(("r1" != "#0")[9] {
// Note(Lokathor): We are *SKIPPING* the part where we ensure that the
// System stack pointer is aligned to 8 during the call to the rust
// function. This is *technically* against the AAPCS ABI, but the GBA's
// ARMv4T CPU does not even support any instructions that require an
// alignment of 8. By not bothering to align the stack, we save about 5
// cycles total. Which is neat, but if this were on the DS (which has an
// ARMv5TE CPU) you'd want to ensure the aligned stack.

bracer::a32_read_spsr_to!("r2"),
bracer::a32_set_cpu_control!(System, irq_masked= false, fiq_masked= false),
"push {{r2, r3, r12, lr}}",
bracer::a32_fake_blx!("r1"),
"pop {{r2, r3, r12, lr}}",
bracer::a32_set_cpu_control!(Supervisor, irq_masked= true, fiq_masked= false),
bracer::a32_write_spsr_from!("r2")
/* A fox wizard told me how to do this one */
// handle MMIO interrupt system
"mov r12, 0x04000000", // load r12 with a 1 cycle value
"ldr r0, [r12, #0x200]!", // load IE_IF with r12 writeback
"and r0, r0, r0, LSR #16", // bits = IE & IF
"strh r0, [r12, #2]", // write16 to just IF
// handle BIOS IntrWait system
"ldr r1, [r12, #-0x208]!", // load BIOS_IF_?? with r12 writeback
"orr r1, r1, r0", // mark `bits` as `has_occurred`
"strh r1, [r12]", // write16 to just BIOS_IF

// Get the rust code handler fn pointer, call it if non-null.
"ldr r12, ={RUST_IRQ_HANDLER}",
"ldr r12, [r12]",
bracer::when!(("r12" != "#0")[1] {
bracer::a32_read_spsr_to!("r3"),
"push {{r3, lr}}",
bracer::a32_set_cpu_control!(System, irq_masked = true, fiq_masked = true),
bracer::a32_fake_blx!("r12"),
bracer::a32_set_cpu_control!(IRQ, irq_masked = true, fiq_masked = true),
"pop {{r3, lr}}",
bracer::a32_write_spsr_from!("r3"),
}),

/* Restore initial IME setting and return */
"swp r3, r3, [r12]",
// return to the BIOS
"bx lr",
},

// Define Our Constants
ime_offset = const IME_OFFSET,
RUST_IRQ_HANDLER = sym crate::RUST_IRQ_HANDLER,
}

0 comments on commit aa656a5

Please sign in to comment.