mirror of
https://github.com/italicsjenga/agb.git
synced 2024-12-24 00:31:34 +11:00
Merge pull request #238 from gwilymk/agbabi
Start using agbabi for memset and memcpy
This commit is contained in:
commit
c83c9cbb60
|
@ -1,7 +1,13 @@
|
|||
use std::path;
|
||||
|
||||
fn main() {
|
||||
let asm = &["crt0.s", "interrupt_handler.s", "src/sound/mixer/mixer.s"];
|
||||
let asm = &[
|
||||
"crt0.s",
|
||||
"interrupt_handler.s",
|
||||
"src/sound/mixer/mixer.s",
|
||||
"src/agbabi/memset.s",
|
||||
"src/agbabi/memcpy.s",
|
||||
];
|
||||
|
||||
println!("cargo:rerun-if-changed=gba.ld");
|
||||
println!("cargo:rerun-if-changed=gba_mb.ld");
|
||||
|
@ -50,6 +56,7 @@ fn main() {
|
|||
}
|
||||
|
||||
let archive = format!("{out_dir}/agb.a");
|
||||
let _ = std::fs::remove_file(&archive);
|
||||
let ar_out = std::process::Command::new("arm-none-eabi-ar")
|
||||
.arg("-crs")
|
||||
.arg(&archive)
|
||||
|
|
|
@ -4,6 +4,9 @@ OUTPUT_ARCH(arm)
|
|||
ENTRY(__start)
|
||||
EXTERN(__RUST_INTERRUPT_HANDLER)
|
||||
|
||||
EXTERN(__agbabi_memset)
|
||||
EXTERN(__agbabi_memcpy)
|
||||
|
||||
MEMORY {
|
||||
ewram (w!x) : ORIGIN = 0x02000000, LENGTH = 256K
|
||||
iwram (w!x) : ORIGIN = 0x03000000, LENGTH = 32K
|
||||
|
|
|
@ -4,6 +4,9 @@ OUTPUT_ARCH(arm)
|
|||
ENTRY(__start)
|
||||
EXTERN(__RUST_INTERRUPT_HANDLER)
|
||||
|
||||
EXTERN(__agbabi_memset)
|
||||
EXTERN(__agbabi_memcpy)
|
||||
|
||||
MEMORY {
|
||||
ewram (w!x) : ORIGIN = 0x02000000, LENGTH = 256K
|
||||
iwram (w!x) : ORIGIN = 0x03000000, LENGTH = 32K
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
@ An interrupt handler that simply acknowledges all interrupts
|
||||
.arm
|
||||
.global InterruptHandler
|
||||
.section .iwram, "ax"
|
||||
.section .iwram, "ax", %progbits
|
||||
.align
|
||||
InterruptHandler:
|
||||
mov r2, #0x04000000 @ interrupt enable register location
|
||||
|
@ -50,7 +50,7 @@ InterruptHandler:
|
|||
.pool
|
||||
|
||||
|
||||
.section .iwram
|
||||
.section .iwram.program_counter
|
||||
.global agb_rs__program_counter
|
||||
.balign 4
|
||||
agb_rs__program_counter:
|
||||
|
|
17
agb/src/agbabi/LICENSE.md
Normal file
17
agb/src/agbabi/LICENSE.md
Normal file
|
@ -0,0 +1,17 @@
|
|||
libagbabi is available under the [zlib license](https://www.zlib.net/zlib_license.html) :
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
3. This notice may not be removed or altered from any source distribution.
|
10
agb/src/agbabi/README.md
Normal file
10
agb/src/agbabi/README.md
Normal file
|
@ -0,0 +1,10 @@
|
|||
# agbabi
|
||||
|
||||
GBA optimized library functions for common operations.
|
||||
|
||||
Includes implementations for various aeabi functions.
|
||||
|
||||
# Use in agb
|
||||
|
||||
Restricted to the subset of replacement functions which make the biggest difference when using rust on the gba.
|
||||
Minor modifications have been made around adding extra symbols to reference in the linker script.
|
115
agb/src/agbabi/memcpy.s
Normal file
115
agb/src/agbabi/memcpy.s
Normal file
|
@ -0,0 +1,115 @@
|
|||
/*
|
||||
===============================================================================
|
||||
|
||||
ABI:
|
||||
__aeabi_memcpy, __aeabi_memcpy4, __aeabi_memcpy8
|
||||
Standard:
|
||||
memcpy
|
||||
Support:
|
||||
__agbabi_memcpy2
|
||||
|
||||
Copyright (C) 2021-2022 agbabi contributors
|
||||
For conditions of distribution and use, see copyright notice in LICENSE.md
|
||||
|
||||
===============================================================================
|
||||
*/
|
||||
|
||||
.arm
|
||||
.align 4
|
||||
|
||||
.section .iwram.__aeabi_memcpy, "ax", %progbits
|
||||
.global __agbabi_memcpy
|
||||
__agbabi_memcpy:
|
||||
.global __aeabi_memcpy
|
||||
__aeabi_memcpy:
|
||||
// Check pointer alignment
|
||||
eor r3, r1, r0
|
||||
// JoaoBapt carry & sign bit test
|
||||
movs r3, r3, lsl #31
|
||||
bmi .Lcopy1
|
||||
bcs .Lcopy2
|
||||
|
||||
.Lcopy4:
|
||||
// Copy half and byte head
|
||||
rsb r3, r0, #4
|
||||
movs r3, r3, lsl #31
|
||||
ldrmib r3, [r1], #1
|
||||
strmib r3, [r0], #1
|
||||
submi r2, r2, #1
|
||||
ldrcsh r3, [r1], #2
|
||||
strcsh r3, [r0], #2
|
||||
subcs r2, r2, #2
|
||||
// Fallthrough
|
||||
|
||||
.global __aeabi_memcpy8
|
||||
__aeabi_memcpy8:
|
||||
.global __aeabi_memcpy4
|
||||
__aeabi_memcpy4:
|
||||
// Copy 8 words
|
||||
movs r12, r2, lsr #5
|
||||
beq .Lskip32
|
||||
lsl r3, r12, #5
|
||||
sub r2, r2, r3
|
||||
push {r4-r10}
|
||||
.LcopyWords8:
|
||||
ldmia r1!, {r3-r10}
|
||||
stmia r0!, {r3-r10}
|
||||
subs r12, r12, #1
|
||||
bne .LcopyWords8
|
||||
pop {r4-r10}
|
||||
.Lskip32:
|
||||
|
||||
// Copy words
|
||||
movs r12, r2, lsr #2
|
||||
.LcopyWords:
|
||||
subs r12, r12, #1
|
||||
ldrhs r3, [r1], #4
|
||||
strhs r3, [r0], #4
|
||||
bhs .LcopyWords
|
||||
|
||||
// Copy half and byte tail
|
||||
movs r3, r2, lsl #31
|
||||
ldrcsh r3, [r1], #2
|
||||
strcsh r3, [r0], #2
|
||||
ldrmib r3, [r1]
|
||||
strmib r3, [r0]
|
||||
bx lr
|
||||
|
||||
.Lcopy2:
|
||||
// Copy byte head
|
||||
tst r0, #1
|
||||
ldrneb r3, [r1], #1
|
||||
strneb r3, [r0], #1
|
||||
subne r2, r2, #1
|
||||
// Fallthrough
|
||||
|
||||
.global __agbabi_memcpy2
|
||||
__agbabi_memcpy2:
|
||||
// Copy halves
|
||||
movs r12, r2, lsr #1
|
||||
.LcopyHalves:
|
||||
subs r12, r12, #1
|
||||
ldrhsh r3, [r1], #2
|
||||
strhsh r3, [r0], #2
|
||||
bhs .LcopyHalves
|
||||
|
||||
// Copy byte tail
|
||||
tst r2, #1
|
||||
ldrneb r3, [r1]
|
||||
strneb r3, [r0]
|
||||
bx lr
|
||||
|
||||
.Lcopy1:
|
||||
subs r2, r2, #1
|
||||
ldrhsb r3, [r1], #1
|
||||
strhsb r3, [r0], #1
|
||||
bhs .Lcopy1
|
||||
bx lr
|
||||
|
||||
.section .iwram.memcpy, "ax", %progbits
|
||||
.global memcpy
|
||||
memcpy:
|
||||
push {r0, lr}
|
||||
bl __aeabi_memcpy
|
||||
pop {r0, lr}
|
||||
bx lr
|
107
agb/src/agbabi/memset.s
Normal file
107
agb/src/agbabi/memset.s
Normal file
|
@ -0,0 +1,107 @@
|
|||
/*
|
||||
===============================================================================
|
||||
|
||||
ABI:
|
||||
__aeabi_memset, __aeabi_memset4, __aeabi_memset8,
|
||||
__aeabi_memclr, __aeabi_memclr4, __aeabi_memclr8
|
||||
Standard:
|
||||
memset
|
||||
Support:
|
||||
__agbabi_wordset4
|
||||
|
||||
Copyright (C) 2021-2022 agbabi contributors
|
||||
For conditions of distribution and use, see copyright notice in LICENSE.md
|
||||
|
||||
===============================================================================
|
||||
*/
|
||||
|
||||
.arm
|
||||
.balign 4
|
||||
|
||||
.section .iwram.__aeabi_memset, "ax", %progbits
|
||||
.global __agbabi_memset
|
||||
__agbabi_memset:
|
||||
.global __aeabi_memclr
|
||||
__aeabi_memclr:
|
||||
mov r2, #0
|
||||
b .LskipShifts
|
||||
|
||||
.global __aeabi_memset
|
||||
__aeabi_memset:
|
||||
mov r2, r2, lsl #24
|
||||
orr r2, r2, r2, lsr #8
|
||||
orr r2, r2, r2, lsr #16
|
||||
// Fallthrough
|
||||
|
||||
.LskipShifts:
|
||||
// JoaoBapt carry & sign bit test
|
||||
rsb r3, r0, #4
|
||||
movs r3, r3, lsl #31
|
||||
// Set half and byte head
|
||||
strmib r2, [r0], #1
|
||||
submi r1, r1, #1
|
||||
strcsh r2, [r0], #2
|
||||
subcs r1, r1, #2
|
||||
b __agbabi_wordset4
|
||||
|
||||
.global __aeabi_memclr8
|
||||
__aeabi_memclr8:
|
||||
.global __aeabi_memclr4
|
||||
__aeabi_memclr4:
|
||||
mov r2, #0
|
||||
b __agbabi_wordset4
|
||||
|
||||
.global __aeabi_memset8
|
||||
__aeabi_memset8:
|
||||
.global __aeabi_memset4
|
||||
__aeabi_memset4:
|
||||
mov r2, r2, lsl #24
|
||||
orr r2, r2, r2, lsr #8
|
||||
orr r2, r2, r2, lsr #16
|
||||
// Fallthrough
|
||||
|
||||
.global __agbabi_wordset4
|
||||
__agbabi_wordset4:
|
||||
// Set 8 words
|
||||
movs r12, r1, lsr #5
|
||||
beq .Lskip32
|
||||
lsl r3, r12, #5
|
||||
sub r1, r1, r3
|
||||
push {r4-r9}
|
||||
mov r3, r2
|
||||
mov r4, r2
|
||||
mov r5, r2
|
||||
mov r6, r2
|
||||
mov r7, r2
|
||||
mov r8, r2
|
||||
mov r9, r2
|
||||
.LsetWords8:
|
||||
stmia r0!, {r2-r9}
|
||||
subs r12, r12, #1
|
||||
bne .LsetWords8
|
||||
pop {r4-r9}
|
||||
.Lskip32:
|
||||
|
||||
// Set words
|
||||
movs r12, r1, lsr #2
|
||||
.LsetWords:
|
||||
subs r12, r12, #1
|
||||
strhs r2, [r0], #4
|
||||
bhs .LsetWords
|
||||
|
||||
// Set half and byte tail
|
||||
movs r3, r1, lsl #31
|
||||
strcsh r2, [r0], #2
|
||||
strmib r2, [r0]
|
||||
bx lr
|
||||
|
||||
.section .iwram.memset, "ax", %progbits
|
||||
.global memset
|
||||
memset:
|
||||
mov r3, r1
|
||||
mov r1, r2
|
||||
mov r2, r3
|
||||
push {r0, lr}
|
||||
bl __aeabi_memset
|
||||
pop {r0, lr}
|
||||
bx lr
|
|
@ -1,5 +1,5 @@
|
|||
.macro agb_arm_func functionName:req
|
||||
.section .iwram
|
||||
.section .iwram.\functionName, "ax", %progbits
|
||||
.arm
|
||||
.align 2
|
||||
.global \functionName
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
.include "src/asm_include.s"
|
||||
|
||||
.section .iwram
|
||||
.section .iwram.buffer_size
|
||||
.global agb_rs__buffer_size
|
||||
.balign 4
|
||||
agb_rs__buffer_size:
|
||||
|
@ -26,7 +26,8 @@ modifications_fallback:
|
|||
orr r7, r7, r3, lsl #16 @ r7 now is the left channel followed by the right channel modifications.
|
||||
|
||||
mov r5, #0 @ current index we're reading from
|
||||
ldr r8, agb_rs__buffer_size @ the number of steps left
|
||||
ldr r8, =agb_rs__buffer_size @ the number of steps left
|
||||
ldr r8, [r8]
|
||||
|
||||
|
||||
1:
|
||||
|
@ -64,7 +65,8 @@ same_modification:
|
|||
bne 1b
|
||||
|
||||
mov r5, #0 @ current index we're reading from
|
||||
ldr r8, agb_rs__buffer_size @ the number of steps left
|
||||
ldr r8, =agb_rs__buffer_size @ the number of steps left
|
||||
ldr r8, [r8]
|
||||
|
||||
1:
|
||||
.rept 4
|
||||
|
@ -99,7 +101,8 @@ agb_arm_func agb_rs__mixer_add_stereo
|
|||
|
||||
ldr r5, =0x00000FFF
|
||||
|
||||
ldr r8, agb_rs__buffer_size
|
||||
ldr r8, =agb_rs__buffer_size
|
||||
ldr r8, [r8]
|
||||
1:
|
||||
.rept 4
|
||||
ldrsh r6, [r0], #2 @ load the current sound sample to r6
|
||||
|
@ -138,34 +141,6 @@ agb_arm_func agb_rs__mixer_add_stereo
|
|||
|
||||
agb_arm_end agb_rs__mixer_add_stereo
|
||||
|
||||
.section .iwram
|
||||
.balign 4
|
||||
constant_zero:
|
||||
.rept 4
|
||||
.word 0
|
||||
.endr
|
||||
|
||||
agb_arm_func agb_rs__init_buffer
|
||||
@ arguments:
|
||||
@ r0 = target buffer
|
||||
@ r1 = size in bytes (must be a multiple of 16)
|
||||
push {r4-r5}
|
||||
|
||||
@ zero registers r3-r5
|
||||
ldr r2, =constant_zero
|
||||
ldm r2, {r3-r5,r12}
|
||||
|
||||
1:
|
||||
@ zero 4 words worth of the buffer
|
||||
stmia r0!, {r3-r5,r12}
|
||||
subs r1, r1, #(4 * 4)
|
||||
@ loop if we haven't zeroed everything
|
||||
bne 1b
|
||||
|
||||
pop {r4-r5}
|
||||
bx lr
|
||||
agb_arm_end agb_rs__init_buffer
|
||||
|
||||
agb_arm_func agb_rs__mixer_collapse
|
||||
@ Arguments:
|
||||
@ r0 = target buffer (i8)
|
||||
|
@ -184,7 +159,8 @@ SWAP_SIGN .req r11
|
|||
ldr CONST_127, =127
|
||||
ldr SWAP_SIGN, =0x80808080
|
||||
|
||||
ldr r2, agb_rs__buffer_size @ loop counter
|
||||
ldr r2, =agb_rs__buffer_size @ loop counter
|
||||
ldr r2, [r2]
|
||||
mov r4, r2
|
||||
|
||||
@ The idea for this solution came from pimpmobile:
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
use core::cell::RefCell;
|
||||
use core::mem;
|
||||
use core::mem::MaybeUninit;
|
||||
use core::intrinsics::transmute;
|
||||
|
||||
use bare_metal::{CriticalSection, Mutex};
|
||||
|
||||
|
@ -29,8 +28,6 @@ extern "C" {
|
|||
fn agb_rs__mixer_add_stereo(sound_data: *const u8, sound_buffer: *mut Num<i16, 4>);
|
||||
|
||||
fn agb_rs__mixer_collapse(sound_buffer: *mut i8, input_buffer: *const Num<i16, 4>);
|
||||
|
||||
fn agb_rs__init_buffer(buffer: *mut MaybeUninit<Num<i16, 4>>, size_in_bytes: usize);
|
||||
}
|
||||
|
||||
pub struct Mixer {
|
||||
|
@ -235,28 +232,8 @@ impl MixerBuffer {
|
|||
}
|
||||
|
||||
fn write_channels<'a>(&mut self, channels: impl Iterator<Item = &'a mut SoundChannel>) {
|
||||
// This code is equivalent to:
|
||||
// let mut buffer: [Num<i16, 4>; constants::SOUND_BUFFER_SIZE * 2] =
|
||||
// [Num::new(0); constants::SOUND_BUFFER_SIZE * 2];
|
||||
// but the above uses approximately 7% of the CPU time if running at 32kHz
|
||||
let mut buffer: [Num<i16, 4>; constants::SOUND_BUFFER_SIZE * 2] = {
|
||||
// Create an uninitialized array of `MaybeUninit`. The `assume_init` is
|
||||
// safe because the type we are claiming to have initialized here is a
|
||||
// bunch of `MaybeUninit`s, which do not require initialization.
|
||||
let mut data: [MaybeUninit<Num<i16, 4>>; constants::SOUND_BUFFER_SIZE * 2] =
|
||||
unsafe { MaybeUninit::uninit().assume_init() };
|
||||
|
||||
// Actually init the array (by filling it with zeros) and then transmute it (which is safe because
|
||||
// we have now zeroed everything)
|
||||
unsafe {
|
||||
agb_rs__init_buffer(
|
||||
data.as_mut_ptr(),
|
||||
mem::size_of::<Num<i16, 4>>() * data.len(),
|
||||
);
|
||||
|
||||
mem::transmute(data)
|
||||
}
|
||||
};
|
||||
let mut buffer: [Num<i16, 4>; constants::SOUND_BUFFER_SIZE * 2] =
|
||||
unsafe { transmute([0i16; constants::SOUND_BUFFER_SIZE * 2]) };
|
||||
|
||||
for channel in channels {
|
||||
if channel.is_done {
|
||||
|
|
|
@ -4,6 +4,9 @@ OUTPUT_ARCH(arm)
|
|||
ENTRY(__start)
|
||||
EXTERN(__RUST_INTERRUPT_HANDLER)
|
||||
|
||||
EXTERN(__agbabi_memset)
|
||||
EXTERN(__agbabi_memcpy)
|
||||
|
||||
MEMORY {
|
||||
ewram (w!x) : ORIGIN = 0x02000000, LENGTH = 256K
|
||||
iwram (w!x) : ORIGIN = 0x03000000, LENGTH = 32K
|
||||
|
|
|
@ -4,6 +4,9 @@ OUTPUT_ARCH(arm)
|
|||
ENTRY(__start)
|
||||
EXTERN(__RUST_INTERRUPT_HANDLER)
|
||||
|
||||
EXTERN(__agbabi_memset)
|
||||
EXTERN(__agbabi_memcpy)
|
||||
|
||||
MEMORY {
|
||||
ewram (w!x) : ORIGIN = 0x02000000, LENGTH = 256K
|
||||
iwram (w!x) : ORIGIN = 0x03000000, LENGTH = 32K
|
||||
|
|
|
@ -4,6 +4,9 @@ OUTPUT_ARCH(arm)
|
|||
ENTRY(__start)
|
||||
EXTERN(__RUST_INTERRUPT_HANDLER)
|
||||
|
||||
EXTERN(__agbabi_memset)
|
||||
EXTERN(__agbabi_memcpy)
|
||||
|
||||
MEMORY {
|
||||
ewram (w!x) : ORIGIN = 0x02000000, LENGTH = 256K
|
||||
iwram (w!x) : ORIGIN = 0x03000000, LENGTH = 32K
|
||||
|
|
|
@ -4,6 +4,9 @@ OUTPUT_ARCH(arm)
|
|||
ENTRY(__start)
|
||||
EXTERN(__RUST_INTERRUPT_HANDLER)
|
||||
|
||||
EXTERN(__agbabi_memset)
|
||||
EXTERN(__agbabi_memcpy)
|
||||
|
||||
MEMORY {
|
||||
ewram (w!x) : ORIGIN = 0x02000000, LENGTH = 256K
|
||||
iwram (w!x) : ORIGIN = 0x03000000, LENGTH = 32K
|
||||
|
|
|
@ -4,6 +4,9 @@ OUTPUT_ARCH(arm)
|
|||
ENTRY(__start)
|
||||
EXTERN(__RUST_INTERRUPT_HANDLER)
|
||||
|
||||
EXTERN(__agbabi_memset)
|
||||
EXTERN(__agbabi_memcpy)
|
||||
|
||||
MEMORY {
|
||||
ewram (w!x) : ORIGIN = 0x02000000, LENGTH = 256K
|
||||
iwram (w!x) : ORIGIN = 0x03000000, LENGTH = 32K
|
||||
|
|
4
justfile
4
justfile
|
@ -50,6 +50,10 @@ build-book:
|
|||
update-lockfiles:
|
||||
bash .github/scripts/update-lockfiles.sh
|
||||
|
||||
update-linker-scripts:
|
||||
find -type f -name gba.ld | grep -v ./agb/gba.ld | xargs -n1 cp -v -- agb/gba.ld
|
||||
find -type f -name gba_mb.ld | grep -v ./agb/gba_mb.ld | xargs -n1 cp -v -- agb/gba_mb.ld
|
||||
|
||||
_build-rom folder name:
|
||||
#!/usr/bin/env bash
|
||||
set -euxo pipefail
|
||||
|
|
|
@ -4,6 +4,9 @@ OUTPUT_ARCH(arm)
|
|||
ENTRY(__start)
|
||||
EXTERN(__RUST_INTERRUPT_HANDLER)
|
||||
|
||||
EXTERN(__agbabi_memset)
|
||||
EXTERN(__agbabi_memcpy)
|
||||
|
||||
MEMORY {
|
||||
ewram (w!x) : ORIGIN = 0x02000000, LENGTH = 256K
|
||||
iwram (w!x) : ORIGIN = 0x03000000, LENGTH = 32K
|
||||
|
|
|
@ -4,6 +4,9 @@ OUTPUT_ARCH(arm)
|
|||
ENTRY(__start)
|
||||
EXTERN(__RUST_INTERRUPT_HANDLER)
|
||||
|
||||
EXTERN(__agbabi_memset)
|
||||
EXTERN(__agbabi_memcpy)
|
||||
|
||||
MEMORY {
|
||||
ewram (w!x) : ORIGIN = 0x02000000, LENGTH = 256K
|
||||
iwram (w!x) : ORIGIN = 0x03000000, LENGTH = 32K
|
||||
|
|
Loading…
Reference in a new issue