Skip to content

Commit

Permalink
the whole example works now (the DMA offsets were miscalculated)
Browse files Browse the repository at this point in the history
  • Loading branch information
Lokathor committed May 14, 2024
1 parent 865cb95 commit c048783
Show file tree
Hide file tree
Showing 2 changed files with 37 additions and 27 deletions.
16 changes: 15 additions & 1 deletion examples/basic_keyinput.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,17 +13,31 @@ gba::panic_handler!(empty_loop);

#[no_mangle]
pub extern "C" fn main() -> ! {
// Set a handler, and then configure interrupts on (IME), vblank interrupts
// enabled for receiving (IE), and vblank interrupts being sent (DISPSTAT).
// All these steps can be done in any order.
USER_IRQ_HANDLER.write(Some(handler));
IE.write(IrqBits::new().with_vblank(true));
IME.write(true);
IE.write(IrqBits::new().with_vblank(true));
DISPSTAT.write(DisplayStatus::new().with_vblank_irq(true));

// Once the program is ready, we turn off the forced blank bit in the display
// to begin showing things, and it will trigger a vblank interrupt after each
// draw cycle.
DISPCNT.write(DisplayControl::new());

// The body of the game is to just sleep until each vblank (this saves a lot
// of battery power), then immediately upon waking we just go back to sleep.
// The handler is effectively run "during" this wait call.
loop {
VBlankIntrWait();
}
}

extern "C" fn handler(_: IrqBits) {
// As an example of what we can do with the per-frame key data, we use it to
// set a color to the backdrop. When keys are pressed/released, the color of
// the backdrop will change.
let keys = KEYINPUT.read();
BACKDROP_COLOR.write(Color(keys.0));
}
48 changes: 22 additions & 26 deletions src/asm_runtime.rs
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,7 @@ macro_rules! global_a32_fn {
#[cfg(feature = "on_gba")]
core::arch::global_asm!{
a32_code! {
concat!(".section .iwram.text.", stringify!($name), ", \"x\" "),
concat!(".section .iwram.text.", stringify!($name), ", \"ax\",%progbits "),
concat!(".global ",stringify!($name)),
concat!(stringify!($name),":"),
$( concat!($asm_line, "\n") ),+ ,
Expand All @@ -122,7 +122,7 @@ macro_rules! global_a32_fn {
#[cfg(feature = "on_gba")]
core::arch::global_asm!{
a32_code! {
concat!(".section .text.", stringify!($name), ", \"x\" "),
concat!(".section .text.", stringify!($name), ", \"ax\",%progbits "),
concat!(".global ",stringify!($name)),
concat!(stringify!($name),":"),
$( concat!($asm_line, "\n") ),+ ,
Expand Down Expand Up @@ -244,42 +244,38 @@ global_a32_fn! {_start [] {
"1:",

"mov r12, #0x04000000",
"add r3, r12, #0xD4", // DMA3 base address

// Configure WAITCNT to the GBATEK suggested default
"add r0, r12, #0x204",
"ldr r1, =0x4317",
"strh r1, [r0]",

/* iwram copy */
"_iwram_copy:",
"ldr r4, =_iwram_word_copy_count",
when!("r4" != "#0" [label_id=1] {
"add r3, r12, #0xB0",
"mov r5, #(1<<10|1<<15)",
"ldr r0, =_iwram_start",
"ldr r2, =_iwram_position_in_rom",
"str r2, [r3]", /* source */
"str r0, [r3, #4]", /* destination */
"strh r4, [r3, #8]", /* word count */
"strh r5, [r3, #10]", /* set control bits */
"ldr r0, =_iwram_word_copy_count",
when!("r0" != "#0" [label_id=1] {
"ldr r1, =_iwram_position_in_rom",
"str r1, [r3]",
"ldr r1, =_iwram_start",
"str r1, [r3, #4]",
"strh r0, [r3, #8]",
"mov r1, #(1<<10|1<<15)",
"strh r1, [r3, #10]",
}),
"_iwram_copy_done:",

/* ewram copy */
"ldr r4, =_ewram_word_copy_count",
when!("r4" != "#0" [label_id=1] {
"add r3, r12, #0xB0",
"mov r5, #(1<<10|1<<15)",
"ldr r0, =_ewram_start",
"ldr r2, =_ewram_position_in_rom",
"str r2, [r3]", /* source */
"str r0, [r3, #4]", /* destination */
"strh r4, [r3, #8]", /* word count */
"strh r5, [r3, #10]", /* set control bits */
"ldr r1, =_ewram_position_in_rom",
"str r1, [r3]",
"ldr r1, =_ewram_start",
"str r1, [r3, #4]",
"strh r0, [r3, #8]",
"mov r1, #(1<<10|1<<15)",
"strh r1, [r3, #10]",
}),

/* bss zero */
"_begin_zeroing:",
"ldr r4, =_bss_word_clear_count",
when!("r4" != "#0" [label_id=1] {
"ldr r0, =_bss_start",
Expand All @@ -289,7 +285,6 @@ global_a32_fn! {_start [] {
"subs r4, r4, #1",
"bne 2b",
}),
"_end_zeroing:",

// Tell the BIOS about our irq handler
"ldr r0, =_asm_runtime_irq_handler",
Expand All @@ -300,7 +295,6 @@ global_a32_fn! {_start [] {
// requires a linker shim to call.
"ldr r0, =main",
"bx r0",
"_literals:",

// TODO: should we soft reset or something if `main` returns?
}}
Expand Down Expand Up @@ -346,9 +340,11 @@ global_a32_fn! {_asm_runtime_irq_handler [iwram=true] {
* r0: holds 0x0400_0000
*/

// Put IME into r12 as a base pointer.
"add r12, r0, #0x208",

// Suppress IME while this is running. If the user wants to allow for
// interrupts *during* other interrupts they can enable IME in their handler.
"add r12, r0, #0x208",
"mov r3, #0",
while_swapped! { ptr="r12", val="r3" {
// handle MMIO interrupt system
Expand Down

0 comments on commit c048783

Please sign in to comment.