Compare commits
No commits in common. "2a2e2cbc341270e5b50818460d8bdfb5c08fdfe6" and "c8c2a4fc199bb6cd4353f8806ad2c0b7d6eea9da" have entirely different histories.
2a2e2cbc34
...
c8c2a4fc19
2
.gitignore
vendored
2
.gitignore
vendored
@ -6,8 +6,6 @@
|
|||||||
*.ko
|
*.ko
|
||||||
*.obj
|
*.obj
|
||||||
*.elf
|
*.elf
|
||||||
.*.swp
|
|
||||||
*.gb
|
|
||||||
|
|
||||||
# Linker output
|
# Linker output
|
||||||
*.ilk
|
*.ilk
|
||||||
|
|||||||
14
Makefile
14
Makefile
@ -1,10 +1,18 @@
|
|||||||
CFLAGS= -Wall -g
|
CC=tcc
|
||||||
|
CFLAGS= -c -Wall -g -Wextra
|
||||||
|
SRC:=$(wildcard *.c)
|
||||||
|
OBJ:=$(SRC:.c=.o)
|
||||||
|
|
||||||
all: gb
|
all: gb
|
||||||
|
|
||||||
clean:
|
clean:
|
||||||
rm -f *.o
|
make clean -C co/
|
||||||
|
rm -f $(OBJ)
|
||||||
rm -f gb
|
rm -f gb
|
||||||
|
|
||||||
|
%.o: %.c gb.h
|
||||||
|
$(CC) $(CFLAGS) -o $@ $<
|
||||||
|
|
||||||
gb: $(OBJ)
|
gb: $(OBJ)
|
||||||
$(CC) jmp.S *.c -lSDL2 -o gb $(CFLAGS)
|
make all -C co/
|
||||||
|
$(CC) co/*.o *.o -lucontext -lSDL2 -g -o gb
|
||||||
|
|||||||
15
co/Makefile
Normal file
15
co/Makefile
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
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)
|
||||||
|
|
||||||
2
co/README.md
Normal file
2
co/README.md
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
# coroutine library
|
||||||
|
https://github.com/Hojun-Cho/coroutine
|
||||||
356
co/channel.c
Normal file
356
co/channel.c
Normal file
@ -0,0 +1,356 @@
|
|||||||
|
#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);
|
||||||
|
}
|
||||||
60
co/qlock.c
Normal file
60
co/qlock.c
Normal file
@ -0,0 +1,60 @@
|
|||||||
|
#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;
|
||||||
|
}
|
||||||
54
co/rendez.c
Normal file
54
co/rendez.c
Normal file
@ -0,0 +1,54 @@
|
|||||||
|
#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;
|
||||||
|
}
|
||||||
253
co/task.c
Normal file
253
co/task.c
Normal file
@ -0,0 +1,253 @@
|
|||||||
|
#include "taskimpl.h"
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
138
co/task.h
Normal file
138
co/task.h
Normal file
@ -0,0 +1,138 @@
|
|||||||
|
#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
|
||||||
44
co/taskimpl.h
Normal file
44
co/taskimpl.h
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
#include "task.h"
|
||||||
|
#include <assert.h>
|
||||||
|
#include <signal.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <ucontext.h>
|
||||||
|
|
||||||
|
#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);
|
||||||
7
cpu.c
7
cpu.c
@ -1,5 +1,5 @@
|
|||||||
#include "gb.h"
|
#include "gb.h"
|
||||||
#include "print.h"
|
#include <stdio.h>
|
||||||
|
|
||||||
#define BC() ((u16)r[rB] << 8 | r[rC])
|
#define BC() ((u16)r[rB] << 8 | r[rC])
|
||||||
#define DE() ((u16)r[rD] << 8 | r[rE])
|
#define DE() ((u16)r[rD] << 8 | r[rE])
|
||||||
@ -30,13 +30,10 @@ u8 r[8], ime;
|
|||||||
u16 pc, sp, curpc;
|
u16 pc, sp, curpc;
|
||||||
int halt;
|
int halt;
|
||||||
|
|
||||||
Var cpuvars[] = {ARR(r), VAR(ime), VAR(pc), VAR(curpc), VAR(sp), VAR(halt),
|
|
||||||
{nil, 0, 0}};
|
|
||||||
|
|
||||||
void
|
void
|
||||||
state(void)
|
state(void)
|
||||||
{
|
{
|
||||||
print("A:%02X F:%02X B:%02X C:%02X D:%02X E:%02X H:%02X L:%02X SP:%04X "
|
printf("A:%02X F:%02X B:%02X C:%02X D:%02X E:%02X H:%02X L:%02X SP:%04X "
|
||||||
"PC:%04X PCMEM:%02X,%02X,%02X,%02X\n",
|
"PC:%04X PCMEM:%02X,%02X,%02X,%02X\n",
|
||||||
r[rA],
|
r[rA],
|
||||||
r[rF],
|
r[rF],
|
||||||
|
|||||||
19
error.c
19
error.c
@ -1,29 +1,30 @@
|
|||||||
#include "gb.h"
|
#include "gb.h"
|
||||||
#include "print.h"
|
#include <stdarg.h>
|
||||||
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
void
|
void
|
||||||
panic(char* fmt, ...)
|
panic(const char* fmt, ...)
|
||||||
{
|
{
|
||||||
va_list ap;
|
va_list ap;
|
||||||
|
|
||||||
va_start(ap, fmt);
|
va_start(ap, fmt);
|
||||||
fprint(2, "panic:");
|
fprintf(stderr, "panic:");
|
||||||
vfprint(2, fmt, ap);
|
vfprintf(stderr, fmt, ap);
|
||||||
fprint(2, "\n");
|
fprintf(stderr, "\n");
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
error(char* fmt, ...)
|
error(const char* fmt, ...)
|
||||||
{
|
{
|
||||||
va_list ap;
|
va_list ap;
|
||||||
|
|
||||||
va_start(ap, fmt);
|
va_start(ap, fmt);
|
||||||
fprint(2, "panic:");
|
fprintf(stderr, "panic:");
|
||||||
vfprint(2, fmt, ap);
|
vfprintf(stderr, fmt, ap);
|
||||||
fprint(2, "\n");
|
fprintf(stderr, "\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
void*
|
void*
|
||||||
|
|||||||
10
eui.c
10
eui.c
@ -9,7 +9,7 @@ u8* pic;
|
|||||||
SDL_Renderer* renderer;
|
SDL_Renderer* renderer;
|
||||||
SDL_Texture* bitmapTex;
|
SDL_Texture* bitmapTex;
|
||||||
|
|
||||||
void
|
static void
|
||||||
render()
|
render()
|
||||||
{
|
{
|
||||||
SDL_UpdateTexture(bitmapTex, nil, pic, 160 * sizeof(u32));
|
SDL_UpdateTexture(bitmapTex, nil, pic, 160 * sizeof(u32));
|
||||||
@ -29,8 +29,6 @@ joypadevent(void*_)
|
|||||||
case SDL_KEYUP: keys = 0; break;
|
case SDL_KEYUP: keys = 0; break;
|
||||||
case SDL_KEYDOWN:
|
case SDL_KEYDOWN:
|
||||||
switch (evt.key.keysym.scancode) {
|
switch (evt.key.keysym.scancode) {
|
||||||
case SDL_SCANCODE_F1: savereq = 1; break;
|
|
||||||
case SDL_SCANCODE_F2: loadreq = 1; break;
|
|
||||||
case SDL_SCANCODE_X: keys = GB_KEY_A; break;
|
case SDL_SCANCODE_X: keys = GB_KEY_A; break;
|
||||||
case SDL_SCANCODE_Z: keys = GB_KEY_B; break;
|
case SDL_SCANCODE_Z: keys = GB_KEY_B; break;
|
||||||
case SDL_SCANCODE_UP: keys = GB_KEY_UP; break;
|
case SDL_SCANCODE_UP: keys = GB_KEY_UP; break;
|
||||||
@ -47,6 +45,12 @@ joypadevent(void*_)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
flush()
|
||||||
|
{
|
||||||
|
render();
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
initwindow(int scale)
|
initwindow(int scale)
|
||||||
{
|
{
|
||||||
|
|||||||
3
ev.c
3
ev.c
@ -1,11 +1,8 @@
|
|||||||
#include "gb.h"
|
#include "gb.h"
|
||||||
|
|
||||||
Event evhblank, evjoypad;
|
Event evhblank, evjoypad;
|
||||||
Event *events[NEVENT] = {&evhblank, &evjoypad};
|
|
||||||
Event* elist;
|
Event* elist;
|
||||||
|
|
||||||
Var evvars[] = {{nil, 0, 0}};
|
|
||||||
|
|
||||||
void
|
void
|
||||||
addevent(Event* ev, int time)
|
addevent(Event* ev, int time)
|
||||||
{
|
{
|
||||||
|
|||||||
134
gb.c
134
gb.c
@ -1,73 +1,17 @@
|
|||||||
#include "gb.h"
|
#include "gb.h"
|
||||||
#include <stdlib.h>
|
#include "co/task.h"
|
||||||
#include <string.h>
|
#include <stdio.h>
|
||||||
#include <unistd.h>
|
|
||||||
#include <fcntl.h>
|
|
||||||
|
|
||||||
int savereq, loadreq;
|
int cpuhalt;
|
||||||
|
int backup;
|
||||||
int savefd = -1;
|
int savefd = -1;
|
||||||
int saveframes;
|
u64 clock;
|
||||||
const char *romname;
|
u8 mbc, feat, mode;
|
||||||
u8 mbc, mode;
|
|
||||||
|
|
||||||
void
|
|
||||||
writeback(void)
|
|
||||||
{
|
|
||||||
if(saveframes == 0)
|
|
||||||
saveframes = 15;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
flushback(void)
|
|
||||||
{
|
|
||||||
if(savefd >= 0)
|
|
||||||
pwrite(savefd, back, nback, 0);
|
|
||||||
saveframes = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
_flushback(void)
|
|
||||||
{
|
|
||||||
flushback();
|
|
||||||
close(savefd);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
loadsave(const char *file)
|
|
||||||
{
|
|
||||||
u8 *buf, *p;
|
|
||||||
|
|
||||||
buf = xalloc(strlen(file) + 4);
|
|
||||||
strcpy(buf, file);
|
|
||||||
p = strrchr(buf, '.');
|
|
||||||
if(p == nil)
|
|
||||||
p = buf + strlen(buf);
|
|
||||||
strcpy(p, ".sav");
|
|
||||||
savefd = open(buf, O_RDWR);
|
|
||||||
if(savefd == -1){
|
|
||||||
savefd = open(buf, O_RDWR|O_CREAT, 0664);
|
|
||||||
if(savefd == -1)
|
|
||||||
error("Can't load save file '%s'", file);
|
|
||||||
back = xalloc(nback);
|
|
||||||
if(write(savefd, back, nback)!= nback)
|
|
||||||
error("Can't Write %d byte to savefile", nback);
|
|
||||||
atexit(_flushback);
|
|
||||||
free(buf);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
back = xalloc(nback);
|
|
||||||
if(read(savefd, back, nback) != nback)
|
|
||||||
error("savefile size is not matched\n");
|
|
||||||
atexit(_flushback);
|
|
||||||
free(buf);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
static void
|
||||||
loadrom(const char* file)
|
loadrom(const char* file)
|
||||||
{
|
{
|
||||||
int rc;
|
FILE* f;
|
||||||
int feat;
|
|
||||||
int fd;
|
|
||||||
long sz;
|
long sz;
|
||||||
static u8 mbctab[31] = { 0, 1, 1, 1, -1, 2, 2, -1, 0, 0, -1, 6, 6, 6, -1, 3,
|
static u8 mbctab[31] = { 0, 1, 1, 1, -1, 2, 2, -1, 0, 0, -1, 6, 6, 6, -1, 3,
|
||||||
3, 3, 3, 3, -1, 4, 4, 4, -1, 5, 5, 5, 5, 5, 5 };
|
3, 3, 3, 3, -1, 4, 4, 4, -1, 5, 5, 5, 5, 5, 5 };
|
||||||
@ -78,18 +22,19 @@ loadrom(const char* file)
|
|||||||
0, 0, FEATRAM, FEATRAM|FEATBAT, 0, FEATRAM, FEATRAM|FEATBAT,
|
0, 0, FEATRAM, FEATRAM|FEATBAT, 0, FEATRAM, FEATRAM|FEATBAT,
|
||||||
};
|
};
|
||||||
|
|
||||||
fd = open(file, O_RDONLY);
|
f = fopen(file, "r");
|
||||||
if (fd == nil)
|
if (f == nil)
|
||||||
panic("can't open %s", file);
|
panic("can't open %s", file);
|
||||||
sz = lseek(fd, 0, SEEK_END);
|
fseek(f, 0, SEEK_END);
|
||||||
if(sz <= 0 || sz > 32*1024*1024)
|
sz = ftell(f);
|
||||||
panic("invalid file size %d", sz);
|
if (sz < 0 || sz > 32 * 1024 * 1024)
|
||||||
lseek(fd, 0, SEEK_SET);
|
panic("bad size %d", sz);
|
||||||
|
fseek(f, 0, SEEK_SET);
|
||||||
nrom = sz;
|
nrom = sz;
|
||||||
rom = xalloc(nrom);
|
rom = xalloc(nrom);
|
||||||
if((rc = read(fd, rom, nrom)) != nrom)
|
if (fread(rom, 1, nrom, f) != nrom)
|
||||||
panic("rom size is not matched %d\n", rc);
|
panic("siz is different %z", nrom);
|
||||||
close(fd);
|
fclose(f);
|
||||||
if (rom[0x147] > 0x1F)
|
if (rom[0x147] > 0x1F)
|
||||||
panic("bad cartidge type %d\n", rom[0x147]);
|
panic("bad cartidge type %d\n", rom[0x147]);
|
||||||
mbc = mbctab[rom[0x147]];
|
mbc = mbctab[rom[0x147]];
|
||||||
@ -103,6 +48,7 @@ loadrom(const char* file)
|
|||||||
default: panic("Unkown Ram size %d\n", rom[0x149]);
|
default: panic("Unkown Ram size %d\n", rom[0x149]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
back = xalloc(nback);
|
||||||
if(nback == 0)
|
if(nback == 0)
|
||||||
nbackbank = 1;
|
nbackbank = 1;
|
||||||
else
|
else
|
||||||
@ -112,40 +58,18 @@ loadrom(const char* file)
|
|||||||
break;
|
break;
|
||||||
default: panic("unsupported mbc %d", mbc);
|
default: panic("unsupported mbc %d", mbc);
|
||||||
}
|
}
|
||||||
if (rom[0x143] & 0x80 != 0)
|
if ((rom[0x143] & 0x80) != 0 && (mode & FORCEDMG) == 0)
|
||||||
panic("unsupported color");
|
mode = CGB | COL;
|
||||||
if((feat & FEATBAT) != 0)
|
|
||||||
loadsave(file);
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
flush()
|
|
||||||
{
|
|
||||||
static char *savestatename;
|
|
||||||
if (savestatename == 0){
|
|
||||||
int len = strlen(romname);
|
|
||||||
savestatename = xalloc(len + 4);
|
|
||||||
strncpy(savestatename, romname, len);
|
|
||||||
strcpy(savestatename + len, "-state.save");
|
|
||||||
}
|
|
||||||
|
|
||||||
render();
|
|
||||||
if(saveframes > 0 && -- saveframes == 0)
|
|
||||||
flushback();
|
|
||||||
if(savereq){
|
|
||||||
savestate(savestatename);
|
|
||||||
savereq = 0;
|
|
||||||
}
|
|
||||||
if(loadreq){
|
|
||||||
loadstate(savestatename);
|
|
||||||
loadreq = 0;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
colinit(void)
|
colinit(void)
|
||||||
{
|
{
|
||||||
union {u8 c[4]; u32 l;}c;
|
union
|
||||||
|
{
|
||||||
|
u8 c[4];
|
||||||
|
u32 l;
|
||||||
|
} c;
|
||||||
|
|
||||||
c.c[3] = 0;
|
c.c[3] = 0;
|
||||||
for (int i = 0; i < 4; i++) {
|
for (int i = 0; i < 4; i++) {
|
||||||
@ -154,16 +78,16 @@ colinit(void)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
void
|
||||||
main(int argc, char* argv[])
|
taskmain(int argc, char* argv[])
|
||||||
{
|
{
|
||||||
loadrom(romname = argv[1]);
|
|
||||||
colinit();
|
colinit();
|
||||||
|
loadrom(argv[1]);
|
||||||
initwindow(5);
|
initwindow(5);
|
||||||
initevent();
|
initevent();
|
||||||
meminit();
|
meminit();
|
||||||
reset();
|
reset();
|
||||||
ppuinit();
|
taskcreate(pputask, 0, 32768);
|
||||||
|
|
||||||
for (;;) {
|
for (;;) {
|
||||||
int t = step();
|
int t = step();
|
||||||
|
|||||||
51
gb.h
51
gb.h
@ -1,9 +1,5 @@
|
|||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
||||||
#define nelem(x) (sizeof(x)/sizeof(x[0]))
|
|
||||||
|
|
||||||
#define VAR(a) {&a, sizeof(a), 1}
|
|
||||||
#define ARR(a) {a, sizeof(*a), nelem(a)}
|
|
||||||
#define nil ((void*)0)
|
#define nil ((void*)0)
|
||||||
#define JOYPAD_CYCLE (30)
|
#define JOYPAD_CYCLE (30)
|
||||||
|
|
||||||
@ -132,14 +128,6 @@ enum
|
|||||||
GB_KEY_START = 0x80
|
GB_KEY_START = 0x80
|
||||||
};
|
};
|
||||||
|
|
||||||
enum { NEVENT = 2 };
|
|
||||||
|
|
||||||
enum
|
|
||||||
{
|
|
||||||
REG_RIP = 7,
|
|
||||||
REG_RSP = 6,
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef uint8_t u8;
|
typedef uint8_t u8;
|
||||||
typedef uint16_t u16;
|
typedef uint16_t u16;
|
||||||
typedef int8_t i8;
|
typedef int8_t i8;
|
||||||
@ -148,7 +136,6 @@ typedef int32_t i32;
|
|||||||
typedef uint64_t u64;
|
typedef uint64_t u64;
|
||||||
typedef int64_t i64;
|
typedef int64_t i64;
|
||||||
typedef struct Event Event;
|
typedef struct Event Event;
|
||||||
typedef struct Var Var;
|
|
||||||
|
|
||||||
struct Event
|
struct Event
|
||||||
{
|
{
|
||||||
@ -158,15 +145,6 @@ struct Event
|
|||||||
void* aux;
|
void* aux;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct Var
|
|
||||||
{
|
|
||||||
void *a;
|
|
||||||
int s, n;
|
|
||||||
};
|
|
||||||
|
|
||||||
#define VAR(a) {&a, sizeof(a), 1}
|
|
||||||
#define ARR(a) {a, sizeof(*a), nelem(a)}
|
|
||||||
|
|
||||||
extern u8 *rom, *back, reg[256], oam[256];
|
extern u8 *rom, *back, reg[256], oam[256];
|
||||||
extern u8 vram[16384];
|
extern u8 vram[16384];
|
||||||
extern int nrom, nback, nbackbank;
|
extern int nrom, nback, nbackbank;
|
||||||
@ -174,18 +152,17 @@ extern u32 pal[64];
|
|||||||
extern u8 dma;
|
extern u8 dma;
|
||||||
extern u32 divclock;
|
extern u32 divclock;
|
||||||
extern u64 clock;
|
extern u64 clock;
|
||||||
extern u8 ppuy, ppustate;
|
extern u8 ppuy, ppustate, ppuw;
|
||||||
extern u8 keys;
|
extern u8 keys;
|
||||||
extern int prish;
|
extern int prish;
|
||||||
extern u8 mode;
|
extern u8 mode;
|
||||||
extern u8 mbc;
|
extern u8 mbc, feat;
|
||||||
extern Event* elist;
|
extern Event* elist;
|
||||||
extern Event evhblank, evjoypad;
|
extern Event evhblank, evjoypad;
|
||||||
extern u32 moncols[4];
|
extern u32 moncols[4];
|
||||||
|
extern u32 white;
|
||||||
extern u8* pic;
|
extern u8* pic;
|
||||||
extern int (*mapper)(int, int);
|
extern int (*mapper)(int, int);
|
||||||
extern Event *events[NEVENT];
|
|
||||||
extern int savereq, loadreq;
|
|
||||||
|
|
||||||
/* joypad */
|
/* joypad */
|
||||||
void
|
void
|
||||||
@ -215,7 +192,7 @@ hblanktick(void*);
|
|||||||
void
|
void
|
||||||
ppusync(void);
|
ppusync(void);
|
||||||
void
|
void
|
||||||
ppuinit(void);
|
pputask(void*);
|
||||||
|
|
||||||
/* cpu */
|
/* cpu */
|
||||||
int
|
int
|
||||||
@ -225,28 +202,14 @@ reset(void);
|
|||||||
|
|
||||||
/* graphic */
|
/* graphic */
|
||||||
void
|
void
|
||||||
initwindow(int scale);
|
|
||||||
void
|
|
||||||
render();
|
|
||||||
|
|
||||||
/* save */
|
|
||||||
void
|
|
||||||
putvars(Var *v);
|
|
||||||
void
|
|
||||||
getvars(Var *v);
|
|
||||||
void
|
|
||||||
flush();
|
flush();
|
||||||
int
|
|
||||||
savestate(const char *fname);
|
|
||||||
int
|
|
||||||
loadstate(const char *fname);
|
|
||||||
void
|
void
|
||||||
writeback(void);
|
initwindow(int scale);
|
||||||
|
|
||||||
/* error */
|
/* error */
|
||||||
void
|
void
|
||||||
error(char*, ...);
|
error(const char*, ...);
|
||||||
void
|
void
|
||||||
panic(char*, ...);
|
panic(const char*, ...);
|
||||||
void*
|
void*
|
||||||
xalloc(long);
|
xalloc(long);
|
||||||
|
|||||||
30
jmp.S
30
jmp.S
@ -1,30 +0,0 @@
|
|||||||
.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)
|
|
||||||
31
mem.c
31
mem.c
@ -9,18 +9,17 @@ u8* rom;
|
|||||||
u8 *romb, *vramb, *wramb, *eramb;
|
u8 *romb, *vramb, *wramb, *eramb;
|
||||||
u8 wram[32768], vram[16384], oam[256], reg[256];
|
u8 wram[32768], vram[16384], oam[256], reg[256];
|
||||||
u8* back;
|
u8* back;
|
||||||
|
u8 palm[128];
|
||||||
u32 pal[64];
|
u32 pal[64];
|
||||||
int nrom, nback, nbackbank;
|
int nrom, nback, nbackbank;
|
||||||
u64 clock;
|
|
||||||
u32 divclock;
|
u32 divclock;
|
||||||
int prish;
|
int prish;
|
||||||
|
u8 dma;
|
||||||
u32 moncols[4];
|
u32 moncols[4];
|
||||||
u32 white;
|
u32 white;
|
||||||
int (*mappers[])(int, int) = { mbc0, mbc1 };
|
int (*mappers[])(int, int) = { mbc0, mbc1 };
|
||||||
int (*mapper)(int, int);
|
int (*mapper)(int, int);
|
||||||
|
|
||||||
Var memvars[] = {ARR(wram), ARR(vram), ARR(oam), ARR(reg), VAR(clock), VAR(divclock), {nil, 0, 0}};
|
|
||||||
|
|
||||||
static u8
|
static u8
|
||||||
regread(u16 a)
|
regread(u16 a)
|
||||||
{
|
{
|
||||||
@ -71,6 +70,7 @@ regwrite(u16 a, u8 v)
|
|||||||
ppusync();
|
ppusync();
|
||||||
if ((~v & reg[a] & LCDEN) != 0) {
|
if ((~v & reg[a] & LCDEN) != 0) {
|
||||||
ppuy = 0;
|
ppuy = 0;
|
||||||
|
ppuw = 0;
|
||||||
ppustate = 0;
|
ppustate = 0;
|
||||||
delevent(&evhblank);
|
delevent(&evhblank);
|
||||||
}
|
}
|
||||||
@ -159,7 +159,6 @@ memwrite(u16 a, u8 v)
|
|||||||
eramb[a - 0xa000] = v;
|
eramb[a - 0xa000] = v;
|
||||||
else
|
else
|
||||||
mapper(a, v);
|
mapper(a, v);
|
||||||
writeback();
|
|
||||||
return;
|
return;
|
||||||
case 12: case 14:
|
case 12: case 14:
|
||||||
wram[a & 0xFFF] = v;
|
wram[a & 0xFFF] = v;
|
||||||
@ -199,29 +198,29 @@ static int
|
|||||||
mbc1(int a, int v)
|
mbc1(int a, int v)
|
||||||
{
|
{
|
||||||
static u8 ramen, b0, b1, romram;
|
static u8 ramen, b0, b1, romram;
|
||||||
static Var mbc1vars[] = {VAR(ramen), VAR(b0), VAR(b1), VAR(romram),
|
|
||||||
{nil, 0,0}};
|
|
||||||
u16 b;
|
u16 b;
|
||||||
|
|
||||||
if (a < 0) {
|
if (a < 0) {
|
||||||
switch(a) {
|
switch(a) {
|
||||||
case INIT: return 0;
|
case INIT: return 0;
|
||||||
case SAVE: putvars(mbc1vars); break;
|
case SAVE:
|
||||||
case RSTR: getvars(mbc1vars); break;
|
case RSTR:
|
||||||
case READ: return -1;
|
break;
|
||||||
|
case READ:
|
||||||
|
return -1;
|
||||||
default: panic("MBC1 does not have function of %d", a);
|
default: panic("MBC1 does not have function of %d", a);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
switch (a >> 13) {
|
switch (a >> 13) {
|
||||||
case 0: ramen = (v & 0xF) == 0xA; break;
|
case 0: ramen = (v & 0xF) == 0xA; break;
|
||||||
case 1: v &= 0x1F; b0 = v != 0 ? v : 1; break;
|
case 1: v &= 0x1F; b0 = v != 0 ? v : 1; break;
|
||||||
case 2: b1 = v & 3; b1 %= nbackbank; break;
|
case 2: b1 = v & 3; b1 % nbackbank; break;
|
||||||
case 3: romram = v & 1; break;
|
case 3: romram = v & 1; break;
|
||||||
}
|
}
|
||||||
b = b0;
|
b = b0;
|
||||||
if (romram == 0)
|
if (romram == 0)
|
||||||
b |= b1 << 5;
|
b |= b1 << 5;
|
||||||
b %= nrom >> 14;
|
b %= nrom >> 14; /* 32KB => 2bank */
|
||||||
romb = rom + (b << 14);
|
romb = rom + (b << 14);
|
||||||
if (ramen) {
|
if (ramen) {
|
||||||
if (romram)
|
if (romram)
|
||||||
@ -235,9 +234,13 @@ mbc1(int a, int v)
|
|||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
meminit()
|
meminit(void)
|
||||||
{
|
{
|
||||||
union {u8 c[4]; u32 l;}c;
|
union
|
||||||
|
{
|
||||||
|
u8 c[4];
|
||||||
|
u32 l;
|
||||||
|
} c;
|
||||||
|
|
||||||
c.c[0] = c.c[1] = c.c[2] = 0;
|
c.c[0] = c.c[1] = c.c[2] = 0;
|
||||||
c.c[3] = 1;
|
c.c[3] = 1;
|
||||||
@ -245,12 +248,14 @@ meminit()
|
|||||||
c.l >>= 1;
|
c.l >>= 1;
|
||||||
c.c[0] = c.c[1] = c.c[2] = 0xff;
|
c.c[0] = c.c[1] = c.c[2] = 0xff;
|
||||||
c.c[3] = 0;
|
c.c[3] = 0;
|
||||||
|
white = c.l;
|
||||||
|
|
||||||
romb = rom + 0x4000;
|
romb = rom + 0x4000;
|
||||||
wramb = wram + 0x1000;
|
wramb = wram + 0x1000;
|
||||||
vramb = vram;
|
vramb = vram;
|
||||||
mapper = mappers[mbc];
|
mapper = mappers[mbc];
|
||||||
mapper(INIT, 0);
|
mapper(INIT, 0);
|
||||||
|
|
||||||
reg[LCDC] = 0x91;
|
reg[LCDC] = 0x91;
|
||||||
reg[IF] = 0xE0;
|
reg[IF] = 0xE0;
|
||||||
reg[SVBK] = 0xff;
|
reg[SVBK] = 0xff;
|
||||||
|
|||||||
48
ppu.c
48
ppu.c
@ -1,17 +1,15 @@
|
|||||||
|
#include "co/task.h"
|
||||||
#include "gb.h"
|
#include "gb.h"
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
#define ryield() {if(psetjmp(renderjmp) == 0) plongjmp(mainjmp, 1);}
|
|
||||||
#define myield() {if(psetjmp(mainjmp) == 0) plongjmp(renderjmp, 1);}
|
|
||||||
#define eat(nc) \
|
#define eat(nc) \
|
||||||
if (cyc <= nc) { \
|
if (cyc <= nc) { \
|
||||||
for (i = 0; i < nc; i++) \
|
for (i = 0; i < nc; i++) \
|
||||||
if (--cyc == 0) \
|
if (--cyc == 0) \
|
||||||
ryield(); \
|
taskyield(); \
|
||||||
} else \
|
} else \
|
||||||
cyc -= nc;
|
cyc -= nc;
|
||||||
|
|
||||||
typedef void *jmp_buf[10];
|
|
||||||
typedef struct sprite sprite;
|
typedef struct sprite sprite;
|
||||||
struct sprite
|
struct sprite
|
||||||
{
|
{
|
||||||
@ -33,28 +31,19 @@ enum
|
|||||||
TILSPR = 0x04,
|
TILSPR = 0x04,
|
||||||
};
|
};
|
||||||
|
|
||||||
jmp_buf mainjmp,renderjmp;
|
u8 ppustate, ppuy, ppuw;
|
||||||
u8 ppustate, ppuy;
|
|
||||||
u64 hblclock, rendclock;
|
u64 hblclock, rendclock;
|
||||||
static int cyc, ppux, ppux0;
|
static int cyc, ppux, ppux0;
|
||||||
sprite spr[10], *sprm;
|
sprite spr[10], *sprm;
|
||||||
|
|
||||||
Var ppuvars[] = {VAR(ppustate), VAR(ppuy), VAR(hblclock), VAR(rendclock),
|
void
|
||||||
{nil, 0, 0}};
|
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;
|
int x, y, i, n, m, win;
|
||||||
u16 ta, ca, chr;
|
u16 ta, ca, chr;
|
||||||
u8 tile;
|
u8 tile;
|
||||||
u32 sr[8], *picp;
|
u32 sr[8], *picp;
|
||||||
|
|
||||||
ryield();
|
|
||||||
|
|
||||||
for (;;) {
|
for (;;) {
|
||||||
eat(6 * 2);
|
eat(6 * 2);
|
||||||
m = 168 + (reg[SCX] & 7);
|
m = 168 + (reg[SCX] & 7);
|
||||||
@ -90,7 +79,7 @@ ppurender(void)
|
|||||||
if (cyc <= 2 * 8) {
|
if (cyc <= 2 * 8) {
|
||||||
for (i = 0; i < 2 * 8; ++i)
|
for (i = 0; i < 2 * 8; ++i)
|
||||||
if (--cyc == 0)
|
if (--cyc == 0)
|
||||||
ryield();
|
taskyield();
|
||||||
y = ppuy + reg[SCY] << 1 & 14;
|
y = ppuy + reg[SCY] << 1 & 14;
|
||||||
ta = 0x1800 | reg[LCDC] << 7 & 0x400 | ppuy + reg[SCY] << 2 & 0x3E0 |
|
ta = 0x1800 | reg[LCDC] << 7 & 0x400 | ppuy + reg[SCY] << 2 & 0x3E0 |
|
||||||
ta & 0x1F;
|
ta & 0x1F;
|
||||||
@ -110,13 +99,13 @@ ppurender(void)
|
|||||||
} while (m > 8);
|
} while (m > 8);
|
||||||
if (win == -1) {
|
if (win == -1) {
|
||||||
win = 1;
|
win = 1;
|
||||||
ta = 0x1800 | reg[LCDC] << 4 & 0x400 | ppuy - reg[WY] << 2 & 0x3E0;
|
ta = 0x1800 | reg[LCDC] << 4 & 0x400 | ppuw - reg[WY] << 2 & 0x3E0;
|
||||||
y = ppuy - reg[WY] << 1 & 14;
|
y = ppuw - reg[WY] << 1 & 14;
|
||||||
cyc += 12;
|
cyc += 2;
|
||||||
m = 175 - reg[WX];
|
m = 175 - reg[WX];
|
||||||
goto restart;
|
goto restart;
|
||||||
}
|
}
|
||||||
ryield();
|
taskyield();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -219,7 +208,7 @@ ppusync(void)
|
|||||||
return;
|
return;
|
||||||
cyc = clock - rendclock;
|
cyc = clock - rendclock;
|
||||||
if (cyc != 0)
|
if (cyc != 0)
|
||||||
myield();
|
taskyield();
|
||||||
sprites();
|
sprites();
|
||||||
rendclock = clock;
|
rendclock = clock;
|
||||||
}
|
}
|
||||||
@ -245,6 +234,8 @@ hblanktick(void* _)
|
|||||||
switch (ppustate) {
|
switch (ppustate) {
|
||||||
case 0:
|
case 0:
|
||||||
hblclock = clock + evhblank.time;
|
hblclock = clock + evhblank.time;
|
||||||
|
if (reg[WX] <= 166 && reg[WY] <= 143)
|
||||||
|
ppuw++;
|
||||||
if (++ppuy == 144) {
|
if (++ppuy == 144) {
|
||||||
ppustate = 1;
|
ppustate = 1;
|
||||||
if (reg[STAT] & IRQM1)
|
if (reg[STAT] & IRQM1)
|
||||||
@ -263,8 +254,11 @@ hblanktick(void* _)
|
|||||||
break;
|
break;
|
||||||
case 1:
|
case 1:
|
||||||
hblclock = clock + evhblank.time;
|
hblclock = clock + evhblank.time;
|
||||||
|
if (reg[WX] <= 166 && reg[WY] <= 143)
|
||||||
|
ppuw++;
|
||||||
if (++ppuy == 154) {
|
if (++ppuy == 154) {
|
||||||
ppuy = 0;
|
ppuy = 0;
|
||||||
|
ppuw = 0;
|
||||||
ppustate = 2;
|
ppustate = 2;
|
||||||
if (reg[STAT] & IRQM2)
|
if (reg[STAT] & IRQM2)
|
||||||
reg[IF] |= IRQLCDS;
|
reg[IF] |= IRQLCDS;
|
||||||
@ -290,13 +284,3 @@ hblanktick(void* _)
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
|
||||||
ppuinit(void)
|
|
||||||
{
|
|
||||||
static u8 stk[8192];
|
|
||||||
|
|
||||||
renderjmp[REG_RSP] = stk + sizeof(stk) - 64;
|
|
||||||
renderjmp[REG_RIP] = ppurender;
|
|
||||||
myield();
|
|
||||||
}
|
|
||||||
|
|||||||
222
print.c
222
print.c
@ -1,222 +0,0 @@
|
|||||||
#include "print.h"
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <errno.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include <unistd.h>
|
|
||||||
#include <assert.h>
|
|
||||||
|
|
||||||
enum
|
|
||||||
{
|
|
||||||
FlagLong = 1<<0,
|
|
||||||
FlagLongLong = 1<<1,
|
|
||||||
FlagUnsigned = 1<<2,
|
|
||||||
};
|
|
||||||
|
|
||||||
static char*
|
|
||||||
printstr(char *dst, char *edst, char *s, int sz)
|
|
||||||
{
|
|
||||||
int l, n, isneg;
|
|
||||||
|
|
||||||
isneg = 0;
|
|
||||||
if(sz < 0){
|
|
||||||
sz = -sz;
|
|
||||||
isneg = 1;
|
|
||||||
}
|
|
||||||
if(dst >= edst)
|
|
||||||
return dst;
|
|
||||||
n = l = strlen(s);
|
|
||||||
if(n < sz)
|
|
||||||
n = sz;
|
|
||||||
if(n >= edst - dst)
|
|
||||||
n = (edst - dst) - 1;
|
|
||||||
if(l > n)
|
|
||||||
l = n;
|
|
||||||
if(isneg){
|
|
||||||
memmove(dst, s, l);
|
|
||||||
if(n - l)
|
|
||||||
memset(dst + l, ' ', n - l);
|
|
||||||
}else{
|
|
||||||
if(n - l)
|
|
||||||
memset(dst, ' ', n - l);
|
|
||||||
memmove(dst + n - l, s, l);
|
|
||||||
}
|
|
||||||
return dst + n;
|
|
||||||
}
|
|
||||||
|
|
||||||
char*
|
|
||||||
vseprint(char *dst, char *edst, char *fmt, va_list arg)
|
|
||||||
{
|
|
||||||
int fl, sz, sign, base;
|
|
||||||
char *p, *w;
|
|
||||||
char cbuf[2];
|
|
||||||
|
|
||||||
w = dst;
|
|
||||||
for(p = fmt; *p && w < edst - 1; p++){
|
|
||||||
switch(*p){
|
|
||||||
default:
|
|
||||||
*w++ = *p;
|
|
||||||
break;
|
|
||||||
case '%':
|
|
||||||
sign = 1;
|
|
||||||
fl = sz = 0;
|
|
||||||
for(p++; *p; p++){
|
|
||||||
switch(*p){
|
|
||||||
case '-': sign = -1; break;
|
|
||||||
case '0': case '1': case '2': case '3': case '4':
|
|
||||||
case '5': case '6': case '7': case '8': case '9':
|
|
||||||
sz = sz * 10 + *p - '0';
|
|
||||||
break;
|
|
||||||
case 'l': if(fl & FlagLong)fl |= FlagLongLong;break;
|
|
||||||
case 'u': fl |= FlagUnsigned; break;
|
|
||||||
case 'i': case 'd':
|
|
||||||
base = 10; goto num;
|
|
||||||
case 'o': base = 8; goto num;
|
|
||||||
case 'p': case 'x': case 'X':
|
|
||||||
base = 16;
|
|
||||||
goto num;
|
|
||||||
num:
|
|
||||||
{
|
|
||||||
static char digits[] = "0123456789abcdef";
|
|
||||||
char buf[30], *p;
|
|
||||||
int neg, zero;
|
|
||||||
unsigned long long luv;
|
|
||||||
|
|
||||||
if(fl & FlagLongLong){
|
|
||||||
if(fl & FlagUnsigned)
|
|
||||||
luv = va_arg(arg, unsigned long long);
|
|
||||||
else
|
|
||||||
luv = va_arg(arg, long long);
|
|
||||||
}else{
|
|
||||||
if(fl & FlagLong){
|
|
||||||
if(fl & FlagUnsigned)
|
|
||||||
luv = va_arg(arg, unsigned long);
|
|
||||||
else
|
|
||||||
luv = va_arg(arg, long);
|
|
||||||
}else{
|
|
||||||
if(fl & FlagUnsigned)
|
|
||||||
luv = va_arg(arg, unsigned int);
|
|
||||||
else
|
|
||||||
luv = va_arg(arg, int);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
p = buf + sizeof(buf);
|
|
||||||
neg = zero = 0;
|
|
||||||
if((fl & FlagUnsigned) == 0 && (long long)luv < 0){
|
|
||||||
neg = 1;
|
|
||||||
luv = -luv;
|
|
||||||
}
|
|
||||||
if(luv == 0)
|
|
||||||
zero = 1;
|
|
||||||
*--p = 0;
|
|
||||||
while(luv){
|
|
||||||
*--p = digits[luv % base];
|
|
||||||
luv /= base;
|
|
||||||
}
|
|
||||||
if(base == 16){
|
|
||||||
*--p = 'x';
|
|
||||||
*--p = '0';
|
|
||||||
}
|
|
||||||
if(base == 8 || zero)
|
|
||||||
*--p = '0';
|
|
||||||
w = printstr(w, edst,p, sz * sign);
|
|
||||||
goto break2;
|
|
||||||
}
|
|
||||||
case 'c':
|
|
||||||
cbuf[0] = va_arg(arg, int);
|
|
||||||
cbuf[1] = 0;
|
|
||||||
w = printstr(w, edst, cbuf, sz * sign);
|
|
||||||
goto break2;
|
|
||||||
case 's':
|
|
||||||
w = printstr(w, edst, va_arg(arg, char*), sz*sign);
|
|
||||||
goto break2;
|
|
||||||
case 'r':
|
|
||||||
w = printstr(w, edst, strerror(errno), sz*sign);
|
|
||||||
goto break2;
|
|
||||||
default:
|
|
||||||
p = "error";
|
|
||||||
goto break2;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break2:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
assert(w < edst);
|
|
||||||
*w = 0;
|
|
||||||
return dst;
|
|
||||||
}
|
|
||||||
|
|
||||||
char*
|
|
||||||
vsnprint(char *dst, unsigned int n, char *fmt, va_list arg)
|
|
||||||
{
|
|
||||||
return vseprint(dst, dst + n, fmt, arg);
|
|
||||||
}
|
|
||||||
|
|
||||||
char*
|
|
||||||
snprint(char *dst, unsigned int n, char *fmt, ...)
|
|
||||||
{
|
|
||||||
va_list arg;
|
|
||||||
|
|
||||||
va_start(arg, fmt);
|
|
||||||
vsnprint(dst, n, fmt, arg);
|
|
||||||
va_end(arg);
|
|
||||||
return dst;
|
|
||||||
}
|
|
||||||
|
|
||||||
char*
|
|
||||||
seprint(char* dst, char* edst, char* fmt, ...)
|
|
||||||
{
|
|
||||||
va_list arg;
|
|
||||||
|
|
||||||
va_start(arg, fmt);
|
|
||||||
vseprint(dst, edst, fmt, arg);
|
|
||||||
va_end(arg);
|
|
||||||
return dst;
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
vfprint(int fd, char *fmt, va_list arg)
|
|
||||||
{
|
|
||||||
char buf[1024];
|
|
||||||
|
|
||||||
vseprint(buf, buf + sizeof buf, fmt, arg);
|
|
||||||
return write(fd, buf, strlen(buf));
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
int
|
|
||||||
vprint(char *fmt, va_list arg)
|
|
||||||
{
|
|
||||||
return vfprint(1, fmt, arg);
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
fprint(int fd, char *fmt, ...)
|
|
||||||
{
|
|
||||||
int n;
|
|
||||||
va_list arg;
|
|
||||||
|
|
||||||
va_start(arg, fmt);
|
|
||||||
n = vfprint(fd, fmt, arg);
|
|
||||||
va_end(arg);
|
|
||||||
return n;
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
print(char *fmt, ...)
|
|
||||||
{
|
|
||||||
int n;
|
|
||||||
va_list arg;
|
|
||||||
|
|
||||||
va_start(arg, fmt);
|
|
||||||
n = vprint(fmt, arg);
|
|
||||||
va_end(arg);
|
|
||||||
return n;
|
|
||||||
}
|
|
||||||
|
|
||||||
char*
|
|
||||||
strecpy(char *dst, char *edst, char *src)
|
|
||||||
{
|
|
||||||
*printstr(dst, edst, src, 0) = 0;
|
|
||||||
return dst;
|
|
||||||
}
|
|
||||||
11
print.h
11
print.h
@ -1,11 +0,0 @@
|
|||||||
#include <stdarg.h>
|
|
||||||
|
|
||||||
char* vseprint(char *dst, char *edst, char *fmt, va_list arg);
|
|
||||||
char* vsnprint(char *dst, unsigned int n, char *fmt, va_list arg);
|
|
||||||
char* snprint(char *dst, unsigned int n, char *fmt, ...);
|
|
||||||
char* seprint(char* dst, char* edst, char* fmt, ...);
|
|
||||||
int vfprint(int fd, char *fmt, va_list arg);
|
|
||||||
int vprint(char *fmt, va_list arg);
|
|
||||||
int fprint(int fd, char *fmt, ...);
|
|
||||||
int print(char *fmt, ...);
|
|
||||||
char* strecpy(char *dst, char *edst, char *src);
|
|
||||||
163
save.c
163
save.c
@ -1,163 +0,0 @@
|
|||||||
#include "gb.h"
|
|
||||||
#include <stdio.h>
|
|
||||||
|
|
||||||
extern Var cpuvars[], ppuvars[], memvars[], evvars[];
|
|
||||||
static FILE *fp;
|
|
||||||
|
|
||||||
void
|
|
||||||
putevents(void)
|
|
||||||
{
|
|
||||||
u8 i, j;
|
|
||||||
Event *e;
|
|
||||||
|
|
||||||
for(i = 0; i < NEVENT; ++i)
|
|
||||||
if(elist == events[i]) /* find head */
|
|
||||||
break;
|
|
||||||
if(i == NEVENT && elist != nil)
|
|
||||||
error("Unkown event in chain [%p]", elist);
|
|
||||||
fputc(i, fp);
|
|
||||||
for(i = 0; i < NEVENT; ++i){
|
|
||||||
e = events[i];
|
|
||||||
fputc(e->time & 0x000000ff, fp);
|
|
||||||
fputc(e->time & 0x0000ff00, fp);
|
|
||||||
fputc(e->time & 0x00ff0000, fp);
|
|
||||||
fputc(e->time & 0xff000000, fp);
|
|
||||||
for(j = 0; j < NEVENT; ++j)
|
|
||||||
if(e->next == events[j]) /* find next */
|
|
||||||
break;
|
|
||||||
if(j == NEVENT && e->next != nil)
|
|
||||||
error("Unkown event in chain [%p]", e->next);
|
|
||||||
fputc(j, fp);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
putvars(Var *v)
|
|
||||||
{
|
|
||||||
int n;
|
|
||||||
u16 *p;
|
|
||||||
u32 *q;
|
|
||||||
|
|
||||||
for(; v->a != nil; v++){
|
|
||||||
switch(v->s){
|
|
||||||
case 1:
|
|
||||||
fwrite(v->a, 1, v->n, fp);
|
|
||||||
break;
|
|
||||||
case 2:
|
|
||||||
n = v->n;
|
|
||||||
p = v->a;
|
|
||||||
while(n--){
|
|
||||||
fputc(*p & 0xff, fp);
|
|
||||||
fputc(*p++ >> 8, fp);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case 4:
|
|
||||||
n = v->n;
|
|
||||||
q = v->a;
|
|
||||||
while(n--){
|
|
||||||
fputc(*q, fp);
|
|
||||||
fputc(*q >> 8, fp);
|
|
||||||
fputc(*q >> 16, fp);
|
|
||||||
fputc(*q >> 24, fp);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
getvars(Var *v)
|
|
||||||
{
|
|
||||||
int n;
|
|
||||||
u16 *p, w;
|
|
||||||
u32 *q, l;
|
|
||||||
|
|
||||||
for(; v->a != nil; v++){
|
|
||||||
switch(v->s){
|
|
||||||
case 1: fread(v->a, v->n, 1, fp); break;
|
|
||||||
case 2:
|
|
||||||
n = v->n;
|
|
||||||
p = v->a;
|
|
||||||
while(n--){
|
|
||||||
w = fgetc(fp);
|
|
||||||
w |= fgetc(fp) << 8;
|
|
||||||
*p++ = w;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case 4:
|
|
||||||
n = v->n;
|
|
||||||
q = v->a;
|
|
||||||
while(n--){
|
|
||||||
l = fgetc(fp);
|
|
||||||
l |= fgetc(fp) << 8;
|
|
||||||
l |= fgetc(fp) << 16;
|
|
||||||
l |= fgetc(fp) << 24;
|
|
||||||
*q++ = l;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
savestate(const char *fname)
|
|
||||||
{
|
|
||||||
fp = fopen(fname, "w");
|
|
||||||
if(fp == 0){
|
|
||||||
error("Can't open '%s'", fname);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
putvars(cpuvars);
|
|
||||||
putvars(ppuvars);
|
|
||||||
putvars(memvars);
|
|
||||||
putvars(evvars);
|
|
||||||
putevents();
|
|
||||||
mapper(SAVE, 0);
|
|
||||||
fclose(fp);
|
|
||||||
fp = 0;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
getevents(void)
|
|
||||||
{
|
|
||||||
int i, j;
|
|
||||||
Event *e;
|
|
||||||
|
|
||||||
i = fgetc(fp);
|
|
||||||
if(i >= NEVENT)
|
|
||||||
elist = nil;
|
|
||||||
else
|
|
||||||
elist = events[i];
|
|
||||||
for(i = 0; i < NEVENT; ++i){
|
|
||||||
e = events[i];
|
|
||||||
e->time = fgetc(fp);
|
|
||||||
e->time |= fgetc(fp) << 8;
|
|
||||||
e->time |= fgetc(fp) << 16;
|
|
||||||
e->time |= fgetc(fp) << 24;
|
|
||||||
j = fgetc(fp);
|
|
||||||
if(j >= NEVENT)
|
|
||||||
e->next = nil;
|
|
||||||
else
|
|
||||||
e->next = events[j];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
loadstate(const char *fname)
|
|
||||||
{
|
|
||||||
fp = fopen(fname, "r");
|
|
||||||
if(fp == 0){
|
|
||||||
error("Can't load '%s'", fname);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
getvars(cpuvars);
|
|
||||||
getvars(ppuvars);
|
|
||||||
getvars(memvars);
|
|
||||||
getvars(evvars);
|
|
||||||
getevents();
|
|
||||||
mapper(RSTR, 0);
|
|
||||||
fclose(fp);
|
|
||||||
fp = 0;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
Loading…
Reference in New Issue
Block a user