add libemu
move redundant code from emulators to a common library
This commit is contained in:
parent
70c7a9eb07
commit
1195ca910c
|
@ -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:
|
||||
|
|
|
@ -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
137
sys/man/2/emu
Normal 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.
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
#include <u.h>
|
||||
#include <libc.h>
|
||||
#include <thread.h>
|
||||
#include <emu.h>
|
||||
#include "dat.h"
|
||||
#include "fns.h"
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
#include <u.h>
|
||||
#include <libc.h>
|
||||
#include <thread.h>
|
||||
#include <emu.h>
|
||||
#include "dat.h"
|
||||
#include "fns.h"
|
||||
|
||||
|
|
|
@ -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
|
||||
};
|
||||
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
#include <u.h>
|
||||
#include <libc.h>
|
||||
#include <thread.h>
|
||||
#include <emu.h>
|
||||
#include "dat.h"
|
||||
#include "fns.h"
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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),
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
#include <u.h>
|
||||
#include <libc.h>
|
||||
#include <thread.h>
|
||||
#include <emu.h>
|
||||
#include "dat.h"
|
||||
#include "fns.h"
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
#include <libc.h>
|
||||
#include <thread.h>
|
||||
#include <draw.h>
|
||||
#include <emu.h>
|
||||
#include "dat.h"
|
||||
#include "fns.h"
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
#include <u.h>
|
||||
#include <libc.h>
|
||||
#include <thread.h>
|
||||
#include <emu.h>
|
||||
#include "dat.h"
|
||||
#include "fns.h"
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
316
sys/src/libemu/emu.c
Normal 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
20
sys/src/libemu/mkfile
Normal 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
|
Loading…
Reference in a new issue