Created
July 17, 2018 19:47
-
-
Save slembcke/0438c6092109ea1f632c81ca581c495a to your computer and use it in GitHub Desktop.
libnaco: Nano coroutine library for cc65.
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
#ifndef NACO_H | |
#define NACO_H | |
#include <stdint.h> | |
#include <stdlib.h> | |
typedef uintptr_t (*naco_func)(uintptr_t); | |
void naco_init(naco_func func, void *naco_buffer, size_t buffer_size); | |
uintptr_t naco_yield(uintptr_t value); | |
uintptr_t naco_resume(void *naco_buffer, uintptr_t value); | |
#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
; TODO Save CORO_BUFF_PTR so coroutines can call coroutines? | |
.include "zeropage.inc" | |
.macpack generic | |
.import pusha, popa | |
.import pushax, popax | |
.import addysp, subysp | |
; Error handler to call when resuming a coroutine that has finished. | |
.import _exit | |
CORO_ABORT = _exit | |
.zeropage | |
; Pointer to the currently running coroutine. | |
; TODO document buffer layout. | |
CORO_BUFF_PTR: .res 2 | |
.code | |
.proc naco_swap_sp | |
ldy #0 | |
lda (CORO_BUFF_PTR), y | |
ldx sp+0 | |
sta sp+0 | |
txa | |
sta (CORO_BUFF_PTR), y | |
iny | |
lda (CORO_BUFF_PTR), y | |
ldx sp+1 | |
sta sp+1 | |
txa | |
sta (CORO_BUFF_PTR), y | |
rts | |
.endproc | |
.export _naco_init | |
.proc _naco_init ; naco_func func, u8 *naco_buffer, size_t buffer_size -> void | |
func = ptr1 | |
size = sreg | |
; Stash buffer size. | |
sta size+0 | |
stx size+1 | |
; Load the buffer pointer. | |
jsr popax | |
sta CORO_BUFF_PTR+0 | |
stx CORO_BUFF_PTR+1 | |
; Store the end address into the stack pointer. | |
add size+0 | |
ldy #0 | |
sta (CORO_BUFF_PTR), y | |
txa | |
adc size+1 | |
iny | |
sta (CORO_BUFF_PTR), y | |
; Subtract 1 from the function address due to how jsr/ret work. | |
jsr popax | |
sub #1 | |
sta func+0 | |
bcs :+ | |
dex | |
: | |
stx func+1 | |
jsr naco_swap_sp | |
lda func+1 | |
ldx func+0 | |
jsr pushax | |
lda #>(naco_catch - 1) | |
ldx #<(naco_catch - 1) | |
jsr pushax | |
lda #2 | |
tay | |
sta (CORO_BUFF_PTR), y | |
; Restore the stack. | |
jmp naco_swap_sp | |
.endproc | |
.proc naco_finish | |
value = sreg | |
; Pop the resume address from the coroutine stack. | |
jsr popax | |
pha | |
txa | |
pha | |
; Load the return value. | |
lda value+0 | |
ldx value+1 | |
rts | |
.endproc | |
.export _naco_resume | |
.proc _naco_resume ; void *naco_buffer, u16 value -> u16 | |
value = sreg | |
tmp = tmp1 | |
; Save the resume value; | |
sta value+0 | |
stx value+1 | |
jsr popax | |
sta CORO_BUFF_PTR+0 | |
stx CORO_BUFF_PTR+1 | |
; Push the yield address to the caller's stack. | |
pla | |
tax | |
pla | |
jsr pushax | |
jsr naco_swap_sp | |
; Stash the stack register. | |
tsx | |
ldy #2 | |
lda (CORO_BUFF_PTR), y | |
sta tmp | |
ldy #0 | |
: lda (sp), y | |
pha | |
iny | |
cpy tmp | |
bne :- | |
jsr addysp | |
; Save the old stack register value. | |
ldy #2 | |
txa | |
sta (CORO_BUFF_PTR), y | |
jmp naco_finish | |
.endproc | |
.export _naco_yield | |
.proc _naco_yield ; u16 value -> u16 | |
value = sreg | |
; Save the resume value; | |
sta value+0 | |
stx value+1 | |
; Push the resume address onto the coroutine's stack. | |
pla | |
tax | |
pla | |
jsr pushax | |
; Calculate stack offset. -(s - stack_offset) | |
clc | |
tsx | |
txa | |
ldy #2 | |
sbc (CORO_BUFF_PTR), y | |
eor #$FF | |
sta (CORO_BUFF_PTR), y | |
tay | |
jsr subysp | |
: dey | |
pla | |
sta (sp), y | |
cpy #0 | |
bne :- | |
jsr naco_swap_sp | |
jmp naco_finish | |
.endproc | |
.proc naco_catch ; u16 -> u16 | |
value = sreg | |
; Save the resume value; | |
sta value+0 | |
stx value+1 | |
; Push error func. | |
lda #>(CORO_ABORT - 1) | |
ldx #<(CORO_ABORT - 1) | |
jsr pushax | |
; Zero out the stack offset. | |
lda #0 | |
ldy #2 | |
sta (CORO_BUFF_PTR), y | |
jsr naco_swap_sp | |
jmp naco_finish | |
.endproc |
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
#include <stdlib.h> | |
#include <stdio.h> | |
#include "naco.h" | |
void func2(uintptr_t n){ | |
n = naco_yield(n); | |
n = naco_yield(n); | |
} | |
uintptr_t func(uintptr_t n){ | |
n = naco_yield(n); | |
n = naco_yield(n); | |
func2(n); | |
n = naco_yield(n); | |
n = naco_yield(n); | |
return 0; | |
} | |
uint8_t buff[64]; | |
int main(void){ | |
static uintptr_t n; | |
naco_init(func, buff, sizeof(buff)); | |
for(n = 1; n < 20; ++n){ | |
uintptr_t value; | |
value = naco_resume(buff, n); | |
printf("main() n: %d, value: %d\n", n, value); | |
if(value == 0) break; | |
} | |
return EXIT_SUCCESS; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment