commit d250bb5c4632610de449e73d8100362cc155cd25 Author: lif <> Date: Sat Dec 9 01:07:49 2023 -0800 minimal template project for gba-0.11.3 diff --git a/.cargo/config.toml b/.cargo/config.toml new file mode 100644 index 0000000..1258653 --- /dev/null +++ b/.cargo/config.toml @@ -0,0 +1,13 @@ +[build] +target = "armv4t-none-eabi" + +[unstable] +build-std = ["core"] + +[target.thumbv4t-none-eabi] +runner = "mgba-qt" +rustflags = ["-Clink-arg=-Tlinker_scripts/mono_boot.ld"] + +[target.armv4t-none-eabi] +runner = "mgba-qt" +rustflags = ["-Clink-arg=-Tlinker_scripts/mono_boot.ld"] diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..ea8c4bf --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +/target diff --git a/Cargo.lock b/Cargo.lock new file mode 100644 index 0000000..617a7cd --- /dev/null +++ b/Cargo.lock @@ -0,0 +1,39 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "bitfrob" +version = "1.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a96c7c818dc8807bb1982dd2cba4c7de0ed6eba4ffb5fc24321d1b38676a120" + +[[package]] +name = "bracer" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6559b8c3065745016f5cc2d1095273fe8a175e953c976426947ad828d6ba6fda" + +[[package]] +name = "gba" +version = "0.11.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ab90d1de12c1323d80d9850c55d68931512ef7f0462a8c79e92b726f5037ad6" +dependencies = [ + "bitfrob", + "bracer", + "voladdress", +] + +[[package]] +name = "gba-template" +version = "0.1.0" +dependencies = [ + "gba", +] + +[[package]] +name = "voladdress" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7fbf3fef7bc995d3f8350936bdd07966c7a1f96183d52e3f28c29d099d0b5ecc" diff --git a/Cargo.toml b/Cargo.toml new file mode 100644 index 0000000..65a270f --- /dev/null +++ b/Cargo.toml @@ -0,0 +1,9 @@ +[package] +name = "gba-template" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +gba = "0.11.3" diff --git a/linker_scripts/mono_boot.ld b/linker_scripts/mono_boot.ld new file mode 100644 index 0000000..2f21d9d --- /dev/null +++ b/linker_scripts/mono_boot.ld @@ -0,0 +1,100 @@ +/* THIS LINKER SCRIPT FILE IS RELEASED TO THE PUBLIC DOMAIN (SPDX: CC0-1.0) */ + +ENTRY(__start) + +MEMORY { + ewram (w!x) : ORIGIN = 0x2000000, LENGTH = 256K + iwram (w!x) : ORIGIN = 0x3000000, LENGTH = 32K + rom (rx) : ORIGIN = 0x8000000, LENGTH = 32M +} + +SECTIONS { + .text : { + /* be sure that the ROM header is the very first */ + *(.text.gba_rom_header); + *(.text .text.*); + . = ALIGN(4); + } >rom = 0x00 + + .rodata : { + *(.rodata .rodata.*); + . = ALIGN(4); + } >rom = 0x00 + + . = ALIGN(4); + __iwram_position_in_rom = .; + .data : { + __iwram_start = ABSOLUTE(.); + + *(.data .data.*); + *(.iwram .iwram.*); + . = ALIGN(4); + + __iwram_end = ABSOLUTE(.); + } >iwram AT>rom = 0x00 + + . = ALIGN(4); + __ewram_position_in_rom = __iwram_position_in_rom + (__iwram_end - __iwram_start); + .ewram : { + __ewram_start = ABSOLUTE(.); + + *(.ewram .ewram.*); + . = ALIGN(4); + + __ewram_end = ABSOLUTE(.); + } >ewram AT>rom = 0x00 + + . = ALIGN(4); + __bss_position_in_rom = __ewram_position_in_rom + (__ewram_end - __ewram_start); + .bss : { + __bss_start = ABSOLUTE(.); + + *(.bss .bss.*); + . = ALIGN(4); + + __bss_end = ABSOLUTE(.); + } >iwram + + __iwram_word_copy_count = (__iwram_end - __iwram_start) / 4; + __ewram_word_copy_count = (__ewram_end - __ewram_start) / 4; + __bss_word_clear_count = (__bss_end - __bss_start) / 4; + + /* rust-lld demands we keep the `section header string table` */ + .shstrtab 0 : { *(.shstrtab) } + + /* debugging sections */ + /* Stabs */ + .stab 0 : { *(.stab) } + .stabstr 0 : { *(.stabstr) } + .stab.excl 0 : { *(.stab.excl) } + .stab.exclstr 0 : { *(.stab.exclstr) } + .stab.index 0 : { *(.stab.index) } + .stab.indexstr 0 : { *(.stab.indexstr) } + .comment 0 : { *(.comment) } + /* DWARF 1 */ + .debug 0 : { *(.debug) } + .line 0 : { *(.line) } + /* GNU DWARF 1 extensions */ + .debug_srcinfo 0 : { *(.debug_srcinfo) } + .debug_sfnames 0 : { *(.debug_sfnames) } + /* DWARF 1.1 and DWARF 2 */ + .debug_aranges 0 : { *(.debug_aranges) } + .debug_pubnames 0 : { *(.debug_pubnames) } + /* DWARF 2 */ + .debug_info 0 : { *(.debug_info) } + .debug_abbrev 0 : { *(.debug_abbrev) } + .debug_line 0 : { *(.debug_line) } + .debug_frame 0 : { *(.debug_frame) } + .debug_str 0 : { *(.debug_str) } + .debug_loc 0 : { *(.debug_loc) } + .debug_macinfo 0 : { *(.debug_macinfo) } + /* SGI/MIPS DWARF 2 extensions */ + .debug_weaknames 0 : { *(.debug_weaknames) } + .debug_funcnames 0 : { *(.debug_funcnames) } + .debug_typenames 0 : { *(.debug_typenames) } + .debug_varnames 0 : { *(.debug_varnames) } + + /* discard anything not already mentioned */ + /DISCARD/ : { *(*) } +} + diff --git a/src/main.rs b/src/main.rs new file mode 100644 index 0000000..bf04120 --- /dev/null +++ b/src/main.rs @@ -0,0 +1,98 @@ +// from https://github.com/rust-console/gba/blob/main/examples/hello.rs +#![no_std] +#![no_main] + +use core::fmt::Write; +use gba::prelude::*; + +#[panic_handler] +fn panic_handler(info: &core::panic::PanicInfo) -> ! { + #[cfg(debug_assertions)] + if let Ok(mut logger) = MgbaBufferedLogger::try_new(MgbaMessageLevel::Fatal) { + writeln!(logger, "{info}").ok(); + } + loop {} +} + +#[link_section = ".ewram"] +static FRAME_KEYS: GbaCell = GbaCell::new(KeyInput::new()); + +#[link_section = ".iwram"] +extern "C" fn irq_handler(_: IrqBits) { + // We'll read the keys during vblank and store it for later. + FRAME_KEYS.write(KEYINPUT.read()); +} + +#[no_mangle] +extern "C" fn main() -> ! { + RUST_IRQ_HANDLER.write(Some(irq_handler)); + DISPSTAT.write(DisplayStatus::new().with_irq_vblank(true)); + IE.write(IrqBits::VBLANK); + IME.write(true); + + if let Ok(mut logger) = MgbaBufferedLogger::try_new(MgbaMessageLevel::Debug) { + writeln!(logger, "hello!").ok(); + + let fx_u: Fixed = Fixed::::wrapping_from(7) + Fixed::::from_raw(12); + writeln!(logger, "fixed unsigned: {fx_u:?}").ok(); + + let fx_i1: Fixed = + Fixed::::wrapping_from(8) + Fixed::::from_raw(15); + writeln!(logger, "fixed signed positive: {fx_i1:?}").ok(); + + let fx_i2: Fixed = Fixed::::wrapping_from(0) + - Fixed::::wrapping_from(3) + - Fixed::::from_raw(17); + writeln!(logger, "fixed signed negative: {fx_i2:?}").ok(); + } + + { + // get our tile data into memory. + Cga8x8Thick.bitunpack_4bpp(CHARBLOCK0_4BPP.as_region(), 0); + } + + { + // set up the tilemap + let tsb = TEXT_SCREENBLOCKS.get_frame(31).unwrap(); + for y in 0..16 { + let row = tsb.get_row(y).unwrap(); + for (x, addr) in row.iter().enumerate().take(16) { + let te = TextEntry::new().with_tile((y * 16 + x) as u16); + addr.write(te); + } + } + } + + { + // Set BG0 to use the tilemap we just made, and set it to be shown. + BG0CNT.write(BackgroundControl::new().with_screenblock(31)); + DISPCNT.write(DisplayControl::new().with_show_bg0(true)); + } + + let mut x_off = 0_u32; + let mut y_off = 0_u32; + let mut backdrop_color = Color(0); + loop { + VBlankIntrWait(); + // show current frame + BACKDROP_COLOR.write(backdrop_color); + BG0HOFS.write(x_off as u16); + BG0VOFS.write(y_off as u16); + + // prep next frame + let k = FRAME_KEYS.read(); + backdrop_color = Color(k.to_u16()); + if k.up() { + y_off = y_off.wrapping_add(1); + } + if k.down() { + y_off = y_off.wrapping_sub(1); + } + if k.left() { + x_off = x_off.wrapping_add(1); + } + if k.right() { + x_off = x_off.wrapping_sub(1); + } + } +}