Last active
March 15, 2023 00:11
-
-
Save JoaoBaptMG/82d3eab16a24cbad072ed57b9198131f to your computer and use it in GitHub Desktop.
Simple context switching subroutines for ARMv4 and possibly other platforms
This file contains 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
//---------------------------------------------------------------------------- | |
// context.h | |
//---------------------------------------------------------------------------- | |
// Provides an API for context switching (a primitive form of coroutines) | |
//---------------------------------------------------------------------------- | |
// Copyright 2023 João Baptista de Paula e Silva | |
// | |
// 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. | |
//---------------------------------------------------------------------------- | |
#pragma once | |
#ifdef __cplusplus | |
extern "C" | |
{ | |
#endif | |
// An opaque pointer (but deeply, nothing more than the sp of that context) | |
typedef struct __context* context_t; | |
// The context entry point, for beginning questions | |
typedef context_t (*context_entry_point_t)(context_t ctx, void* arg); | |
// Gives up ownership and switches to another context. This function will | |
// "wake up" the other context and, when this context is switched to again, | |
// the function will return with a new context | |
context_t context_switch(context_t ctx) IWRAM_CODE; | |
// All stack pointers must be aligned by 8 bytes | |
#define STACKPTR __attribute__((aligned(8))) | |
void ctx_entry_point() IWRAM_CODE; | |
// The stack layout after a context switch is | |
// (from the sp pointed by context_t) r4 r5 r6 r7 r8 r9 r10 r11 lr | |
// And ctx_entry_point will expect you to pass the entry point too. | |
// So this routine sets it to 8*(undefined) ctx_entry_point arg entry | |
inline static context_t context_new(void* stack_top, context_entry_point_t entry, void* arg) | |
{ | |
// Set up the stack | |
unsigned int* stack = (unsigned int*)stack_top; | |
stack[-1] = (unsigned int)entry; | |
stack[-2] = (unsigned int)arg; | |
stack[-3] = (unsigned int)&ctx_entry_point; | |
// Return the correct pointer | |
return (context_t)(stack-11); | |
} | |
#ifdef __cplusplus | |
} | |
#endif |
This file contains 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
@---------------------------------------------------------------------------- | |
@ context.s | |
@---------------------------------------------------------------------------- | |
@ Provides an API for context switching (a primitive form of coroutines) | |
@---------------------------------------------------------------------------- | |
@ 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. | |
@---------------------------------------------------------------------------- | |
@ context_t context_switch(context_t ctx) | |
@ switches to the context ctx, returning the original context on the other side | |
@ ctx: r0 | |
.section .iwram, "ax", %progbits | |
.align 2 | |
.arm | |
.global context_switch | |
.type context_switch STT_FUNC | |
context_switch: | |
@ Test first if it is the null pointer or the same register | |
cmp r0, #0 | |
bxeq lr | |
cmp r0, sp | |
bxeq lr | |
push {r4-r11, lr} @ Save the static registers to stack | |
eor r0, sp, r0 @ XOR-swap r0 and the stack pointer | |
eor sp, r0, sp | |
eor r0, sp, r0 | |
pop {r4-r11, lr} @ Restore the static registers and branch | |
bx lr @ popping to pc doesn't work because the T flag is not updated (GBA only) | |
@ ctx_entry_point pops the real entry_point and the first arg from stack | |
.section .iwram, "ax", %progbits | |
.align 2 | |
.arm | |
.global ctx_entry_point | |
.type ctx_entry_point STT_FUNC | |
ctx_entry_point: | |
pop {r1, r2} @ get the entry point for the context | |
mov lr, pc @ "emulate" a bl | |
bx r2 @ jump to the entry point | |
mov sp, r0 @ null out the context pointer | |
mov r0, #0 | |
pop {r4-r11, lr} @ Restore the static registers and branch | |
bx lr |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment