Skip to content

Instantly share code, notes, and snippets.

@velipso
Created October 22, 2025 21:37
Show Gist options
  • Select an option

  • Save velipso/33db98706e863776471dbf207011d578 to your computer and use it in GitHub Desktop.

Select an option

Save velipso/33db98706e863776471dbf207011d578 to your computer and use it in GitHub Desktop.
GBA coroutine library
//
// Coroutine API:
//
// static int my_function(coroutine_t *c, int A) {
// // A=123
// int C = coroutine_yield(c, 456); // sends B=456
// // C=789
// return 555; // finishes coroutine, sends D=555
// }
//
// int main() {
// coroutine_t c;
// int stack[100];
// coroutine_create(&c, my_function, stack, sizeof(stack));
// // c.active is false
// int B = coroutine_resume(&c, 123); // <- starts coroutine, sends A=123
// // c.active is true, B=456
// int D = coroutine_resume(&c, 789); // <- resume coroutine, sends C=789
// // c.active is false, D=555
// // the coroutine can be restarted by calling coroutine_resume again
// return 0;
// }
//
typedef struct {
unsigned int active : 1;
unsigned int sp : 31;
} coroutine_t;
typedef int (*coroutine_func)(coroutine_t *c, int user);
void coroutine_create(coroutine_t *c, coroutine_func f_routine, int *stack, size_t size);
int coroutine_resume(coroutine_t *c, int user);
int coroutine_yield(coroutine_t *c, int user);
//
// ASSEMBLY:
//
.section .iwram, "ax"
.global coroutine_create
.global coroutine_resume
.global coroutine_yield
.cpu arm7tdmi
.arm
coroutine_create: // (coroutine_t *c, coroutine_func f_routine, int *stack, size_t size)
add r2, r2, r3
bic r2, r2, #7 // align
sub r2, r2, #8
str r2, [r0]
str r0, [r2]
str r1, [r2, #4]
bx lr
coroutine_resume: // (coroutine_t *c, int user);
ldr r2, [r0]
tst r2, #1
beq 1f
bic r2, r2, #1
// resuming an active coroutine
push {r4-r11, lr}
str sp, [r0]
mov sp, r2
pop {r4-r11, lr}
mov r0, r1
bx lr
1: // starting a new coroutine
push {r4-r11, lr}
str sp, [r0]
mov sp, r2
ldr r3, [r2, #4] // fetch f_routine
adr lr, coroutine_return
bx r3
coroutine_return:
ldr r1, [sp]
ldr r2, [r1]
str sp, [r1]
mov sp, r2
pop {r4-r11, lr}
bx lr
coroutine_yield: // (coroutine_t *c, int user)
push {r4-r11, lr}
orr r2, sp, #1
ldr sp, [r0]
str r2, [r0]
pop {r4-r11, lr}
mov r0, r1
bx lr
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment