#![cfg_attr(not(feature = "on_gba"), allow(unused_variables))]
use crate::macros::on_gba_or_unimplemented;
#[cfg_attr(feature = "on_gba", instruction_set(arm::a32))]
#[cfg_attr(feature = "on_gba", link_section = ".iwram.copy_u8_unchecked")]
pub unsafe extern "C" fn copy_u8_unchecked(
dest: *mut u8, src: *const u8, byte_count: usize,
) {
on_gba_or_unimplemented!(unsafe {
core::arch::asm! {
"1:",
"subs {count}, {count}, #1",
"ldrbge {temp}, [{src}], #1",
"strbge {temp}, [{dest}], #1",
"bgt 1b",
temp = out(reg) _,
count = inout(reg) byte_count => _,
src = inout(reg) src => _,
dest = inout(reg) dest => _,
options(nostack)
}
});
}
#[cfg_attr(feature = "on_gba", instruction_set(arm::a32))]
#[cfg_attr(feature = "on_gba", link_section = ".iwram.copy_u32x8_unchecked")]
pub unsafe extern "C" fn copy_u32x8_unchecked(
dest: *mut [u32; 8], src: *const [u32; 8], count: usize,
) {
on_gba_or_unimplemented!(unsafe {
core::arch::asm!(
"1:",
"subs {count}, {count}, #1",
"ldmge {src}!, {{r3,r4,r5,r7, r8,r9,r12,lr}}",
"stmge {dest}!, {{r3,r4,r5,r7, r8,r9,r12,lr}}",
"bgt 1b",
count = inout(reg) count => _,
dest = inout(reg) dest => _,
src = inout(reg) src => _,
out("r3") _,
out("r4") _,
out("r5") _,
out("r7") _,
out("r8") _,
out("r9") _,
out("r12") _,
out("lr") _,
options(nostack)
)
});
}
#[cfg_attr(feature = "on_gba", instruction_set(arm::a32))]
#[cfg_attr(feature = "on_gba", link_section = ".iwram.set_u32x80_unchecked")]
pub unsafe extern "C" fn set_u32x80_unchecked(
dest: *mut [u32; 80], word: u32, count: usize,
) {
on_gba_or_unimplemented!(unsafe {
core::arch::asm!(
"1:",
"subs {count}, {count}, #1",
"stmge {dest}!, {{r1,r3,r4,r5, r7,r8,r12,lr}}",
"stmge {dest}!, {{r1,r3,r4,r5, r7,r8,r12,lr}}",
"stmge {dest}!, {{r1,r3,r4,r5, r7,r8,r12,lr}}",
"stmge {dest}!, {{r1,r3,r4,r5, r7,r8,r12,lr}}",
"stmge {dest}!, {{r1,r3,r4,r5, r7,r8,r12,lr}}",
"stmge {dest}!, {{r1,r3,r4,r5, r7,r8,r12,lr}}",
"stmge {dest}!, {{r1,r3,r4,r5, r7,r8,r12,lr}}",
"stmge {dest}!, {{r1,r3,r4,r5, r7,r8,r12,lr}}",
"stmge {dest}!, {{r1,r3,r4,r5, r7,r8,r12,lr}}",
"stmge {dest}!, {{r1,r3,r4,r5, r7,r8,r12,lr}}",
"bgt 1b",
in("r1") word,
in("r3") word,
in("r4") word,
in("r5") word,
in("r7") word,
in("r8") word,
in("r12") word,
in("lr") word,
dest = inout(reg) dest => _,
count = inout(reg) count => _,
options(nostack),
)
});
}
#[cfg(feature = "aeabi_mem_fns")]
pub use aeabi_mem_fns::*;
#[cfg(feature = "aeabi_mem_fns")]
mod aeabi_mem_fns {
use core::ffi::c_void;
#[inline]
#[no_mangle]
#[instruction_set(arm::a32)]
#[link_section = ".iwram.__aeabi_memcpy1"]
pub unsafe extern "C" fn __aeabi_memcpy1(
dest: *mut u8, src: *const u8, byte_count: usize,
) {
core::arch::asm! {
"1:",
"subs {count}, {count}, #1",
"ldrbge {temp}, [{src}], #1",
"strbge {temp}, [{dest}], #1",
"bgt 1b",
temp = out(reg) _,
count = inout(reg) byte_count => _,
src = inout(reg) src => _,
dest = inout(reg) dest => _,
options(nostack)
}
}
#[inline]
#[no_mangle]
#[instruction_set(arm::a32)]
#[link_section = ".iwram.__aeabi_memcpy2"]
pub unsafe extern "C" fn __aeabi_memcpy2(
mut dest: *mut u16, mut src: *const u16, mut byte_count: usize,
) {
core::arch::asm! {
"1:",
"subs {count}, {count}, #2",
"ldrhge {temp}, [{src}], #2",
"strhge {temp}, [{dest}], #2",
"bgt 1b",
temp = out(reg) _,
count = inout(reg) byte_count,
src = inout(reg) src,
dest = inout(reg) dest,
options(nostack)
}
if byte_count != 0 {
let dest = dest.cast::<u8>();
let src = src.cast::<u8>();
dest.write_volatile(src.read_volatile());
}
}
#[naked]
#[no_mangle]
#[instruction_set(arm::a32)]
#[link_section = ".iwram.__aeabi_memcpy4"]
pub unsafe extern "C" fn __aeabi_memcpy4(
dest: *mut u32, src: *const u32, byte_count: usize,
) {
core::arch::naked_asm! {
bracer::when!(("r2" >=u "#32") [2] {
"push {{r4-r9}}",
"1:",
"subs r2, r2, #32",
"ldmge r1!, {{r3-r9, r12}}",
"stmge r0!, {{r3-r9, r12}}",
"bgt 1b",
"pop {{r4-r9}}",
"bxeq lr",
}),
"tst r2, #0b10000",
"ldmne r1!, {{r3, r12}}",
"stmne r0!, {{r3, r12}}",
"ldmne r1!, {{r3, r12}}",
"stmne r0!, {{r3, r12}}",
"bics r2, r2, #0b10000",
"bxeq lr",
"lsls r3, r2, #29",
"ldmcs r1!, {{r3, r12}}",
"stmcs r0!, {{r3, r12}}",
"ldrmi r3, [r1], #4",
"strmi r3, [r0], #4",
"bics r2, r2, #0b1100",
"bxeq lr",
"lsls r3, r2, #31",
"ldrhcs r3, [r1], #2",
"strhcs r3, [r0], #2",
"ldrbmi r3, [r1], #1",
"strbmi r3, [r0], #1",
"bx lr",
}
}
#[inline]
#[no_mangle]
#[instruction_set(arm::a32)]
#[link_section = ".iwram.__aeabi_memcpy8"]
pub unsafe extern "C" fn __aeabi_memcpy8(
dest: *mut u32, src: *const u32, byte_count: usize,
) {
__aeabi_memcpy4(dest, src, byte_count);
}
#[naked]
#[no_mangle]
#[instruction_set(arm::a32)]
#[link_section = ".iwram.__aeabi_memcpy"]
pub unsafe extern "C" fn __aeabi_memcpy(
dest: *mut u8, src: *const u8, byte_count: usize,
) {
core::arch::naked_asm! {
"cmp r2, #7", "ble {__aeabi_memcpy1}",
"eor r3, r0, r1",
"lsls r3, r3, #31",
"bmi {__aeabi_memcpy1}",
"bcs 2f",
"lsls r3, r0, #31",
"submi r2, r2, #1",
"ldrbmi r3, [r1], #1",
"strbmi r3, [r0], #1",
"subcs r2, r2, #2",
"ldrhcs r3, [r1], #2",
"strhcs r3, [r0], #2",
"b {__aeabi_memcpy4}",
"2:",
"lsls r3, r0, #31",
"submi r2, r2, #1",
"ldrbmi r3, [r1], #1",
"strbmi r3, [r0], #1",
"b {__aeabi_memcpy2}",
__aeabi_memcpy4 = sym __aeabi_memcpy4,
__aeabi_memcpy2 = sym __aeabi_memcpy2,
__aeabi_memcpy1 = sym __aeabi_memcpy1,
}
}
#[naked]
#[no_mangle]
#[instruction_set(arm::a32)]
#[link_section = ".iwram.memcpy"]
pub unsafe extern "C" fn memcpy(
dest: *mut u8, src: *const u8, byte_count: usize,
) -> *mut u8 {
core::arch::naked_asm! {
"push {{r0, lr}}",
"bl {__aeabi_memcpy}",
"pop {{r0, lr}}",
"bx lr",
__aeabi_memcpy = sym __aeabi_memcpy,
}
}
#[inline]
#[instruction_set(arm::a32)]
#[link_section = ".iwram.reverse_copy_u8"]
unsafe extern "C" fn reverse_copy_u8(
dest: *mut u8, src: *const u8, byte_count: usize,
) {
core::arch::asm! {
"1:",
"subs {count}, {count}, #1",
"ldrbge {temp}, [{src}, #-1]!",
"strbge {temp}, [{dest}, #-1]!",
"bgt 1b",
temp = out(reg) _,
count = inout(reg) byte_count => _,
src = inout(reg) src => _,
dest = inout(reg) dest => _,
options(nostack)
}
}
#[inline]
#[instruction_set(arm::a32)]
#[link_section = ".iwram.reverse_copy_u16"]
unsafe extern "C" fn reverse_copy_u16(
mut dest: *mut u16, mut src: *const u16, mut byte_count: usize,
) {
core::arch::asm! {
"1:",
"subs {count}, {count}, #2",
"ldrhge {temp}, [{src}, #-2]!",
"strhge {temp}, [{dest}, #-2]!",
"bgt 1b",
temp = out(reg) _,
count = inout(reg) byte_count,
src = inout(reg) src,
dest = inout(reg) dest,
options(nostack)
}
if byte_count != 0 {
let dest = dest.cast::<u8>().sub(1);
let src = src.cast::<u8>().sub(1);
dest.write_volatile(src.read_volatile());
}
}
#[naked]
#[instruction_set(arm::a32)]
#[link_section = ".iwram.reverse_copy_u32"]
unsafe extern "C" fn reverse_copy_u32(
dest: *mut u32, src: *const u32, byte_count: usize,
) {
core::arch::naked_asm! {
bracer::when!(("r2" >=u "#32") [2] {
"push {{r4-r9}}",
"1:",
"subs r2, r2, #32",
"ldmdbcs r1!, {{r3-r9, r12}}",
"stmdbcs r0!, {{r3-r9, r12}}",
"bgt 1b",
"pop {{r4-r9}}",
"bxeq lr",
}),
"tst r2, #0b10000",
"ldmdbne r1!, {{r3, r12}}",
"stmdbne r0!, {{r3, r12}}",
"ldmdbne r1!, {{r3, r12}}",
"stmdbne r0!, {{r3, r12}}",
"bics r2, r2, #0b10000",
"bxeq lr",
"lsls r3, r2, #29",
"ldmdbcs r1!, {{r3, r12}}",
"stmdbcs r0!, {{r3, r12}}",
"ldrmi r3, [r1, #-4]!",
"strmi r3, [r0, #-4]!",
"bxeq lr",
"lsls r2, r2, #31",
"ldrhcs r3, [r1, #-2]!",
"strhcs r3, [r0, #-2]!",
"ldrbmi r3, [r1, #-1]!",
"strbmi r3, [r0, #-1]!",
"bx lr",
}
}
#[inline]
#[no_mangle]
#[instruction_set(arm::a32)]
#[link_section = ".iwram.__aeabi_memmove4"]
pub unsafe extern "C" fn __aeabi_memmove4(
dest: *mut u32, src: *const u32, byte_count: usize,
) {
__aeabi_memmove(dest.cast(), src.cast(), byte_count)
}
#[inline]
#[no_mangle]
#[instruction_set(arm::a32)]
#[link_section = ".iwram.__aeabi_memmove8"]
pub unsafe extern "C" fn __aeabi_memmove8(
dest: *mut u32, src: *const u32, byte_count: usize,
) {
__aeabi_memmove(dest.cast(), src.cast(), byte_count)
}
#[naked]
#[no_mangle]
#[instruction_set(arm::a32)]
#[link_section = ".iwram.__aeabi_memmove"]
pub unsafe extern "C" fn __aeabi_memmove(
dest: *mut u8, src: *const u8, byte_count: usize,
) {
core::arch::naked_asm! {
bracer::when!(("r0" >=u "r1") [1] {
"add r0, r0, r2",
"add r1, r1, r2",
"eor r3, r0, r1",
"lsls r3, r3, #31",
"bmi {reverse_copy_u8}",
"bcs 2f",
"lsls r3, r0, #31",
"submi r2, r2, #1",
"ldrbmi r3, [r1, #-1]!",
"strbmi r3, [r0, #-1]!",
"subcs r2, r2, #2",
"ldrhcs r3, [r1, #-2]!",
"strhcs r3, [r0, #-2]!",
"b {reverse_copy_u32}",
"2:",
"tst r0, #1",
"sub r2, r2, #1",
"ldrb r3, [r1, #-1]!",
"strb r3, [r0, #-1]!",
"b {reverse_copy_u16}",
}),
"b {__aeabi_memcpy}",
__aeabi_memcpy = sym __aeabi_memcpy,
reverse_copy_u8 = sym reverse_copy_u8,
reverse_copy_u16 = sym reverse_copy_u16,
reverse_copy_u32 = sym reverse_copy_u32,
}
}
#[naked]
#[no_mangle]
#[instruction_set(arm::a32)]
#[link_section = ".iwram.memmove"]
pub unsafe extern "C" fn memmove(
dest: *mut u8, src: *const u8, byte_count: usize,
) -> *mut u8 {
core::arch::naked_asm! {
"push {{r0, lr}}",
"bl {__aeabi_memmove}",
"pop {{r0, lr}}",
"bx lr",
__aeabi_memmove = sym __aeabi_memmove,
}
}
#[inline]
#[no_mangle]
#[instruction_set(arm::a32)]
#[link_section = ".iwram.__aeabi_memset4"]
pub unsafe extern "C" fn __aeabi_memset4(
dest: *mut u32, byte_count: usize, byte: i32,
) {
__aeabi_memset(dest.cast(), byte_count, byte)
}
#[inline]
#[no_mangle]
#[instruction_set(arm::a32)]
#[link_section = ".iwram.__aeabi_memset8"]
pub unsafe extern "C" fn __aeabi_memset8(
dest: *mut u32, byte_count: usize, byte: i32,
) {
__aeabi_memset(dest.cast(), byte_count, byte)
}
#[naked]
#[no_mangle]
#[instruction_set(arm::a32)]
#[link_section = ".iwram.__aeabi_memset"]
pub unsafe extern "C" fn __aeabi_memset(
dest: *mut u8, byte_count: usize, byte: i32,
) {
core::arch::naked_asm! {
bracer::when!(("r1" >=u "#8") [7] {
"and r2, r2, #0xFF",
"orr r2, r2, r2, lsl #8",
"orr r2, r2, r2, lsl #16",
"mov r3, r2",
"tst r0, #0b1",
"subne r1, r1, #1",
"strbne r2, [r0], #1",
"tst r0, #0b10",
"subne r1, r1, #2",
"strhne r2, [r0], #2",
bracer::when!(("r1" >=u "#32") [8] {
"push {{r4-r9}}",
"mov r4, r2",
"mov r5, r2",
"mov r6, r2",
"mov r7, r2",
"mov r8, r2",
"mov r9, r2",
"1:",
"subs r1, r1, #32",
"stmge r0!, {{r2-r9}}",
"bgt 1b",
"pop {{r4-r9}}",
"bxeq lr",
}),
"tst r1, #0b10000",
"stmne r0!, {{r2, r3}}",
"stmne r0!, {{r2, r3}}",
"lsls r12, r1, #29",
"stmcs r0!, {{r2, r3}}",
"strmi r2, [r0], #4",
"lsls r12, r1, #31",
"strhcs r2, [r0], #2",
"strbmi r2, [r0], #1",
"bx lr",
}),
"9:",
"subs r1, r1, #1",
"strbcs r2, [r0], #1",
"bgt 9b",
"bx lr",
}
}
#[naked]
#[no_mangle]
#[instruction_set(arm::a32)]
#[link_section = ".iwram.memset"]
pub unsafe extern "C" fn memset(
dest: *mut u8, byte: i32, byte_count: usize,
) -> *mut u8 {
core::arch::naked_asm! {
"push {{r0, lr}}",
"mov r3, r2",
"mov r2, r1",
"mov r1, r3",
"bl {__aeabi_memset}",
"pop {{r0, lr}}",
"bx lr",
__aeabi_memset = sym __aeabi_memset,
}
}
#[inline]
#[no_mangle]
#[instruction_set(arm::a32)]
#[link_section = ".iwram.__aeabi_memclr4"]
pub unsafe extern "C" fn __aeabi_memclr4(dest: *mut u32, byte_count: usize) {
__aeabi_memset(dest.cast(), byte_count, 0)
}
#[inline]
#[no_mangle]
#[instruction_set(arm::a32)]
#[link_section = ".iwram.__aeabi_memclr8"]
pub unsafe extern "C" fn __aeabi_memclr8(dest: *mut u32, byte_count: usize) {
__aeabi_memset(dest.cast(), byte_count, 0)
}
#[inline]
#[no_mangle]
#[instruction_set(arm::a32)]
#[link_section = ".iwram.__aeabi_memclr"]
pub unsafe extern "C" fn __aeabi_memclr(dest: *mut u8, byte_count: usize) {
__aeabi_memset(dest, byte_count, 0)
}
#[naked]
#[no_mangle]
#[instruction_set(arm::a32)]
#[link_section = ".iwram.aeabi.uread4"]
unsafe extern "C" fn __aeabi_uread4(address: *const c_void) -> u32 {
core::arch::naked_asm!(
"ldrb r2, [r0]",
"ldrb r3, [r0, #1]",
"orr r2, r2, r3, lsl #8",
"ldrb r3, [r0, #2]",
"orr r2, r2, r3, lsl #16",
"ldrb r3, [r0, #3]",
"orr r2, r2, r3, lsl #24",
"mov r0, r2",
"bx lr",
)
}
#[naked]
#[no_mangle]
#[instruction_set(arm::a32)]
#[link_section = ".iwram.aeabi.uwrite4"]
unsafe extern "C" fn __aeabi_uwrite4(value: u32, address: *mut c_void) {
core::arch::naked_asm!(
"strb r0, [r1]",
"lsr r2, r0, #8",
"strb r2, [r1, #1]",
"lsr r2, r2, #8",
"strb r2, [r1, #2]",
"lsr r2, r2, #8",
"strb r2, [r1, #3]",
"bx lr",
)
}
#[naked]
#[no_mangle]
#[instruction_set(arm::a32)]
#[link_section = ".iwram.aeabi.uread8"]
unsafe extern "C" fn __aeabi_uread8(address: *const c_void) -> u64 {
core::arch::naked_asm!(
"ldrb r1, [r0, #4]",
"ldrb r2, [r0, #5]",
"orr r1, r1, r2, lsl #8",
"ldrb r2, [r0, #6]",
"orr r1, r1, r2, lsl #16",
"ldrb r2, [r0, #7]",
"orr r1, r1, r2, lsl #24",
"b {__aeabi_uread4}",
__aeabi_uread4 = sym __aeabi_uread4,
)
}
#[naked]
#[no_mangle]
#[instruction_set(arm::a32)]
#[link_section = ".iwram.aeabi.uwrite8"]
unsafe extern "C" fn __aeabi_uwrite8(value: u64, address: *mut c_void) {
core::arch::naked_asm!(
"strb r0, [r2]",
"lsr r3, r0, #8",
"strb r3, [r2, #1]",
"lsr r3, r3, #8",
"strb r3, [r2, #2]",
"lsr r3, r3, #8",
"strb r3, [r2, #3]",
"strb r1, [r2, #4]",
"lsr r3, r1, #8",
"strb r3, [r2, #5]",
"lsr r3, r3, #8",
"strb r3, [r2, #6]",
"lsr r3, r3, #8",
"strb r3, [r2, #7]",
"bx lr",
)
}
}