-
Notifications
You must be signed in to change notification settings - Fork 5
libagbabi
libagbabi provides GBA optimized functions for some common, handy operations.
It was originally created as an optional utility library for gba-toolchain projects, where it is still available with the CMake function gba_target_link_agb_abi.
The library
Replaces the GNU arm-eabi signed integer division/modulo with a fast, IWRAM, ARM assembly optimized division.
This is faster than the default GNU division operator for several reasons, but it is also faster than the BIOS provided division functions (Div, DivArm).
__aeabi_idiv is an alias for __aeabi_idivmod.
signed int a, b;
signed int c = a % b; // Replaces the modulo operator
c = __aeabi_idivmod( a, b ); // Performs a division, leaving modulo in r1Replaces the GNU arm-eabi unsigned integer division/modulo with a fast, IWRAM, ARM assembly optimized division.
This is faster than the default GNU division operator for several reasons, but it is also faster than the BIOS provided division functions (Div, DivArm).
__aeabi_uidiv is an alias for __aeabi_uidivmod.
unsigned int a, b;
unsigned int c = a % b; // Replaces the modulo operator
c = __aeabi_uidivmod( a, b ); // Performs a division, leaving modulo in r1The same as __aeabi_uidivmod, but after a divide-by-zero check.
It is entirely up to the caller to protect against divide-by-zero.
unsigned int a, b;
unsigned int c = a % b; // Replaces the modulo operator
c = __agbabi_unsafe_uidiv( a, b ); // Performs a division, leaving modulo in r1An empty IRQ implementation that acknowledges any raised IRQs and returns.
This is useful if you don't want an IRQ handler, but still want to use BIOS functions that require IRQs to be acknowledged, such as the BIOS halt functions.
typedef void( * handler_t )( void );
*( volatile handler_t * )0x03007FFC = __agbabi_irq_empty;IRQ implementation that further calls a function pointed to by __agbabi_irq_uproc.
This IRQ calls __agbabi_irq_uproc in CPU user-mode with the raise IRQs disabled and IME disabled. IME can be re-enabled to allow nested IRQs.
void my_handler( int );
typedef void( * handler_t )( void );
*( volatile handler_t * )0x03007FFC = __agbabi_irq_user;
__agbabi_irq_uproc = my_handler;Used by __agbabi_irq_user.
__agbabi_irq_uproc has the raised IRQ flags passed to it, allowing for the implementing IRQ handling switchboards.
void my_handler( int irqFlags ) {
if ( irqFlags & 1 ) {
// Handle VBlank
}
}
__agbabi_irq_uproc = my_handler;
typedef void( * handler_t )( void );
*( volatile handler_t * )0x03007FFC = __agbabi_irq_user;Partial implementation of UNIX-like getcontext.
#include <sys/ucontext.h>
ucontext_t ctx;
__agbabi_getcontext( &ctx );Partial implementation of UNIX-like setcontext.
#include <sys/ucontext.h>
ucontext_t ctx;
__agbabi_getcontext( &ctx );
// Other stuff
__agbabi_setcontext( &ctx ); // Returns up to where __agbabi_getcontext was calledPartial implementation of UNIX-like makecontext.
#include <sys/ucontext.h>
void my_context_function( int a, int b ) {}
static int ctx_stack[200] {};
ucontext_t link_ctx;
ucontext_t ctx;
ctx.uc_stack.ss_sp = ctx_stack;
ctx.uc_stack.ss_size = sizeof( ctx_stack );
ctx.uc_link = &link_ctx;
__agbabi_makecontext( &ctx, my_context_function, 2, 3, 6 ); // Create context that calls my_context_function with args 3 and 6Partial implementation of UNIX-like swapcontext.
#include <sys/ucontext.h>
void my_context_function() {}
static int ctx_stack[200] {};
ucontext_t link_ctx;
ucontext_t ctx;
ctx.uc_stack.ss_sp = ctx_stack;
ctx.uc_stack.ss_size = sizeof( ctx_stack );
ctx.uc_link = &link_ctx;
__agbabi_makecontext( &ctx, my_context_function, 0 );
__agbabi_swapcontext( &link_ctx, &ctx ); // Swap from link_ctx to ctxAssigned to the stored context's link register by __agbabi_makecontext. Used to return to the parent context.
Not recommended to ever call directly.