agb 0.15.0

Library for Game Boy Advance Development
Documentation
/*
===============================================================================
 ABI:
    __aeabi_memcpy, __aeabi_memcpy4, __aeabi_memcpy8
 Standard:
    memcpy
 Support:
    __agbabi_memcpy2, __agbabi_memcpy1
 Copyright (C) 2021-2022 agbabi contributors
 For conditions of distribution and use, see copyright notice in LICENSE.md
===============================================================================
*/

.include "src/agbabi/macros.inc"

    .arm
    .align 2

    .section .iwram.__aeabi_memcpy, "ax", %progbits
    .global __agbabi_memcpy
__agbabi_memcpy:
    .global __aeabi_memcpy
__aeabi_memcpy:
    // >6-bytes is roughly the threshold when byte-by-byte copy is slower
    cmp     r2, #6
    ble     __agbabi_memcpy1

    align_switch r0, r1, r3, __agbabi_memcpy1, .Lcopy_halves

    // Check if r0 (or r1) needs word aligning
    rsbs    r3, r0, #4
    joaobapt_test r3

    // Copy byte head to align
    ldrmib  r3, [r1], #1
    strmib  r3, [r0], #1
    submi   r2, r2, #1
    // r0, r1 are now half aligned

    // Copy half head to align
    ldrcsh  r3, [r1], #2
    strcsh  r3, [r0], #2
    subcs   r2, r2, #2
    // r0, r1 are now word aligned

    .global __aeabi_memcpy8
__aeabi_memcpy8:
    .global __aeabi_memcpy4
__aeabi_memcpy4:
    cmp     r2, #32
    blt     .Lcopy_words

    // Word aligned, 32-byte copy
    push    {r4-r10}
.Lloop_32:
    subs    r2, r2, #32
    ldmgeia r1!, {r3-r10}
    stmgeia r0!, {r3-r10}
    bgt     .Lloop_32
    pop     {r4-r10}
    bxeq    lr

    // < 32 bytes remaining to be copied
    add     r2, r2, #32

.Lcopy_words:
    cmp     r2, #4
    blt     .Lcopy_halves
.Lloop_4:
    subs    r2, r2, #4
    ldrge   r3, [r1], #4
    strge   r3, [r0], #4
    bgt     .Lloop_4
    bxeq    lr

    // Copy byte & half tail
    // This test still works when r2 is negative
    joaobapt_test r2
    // Copy half
    ldrcsh  r3, [r1], #2
    strcsh  r3, [r0], #2
    // Copy byte
    ldrmib  r3, [r1]
    strmib  r3, [r0]
    bx      lr

.Lcopy_halves:
    // Copy byte head to align
    tst     r0, #1
    ldrneb  r3, [r1], #1
    strneb  r3, [r0], #1
    subne   r2, r2, #1
    // r0, r1 are now half aligned

    .global __agbabi_memcpy2
__agbabi_memcpy2:
    subs    r2, r2, #2
    ldrgeh  r3, [r1], #2
    strgeh  r3, [r0], #2
    bgt     __agbabi_memcpy2
    bxeq    lr

    // Copy byte tail
    adds    r2, r2, #1
    ldreqb  r3, [r1]
    streqb  r3, [r0]
    bx      lr

    .global __agbabi_memcpy1
__agbabi_memcpy1:
    subs    r2, r2, #1
    ldrgeb  r3, [r1], #1
    strgeb  r3, [r0], #1
    bgt     __agbabi_memcpy1
    bx      lr

    .section .iwram.memcpy, "ax", %progbits
    .global memcpy
memcpy:
    push    {r0, lr}
    bl      __aeabi_memcpy
    pop     {r0, lr}
    bx      lr