Created
October 22, 2025 21:37
-
-
Save velipso/33db98706e863776471dbf207011d578 to your computer and use it in GitHub Desktop.
GBA coroutine library
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| // | |
| // 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