diff --git a/.cargo/config.toml b/.cargo/config.toml index 53c39bf..9a77031 100644 --- a/.cargo/config.toml +++ b/.cargo/config.toml @@ -6,4 +6,4 @@ build-std = ["core"] [target.thumbv4t-none-eabi] runner = "mgba-qt" -rustflags = ["-Clink-arg=-Tlinker_scripts/mono_boot.ld"] +rustflags = ["-Clink-arg=-Tlinker_scripts/mono_boot.ld", "--emit=mir"] diff --git a/Cargo.toml b/Cargo.toml index ac05cf9..20073b6 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -13,12 +13,18 @@ track_caller = [] [dependencies] bitfrob = "0.2.3" voladdress = { version = "1.2.1", features = ["experimental_volregion"] } +bracer = "0.1" [profile.dev] opt-level = 3 +incremental = false + +[profile.dev.package."*"] +debug-assertions = false [profile.release] codegen-units = 1 +incremental = false [package.metadata.docs.rs] # The crate can only be built for targets that have thumb-interworking support, diff --git a/dump.bat b/dump.bat index 8da0181..c62a600 100644 --- a/dump.bat +++ b/dump.bat @@ -1,3 +1,3 @@ -cargo build --examples +cargo build --examples --verbose arm-none-eabi-objdump --headers --disassemble --demangle --architecture=armv4t --no-show-raw-insn -Mreg-names-std target/thumbv4t-none-eabi/debug/examples/hello >target/dump-hello.txt arm-none-eabi-objdump --headers --disassemble --demangle --architecture=armv4t --no-show-raw-insn -Mreg-names-std target/thumbv4t-none-eabi/debug/examples/instruction_inline >target/dump-instruction_inline.txt diff --git a/dump.sh b/dump.sh index 00df37f..0ed55ce 100755 --- a/dump.sh +++ b/dump.sh @@ -1,4 +1,4 @@ #!/bin/sh -cargo build --examples +cargo build --examples --verbose arm-none-eabi-objdump --headers --disassemble --demangle --architecture=armv4t --no-show-raw-insn -Mreg-names-std target/thumbv4t-none-eabi/debug/examples/hello >target/dump-hello.txt arm-none-eabi-objdump --headers --disassemble --demangle --architecture=armv4t --no-show-raw-insn -Mreg-names-std target/thumbv4t-none-eabi/debug/examples/instruction_inline >target/dump-instruction_inline.txt diff --git a/examples/instruction_inline.rs b/examples/instruction_inline.rs index 94577bc..cfd295e 100644 --- a/examples/instruction_inline.rs +++ b/examples/instruction_inline.rs @@ -8,12 +8,16 @@ fn panic_handler(_: &core::panic::PanicInfo) -> ! { loop {} } +//#[inline(always)] #[instruction_set(arm::a32)] fn make_3rd_bg_pal_entry_black() { - BG_PALETTE.index(3).write(Color::new()); + let x: u16; + unsafe { core::arch::asm!("movs {}, #0", out(reg) x) }; + BG_PALETTE.index(3).write(Color(x)); } #[no_mangle] +#[instruction_set(arm::t32)] extern "C" fn main() -> ! { make_3rd_bg_pal_entry_black(); loop {} diff --git a/src/asm_runtime.rs b/src/asm_runtime.rs index 921a92a..b48f072 100644 --- a/src/asm_runtime.rs +++ b/src/asm_runtime.rs @@ -18,169 +18,7 @@ use crate::{ mgba::MGBA_LOGGING_ENABLE_REQUEST, mmio::{DMA3_SRC, IME, MGBA_LOG_ENABLE}, }; - -/// Builds an assembly string that puts the contained code in the section -/// specified. -/// -/// ```txt -/// put_code_in_section!( ".example.section", { -/// "lines" -/// "go" -/// "here" -/// }); -/// ``` -macro_rules! put_code_in_section { - ($section_name:expr, { - $($asm_line:expr),+ $(,)? - }) => { - concat!( - concat!(".section ", $section_name, "\n"), - $( concat!($asm_line, "\n") ),+ , - concat!(".previous\n"), - ) - } -} - -/// Builds an assembly string wrapped in `.code 32` and `.code 16` as necessary -/// -/// ```txt -/// emit_a32_code!{ -/// "lines" -/// "go" -/// "here" -/// }; -/// ``` -#[cfg(target_feature = "thumb-mode")] -macro_rules! emit_a32_code { - ($($asm_line:expr),+ $(,)?) => { - concat!( - concat!(".code 32\n"), - $( concat!($asm_line, "\n") ),+ , - concat!(".code 16\n"), - ) - } -} - -/// Builds an assembly string wrapped in `.code 32` and `.code 16` as necessary -/// -/// ```txt -/// emit_a32_code!{ -/// "lines" -/// "go" -/// "here" -/// }; -/// ``` -#[cfg(not(target_feature = "thumb-mode"))] -macro_rules! emit_a32_code { - ($($asm_line:expr),+ $(,)?) => { - concat!( - $( concat!($asm_line, "\n") ),+ , - ) - } -} - -/// Builds an assembly string that pushes some regs, does the body, then pops -/// the regs. -/// -/// The `reglist` expression should include the appropriate level of braces for -/// the enclosing assembly block (two for normal asm, or one for raw asm). -/// -/// ```txt -/// with_pushed_registers!( "reglist", { -/// "lines" -/// "go" -/// "here" -/// }); -/// ``` -macro_rules! with_pushed_registers { - ($reglist:expr, { - $($asm_line:expr),* $(,)? - }) => { - concat!( - concat!("push ", $reglist, "\n"), - $( concat!($asm_line, "\n") ),* , - concat!("pop ", $reglist, "\n"), - ) - } -} - -/// Reads SPSR into the register named, does the block, and writes the same -/// register back to SPSR. -macro_rules! with_spsr_held_in { - ($reg:literal { - $($asm_line:expr),* $(,)? - }) => { - concat!( - concat!("mrs ", $reg, ", SPSR\n"), - $( concat!($asm_line, "\n") ),* , - concat!("msr SPSR, ", $reg, "\n"), - ) - } -} - -/// Sets `lr` to just after the `bx`, then uses `bx` with the given register. -/// -/// This generates a label, so pick a `label_id` that won't interfere with any -/// nearby code. -macro_rules! adr_lr_then_bx_to { - (reg=$reg_name:expr, label_id=$label:expr) => { - concat!( - concat!("adr lr, ", $label, "f\n"), - concat!("bx ", $reg_name, "\n"), - concat!($label, ":\n"), - ) - }; -} - -/// Expands to the asm line to set the control bits of CPSR. -/// -/// * Can only be used in `a32` -/// * Only sets the control bits, all other bits (eg: flag bits) are unchanged. -/// -/// Currently, not all possible patterns are covered by this macro, just the -/// patterns needed by this runtime when it was written. In general, any of the -/// five CPU modes can be combined with irq and fiq masking each being either -/// off or on. If a desired combination is missing just add it. -macro_rules! set_cpu_control { - // CPSR low bits are: `I F T MMMMM`, and T must always be left as 0. - // * 0b10011: Supervisor (SVC) - // * 0b11111: System (SYS) - (System, irq_masked: false, fiq_masked: false) => { - "msr CPSR_c, #0b00011111\n" - }; - (Supervisor, irq_masked: true, fiq_masked: false) => { - "msr CPSR_c, #0b10010010\n" - }; -} - -/// Performs the appropriate test, then either runs the block or jumps past it, -/// depending on the test result. -/// -/// Currently supports: -/// * `$reg == $op2` -/// * `$reg != $op2` -macro_rules! when { - ($reg:literal == $op2:literal [label_id=$label:literal] { - $($asm_line:expr),* $(,)? - }) => { - concat!( - concat!("cmp ", $reg, ", ", $op2, "\n"), - concat!("bne ", $label, "f\n"), - $( concat!($asm_line, "\n") ),* , - concat!($label, ":\n"), - ) - }; - ($reg:literal != $op2:literal [label_id=$label:literal] { - $($asm_line:expr),* $(,)? - }) => { - concat!( - concat!("cmp ", $reg, ", ", $op2, "\n"), - concat!("beq ", $label, "f\n"), - $( concat!($asm_line, "\n") ),* , - concat!($label, ":\n"), - ) - }; -} +use bracer::*; /// The function pointer that the assembly runtime calls when an interrupt /// occurs. @@ -296,7 +134,7 @@ unsafe extern "C" fn runtime_irq_handler() { "ldr r1, ={RUST_IRQ_HANDLER}", "ldr r1, [r1]", when!("r1" != "#0" [label_id=9] { - with_spsr_held_in!("r2" { + with_spsr_held_in!("r2", { set_cpu_control!(System, irq_masked: false, fiq_masked: false), // Note(Lokathor): We are *SKIPPING* the part where we ensure that the