From 3181653d9221d0653e552c530b5ac3c59eedc4ee Mon Sep 17 00:00:00 2001 From: Hojun-Cho Date: Mon, 22 Jul 2024 21:36:18 +0900 Subject: [PATCH] replace coroutine to setjmp --- Makefile | 11 +- co/Makefile | 15 --- co/README.md | 2 - co/channel.c | 356 -------------------------------------------------- co/qlock.c | 60 --------- co/rendez.c | 54 -------- co/task.c | 253 ----------------------------------- co/task.h | 138 ------------------- co/taskimpl.h | 44 ------- gb.c | 7 +- gb.h | 8 +- jmp.S | 30 +++++ ppu.c | 32 ++++- 13 files changed, 67 insertions(+), 943 deletions(-) delete mode 100644 co/Makefile delete mode 100644 co/README.md delete mode 100644 co/channel.c delete mode 100644 co/qlock.c delete mode 100644 co/rendez.c delete mode 100644 co/task.c delete mode 100644 co/task.h delete mode 100644 co/taskimpl.h create mode 100644 jmp.S diff --git a/Makefile b/Makefile index 0f2718a..7b8ffb5 100644 --- a/Makefile +++ b/Makefile @@ -1,18 +1,11 @@ CC=tcc CFLAGS= -c -Wall -g -Wextra -SRC:=$(wildcard *.c) -OBJ:=$(SRC:.c=.o) all: gb clean: - make clean -C co/ - rm -f $(OBJ) + rm -f *.o rm -f gb -%.o: %.c gb.h - $(CC) $(CFLAGS) -o $@ $< - gb: $(OBJ) - make all -C co/ - $(CC) co/*.o *.o -lucontext -lSDL2 -g -o gb + $(CC) jmp.S *.c -lSDL2 -o gb diff --git a/co/Makefile b/co/Makefile deleted file mode 100644 index 5465741..0000000 --- a/co/Makefile +++ /dev/null @@ -1,15 +0,0 @@ -CC=tcc -CFLAGS= -c -Wall -g -SRC:=$(wildcard *.c) -OBJ:=$(SRC:.c=.o) - -all: co - -clean: - rm -f $(OBJ) - -%.o: %.c - $(CC) $(CFLAGS) -o $@ $< - -co: $(OBJ) - diff --git a/co/README.md b/co/README.md deleted file mode 100644 index 97ec956..0000000 --- a/co/README.md +++ /dev/null @@ -1,2 +0,0 @@ -# coroutine library - https://github.com/Hojun-Cho/coroutine diff --git a/co/channel.c b/co/channel.c deleted file mode 100644 index aefbc02..0000000 --- a/co/channel.c +++ /dev/null @@ -1,356 +0,0 @@ -#include "taskimpl.h" - -Channel* -newchan(int elemsize, int bufsize) -{ - Channel* c; - - c = malloc(sizeof *c + bufsize * elemsize); - if (c == 0) { - exit(1); - } - *c = (Channel){ - .elemsize = elemsize, - .bufsize = bufsize, - .nbuf = 0, - .buf = (uchar*)&c[1], - }; - return c; -} - -void -deletechan(Channel* c) -{ - if (c == 0) - return; - free(c->name); - free(c->asend.a); - free(c->arecv.a); - free(c); -} - -static void -addarray(Altarray* a, Alt* alt) -{ - if (a->n == a->m) { - a->m += 16; - a->a = realloc(a->a, a->m * sizeof a->a[0]); - if (a->a == nil) { - exit(1); - } - } - a->a[a->n++] = alt; -} - -static void -amove(void* dst, void* src, uint n) -{ - if (dst) { - if (src == nil) - memset(dst, 0, n); - else - memmove(dst, src, n); - } -} - -static void -delarray(Altarray* a, int i) -{ - --a->n; - a->a[i] = a->a[a->n]; -} - -static enum chan_op -otherop(enum chan_op op) -{ - return (CHANSND + CHANRCV) - op; -} - -static Altarray* -chanarray(Channel* c, enum chan_op op) -{ - switch (op) { - default: - return nil; - case CHANSND: - return &c->asend; - case CHANRCV: - return &c->arecv; - } -} - -/* - * 3 players: sender, reciver, 'channel itself' - * if chann.empty - * send(send to reciver); - */ -static void -altcopy(Alt* s, Alt* r) -{ - Channel* c; - uchar* cp; - - if (s == nil && r == nil) - return; - assert(s != nil); /* sender must not nil */ - c = s->c; - if (s->op == CHANRCV) { - Alt* t = s; - s = r; - r = t; - } - assert(s == nil || s->op == CHANSND); /* sender */ - assert(r == nil || r->op == CHANRCV); /* reciver */ - - /* Channel is unbufferd */ - if (s && r && c->nbuf == 0) { - amove(r->v, s->v, c->elemsize); - return; - } - if (r) { - /* recive buffred data first */ - cp = c->buf + c->off * c->elemsize; - amove(r->v, cp, c->elemsize); - --c->nbuf; - if (++c->off == c->bufsize) - c->off = 0; - } - if (s) { - cp = c->buf + (c->off + c->nbuf) % c->bufsize * c->elemsize; - amove(cp, s->v, c->elemsize); - ++c->nbuf; - } -} - -static void -altdeque(Alt* a) -{ - Altarray* ar; - - ar = chanarray(a->c, a->op); - if (ar == nil) { - exit(1); - } - - for (uint i = 0; i < ar->n; ++i) { - if (ar->a[i] == a) { - delarray(ar, i); - return; - } - } - /* can't find self in altdq */ - exit(1); -} - -static void -altqueue(Alt* a) -{ - Altarray* ar; - - ar = chanarray(a->c, a->op); - addarray(ar, a); -} - -static void -altalldeque(Alt* a) -{ - for (int i = 0; a[i].op != CHANEND && a[i].op != CHANNOBLK; i++) { - if (a[i].op != CHANNOP) - altdeque(&a[i]); - } -} - -static void -altexec(Alt* a) -{ - Altarray* ar; - Channel* c; - - c = a->c; - ar = chanarray(c, otherop(a->op)); - if (ar && ar->n) { - int i = rand() % ar->n; /* find any other palyer */ - Alt* other = ar->a[i]; - altcopy(a, other); /* copy data to other's buffer */ - altalldeque(other->xalt); /* delete because now request is completed */ - other->xalt[0].xalt = other; - taskready(other->task); - } else - altcopy(a, nil); /* if channel is unbufferd then do nothing */ -} - -static int -altcanexec(Alt* a) -{ - Channel* c; - - if (a->op == CHANNOP) - return 0; - c = a->c; - if (c->bufsize == 0) { - Altarray* ar = chanarray(c, otherop(a->op)); - return ar && ar->n; - } - switch (a->op) { - default: - return 0; - case CHANSND: - return c->nbuf < c->bufsize; - case CHANRCV: - return c->nbuf > 0; - } -} - -int -chanalt(Alt* a) -{ - int i, j, ncan, n, canblock; - Task* t; - - assertstack(512); - for (i = 0; a[i].op != CHANEND && a[i].op != CHANNOBLK; ++i) - ; - n = i; - canblock = (a[i].op == CHANEND); - t = taskrunning; - for (i = 0; i < n; ++i) { - a[i].task = t; - a[i].xalt = a; - } - ncan = 0; - for (i = 0; i < n; i++) { - if (altcanexec(&a[i])) { - ncan++; - } - } - if (ncan) { - j = rand() % ncan; - for (i = 0; i < n; ++i) { - if (altcanexec(&a[i])) { - if (j-- == 0) { - altexec(&a[i]); - return i; - } - } - } - } - if (canblock == 0) - return -1; - for (i = 0; i < n; ++i) { - if (a[i].op != CHANNOP) - altqueue(&a[i]); - } - taskswitch(); - return a[0].xalt - a; /* calculate offset */ -} - -static int -_chanop(Channel* c, int op, void* p, int canblock) -{ - Alt ar[2]; - - ar[0] = (Alt){ - .c = c, - .op = op, - .v = p, - }; - ar[1] = (Alt){ - .op = canblock ? CHANEND : CHANNOBLK, - }; - if (chanalt(ar) < 0) - return -1; - return 1; -} - -int -chansend(Channel* c, void* v) -{ - return _chanop(c, CHANSND, v, 1); -} - -int -chanbsend(Channel* c, void* v) -{ - return _chanop(c, CHANSND, v, 0); -} - -int -chanrecv(Channel* c, void* v) -{ - return _chanop(c, CHANRCV, v, 1); -} - -int -chanbrecv(Channel* c, void* v) -{ - return _chanop(c, CHANSND, v, 0); -} - -int -chansendp(Channel* c, void* v) -{ - return _chanop(c, CHANSND, &v, 1); -} - -void* -chanrecvp(Channel* c) -{ - void* v; - - _chanop(c, CHANRCV, &v, 1); - return v; -} - -int -channbsendp(Channel* c, void* v) -{ - return _chanop(c, CHANSND, (void*)&v, 0); -} - -void* -channbrecvp(Channel* c) -{ - void* v; - - _chanop(c, CHANRCV, &v, 0); - return v; -} - -int -chansendul(Channel* c, ulong v) -{ - return _chanop(c, CHANSND, &v, 1); -} - -ulong -chanrecvul(Channel* c) -{ - ulong v; - - _chanop(c, CHANRCV, &v, 1); - return v; -} - -int -channbsendul(Channel* c, ulong v) -{ - return _chanop(c, CHANSND, &v, 0); -} - -int -channbrecvul(Channel* c, ulong v) -{ - return _chanop(c, CHANRCV, &v, 0); -} - -int -channbsend(Channel* c, void* v) -{ - return _chanop(c, CHANSND, v, 0); -} - -int -channbrecv(Channel* c, void* v) -{ - return _chanop(c, CHANRCV, v, 0); -} diff --git a/co/qlock.c b/co/qlock.c deleted file mode 100644 index 974005e..0000000 --- a/co/qlock.c +++ /dev/null @@ -1,60 +0,0 @@ -#include "taskimpl.h" - -int -_qlock(QLock* l, int block) -{ - if (l->owner == nil) { - l->owner = taskrunning; - return 1; - } - if (!block) - return 0; - addtask(&l->waiting, taskrunning); - taskswitch(); /* wait until own lock */ - if (l->owner != taskrunning) { - /* TODO: */ - exit(1); - } - return 1; -} - -void -qlock(QLock* l) -{ - _qlock(l, 1); -} - -int -canqlock(QLock* l) -{ - return _qlock(l, 0); -} - -void -qunlock(QLock* l) -{ - Task* ready; - - if (l->owner == nil) { - /* TODO: */ - exit(1); - } - l->owner = ready = l->waiting.head; - if (l->owner != nil) { - deltask(&l->waiting, ready); - taskready(ready); - } -} - -QLock* -newqlock() -{ - QLock* l; - - l = malloc(sizeof *l); - if (l == nil) - exit(1); - l->owner = 0; - l->waiting = (Tasklist){ 0 }; - return l; -} diff --git a/co/rendez.c b/co/rendez.c deleted file mode 100644 index cea53fe..0000000 --- a/co/rendez.c +++ /dev/null @@ -1,54 +0,0 @@ -#include "taskimpl.h" - -void -tasksleep(Rendez* r) -{ - addtask(&r->waiting, taskrunning); - if (r->l) - qunlock(r->l); - taskswitch(); - if (r->l) - qlock(r->l); -} - -static int -_taskwakeup(Rendez* r, int all) -{ - int i; - Task* t; - - for (i = 0;; ++i) { - if (i == 1 && !all) - break; - if ((t = r->waiting.head) == nil) - break; - deltask(&r->waiting, t); - taskready(t); - } - return i; -} - -int -taskwakeup(Rendez* r) -{ - return _taskwakeup(r, 0); -} - -int -taskwakeupall(Rendez* r) -{ - return _taskwakeup(r, 1); -} - -Rendez* -newrendez(QLock* l) -{ - Rendez* r; - - r = malloc(sizeof *r); - if (r == nil) - exit(1); - r->l = l; - r->waiting = (Tasklist){ 0 }; - return r; -} diff --git a/co/task.c b/co/task.c deleted file mode 100644 index 6688461..0000000 --- a/co/task.c +++ /dev/null @@ -1,253 +0,0 @@ -#include "taskimpl.h" -#include - -int taskcount; -int taskidgen; -int tasknswitch; -int taskexitval; - -Task* taskrunning; -ucontext_t taskschedcontext; -Tasklist taskrunqueue; -Task** alltask; -int nalltask; - -static void -contextswitch(ucontext_t* from, ucontext_t* to); -void -assertstack(uint n); - -static void -taskinfo(int s) -{ - int i; - Task* t; - char* extra; - - for (i = 0; i < nalltask; ++i) { - t = alltask[i]; - if (t == taskrunning) - extra = " (running)"; - else if (t->ready) - extra = " (ready)"; - else - extra = ""; - printf("%s\n", extra); - } -} - -static void -taskstart(uint x, uint y) -{ - Task* t; - ulong z; - - z = x << 16; - z <<= 16; - z |= y; - t = (Task*)z; - t->startfn(t->startarg); - taskexit(0); -} - -static Task* -taskalloc(void (*fn)(void*), void* arg, uint stk) -{ - Task* t; - sigset_t zero; - uint x, y; - ulong z; - - if ((t = malloc(sizeof *t + stk)) == nil) { - exit(1); - } - *t = (Task){ - .stk = (uchar*)(&t[1]), - .stksize = stk, - .id = ++taskidgen, - .startfn = fn, - .startarg = arg, - }; - sigemptyset(&zero); - sigprocmask(SIG_BLOCK, &zero, &t->uc.uc_sigmask); - if (getcontext(&t->uc)) { - exit(1); - } - t->uc.uc_stack.ss_sp = t->stk + 8; - t->uc.uc_stack.ss_size = t->stksize - 64; - - z = (ulong)t; - y = z; - z >>= 16; - x = z >> 16; - makecontext(&t->uc, (void (*)())taskstart, 2, x, y); - return t; -} - -int -taskcreate(void (*fn)(void*), void* arg, uint stk) -{ - int id; - Task* t; - - t = taskalloc(fn, arg, stk); - taskcount++; - id = t->id; - if (nalltask % 64 == 0) { - alltask = realloc(alltask, (nalltask + 64) * sizeof(alltask[0])); - if (alltask == 0) { - exit(1); - } - } - t->alltaskslot = nalltask; - alltask[nalltask++] = t; - taskready(t); - return id; -} - -void -taskready(Task* t) -{ - t->ready = 1; - addtask(&taskrunqueue, t); -} - -void -taskswitch(void) -{ - assertstack(0); - contextswitch(&taskrunning->uc, &taskschedcontext); -} - -int -taskyield(void) -{ - int n; - - n = tasknswitch; - taskready(taskrunning); - taskswitch(); - return tasknswitch - n - 1; -} - -void -taskexit(int val) -{ - taskexitval = val; - taskrunning->exiting = 1; - taskswitch(); -} - -void -taskexitall(int val) -{ - exit(val); -} - -void -deltask(Tasklist* l, Task* t) -{ - if (t->prev) - t->prev->next = t->next; - else - l->head = t->next; - if (t->next) - t->next->prev = t->prev; - else - l->tail = t->prev; -} - -void -addtask(Tasklist* l, Task* t) -{ - if (l->tail) { - l->tail->next = t; - t->prev = l->tail; - } else { - l->head = t; - t->prev = nil; - } - l->tail = t; - t->next = nil; -} - -static void -contextswitch(ucontext_t* from, ucontext_t* to) -{ - if (swapcontext(from, to) < 0) { - printf("swapcontext is fail\n"); - exit(1); - } -} - -void -assertstack(uint n) -{ - Task* t; - - t = taskrunning; - if ((uchar*)&t <= (uchar*)t->stk || (uchar*)&t - (uchar*)t->stk < 256 + n) { - /* satck over flow */ - exit(1); - } -} - -static void -taskscheduler(void) -{ - int i; - Task* t; - - for (;;) { - if (taskcount == 0) - exit(taskexitval); - t = taskrunqueue.head; - if (t == nil) { - /* nothing to do */ - exit(1); - } - deltask(&taskrunqueue, t); /* delete from runqueue */ - t->ready = 0; - taskrunning = t; - tasknswitch++; - contextswitch(&taskschedcontext, &t->uc); - taskrunning = nil; /* ready for next task */ - if (t->exiting) { - taskcount--; - i = t->alltaskslot; - alltask[i] = alltask[--nalltask]; - alltask[i]->alltaskslot = i; - free(t); - } - } -} - -static char* argv0; -static int taskargc; -static char** taskargv; -int mainstacksize; - -static void -taskmainstart(void* v) -{ - taskmain(taskargc, taskargv); -} - -int -main(int argc, char** argv) -{ - struct sigaction sa, osa; - - memset(&sa, 0, sizeof(sigaction)); - sa.sa_handler = taskinfo; - sa.sa_flags = SA_RESTART; - sigaction(SIGQUIT, &sa, &osa); - /*sigaction(SIGINFO, &sa, &osa);*/ - argv0 = argv[0]; - taskargc = argc; - taskargv = argv; - mainstacksize = 256 * 1024; - taskcreate(taskmainstart, nil, mainstacksize); - taskscheduler(); - exit(0); -} diff --git a/co/task.h b/co/task.h deleted file mode 100644 index ca24745..0000000 --- a/co/task.h +++ /dev/null @@ -1,138 +0,0 @@ -#ifndef _TASK_H_ -#define _TASK_H_ - -typedef struct Task Task; -typedef struct Tasklist Tasklist; - -struct Tasklist -{ - Task* head; - Task* tail; -}; - -typedef struct QLock -{ - Task* owner; - Tasklist waiting; -} QLock; - -void -taskmain(int argc, char** argv); -int -taskyield(void); -void -taskexitall(int val); -int -taskcreate(void (*fn)(void*), void* arg, unsigned int stk); -void -taskready(Task* t); -void -taskexit(int val); -void -taskswitch(void); -void -assertstack(unsigned int n); - -void -qlock(QLock*); -int -canqlock(QLock*); -void -qunlock(QLock*); -QLock* -newqlock(); - -typedef struct Rendez Rendez; -struct Rendez -{ - QLock* l; - Tasklist waiting; -}; - -void -tasksleep(Rendez*); -int -taskwakeup(Rendez*); -int -taskwakeupall(Rendez*); -Rendez* -newrendez(QLock* l); - -extern Task* taskrunning; -extern int taskcount; - -typedef struct Alt Alt; -typedef struct Altarray Altarray; -typedef struct Channel Channel; - -enum chan_op -{ - CHANEND, - CHANSND, - CHANRCV, - CHANNOP, - CHANNOBLK, -}; - -struct Alt -{ - Channel* c; - void* v; - enum chan_op op; - Task* task; - Alt* xalt; -}; - -struct Altarray -{ - Alt** a; - unsigned int n; - unsigned int m; -}; - -struct Channel -{ - unsigned int bufsize; - unsigned int elemsize; - unsigned char* buf; - unsigned int nbuf; - unsigned int off; - Altarray asend; - Altarray arecv; - char* name; -}; - -Channel* -newchan(int elemsize, int bufsize); -void -deletechan(Channel* c); -int -chansend(Channel* c, void* v); -int -chanbsend(Channel* c, void* v); -int -chanrecv(Channel* c, void* v); -int -chanbrecv(Channel* c, void* v); -int -chansendp(Channel* c, void* v); -void* -chanrecvp(Channel* c); -int -channbsend(Channel* c, void* v); -int -channbsendp(Channel* c, void* v); -void* -channbrecvp(Channel* c); -int -channbrecv(Channel* c, void* v); -int -chansendul(Channel* c, unsigned long v); -unsigned long -chanrecvul(Channel* c); -int -channbsendul(Channel* c, unsigned long v); -int -channbrecvul(Channel* c, unsigned long v); - -#endif diff --git a/co/taskimpl.h b/co/taskimpl.h deleted file mode 100644 index 82bb4e6..0000000 --- a/co/taskimpl.h +++ /dev/null @@ -1,44 +0,0 @@ -#include "task.h" -#include -#include -#include -#include -#include - -#define nil ((void*)0) -#define nelem(x) (sizeof(x) / sizeof((x)[0])) - -typedef unsigned long ulong; -typedef unsigned int uint; -typedef unsigned char uchar; -typedef unsigned long long uvlong; -typedef long long vlong; - -enum -{ - STACK = 8192, -}; - -struct Task -{ - Task* next; - Task* prev; - Task* allnext; - Task* allprev; - ucontext_t uc; - uvlong alarmtime; - uint id; - uchar* stk; - uint stksize; - int exiting; - int alltaskslot; - int ready; - void (*startfn)(void*); - void* startarg; -}; - -void -deltask(Tasklist* l, Task* t); - -void -addtask(Tasklist* l, Task* t); diff --git a/gb.c b/gb.c index 4eda52b..7e54112 100644 --- a/gb.c +++ b/gb.c @@ -1,5 +1,4 @@ #include "gb.h" -#include "co/task.h" #include #include #include @@ -146,8 +145,8 @@ colinit(void) } } -void -taskmain(int argc, char* argv[]) +int +main(int argc, char* argv[]) { loadrom(romname = argv[1]); colinit(); @@ -155,7 +154,7 @@ taskmain(int argc, char* argv[]) initevent(); meminit(); reset(); - taskcreate(pputask, 0, 32768); + ppuinit(); for (;;) { int t = step(); diff --git a/gb.h b/gb.h index bfef481..07101e2 100644 --- a/gb.h +++ b/gb.h @@ -134,6 +134,12 @@ enum enum { NEVENT = 2 }; +enum +{ + REG_RIP = 7, + REG_RSP = 6, +}; + typedef uint8_t u8; typedef uint16_t u16; typedef int8_t i8; @@ -210,7 +216,7 @@ hblanktick(void*); void ppusync(void); void -pputask(void*); +ppuinit(void); /* cpu */ int diff --git a/jmp.S b/jmp.S new file mode 100644 index 0000000..3570205 --- /dev/null +++ b/jmp.S @@ -0,0 +1,30 @@ +.global psetjmp +.type psetjmp,@function +psetjmp: + mov %rbx,(%rdi) /* rdi is jmp_buf, move registers onto it */ + mov %rbp,8(%rdi) + mov %r12,16(%rdi) + mov %r13,24(%rdi) + mov %r14,32(%rdi) + mov %r15,40(%rdi) + lea 8(%rsp),%rdx /* this is our rsp WITHOUT current ret addr */ + mov %rdx,48(%rdi) + mov (%rsp),%rdx /* save return addr ptr for new rip */ + mov %rdx,56(%rdi) + xor %eax,%eax /* always return 0 */ + ret + +.global plongjmp +.type plongjmp,@function +plongjmp: + xor %eax,%eax + cmp $1,%esi /* CF = val ? 0 : 1 */ + adc %esi,%eax /* eax = val + !val */ + mov (%rdi),%rbx /* rdi is the jmp_buf, restore regs from it */ + mov 8(%rdi),%rbp + mov 16(%rdi),%r12 + mov 24(%rdi),%r13 + mov 32(%rdi),%r14 + mov 40(%rdi),%r15 + mov 48(%rdi),%rsp + jmp *56(%rdi) diff --git a/ppu.c b/ppu.c index 0791908..99c8262 100644 --- a/ppu.c +++ b/ppu.c @@ -1,15 +1,17 @@ -#include "co/task.h" #include "gb.h" #include +#define ryield() {if(psetjmp(renderjmp) == 0) plongjmp(mainjmp, 1);} +#define myield() {if(psetjmp(mainjmp) == 0) plongjmp(renderjmp, 1);} #define eat(nc) \ if (cyc <= nc) { \ for (i = 0; i < nc; i++) \ if (--cyc == 0) \ - taskyield(); \ + ryield(); \ } else \ cyc -= nc; +typedef void *jmp_buf[10]; typedef struct sprite sprite; struct sprite { @@ -31,6 +33,7 @@ enum TILSPR = 0x04, }; +jmp_buf mainjmp,renderjmp; u8 ppustate, ppuy, ppuw; u64 hblclock, rendclock; static int cyc, ppux, ppux0; @@ -39,14 +42,19 @@ sprite spr[10], *sprm; Var ppuvars[] = {VAR(ppustate), VAR(ppuy), VAR(hblclock), VAR(rendclock), {nil, 0, 0}}; -void -pputask(void* _) +extern int psetjmp(jmp_buf buf); +extern void plongjmp(jmp_buf buf, int v); + +static void +ppurender(void) { int x, y, i, n, m, win; u16 ta, ca, chr; u8 tile; u32 sr[8], *picp; + ryield(); + for (;;) { eat(6 * 2); m = 168 + (reg[SCX] & 7); @@ -82,7 +90,7 @@ pputask(void* _) if (cyc <= 2 * 8) { for (i = 0; i < 2 * 8; ++i) if (--cyc == 0) - taskyield(); + ryield(); y = ppuy + reg[SCY] << 1 & 14; ta = 0x1800 | reg[LCDC] << 7 & 0x400 | ppuy + reg[SCY] << 2 & 0x3E0 | ta & 0x1F; @@ -108,7 +116,7 @@ pputask(void* _) m = 175 - reg[WX]; goto restart; } - taskyield(); + ryield(); } } @@ -211,7 +219,7 @@ ppusync(void) return; cyc = clock - rendclock; if (cyc != 0) - taskyield(); + myield(); sprites(); rendclock = clock; } @@ -287,3 +295,13 @@ hblanktick(void* _) break; } } + +void +ppuinit(void) +{ + static u8 stk[8192]; + + renderjmp[REG_RSP] = stk + sizeof(stk) - 64; + renderjmp[REG_RIP] = ppurender; + myield(); +}