Merge pull request #238 from gwilymk/agbabi

Start using agbabi for memset and memcpy
This commit is contained in:
Corwin 2022-06-17 00:58:40 +01:00 committed by GitHub
commit c83c9cbb60
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
19 changed files with 303 additions and 63 deletions

View file

@ -1,7 +1,13 @@
use std::path; use std::path;
fn main() { 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.ld");
println!("cargo:rerun-if-changed=gba_mb.ld"); println!("cargo:rerun-if-changed=gba_mb.ld");
@ -50,6 +56,7 @@ fn main() {
} }
let archive = format!("{out_dir}/agb.a"); let archive = format!("{out_dir}/agb.a");
let _ = std::fs::remove_file(&archive);
let ar_out = std::process::Command::new("arm-none-eabi-ar") let ar_out = std::process::Command::new("arm-none-eabi-ar")
.arg("-crs") .arg("-crs")
.arg(&archive) .arg(&archive)

View file

@ -4,6 +4,9 @@ OUTPUT_ARCH(arm)
ENTRY(__start) ENTRY(__start)
EXTERN(__RUST_INTERRUPT_HANDLER) EXTERN(__RUST_INTERRUPT_HANDLER)
EXTERN(__agbabi_memset)
EXTERN(__agbabi_memcpy)
MEMORY { MEMORY {
ewram (w!x) : ORIGIN = 0x02000000, LENGTH = 256K ewram (w!x) : ORIGIN = 0x02000000, LENGTH = 256K
iwram (w!x) : ORIGIN = 0x03000000, LENGTH = 32K iwram (w!x) : ORIGIN = 0x03000000, LENGTH = 32K

View file

@ -4,6 +4,9 @@ OUTPUT_ARCH(arm)
ENTRY(__start) ENTRY(__start)
EXTERN(__RUST_INTERRUPT_HANDLER) EXTERN(__RUST_INTERRUPT_HANDLER)
EXTERN(__agbabi_memset)
EXTERN(__agbabi_memcpy)
MEMORY { MEMORY {
ewram (w!x) : ORIGIN = 0x02000000, LENGTH = 256K ewram (w!x) : ORIGIN = 0x02000000, LENGTH = 256K
iwram (w!x) : ORIGIN = 0x03000000, LENGTH = 32K iwram (w!x) : ORIGIN = 0x03000000, LENGTH = 32K

View file

@ -2,7 +2,7 @@
@ An interrupt handler that simply acknowledges all interrupts @ An interrupt handler that simply acknowledges all interrupts
.arm .arm
.global InterruptHandler .global InterruptHandler
.section .iwram, "ax" .section .iwram, "ax", %progbits
.align .align
InterruptHandler: InterruptHandler:
mov r2, #0x04000000 @ interrupt enable register location mov r2, #0x04000000 @ interrupt enable register location
@ -50,7 +50,7 @@ InterruptHandler:
.pool .pool
.section .iwram .section .iwram.program_counter
.global agb_rs__program_counter .global agb_rs__program_counter
.balign 4 .balign 4
agb_rs__program_counter: agb_rs__program_counter:

17
agb/src/agbabi/LICENSE.md Normal file
View 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
View 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
View 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
View 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

View file

@ -1,5 +1,5 @@
.macro agb_arm_func functionName:req .macro agb_arm_func functionName:req
.section .iwram .section .iwram.\functionName, "ax", %progbits
.arm .arm
.align 2 .align 2
.global \functionName .global \functionName

View file

@ -1,6 +1,6 @@
.include "src/asm_include.s" .include "src/asm_include.s"
.section .iwram .section .iwram.buffer_size
.global agb_rs__buffer_size .global agb_rs__buffer_size
.balign 4 .balign 4
agb_rs__buffer_size: 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. 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 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: 1:
@ -64,7 +65,8 @@ same_modification:
bne 1b bne 1b
mov r5, #0 @ current index we're reading from 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: 1:
.rept 4 .rept 4
@ -99,7 +101,8 @@ agb_arm_func agb_rs__mixer_add_stereo
ldr r5, =0x00000FFF ldr r5, =0x00000FFF
ldr r8, agb_rs__buffer_size ldr r8, =agb_rs__buffer_size
ldr r8, [r8]
1: 1:
.rept 4 .rept 4
ldrsh r6, [r0], #2 @ load the current sound sample to r6 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 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 agb_arm_func agb_rs__mixer_collapse
@ Arguments: @ Arguments:
@ r0 = target buffer (i8) @ r0 = target buffer (i8)
@ -184,7 +159,8 @@ SWAP_SIGN .req r11
ldr CONST_127, =127 ldr CONST_127, =127
ldr SWAP_SIGN, =0x80808080 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 mov r4, r2
@ The idea for this solution came from pimpmobile: @ The idea for this solution came from pimpmobile:

View file

@ -1,6 +1,5 @@
use core::cell::RefCell; use core::cell::RefCell;
use core::mem; use core::intrinsics::transmute;
use core::mem::MaybeUninit;
use bare_metal::{CriticalSection, Mutex}; 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_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__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 { pub struct Mixer {
@ -235,28 +232,8 @@ impl MixerBuffer {
} }
fn write_channels<'a>(&mut self, channels: impl Iterator<Item = &'a mut SoundChannel>) { 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] =
// let mut buffer: [Num<i16, 4>; constants::SOUND_BUFFER_SIZE * 2] = unsafe { transmute([0i16; 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)
}
};
for channel in channels { for channel in channels {
if channel.is_done { if channel.is_done {

View file

@ -4,6 +4,9 @@ OUTPUT_ARCH(arm)
ENTRY(__start) ENTRY(__start)
EXTERN(__RUST_INTERRUPT_HANDLER) EXTERN(__RUST_INTERRUPT_HANDLER)
EXTERN(__agbabi_memset)
EXTERN(__agbabi_memcpy)
MEMORY { MEMORY {
ewram (w!x) : ORIGIN = 0x02000000, LENGTH = 256K ewram (w!x) : ORIGIN = 0x02000000, LENGTH = 256K
iwram (w!x) : ORIGIN = 0x03000000, LENGTH = 32K iwram (w!x) : ORIGIN = 0x03000000, LENGTH = 32K

View file

@ -4,6 +4,9 @@ OUTPUT_ARCH(arm)
ENTRY(__start) ENTRY(__start)
EXTERN(__RUST_INTERRUPT_HANDLER) EXTERN(__RUST_INTERRUPT_HANDLER)
EXTERN(__agbabi_memset)
EXTERN(__agbabi_memcpy)
MEMORY { MEMORY {
ewram (w!x) : ORIGIN = 0x02000000, LENGTH = 256K ewram (w!x) : ORIGIN = 0x02000000, LENGTH = 256K
iwram (w!x) : ORIGIN = 0x03000000, LENGTH = 32K iwram (w!x) : ORIGIN = 0x03000000, LENGTH = 32K

View file

@ -4,6 +4,9 @@ OUTPUT_ARCH(arm)
ENTRY(__start) ENTRY(__start)
EXTERN(__RUST_INTERRUPT_HANDLER) EXTERN(__RUST_INTERRUPT_HANDLER)
EXTERN(__agbabi_memset)
EXTERN(__agbabi_memcpy)
MEMORY { MEMORY {
ewram (w!x) : ORIGIN = 0x02000000, LENGTH = 256K ewram (w!x) : ORIGIN = 0x02000000, LENGTH = 256K
iwram (w!x) : ORIGIN = 0x03000000, LENGTH = 32K iwram (w!x) : ORIGIN = 0x03000000, LENGTH = 32K

View file

@ -4,6 +4,9 @@ OUTPUT_ARCH(arm)
ENTRY(__start) ENTRY(__start)
EXTERN(__RUST_INTERRUPT_HANDLER) EXTERN(__RUST_INTERRUPT_HANDLER)
EXTERN(__agbabi_memset)
EXTERN(__agbabi_memcpy)
MEMORY { MEMORY {
ewram (w!x) : ORIGIN = 0x02000000, LENGTH = 256K ewram (w!x) : ORIGIN = 0x02000000, LENGTH = 256K
iwram (w!x) : ORIGIN = 0x03000000, LENGTH = 32K iwram (w!x) : ORIGIN = 0x03000000, LENGTH = 32K

View file

@ -4,6 +4,9 @@ OUTPUT_ARCH(arm)
ENTRY(__start) ENTRY(__start)
EXTERN(__RUST_INTERRUPT_HANDLER) EXTERN(__RUST_INTERRUPT_HANDLER)
EXTERN(__agbabi_memset)
EXTERN(__agbabi_memcpy)
MEMORY { MEMORY {
ewram (w!x) : ORIGIN = 0x02000000, LENGTH = 256K ewram (w!x) : ORIGIN = 0x02000000, LENGTH = 256K
iwram (w!x) : ORIGIN = 0x03000000, LENGTH = 32K iwram (w!x) : ORIGIN = 0x03000000, LENGTH = 32K

View file

@ -50,6 +50,10 @@ build-book:
update-lockfiles: update-lockfiles:
bash .github/scripts/update-lockfiles.sh 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: _build-rom folder name:
#!/usr/bin/env bash #!/usr/bin/env bash
set -euxo pipefail set -euxo pipefail

View file

@ -4,6 +4,9 @@ OUTPUT_ARCH(arm)
ENTRY(__start) ENTRY(__start)
EXTERN(__RUST_INTERRUPT_HANDLER) EXTERN(__RUST_INTERRUPT_HANDLER)
EXTERN(__agbabi_memset)
EXTERN(__agbabi_memcpy)
MEMORY { MEMORY {
ewram (w!x) : ORIGIN = 0x02000000, LENGTH = 256K ewram (w!x) : ORIGIN = 0x02000000, LENGTH = 256K
iwram (w!x) : ORIGIN = 0x03000000, LENGTH = 32K iwram (w!x) : ORIGIN = 0x03000000, LENGTH = 32K

View file

@ -4,6 +4,9 @@ OUTPUT_ARCH(arm)
ENTRY(__start) ENTRY(__start)
EXTERN(__RUST_INTERRUPT_HANDLER) EXTERN(__RUST_INTERRUPT_HANDLER)
EXTERN(__agbabi_memset)
EXTERN(__agbabi_memcpy)
MEMORY { MEMORY {
ewram (w!x) : ORIGIN = 0x02000000, LENGTH = 256K ewram (w!x) : ORIGIN = 0x02000000, LENGTH = 256K
iwram (w!x) : ORIGIN = 0x03000000, LENGTH = 32K iwram (w!x) : ORIGIN = 0x03000000, LENGTH = 32K