add libemu

move redundant code from emulators to a common library
This commit is contained in:
qwx 2018-05-12 19:20:53 +02:00
parent 70c7a9eb07
commit 1195ca910c
40 changed files with 802 additions and 1247 deletions

View file

@ -4,7 +4,7 @@ gb, gba, nes, snes \- emulators
.SH SYNOPSIS
.B games/gb
[
.B -23acdT
.B -acdT
]
[
.B -C
@ -14,7 +14,7 @@ gb, gba, nes, snes \- emulators
.br
.B games/gba
[
.B -23aT
.B -aT
] [
.B -b
.I biosfile
@ -26,13 +26,13 @@ gb, gba, nes, snes \- emulators
.br
.B games/nes
[
.B -23aos
.B -aos
]
.I romfile
.br
.B games/snes
[
.B -23ahmsT
.B -ahmsT
]
.I romfile
.SH DESCRIPTION
@ -43,7 +43,7 @@ and
.I snes
are emulators for the Nintendo Game Boy and Game Boy Color (GB and GBC), Nintendo Game Boy Advance (GBA), Nintendo Entertainment System (NES), and Super Nintendo Entertainment System (SNES).
They execute the romfile given as an argument.
The \fBz\fR, \fBx\fR, \fBa\fR, \fBs\fR, return and shift keys correspond to B, A, Y, X, Start and Select, respectively.
The \fBz\fR, \fBx\fR, \fBa\fR, \fBs\fR, \fBq\fR, \fBw\fRreturn and shift keys correspond to B, A, Y, X, L1, L2, Start and Select, respectively.
Other keys:
.TP
F5
@ -60,14 +60,8 @@ Exit the emulator.
.PP
Command line options:
.TP
.B -2 -3
Scale the screen by the given factor.
.TP
.B -a
Enable audio output.
.TP
.B -T
Display percentage of how fast the emulator is running relative to a real console.
.PP
.B gb
options:

View file

@ -4,14 +4,14 @@ md \- emulator
.SH SYNOPSIS
.B games/md
[
.B -23a
.B -a
]
.I romfile
.SH DESCRIPTION
.I Md
is an emulator for the Sega Megadrive/Genesis.
It executes the romfile given as an argument.
The \fBz\fR, \fBx\fR, \fBc\fR, return and shift keys correspond to A, B, C, Start and Select, respectively.
The \fBz\fR, \fBx\fR, \fBa\fR, return and shift keys correspond to A, B, C, Start and Select, respectively.
Other keys:
.TP
Esc
@ -22,9 +22,6 @@ Exit the emulator.
.PP
Command line options:
.TP
.B -2 -3
Scale the screen by the given factor.
.TP
.B -a
Enable audio output.
.SH SOURCE
@ -33,4 +30,4 @@ Enable audio output.
Probably!
.SH HISTORY
.I Md
first appeared in 9front (May, 2014).
first appeared in 9front (November, 2014).

137
sys/man/2/emu Normal file
View file

@ -0,0 +1,137 @@
.TH EMU 2
.SH NAME
initemu, regkeyfn, flushmouse, flushscreen, flushaudio, screenwipe \- graphical emulator-like software scaffolding
.SH SYNOPSIS
.nf
.ft L
#include <u.h>
#include <libc.h>
#include <emu.h>
.PP
.ta +\w'\fLvoid fP'u
.B
void flushmouse(int discard);
.PP
.B
void flushscreen(void);
.PP
.B
void flushaudio(int (*fn)(void));
.PP
.B
void regkeyfn(Rune r, void (*fn)(void));
.PP
.B
void regkey(char *joyk, Rune r, int k);
.PP
.B
void initemu(int dx, int dy, int bpp, ulong chan,
.B
int dokey, void(*kproc)(void*));
.SH DESCRIPTION
.I Libemu
implements common user interfaces for programs controlled
with a joypad or a limited number of keys.
.PP
.B initemu
initializes the display for the given internal screen size
.B dx
by
.B dy
and
.B bpp
bit depth.
.B Chan
is an
.B Image
pixel format descriptor to be used for an internal framebuffer (see
.IR draw (2)).
.PP
If
.B dokey
is true,
a keyboard process is started which sets a 64-bit wide bit vector for input keys.
.PP
Keys are set via
.B regkey.
Pressing the key corresponding to the
.B r
rune, or writing
.B joyk
to standard in will
.L OR
.B k
with the key bit vector.
.PP
.B Regkeyfn
registers an additional rune and a callback for the keyboard process.
.PP
Normally, a joypad process is also started, and parses standard input for key presses.
If
.B dokey
is false, only the joypad process will be started.
If
.B kproc
is a valid function pointer,
it will be used for keyboard processing instead of the library-provided one,
and no joypad process will be started.
.PP
.IP
.EX
.ta 6n
uchar *pic;
.EE
.PP
Once
.B initemu
is called, a framebuffer of the specifized size is allocated,
and may be accessed via
.BR pic .
.L Libemu
scales the framebuffer to fit the greatest multiple of the framebuffer's
width in the window.
The scaling is horizontal only and needs to be taken into account for drawing
within the program.
.PP
Typically, mouse event handling is followed by drawing the final image from the
internal framebuffer render and writing a constant amount of audio samples,
thereby synchronizing the program's framerate to the audio writes.
.IP
.EX
.ta 6n
Mouse m;
extern Mousectl *mc;
flushmouse(0);
while(nbrecv(mc->c, &m) > 0){
...
}
flushscreen();
flushaudio(audioout);
.EE
.PP
Besides window resizing, mouse events are discarded by default.
If
.B discard
is false
.B flushmouse
will let the user program handle mouse events prior to flushing the screen (see
.BR event (2)).
.PP
.B Flushscreen
handles re-scaling and re-allocating the buffers used, as well as drawing to
the screen, either directly, or by duplicating pre-scaled scanlines.
.SH SOURCE
.B /sys/src/libemu
.SH "SEE ALSO"
.IR draw (2),
.IR event (2)
.SH BUGS
The semantics for
.B initemu
input selection are confusing.
.PP
A greater effort should be made to simplify automatic scaling for user programs.
.SH HISTORY
.I Libemu
first appeared in 9front in May, 2018.

View file

@ -4,18 +4,15 @@
#include <draw.h>
#include <mouse.h>
#include <keyboard.h>
#include <emu.h>
#include "dat.h"
#include "fns.h"
char *bindir = "/sys/lib/c64";
Image *tmp, *bg, *red;
Rectangle picr, progr;
Mousectl *mc;
QLock pauselock;
int paused, scale;
Image *red;
Rectangle progr;
u8int *rom;
int nrom;
u64int keys;
u16int joys;
uchar *tape, tapever, tapeplay;
ulong tapelen;
@ -26,7 +23,8 @@ progress(int a, int b)
{
static int cur;
int w;
extern Image *bg;
if(b == 0 || a == 0){
if(cur != 0){
draw(screen, progr, bg, nil, ZP);
@ -211,21 +209,6 @@ keyproc(void *)
}
static void
screeninit(void)
{
Point p, q;
p = divpt(addpt(screen->r.min, screen->r.max), 2);
picr = (Rectangle){subpt(p, Pt(picw/2*scale, pich/2*scale)), addpt(p, Pt(picw/2*scale, pich/2*scale))};
p.y += pich*scale*3/4;
q = Pt(Dx(screen->r) * 2/5, 8);
progr = (Rectangle){subpt(p, q), addpt(p, q)};
freeimage(tmp);
tmp = allocimage(display, Rect(0, 0, picw*scale, scale > 1 ? 1 : pich), XRGB32, 1, 0);
draw(screen, screen->r, bg, nil, ZP);
}
static void
usage(void)
{
@ -236,17 +219,9 @@ usage(void)
void
threadmain(int argc, char **argv)
{
scale = 1;
memreset();
ARGBEGIN {
case '2':
scale = 2;
break;
case '3':
scale = 3;
break;
case 'c':
loadcart(EARGF(usage()));
break;
@ -272,16 +247,8 @@ threadmain(int argc, char **argv)
loadsys("crom.bin", crom, 4096);
vicreset();
if(initdraw(nil, nil, nil) < 0)
sysfatal("initdraw: %r");
mc = initmouse(nil, screen);
if(mc == nil)
sysfatal("initmouse: %r");
bg = allocimage(display, Rect(0, 0, 1, 1), screen->chan, 1, 0xCCCCCCFF);
initemu(picw, pich, 4, XRGB32, 1, keyproc);
red = allocimage(display, Rect(0, 0, 1, 1), screen->chan, 1, 0xFF0000FF);
screeninit();
proccreate(keyproc, nil, mainstacksize);
nmien = IRQRESTORE;
pc = memread(0xFFFC) | memread(0xFFFD) << 8;
@ -309,7 +276,8 @@ menu(void)
static Menu m = {
items, nil, 0
};
extern Mousectl *mc;
switch(menuhit(3, mc, &m, nil)){
case JOY:
joymode = (joymode + 1) % 3;
@ -332,52 +300,11 @@ menu(void)
void
flush(void)
{
extern u8int pic[];
// vlong new, diff;
// static vlong old, delta;
if(nbrecvul(mc->resizec) > 0){
if(getwindow(display, Refnone) < 0)
sysfatal("resize failed: %r");
screeninit();
}
extern Mousectl *mc;
flushmouse(0);
while(nbrecv(mc->c, &mc->Mouse) > 0)
if((mc->buttons & 4) != 0)
menu();
if(scale == 1){
loadimage(tmp, tmp->r, pic, picw*pich*4);
draw(screen, picr, tmp, nil, ZP);
}else{
Rectangle r;
uchar *s;
int w;
s = pic;
r = picr;
w = picw*4*scale;
while(r.min.y < picr.max.y){
loadimage(tmp, tmp->r, s, w);
s += w;
r.max.y = r.min.y+scale;
draw(screen, r, tmp, nil, ZP);
r.min.y = r.max.y;
}
}
flushimage(display, 1);
/*
if(audioout() < 0){
new = nsec();
diff = 0;
if(old != 0){
diff = BILLION/60 - (new - old) - delta;
if(diff >= MILLION)
sleep(diff/MILLION);
}
old = nsec();
if(diff != 0){
diff = (old - new) - (diff / MILLION) * MILLION;
delta += (diff - delta) / 100;
}
}
*/
flushscreen();
flushaudio(nil);
}

View file

@ -1,5 +1,6 @@
#include <u.h>
#include <libc.h>
#include <emu.h>
#include "dat.h"
#include "fns.h"
@ -289,8 +290,6 @@ interrupt(int nmi, int brk)
rP |= FLAGI;
}
int trace;
void
step(void)
{

View file

@ -1,10 +1,8 @@
typedef char s8int;
extern u8int reg[47], crom[4096], krom[8192], brom[8192], cram[1024], cart[16384];
extern u16int pc, curpc;
extern u8int rP;
extern int nrdy, irq, nmi, irqen, nmien, trace;
extern int nrdy, irq, nmi, irqen, nmien;
extern u8int pla;
@ -12,9 +10,8 @@ extern uchar *tape, tapever, tapeplay;
extern ulong tapelen;
extern u16int ppux, ppuy, picw, pich;
extern u64int keys;
extern u16int joys;
extern int scale, region;
extern int region;
enum {
FLAGC = 1<<0,
@ -81,8 +78,6 @@ enum {
};
enum {
BILLION = 1000*1000*1000,
MILLION = 1000*1000,
HZ = 3579545,
RATE = 44100,
SAMPDIV = HZ / 3 / RATE,

View file

@ -1,6 +1,7 @@
#include <u.h>
#include <libc.h>
#include <thread.h>
#include <emu.h>
#include "dat.h"
#include "fns.h"

View file

@ -1,6 +1,7 @@
#include <u.h>
#include <libc.h>
#include <thread.h>
#include <emu.h>
#include "dat.h"
#include "fns.h"
@ -9,7 +10,6 @@ u16int ppux, ppuy, lastx, wrapx, maxy, lvis, rvis, uvis, dvis, picw, pich, lbord
u16int vc, vcbase, vmli;
u8int badln, rc, displ, fract, visreg, hbord, vbord, rbord0, lbord0;
u16int chrp[40];
u8int pic[420*263*4*3];
u64int pxs, npxs, npxs0, opxs;
u8int fg;
@ -92,24 +92,40 @@ vicreset(void)
void
pixeldraw(u64int p, int n)
{
int i, j;
int i;
union { u8int c[4]; u32int l; } u;
static u8int cr[] = {0, 255, 136, 170, 204, 0, 0, 238, 221, 102, 255, 51, 119, 170, 0, 187};
static u8int cg[] = {0, 255, 0, 255, 68, 204, 0, 238, 136, 68, 119, 51, 119, 255, 136, 187};
static u8int cb[] = {0, 255, 0, 238, 204, 85, 170, 119, 85, 0, 119, 51, 119, 102, 255, 187};
u8int *q, c;
q = pic + picidx * 4 * scale;
u8int c;
u32int *q;
q = (u32int *)pic + picidx * scale;
for(i = 0; i < n; i++){
c = p >> 56;
p <<= 8;
j = scale;
do{
*q++ = cb[c];
*q++ = cg[c];
*q++ = cr[c];
q++;
}while(--j);
u.c[0] = cb[c];
u.c[1] = cg[c];
u.c[2] = cr[c];
u.c[3] = 0;
switch(scale){
case 16: *q++ = u.l;
case 15: *q++ = u.l;
case 14: *q++ = u.l;
case 13: *q++ = u.l;
case 12: *q++ = u.l;
case 11: *q++ = u.l;
case 10: *q++ = u.l;
case 9: *q++ = u.l;
case 8: *q++ = u.l;
case 7: *q++ = u.l;
case 6: *q++ = u.l;
case 5: *q++ = u.l;
case 4: *q++ = u.l;
case 3: *q++ = u.l;
case 2: *q++ = u.l;
default: *q++ = u.l;
}
}
picidx += n;
}

View file

@ -1,6 +1,7 @@
#include <u.h>
#include <libc.h>
#include <thread.h>
#include <emu.h>
#include "dat.h"
#include "fns.h"
@ -475,7 +476,7 @@ audioout(void)
if(sbufp == sbuf)
return 0;
cl = clock;
rc = write(fd, sbuf, (sbufp - sbuf) * 2);
rc = warp10 ? (sbufp - sbuf) * 2 : write(fd, sbuf, (sbufp - sbuf) * 2);
if(rc > 0)
sbufp -= (rc+1)/2;
if(sbufp < sbuf)

View file

@ -1,6 +1,7 @@
#include <u.h>
#include <libc.h>
#include <thread.h>
#include <emu.h>
#include "dat.h"
#include "fns.h"

View file

@ -1,10 +1,6 @@
typedef char s8int;
typedef short s16int;
typedef long s32int;
typedef struct Event Event;
typedef struct MBC3Timer MBC3Timer;
extern int trace;
extern u16int curpc;
extern uchar *rom, *back, reg[256], oam[256];
@ -24,7 +20,6 @@ extern u8int apustatus;
extern u8int mode;
extern u8int mbc, feat;
extern int keys, scale;
enum {
JOYP = 0x00,
@ -129,8 +124,6 @@ enum {
TIMERSIZ = 18,
PICW = 160,
PICH = 144,
MILLION = 1000000,
BILLION = 1000000000,
FREQ = 1<<23
};

View file

@ -2,34 +2,28 @@
#include <libc.h>
#include <thread.h>
#include <draw.h>
#include <mouse.h>
#include <keyboard.h>
#include <emu.h>
#include "dat.h"
#include "fns.h"
int cpuhalt;
int scale, profile;
Rectangle picr;
Image *bg, *tmp;
Mousectl *mc;
int keys, paused, framestep, backup;
QLock pauselock;
int backup;
int savefd = -1, saveframes;
ulong clock;
int savereq, loadreq;
u8int mbc, feat, mode;
extern MBC3Timer timer, timerl;
void *
emalloc(ulong sz)
extern double TAU;
void
tauup(void)
{
void *v;
v = malloc(sz);
if(v == nil)
sysfatal("malloc: %r");
setmalloctag(v, getcallerpc(&sz));
return v;
TAU += 5000;
}
void
taudn(void)
{
TAU -= 5000;
}
void
@ -203,175 +197,15 @@ loadrom(char *file)
}
void
screeninit(void)
{
Point p;
p = divpt(addpt(screen->r.min, screen->r.max), 2);
picr = (Rectangle){subpt(p, Pt(scale * PICW/2, scale * PICH/2)), addpt(p, Pt(scale * PICW/2, scale * PICH/2))};
freeimage(tmp);
tmp = allocimage(display, Rect(0, 0, scale * PICW, scale > 1 ? 1 : scale * PICH), XRGB32, scale > 1, 0);
draw(screen, screen->r, bg, nil, ZP);
}
void
keyproc(void *)
{
int fd, n, k;
static char buf[256];
char *s;
Rune r;
extern double TAU;
fd = open("/dev/kbd", OREAD);
if(fd < 0)
sysfatal("open: %r");
for(;;){
if(buf[0] != 0){
n = strlen(buf)+1;
memmove(buf, buf+n, sizeof(buf)-n);
}
if(buf[0] == 0){
n = read(fd, buf, sizeof(buf)-1);
if(n <= 0)
sysfatal("read /dev/kbd: %r");
buf[n-1] = 0;
buf[n] = 0;
}
if(buf[0] == 'c'){
if(utfrune(buf, KF|5))
savereq = 1;
if(utfrune(buf, KF|6))
loadreq = 1;
if(utfrune(buf, Kdel)){
close(fd);
threadexitsall(nil);
}
if(utfrune(buf, 't'))
trace = !trace;
if(utfrune(buf, KF|9))
TAU += 5000;
if(utfrune(buf, KF|10))
TAU -= 5000;
}
if(buf[0] != 'k' && buf[0] != 'K')
continue;
s = buf + 1;
k = 0;
while(*s != 0){
s += chartorune(&r, s);
switch(r){
case Kdel: close(fd); threadexitsall(nil);
case 'z': k |= 1<<5; break;
case 'x': k |= 1<<4; break;
case Kshift: k |= 1<<6; break;
case 10: k |= 1<<7; break;
case Kup: k |= 1<<2; break;
case Kdown: k |= 1<<3; break;
case Kleft: k |= 1<<1; break;
case Kright: k |= 1<<0; break;
case Kesc:
if(paused)
qunlock(&pauselock);
else
qlock(&pauselock);
paused = !paused;
break;
case KF|1:
if(paused){
qunlock(&pauselock);
paused=0;
}
framestep = !framestep;
break;
}
}
k &= ~(k << 1 & 0x0a | k >> 1 & 0x05);
keys = k;
}
}
void
timing(void)
{
static int fcount;
static vlong old;
static char buf[32];
vlong new;
if(++fcount == 60)
fcount = 0;
else
return;
new = nsec();
if(new != old)
sprint(buf, "%6.2f%%", 1e11 / (new - old));
else
buf[0] = 0;
draw(screen, rectaddpt(Rect(10, 10, 200, 30), screen->r.min), bg, nil, ZP);
string(screen, addpt(screen->r.min, Pt(10, 10)), display->black, ZP, display->defaultfont, buf);
old = nsec();
}
void
flush(void)
{
extern uchar pic[];
Mouse m;
static vlong old, delta;
vlong new, diff;
if(nbrecvul(mc->resizec) > 0){
if(getwindow(display, Refnone) < 0)
sysfatal("resize failed: %r");
screeninit();
}
while(nbrecv(mc->c, &m) > 0)
;
if(scale == 1){
loadimage(tmp, tmp->r, pic, PICW*PICH*4);
draw(screen, picr, tmp, nil, ZP);
} else {
Rectangle r;
uchar *s;
int w;
s = pic;
r = picr;
w = PICW*4*scale;
while(r.min.y < picr.max.y){
loadimage(tmp, tmp->r, s, w);
s += w;
r.max.y = r.min.y+scale;
draw(screen, r, tmp, nil, ZP);
r.min.y = r.max.y;
}
}
flushimage(display, 1);
if(profile)
timing();
if(audioout() < 0){
new = nsec();
diff = 0;
if(old != 0){
diff = BILLION/60 - (new - old) - delta;
if(diff >= MILLION)
sleep(diff/MILLION);
}
old = nsec();
if(diff != 0){
diff = (old - new) - (diff / MILLION) * MILLION;
delta += (diff - delta) / 100;
}
}
if(framestep){
paused = 1;
qlock(&pauselock);
framestep = 0;
}
flushmouse(1);
flushscreen();
flushaudio(audioout);
if(saveframes > 0 && --saveframes == 0)
flushback();
if(savereq){
@ -430,20 +264,10 @@ threadmain(int argc, char **argv)
int t;
colinit();
scale = 1;
ARGBEGIN {
case '2':
scale = 2;
break;
case '3':
scale = 3;
break;
case 'a':
audioinit();
break;
case 'T':
profile++;
break;
case 'c':
mode |= CGB;
break;
@ -460,15 +284,17 @@ threadmain(int argc, char **argv)
usage();
loadrom(argv[0]);
if(initdraw(nil, nil, nil) < 0)
sysfatal("initdraw: %r");
mc = initmouse(nil, screen);
if(mc == nil)
sysfatal("initmouse: %r");
proccreate(keyproc, nil, mainstacksize);
bg = allocimage(display, Rect(0, 0, 1, 1), screen->chan, 1, 0xCCCCCCFF);
screeninit();
initemu(PICW, PICH, 4, XRGB32, 1, nil);
regkey("b", 'z', 1<<5);
regkey("a", 'x', 1<<4);
regkey("control", Kshift, 1<<6);
regkey("start", '\n', 1<<7);
regkey("up", Kup, 1<<2);
regkey("down", Kdown, 1<<3);
regkey("left", Kleft, 1<<1);
regkey("right", Kright, 1<<0);
regkeyfn(KF|9, tauup);
regkeyfn(KF|10, taudn);
eventinit();
meminit();

View file

@ -1,6 +1,7 @@
#include <u.h>
#include <libc.h>
#include <thread.h>
#include <emu.h>
#include "dat.h"
#include "fns.h"

View file

@ -1,11 +1,11 @@
#include <u.h>
#include <libc.h>
#include <thread.h>
#include <emu.h>
#include "dat.h"
#include "fns.h"
u8int ppustate, ppuy;
u32int pic[PICW*PICH*3];
ulong hblclock, rendclock;
jmp_buf mainjmp, renderjmp;
static int cyc, done, ppux, ppux0;
@ -63,7 +63,7 @@ ppurender(void)
}
ppux = 0;
ppux0 = 0;
picp = pic + ppuy * PICW * scale;
picp = (u32int*)pic + ppuy * PICW * scale;
y = ppuy + reg[SCY] << 1 & 14;
ta = 0x1800 | reg[LCDC] << 7 & 0x400 | ppuy + reg[SCY] << 2 & 0x3e0 | reg[SCX] >> 3;
x = -(reg[SCX] & 7);
@ -197,7 +197,7 @@ sprites(void)
int x, x1;
u16int chr;
picp = pic + ppuy * PICW * scale;
picp = (u32int*)pic + ppuy * PICW * scale;
for(q = spr; q < sprm; q++){
if(q->x <= ppux0 || q->x >= ppux + 8)
continue;
@ -254,18 +254,31 @@ static void
lineexpand(void)
{
u32int *picp, *p, *q, l;
int i, s;
int i;
s = scale;
picp = pic + ppuy * PICW * s;
picp = (u32int*)pic + ppuy * PICW * scale;
p = picp + PICW;
q = picp + PICW * scale;
for(i = PICW; --i >= 0; ){
l = *--p;
*--q = l;
*--q = l;
if(scale == 3)
*--q = l;
switch(scale){
case 16: *--q = l;
case 15: *--q = l;
case 14: *--q = l;
case 13: *--q = l;
case 12: *--q = l;
case 11: *--q = l;
case 10: *--q = l;
case 9: *--q = l;
case 8: *--q = l;
case 7: *--q = l;
case 6: *--q = l;
case 5: *--q = l;
case 4: *--q = l;
case 3: *--q = l;
case 2: *--q = l;
case 1: *--q = l;
}
}
}

View file

@ -1,6 +1,7 @@
#include <u.h>
#include <libc.h>
#include <thread.h>
#include <emu.h>
#include "dat.h"
#include "fns.h"
@ -350,7 +351,7 @@ sndwrite(u16int a, u16int v)
void
audioinit(void)
{
fd = open("/dev/audio", OWRITE);
fd = open("/dev/audio", OWRITE);
if(fd < 0)
sysfatal("open: %r");
sbufp = sbuf;
@ -370,7 +371,7 @@ audioout(void)
if(sbufp == sbuf)
return 0;
cl = clock;
rc = write(fd, sbuf, (sbufp - sbuf) * 2);
rc = warp10 ? (sbufp - sbuf) * 2 : write(fd, sbuf, (sbufp - sbuf) * 2);
if(rc > 0)
sbufp -= (rc+1)/2;
if(sbufp < sbuf)

View file

@ -1,6 +1,7 @@
#include <u.h>
#include <libc.h>
#include <thread.h>
#include <emu.h>
#include "dat.h"
#include "fns.h"
@ -34,7 +35,7 @@ u32int curpc;
int irq;
u32int instr0, instr1, pipel = -1;
int cyc, trace;
int cyc;
Var cpuvars[] = {
ARR(r), VAR(cpsr), VAR(spsr), ARR(saver), VAR(irq),

View file

@ -1,9 +1,4 @@
typedef char s8int;
typedef short s16int;
typedef long s32int;
typedef vlong s64int;
extern int cpuhalt, trace, keys;
extern int cpuhalt;
extern u32int curpc;
extern int irq;
@ -18,7 +13,6 @@ extern int nrom, nback, backup;
extern int hblank, ppuy;
extern int clock;
extern int scale;
typedef struct Event Event;
struct Event {
@ -141,8 +135,6 @@ enum {
KB = 1024,
BACKTYPELEN = 64,
HZ = 16777216,
MILLION = 1000000,
BILLION = 1000000000,
};
typedef struct Var Var;

View file

@ -2,36 +2,19 @@
#include <libc.h>
#include <thread.h>
#include <draw.h>
#include <mouse.h>
#include <keyboard.h>
#include <emu.h>
#include "dat.h"
#include "fns.h"
int cpuhalt;
int scale, profile;
Rectangle picr;
Image *bg, *tmp;
Mousectl *mc;
int keys, paused, framestep, backup;
QLock pauselock;
Image *tmp;
int backup;
int savefd, saveframes;
int clock;
int savereq, loadreq;
char *biosfile = "/sys/games/lib/gbabios.bin";
void *
emalloc(ulong sz)
{
void *v;
v = malloc(sz);
if(v == nil)
sysfatal("malloc: %r");
setmalloctag(v, getcallerpc(&sz));
return v;
}
void
writeback(void)
{
@ -211,173 +194,15 @@ loadrom(char *file)
nrom -= 256;
}
void
screeninit(void)
{
Point p;
p = divpt(addpt(screen->r.min, screen->r.max), 2);
picr = (Rectangle){subpt(p, Pt(scale * 120, scale * 80)), addpt(p, Pt(scale * 120, scale * 80))};
freeimage(tmp);
tmp = allocimage(display, Rect(0, 0, scale * 240, scale > 1 ? 1 : scale * 160), CHAN4(CIgnore, 1, CBlue, 5, CGreen, 5, CRed, 5), scale > 1, 0);
draw(screen, screen->r, bg, nil, ZP);
}
void
keyproc(void *)
{
int fd, n, k;
static char buf[256];
char *s;
Rune r;
fd = open("/dev/kbd", OREAD);
if(fd < 0)
sysfatal("open: %r");
for(;;){
if(buf[0] != 0){
n = strlen(buf)+1;
memmove(buf, buf+n, sizeof(buf)-n);
}
if(buf[0] == 0){
n = read(fd, buf, sizeof(buf)-1);
if(n <= 0)
sysfatal("read /dev/kbd: %r");
buf[n-1] = 0;
buf[n] = 0;
}
if(buf[0] == 'c'){
if(utfrune(buf, KF|5))
savereq = 1;
if(utfrune(buf, KF|6))
loadreq = 1;
if(utfrune(buf, Kdel)){
close(fd);
threadexitsall(nil);
}
if(utfrune(buf, 't'))
trace = !trace;
}
if(buf[0] != 'k' && buf[0] != 'K')
continue;
s = buf + 1;
k = 0;
while(*s != 0){
s += chartorune(&r, s);
switch(r){
case Kdel: close(fd); threadexitsall(nil);
case 'z': k |= 1<<1; break;
case 'x': k |= 1<<0; break;
case 'a': k |= 1<<9; break;
case 's': k |= 1<<8; break;
case Kshift: k |= 1<<2; break;
case 10: k |= 1<<3; break;
case Kup: k |= 1<<6; break;
case Kdown: k |= 1<<7; break;
case Kleft: k |= 1<<5; break;
case Kright: k |= 1<<4; break;
case Kesc:
if(paused)
qunlock(&pauselock);
else
qlock(&pauselock);
paused = !paused;
break;
case KF|1:
if(paused){
qunlock(&pauselock);
paused=0;
}
framestep = !framestep;
break;
}
}
k &= ~(k << 1 & 0xa0 | k >> 1 & 0x50);
keys = k;
}
}
void
timing(void)
{
static int fcount;
static vlong old;
static char buf[32];
vlong new;
if(++fcount == 60)
fcount = 0;
else
return;
new = nsec();
if(new != old)
sprint(buf, "%6.2f%%", 1e11 / (new - old));
else
buf[0] = 0;
draw(screen, rectaddpt(Rect(10, 10, 200, 30), screen->r.min), bg, nil, ZP);
string(screen, addpt(screen->r.min, Pt(10, 10)), display->black, ZP, display->defaultfont, buf);
old = nsec();
}
void
flush(void)
{
extern uchar pic[];
Mouse m;
int x;
static vlong old, delta;
vlong new, diff;
if(nbrecvul(mc->resizec) > 0){
if(getwindow(display, Refnone) < 0)
sysfatal("resize failed: %r");
screeninit();
}
while(nbrecv(mc->c, &m) > 0)
;
if(scale == 1){
loadimage(tmp, tmp->r, pic, 240*160*2);
draw(screen, picr, tmp, nil, ZP);
} else {
Rectangle r;
uchar *s;
int w;
flushmouse(1);
flushscreen();
flushaudio(audioout);
s = pic;
r = picr;
w = 240*2*scale;
while(r.min.y < picr.max.y){
loadimage(tmp, tmp->r, s, w);
s += w;
r.max.y = r.min.y+scale;
draw(screen, r, tmp, nil, ZP);
r.min.y = r.max.y;
}
}
flushimage(display, 1);
if(profile)
timing();
if(audioout() < 0){
new = nsec();
diff = 0;
if(old != 0){
diff = BILLION/60 - (new - old) - delta;
if(diff >= MILLION)
sleep(diff/MILLION);
}
old = nsec();
if(diff != 0){
diff = (old - new) - (diff / MILLION) * MILLION;
delta += (diff - delta) / 100;
}
}
if(framestep){
paused = 1;
qlock(&pauselock);
framestep = 0;
}
if(saveframes > 0 && --saveframes == 0)
flushback();
@ -395,7 +220,7 @@ flush(void)
void
usage(void)
{
fprint(2, "usage: %s [-23aT] [-s savetype] [-b biosfile] rom\n", argv0);
fprint(2, "usage: %s [-aT] [-s savetype] [-b biosfile] rom\n", argv0);
exits("usage");
}
@ -405,14 +230,7 @@ threadmain(int argc, char **argv)
char *s;
int t;
scale = 1;
ARGBEGIN {
case '2':
scale = 2;
break;
case '3':
scale = 3;
break;
case 'a':
audioinit();
break;
@ -425,9 +243,6 @@ threadmain(int argc, char **argv)
case 'b':
biosfile = strdup(EARGF(usage()));
break;
case 'T':
profile++;
break;
default:
usage();
} ARGEND;
@ -436,16 +251,17 @@ threadmain(int argc, char **argv)
loadbios();
loadrom(argv[0]);
if(initdraw(nil, nil, nil) < 0)
sysfatal("initdraw: %r");
mc = initmouse(nil, screen);
if(mc == nil)
sysfatal("initmouse: %r");
proccreate(keyproc, nil, mainstacksize);
bg = allocimage(display, Rect(0, 0, 1, 1), screen->chan, 1, 0xCCCCCCFF);
screeninit();
initemu(240, 160, 2, CHAN4(CIgnore, 1, CBlue, 5, CGreen, 5, CRed, 5), 1, nil);
regkey("b", 'z', 1<<1);
regkey("a", 'x', 1<<0);
regkey("l1", 'a', 1<<9);
regkey("r1", 's', 1<<8);
regkey("control", Kshift, 1<<2);
regkey("start", '\n', 1<<3);
regkey("up", Kup, 1<<6);
regkey("down", Kdown, 1<<7);
regkey("left", Kleft, 1<<5);
regkey("right", Kright, 1<<4);
eventinit();
memreset();
reset();

View file

@ -1,6 +1,7 @@
#include <u.h>
#include <libc.h>
#include <thread.h>
#include <emu.h>
#include "dat.h"
#include "fns.h"

View file

@ -1,6 +1,7 @@
#include <u.h>
#include <libc.h>
#include <thread.h>
#include <emu.h>
#include "dat.h"
#include "fns.h"
@ -11,7 +12,6 @@ int ppux0;
u32int pixcol[480];
u8int pixpri[480];
u8int pixwin[240];
uchar pic[240*160*3*2];
int objalpha;
typedef struct bg bg;
@ -642,40 +642,6 @@ colormath(int x1)
}
}
void
linecopy(void)
{
u32int *p;
uchar *q;
u16int *r;
u16int v;
union { u16int w; u8int b[2]; } u;
int n;
p = pixcol;
q = pic + ppuy * 240 * 2 * scale;
r = (u16int*)q;
n = 240;
while(n--){
v = *p++;
if(scale == 1){
*q++ = v;
*q++ = v >> 8;
continue;
}
u.b[0] = v;
u.b[1] = v >> 8;
if(scale == 2){
*r++ = u.w;
*r++ = u.w;
}else{
*r++ = u.w;
*r++ = u.w;
*r++ = u.w;
}
}
}
void
syncppu(int x1)
{
@ -724,6 +690,43 @@ syncppu(int x1)
ppux0 = x1;
}
void
linecopy(u32int *p, int y)
{
uchar *q;
u16int *r;
u16int v;
union { u16int w; u8int b[2]; } u;
int n;
q = pic + y * 240 * 2 * scale;
r = (u16int*)q;
n = 240;
while(n--){
v = *p++;
u.b[0] = v;
u.b[1] = v >> 8;
switch(scale){
case 16: *r++ = u.w;
case 15: *r++ = u.w;
case 14: *r++ = u.w;
case 13: *r++ = u.w;
case 12: *r++ = u.w;
case 11: *r++ = u.w;
case 10: *r++ = u.w;
case 9: *r++ = u.w;
case 8: *r++ = u.w;
case 7: *r++ = u.w;
case 6: *r++ = u.w;
case 5: *r++ = u.w;
case 4: *r++ = u.w;
case 3: *r++ = u.w;
case 2: *r++ = u.w;
default: *r++ = u.w;
}
}
}
void
hblanktick(void *)
{
@ -755,7 +758,7 @@ hblanktick(void *)
}else{
syncppu(240);
if(ppuy < 160)
linecopy();
linecopy(pixcol, ppuy);
addevent(&evhblank, 68*4);
hblank = 1;
if((stat & IRQHBLEN) != 0)

View file

@ -1,6 +1,7 @@
#include <u.h>
#include <libc.h>
#include <thread.h>
#include <emu.h>
#include "dat.h"
#include "fns.h"
@ -19,7 +20,7 @@ extern u32int irql[8];
u32int irqla[8];
u16int rS;
static u32int op;
int trace, tim;
int tim;
#define ra (r+8)
static void

View file

@ -1,9 +1,4 @@
typedef signed char s8int;
typedef signed short s16int;
typedef signed long s32int;
extern u32int curpc, irq;
extern int trace, debug;
extern u8int reg[32];
extern u8int dma;
@ -18,8 +13,6 @@ extern u8int *sram;
extern u32int sramctl, sram0, sram1;
extern int savefd, saveclock;
extern int keys, scale;
extern u16int vram[32768], vsram[40];
extern u32int cramc[64];
extern u16int vdpstat;
@ -82,8 +75,6 @@ enum {
RATE = 44100,
SAMPDIV = FREQ / RATE,
SAVEFREQ = FREQ / 4,
MILLION = 1000 * 1000,
BILLION = 1000 * 1000 * 1000,
};
enum {

View file

@ -3,29 +3,18 @@
#include <thread.h>
#include <draw.h>
#include <keyboard.h>
#include <mouse.h>
#include <emu.h>
#include "dat.h"
#include "fns.h"
int debug;
u16int *prg;
int nprg;
u8int *sram;
u32int sramctl, nsram, sram0, sram1;
int savefd = -1;
int keys;
int dmaclock, vdpclock, z80clock, audioclock, ymclock, saveclock;
int scale, paused;
QLock pauselock;
Mousectl *mc;
Channel *flushc;
Rectangle picr;
Image *tmp, *bg;
void
flushram(void)
{
@ -113,147 +102,15 @@ loadrom(char *file)
}
}
void
screeninit(void)
{
Point p;
originwindow(screen, Pt(0, 0), screen->r.min);
p = divpt(addpt(screen->r.min, screen->r.max), 2);
picr = (Rectangle){subpt(p, Pt(scale * 160, scale * 112)), addpt(p, Pt(scale * 160, scale * 112))};
if(tmp != nil) freeimage(tmp);
tmp = allocimage(display, Rect(0, 0, scale * 320, scale > 1 ? 1 : scale * 224), XRGB32, scale > 1, 0);
if(bg != nil) freeimage(bg);
bg = allocimage(display, Rect(0, 0, 1, 1), screen->chan, 1, 0xCCCCCCFF);
draw(screen, screen->r, bg, nil, ZP);
}
void
screenproc(void *)
{
extern u8int pic[320*224*4*4];
extern int intla;
Rectangle r;
uchar *s;
int w, h;
enum { AMOUSE, ARESIZE, AFLUSH, AEND };
Alt a[AEND+1] = {
{ mc->c, nil, CHANRCV },
{ mc->resizec, nil, CHANRCV },
{ flushc, nil, CHANRCV },
{ nil, nil, CHANEND }
};
for(;;){
switch(alt(a)){
case ARESIZE:
if(getwindow(display, Refnone) < 0)
sysfatal("resize failed: %r");
screeninit();
/* wet floor */
case AFLUSH:
if(scale == 1){
loadimage(tmp, tmp->r, pic, 320*224*4);
draw(screen, picr, tmp, nil, ZP);
}else{
s = pic;
r = picr;
w = 320*4*scale;
h = scale;
if(intla && (h & 1) == 0)
h >>= 1;
while(r.min.y < picr.max.y){
loadimage(tmp, tmp->r, s, w);
s += w;
r.max.y = r.min.y+h;
draw(screen, r, tmp, nil, ZP);
r.min.y = r.max.y;
}
}
flushimage(display, 1);
break;
}
}
}
void
keyproc(void *)
{
int fd, n, k;
static char buf[256];
char *s;
Rune r;
fd = open("/dev/kbd", OREAD);
if(fd < 0)
sysfatal("open: %r");
for(;;){
if(buf[0] != 0){
n = strlen(buf)+1;
memmove(buf, buf+n, sizeof(buf)-n);
}
if(buf[0] == 0){
n = read(fd, buf, sizeof(buf)-1);
if(n <= 0)
sysfatal("read /dev/kbd: %r");
buf[n-1] = 0;
buf[n] = 0;
}
if(buf[0] == 'c'){
if(utfrune(buf, Kdel)){
close(fd);
threadexitsall(nil);
}
if(utfrune(buf, 't'))
trace = !trace;
}
if(buf[0] != 'k' && buf[0] != 'K')
continue;
s = buf + 1;
k = 0xc00;
while(*s != 0){
s += chartorune(&r, s);
if(r >= '0' && r <= '9') debug = r - '0';
switch(r){
case Kdel: close(fd); threadexitsall(nil);
case 'c': k |= 0x0020; break;
case 'x': k |= 0x0010; break;
case 'z': k |= 0x1000; break;
case 10: k |= 0x2000; break;
case Kup: k |= 0x0101; break;
case Kdown: k |= 0x0202; break;
case Kleft: k |= 0x0004; break;
case Kright: k |= 0x0008; break;
case Kesc:
if(paused)
qunlock(&pauselock);
else
qlock(&pauselock);
paused = !paused;
break;
}
}
keys = ~k;
}
}
void
threadmain(int argc, char **argv)
{
int t;
scale = 1;
ARGBEGIN{
case 'a':
initaudio();
break;
case '2':
scale = 2;
break;
case '3':
scale = 3;
break;
default:
;
} ARGEND;
@ -263,15 +120,15 @@ threadmain(int argc, char **argv)
threadexitsall("usage");
}
loadrom(*argv);
if(initdraw(nil, nil, argv0) < 0)
sysfatal("initdraw: %r");
flushc = chancreate(sizeof(ulong), 1);
mc = initmouse(nil, screen);
if(mc == nil)
sysfatal("initmouse: %r");
screeninit();
proccreate(keyproc, nil, 8192);
proccreate(screenproc, nil, 8192);
initemu(320, 224, 4, XRGB32, 1, nil);
regkey("a", 'c', 1<<5);
regkey("b", 'x', 1<<4);
regkey("y", 'z', 1<<12);
regkey("start", '\n', 1<<13);
regkey("up", Kup, 0x101);
regkey("down", Kdown, 0x202);
regkey("left", Kleft, 1<<2);
regkey("right", Kright, 1<<3);
cpureset();
vdpmode();
ymreset();
@ -320,22 +177,7 @@ threadmain(int argc, char **argv)
void
flush(void)
{
static vlong old, delta;
vlong new, diff;
sendul(flushc, 1); /* flush screen */
if(audioout() < 0){
new = nsec();
diff = 0;
if(old != 0){
diff = BILLION/60 - (new - old) - delta;
if(diff >= MILLION)
sleep(diff/MILLION);
}
old = nsec();
if(diff != 0){
diff = (old - new) - (diff / MILLION) * MILLION;
delta += (diff - delta) / 100;
}
}
flushmouse(1);
flushscreen();
flushaudio(audioout);
}

View file

@ -1,6 +1,7 @@
#include <u.h>
#include <libc.h>
#include <thread.h>
#include <emu.h>
#include "dat.h"
#include "fns.h"
@ -31,7 +32,7 @@ regread(u16int a)
switch(a | 1){
case 0x0001: return 0xa0;
case 0x0003:
v = keys;
v = ~(keys & 0xffff);
if((ctl[0] & 0x40) == 0)
v >>= 8;
return ctl[0] & 0xc0 | v & 0x3f;

View file

@ -1,10 +1,10 @@
#include <u.h>
#include <libc.h>
#include <thread.h>
#include <emu.h>
#include "dat.h"
#include "fns.h"
u8int pic[320*224*4*4];
u16int vdpstat = 0x3400;
int vdpx, vdpy, vdpyy, frame, intla;
u16int hctr;
@ -29,32 +29,31 @@ vdpmode(void)
static void
pixeldraw(int x, int y, int v)
{
u8int *p;
u32int *q;
union { u32int w; u8int b[4]; } u;
u32int *p;
union { u32int l; u8int b[4]; } u;
if(scale == 1){
p = pic + (x + y * 320) * 4;
p[0] = v >> 16;
p[1] = v >> 8;
p[2] = v;
return;
}
p = (u32int *)pic + (x + y * 320) * scale;
u.b[0] = v >> 16;
u.b[1] = v >> 8;
u.b[2] = v;
u.b[3] = 0;
if(scale == 2){
if(intla)
y = y << 1 | frame;
q = (u32int*)pic + (x + y * 320) * 2;
q[0] = u.w;
q[1] = u.w;
}else{
q = (u32int*)pic + (x + y * 320) * 3;
q[0] = u.w;
q[1] = u.w;
q[2] = u.w;
switch(scale){
case 16: *p++ = u.l;
case 15: *p++ = u.l;
case 14: *p++ = u.l;
case 13: *p++ = u.l;
case 12: *p++ = u.l;
case 11: *p++ = u.l;
case 10: *p++ = u.l;
case 9: *p++ = u.l;
case 8: *p++ = u.l;
case 7: *p++ = u.l;
case 6: *p++ = u.l;
case 5: *p++ = u.l;
case 4: *p++ = u.l;
case 3: *p++ = u.l;
case 2: *p++ = u.l; /* intla ignored */
default: *p = u.l;
}
}

View file

@ -1,11 +1,10 @@
#include <u.h>
#include <libc.h>
#include <thread.h>
#include <emu.h>
#include "dat.h"
#include "fns.h"
extern int debug;
u8int ym[512];
enum {
MODE = 0x27,
@ -436,7 +435,7 @@ audioout(void)
return -1;
if(sbufp == sbuf)
return 0;
rc = write(fd, sbuf, (sbufp - sbuf) * 2);
rc = warp10 ? (sbufp - sbuf) * 2 : write(fd, sbuf, (sbufp - sbuf) * 2);
if(rc > 0)
sbufp -= (rc+1)/2;
if(sbufp < sbuf)

View file

@ -2,6 +2,7 @@
#include <libc.h>
#include <thread.h>
#include <draw.h>
#include <emu.h>
#include "dat.h"
#include "fns.h"
@ -279,7 +280,7 @@ audioout(void)
return -1;
if(sbufp == sbuf)
return 0;
rc = write(fd, sbuf, (sbufp - sbuf) * 2);
rc = warp10 ? (sbufp - sbuf) * 2 : write(fd, sbuf, (sbufp - sbuf) * 2);
if(rc > 0)
sbufp -= (rc+1)/2;
if(sbufp < sbuf)

View file

@ -6,14 +6,14 @@ extern u16int pput, ppuv;
extern u8int ppusx, vrambuf;
extern int mirr, ppux, ppuy, odd, vramlatch, keylatch, keylatch2;
extern int map, scale, mmc3hack, oflag;
extern int map, mmc3hack, oflag;
extern uchar *prg, *chr;
extern int nprg, nchr, map, chrram;
extern u8int apuseq, apuctr[13];
extern u16int dmcaddr, dmccnt;
extern int keys, keys2, clock, ppuclock, apuclock, dmcclock, dmcfreq, saveclock, paused;
extern int clock, ppuclock, apuclock, dmcclock, dmcfreq, saveclock;
extern void (*mapper[])(int, u8int);
@ -78,8 +78,6 @@ enum {
enum {
FREQ = 21477272,
MILLION = 1000000,
BILLION = 1000000000,
APUDIV = 89490,
RATE = 44100,
SAMPDIV = FREQ / RATE,

View file

@ -2,6 +2,7 @@
#include <libc.h>
#include <thread.h>
#include <draw.h>
#include <emu.h>
#include "dat.h"
#include "fns.h"

View file

@ -2,22 +2,17 @@
#include <libc.h>
#include <draw.h>
#include <thread.h>
#include <mouse.h>
#include <keyboard.h>
#include <emu.h>
#include "dat.h"
#include "fns.h"
extern uchar ppuram[16384];
int nprg, nchr, map, chrram;
uchar *prg, *chr;
int scale;
Rectangle picr;
Image *tmp, *bg;
int clock, ppuclock, apuclock, dmcclock, dmcfreq, sampclock, msgclock, saveclock;
Mousectl *mc;
int keys, keys2, paused, savereq, loadreq, oflag, savefd = -1;
int oflag, savefd = -1;
int mirr;
QLock pauselock;
void
message(char *fmt, ...)
@ -122,139 +117,18 @@ loadrom(char *file, int sflag)
mapper[map](INIT, 0);
}
extern int trace;
void
joyproc(void *)
{
char *s, *down[9];
static char buf[64];
int n, k, j;
j = 1;
for(;;){
n = read(0, buf, sizeof(buf) - 1);
if(n <= 0)
sysfatal("read: %r");
buf[n] = 0;
n = getfields(buf, down, nelem(down), 1, " ");
k = 0;
for(n--; n >= 0; n--){
s = down[n];
if(strcmp(s, "joy1") == 0)
j = 1;
else if(strcmp(s, "joy2") == 0)
j = 2;
else if(strcmp(s, "a") == 0)
k |= 1<<0;
else if(strcmp(s, "b") == 0)
k |= 1<<1;
else if(strcmp(s, "control") == 0)
k |= 1<<2;
else if(strcmp(s, "start") == 0)
k |= 1<<3;
else if(strcmp(s, "up") == 0)
k |= 1<<4;
else if(strcmp(s, "down") == 0)
k |= 1<<5;
else if(strcmp(s, "left") == 0)
k |= 1<<6;
else if(strcmp(s, "right") == 0)
k |= 1<<7;
}
if(j == 2)
keys2 = k;
else
keys = k;
}
}
void
keyproc(void *)
{
int fd, n, k;
static char buf[256];
char *s;
Rune r;
fd = open("/dev/kbd", OREAD);
if(fd < 0)
sysfatal("open: %r");
for(;;){
if(buf[0] != 0){
n = strlen(buf)+1;
memmove(buf, buf+n, sizeof(buf)-n);
}
if(buf[0] == 0){
n = read(fd, buf, sizeof(buf)-1);
if(n <= 0)
sysfatal("read /dev/kbd: %r");
buf[n-1] = 0;
buf[n] = 0;
}
if(buf[0] == 'c'){
if(utfrune(buf, Kdel)){
close(fd);
threadexitsall(nil);
}
if(utfrune(buf, KF|5))
savereq = 1;
if(utfrune(buf, KF|6))
loadreq = 1;
if(utfrune(buf, 't'))
trace ^= 1;
}
if(buf[0] != 'k' && buf[0] != 'K')
continue;
s = buf + 1;
k = 0;
while(*s != 0){
s += chartorune(&r, s);
switch(r){
case Kdel: close(fd); threadexitsall(nil);
case 'x': k |= 1<<0; break;
case 'z': k |= 1<<1; break;
case Kshift: k |= 1<<2; break;
case 10: k |= 1<<3; break;
case Kup: k |= 1<<4; break;
case Kdown: k |= 1<<5; break;
case Kleft: k |= 1<<6; break;
case Kright: k |= 1<<7; break;
case Kesc:
if(paused)
qunlock(&pauselock);
else
qlock(&pauselock);
paused = !paused;
break;
}
}
keys = k;
}
}
void
threadmain(int argc, char **argv)
{
int t, h, sflag;
Point p;
int t, sflag;
scale = 1;
h = 240;
sflag = 0;
ARGBEGIN {
case 'a':
initaudio();
break;
case '2':
scale = 2;
break;
case '3':
scale = 3;
break;
case 'o':
oflag = 1;
h -= 16;
break;
case 's':
sflag = 1;
@ -269,20 +143,16 @@ threadmain(int argc, char **argv)
threadexitsall("usage");
}
loadrom(argv[0], sflag);
if(initdraw(nil, nil, nil) < 0)
sysfatal("initdraw: %r");
mc = initmouse(nil, screen);
if(mc == nil)
sysfatal("initmouse: %r");
proccreate(joyproc, nil, 8192);
proccreate(keyproc, nil, 8192);
originwindow(screen, Pt(0, 0), screen->r.min);
p = divpt(addpt(screen->r.min, screen->r.max), 2);
picr = (Rectangle){subpt(p, Pt(scale * 128, scale * h/2)), addpt(p, Pt(scale * 128, scale * h/2))};
tmp = allocimage(display, Rect(0, 0, scale * 256, scale * h), XRGB32, 0, 0);
bg = allocimage(display, Rect(0, 0, 1, 1), screen->chan, 1, 0xCCCCCCFF);
draw(screen, screen->r, bg, nil, ZP);
initemu(256, 240 - oflag * 16, 4, XRGB32, 1, nil);
regkey("b", 'z', 1<<1);
regkey("a", 'x', 1<<0);
regkey("control", Kshift, 1<<2);
regkey("start", '\n', 1<<3);
regkey("up", Kup, 1<<4);
regkey("down", Kdown, 1<<5);
regkey("left", Kleft, 1<<6);
regkey("right", Kright, 1<<7);
pc = memread(0xFFFC) | memread(0xFFFD) << 8;
rP = FLAGI;
dmcfreq = 12 * 428;
@ -324,7 +194,8 @@ threadmain(int argc, char **argv)
if(msgclock > 0){
msgclock -= t;
if(msgclock <= 0){
draw(screen, screen->r, bg, nil, ZP);
extern Image *bg;
draw(screen, screen->r, bg, nil, ZP);
msgclock = 0;
}
}

View file

@ -3,18 +3,17 @@
#include <thread.h>
#include <draw.h>
#include <mouse.h>
#include <emu.h>
#include "dat.h"
#include "fns.h"
int ppuy, ppux, odd;
uchar pic[256*240*4*9];
static void
pixel(int x, int y, int val, int back)
{
int Y;
union { u8int c[4]; u32int l; } u;
u32int *p, l;
u32int *p;
static u8int palred[64] = {
0x7C, 0x00, 0x00, 0x44, 0x94, 0xA8, 0xA8, 0x88,
0x50, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
@ -50,32 +49,31 @@ pixel(int x, int y, int val, int back)
u.c[1] = palgreen[val];
u.c[2] = palred[val];
u.c[3] = back ? 0 : 0xFF;
l = u.l;
if(scale == 3){
p = ((u32int*)pic) + y * 3 * 3 * 256 + 3 * x;
for(Y = 0; Y < 3; Y++){
*p++ = l;
*p++ = l;
*p = l;
p += 3 * 256 - 2;
}
}else if(scale == 2){
p = ((u32int*)pic) + y * 2 * 2 * 256 + 2 * x;
*p++ = l;
*p = l;
p += 2 * 256 - 1;
*p++ = l;
*p = l;
}else{
p = ((u32int*)pic) + y * 256 + x;
*p = l;
p = (u32int *)pic + y * 256 * scale + x * scale;
switch(scale){
case 16: *p++ = u.l;
case 15: *p++ = u.l;
case 14: *p++ = u.l;
case 13: *p++ = u.l;
case 12: *p++ = u.l;
case 11: *p++ = u.l;
case 10: *p++ = u.l;
case 9: *p++ = u.l;
case 8: *p++ = u.l;
case 7: *p++ = u.l;
case 6: *p++ = u.l;
case 5: *p++ = u.l;
case 4: *p++ = u.l;
case 3: *p++ = u.l;
case 2: *p++ = u.l;
default: *p = u.l;
}
}
static int
iscolor(int x, int y)
{
return pic[y * scale * scale * 256 * 4 + x * scale * 4 + 3] != 0;
return pic[(scale * 4) * (y * 256 + x) + 3] != 0;
}
static int
@ -252,52 +250,9 @@ drawsprites(int show)
static void
flush(void)
{
extern Rectangle picr;
extern Image *tmp, *bg;
extern Mousectl *mc;
static vlong old, delta;
vlong new, diff;
Mouse m;
Point p;
int h;
h = 240;
if(oflag)
h -= 16;
while(nbrecv(mc->c, &m) > 0)
;
if(nbrecvul(mc->resizec) > 0){
if(getwindow(display, Refnone) < 0)
sysfatal("resize failed: %r");
p = divpt(addpt(screen->r.min, screen->r.max), 2);
picr = (Rectangle){subpt(p, Pt(scale * 128, scale * h/2)), addpt(p, Pt(scale * 128, scale * h/2))};
if(bg->chan != screen->chan){
freeimage(bg);
bg = allocimage(display, Rect(0, 0, 1, 1), screen->chan, 1, 0xCCCCCCFF);
}
draw(screen, screen->r, bg, nil, ZP);
}
if(screen->chan != tmp->chan || !rectinrect(picr, screen->r)){
loadimage(tmp, tmp->r, pic + oflag*8*256*4*scale*scale, 256*h*4*scale*scale);
draw(screen, picr, tmp, nil, ZP);
}else
loadimage(screen, picr, pic + oflag*8*256*4*scale*scale, 256*h*4*scale*scale);
flushimage(display, 1);
memset(pic, sizeof pic, 0);
if(audioout() < 0){
new = nsec();
diff = 0;
if(old != 0){
diff = BILLION/60 - (new - old) - delta;
if(diff >= MILLION)
sleep(diff/MILLION);
}
old = nsec();
if(diff != 0){
diff = (old - new) - (diff / MILLION) * MILLION;
delta += (diff - delta) / 100;
}
}
flushmouse(1);
flushscreen();
flushaudio(audioout);
}
void

View file

@ -1,6 +1,7 @@
#include <u.h>
#include <libc.h>
#include <thread.h>
#include <emu.h>
#include "dat.h"
#include "fns.h"
@ -640,8 +641,6 @@ cpureset(void)
rP = 0x35;
}
int trace;
int
cpustep(void)
{

View file

@ -1,14 +1,10 @@
typedef signed char s8int;
typedef signed short s16int;
extern u8int rP, dma, nmi, irq, emu, wai;
extern u16int rA, rX, rY, rS, rD, pc;
extern u32int rPB, rDB, curpc, hdma;
extern int trace;
extern uchar *prg, *sram;
extern int nprg, nsram, hirom;
extern u32int keys, keylatch, lastkeys;
extern u32int keylatch, lastkeys;
extern u8int reg[32768], mem[131072], spcmem[65536], vram[65536], oam[544];
extern u16int cgram[256], vramlatch;
extern u8int mdr, mdr1, mdr2;
@ -25,7 +21,7 @@ extern u8int dspstate;
extern u16int dspcounter, noise;
extern int ppuclock, spcclock, dspclock, stimerclock, cpupause;
extern int battery, saveclock, scale, mouse;
extern int battery, saveclock, mouse;
enum {
FLAGC = 1<<0,

View file

@ -1,6 +1,7 @@
#include <u.h>
#include <libc.h>
#include <thread.h>
#include <emu.h>
#include "dat.h"
#include "fns.h"
@ -77,7 +78,7 @@ audioout(void)
return -1;
if(sbufp == sbuf)
return 0;
rc = write(fd, sbuf, (sbufp - sbuf) * 2);
rc = warp10 ? (sbufp - sbuf) * 2 : write(fd, sbuf, (sbufp - sbuf) * 2);
if(rc > 0)
sbufp -= (rc+1)/2;
if(sbufp < sbuf)

View file

@ -1,6 +1,7 @@
#include <u.h>
#include <libc.h>
#include <thread.h>
#include <emu.h>
#include "dat.h"
#include "fns.h"

View file

@ -1,6 +1,7 @@
#include <u.h>
#include <libc.h>
#include <thread.h>
#include <emu.h>
#include "dat.h"
#include "fns.h"
@ -8,7 +9,6 @@ int ppux, ppuy, rx;
static u8int mode, bright, pixelpri[2], hires;
static u32int pixelcol[2];
u16int vtime = 0x1ff, htime = 0x1ff, subcolor;
uchar pic[256*239*2*3];
u16int hofs[5], vofs[5];
s16int m7[6];
@ -40,30 +40,31 @@ darken(u16int v)
static void
pixeldraw(int x, int y, u16int v, int s)
{
uchar *p;
u16int *q;
u16int *p;
union { u16int w; u8int b[2]; } u;
if(bright != 0xf && s >= 0)
v = darken(v);
if(scale == 1){
p = pic + (x + y * 256) * 2;
p[0] = v;
p[1] = v >> 8;
return;
}
p = (u16int *)pic + (x + y * 256) * scale;
u.b[0] = v;
u.b[1] = v >> 8;
if(scale == 2){
q = (u16int*)pic + (x + y * 256) * 2;
if(s < 1)
q[0] = u.w;
q[1] = u.w;
}else{
q = (u16int*)pic + (x + y * 256) * 3;
q[0] = u.w;
q[1] = u.w;
q[2] = u.w;
switch(scale){
case 16: *p++ = u.w;
case 15: *p++ = u.w;
case 14: *p++ = u.w;
case 13: *p++ = u.w;
case 12: *p++ = u.w;
case 11: *p++ = u.w;
case 10: *p++ = u.w;
case 9: *p++ = u.w;
case 8: *p++ = u.w;
case 7: *p++ = u.w;
case 6: *p++ = u.w;
case 5: *p++ = u.w;
case 4: *p++ = u.w;
case 3: *p++ = u.w;
case 2: if(s < 1) *p++ = u.w;
default: *p = u.w;
}
}

View file

@ -4,21 +4,16 @@
#include <draw.h>
#include <keyboard.h>
#include <mouse.h>
#include <ctype.h>
#include <emu.h>
#include "dat.h"
#include "fns.h"
uchar *prg, *sram;
int nprg, nsram, hirom, battery;
int ppuclock, spcclock, dspclock, stimerclock, saveclock, msgclock, paused, perfclock, cpupause;
Mousectl *mc;
Channel *flushc, *msgc;
QLock pauselock;
u32int keys;
int savefd, scale, profile, mouse, loadreq, savereq;
Rectangle picr;
Image *tmp, *bg;
int ppuclock, spcclock, dspclock, stimerclock, saveclock, msgclock, cpupause;
Channel *msgc;
int savefd, mouse;
void
flushram(void)
@ -113,188 +108,14 @@ loadbat(char *file)
}
}
void
keyproc(void *)
{
int fd, n, k;
static char buf[256];
char *s;
Rune r;
fd = open("/dev/kbd", OREAD);
if(fd < 0)
sysfatal("open: %r");
for(;;){
if(buf[0] != 0){
n = strlen(buf)+1;
memmove(buf, buf+n, sizeof(buf)-n);
}
if(buf[0] == 0){
n = read(fd, buf, sizeof(buf)-1);
if(n <= 0)
sysfatal("read /dev/kbd: %r");
buf[n-1] = 0;
buf[n] = 0;
}
if(buf[0] == 'c'){
if(utfrune(buf, KF|5))
savereq = 1;
if(utfrune(buf, KF|6))
loadreq = 1;
if(utfrune(buf, Kdel)){
close(fd);
threadexitsall(nil);
}
if(utfrune(buf, 't'))
trace = !trace;
}
if(buf[0] != 'k' && buf[0] != 'K')
continue;
s = buf + 1;
k = 0xffff;
while(*s != 0){
s += chartorune(&r, s);
switch(r){
case Kdel: close(fd); threadexitsall(nil);
case 'z': k |= 1<<31; break;
case 'x': k |= 1<<23; break;
case 'a': k |= 1<<30; break;
case 's': k |= 1<<22; break;
case 'q': k |= 1<<21; break;
case 'w': k |= 1<<20; break;
case Kshift: k |= 1<<29; break;
case 10: k |= 1<<28; break;
case Kup: k |= 1<<27; break;
case Kdown: k |= 1<<26; break;
case Kleft: k |= 1<<25; break;
case Kright: k |= 1<<24; break;
case Kesc:
if(paused)
qunlock(&pauselock);
else
qlock(&pauselock);
paused = !paused;
break;
}
}
if(!mouse)
keys = k;
}
}
void
screeninit(void)
{
Point p;
p = divpt(addpt(screen->r.min, screen->r.max), 2);
picr = (Rectangle){subpt(p, Pt(scale * 128, scale * 112)), addpt(p, Pt(scale * 128, scale * 127))};
if(tmp != nil) freeimage(tmp);
tmp = allocimage(display, Rect(0, 0, scale * 256, scale > 1 ? 1 : scale * 239), RGB15, scale > 1, 0);
if(bg != nil) freeimage(bg);
bg = allocimage(display, Rect(0, 0, 1, 1), screen->chan, 1, 0xCCCCCCFF);
draw(screen, screen->r, bg, nil, ZP);
}
void
screenproc(void *)
{
extern uchar pic[256*239*2*3];
char *s;
Mouse m;
Point p;
enum { AMOUSE, ARESIZE, AFLUSH, AMSG, AEND };
Alt a[AEND+1] = {
{ mc->c, &m, CHANRCV },
{ mc->resizec, nil, CHANRCV },
{ flushc, nil, CHANRCV },
{ msgc, &s, CHANRCV },
{ nil, nil, CHANEND }
};
for(;;){
switch(alt(a)){
case AMOUSE:
if(mouse && ptinrect(m.xy, picr)){
p = subpt(m.xy, picr.min);
p.x /= scale;
p.y /= scale;
keys = keys & 0xff3f0000 | p.x | p.y << 8;
if((m.buttons & 1) != 0)
keys |= 1<<22;
if((m.buttons & 4) != 0)
keys |= 1<<23;
if((m.buttons & 2) != 0)
lastkeys = keys;
}
break;
case ARESIZE:
if(getwindow(display, Refnone) < 0)
sysfatal("resize failed: %r");
screeninit();
/* wet floor */
case AFLUSH:
if(scale == 1){
loadimage(tmp, tmp->r, pic, 256*239*2);
draw(screen, picr, tmp, nil, ZP);
} else {
Rectangle r;
uchar *s;
int w;
s = pic;
r = picr;
w = 256*2*scale;
while(r.min.y < picr.max.y){
loadimage(tmp, tmp->r, s, w);
s += w;
r.max.y = r.min.y+scale;
draw(screen, r, tmp, nil, ZP);
r.min.y = r.max.y;
}
}
flushimage(display, 1);
break;
case AMSG:
draw(screen, rectaddpt(Rect(10, 10, 200, 30), screen->r.min), bg, nil, ZP);
if(s != nil){
string(screen, addpt(screen->r.min, Pt(10, 10)), display->black, ZP,
display->defaultfont, s);
free(s);
}
break;
}
}
}
void
timing(void)
{
static vlong old;
vlong new;
new = nsec();
if(new != old)
message("%6.2f%%", 1e11 / (new - old));
old = nsec();
}
void
threadmain(int argc, char **argv)
{
int t;
extern u16int pc;
scale = 1;
hirom = -1;
ARGBEGIN {
case '2':
scale = 2;
break;
case '3':
scale = 3;
break;
case 'a':
audioinit();
break;
@ -308,9 +129,6 @@ threadmain(int argc, char **argv)
case 'h':
hirom++;
break;
case 'T':
profile++;
break;
default:
goto usage;
} ARGEND;
@ -321,16 +139,20 @@ usage:
threadexitsall("usage");
}
loadrom(argv[0]);
if(initdraw(nil, nil, argv0) < 0)
sysfatal("initdraw: %r");
flushc = chancreate(sizeof(ulong), 1);
msgc = chancreate(sizeof(char*), 0);
mc = initmouse(nil, screen);
if(mc == nil)
sysfatal("initmouse: %r");
screeninit();
proccreate(keyproc, 0, 8192);
proccreate(screenproc, 0, 8192);
initemu(256, 239, 2, RGB15, !mouse, nil);
regkey("b", 'z', 1<<31);
regkey("a", 'x', 1<<23);
regkey("y", 'a', 1<<30);
regkey("x", 's', 1<<22);
regkey("l1", 'q', 1<<21);
regkey("r1", 'w', 1<<20);
regkey("control", Kshift, 1<<29);
regkey("start", '\n', 1<<28);
regkey("up", Kup, 1<<27);
regkey("down", Kdown, 1<<26);
regkey("left", Kleft, 1<<25);
regkey("right", Kright, 1<<24);
msgc = chancreate(sizeof(char*), 1);
loadbat(argv[0]);
cpureset();
memreset();
@ -358,7 +180,6 @@ usage:
stimerclock += t;
ppuclock += t;
dspclock += t;
perfclock -= t;
while(ppuclock >= 4){
ppustep();
@ -386,18 +207,43 @@ usage:
msgclock = 0;
}
}
if(profile && perfclock <= 0){
perfclock = FREQ;
timing();
}
}
}
void
flush(void)
{
sendul(flushc, 1); /* flush screen */
audioout();
char *s;
Mouse m;
Point p;
extern Rectangle picr;
extern Mousectl *mc;
flushmouse(!mouse);
while(nbrecv(mc->c, &m) > 0){
if(ptinrect(m.xy, picr)){
p = subpt(m.xy, picr.min);
p.x /= scale;
p.y /= scale;
keys = keys & 0xff3f0000 | p.x | p.y << 8;
if((m.buttons & 1) != 0)
keys |= 1<<22;
if((m.buttons & 4) != 0)
keys |= 1<<23;
if((m.buttons & 2) != 0)
lastkeys = keys;
}
}
flushscreen();
while(nbrecv(msgc, &s) > 0){
if(s != nil){
string(screen, addpt(screen->r.min, Pt(10, 10)), display->black, ZP,
display->defaultfont, s);
free(s);
flushimage(display, 1);
}
}
flushaudio(audioout);
}
void

View file

@ -1,6 +1,7 @@
#include <u.h>
#include <libc.h>
#include <thread.h>
#include <emu.h>
#include "dat.h"
#include "fns.h"

316
sys/src/libemu/emu.c Normal file
View file

@ -0,0 +1,316 @@
#include <u.h>
#include <libc.h>
#include <thread.h>
#include <draw.h>
#include <keyboard.h>
#include <mouse.h>
#include <emu.h>
typedef struct Kfn Kfn;
u64int keys, keys2;
int trace, paused;
int savereq, loadreq;
QLock pauselock;
int scale, warp10;
uchar *pic;
Rectangle picr;
Mousectl *mc;
Image *bg;
static int profile, framestep;
static int vwdx, vwdy, vwbpp;
static ulong vwchan;
static Image *fb;
struct Kfn{
Rune r;
int k;
char joyk[16];
void(*fn)(void);
Kfn *n;
};
Kfn kfn, kkn;
void *
emalloc(ulong sz)
{
void *v;
v = mallocz(sz, 1);
if(v == nil)
sysfatal("malloc: %r");
setmalloctag(v, getcallerpc(&sz));
return v;
}
static void
joyproc(void *)
{
char *s, *down[9];
static char buf[64];
int n, k, j;
Kfn *kp;
j = 1;
for(;;){
n = read(0, buf, sizeof(buf) - 1);
if(n <= 0)
sysfatal("read: %r");
buf[n] = 0;
n = getfields(buf, down, nelem(down), 1, " ");
k = 0;
for(n--; n >= 0; n--){
s = down[n];
if(strcmp(s, "joy1") == 0)
j = 1;
else if(strcmp(s, "joy2") == 0)
j = 2;
for(kp=kkn.n; kp!=nil; kp=kp->n){
if(strcmp(kp->joyk, s) == 0)
k |= kp->k;
}
}
if(j == 2)
keys2 = k;
else
keys = k;
}
}
static void
keyproc(void *)
{
int fd, n, k;
static char buf[256];
char *s;
Rune r;
Kfn *kp;
fd = open("/dev/kbd", OREAD);
if(fd < 0)
sysfatal("open: %r");
for(;;){
if(buf[0] != 0){
n = strlen(buf)+1;
memmove(buf, buf+n, sizeof(buf)-n);
}
if(buf[0] == 0){
n = read(fd, buf, sizeof(buf)-1);
if(n <= 0)
sysfatal("read /dev/kbd: %r");
buf[n-1] = 0;
buf[n] = 0;
}
if(buf[0] == 'c'){
if(utfrune(buf, Kdel)){
close(fd);
threadexitsall(nil);
}
if(utfrune(buf, KF|5))
savereq = 1;
if(utfrune(buf, KF|6))
loadreq = 1;
if(utfrune(buf, KF|12))
profile ^= 1;
if(utfrune(buf, 't'))
trace = !trace;
for(kp=kfn.n; kp!=nil; kp=kp->n){
if(utfrune(buf, kp->r))
kp->fn();
}
}
if(buf[0] != 'k' && buf[0] != 'K')
continue;
s = buf + 1;
k = 0;
while(*s != 0){
s += chartorune(&r, s);
switch(r){
case Kdel: close(fd); threadexitsall(nil);
case Kesc:
if(paused)
qunlock(&pauselock);
else
qlock(&pauselock);
paused = !paused;
break;
case KF|1:
if(paused){
qunlock(&pauselock);
paused=0;
}
framestep = !framestep;
break;
case '`':
warp10 = !warp10;
break;
}
for(kp=kkn.n; kp!=nil; kp=kp->n){
if(utfrune(buf, kp->r))
k |= kp->k;
}
}
k &= ~(k << 1 & 0xa0 | k >> 1 & 0x50);
keys = k;
}
}
static void
timing(void)
{
static int fcount;
static vlong old;
static char buf[32];
vlong new;
if(++fcount == 60)
fcount = 0;
else
return;
new = nsec();
if(new != old)
sprint(buf, "%6.2f%%", 1e11 / (new - old));
else
buf[0] = 0;
draw(screen, rectaddpt(Rect(10, 10, vwdx-40, 30), screen->r.min), bg, nil, ZP);
string(screen, addpt(screen->r.min, Pt(10, 10)), display->black, ZP, display->defaultfont, buf);
old = nsec();
}
static void
screeninit(void)
{
Point p;
scale = Dx(screen->r) / vwdx;
if(scale <= 0)
scale = 1;
else if(scale > 16)
scale = 16;
p = divpt(addpt(screen->r.min, screen->r.max), 2);
picr = Rpt(subpt(p, Pt(scale * vwdx/2, scale * vwdy/2)),
addpt(p, Pt(scale * vwdx/2, scale * vwdy/2)));
freeimage(fb);
fb = allocimage(display, Rect(0, 0, scale * vwdx, scale > 1 ? 1 : scale * vwdy),
vwchan, scale > 1, 0);
free(pic);
pic = emalloc(vwdx * vwdy * vwbpp * scale);
draw(screen, screen->r, bg, nil, ZP);
}
void
flushmouse(int discard)
{
Mouse m;
if(nbrecvul(mc->resizec) > 0){
if(getwindow(display, Refnone) < 0)
sysfatal("resize failed: %r");
screeninit();
}
if(discard)
while(nbrecv(mc->c, &m) > 0)
;
}
void
flushscreen(void)
{
flushmouse(1);
if(scale == 1){
loadimage(fb, fb->r, pic, vwdx * vwdy * vwbpp);
draw(screen, picr, fb, nil, ZP);
} else {
Rectangle r;
uchar *s;
int w;
s = pic;
r = picr;
w = vwdx * vwbpp * scale;
while(r.min.y < picr.max.y){
loadimage(fb, fb->r, s, w);
s += w;
r.max.y = r.min.y+scale;
draw(screen, r, fb, nil, ZP);
r.min.y = r.max.y;
}
}
flushimage(display, 1);
if(profile)
timing();
}
void
flushaudio(int (*audioout)(void))
{
static vlong old, delta;
vlong new, diff;
if(audioout == nil || audioout() < 0 && !warp10){
new = nsec();
diff = 0;
if(old != 0){
diff = BILLION/60 - (new - old) - delta;
if(diff >= MILLION)
sleep(diff/MILLION);
}
old = nsec();
if(diff > 0){
diff = (old - new) - (diff / MILLION) * MILLION;
delta += (diff - delta) / 100;
}
}
if(framestep){
paused = 1;
qlock(&pauselock);
framestep = 0;
}
}
void
regkeyfn(Rune r, void (*fn)(void))
{
Kfn *kp;
for(kp=&kfn; kp->n!=nil; kp=kp->n)
;
kp->n = emalloc(sizeof *kp);
kp->n->r = r;
kp->n->fn = fn;
}
void
regkey(char *joyk, Rune r, int k)
{
Kfn *kp;
for(kp=&kkn; kp->n!=nil; kp=kp->n)
;
kp->n = emalloc(sizeof *kp);
strncpy(kp->n->joyk, joyk, sizeof(kp->n->joyk)-1);
kp->n->r = r;
kp->n->k = k;
}
void
initemu(int dx, int dy, int bpp, ulong chan, int dokey, void(*kproc)(void*))
{
vwdx = dx;
vwdy = dy;
vwchan = chan;
vwbpp = bpp;
if(initdraw(nil, nil, nil) < 0)
sysfatal("initdraw: %r");
mc = initmouse(nil, screen);
if(mc == nil)
sysfatal("initmouse: %r");
if(dokey)
proccreate(kproc != nil ? kproc : keyproc, nil, mainstacksize);
if(kproc == nil)
proccreate(joyproc, nil, mainstacksize*2);
bg = allocimage(display, Rect(0, 0, 1, 1), screen->chan, 1, 0xCCCCCCFF);
screeninit();
}

20
sys/src/libemu/mkfile Normal file
View file

@ -0,0 +1,20 @@
</$objtype/mkfile
LIB=/$objtype/lib/libemu.a
OFILES=\
emu.$O\
HFILES=\
/sys/include/draw.h\
/sys/include/emu.h\
/sys/include/mouse.h\
/sys/include/keyboard.h
UPDATE=\
mkfile\
$HFILES\
${OFILES:%.$O=%.c}\
${LIB:/$objtype/%=/386/%}\
</sys/src/cmd/mksyslib