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
|
.SH SYNOPSIS
|
||||||
.B games/gb
|
.B games/gb
|
||||||
[
|
[
|
||||||
.B -23acdT
|
.B -acdT
|
||||||
]
|
]
|
||||||
[
|
[
|
||||||
.B -C
|
.B -C
|
||||||
|
@ -14,7 +14,7 @@ gb, gba, nes, snes \- emulators
|
||||||
.br
|
.br
|
||||||
.B games/gba
|
.B games/gba
|
||||||
[
|
[
|
||||||
.B -23aT
|
.B -aT
|
||||||
] [
|
] [
|
||||||
.B -b
|
.B -b
|
||||||
.I biosfile
|
.I biosfile
|
||||||
|
@ -26,13 +26,13 @@ gb, gba, nes, snes \- emulators
|
||||||
.br
|
.br
|
||||||
.B games/nes
|
.B games/nes
|
||||||
[
|
[
|
||||||
.B -23aos
|
.B -aos
|
||||||
]
|
]
|
||||||
.I romfile
|
.I romfile
|
||||||
.br
|
.br
|
||||||
.B games/snes
|
.B games/snes
|
||||||
[
|
[
|
||||||
.B -23ahmsT
|
.B -ahmsT
|
||||||
]
|
]
|
||||||
.I romfile
|
.I romfile
|
||||||
.SH DESCRIPTION
|
.SH DESCRIPTION
|
||||||
|
@ -43,7 +43,7 @@ and
|
||||||
.I snes
|
.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).
|
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.
|
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:
|
Other keys:
|
||||||
.TP
|
.TP
|
||||||
F5
|
F5
|
||||||
|
@ -60,14 +60,8 @@ Exit the emulator.
|
||||||
.PP
|
.PP
|
||||||
Command line options:
|
Command line options:
|
||||||
.TP
|
.TP
|
||||||
.B -2 -3
|
|
||||||
Scale the screen by the given factor.
|
|
||||||
.TP
|
|
||||||
.B -a
|
.B -a
|
||||||
Enable audio output.
|
Enable audio output.
|
||||||
.TP
|
|
||||||
.B -T
|
|
||||||
Display percentage of how fast the emulator is running relative to a real console.
|
|
||||||
.PP
|
.PP
|
||||||
.B gb
|
.B gb
|
||||||
options:
|
options:
|
||||||
|
|
|
@ -4,14 +4,14 @@ md \- emulator
|
||||||
.SH SYNOPSIS
|
.SH SYNOPSIS
|
||||||
.B games/md
|
.B games/md
|
||||||
[
|
[
|
||||||
.B -23a
|
.B -a
|
||||||
]
|
]
|
||||||
.I romfile
|
.I romfile
|
||||||
.SH DESCRIPTION
|
.SH DESCRIPTION
|
||||||
.I Md
|
.I Md
|
||||||
is an emulator for the Sega Megadrive/Genesis.
|
is an emulator for the Sega Megadrive/Genesis.
|
||||||
It executes the romfile given as an argument.
|
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:
|
Other keys:
|
||||||
.TP
|
.TP
|
||||||
Esc
|
Esc
|
||||||
|
@ -22,9 +22,6 @@ Exit the emulator.
|
||||||
.PP
|
.PP
|
||||||
Command line options:
|
Command line options:
|
||||||
.TP
|
.TP
|
||||||
.B -2 -3
|
|
||||||
Scale the screen by the given factor.
|
|
||||||
.TP
|
|
||||||
.B -a
|
.B -a
|
||||||
Enable audio output.
|
Enable audio output.
|
||||||
.SH SOURCE
|
.SH SOURCE
|
||||||
|
@ -33,4 +30,4 @@ Enable audio output.
|
||||||
Probably!
|
Probably!
|
||||||
.SH HISTORY
|
.SH HISTORY
|
||||||
.I Md
|
.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 <draw.h>
|
||||||
#include <mouse.h>
|
#include <mouse.h>
|
||||||
#include <keyboard.h>
|
#include <keyboard.h>
|
||||||
|
#include <emu.h>
|
||||||
#include "dat.h"
|
#include "dat.h"
|
||||||
#include "fns.h"
|
#include "fns.h"
|
||||||
|
|
||||||
char *bindir = "/sys/lib/c64";
|
char *bindir = "/sys/lib/c64";
|
||||||
Image *tmp, *bg, *red;
|
Image *red;
|
||||||
Rectangle picr, progr;
|
Rectangle progr;
|
||||||
Mousectl *mc;
|
|
||||||
QLock pauselock;
|
|
||||||
int paused, scale;
|
|
||||||
u8int *rom;
|
u8int *rom;
|
||||||
int nrom;
|
int nrom;
|
||||||
u64int keys;
|
|
||||||
u16int joys;
|
u16int joys;
|
||||||
uchar *tape, tapever, tapeplay;
|
uchar *tape, tapever, tapeplay;
|
||||||
ulong tapelen;
|
ulong tapelen;
|
||||||
|
@ -27,6 +24,7 @@ progress(int a, int b)
|
||||||
static int cur;
|
static int cur;
|
||||||
int w;
|
int w;
|
||||||
|
|
||||||
|
extern Image *bg;
|
||||||
if(b == 0 || a == 0){
|
if(b == 0 || a == 0){
|
||||||
if(cur != 0){
|
if(cur != 0){
|
||||||
draw(screen, progr, bg, nil, ZP);
|
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
|
static void
|
||||||
usage(void)
|
usage(void)
|
||||||
{
|
{
|
||||||
|
@ -236,17 +219,9 @@ usage(void)
|
||||||
void
|
void
|
||||||
threadmain(int argc, char **argv)
|
threadmain(int argc, char **argv)
|
||||||
{
|
{
|
||||||
scale = 1;
|
|
||||||
|
|
||||||
memreset();
|
memreset();
|
||||||
|
|
||||||
ARGBEGIN {
|
ARGBEGIN {
|
||||||
case '2':
|
|
||||||
scale = 2;
|
|
||||||
break;
|
|
||||||
case '3':
|
|
||||||
scale = 3;
|
|
||||||
break;
|
|
||||||
case 'c':
|
case 'c':
|
||||||
loadcart(EARGF(usage()));
|
loadcart(EARGF(usage()));
|
||||||
break;
|
break;
|
||||||
|
@ -272,16 +247,8 @@ threadmain(int argc, char **argv)
|
||||||
loadsys("crom.bin", crom, 4096);
|
loadsys("crom.bin", crom, 4096);
|
||||||
|
|
||||||
vicreset();
|
vicreset();
|
||||||
|
initemu(picw, pich, 4, XRGB32, 1, keyproc);
|
||||||
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);
|
|
||||||
red = allocimage(display, Rect(0, 0, 1, 1), screen->chan, 1, 0xFF0000FF);
|
red = allocimage(display, Rect(0, 0, 1, 1), screen->chan, 1, 0xFF0000FF);
|
||||||
screeninit();
|
|
||||||
proccreate(keyproc, nil, mainstacksize);
|
|
||||||
|
|
||||||
nmien = IRQRESTORE;
|
nmien = IRQRESTORE;
|
||||||
pc = memread(0xFFFC) | memread(0xFFFD) << 8;
|
pc = memread(0xFFFC) | memread(0xFFFD) << 8;
|
||||||
|
@ -310,6 +277,7 @@ menu(void)
|
||||||
items, nil, 0
|
items, nil, 0
|
||||||
};
|
};
|
||||||
|
|
||||||
|
extern Mousectl *mc;
|
||||||
switch(menuhit(3, mc, &m, nil)){
|
switch(menuhit(3, mc, &m, nil)){
|
||||||
case JOY:
|
case JOY:
|
||||||
joymode = (joymode + 1) % 3;
|
joymode = (joymode + 1) % 3;
|
||||||
|
@ -332,52 +300,11 @@ menu(void)
|
||||||
void
|
void
|
||||||
flush(void)
|
flush(void)
|
||||||
{
|
{
|
||||||
extern u8int pic[];
|
extern Mousectl *mc;
|
||||||
// vlong new, diff;
|
flushmouse(0);
|
||||||
// static vlong old, delta;
|
|
||||||
|
|
||||||
if(nbrecvul(mc->resizec) > 0){
|
|
||||||
if(getwindow(display, Refnone) < 0)
|
|
||||||
sysfatal("resize failed: %r");
|
|
||||||
screeninit();
|
|
||||||
}
|
|
||||||
while(nbrecv(mc->c, &mc->Mouse) > 0)
|
while(nbrecv(mc->c, &mc->Mouse) > 0)
|
||||||
if((mc->buttons & 4) != 0)
|
if((mc->buttons & 4) != 0)
|
||||||
menu();
|
menu();
|
||||||
if(scale == 1){
|
flushscreen();
|
||||||
loadimage(tmp, tmp->r, pic, picw*pich*4);
|
flushaudio(nil);
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
#include <u.h>
|
#include <u.h>
|
||||||
#include <libc.h>
|
#include <libc.h>
|
||||||
|
#include <emu.h>
|
||||||
#include "dat.h"
|
#include "dat.h"
|
||||||
#include "fns.h"
|
#include "fns.h"
|
||||||
|
|
||||||
|
@ -289,8 +290,6 @@ interrupt(int nmi, int brk)
|
||||||
rP |= FLAGI;
|
rP |= FLAGI;
|
||||||
}
|
}
|
||||||
|
|
||||||
int trace;
|
|
||||||
|
|
||||||
void
|
void
|
||||||
step(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 u8int reg[47], crom[4096], krom[8192], brom[8192], cram[1024], cart[16384];
|
||||||
|
|
||||||
extern u16int pc, curpc;
|
extern u16int pc, curpc;
|
||||||
extern u8int rP;
|
extern u8int rP;
|
||||||
extern int nrdy, irq, nmi, irqen, nmien, trace;
|
extern int nrdy, irq, nmi, irqen, nmien;
|
||||||
|
|
||||||
extern u8int pla;
|
extern u8int pla;
|
||||||
|
|
||||||
|
@ -12,9 +10,8 @@ extern uchar *tape, tapever, tapeplay;
|
||||||
extern ulong tapelen;
|
extern ulong tapelen;
|
||||||
|
|
||||||
extern u16int ppux, ppuy, picw, pich;
|
extern u16int ppux, ppuy, picw, pich;
|
||||||
extern u64int keys;
|
|
||||||
extern u16int joys;
|
extern u16int joys;
|
||||||
extern int scale, region;
|
extern int region;
|
||||||
|
|
||||||
enum {
|
enum {
|
||||||
FLAGC = 1<<0,
|
FLAGC = 1<<0,
|
||||||
|
@ -81,8 +78,6 @@ enum {
|
||||||
};
|
};
|
||||||
|
|
||||||
enum {
|
enum {
|
||||||
BILLION = 1000*1000*1000,
|
|
||||||
MILLION = 1000*1000,
|
|
||||||
HZ = 3579545,
|
HZ = 3579545,
|
||||||
RATE = 44100,
|
RATE = 44100,
|
||||||
SAMPDIV = HZ / 3 / RATE,
|
SAMPDIV = HZ / 3 / RATE,
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
#include <u.h>
|
#include <u.h>
|
||||||
#include <libc.h>
|
#include <libc.h>
|
||||||
#include <thread.h>
|
#include <thread.h>
|
||||||
|
#include <emu.h>
|
||||||
#include "dat.h"
|
#include "dat.h"
|
||||||
#include "fns.h"
|
#include "fns.h"
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
#include <u.h>
|
#include <u.h>
|
||||||
#include <libc.h>
|
#include <libc.h>
|
||||||
#include <thread.h>
|
#include <thread.h>
|
||||||
|
#include <emu.h>
|
||||||
#include "dat.h"
|
#include "dat.h"
|
||||||
#include "fns.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;
|
u16int vc, vcbase, vmli;
|
||||||
u8int badln, rc, displ, fract, visreg, hbord, vbord, rbord0, lbord0;
|
u8int badln, rc, displ, fract, visreg, hbord, vbord, rbord0, lbord0;
|
||||||
u16int chrp[40];
|
u16int chrp[40];
|
||||||
u8int pic[420*263*4*3];
|
|
||||||
u64int pxs, npxs, npxs0, opxs;
|
u64int pxs, npxs, npxs0, opxs;
|
||||||
u8int fg;
|
u8int fg;
|
||||||
|
|
||||||
|
@ -92,24 +92,40 @@ vicreset(void)
|
||||||
void
|
void
|
||||||
pixeldraw(u64int p, int n)
|
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 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 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};
|
static u8int cb[] = {0, 255, 0, 238, 204, 85, 170, 119, 85, 0, 119, 51, 119, 102, 255, 187};
|
||||||
u8int *q, c;
|
u8int c;
|
||||||
|
u32int *q;
|
||||||
|
|
||||||
q = pic + picidx * 4 * scale;
|
q = (u32int *)pic + picidx * scale;
|
||||||
for(i = 0; i < n; i++){
|
for(i = 0; i < n; i++){
|
||||||
c = p >> 56;
|
c = p >> 56;
|
||||||
p <<= 8;
|
p <<= 8;
|
||||||
|
u.c[0] = cb[c];
|
||||||
j = scale;
|
u.c[1] = cg[c];
|
||||||
do{
|
u.c[2] = cr[c];
|
||||||
*q++ = cb[c];
|
u.c[3] = 0;
|
||||||
*q++ = cg[c];
|
switch(scale){
|
||||||
*q++ = cr[c];
|
case 16: *q++ = u.l;
|
||||||
q++;
|
case 15: *q++ = u.l;
|
||||||
}while(--j);
|
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;
|
picidx += n;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
#include <u.h>
|
#include <u.h>
|
||||||
#include <libc.h>
|
#include <libc.h>
|
||||||
#include <thread.h>
|
#include <thread.h>
|
||||||
|
#include <emu.h>
|
||||||
#include "dat.h"
|
#include "dat.h"
|
||||||
#include "fns.h"
|
#include "fns.h"
|
||||||
|
|
||||||
|
@ -475,7 +476,7 @@ audioout(void)
|
||||||
if(sbufp == sbuf)
|
if(sbufp == sbuf)
|
||||||
return 0;
|
return 0;
|
||||||
cl = clock;
|
cl = clock;
|
||||||
rc = write(fd, sbuf, (sbufp - sbuf) * 2);
|
rc = warp10 ? (sbufp - sbuf) * 2 : write(fd, sbuf, (sbufp - sbuf) * 2);
|
||||||
if(rc > 0)
|
if(rc > 0)
|
||||||
sbufp -= (rc+1)/2;
|
sbufp -= (rc+1)/2;
|
||||||
if(sbufp < sbuf)
|
if(sbufp < sbuf)
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
#include <u.h>
|
#include <u.h>
|
||||||
#include <libc.h>
|
#include <libc.h>
|
||||||
#include <thread.h>
|
#include <thread.h>
|
||||||
|
#include <emu.h>
|
||||||
#include "dat.h"
|
#include "dat.h"
|
||||||
#include "fns.h"
|
#include "fns.h"
|
||||||
|
|
||||||
|
|
|
@ -1,10 +1,6 @@
|
||||||
typedef char s8int;
|
|
||||||
typedef short s16int;
|
|
||||||
typedef long s32int;
|
|
||||||
typedef struct Event Event;
|
typedef struct Event Event;
|
||||||
typedef struct MBC3Timer MBC3Timer;
|
typedef struct MBC3Timer MBC3Timer;
|
||||||
|
|
||||||
extern int trace;
|
|
||||||
extern u16int curpc;
|
extern u16int curpc;
|
||||||
|
|
||||||
extern uchar *rom, *back, reg[256], oam[256];
|
extern uchar *rom, *back, reg[256], oam[256];
|
||||||
|
@ -24,7 +20,6 @@ extern u8int apustatus;
|
||||||
|
|
||||||
extern u8int mode;
|
extern u8int mode;
|
||||||
extern u8int mbc, feat;
|
extern u8int mbc, feat;
|
||||||
extern int keys, scale;
|
|
||||||
|
|
||||||
enum {
|
enum {
|
||||||
JOYP = 0x00,
|
JOYP = 0x00,
|
||||||
|
@ -129,8 +124,6 @@ enum {
|
||||||
TIMERSIZ = 18,
|
TIMERSIZ = 18,
|
||||||
PICW = 160,
|
PICW = 160,
|
||||||
PICH = 144,
|
PICH = 144,
|
||||||
MILLION = 1000000,
|
|
||||||
BILLION = 1000000000,
|
|
||||||
FREQ = 1<<23
|
FREQ = 1<<23
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -2,34 +2,28 @@
|
||||||
#include <libc.h>
|
#include <libc.h>
|
||||||
#include <thread.h>
|
#include <thread.h>
|
||||||
#include <draw.h>
|
#include <draw.h>
|
||||||
#include <mouse.h>
|
|
||||||
#include <keyboard.h>
|
#include <keyboard.h>
|
||||||
|
#include <emu.h>
|
||||||
#include "dat.h"
|
#include "dat.h"
|
||||||
#include "fns.h"
|
#include "fns.h"
|
||||||
|
|
||||||
int cpuhalt;
|
int cpuhalt;
|
||||||
int scale, profile;
|
int backup;
|
||||||
Rectangle picr;
|
|
||||||
Image *bg, *tmp;
|
|
||||||
Mousectl *mc;
|
|
||||||
int keys, paused, framestep, backup;
|
|
||||||
QLock pauselock;
|
|
||||||
int savefd = -1, saveframes;
|
int savefd = -1, saveframes;
|
||||||
ulong clock;
|
ulong clock;
|
||||||
int savereq, loadreq;
|
|
||||||
u8int mbc, feat, mode;
|
u8int mbc, feat, mode;
|
||||||
extern MBC3Timer timer, timerl;
|
extern MBC3Timer timer, timerl;
|
||||||
|
|
||||||
void *
|
extern double TAU;
|
||||||
emalloc(ulong sz)
|
void
|
||||||
|
tauup(void)
|
||||||
{
|
{
|
||||||
void *v;
|
TAU += 5000;
|
||||||
|
}
|
||||||
v = malloc(sz);
|
void
|
||||||
if(v == nil)
|
taudn(void)
|
||||||
sysfatal("malloc: %r");
|
{
|
||||||
setmalloctag(v, getcallerpc(&sz));
|
TAU -= 5000;
|
||||||
return v;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
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
|
void
|
||||||
flush(void)
|
flush(void)
|
||||||
{
|
{
|
||||||
extern uchar pic[];
|
extern uchar pic[];
|
||||||
Mouse m;
|
|
||||||
static vlong old, delta;
|
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)
|
if(saveframes > 0 && --saveframes == 0)
|
||||||
flushback();
|
flushback();
|
||||||
if(savereq){
|
if(savereq){
|
||||||
|
@ -430,20 +264,10 @@ threadmain(int argc, char **argv)
|
||||||
int t;
|
int t;
|
||||||
|
|
||||||
colinit();
|
colinit();
|
||||||
scale = 1;
|
|
||||||
ARGBEGIN {
|
ARGBEGIN {
|
||||||
case '2':
|
|
||||||
scale = 2;
|
|
||||||
break;
|
|
||||||
case '3':
|
|
||||||
scale = 3;
|
|
||||||
break;
|
|
||||||
case 'a':
|
case 'a':
|
||||||
audioinit();
|
audioinit();
|
||||||
break;
|
break;
|
||||||
case 'T':
|
|
||||||
profile++;
|
|
||||||
break;
|
|
||||||
case 'c':
|
case 'c':
|
||||||
mode |= CGB;
|
mode |= CGB;
|
||||||
break;
|
break;
|
||||||
|
@ -460,15 +284,17 @@ threadmain(int argc, char **argv)
|
||||||
usage();
|
usage();
|
||||||
|
|
||||||
loadrom(argv[0]);
|
loadrom(argv[0]);
|
||||||
|
initemu(PICW, PICH, 4, XRGB32, 1, nil);
|
||||||
if(initdraw(nil, nil, nil) < 0)
|
regkey("b", 'z', 1<<5);
|
||||||
sysfatal("initdraw: %r");
|
regkey("a", 'x', 1<<4);
|
||||||
mc = initmouse(nil, screen);
|
regkey("control", Kshift, 1<<6);
|
||||||
if(mc == nil)
|
regkey("start", '\n', 1<<7);
|
||||||
sysfatal("initmouse: %r");
|
regkey("up", Kup, 1<<2);
|
||||||
proccreate(keyproc, nil, mainstacksize);
|
regkey("down", Kdown, 1<<3);
|
||||||
bg = allocimage(display, Rect(0, 0, 1, 1), screen->chan, 1, 0xCCCCCCFF);
|
regkey("left", Kleft, 1<<1);
|
||||||
screeninit();
|
regkey("right", Kright, 1<<0);
|
||||||
|
regkeyfn(KF|9, tauup);
|
||||||
|
regkeyfn(KF|10, taudn);
|
||||||
|
|
||||||
eventinit();
|
eventinit();
|
||||||
meminit();
|
meminit();
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
#include <u.h>
|
#include <u.h>
|
||||||
#include <libc.h>
|
#include <libc.h>
|
||||||
#include <thread.h>
|
#include <thread.h>
|
||||||
|
#include <emu.h>
|
||||||
#include "dat.h"
|
#include "dat.h"
|
||||||
#include "fns.h"
|
#include "fns.h"
|
||||||
|
|
||||||
|
|
|
@ -1,11 +1,11 @@
|
||||||
#include <u.h>
|
#include <u.h>
|
||||||
#include <libc.h>
|
#include <libc.h>
|
||||||
#include <thread.h>
|
#include <thread.h>
|
||||||
|
#include <emu.h>
|
||||||
#include "dat.h"
|
#include "dat.h"
|
||||||
#include "fns.h"
|
#include "fns.h"
|
||||||
|
|
||||||
u8int ppustate, ppuy;
|
u8int ppustate, ppuy;
|
||||||
u32int pic[PICW*PICH*3];
|
|
||||||
ulong hblclock, rendclock;
|
ulong hblclock, rendclock;
|
||||||
jmp_buf mainjmp, renderjmp;
|
jmp_buf mainjmp, renderjmp;
|
||||||
static int cyc, done, ppux, ppux0;
|
static int cyc, done, ppux, ppux0;
|
||||||
|
@ -63,7 +63,7 @@ ppurender(void)
|
||||||
}
|
}
|
||||||
ppux = 0;
|
ppux = 0;
|
||||||
ppux0 = 0;
|
ppux0 = 0;
|
||||||
picp = pic + ppuy * PICW * scale;
|
picp = (u32int*)pic + ppuy * PICW * scale;
|
||||||
y = ppuy + reg[SCY] << 1 & 14;
|
y = ppuy + reg[SCY] << 1 & 14;
|
||||||
ta = 0x1800 | reg[LCDC] << 7 & 0x400 | ppuy + reg[SCY] << 2 & 0x3e0 | reg[SCX] >> 3;
|
ta = 0x1800 | reg[LCDC] << 7 & 0x400 | ppuy + reg[SCY] << 2 & 0x3e0 | reg[SCX] >> 3;
|
||||||
x = -(reg[SCX] & 7);
|
x = -(reg[SCX] & 7);
|
||||||
|
@ -197,7 +197,7 @@ sprites(void)
|
||||||
int x, x1;
|
int x, x1;
|
||||||
u16int chr;
|
u16int chr;
|
||||||
|
|
||||||
picp = pic + ppuy * PICW * scale;
|
picp = (u32int*)pic + ppuy * PICW * scale;
|
||||||
for(q = spr; q < sprm; q++){
|
for(q = spr; q < sprm; q++){
|
||||||
if(q->x <= ppux0 || q->x >= ppux + 8)
|
if(q->x <= ppux0 || q->x >= ppux + 8)
|
||||||
continue;
|
continue;
|
||||||
|
@ -254,18 +254,31 @@ static void
|
||||||
lineexpand(void)
|
lineexpand(void)
|
||||||
{
|
{
|
||||||
u32int *picp, *p, *q, l;
|
u32int *picp, *p, *q, l;
|
||||||
int i, s;
|
int i;
|
||||||
|
|
||||||
s = scale;
|
picp = (u32int*)pic + ppuy * PICW * scale;
|
||||||
picp = pic + ppuy * PICW * s;
|
|
||||||
p = picp + PICW;
|
p = picp + PICW;
|
||||||
q = picp + PICW * scale;
|
q = picp + PICW * scale;
|
||||||
for(i = PICW; --i >= 0; ){
|
for(i = PICW; --i >= 0; ){
|
||||||
l = *--p;
|
l = *--p;
|
||||||
*--q = l;
|
switch(scale){
|
||||||
*--q = l;
|
case 16: *--q = l;
|
||||||
if(scale == 3)
|
case 15: *--q = l;
|
||||||
*--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 <u.h>
|
||||||
#include <libc.h>
|
#include <libc.h>
|
||||||
#include <thread.h>
|
#include <thread.h>
|
||||||
|
#include <emu.h>
|
||||||
#include "dat.h"
|
#include "dat.h"
|
||||||
#include "fns.h"
|
#include "fns.h"
|
||||||
|
|
||||||
|
@ -370,7 +371,7 @@ audioout(void)
|
||||||
if(sbufp == sbuf)
|
if(sbufp == sbuf)
|
||||||
return 0;
|
return 0;
|
||||||
cl = clock;
|
cl = clock;
|
||||||
rc = write(fd, sbuf, (sbufp - sbuf) * 2);
|
rc = warp10 ? (sbufp - sbuf) * 2 : write(fd, sbuf, (sbufp - sbuf) * 2);
|
||||||
if(rc > 0)
|
if(rc > 0)
|
||||||
sbufp -= (rc+1)/2;
|
sbufp -= (rc+1)/2;
|
||||||
if(sbufp < sbuf)
|
if(sbufp < sbuf)
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
#include <u.h>
|
#include <u.h>
|
||||||
#include <libc.h>
|
#include <libc.h>
|
||||||
#include <thread.h>
|
#include <thread.h>
|
||||||
|
#include <emu.h>
|
||||||
#include "dat.h"
|
#include "dat.h"
|
||||||
#include "fns.h"
|
#include "fns.h"
|
||||||
|
|
||||||
|
@ -34,7 +35,7 @@ u32int curpc;
|
||||||
int irq;
|
int irq;
|
||||||
|
|
||||||
u32int instr0, instr1, pipel = -1;
|
u32int instr0, instr1, pipel = -1;
|
||||||
int cyc, trace;
|
int cyc;
|
||||||
|
|
||||||
Var cpuvars[] = {
|
Var cpuvars[] = {
|
||||||
ARR(r), VAR(cpsr), VAR(spsr), ARR(saver), VAR(irq),
|
ARR(r), VAR(cpsr), VAR(spsr), ARR(saver), VAR(irq),
|
||||||
|
|
|
@ -1,9 +1,4 @@
|
||||||
typedef char s8int;
|
extern int cpuhalt;
|
||||||
typedef short s16int;
|
|
||||||
typedef long s32int;
|
|
||||||
typedef vlong s64int;
|
|
||||||
|
|
||||||
extern int cpuhalt, trace, keys;
|
|
||||||
|
|
||||||
extern u32int curpc;
|
extern u32int curpc;
|
||||||
extern int irq;
|
extern int irq;
|
||||||
|
@ -18,7 +13,6 @@ extern int nrom, nback, backup;
|
||||||
extern int hblank, ppuy;
|
extern int hblank, ppuy;
|
||||||
|
|
||||||
extern int clock;
|
extern int clock;
|
||||||
extern int scale;
|
|
||||||
|
|
||||||
typedef struct Event Event;
|
typedef struct Event Event;
|
||||||
struct Event {
|
struct Event {
|
||||||
|
@ -141,8 +135,6 @@ enum {
|
||||||
KB = 1024,
|
KB = 1024,
|
||||||
BACKTYPELEN = 64,
|
BACKTYPELEN = 64,
|
||||||
HZ = 16777216,
|
HZ = 16777216,
|
||||||
MILLION = 1000000,
|
|
||||||
BILLION = 1000000000,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef struct Var Var;
|
typedef struct Var Var;
|
||||||
|
|
|
@ -2,36 +2,19 @@
|
||||||
#include <libc.h>
|
#include <libc.h>
|
||||||
#include <thread.h>
|
#include <thread.h>
|
||||||
#include <draw.h>
|
#include <draw.h>
|
||||||
#include <mouse.h>
|
|
||||||
#include <keyboard.h>
|
#include <keyboard.h>
|
||||||
|
#include <emu.h>
|
||||||
#include "dat.h"
|
#include "dat.h"
|
||||||
#include "fns.h"
|
#include "fns.h"
|
||||||
|
|
||||||
int cpuhalt;
|
int cpuhalt;
|
||||||
int scale, profile;
|
Image *tmp;
|
||||||
Rectangle picr;
|
int backup;
|
||||||
Image *bg, *tmp;
|
|
||||||
Mousectl *mc;
|
|
||||||
int keys, paused, framestep, backup;
|
|
||||||
QLock pauselock;
|
|
||||||
int savefd, saveframes;
|
int savefd, saveframes;
|
||||||
int clock;
|
int clock;
|
||||||
int savereq, loadreq;
|
|
||||||
|
|
||||||
char *biosfile = "/sys/games/lib/gbabios.bin";
|
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
|
void
|
||||||
writeback(void)
|
writeback(void)
|
||||||
{
|
{
|
||||||
|
@ -211,172 +194,14 @@ loadrom(char *file)
|
||||||
nrom -= 256;
|
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
|
void
|
||||||
flush(void)
|
flush(void)
|
||||||
{
|
{
|
||||||
extern uchar pic[];
|
|
||||||
Mouse m;
|
|
||||||
int x;
|
int x;
|
||||||
static vlong old, delta;
|
|
||||||
vlong new, diff;
|
|
||||||
|
|
||||||
if(nbrecvul(mc->resizec) > 0){
|
flushmouse(1);
|
||||||
if(getwindow(display, Refnone) < 0)
|
flushscreen();
|
||||||
sysfatal("resize failed: %r");
|
flushaudio(audioout);
|
||||||
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;
|
|
||||||
|
|
||||||
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)
|
if(saveframes > 0 && --saveframes == 0)
|
||||||
flushback();
|
flushback();
|
||||||
|
@ -395,7 +220,7 @@ flush(void)
|
||||||
void
|
void
|
||||||
usage(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");
|
exits("usage");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -405,14 +230,7 @@ threadmain(int argc, char **argv)
|
||||||
char *s;
|
char *s;
|
||||||
int t;
|
int t;
|
||||||
|
|
||||||
scale = 1;
|
|
||||||
ARGBEGIN {
|
ARGBEGIN {
|
||||||
case '2':
|
|
||||||
scale = 2;
|
|
||||||
break;
|
|
||||||
case '3':
|
|
||||||
scale = 3;
|
|
||||||
break;
|
|
||||||
case 'a':
|
case 'a':
|
||||||
audioinit();
|
audioinit();
|
||||||
break;
|
break;
|
||||||
|
@ -425,9 +243,6 @@ threadmain(int argc, char **argv)
|
||||||
case 'b':
|
case 'b':
|
||||||
biosfile = strdup(EARGF(usage()));
|
biosfile = strdup(EARGF(usage()));
|
||||||
break;
|
break;
|
||||||
case 'T':
|
|
||||||
profile++;
|
|
||||||
break;
|
|
||||||
default:
|
default:
|
||||||
usage();
|
usage();
|
||||||
} ARGEND;
|
} ARGEND;
|
||||||
|
@ -436,16 +251,17 @@ threadmain(int argc, char **argv)
|
||||||
|
|
||||||
loadbios();
|
loadbios();
|
||||||
loadrom(argv[0]);
|
loadrom(argv[0]);
|
||||||
|
initemu(240, 160, 2, CHAN4(CIgnore, 1, CBlue, 5, CGreen, 5, CRed, 5), 1, nil);
|
||||||
if(initdraw(nil, nil, nil) < 0)
|
regkey("b", 'z', 1<<1);
|
||||||
sysfatal("initdraw: %r");
|
regkey("a", 'x', 1<<0);
|
||||||
mc = initmouse(nil, screen);
|
regkey("l1", 'a', 1<<9);
|
||||||
if(mc == nil)
|
regkey("r1", 's', 1<<8);
|
||||||
sysfatal("initmouse: %r");
|
regkey("control", Kshift, 1<<2);
|
||||||
proccreate(keyproc, nil, mainstacksize);
|
regkey("start", '\n', 1<<3);
|
||||||
bg = allocimage(display, Rect(0, 0, 1, 1), screen->chan, 1, 0xCCCCCCFF);
|
regkey("up", Kup, 1<<6);
|
||||||
screeninit();
|
regkey("down", Kdown, 1<<7);
|
||||||
|
regkey("left", Kleft, 1<<5);
|
||||||
|
regkey("right", Kright, 1<<4);
|
||||||
eventinit();
|
eventinit();
|
||||||
memreset();
|
memreset();
|
||||||
reset();
|
reset();
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
#include <u.h>
|
#include <u.h>
|
||||||
#include <libc.h>
|
#include <libc.h>
|
||||||
#include <thread.h>
|
#include <thread.h>
|
||||||
|
#include <emu.h>
|
||||||
#include "dat.h"
|
#include "dat.h"
|
||||||
#include "fns.h"
|
#include "fns.h"
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
#include <u.h>
|
#include <u.h>
|
||||||
#include <libc.h>
|
#include <libc.h>
|
||||||
#include <thread.h>
|
#include <thread.h>
|
||||||
|
#include <emu.h>
|
||||||
#include "dat.h"
|
#include "dat.h"
|
||||||
#include "fns.h"
|
#include "fns.h"
|
||||||
|
|
||||||
|
@ -11,7 +12,6 @@ int ppux0;
|
||||||
u32int pixcol[480];
|
u32int pixcol[480];
|
||||||
u8int pixpri[480];
|
u8int pixpri[480];
|
||||||
u8int pixwin[240];
|
u8int pixwin[240];
|
||||||
uchar pic[240*160*3*2];
|
|
||||||
int objalpha;
|
int objalpha;
|
||||||
|
|
||||||
typedef struct bg bg;
|
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
|
void
|
||||||
syncppu(int x1)
|
syncppu(int x1)
|
||||||
{
|
{
|
||||||
|
@ -724,6 +690,43 @@ syncppu(int x1)
|
||||||
ppux0 = 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
|
void
|
||||||
hblanktick(void *)
|
hblanktick(void *)
|
||||||
{
|
{
|
||||||
|
@ -755,7 +758,7 @@ hblanktick(void *)
|
||||||
}else{
|
}else{
|
||||||
syncppu(240);
|
syncppu(240);
|
||||||
if(ppuy < 160)
|
if(ppuy < 160)
|
||||||
linecopy();
|
linecopy(pixcol, ppuy);
|
||||||
addevent(&evhblank, 68*4);
|
addevent(&evhblank, 68*4);
|
||||||
hblank = 1;
|
hblank = 1;
|
||||||
if((stat & IRQHBLEN) != 0)
|
if((stat & IRQHBLEN) != 0)
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
#include <u.h>
|
#include <u.h>
|
||||||
#include <libc.h>
|
#include <libc.h>
|
||||||
#include <thread.h>
|
#include <thread.h>
|
||||||
|
#include <emu.h>
|
||||||
#include "dat.h"
|
#include "dat.h"
|
||||||
#include "fns.h"
|
#include "fns.h"
|
||||||
|
|
||||||
|
@ -19,7 +20,7 @@ extern u32int irql[8];
|
||||||
u32int irqla[8];
|
u32int irqla[8];
|
||||||
u16int rS;
|
u16int rS;
|
||||||
static u32int op;
|
static u32int op;
|
||||||
int trace, tim;
|
int tim;
|
||||||
#define ra (r+8)
|
#define ra (r+8)
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
|
|
@ -1,9 +1,4 @@
|
||||||
typedef signed char s8int;
|
|
||||||
typedef signed short s16int;
|
|
||||||
typedef signed long s32int;
|
|
||||||
|
|
||||||
extern u32int curpc, irq;
|
extern u32int curpc, irq;
|
||||||
extern int trace, debug;
|
|
||||||
|
|
||||||
extern u8int reg[32];
|
extern u8int reg[32];
|
||||||
extern u8int dma;
|
extern u8int dma;
|
||||||
|
@ -18,8 +13,6 @@ extern u8int *sram;
|
||||||
extern u32int sramctl, sram0, sram1;
|
extern u32int sramctl, sram0, sram1;
|
||||||
extern int savefd, saveclock;
|
extern int savefd, saveclock;
|
||||||
|
|
||||||
extern int keys, scale;
|
|
||||||
|
|
||||||
extern u16int vram[32768], vsram[40];
|
extern u16int vram[32768], vsram[40];
|
||||||
extern u32int cramc[64];
|
extern u32int cramc[64];
|
||||||
extern u16int vdpstat;
|
extern u16int vdpstat;
|
||||||
|
@ -82,8 +75,6 @@ enum {
|
||||||
RATE = 44100,
|
RATE = 44100,
|
||||||
SAMPDIV = FREQ / RATE,
|
SAMPDIV = FREQ / RATE,
|
||||||
SAVEFREQ = FREQ / 4,
|
SAVEFREQ = FREQ / 4,
|
||||||
MILLION = 1000 * 1000,
|
|
||||||
BILLION = 1000 * 1000 * 1000,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
enum {
|
enum {
|
||||||
|
|
|
@ -3,29 +3,18 @@
|
||||||
#include <thread.h>
|
#include <thread.h>
|
||||||
#include <draw.h>
|
#include <draw.h>
|
||||||
#include <keyboard.h>
|
#include <keyboard.h>
|
||||||
#include <mouse.h>
|
#include <emu.h>
|
||||||
#include "dat.h"
|
#include "dat.h"
|
||||||
#include "fns.h"
|
#include "fns.h"
|
||||||
|
|
||||||
int debug;
|
|
||||||
|
|
||||||
u16int *prg;
|
u16int *prg;
|
||||||
int nprg;
|
int nprg;
|
||||||
u8int *sram;
|
u8int *sram;
|
||||||
u32int sramctl, nsram, sram0, sram1;
|
u32int sramctl, nsram, sram0, sram1;
|
||||||
int savefd = -1;
|
int savefd = -1;
|
||||||
|
|
||||||
int keys;
|
|
||||||
|
|
||||||
int dmaclock, vdpclock, z80clock, audioclock, ymclock, saveclock;
|
int dmaclock, vdpclock, z80clock, audioclock, ymclock, saveclock;
|
||||||
|
|
||||||
int scale, paused;
|
|
||||||
QLock pauselock;
|
|
||||||
Mousectl *mc;
|
|
||||||
Channel *flushc;
|
|
||||||
Rectangle picr;
|
|
||||||
Image *tmp, *bg;
|
|
||||||
|
|
||||||
void
|
void
|
||||||
flushram(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
|
void
|
||||||
threadmain(int argc, char **argv)
|
threadmain(int argc, char **argv)
|
||||||
{
|
{
|
||||||
int t;
|
int t;
|
||||||
|
|
||||||
scale = 1;
|
|
||||||
ARGBEGIN{
|
ARGBEGIN{
|
||||||
case 'a':
|
case 'a':
|
||||||
initaudio();
|
initaudio();
|
||||||
break;
|
break;
|
||||||
case '2':
|
|
||||||
scale = 2;
|
|
||||||
break;
|
|
||||||
case '3':
|
|
||||||
scale = 3;
|
|
||||||
break;
|
|
||||||
default:
|
default:
|
||||||
;
|
;
|
||||||
} ARGEND;
|
} ARGEND;
|
||||||
|
@ -263,15 +120,15 @@ threadmain(int argc, char **argv)
|
||||||
threadexitsall("usage");
|
threadexitsall("usage");
|
||||||
}
|
}
|
||||||
loadrom(*argv);
|
loadrom(*argv);
|
||||||
if(initdraw(nil, nil, argv0) < 0)
|
initemu(320, 224, 4, XRGB32, 1, nil);
|
||||||
sysfatal("initdraw: %r");
|
regkey("a", 'c', 1<<5);
|
||||||
flushc = chancreate(sizeof(ulong), 1);
|
regkey("b", 'x', 1<<4);
|
||||||
mc = initmouse(nil, screen);
|
regkey("y", 'z', 1<<12);
|
||||||
if(mc == nil)
|
regkey("start", '\n', 1<<13);
|
||||||
sysfatal("initmouse: %r");
|
regkey("up", Kup, 0x101);
|
||||||
screeninit();
|
regkey("down", Kdown, 0x202);
|
||||||
proccreate(keyproc, nil, 8192);
|
regkey("left", Kleft, 1<<2);
|
||||||
proccreate(screenproc, nil, 8192);
|
regkey("right", Kright, 1<<3);
|
||||||
cpureset();
|
cpureset();
|
||||||
vdpmode();
|
vdpmode();
|
||||||
ymreset();
|
ymreset();
|
||||||
|
@ -320,22 +177,7 @@ threadmain(int argc, char **argv)
|
||||||
void
|
void
|
||||||
flush(void)
|
flush(void)
|
||||||
{
|
{
|
||||||
static vlong old, delta;
|
flushmouse(1);
|
||||||
vlong new, diff;
|
flushscreen();
|
||||||
|
flushaudio(audioout);
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
#include <u.h>
|
#include <u.h>
|
||||||
#include <libc.h>
|
#include <libc.h>
|
||||||
#include <thread.h>
|
#include <thread.h>
|
||||||
|
#include <emu.h>
|
||||||
#include "dat.h"
|
#include "dat.h"
|
||||||
#include "fns.h"
|
#include "fns.h"
|
||||||
|
|
||||||
|
@ -31,7 +32,7 @@ regread(u16int a)
|
||||||
switch(a | 1){
|
switch(a | 1){
|
||||||
case 0x0001: return 0xa0;
|
case 0x0001: return 0xa0;
|
||||||
case 0x0003:
|
case 0x0003:
|
||||||
v = keys;
|
v = ~(keys & 0xffff);
|
||||||
if((ctl[0] & 0x40) == 0)
|
if((ctl[0] & 0x40) == 0)
|
||||||
v >>= 8;
|
v >>= 8;
|
||||||
return ctl[0] & 0xc0 | v & 0x3f;
|
return ctl[0] & 0xc0 | v & 0x3f;
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
#include <u.h>
|
#include <u.h>
|
||||||
#include <libc.h>
|
#include <libc.h>
|
||||||
#include <thread.h>
|
#include <thread.h>
|
||||||
|
#include <emu.h>
|
||||||
#include "dat.h"
|
#include "dat.h"
|
||||||
#include "fns.h"
|
#include "fns.h"
|
||||||
|
|
||||||
u8int pic[320*224*4*4];
|
|
||||||
u16int vdpstat = 0x3400;
|
u16int vdpstat = 0x3400;
|
||||||
int vdpx, vdpy, vdpyy, frame, intla;
|
int vdpx, vdpy, vdpyy, frame, intla;
|
||||||
u16int hctr;
|
u16int hctr;
|
||||||
|
@ -29,32 +29,31 @@ vdpmode(void)
|
||||||
static void
|
static void
|
||||||
pixeldraw(int x, int y, int v)
|
pixeldraw(int x, int y, int v)
|
||||||
{
|
{
|
||||||
u8int *p;
|
u32int *p;
|
||||||
u32int *q;
|
union { u32int l; u8int b[4]; } u;
|
||||||
union { u32int w; u8int b[4]; } u;
|
|
||||||
|
|
||||||
if(scale == 1){
|
p = (u32int *)pic + (x + y * 320) * scale;
|
||||||
p = pic + (x + y * 320) * 4;
|
|
||||||
p[0] = v >> 16;
|
|
||||||
p[1] = v >> 8;
|
|
||||||
p[2] = v;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
u.b[0] = v >> 16;
|
u.b[0] = v >> 16;
|
||||||
u.b[1] = v >> 8;
|
u.b[1] = v >> 8;
|
||||||
u.b[2] = v;
|
u.b[2] = v;
|
||||||
u.b[3] = 0;
|
u.b[3] = 0;
|
||||||
if(scale == 2){
|
switch(scale){
|
||||||
if(intla)
|
case 16: *p++ = u.l;
|
||||||
y = y << 1 | frame;
|
case 15: *p++ = u.l;
|
||||||
q = (u32int*)pic + (x + y * 320) * 2;
|
case 14: *p++ = u.l;
|
||||||
q[0] = u.w;
|
case 13: *p++ = u.l;
|
||||||
q[1] = u.w;
|
case 12: *p++ = u.l;
|
||||||
}else{
|
case 11: *p++ = u.l;
|
||||||
q = (u32int*)pic + (x + y * 320) * 3;
|
case 10: *p++ = u.l;
|
||||||
q[0] = u.w;
|
case 9: *p++ = u.l;
|
||||||
q[1] = u.w;
|
case 8: *p++ = u.l;
|
||||||
q[2] = u.w;
|
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 <u.h>
|
||||||
#include <libc.h>
|
#include <libc.h>
|
||||||
#include <thread.h>
|
#include <thread.h>
|
||||||
|
#include <emu.h>
|
||||||
#include "dat.h"
|
#include "dat.h"
|
||||||
#include "fns.h"
|
#include "fns.h"
|
||||||
|
|
||||||
extern int debug;
|
|
||||||
|
|
||||||
u8int ym[512];
|
u8int ym[512];
|
||||||
enum {
|
enum {
|
||||||
MODE = 0x27,
|
MODE = 0x27,
|
||||||
|
@ -436,7 +435,7 @@ audioout(void)
|
||||||
return -1;
|
return -1;
|
||||||
if(sbufp == sbuf)
|
if(sbufp == sbuf)
|
||||||
return 0;
|
return 0;
|
||||||
rc = write(fd, sbuf, (sbufp - sbuf) * 2);
|
rc = warp10 ? (sbufp - sbuf) * 2 : write(fd, sbuf, (sbufp - sbuf) * 2);
|
||||||
if(rc > 0)
|
if(rc > 0)
|
||||||
sbufp -= (rc+1)/2;
|
sbufp -= (rc+1)/2;
|
||||||
if(sbufp < sbuf)
|
if(sbufp < sbuf)
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
#include <libc.h>
|
#include <libc.h>
|
||||||
#include <thread.h>
|
#include <thread.h>
|
||||||
#include <draw.h>
|
#include <draw.h>
|
||||||
|
#include <emu.h>
|
||||||
#include "dat.h"
|
#include "dat.h"
|
||||||
#include "fns.h"
|
#include "fns.h"
|
||||||
|
|
||||||
|
@ -279,7 +280,7 @@ audioout(void)
|
||||||
return -1;
|
return -1;
|
||||||
if(sbufp == sbuf)
|
if(sbufp == sbuf)
|
||||||
return 0;
|
return 0;
|
||||||
rc = write(fd, sbuf, (sbufp - sbuf) * 2);
|
rc = warp10 ? (sbufp - sbuf) * 2 : write(fd, sbuf, (sbufp - sbuf) * 2);
|
||||||
if(rc > 0)
|
if(rc > 0)
|
||||||
sbufp -= (rc+1)/2;
|
sbufp -= (rc+1)/2;
|
||||||
if(sbufp < sbuf)
|
if(sbufp < sbuf)
|
||||||
|
|
|
@ -6,14 +6,14 @@ extern u16int pput, ppuv;
|
||||||
extern u8int ppusx, vrambuf;
|
extern u8int ppusx, vrambuf;
|
||||||
extern int mirr, ppux, ppuy, odd, vramlatch, keylatch, keylatch2;
|
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 uchar *prg, *chr;
|
||||||
extern int nprg, nchr, map, chrram;
|
extern int nprg, nchr, map, chrram;
|
||||||
|
|
||||||
extern u8int apuseq, apuctr[13];
|
extern u8int apuseq, apuctr[13];
|
||||||
extern u16int dmcaddr, dmccnt;
|
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);
|
extern void (*mapper[])(int, u8int);
|
||||||
|
|
||||||
|
@ -78,8 +78,6 @@ enum {
|
||||||
|
|
||||||
enum {
|
enum {
|
||||||
FREQ = 21477272,
|
FREQ = 21477272,
|
||||||
MILLION = 1000000,
|
|
||||||
BILLION = 1000000000,
|
|
||||||
APUDIV = 89490,
|
APUDIV = 89490,
|
||||||
RATE = 44100,
|
RATE = 44100,
|
||||||
SAMPDIV = FREQ / RATE,
|
SAMPDIV = FREQ / RATE,
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
#include <libc.h>
|
#include <libc.h>
|
||||||
#include <thread.h>
|
#include <thread.h>
|
||||||
#include <draw.h>
|
#include <draw.h>
|
||||||
|
#include <emu.h>
|
||||||
#include "dat.h"
|
#include "dat.h"
|
||||||
#include "fns.h"
|
#include "fns.h"
|
||||||
|
|
||||||
|
|
|
@ -2,22 +2,17 @@
|
||||||
#include <libc.h>
|
#include <libc.h>
|
||||||
#include <draw.h>
|
#include <draw.h>
|
||||||
#include <thread.h>
|
#include <thread.h>
|
||||||
#include <mouse.h>
|
|
||||||
#include <keyboard.h>
|
#include <keyboard.h>
|
||||||
|
#include <emu.h>
|
||||||
#include "dat.h"
|
#include "dat.h"
|
||||||
#include "fns.h"
|
#include "fns.h"
|
||||||
|
|
||||||
extern uchar ppuram[16384];
|
extern uchar ppuram[16384];
|
||||||
int nprg, nchr, map, chrram;
|
int nprg, nchr, map, chrram;
|
||||||
uchar *prg, *chr;
|
uchar *prg, *chr;
|
||||||
int scale;
|
|
||||||
Rectangle picr;
|
|
||||||
Image *tmp, *bg;
|
|
||||||
int clock, ppuclock, apuclock, dmcclock, dmcfreq, sampclock, msgclock, saveclock;
|
int clock, ppuclock, apuclock, dmcclock, dmcfreq, sampclock, msgclock, saveclock;
|
||||||
Mousectl *mc;
|
int oflag, savefd = -1;
|
||||||
int keys, keys2, paused, savereq, loadreq, oflag, savefd = -1;
|
|
||||||
int mirr;
|
int mirr;
|
||||||
QLock pauselock;
|
|
||||||
|
|
||||||
void
|
void
|
||||||
message(char *fmt, ...)
|
message(char *fmt, ...)
|
||||||
|
@ -122,139 +117,18 @@ loadrom(char *file, int sflag)
|
||||||
mapper[map](INIT, 0);
|
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
|
void
|
||||||
threadmain(int argc, char **argv)
|
threadmain(int argc, char **argv)
|
||||||
{
|
{
|
||||||
int t, h, sflag;
|
int t, sflag;
|
||||||
Point p;
|
|
||||||
|
|
||||||
scale = 1;
|
|
||||||
h = 240;
|
|
||||||
sflag = 0;
|
sflag = 0;
|
||||||
ARGBEGIN {
|
ARGBEGIN {
|
||||||
case 'a':
|
case 'a':
|
||||||
initaudio();
|
initaudio();
|
||||||
break;
|
break;
|
||||||
case '2':
|
|
||||||
scale = 2;
|
|
||||||
break;
|
|
||||||
case '3':
|
|
||||||
scale = 3;
|
|
||||||
break;
|
|
||||||
case 'o':
|
case 'o':
|
||||||
oflag = 1;
|
oflag = 1;
|
||||||
h -= 16;
|
|
||||||
break;
|
break;
|
||||||
case 's':
|
case 's':
|
||||||
sflag = 1;
|
sflag = 1;
|
||||||
|
@ -269,19 +143,15 @@ threadmain(int argc, char **argv)
|
||||||
threadexitsall("usage");
|
threadexitsall("usage");
|
||||||
}
|
}
|
||||||
loadrom(argv[0], sflag);
|
loadrom(argv[0], sflag);
|
||||||
if(initdraw(nil, nil, nil) < 0)
|
initemu(256, 240 - oflag * 16, 4, XRGB32, 1, nil);
|
||||||
sysfatal("initdraw: %r");
|
regkey("b", 'z', 1<<1);
|
||||||
mc = initmouse(nil, screen);
|
regkey("a", 'x', 1<<0);
|
||||||
if(mc == nil)
|
regkey("control", Kshift, 1<<2);
|
||||||
sysfatal("initmouse: %r");
|
regkey("start", '\n', 1<<3);
|
||||||
proccreate(joyproc, nil, 8192);
|
regkey("up", Kup, 1<<4);
|
||||||
proccreate(keyproc, nil, 8192);
|
regkey("down", Kdown, 1<<5);
|
||||||
originwindow(screen, Pt(0, 0), screen->r.min);
|
regkey("left", Kleft, 1<<6);
|
||||||
p = divpt(addpt(screen->r.min, screen->r.max), 2);
|
regkey("right", Kright, 1<<7);
|
||||||
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);
|
|
||||||
|
|
||||||
pc = memread(0xFFFC) | memread(0xFFFD) << 8;
|
pc = memread(0xFFFC) | memread(0xFFFD) << 8;
|
||||||
rP = FLAGI;
|
rP = FLAGI;
|
||||||
|
@ -324,6 +194,7 @@ threadmain(int argc, char **argv)
|
||||||
if(msgclock > 0){
|
if(msgclock > 0){
|
||||||
msgclock -= t;
|
msgclock -= t;
|
||||||
if(msgclock <= 0){
|
if(msgclock <= 0){
|
||||||
|
extern Image *bg;
|
||||||
draw(screen, screen->r, bg, nil, ZP);
|
draw(screen, screen->r, bg, nil, ZP);
|
||||||
msgclock = 0;
|
msgclock = 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,18 +3,17 @@
|
||||||
#include <thread.h>
|
#include <thread.h>
|
||||||
#include <draw.h>
|
#include <draw.h>
|
||||||
#include <mouse.h>
|
#include <mouse.h>
|
||||||
|
#include <emu.h>
|
||||||
#include "dat.h"
|
#include "dat.h"
|
||||||
#include "fns.h"
|
#include "fns.h"
|
||||||
|
|
||||||
int ppuy, ppux, odd;
|
int ppuy, ppux, odd;
|
||||||
uchar pic[256*240*4*9];
|
|
||||||
|
|
||||||
static void
|
static void
|
||||||
pixel(int x, int y, int val, int back)
|
pixel(int x, int y, int val, int back)
|
||||||
{
|
{
|
||||||
int Y;
|
|
||||||
union { u8int c[4]; u32int l; } u;
|
union { u8int c[4]; u32int l; } u;
|
||||||
u32int *p, l;
|
u32int *p;
|
||||||
static u8int palred[64] = {
|
static u8int palred[64] = {
|
||||||
0x7C, 0x00, 0x00, 0x44, 0x94, 0xA8, 0xA8, 0x88,
|
0x7C, 0x00, 0x00, 0x44, 0x94, 0xA8, 0xA8, 0x88,
|
||||||
0x50, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
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[1] = palgreen[val];
|
||||||
u.c[2] = palred[val];
|
u.c[2] = palred[val];
|
||||||
u.c[3] = back ? 0 : 0xFF;
|
u.c[3] = back ? 0 : 0xFF;
|
||||||
l = u.l;
|
p = (u32int *)pic + y * 256 * scale + x * scale;
|
||||||
if(scale == 3){
|
switch(scale){
|
||||||
p = ((u32int*)pic) + y * 3 * 3 * 256 + 3 * x;
|
case 16: *p++ = u.l;
|
||||||
for(Y = 0; Y < 3; Y++){
|
case 15: *p++ = u.l;
|
||||||
*p++ = l;
|
case 14: *p++ = u.l;
|
||||||
*p++ = l;
|
case 13: *p++ = u.l;
|
||||||
*p = l;
|
case 12: *p++ = u.l;
|
||||||
p += 3 * 256 - 2;
|
case 11: *p++ = u.l;
|
||||||
}
|
case 10: *p++ = u.l;
|
||||||
}else if(scale == 2){
|
case 9: *p++ = u.l;
|
||||||
p = ((u32int*)pic) + y * 2 * 2 * 256 + 2 * x;
|
case 8: *p++ = u.l;
|
||||||
*p++ = l;
|
case 7: *p++ = u.l;
|
||||||
*p = l;
|
case 6: *p++ = u.l;
|
||||||
p += 2 * 256 - 1;
|
case 5: *p++ = u.l;
|
||||||
*p++ = l;
|
case 4: *p++ = u.l;
|
||||||
*p = l;
|
case 3: *p++ = u.l;
|
||||||
}else{
|
case 2: *p++ = u.l;
|
||||||
p = ((u32int*)pic) + y * 256 + x;
|
default: *p = u.l;
|
||||||
*p = l;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
iscolor(int x, int y)
|
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
|
static int
|
||||||
|
@ -252,52 +250,9 @@ drawsprites(int show)
|
||||||
static void
|
static void
|
||||||
flush(void)
|
flush(void)
|
||||||
{
|
{
|
||||||
extern Rectangle picr;
|
flushmouse(1);
|
||||||
extern Image *tmp, *bg;
|
flushscreen();
|
||||||
extern Mousectl *mc;
|
flushaudio(audioout);
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
#include <u.h>
|
#include <u.h>
|
||||||
#include <libc.h>
|
#include <libc.h>
|
||||||
#include <thread.h>
|
#include <thread.h>
|
||||||
|
#include <emu.h>
|
||||||
#include "dat.h"
|
#include "dat.h"
|
||||||
#include "fns.h"
|
#include "fns.h"
|
||||||
|
|
||||||
|
@ -640,8 +641,6 @@ cpureset(void)
|
||||||
rP = 0x35;
|
rP = 0x35;
|
||||||
}
|
}
|
||||||
|
|
||||||
int trace;
|
|
||||||
|
|
||||||
int
|
int
|
||||||
cpustep(void)
|
cpustep(void)
|
||||||
{
|
{
|
||||||
|
|
|
@ -1,14 +1,10 @@
|
||||||
typedef signed char s8int;
|
|
||||||
typedef signed short s16int;
|
|
||||||
|
|
||||||
extern u8int rP, dma, nmi, irq, emu, wai;
|
extern u8int rP, dma, nmi, irq, emu, wai;
|
||||||
extern u16int rA, rX, rY, rS, rD, pc;
|
extern u16int rA, rX, rY, rS, rD, pc;
|
||||||
extern u32int rPB, rDB, curpc, hdma;
|
extern u32int rPB, rDB, curpc, hdma;
|
||||||
extern int trace;
|
|
||||||
|
|
||||||
extern uchar *prg, *sram;
|
extern uchar *prg, *sram;
|
||||||
extern int nprg, nsram, hirom;
|
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 u8int reg[32768], mem[131072], spcmem[65536], vram[65536], oam[544];
|
||||||
extern u16int cgram[256], vramlatch;
|
extern u16int cgram[256], vramlatch;
|
||||||
extern u8int mdr, mdr1, mdr2;
|
extern u8int mdr, mdr1, mdr2;
|
||||||
|
@ -25,7 +21,7 @@ extern u8int dspstate;
|
||||||
extern u16int dspcounter, noise;
|
extern u16int dspcounter, noise;
|
||||||
|
|
||||||
extern int ppuclock, spcclock, dspclock, stimerclock, cpupause;
|
extern int ppuclock, spcclock, dspclock, stimerclock, cpupause;
|
||||||
extern int battery, saveclock, scale, mouse;
|
extern int battery, saveclock, mouse;
|
||||||
|
|
||||||
enum {
|
enum {
|
||||||
FLAGC = 1<<0,
|
FLAGC = 1<<0,
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
#include <u.h>
|
#include <u.h>
|
||||||
#include <libc.h>
|
#include <libc.h>
|
||||||
#include <thread.h>
|
#include <thread.h>
|
||||||
|
#include <emu.h>
|
||||||
#include "dat.h"
|
#include "dat.h"
|
||||||
#include "fns.h"
|
#include "fns.h"
|
||||||
|
|
||||||
|
@ -77,7 +78,7 @@ audioout(void)
|
||||||
return -1;
|
return -1;
|
||||||
if(sbufp == sbuf)
|
if(sbufp == sbuf)
|
||||||
return 0;
|
return 0;
|
||||||
rc = write(fd, sbuf, (sbufp - sbuf) * 2);
|
rc = warp10 ? (sbufp - sbuf) * 2 : write(fd, sbuf, (sbufp - sbuf) * 2);
|
||||||
if(rc > 0)
|
if(rc > 0)
|
||||||
sbufp -= (rc+1)/2;
|
sbufp -= (rc+1)/2;
|
||||||
if(sbufp < sbuf)
|
if(sbufp < sbuf)
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
#include <u.h>
|
#include <u.h>
|
||||||
#include <libc.h>
|
#include <libc.h>
|
||||||
#include <thread.h>
|
#include <thread.h>
|
||||||
|
#include <emu.h>
|
||||||
#include "dat.h"
|
#include "dat.h"
|
||||||
#include "fns.h"
|
#include "fns.h"
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
#include <u.h>
|
#include <u.h>
|
||||||
#include <libc.h>
|
#include <libc.h>
|
||||||
#include <thread.h>
|
#include <thread.h>
|
||||||
|
#include <emu.h>
|
||||||
#include "dat.h"
|
#include "dat.h"
|
||||||
#include "fns.h"
|
#include "fns.h"
|
||||||
|
|
||||||
|
@ -8,7 +9,6 @@ int ppux, ppuy, rx;
|
||||||
static u8int mode, bright, pixelpri[2], hires;
|
static u8int mode, bright, pixelpri[2], hires;
|
||||||
static u32int pixelcol[2];
|
static u32int pixelcol[2];
|
||||||
u16int vtime = 0x1ff, htime = 0x1ff, subcolor;
|
u16int vtime = 0x1ff, htime = 0x1ff, subcolor;
|
||||||
uchar pic[256*239*2*3];
|
|
||||||
u16int hofs[5], vofs[5];
|
u16int hofs[5], vofs[5];
|
||||||
s16int m7[6];
|
s16int m7[6];
|
||||||
|
|
||||||
|
@ -40,30 +40,31 @@ darken(u16int v)
|
||||||
static void
|
static void
|
||||||
pixeldraw(int x, int y, u16int v, int s)
|
pixeldraw(int x, int y, u16int v, int s)
|
||||||
{
|
{
|
||||||
uchar *p;
|
u16int *p;
|
||||||
u16int *q;
|
|
||||||
union { u16int w; u8int b[2]; } u;
|
union { u16int w; u8int b[2]; } u;
|
||||||
|
|
||||||
if(bright != 0xf && s >= 0)
|
if(bright != 0xf && s >= 0)
|
||||||
v = darken(v);
|
v = darken(v);
|
||||||
if(scale == 1){
|
p = (u16int *)pic + (x + y * 256) * scale;
|
||||||
p = pic + (x + y * 256) * 2;
|
|
||||||
p[0] = v;
|
|
||||||
p[1] = v >> 8;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
u.b[0] = v;
|
u.b[0] = v;
|
||||||
u.b[1] = v >> 8;
|
u.b[1] = v >> 8;
|
||||||
if(scale == 2){
|
switch(scale){
|
||||||
q = (u16int*)pic + (x + y * 256) * 2;
|
case 16: *p++ = u.w;
|
||||||
if(s < 1)
|
case 15: *p++ = u.w;
|
||||||
q[0] = u.w;
|
case 14: *p++ = u.w;
|
||||||
q[1] = u.w;
|
case 13: *p++ = u.w;
|
||||||
}else{
|
case 12: *p++ = u.w;
|
||||||
q = (u16int*)pic + (x + y * 256) * 3;
|
case 11: *p++ = u.w;
|
||||||
q[0] = u.w;
|
case 10: *p++ = u.w;
|
||||||
q[1] = u.w;
|
case 9: *p++ = u.w;
|
||||||
q[2] = 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 <draw.h>
|
||||||
#include <keyboard.h>
|
#include <keyboard.h>
|
||||||
#include <mouse.h>
|
#include <mouse.h>
|
||||||
#include <ctype.h>
|
#include <emu.h>
|
||||||
#include "dat.h"
|
#include "dat.h"
|
||||||
#include "fns.h"
|
#include "fns.h"
|
||||||
|
|
||||||
uchar *prg, *sram;
|
uchar *prg, *sram;
|
||||||
int nprg, nsram, hirom, battery;
|
int nprg, nsram, hirom, battery;
|
||||||
|
|
||||||
int ppuclock, spcclock, dspclock, stimerclock, saveclock, msgclock, paused, perfclock, cpupause;
|
int ppuclock, spcclock, dspclock, stimerclock, saveclock, msgclock, cpupause;
|
||||||
Mousectl *mc;
|
Channel *msgc;
|
||||||
Channel *flushc, *msgc;
|
int savefd, mouse;
|
||||||
QLock pauselock;
|
|
||||||
u32int keys;
|
|
||||||
int savefd, scale, profile, mouse, loadreq, savereq;
|
|
||||||
Rectangle picr;
|
|
||||||
Image *tmp, *bg;
|
|
||||||
|
|
||||||
void
|
void
|
||||||
flushram(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
|
void
|
||||||
threadmain(int argc, char **argv)
|
threadmain(int argc, char **argv)
|
||||||
{
|
{
|
||||||
int t;
|
int t;
|
||||||
extern u16int pc;
|
extern u16int pc;
|
||||||
|
|
||||||
scale = 1;
|
|
||||||
hirom = -1;
|
hirom = -1;
|
||||||
ARGBEGIN {
|
ARGBEGIN {
|
||||||
case '2':
|
|
||||||
scale = 2;
|
|
||||||
break;
|
|
||||||
case '3':
|
|
||||||
scale = 3;
|
|
||||||
break;
|
|
||||||
case 'a':
|
case 'a':
|
||||||
audioinit();
|
audioinit();
|
||||||
break;
|
break;
|
||||||
|
@ -308,9 +129,6 @@ threadmain(int argc, char **argv)
|
||||||
case 'h':
|
case 'h':
|
||||||
hirom++;
|
hirom++;
|
||||||
break;
|
break;
|
||||||
case 'T':
|
|
||||||
profile++;
|
|
||||||
break;
|
|
||||||
default:
|
default:
|
||||||
goto usage;
|
goto usage;
|
||||||
} ARGEND;
|
} ARGEND;
|
||||||
|
@ -321,16 +139,20 @@ usage:
|
||||||
threadexitsall("usage");
|
threadexitsall("usage");
|
||||||
}
|
}
|
||||||
loadrom(argv[0]);
|
loadrom(argv[0]);
|
||||||
if(initdraw(nil, nil, argv0) < 0)
|
initemu(256, 239, 2, RGB15, !mouse, nil);
|
||||||
sysfatal("initdraw: %r");
|
regkey("b", 'z', 1<<31);
|
||||||
flushc = chancreate(sizeof(ulong), 1);
|
regkey("a", 'x', 1<<23);
|
||||||
msgc = chancreate(sizeof(char*), 0);
|
regkey("y", 'a', 1<<30);
|
||||||
mc = initmouse(nil, screen);
|
regkey("x", 's', 1<<22);
|
||||||
if(mc == nil)
|
regkey("l1", 'q', 1<<21);
|
||||||
sysfatal("initmouse: %r");
|
regkey("r1", 'w', 1<<20);
|
||||||
screeninit();
|
regkey("control", Kshift, 1<<29);
|
||||||
proccreate(keyproc, 0, 8192);
|
regkey("start", '\n', 1<<28);
|
||||||
proccreate(screenproc, 0, 8192);
|
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]);
|
loadbat(argv[0]);
|
||||||
cpureset();
|
cpureset();
|
||||||
memreset();
|
memreset();
|
||||||
|
@ -358,7 +180,6 @@ usage:
|
||||||
stimerclock += t;
|
stimerclock += t;
|
||||||
ppuclock += t;
|
ppuclock += t;
|
||||||
dspclock += t;
|
dspclock += t;
|
||||||
perfclock -= t;
|
|
||||||
|
|
||||||
while(ppuclock >= 4){
|
while(ppuclock >= 4){
|
||||||
ppustep();
|
ppustep();
|
||||||
|
@ -386,18 +207,43 @@ usage:
|
||||||
msgclock = 0;
|
msgclock = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if(profile && perfclock <= 0){
|
|
||||||
perfclock = FREQ;
|
|
||||||
timing();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
flush(void)
|
flush(void)
|
||||||
{
|
{
|
||||||
sendul(flushc, 1); /* flush screen */
|
char *s;
|
||||||
audioout();
|
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
|
void
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
#include <u.h>
|
#include <u.h>
|
||||||
#include <libc.h>
|
#include <libc.h>
|
||||||
#include <thread.h>
|
#include <thread.h>
|
||||||
|
#include <emu.h>
|
||||||
#include "dat.h"
|
#include "dat.h"
|
||||||
#include "fns.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