]> git.lizzy.rs Git - plan9front.git/commitdiff
add libemu
authorqwx <devnull@localhost>
Sat, 12 May 2018 17:20:53 +0000 (19:20 +0200)
committerqwx <devnull@localhost>
Sat, 12 May 2018 17:20:53 +0000 (19:20 +0200)
move redundant code from emulators to a common library

40 files changed:
sys/man/1/nintendo
sys/man/1/sega
sys/man/2/emu [new file with mode: 0644]
sys/src/games/c64/c64.c
sys/src/games/c64/cpu.c
sys/src/games/c64/dat.h
sys/src/games/c64/mem.c
sys/src/games/c64/vic.c
sys/src/games/gb/apu.c
sys/src/games/gb/cpu.c
sys/src/games/gb/dat.h
sys/src/games/gb/gb.c
sys/src/games/gb/mem.c
sys/src/games/gb/ppu.c
sys/src/games/gba/apu.c
sys/src/games/gba/cpu.c
sys/src/games/gba/dat.h
sys/src/games/gba/gba.c
sys/src/games/gba/mem.c
sys/src/games/gba/ppu.c
sys/src/games/md/cpu.c
sys/src/games/md/dat.h
sys/src/games/md/md.c
sys/src/games/md/mem.c
sys/src/games/md/vdp.c
sys/src/games/md/ym.c
sys/src/games/nes/apu.c
sys/src/games/nes/dat.h
sys/src/games/nes/mem.c
sys/src/games/nes/nes.c
sys/src/games/nes/ppu.c
sys/src/games/snes/cpu.c
sys/src/games/snes/dat.h
sys/src/games/snes/dsp.c
sys/src/games/snes/mem.c
sys/src/games/snes/ppu.c
sys/src/games/snes/snes.c
sys/src/games/snes/spc.c
sys/src/libemu/emu.c [new file with mode: 0644]
sys/src/libemu/mkfile [new file with mode: 0644]

index 89696f18e1ed76000cf4e73eb6fdd4d0df00f71e..b1ea5cc7c8e9e24b99b05a65ec2c757221518e5d 100644 (file)
@@ -4,7 +4,7 @@ gb, gba, nes, snes \- emulators
 .SH SYNOPSIS
 .B games/gb
 [
-.B -23acdT
+.B -acdT
 ]
 [
 .B -C
@@ -14,7 +14,7 @@ gb, gba, nes, snes \- emulators
 .br
 .B games/gba
 [
-.B -23aT
+.B -aT
 ] [
 .B -b
 .I biosfile
@@ -26,13 +26,13 @@ gb, gba, nes, snes \- emulators
 .br
 .B games/nes
 [
-.B -23aos
+.B -aos
 ]
 .I romfile
 .br
 .B games/snes
 [
-.B -23ahmsT
+.B -ahmsT
 ]
 .I romfile
 .SH DESCRIPTION
@@ -43,7 +43,7 @@ and
 .I snes
 are emulators for the Nintendo Game Boy and Game Boy Color (GB and GBC), Nintendo Game Boy Advance (GBA), Nintendo Entertainment System (NES), and Super Nintendo Entertainment System (SNES).
 They execute the romfile given as an argument.
-The \fBz\fR, \fBx\fR, \fBa\fR, \fBs\fR, return and shift keys correspond to B, A, Y, X, Start and Select, respectively.
+The \fBz\fR, \fBx\fR, \fBa\fR, \fBs\fR, \fBq\fR, \fBw\fRreturn and shift keys correspond to B, A, Y, X, L1, L2, Start and Select, respectively.
 Other keys:
 .TP
 F5
@@ -60,14 +60,8 @@ Exit the emulator.
 .PP
 Command line options:
 .TP
-.B -2 -3
-Scale the screen by the given factor.
-.TP
 .B -a
 Enable audio output.
-.TP
-.B -T
-Display percentage of how fast the emulator is running relative to a real console.
 .PP
 .B gb
 options:
index 382c34bf9ab867766aef828fc32b34e13c70d3b0..5b0714b357d8378600cef232d273e35c04ff0880 100644 (file)
@@ -4,14 +4,14 @@ md \- emulator
 .SH SYNOPSIS
 .B games/md
 [
-.B -23a
+.B -a
 ]
 .I romfile
 .SH DESCRIPTION
 .I Md
 is an emulator for the Sega Megadrive/Genesis.
 It executes the romfile given as an argument.
-The \fBz\fR, \fBx\fR, \fBc\fR, return and shift keys correspond to A, B, C, Start and Select, respectively.
+The \fBz\fR, \fBx\fR, \fBa\fR, return and shift keys correspond to A, B, C, Start and Select, respectively.
 Other keys:
 .TP
 Esc
@@ -22,9 +22,6 @@ Exit the emulator.
 .PP
 Command line options:
 .TP
-.B -2 -3
-Scale the screen by the given factor.
-.TP
 .B -a
 Enable audio output.
 .SH SOURCE
@@ -33,4 +30,4 @@ Enable audio output.
 Probably!
 .SH HISTORY
 .I Md
-first appeared in 9front (May, 2014).
+first appeared in 9front (November, 2014).
diff --git a/sys/man/2/emu b/sys/man/2/emu
new file mode 100644 (file)
index 0000000..6802641
--- /dev/null
@@ -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.
index c20333760629d31d6d030aa851816fe80250bc07..9b4e0504b30162460105b8371277d2ad7434d690 100644 (file)
@@ -4,18 +4,15 @@
 #include <draw.h>
 #include <mouse.h>
 #include <keyboard.h>
+#include <emu.h>
 #include "dat.h"
 #include "fns.h"
 
 char *bindir = "/sys/lib/c64";
-Image *tmp, *bg, *red;
-Rectangle picr, progr;
-Mousectl *mc;
-QLock pauselock;
-int paused, scale;
+Image *red;
+Rectangle progr;
 u8int *rom;
 int nrom;
-u64int keys;
 u16int joys;
 uchar *tape, tapever, tapeplay;
 ulong tapelen;
@@ -26,7 +23,8 @@ progress(int a, int b)
 {
        static int cur;
        int w;
-       
+
+       extern Image *bg;
        if(b == 0 || a == 0){
                if(cur != 0){
                        draw(screen, progr, bg, nil, ZP);
@@ -211,21 +209,6 @@ keyproc(void *)
 
 }
 
-static void
-screeninit(void)
-{
-       Point p, q;
-
-       p = divpt(addpt(screen->r.min, screen->r.max), 2);
-       picr = (Rectangle){subpt(p, Pt(picw/2*scale, pich/2*scale)), addpt(p, Pt(picw/2*scale, pich/2*scale))};
-       p.y += pich*scale*3/4;
-       q = Pt(Dx(screen->r) * 2/5, 8);
-       progr = (Rectangle){subpt(p, q), addpt(p, q)};
-       freeimage(tmp);
-       tmp = allocimage(display, Rect(0, 0, picw*scale, scale > 1 ? 1 : pich), XRGB32, 1, 0);
-       draw(screen, screen->r, bg, nil, ZP);
-}
-
 static void
 usage(void)
 {
@@ -236,17 +219,9 @@ usage(void)
 void
 threadmain(int argc, char **argv)
 {
-       scale = 1;
-
        memreset();
 
        ARGBEGIN {
-       case '2':
-               scale = 2;
-               break;
-       case '3':
-               scale = 3;
-               break;
        case 'c':
                loadcart(EARGF(usage()));
                break;
@@ -272,16 +247,8 @@ threadmain(int argc, char **argv)
        loadsys("crom.bin", crom, 4096);
        
        vicreset();
-       
-       if(initdraw(nil, nil, nil) < 0)
-               sysfatal("initdraw: %r");
-       mc = initmouse(nil, screen);
-       if(mc == nil)
-               sysfatal("initmouse: %r");
-       bg = allocimage(display, Rect(0, 0, 1, 1), screen->chan, 1, 0xCCCCCCFF);
+       initemu(picw, pich, 4, XRGB32, 1, keyproc);
        red = allocimage(display, Rect(0, 0, 1, 1), screen->chan, 1, 0xFF0000FF);
-       screeninit();
-       proccreate(keyproc, nil, mainstacksize);
 
        nmien = IRQRESTORE;
        pc = memread(0xFFFC) | memread(0xFFFD) << 8;
@@ -309,7 +276,8 @@ menu(void)
        static Menu m = {
                items, nil, 0
        };
-       
+
+       extern Mousectl *mc;
        switch(menuhit(3, mc, &m, nil)){
        case JOY:
                joymode = (joymode + 1) % 3;
@@ -332,52 +300,11 @@ menu(void)
 void
 flush(void)
 {
-       extern u8int pic[];
-//     vlong new, diff;
-//     static vlong old, delta;
-
-       if(nbrecvul(mc->resizec) > 0){
-               if(getwindow(display, Refnone) < 0)
-                       sysfatal("resize failed: %r");
-               screeninit();
-       }
+       extern Mousectl *mc;
+       flushmouse(0);
        while(nbrecv(mc->c, &mc->Mouse) > 0)
                if((mc->buttons & 4) != 0)
                        menu();
-       if(scale == 1){
-               loadimage(tmp, tmp->r, pic, picw*pich*4);
-               draw(screen, picr, tmp, nil, ZP);
-       }else{
-               Rectangle r;
-               uchar *s;
-               int w;
-
-               s = pic;
-               r = picr;
-               w = picw*4*scale;
-               while(r.min.y < picr.max.y){
-                       loadimage(tmp, tmp->r, s, w);
-                       s += w;
-                       r.max.y = r.min.y+scale;
-                       draw(screen, r, tmp, nil, ZP);
-                       r.min.y = r.max.y;
-               }
-       }
-       flushimage(display, 1);
-/*
-       if(audioout() < 0){
-               new = nsec();
-               diff = 0;
-               if(old != 0){
-                       diff = BILLION/60 - (new - old) - delta;
-                       if(diff >= MILLION)
-                               sleep(diff/MILLION);
-               }
-               old = nsec();
-               if(diff != 0){
-                       diff = (old - new) - (diff / MILLION) * MILLION;
-                       delta += (diff - delta) / 100;
-               }
-       }
-*/
+       flushscreen();
+       flushaudio(nil);
 }
index 5f77ff92f442fffddd3602483dbf5a4e6490e11d..cafd8e33328662b40532039dd1b9c05388dc1252 100644 (file)
@@ -1,5 +1,6 @@
 #include <u.h>
 #include <libc.h>
+#include <emu.h>
 #include "dat.h"
 #include "fns.h"
 
@@ -289,8 +290,6 @@ interrupt(int nmi, int brk)
        rP |= FLAGI;
 }
 
-int trace;
-
 void
 step(void)
 {
index f8f1de1ce93aa66e9f7c06af8ab8eb9de45628a7..723053d758aba782ea71f3fe3de9958e8ca7c298 100644 (file)
@@ -1,10 +1,8 @@
-typedef char s8int;
-
 extern u8int reg[47], crom[4096], krom[8192], brom[8192], cram[1024], cart[16384];
 
 extern u16int pc, curpc;
 extern u8int rP;
-extern int nrdy, irq, nmi, irqen, nmien, trace;
+extern int nrdy, irq, nmi, irqen, nmien;
 
 extern u8int pla;
 
@@ -12,9 +10,8 @@ extern uchar *tape, tapever, tapeplay;
 extern ulong tapelen;
 
 extern u16int ppux, ppuy, picw, pich;
-extern u64int keys;
 extern u16int joys;
-extern int scale, region;
+extern int region;
 
 enum {
        FLAGC = 1<<0,
@@ -81,8 +78,6 @@ enum {
 };
 
 enum {
-       BILLION = 1000*1000*1000,
-       MILLION = 1000*1000,
        HZ = 3579545,
        RATE = 44100,
        SAMPDIV = HZ / 3 / RATE,
index 5245a55e960b136629a70cac8af7423f167d7781..8e00bec4bb9b89602b537936c38e566b06f888a8 100644 (file)
@@ -1,6 +1,7 @@
 #include <u.h>
 #include <libc.h>
 #include <thread.h>
+#include <emu.h>
 #include "dat.h"
 #include "fns.h"
 
index 8233f38c8d4efbddcb368298813a86e6c78f17b2..c181b24468b30f466bbba71cc9c9bfb90113083b 100644 (file)
@@ -1,6 +1,7 @@
 #include <u.h>
 #include <libc.h>
 #include <thread.h>
+#include <emu.h>
 #include "dat.h"
 #include "fns.h"
 
@@ -9,7 +10,6 @@ u16int ppux, ppuy, lastx, wrapx, maxy, lvis, rvis, uvis, dvis, picw, pich, lbord
 u16int vc, vcbase, vmli;
 u8int badln, rc, displ, fract, visreg, hbord, vbord, rbord0, lbord0;
 u16int chrp[40];
-u8int pic[420*263*4*3];
 u64int pxs, npxs, npxs0, opxs;
 u8int fg;
 
@@ -92,24 +92,40 @@ vicreset(void)
 void
 pixeldraw(u64int p, int n)
 {
-       int i, j;
+       int i;
+       union { u8int c[4]; u32int l; } u;
        static u8int cr[] = {0, 255, 136, 170, 204, 0, 0, 238, 221, 102, 255, 51, 119, 170, 0, 187};
        static u8int cg[] = {0, 255, 0, 255, 68, 204, 0, 238, 136, 68, 119, 51, 119, 255, 136, 187};
        static u8int cb[] = {0, 255, 0, 238, 204, 85, 170, 119, 85, 0, 119, 51, 119, 102, 255, 187};
-       u8int *q, c;
-       
-       q = pic + picidx * 4 * scale;
+       u8int c;
+       u32int *q;
+
+       q = (u32int *)pic + picidx * scale;
        for(i = 0; i < n; i++){
                c = p >> 56;
                p <<= 8;
-       
-               j = scale;
-               do{
-                       *q++ = cb[c];
-                       *q++ = cg[c];
-                       *q++ = cr[c];
-                       q++;
-               }while(--j);
+               u.c[0] = cb[c];
+               u.c[1] = cg[c];
+               u.c[2] = cr[c];
+               u.c[3] = 0;
+               switch(scale){
+               case 16: *q++ = u.l;
+               case 15: *q++ = u.l;
+               case 14: *q++ = u.l;
+               case 13: *q++ = u.l;
+               case 12: *q++ = u.l;
+               case 11: *q++ = u.l;
+               case 10: *q++ = u.l;
+               case 9: *q++ = u.l;
+               case 8: *q++ = u.l;
+               case 7: *q++ = u.l;
+               case 6: *q++ = u.l;
+               case 5: *q++ = u.l;
+               case 4: *q++ = u.l;
+               case 3: *q++ = u.l;
+               case 2: *q++ = u.l;
+               default: *q++ = u.l;
+               }
        }
        picidx += n;
 }
index b01c2f80d3ce2b22faa3c76629db63bb3d09d584..dc78992ace3f3aad65cb5e4bb9fa21103186c62e 100644 (file)
@@ -1,6 +1,7 @@
 #include <u.h>
 #include <libc.h>
 #include <thread.h>
+#include <emu.h>
 #include "dat.h"
 #include "fns.h"
 
@@ -475,7 +476,7 @@ audioout(void)
        if(sbufp == sbuf)
                return 0;
        cl = clock;
-       rc = write(fd, sbuf, (sbufp - sbuf) * 2);
+       rc = warp10 ? (sbufp - sbuf) * 2 : write(fd, sbuf, (sbufp - sbuf) * 2);
        if(rc > 0)
                sbufp -= (rc+1)/2;
        if(sbufp < sbuf)
index 88900ea0b552c30602c9231dc6d83428e080ad8a..81c45a0344882cae44c4e2330a2e3b2c7f210f90 100644 (file)
@@ -1,6 +1,7 @@
 #include <u.h>
 #include <libc.h>
 #include <thread.h>
+#include <emu.h>
 #include "dat.h"
 #include "fns.h"
 
index 428cfffb93090571225f680d693aaf86fd9ce317..68c03372c4bfff91ae2a6f5d85b8eda423c2a879 100644 (file)
@@ -1,10 +1,6 @@
-typedef char s8int;
-typedef short s16int;
-typedef long s32int;
 typedef struct Event Event;
 typedef struct MBC3Timer MBC3Timer;
 
-extern int trace;
 extern u16int curpc;
 
 extern uchar *rom, *back, reg[256], oam[256];
@@ -24,7 +20,6 @@ extern u8int apustatus;
 
 extern u8int mode;
 extern u8int mbc, feat;
-extern int keys, scale;
 
 enum {
        JOYP = 0x00,
@@ -129,8 +124,6 @@ enum {
        TIMERSIZ = 18,
        PICW = 160,
        PICH = 144,
-       MILLION = 1000000,
-       BILLION = 1000000000,
        FREQ = 1<<23
 };
 
index 374af931af30670bb85707e46e62a0dcea5865cb..55ced730a7fd7fa5e6240d2765f190f04b38120a 100644 (file)
@@ -2,34 +2,28 @@
 #include <libc.h>
 #include <thread.h>
 #include <draw.h>
-#include <mouse.h>
 #include <keyboard.h>
+#include <emu.h>
 #include "dat.h"
 #include "fns.h"
 
 int cpuhalt;
-int scale, profile;
-Rectangle picr;
-Image *bg, *tmp;
-Mousectl *mc;
-int keys, paused, framestep, backup;
-QLock pauselock;
+int backup;
 int savefd = -1, saveframes;
 ulong clock;
-int savereq, loadreq;
 u8int mbc, feat, mode;
 extern MBC3Timer timer, timerl;
 
-void *
-emalloc(ulong sz)
+extern double TAU; 
+void
+tauup(void)
 {
-       void *v;
-       
-       v = malloc(sz);
-       if(v == nil)
-               sysfatal("malloc: %r");
-       setmalloctag(v, getcallerpc(&sz));
-       return v;
+       TAU += 5000;
+}
+void
+taudn(void)
+{
+       TAU -= 5000;
 }
 
 void
@@ -203,175 +197,15 @@ loadrom(char *file)
 
 }
 
-void
-screeninit(void)
-{
-       Point p;
-
-       p = divpt(addpt(screen->r.min, screen->r.max), 2);
-       picr = (Rectangle){subpt(p, Pt(scale * PICW/2, scale * PICH/2)), addpt(p, Pt(scale * PICW/2, scale * PICH/2))};
-       freeimage(tmp);
-       tmp = allocimage(display, Rect(0, 0, scale * PICW, scale > 1 ? 1 : scale * PICH), XRGB32, scale > 1, 0);
-       draw(screen, screen->r, bg, nil, ZP);   
-}
-
-void
-keyproc(void *)
-{
-       int fd, n, k;
-       static char buf[256];
-       char *s;
-       Rune r;
-       extern double TAU;
-
-       fd = open("/dev/kbd", OREAD);
-       if(fd < 0)
-               sysfatal("open: %r");
-       for(;;){
-               if(buf[0] != 0){
-                       n = strlen(buf)+1;
-                       memmove(buf, buf+n, sizeof(buf)-n);
-               }
-               if(buf[0] == 0){
-                       n = read(fd, buf, sizeof(buf)-1);
-                       if(n <= 0)
-                               sysfatal("read /dev/kbd: %r");
-                       buf[n-1] = 0;
-                       buf[n] = 0;
-               }
-               if(buf[0] == 'c'){
-                       if(utfrune(buf, KF|5))
-                               savereq = 1;
-                       if(utfrune(buf, KF|6))
-                               loadreq = 1;
-                       if(utfrune(buf, Kdel)){
-                               close(fd);
-                               threadexitsall(nil);
-                       }
-                       if(utfrune(buf, 't'))
-                               trace = !trace;
-                       if(utfrune(buf, KF|9))
-                               TAU += 5000;
-                       if(utfrune(buf, KF|10))
-                               TAU -= 5000;
-               }
-               if(buf[0] != 'k' && buf[0] != 'K')
-                       continue;
-               s = buf + 1;
-               k = 0;
-               while(*s != 0){
-                       s += chartorune(&r, s);
-                       switch(r){
-                       case Kdel: close(fd); threadexitsall(nil);
-                       case 'z': k |= 1<<5; break;
-                       case 'x': k |= 1<<4; break;
-                       case Kshift: k |= 1<<6; break;
-                       case 10: k |= 1<<7; break;
-                       case Kup: k |= 1<<2; break;
-                       case Kdown: k |= 1<<3; break;
-                       case Kleft: k |= 1<<1; break;
-                       case Kright: k |= 1<<0; break;
-                       case Kesc:
-                               if(paused)
-                                       qunlock(&pauselock);
-                               else
-                                       qlock(&pauselock);
-                               paused = !paused;
-                               break;
-                       case KF|1:      
-                               if(paused){
-                                       qunlock(&pauselock);
-                                       paused=0;
-                               }
-                               framestep = !framestep;
-                               break;
-                       }
-               }
-               k &= ~(k << 1 & 0x0a | k >> 1 & 0x05);
-               keys = k;
-       }
-
-}
-
-void
-timing(void)
-{
-       static int fcount;
-       static vlong old;
-       static char buf[32];
-       vlong new;
-       
-       if(++fcount == 60)
-               fcount = 0;
-       else
-               return;
-       new = nsec();
-       if(new != old)
-               sprint(buf, "%6.2f%%", 1e11 / (new - old));
-       else
-               buf[0] = 0;
-       draw(screen, rectaddpt(Rect(10, 10, 200, 30), screen->r.min), bg, nil, ZP);
-       string(screen, addpt(screen->r.min, Pt(10, 10)), display->black, ZP, display->defaultfont, buf);
-       old = nsec();
-}
-
 void
 flush(void)
 {
        extern uchar pic[];
-       Mouse m;
        static vlong old, delta;
-       vlong new, diff;
-
-       if(nbrecvul(mc->resizec) > 0){
-               if(getwindow(display, Refnone) < 0)
-                       sysfatal("resize failed: %r");
-               screeninit();
-       }
-       while(nbrecv(mc->c, &m) > 0)
-               ;
-       if(scale == 1){
-               loadimage(tmp, tmp->r, pic, PICW*PICH*4);
-               draw(screen, picr, tmp, nil, ZP);
-       } else {
-               Rectangle r;
-               uchar *s;
-               int w;
 
-               s = pic;
-               r = picr;
-               w = PICW*4*scale;
-               while(r.min.y < picr.max.y){
-                       loadimage(tmp, tmp->r, s, w);
-                       s += w;
-                       r.max.y = r.min.y+scale;
-                       draw(screen, r, tmp, nil, ZP);
-                       r.min.y = r.max.y;
-               }
-       }
-       flushimage(display, 1);
-       if(profile)
-               timing();
-       if(audioout() < 0){
-               new = nsec();
-               diff = 0;
-               if(old != 0){
-                       diff = BILLION/60 - (new - old) - delta;
-                       if(diff >= MILLION)
-                               sleep(diff/MILLION);
-               }
-               old = nsec();
-               if(diff != 0){
-                       diff = (old - new) - (diff / MILLION) * MILLION;
-                       delta += (diff - delta) / 100;
-               }
-       }
-       if(framestep){
-               paused = 1;
-               qlock(&pauselock);
-               framestep = 0;
-       }
-       
+       flushmouse(1);
+       flushscreen();
+       flushaudio(audioout);
        if(saveframes > 0 && --saveframes == 0)
                flushback();
        if(savereq){
@@ -430,20 +264,10 @@ threadmain(int argc, char **argv)
        int t;
 
        colinit();
-       scale = 1;
        ARGBEGIN {
-       case '2':
-               scale = 2;
-               break;
-       case '3':
-               scale = 3;
-               break;
        case 'a':
                audioinit();
                break;
-       case 'T':
-               profile++;
-               break;
        case 'c':
                mode |= CGB;
                break;
@@ -460,15 +284,17 @@ threadmain(int argc, char **argv)
                usage();
 
        loadrom(argv[0]);
-       
-       if(initdraw(nil, nil, nil) < 0)
-               sysfatal("initdraw: %r");
-       mc = initmouse(nil, screen);
-       if(mc == nil)
-               sysfatal("initmouse: %r");
-       proccreate(keyproc, nil, mainstacksize);
-       bg = allocimage(display, Rect(0, 0, 1, 1), screen->chan, 1, 0xCCCCCCFF);
-       screeninit();
+       initemu(PICW, PICH, 4, XRGB32, 1, nil);
+       regkey("b", 'z', 1<<5);
+       regkey("a", 'x', 1<<4);
+       regkey("control", Kshift, 1<<6);
+       regkey("start", '\n', 1<<7);
+       regkey("up", Kup, 1<<2);
+       regkey("down", Kdown, 1<<3);
+       regkey("left", Kleft, 1<<1);
+       regkey("right", Kright, 1<<0);
+       regkeyfn(KF|9, tauup);
+       regkeyfn(KF|10, taudn);
 
        eventinit();
        meminit();
index a9c629a1361998a3515e043067cb94375db851a9..a6c6c7599994d033a258cb3800116b2dfb0348d2 100644 (file)
@@ -1,6 +1,7 @@
 #include <u.h>
 #include <libc.h>
 #include <thread.h>
+#include <emu.h>
 #include "dat.h"
 #include "fns.h"
 
index bd1ecf905cad7f4a0aceafa020c5e64b30dd481a..3895816219dd3d38902a2d5d18dccb2d5a5bea9a 100644 (file)
@@ -1,11 +1,11 @@
 #include <u.h>
 #include <libc.h>
 #include <thread.h>
+#include <emu.h>
 #include "dat.h"
 #include "fns.h"
 
 u8int ppustate, ppuy;
-u32int pic[PICW*PICH*3];
 ulong hblclock, rendclock;
 jmp_buf mainjmp, renderjmp;
 static int cyc, done, ppux, ppux0;
@@ -63,7 +63,7 @@ ppurender(void)
                        }
                ppux = 0;
                ppux0 = 0;
-               picp = pic + ppuy * PICW * scale;
+               picp = (u32int*)pic + ppuy * PICW * scale;
                y = ppuy + reg[SCY] << 1 & 14;
                ta = 0x1800 | reg[LCDC] << 7 & 0x400 | ppuy + reg[SCY] << 2 & 0x3e0 | reg[SCX] >> 3;
                x = -(reg[SCX] & 7);
@@ -197,7 +197,7 @@ sprites(void)
        int x, x1;
        u16int chr;
        
-       picp = pic + ppuy * PICW * scale;
+       picp = (u32int*)pic + ppuy * PICW * scale;
        for(q = spr; q < sprm; q++){
                if(q->x <= ppux0 || q->x >= ppux + 8)
                        continue;
@@ -254,18 +254,31 @@ static void
 lineexpand(void)
 {
        u32int *picp, *p, *q, l;
-       int i, s;
+       int i;
 
-       s = scale;
-       picp = pic + ppuy * PICW * s;
+       picp = (u32int*)pic + ppuy * PICW * scale;
        p = picp + PICW;
        q = picp + PICW * scale;
        for(i = PICW; --i >= 0; ){
                l = *--p;
-               *--q = l;
-               *--q = l;
-               if(scale == 3)
-                       *--q = l;
+               switch(scale){
+               case 16: *--q = l;
+               case 15: *--q = l;
+               case 14: *--q = l;
+               case 13: *--q = l;
+               case 12: *--q = l;
+               case 11: *--q = l;
+               case 10: *--q = l;
+               case 9: *--q = l;
+               case 8: *--q = l;
+               case 7: *--q = l;
+               case 6: *--q = l;
+               case 5: *--q = l;
+               case 4: *--q = l;
+               case 3: *--q = l;
+               case 2: *--q = l;
+               case 1: *--q = l;
+               }
        }
 }
 
index 3e888357213ec6ff2fc4a7554a3e6d907b1bbf36..4858aced95795f94f269cf29d0b902db1882117c 100644 (file)
@@ -1,6 +1,7 @@
 #include <u.h>
 #include <libc.h>
 #include <thread.h>
+#include <emu.h>
 #include "dat.h"
 #include "fns.h"
 
@@ -350,7 +351,7 @@ sndwrite(u16int a, u16int v)
 void
 audioinit(void)
 {
-       fd = open("/dev/audio", OWRITE);                                                                                                                                                                                                                                                                                                               
+       fd = open("/dev/audio", OWRITE);
        if(fd < 0)
                sysfatal("open: %r");
        sbufp = sbuf;
@@ -370,7 +371,7 @@ audioout(void)
        if(sbufp == sbuf)
                return 0;
        cl = clock;
-       rc = write(fd, sbuf, (sbufp - sbuf) * 2);
+       rc = warp10 ? (sbufp - sbuf) * 2 : write(fd, sbuf, (sbufp - sbuf) * 2);
        if(rc > 0)
                sbufp -= (rc+1)/2;
        if(sbufp < sbuf)
index c92e4ff9d3c26d8753dba8762d43864c22d078dd..a8354324f748be29a717e70403d9734b6be8b628 100644 (file)
@@ -1,6 +1,7 @@
 #include <u.h>
 #include <libc.h>
 #include <thread.h>
+#include <emu.h>
 #include "dat.h"
 #include "fns.h"
 
@@ -34,7 +35,7 @@ u32int curpc;
 int irq;
 
 u32int instr0, instr1, pipel = -1;
-int cyc, trace;
+int cyc;
 
 Var cpuvars[] = {
        ARR(r), VAR(cpsr), VAR(spsr), ARR(saver), VAR(irq),
index a609b850bbc7ed42fcb4b4dab41f69723129b550..d930c7b287a1af1f81b364a5df49c80528ae64e9 100644 (file)
@@ -1,9 +1,4 @@
-typedef char s8int;
-typedef short s16int;
-typedef long s32int;
-typedef vlong s64int;
-
-extern int cpuhalt, trace, keys;
+extern int cpuhalt;
 
 extern u32int curpc;
 extern int irq;
@@ -18,7 +13,6 @@ extern int nrom, nback, backup;
 extern int hblank, ppuy;
 
 extern int clock;
-extern int scale;
 
 typedef struct Event Event;
 struct Event {
@@ -141,8 +135,6 @@ enum {
        KB = 1024,
        BACKTYPELEN = 64,
        HZ = 16777216,
-       MILLION = 1000000,
-       BILLION = 1000000000,
 };
 
 typedef struct Var Var;
index 5a53b68b3a96d5f87af0a9b9a12e2b9851f8791c..06e90b998b551c35c01f9964ddf51a9152adcf50 100644 (file)
@@ -2,36 +2,19 @@
 #include <libc.h>
 #include <thread.h>
 #include <draw.h>
-#include <mouse.h>
 #include <keyboard.h>
+#include <emu.h>
 #include "dat.h"
 #include "fns.h"
 
 int cpuhalt;
-int scale, profile;
-Rectangle picr;
-Image *bg, *tmp;
-Mousectl *mc;
-int keys, paused, framestep, backup;
-QLock pauselock;
+Image *tmp;
+int backup;
 int savefd, saveframes;
 int clock;
-int savereq, loadreq;
 
 char *biosfile = "/sys/games/lib/gbabios.bin";
 
-void *
-emalloc(ulong sz)
-{
-       void *v;
-       
-       v = malloc(sz);
-       if(v == nil)
-               sysfatal("malloc: %r");
-       setmalloctag(v, getcallerpc(&sz));
-       return v;
-}
-
 void
 writeback(void)
 {
@@ -211,173 +194,15 @@ loadrom(char *file)
                nrom -= 256;
 }
 
-void
-screeninit(void)
-{
-       Point p;
-
-       p = divpt(addpt(screen->r.min, screen->r.max), 2);
-       picr = (Rectangle){subpt(p, Pt(scale * 120, scale * 80)), addpt(p, Pt(scale * 120, scale * 80))};
-       freeimage(tmp);
-       tmp = allocimage(display, Rect(0, 0, scale * 240, scale > 1 ? 1 : scale * 160), CHAN4(CIgnore, 1, CBlue, 5, CGreen, 5, CRed, 5), scale > 1, 0);
-       draw(screen, screen->r, bg, nil, ZP);   
-}
-
-void
-keyproc(void *)
-{
-       int fd, n, k;
-       static char buf[256];
-       char *s;
-       Rune r;
-
-       fd = open("/dev/kbd", OREAD);
-       if(fd < 0)
-               sysfatal("open: %r");
-       for(;;){
-               if(buf[0] != 0){
-                       n = strlen(buf)+1;
-                       memmove(buf, buf+n, sizeof(buf)-n);
-               }
-               if(buf[0] == 0){
-                       n = read(fd, buf, sizeof(buf)-1);
-                       if(n <= 0)
-                               sysfatal("read /dev/kbd: %r");
-                       buf[n-1] = 0;
-                       buf[n] = 0;
-               }
-               if(buf[0] == 'c'){
-                       if(utfrune(buf, KF|5))
-                               savereq = 1;
-                       if(utfrune(buf, KF|6))
-                               loadreq = 1;
-                       if(utfrune(buf, Kdel)){
-                               close(fd);
-                               threadexitsall(nil);
-                       }
-                       if(utfrune(buf, 't'))
-                               trace = !trace;
-               }
-               if(buf[0] != 'k' && buf[0] != 'K')
-                       continue;
-               s = buf + 1;
-               k = 0;
-               while(*s != 0){
-                       s += chartorune(&r, s);
-                       switch(r){
-                       case Kdel: close(fd); threadexitsall(nil);
-                       case 'z': k |= 1<<1; break;
-                       case 'x': k |= 1<<0; break;
-                       case 'a': k |= 1<<9; break;
-                       case 's': k |= 1<<8; break;
-                       case Kshift: k |= 1<<2; break;
-                       case 10: k |= 1<<3; break;
-                       case Kup: k |= 1<<6; break;
-                       case Kdown: k |= 1<<7; break;
-                       case Kleft: k |= 1<<5; break;
-                       case Kright: k |= 1<<4; break;
-                       case Kesc:
-                               if(paused)
-                                       qunlock(&pauselock);
-                               else
-                                       qlock(&pauselock);
-                               paused = !paused;
-                               break;
-                       case KF|1:      
-                               if(paused){
-                                       qunlock(&pauselock);
-                                       paused=0;
-                               }
-                               framestep = !framestep;
-                               break;
-                       }
-               }
-               k &= ~(k << 1 & 0xa0 | k >> 1 & 0x50);
-               keys = k;
-       }
-
-}
-
-void
-timing(void)
-{
-       static int fcount;
-       static vlong old;
-       static char buf[32];
-       vlong new;
-       
-       if(++fcount == 60)
-               fcount = 0;
-       else
-               return;
-       new = nsec();
-       if(new != old)
-               sprint(buf, "%6.2f%%", 1e11 / (new - old));
-       else
-               buf[0] = 0;
-       draw(screen, rectaddpt(Rect(10, 10, 200, 30), screen->r.min), bg, nil, ZP);
-       string(screen, addpt(screen->r.min, Pt(10, 10)), display->black, ZP, display->defaultfont, buf);
-       old = nsec();
-}
-
 void
 flush(void)
 {
-       extern uchar pic[];
-       Mouse m;
        int x;
-       static vlong old, delta;
-       vlong new, diff;
 
-       if(nbrecvul(mc->resizec) > 0){
-               if(getwindow(display, Refnone) < 0)
-                       sysfatal("resize failed: %r");
-               screeninit();
-       }
-       while(nbrecv(mc->c, &m) > 0)
-               ;
-       if(scale == 1){
-               loadimage(tmp, tmp->r, pic, 240*160*2);
-               draw(screen, picr, tmp, nil, ZP);
-       } else {
-               Rectangle r;
-               uchar *s;
-               int w;
+       flushmouse(1);
+       flushscreen();
+       flushaudio(audioout);
 
-               s = pic;
-               r = picr;
-               w = 240*2*scale;
-               while(r.min.y < picr.max.y){
-                       loadimage(tmp, tmp->r, s, w);
-                       s += w;
-                       r.max.y = r.min.y+scale;
-                       draw(screen, r, tmp, nil, ZP);
-                       r.min.y = r.max.y;
-               }
-       }
-       flushimage(display, 1);
-       if(profile)
-               timing();
-       if(audioout() < 0){
-               new = nsec();
-               diff = 0;
-               if(old != 0){
-                       diff = BILLION/60 - (new - old) - delta;
-                       if(diff >= MILLION)
-                               sleep(diff/MILLION);
-               }
-               old = nsec();
-               if(diff != 0){
-                       diff = (old - new) - (diff / MILLION) * MILLION;
-                       delta += (diff - delta) / 100;
-               }
-       }
-       if(framestep){
-               paused = 1;
-               qlock(&pauselock);
-               framestep = 0;
-       }
-       
        if(saveframes > 0 && --saveframes == 0)
                flushback();
        
@@ -395,7 +220,7 @@ flush(void)
 void
 usage(void)
 {
-       fprint(2, "usage: %s [-23aT] [-s savetype] [-b biosfile] rom\n", argv0);
+       fprint(2, "usage: %s [-aT] [-s savetype] [-b biosfile] rom\n", argv0);
        exits("usage");
 }
 
@@ -405,14 +230,7 @@ threadmain(int argc, char **argv)
        char *s;
        int t;
 
-       scale = 1;
        ARGBEGIN {
-       case '2':
-               scale = 2;
-               break;
-       case '3':
-               scale = 3;
-               break;
        case 'a':
                audioinit();
                break;
@@ -425,9 +243,6 @@ threadmain(int argc, char **argv)
        case 'b':
                biosfile = strdup(EARGF(usage()));
                break;
-       case 'T':
-               profile++;
-               break;
        default:
                usage();
        } ARGEND;
@@ -436,16 +251,17 @@ threadmain(int argc, char **argv)
 
        loadbios();
        loadrom(argv[0]);
-       
-       if(initdraw(nil, nil, nil) < 0)
-               sysfatal("initdraw: %r");
-       mc = initmouse(nil, screen);
-       if(mc == nil)
-               sysfatal("initmouse: %r");
-       proccreate(keyproc, nil, mainstacksize);
-       bg = allocimage(display, Rect(0, 0, 1, 1), screen->chan, 1, 0xCCCCCCFF);
-       screeninit();
-
+       initemu(240, 160, 2, CHAN4(CIgnore, 1, CBlue, 5, CGreen, 5, CRed, 5), 1, nil);
+       regkey("b", 'z', 1<<1);
+       regkey("a", 'x', 1<<0);
+       regkey("l1", 'a', 1<<9);
+       regkey("r1", 's', 1<<8);
+       regkey("control", Kshift, 1<<2);
+       regkey("start", '\n', 1<<3);
+       regkey("up", Kup, 1<<6);
+       regkey("down", Kdown, 1<<7);
+       regkey("left", Kleft, 1<<5);
+       regkey("right", Kright, 1<<4);
        eventinit();
        memreset();
        reset();
index 75ff9d31c51a9908a47b17976edd9bd71527894d..032f35eae2f7f821ca516b7f6db929c42cd5bbec 100644 (file)
@@ -1,6 +1,7 @@
 #include <u.h>
 #include <libc.h>
 #include <thread.h>
+#include <emu.h>
 #include "dat.h"
 #include "fns.h"
 
index a87caba172b6e22e22ea63a3c5385bb7fb29899c..7de5a1e7b6887e6f29e4cc162480c653c4a1769d 100644 (file)
@@ -1,6 +1,7 @@
 #include <u.h>
 #include <libc.h>
 #include <thread.h>
+#include <emu.h>
 #include "dat.h"
 #include "fns.h"
 
@@ -11,7 +12,6 @@ int ppux0;
 u32int pixcol[480];
 u8int pixpri[480];
 u8int pixwin[240];
-uchar pic[240*160*3*2];
 int objalpha;
 
 typedef struct bg bg;
@@ -642,40 +642,6 @@ colormath(int x1)
        }
 }
 
-void
-linecopy(void)
-{
-       u32int *p;
-       uchar *q;
-       u16int *r;
-       u16int v;
-       union { u16int w; u8int b[2]; } u;
-       int n;
-       
-       p = pixcol;
-       q = pic + ppuy * 240 * 2 * scale;
-       r = (u16int*)q;
-       n = 240;
-       while(n--){
-               v = *p++;
-               if(scale == 1){
-                       *q++ = v;
-                       *q++ = v >> 8;
-                       continue;
-               }
-               u.b[0] = v;
-               u.b[1] = v >> 8;
-               if(scale == 2){
-                       *r++ = u.w;
-                       *r++ = u.w;
-               }else{
-                       *r++ = u.w;
-                       *r++ = u.w;
-                       *r++ = u.w;
-               }
-       }
-}
-
 void
 syncppu(int x1)
 {
@@ -724,6 +690,43 @@ syncppu(int x1)
        ppux0 = x1;
 }
 
+void
+linecopy(u32int *p, int y)
+{
+       uchar *q;
+       u16int *r;
+       u16int v;
+       union { u16int w; u8int b[2]; } u;
+       int n;
+
+       q = pic + y * 240 * 2 * scale;
+       r = (u16int*)q;
+       n = 240;
+       while(n--){
+               v = *p++;
+               u.b[0] = v;
+               u.b[1] = v >> 8;
+               switch(scale){
+               case 16: *r++ = u.w;
+               case 15: *r++ = u.w;
+               case 14: *r++ = u.w;
+               case 13: *r++ = u.w;
+               case 12: *r++ = u.w;
+               case 11: *r++ = u.w;
+               case 10: *r++ = u.w;
+               case 9: *r++ = u.w;
+               case 8: *r++ = u.w;
+               case 7: *r++ = u.w;
+               case 6: *r++ = u.w;
+               case 5: *r++ = u.w;
+               case 4: *r++ = u.w;
+               case 3: *r++ = u.w;
+               case 2: *r++ = u.w;
+               default: *r++ = u.w;
+               }
+       }
+}
+
 void
 hblanktick(void *)
 {
@@ -755,7 +758,7 @@ hblanktick(void *)
        }else{
                syncppu(240);
                if(ppuy < 160)
-                       linecopy();
+                       linecopy(pixcol, ppuy);
                addevent(&evhblank, 68*4);
                hblank = 1;
                if((stat & IRQHBLEN) != 0)
index 8a7e8db86e22811517af591947ad5472d7a1c3f5..1a0325f52996e0c1deaeca4bb9c605a66c1e96a1 100644 (file)
@@ -1,6 +1,7 @@
 #include <u.h>
 #include <libc.h>
 #include <thread.h>
+#include <emu.h>
 #include "dat.h"
 #include "fns.h"
 
@@ -19,7 +20,7 @@ extern u32int irql[8];
 u32int irqla[8];
 u16int rS;
 static u32int op;
-int trace, tim;
+int tim;
 #define ra (r+8)
 
 static void
index f61e9a13e0b82a58b90619d43008be6ff3209f28..5323a7d79ca8ec5bddf7200e6691af6faae243d5 100644 (file)
@@ -1,9 +1,4 @@
-typedef signed char s8int;
-typedef signed short s16int;
-typedef signed long s32int;
-
 extern u32int curpc, irq;
-extern int trace, debug;
 
 extern u8int reg[32];
 extern u8int dma;
@@ -18,8 +13,6 @@ extern u8int *sram;
 extern u32int sramctl, sram0, sram1;
 extern int savefd, saveclock;
 
-extern int keys, scale;
-
 extern u16int vram[32768], vsram[40];
 extern u32int cramc[64];
 extern u16int vdpstat;
@@ -82,8 +75,6 @@ enum {
        RATE = 44100,
        SAMPDIV = FREQ / RATE,
        SAVEFREQ = FREQ / 4,
-       MILLION = 1000 * 1000,
-       BILLION = 1000 * 1000 * 1000,
 };
 
 enum {
index f8ffcc52c3e541ff1b92ac53d98039bbfe3f0d5a..557668dc7b01bc539227d83f1da99c557e53f9ae 100644 (file)
@@ -3,29 +3,18 @@
 #include <thread.h>
 #include <draw.h>
 #include <keyboard.h>
-#include <mouse.h>
+#include <emu.h>
 #include "dat.h"
 #include "fns.h"
 
-int debug;
-
 u16int *prg;
 int nprg;
 u8int *sram;
 u32int sramctl, nsram, sram0, sram1;
 int savefd = -1;
 
-int keys;
-
 int dmaclock, vdpclock, z80clock, audioclock, ymclock, saveclock;
 
-int scale, paused;
-QLock pauselock;
-Mousectl *mc;
-Channel *flushc;
-Rectangle picr;
-Image *tmp, *bg;
-
 void
 flushram(void)
 {
@@ -113,147 +102,15 @@ loadrom(char *file)
        }
 }
 
-void
-screeninit(void)
-{
-       Point p;
-
-       originwindow(screen, Pt(0, 0), screen->r.min);
-       p = divpt(addpt(screen->r.min, screen->r.max), 2);
-       picr = (Rectangle){subpt(p, Pt(scale * 160, scale * 112)), addpt(p, Pt(scale * 160, scale * 112))};
-       if(tmp != nil) freeimage(tmp);
-       tmp = allocimage(display, Rect(0, 0, scale * 320, scale > 1 ? 1 : scale * 224), XRGB32, scale > 1, 0);
-       if(bg != nil) freeimage(bg);
-       bg = allocimage(display, Rect(0, 0, 1, 1), screen->chan, 1, 0xCCCCCCFF);
-       draw(screen, screen->r, bg, nil, ZP);   
-}
-
-void
-screenproc(void *)
-{
-       extern u8int pic[320*224*4*4];
-       extern int intla;
-       Rectangle r;
-       uchar *s;
-       int w, h;
-
-       enum { AMOUSE, ARESIZE, AFLUSH, AEND };
-       Alt a[AEND+1] = {
-               { mc->c,        nil,    CHANRCV },
-               { mc->resizec,  nil,    CHANRCV },
-               { flushc,       nil,    CHANRCV },
-               { nil,          nil,    CHANEND }
-       };
-
-       for(;;){
-               switch(alt(a)){
-               case ARESIZE:
-                       if(getwindow(display, Refnone) < 0)
-                               sysfatal("resize failed: %r");
-                       screeninit();
-                       /* wet floor */
-               case AFLUSH:
-                       if(scale == 1){
-                               loadimage(tmp, tmp->r, pic, 320*224*4);
-                               draw(screen, picr, tmp, nil, ZP);
-                       }else{
-                               s = pic;
-                               r = picr;
-                               w = 320*4*scale;
-                               h = scale;
-                               if(intla && (h & 1) == 0)
-                                       h >>= 1;
-                               while(r.min.y < picr.max.y){
-                                       loadimage(tmp, tmp->r, s, w);
-                                       s += w;
-                                       r.max.y = r.min.y+h;
-                                       draw(screen, r, tmp, nil, ZP);
-                                       r.min.y = r.max.y;
-                               }
-                       }
-                       flushimage(display, 1);
-                       break;
-               }
-       }
-}
-
-void
-keyproc(void *)
-{
-       int fd, n, k;
-       static char buf[256];
-       char *s;
-       Rune r;
-
-       fd = open("/dev/kbd", OREAD);
-       if(fd < 0)
-               sysfatal("open: %r");
-       for(;;){
-               if(buf[0] != 0){
-                       n = strlen(buf)+1;
-                       memmove(buf, buf+n, sizeof(buf)-n);
-               }
-               if(buf[0] == 0){
-                       n = read(fd, buf, sizeof(buf)-1);
-                       if(n <= 0)
-                               sysfatal("read /dev/kbd: %r");
-                       buf[n-1] = 0;
-                       buf[n] = 0;
-               }
-               if(buf[0] == 'c'){
-                       if(utfrune(buf, Kdel)){
-                               close(fd);
-                               threadexitsall(nil);
-                       }
-                       if(utfrune(buf, 't'))
-                               trace = !trace;
-               }
-               if(buf[0] != 'k' && buf[0] != 'K')
-                       continue;
-               s = buf + 1;
-               k = 0xc00;
-               while(*s != 0){
-                       s += chartorune(&r, s);
-                       if(r >= '0' && r <= '9') debug = r - '0';
-                       switch(r){
-                       case Kdel: close(fd); threadexitsall(nil);
-                       case 'c':       k |= 0x0020; break;
-                       case 'x':       k |= 0x0010; break;
-                       case 'z':       k |= 0x1000; break;
-                       case 10:        k |= 0x2000; break;
-                       case Kup:       k |= 0x0101; break;
-                       case Kdown:     k |= 0x0202; break;
-                       case Kleft:     k |= 0x0004; break;
-                       case Kright:    k |= 0x0008; break;
-                       case Kesc:
-                               if(paused)
-                                       qunlock(&pauselock);
-                               else
-                                       qlock(&pauselock);
-                               paused = !paused;
-                               break;
-                       }
-               }
-               keys = ~k;
-       }
-}
-
 void
 threadmain(int argc, char **argv)
 {
        int t;
 
-       scale = 1;
        ARGBEGIN{
        case 'a':
                initaudio();
                break;
-       case '2':
-               scale = 2;
-               break;
-       case '3':
-               scale = 3;
-               break;
        default:
                ;
        } ARGEND;
@@ -263,15 +120,15 @@ threadmain(int argc, char **argv)
                threadexitsall("usage");
        }
        loadrom(*argv);
-       if(initdraw(nil, nil, argv0) < 0)
-               sysfatal("initdraw: %r");
-       flushc = chancreate(sizeof(ulong), 1);
-       mc = initmouse(nil, screen);
-       if(mc == nil)
-               sysfatal("initmouse: %r");
-       screeninit();
-       proccreate(keyproc, nil, 8192);
-       proccreate(screenproc, nil, 8192);
+       initemu(320, 224, 4, XRGB32, 1, nil);
+       regkey("a", 'c', 1<<5);
+       regkey("b", 'x', 1<<4);
+       regkey("y", 'z', 1<<12);
+       regkey("start", '\n', 1<<13);
+       regkey("up", Kup, 0x101);
+       regkey("down", Kdown, 0x202);
+       regkey("left", Kleft, 1<<2);
+       regkey("right", Kright, 1<<3);
        cpureset();
        vdpmode();
        ymreset();
@@ -320,22 +177,7 @@ threadmain(int argc, char **argv)
 void
 flush(void)
 {
-       static vlong old, delta;
-       vlong new, diff;
-
-       sendul(flushc, 1);      /* flush screen */
-       if(audioout() < 0){
-               new = nsec();
-               diff = 0;
-               if(old != 0){
-                       diff = BILLION/60 - (new - old) - delta;
-                       if(diff >= MILLION)
-                               sleep(diff/MILLION);
-               }
-               old = nsec();
-               if(diff != 0){
-                       diff = (old - new) - (diff / MILLION) * MILLION;
-                       delta += (diff - delta) / 100;
-               }
-       }
+       flushmouse(1);
+       flushscreen();
+       flushaudio(audioout);
 }
index f3b6ede8f839040317cbeb0150a6ab4f1aa713e1..083abaa29b042af991bae6367734d978c6391ffc 100644 (file)
@@ -1,6 +1,7 @@
 #include <u.h>
 #include <libc.h>
 #include <thread.h>
+#include <emu.h>
 #include "dat.h"
 #include "fns.h"
 
@@ -31,7 +32,7 @@ regread(u16int a)
        switch(a | 1){
        case 0x0001: return 0xa0;
        case 0x0003:
-               v = keys;
+               v = ~(keys & 0xffff);
                if((ctl[0] & 0x40) == 0)
                        v >>= 8;
                return ctl[0] & 0xc0 | v & 0x3f;
index e87306559d08eb1d62098f17d13ef15a27b9944e..51d5f20a17c790012b6ecebf9d1cc1056ba16963 100644 (file)
@@ -1,10 +1,10 @@
 #include <u.h>
 #include <libc.h>
 #include <thread.h>
+#include <emu.h>
 #include "dat.h"
 #include "fns.h"
 
-u8int pic[320*224*4*4];
 u16int vdpstat = 0x3400;
 int vdpx, vdpy, vdpyy, frame, intla;
 u16int hctr;
@@ -29,32 +29,31 @@ vdpmode(void)
 static void
 pixeldraw(int x, int y, int v)
 {
-       u8int *p;
-       u32int *q;
-       union { u32int w; u8int b[4]; } u;
+       u32int *p;
+       union { u32int l; u8int b[4]; } u;
 
-       if(scale == 1){
-               p = pic + (x + y * 320) * 4;
-               p[0] = v >> 16;
-               p[1] = v >> 8;
-               p[2] = v;
-               return;
-       }
+       p = (u32int *)pic + (x + y * 320) * scale;
        u.b[0] = v >> 16;
        u.b[1] = v >> 8;
        u.b[2] = v;
        u.b[3] = 0;
-       if(scale == 2){
-               if(intla)
-                       y = y << 1 | frame;
-               q = (u32int*)pic + (x + y * 320) * 2;
-               q[0] = u.w;
-               q[1] = u.w;
-       }else{
-               q = (u32int*)pic + (x + y * 320) * 3;
-               q[0] = u.w;
-               q[1] = u.w;
-               q[2] = u.w;
+       switch(scale){
+       case 16: *p++ = u.l;
+       case 15: *p++ = u.l;
+       case 14: *p++ = u.l;
+       case 13: *p++ = u.l;
+       case 12: *p++ = u.l;
+       case 11: *p++ = u.l;
+       case 10: *p++ = u.l;
+       case 9: *p++ = u.l;
+       case 8: *p++ = u.l;
+       case 7: *p++ = u.l;
+       case 6: *p++ = u.l;
+       case 5: *p++ = u.l;
+       case 4: *p++ = u.l;
+       case 3: *p++ = u.l;
+       case 2: *p++ = u.l;     /* intla ignored */
+       default: *p = u.l;
        }
 }
 
index 2bd83af0a20c4b0ab13857d118f80b5077a00786..ca39884337e0ae4e08dfce169534ef6cd852c672 100644 (file)
@@ -1,11 +1,10 @@
 #include <u.h>
 #include <libc.h>
 #include <thread.h>
+#include <emu.h>
 #include "dat.h"
 #include "fns.h"
 
-extern int debug;
-
 u8int ym[512];
 enum {
        MODE = 0x27,
@@ -436,7 +435,7 @@ audioout(void)
                return -1;
        if(sbufp == sbuf)
                return 0;
-       rc = write(fd, sbuf, (sbufp - sbuf) * 2);
+       rc = warp10 ? (sbufp - sbuf) * 2 : write(fd, sbuf, (sbufp - sbuf) * 2);
        if(rc > 0)
                sbufp -= (rc+1)/2;
        if(sbufp < sbuf)
index cd0a642b243662a85fa77fd48b123e694a8fbf50..52e8e36b534ee768b4d31518d06fc48986b01b7f 100644 (file)
@@ -2,6 +2,7 @@
 #include <libc.h>
 #include <thread.h>
 #include <draw.h>
+#include <emu.h>
 #include "dat.h"
 #include "fns.h"
 
@@ -279,7 +280,7 @@ audioout(void)
                return -1;
        if(sbufp == sbuf)
                return 0;
-       rc = write(fd, sbuf, (sbufp - sbuf) * 2);
+       rc = warp10 ? (sbufp - sbuf) * 2 : write(fd, sbuf, (sbufp - sbuf) * 2);
        if(rc > 0)
                sbufp -= (rc+1)/2;
        if(sbufp < sbuf)
index 8da07fa8497036c6afadf22d2e8cb51f8f002f33..4162f09042dba581bf4c7d56eeff34daf1612d20 100644 (file)
@@ -6,14 +6,14 @@ extern u16int pput, ppuv;
 extern u8int ppusx, vrambuf;
 extern int mirr, ppux, ppuy, odd, vramlatch, keylatch, keylatch2;
 
-extern int map, scale, mmc3hack, oflag;
+extern int map, mmc3hack, oflag;
 extern uchar *prg, *chr;
 extern int nprg, nchr, map, chrram;
 
 extern u8int apuseq, apuctr[13];
 extern u16int dmcaddr, dmccnt;
 
-extern int keys, keys2, clock, ppuclock, apuclock, dmcclock, dmcfreq, saveclock, paused;
+extern int clock, ppuclock, apuclock, dmcclock, dmcfreq, saveclock;
 
 extern void (*mapper[])(int, u8int);
 
@@ -78,8 +78,6 @@ enum {
 
 enum {
        FREQ = 21477272,
-       MILLION = 1000000,
-       BILLION = 1000000000,
        APUDIV = 89490,
        RATE = 44100,
        SAMPDIV = FREQ / RATE,
index 575cf0c0e78de723e38b2dff9eb343a7486ba3af..52e3162ba3ce657cb9d3f613ea9390cc21070e17 100644 (file)
@@ -2,6 +2,7 @@
 #include <libc.h>
 #include <thread.h>
 #include <draw.h>
+#include <emu.h>
 #include "dat.h"
 #include "fns.h"
 
index aa9c4fa2ae4c15887cbcf593cb421ae5cf413c7e..2b4988aec974bcacb7a5eb6e5b3899cb00458a19 100644 (file)
@@ -2,22 +2,17 @@
 #include <libc.h>
 #include <draw.h>
 #include <thread.h>
-#include <mouse.h>
 #include <keyboard.h>
+#include <emu.h>
 #include "dat.h"
 #include "fns.h"
 
 extern uchar ppuram[16384];
 int nprg, nchr, map, chrram;
 uchar *prg, *chr;
-int scale;
-Rectangle picr;
-Image *tmp, *bg;
 int clock, ppuclock, apuclock, dmcclock, dmcfreq, sampclock, msgclock, saveclock;
-Mousectl *mc;
-int keys, keys2, paused, savereq, loadreq, oflag, savefd = -1;
+int oflag, savefd = -1;
 int mirr;
-QLock pauselock;
 
 void
 message(char *fmt, ...)
@@ -122,139 +117,18 @@ loadrom(char *file, int sflag)
        mapper[map](INIT, 0);
 }
 
-extern int trace;
-
-void
-joyproc(void *)
-{
-       char *s, *down[9];
-       static char buf[64];
-       int n, k, j;
-
-       j = 1;
-       for(;;){
-               n = read(0, buf, sizeof(buf) - 1);
-               if(n <= 0)
-                       sysfatal("read: %r");
-               buf[n] = 0;
-               n = getfields(buf, down, nelem(down), 1, " ");
-               k = 0;
-               for(n--; n >= 0; n--){
-                       s = down[n];
-                       if(strcmp(s, "joy1") == 0)
-                               j = 1;
-                       else if(strcmp(s, "joy2") == 0)
-                               j = 2;
-                       else if(strcmp(s, "a") == 0)
-                               k |= 1<<0;
-                       else if(strcmp(s, "b") == 0)
-                               k |= 1<<1;
-                       else if(strcmp(s, "control") == 0)
-                               k |= 1<<2;
-                       else if(strcmp(s, "start") == 0)
-                               k |= 1<<3;
-                       else if(strcmp(s, "up") == 0)
-                               k |= 1<<4;
-                       else if(strcmp(s, "down") == 0)
-                               k |= 1<<5;
-                       else if(strcmp(s, "left") == 0)
-                               k |= 1<<6;
-                       else if(strcmp(s, "right") == 0)
-                               k |= 1<<7;
-               }
-               if(j == 2)
-                       keys2 = k;
-               else
-                       keys = k;
-       }
-}
-
-void
-keyproc(void *)
-{
-       int fd, n, k;
-       static char buf[256];
-       char *s;
-       Rune r;
-
-       fd = open("/dev/kbd", OREAD);
-       if(fd < 0)
-               sysfatal("open: %r");
-       for(;;){
-               if(buf[0] != 0){
-                       n = strlen(buf)+1;
-                       memmove(buf, buf+n, sizeof(buf)-n);
-               }
-               if(buf[0] == 0){
-                       n = read(fd, buf, sizeof(buf)-1);
-                       if(n <= 0)
-                               sysfatal("read /dev/kbd: %r");
-                       buf[n-1] = 0;
-                       buf[n] = 0;
-               }
-               if(buf[0] == 'c'){
-                       if(utfrune(buf, Kdel)){
-                               close(fd);
-                               threadexitsall(nil);
-                       }
-                       if(utfrune(buf, KF|5))
-                               savereq = 1;
-                       if(utfrune(buf, KF|6))
-                               loadreq = 1;
-                       if(utfrune(buf, 't'))
-                               trace ^= 1;
-               }
-               if(buf[0] != 'k' && buf[0] != 'K')
-                       continue;
-               s = buf + 1;
-               k = 0;
-               while(*s != 0){
-                       s += chartorune(&r, s);
-                       switch(r){
-                       case Kdel: close(fd); threadexitsall(nil);
-                       case 'x': k |= 1<<0; break;
-                       case 'z': k |= 1<<1; break;
-                       case Kshift: k |= 1<<2; break;
-                       case 10: k |= 1<<3; break;
-                       case Kup: k |= 1<<4; break;
-                       case Kdown: k |= 1<<5; break;
-                       case Kleft: k |= 1<<6; break;
-                       case Kright: k |= 1<<7; break;
-                       case Kesc:
-                               if(paused)
-                                       qunlock(&pauselock);
-                               else
-                                       qlock(&pauselock);
-                               paused = !paused;
-                               break;
-                       }
-               }
-               keys = k;
-       }
-}
-
 void
 threadmain(int argc, char **argv)
 {
-       int t, h, sflag;
-       Point p;
+       int t, sflag;
 
-       scale = 1;
-       h = 240;
        sflag = 0;
        ARGBEGIN {
        case 'a':
                initaudio();
                break;
-       case '2':
-               scale = 2;
-               break;
-       case '3':
-               scale = 3;
-               break;
        case 'o':
                oflag = 1;
-               h -= 16;
                break;
        case 's':
                sflag = 1;
@@ -269,20 +143,16 @@ threadmain(int argc, char **argv)
                threadexitsall("usage");
        }
        loadrom(argv[0], sflag);
-       if(initdraw(nil, nil, nil) < 0)
-               sysfatal("initdraw: %r");
-       mc = initmouse(nil, screen);
-       if(mc == nil)
-               sysfatal("initmouse: %r");
-       proccreate(joyproc, nil, 8192);
-       proccreate(keyproc, nil, 8192);
-       originwindow(screen, Pt(0, 0), screen->r.min);
-       p = divpt(addpt(screen->r.min, screen->r.max), 2);
-       picr = (Rectangle){subpt(p, Pt(scale * 128, scale * h/2)), addpt(p, Pt(scale * 128, scale * h/2))};
-       tmp = allocimage(display, Rect(0, 0, scale * 256, scale * h), XRGB32, 0, 0);
-       bg = allocimage(display, Rect(0, 0, 1, 1), screen->chan, 1, 0xCCCCCCFF);
-       draw(screen, screen->r, bg, nil, ZP);
-       
+       initemu(256, 240 - oflag * 16, 4, XRGB32, 1, nil);
+       regkey("b", 'z', 1<<1);
+       regkey("a", 'x', 1<<0);
+       regkey("control", Kshift, 1<<2);
+       regkey("start", '\n', 1<<3);
+       regkey("up", Kup, 1<<4);
+       regkey("down", Kdown, 1<<5);
+       regkey("left", Kleft, 1<<6);
+       regkey("right", Kright, 1<<7);
+
        pc = memread(0xFFFC) | memread(0xFFFD) << 8;
        rP = FLAGI;
        dmcfreq = 12 * 428;
@@ -324,7 +194,8 @@ threadmain(int argc, char **argv)
                if(msgclock > 0){
                        msgclock -= t;
                        if(msgclock <= 0){
-                               draw(screen, screen->r, bg, nil, ZP);
+                               extern Image *bg;
+                               draw(screen, screen->r, bg, nil, ZP);   
                                msgclock = 0;
                        }
                }
index 5c1756a19374375e7e2d8bdad0083870a6061402..498c20082fa7dcc1eedb2d134fd769aae30bc43f 100644 (file)
@@ -3,18 +3,17 @@
 #include <thread.h>
 #include <draw.h>
 #include <mouse.h>
+#include <emu.h>
 #include "dat.h"
 #include "fns.h"
 
 int ppuy, ppux, odd;
-uchar pic[256*240*4*9];
 
 static void
 pixel(int x, int y, int val, int back)
 {
-       int Y;
        union { u8int c[4]; u32int l; } u;
-       u32int *p, l;
+       u32int *p;
        static u8int palred[64] = {
                0x7C, 0x00, 0x00, 0x44, 0x94, 0xA8, 0xA8, 0x88, 
                0x50, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
@@ -50,32 +49,31 @@ pixel(int x, int y, int val, int back)
        u.c[1] = palgreen[val];
        u.c[2] = palred[val];
        u.c[3] = back ? 0 : 0xFF;
-       l = u.l;
-       if(scale == 3){
-               p = ((u32int*)pic) + y * 3 * 3 * 256 + 3 * x;
-               for(Y = 0; Y < 3; Y++){
-                       *p++ = l;
-                       *p++ = l;
-                       *p = l;
-                       p += 3 * 256 - 2;
-               }
-       }else if(scale == 2){
-               p = ((u32int*)pic) + y * 2 * 2 * 256 + 2 * x;
-               *p++ = l;
-               *p = l;
-               p += 2 * 256 - 1;
-               *p++ = l;
-               *p = l;
-       }else{
-               p = ((u32int*)pic) + y * 256 + x;
-               *p = l;
+       p = (u32int *)pic + y * 256 * scale + x * scale;
+       switch(scale){
+       case 16: *p++ = u.l;
+       case 15: *p++ = u.l;
+       case 14: *p++ = u.l;
+       case 13: *p++ = u.l;
+       case 12: *p++ = u.l;
+       case 11: *p++ = u.l;
+       case 10: *p++ = u.l;
+       case 9: *p++ = u.l;
+       case 8: *p++ = u.l;
+       case 7: *p++ = u.l;
+       case 6: *p++ = u.l;
+       case 5: *p++ = u.l;
+       case 4: *p++ = u.l;
+       case 3: *p++ = u.l;
+       case 2: *p++ = u.l;
+       default: *p = u.l;
        }
 }
 
 static int
 iscolor(int x, int y)
 {
-       return pic[y * scale * scale * 256 * 4 + x * scale * 4 + 3] != 0;
+       return pic[(scale * 4) * (y * 256 + x) + 3] != 0;
 }
 
 static int
@@ -252,52 +250,9 @@ drawsprites(int show)
 static void
 flush(void)
 {
-       extern Rectangle picr;
-       extern Image *tmp, *bg;
-       extern Mousectl *mc;
-       static vlong old, delta;
-       vlong new, diff;
-       Mouse m;
-       Point p;
-       int h;
-
-       h = 240;
-       if(oflag)
-               h -= 16;
-       while(nbrecv(mc->c, &m) > 0)
-               ;
-       if(nbrecvul(mc->resizec) > 0){
-               if(getwindow(display, Refnone) < 0)
-                       sysfatal("resize failed: %r");
-               p = divpt(addpt(screen->r.min, screen->r.max), 2);
-               picr = (Rectangle){subpt(p, Pt(scale * 128, scale * h/2)), addpt(p, Pt(scale * 128, scale * h/2))};
-               if(bg->chan != screen->chan){
-                       freeimage(bg);
-                       bg = allocimage(display, Rect(0, 0, 1, 1), screen->chan, 1, 0xCCCCCCFF);
-               }
-               draw(screen, screen->r, bg, nil, ZP);
-       }
-       if(screen->chan != tmp->chan || !rectinrect(picr, screen->r)){
-               loadimage(tmp, tmp->r, pic + oflag*8*256*4*scale*scale, 256*h*4*scale*scale);
-               draw(screen, picr, tmp, nil, ZP);
-       }else
-               loadimage(screen, picr, pic + oflag*8*256*4*scale*scale, 256*h*4*scale*scale);
-       flushimage(display, 1);
-       memset(pic, sizeof pic, 0);
-       if(audioout() < 0){
-               new = nsec();
-               diff = 0;
-               if(old != 0){
-                       diff = BILLION/60 - (new - old) - delta;
-                       if(diff >= MILLION)
-                               sleep(diff/MILLION);
-               }
-               old = nsec();
-               if(diff != 0){
-                       diff = (old - new) - (diff / MILLION) * MILLION;
-                       delta += (diff - delta) / 100;
-               }
-       }
+       flushmouse(1);
+       flushscreen();
+       flushaudio(audioout);
 }
 
 void
index 602d4ca8f03ec15e96a872c9389f55e22dba65c8..dbec220a456bde0b2a4de577f8d62b6acc8eba46 100644 (file)
@@ -1,6 +1,7 @@
 #include <u.h>
 #include <libc.h>
 #include <thread.h>
+#include <emu.h>
 #include "dat.h"
 #include "fns.h"
 
@@ -640,8 +641,6 @@ cpureset(void)
        rP = 0x35;
 }
 
-int trace;
-
 int
 cpustep(void)
 {
index 86a14a5a40d5809043dddab75e7ad843dedc733d..971ea724c15ccbe872046dcd32abf384fc962508 100644 (file)
@@ -1,14 +1,10 @@
-typedef signed char s8int;
-typedef signed short s16int;
-
 extern u8int rP, dma, nmi, irq, emu, wai;
 extern u16int rA, rX, rY, rS, rD, pc;
 extern u32int rPB, rDB, curpc, hdma;
-extern int trace;
 
 extern uchar *prg, *sram;
 extern int nprg, nsram, hirom;
-extern u32int keys, keylatch, lastkeys;
+extern u32int keylatch, lastkeys;
 extern u8int reg[32768], mem[131072], spcmem[65536], vram[65536], oam[544];
 extern u16int cgram[256], vramlatch;
 extern u8int mdr, mdr1, mdr2;
@@ -25,7 +21,7 @@ extern u8int dspstate;
 extern u16int dspcounter, noise;
 
 extern int ppuclock, spcclock, dspclock, stimerclock, cpupause;
-extern int battery, saveclock, scale, mouse;
+extern int battery, saveclock, mouse;
 
 enum {
        FLAGC = 1<<0,
index b4ad1e7f135de8578be9f63268e325818e22e82c..991c45316272c4a08320d383e174c567b3f481ac 100644 (file)
@@ -1,6 +1,7 @@
 #include <u.h>
 #include <libc.h>
 #include <thread.h>
+#include <emu.h>
 #include "dat.h"
 #include "fns.h"
 
@@ -77,7 +78,7 @@ audioout(void)
                return -1;
        if(sbufp == sbuf)
                return 0;
-       rc = write(fd, sbuf, (sbufp - sbuf) * 2);
+       rc = warp10 ? (sbufp - sbuf) * 2 : write(fd, sbuf, (sbufp - sbuf) * 2);
        if(rc > 0)
                sbufp -= (rc+1)/2;
        if(sbufp < sbuf)
index 6fea74bfd8b2563992f0371b763c895aceb8858f..885713a85274a4a9429fa571c9c6075e7aa87184 100644 (file)
@@ -1,6 +1,7 @@
 #include <u.h>
 #include <libc.h>
 #include <thread.h>
+#include <emu.h>
 #include "dat.h"
 #include "fns.h"
 
index 0ae2ccfb9b7f2c54e279b8d04fa86fbcc8fff89c..5819e032c10b30de478675dc4ed3bdb6bd6c3563 100644 (file)
@@ -1,6 +1,7 @@
 #include <u.h>
 #include <libc.h>
 #include <thread.h>
+#include <emu.h>
 #include "dat.h"
 #include "fns.h"
 
@@ -8,7 +9,6 @@ int ppux, ppuy, rx;
 static u8int mode, bright, pixelpri[2], hires;
 static u32int pixelcol[2];
 u16int vtime = 0x1ff, htime = 0x1ff, subcolor;
-uchar pic[256*239*2*3];
 u16int hofs[5], vofs[5];
 s16int m7[6];
 
@@ -40,30 +40,31 @@ darken(u16int v)
 static void
 pixeldraw(int x, int y, u16int v, int s)
 {
-       uchar *p;
-       u16int *q;
+       u16int *p;
        union { u16int w; u8int b[2]; } u;
 
        if(bright != 0xf && s >= 0)
                v = darken(v);
-       if(scale == 1){
-               p = pic + (x + y * 256) * 2;
-               p[0] = v;
-               p[1] = v >> 8;
-               return;
-       }
+       p = (u16int *)pic + (x + y * 256) * scale;
        u.b[0] = v;
        u.b[1] = v >> 8;
-       if(scale == 2){
-               q = (u16int*)pic + (x + y * 256) * 2;
-               if(s < 1)
-                       q[0] = u.w;
-               q[1] = u.w;
-       }else{
-               q = (u16int*)pic + (x + y * 256) * 3;
-               q[0] = u.w;
-               q[1] = u.w;
-               q[2] = u.w;
+       switch(scale){
+       case 16: *p++ = u.w;
+       case 15: *p++ = u.w;
+       case 14: *p++ = u.w;
+       case 13: *p++ = u.w;
+       case 12: *p++ = u.w;
+       case 11: *p++ = u.w;
+       case 10: *p++ = u.w;
+       case 9: *p++ = u.w;
+       case 8: *p++ = u.w;
+       case 7: *p++ = u.w;
+       case 6: *p++ = u.w;
+       case 5: *p++ = u.w;
+       case 4: *p++ = u.w;
+       case 3: *p++ = u.w;
+       case 2: if(s < 1) *p++ = u.w;
+       default: *p = u.w;
        }
 }
 
index 863247fef1c114f383b5a89f23a4a516c55e82c4..3e43b631d760ff00fb9d1597702b92be594baf6a 100644 (file)
@@ -4,21 +4,16 @@
 #include <draw.h>
 #include <keyboard.h>
 #include <mouse.h>
-#include <ctype.h>
+#include <emu.h>
 #include "dat.h"
 #include "fns.h"
 
 uchar *prg, *sram;
 int nprg, nsram, hirom, battery;
 
-int ppuclock, spcclock, dspclock, stimerclock, saveclock, msgclock, paused, perfclock, cpupause;
-Mousectl *mc;
-Channel *flushc, *msgc;
-QLock pauselock;
-u32int keys;
-int savefd, scale, profile, mouse, loadreq, savereq;
-Rectangle picr;
-Image *tmp, *bg;
+int ppuclock, spcclock, dspclock, stimerclock, saveclock, msgclock, cpupause;
+Channel *msgc;
+int savefd, mouse;
 
 void
 flushram(void)
@@ -113,188 +108,14 @@ loadbat(char *file)
        }
 }
 
-void
-keyproc(void *)
-{
-       int fd, n, k;
-       static char buf[256];
-       char *s;
-       Rune r;
-
-       fd = open("/dev/kbd", OREAD);
-       if(fd < 0)
-               sysfatal("open: %r");
-       for(;;){
-               if(buf[0] != 0){
-                       n = strlen(buf)+1;
-                       memmove(buf, buf+n, sizeof(buf)-n);
-               }
-               if(buf[0] == 0){
-                       n = read(fd, buf, sizeof(buf)-1);
-                       if(n <= 0)
-                               sysfatal("read /dev/kbd: %r");
-                       buf[n-1] = 0;
-                       buf[n] = 0;
-               }
-               if(buf[0] == 'c'){
-                       if(utfrune(buf, KF|5))
-                               savereq = 1;
-                       if(utfrune(buf, KF|6))
-                               loadreq = 1;
-                       if(utfrune(buf, Kdel)){
-                               close(fd);
-                               threadexitsall(nil);
-                       }
-                       if(utfrune(buf, 't'))
-                               trace = !trace;
-               }
-               if(buf[0] != 'k' && buf[0] != 'K')
-                       continue;
-               s = buf + 1;
-               k = 0xffff;
-               while(*s != 0){
-                       s += chartorune(&r, s);
-                       switch(r){
-                       case Kdel: close(fd); threadexitsall(nil);
-                       case 'z': k |= 1<<31; break;
-                       case 'x': k |= 1<<23; break;
-                       case 'a': k |= 1<<30; break;
-                       case 's': k |= 1<<22; break;
-                       case 'q': k |= 1<<21; break;
-                       case 'w': k |= 1<<20; break;
-                       case Kshift: k |= 1<<29; break;
-                       case 10: k |= 1<<28; break;
-                       case Kup: k |= 1<<27; break;
-                       case Kdown: k |= 1<<26; break;
-                       case Kleft: k |= 1<<25; break;
-                       case Kright: k |= 1<<24; break;
-                       case Kesc:
-                               if(paused)
-                                       qunlock(&pauselock);
-                               else
-                                       qlock(&pauselock);
-                               paused = !paused;
-                               break;
-                       }
-               }
-               if(!mouse)
-                       keys = k;
-       }
-}
-
-void
-screeninit(void)
-{
-       Point p;
-
-       p = divpt(addpt(screen->r.min, screen->r.max), 2);
-       picr = (Rectangle){subpt(p, Pt(scale * 128, scale * 112)), addpt(p, Pt(scale * 128, scale * 127))};
-       if(tmp != nil) freeimage(tmp);
-       tmp = allocimage(display, Rect(0, 0, scale * 256, scale > 1 ? 1 : scale * 239), RGB15, scale > 1, 0);
-       if(bg != nil) freeimage(bg);
-       bg = allocimage(display, Rect(0, 0, 1, 1), screen->chan, 1, 0xCCCCCCFF);
-       draw(screen, screen->r, bg, nil, ZP);   
-}
-
-void
-screenproc(void *)
-{
-       extern uchar pic[256*239*2*3];
-       char *s;
-       Mouse m;
-       Point p;
-
-       enum { AMOUSE, ARESIZE, AFLUSH, AMSG, AEND };
-       Alt a[AEND+1] = {
-               { mc->c,        &m,     CHANRCV },
-               { mc->resizec,  nil,    CHANRCV },
-               { flushc,       nil,    CHANRCV },
-               { msgc,         &s,     CHANRCV },
-               { nil,          nil,    CHANEND }
-       };
-
-       for(;;){
-               switch(alt(a)){
-               case AMOUSE:
-                       if(mouse && ptinrect(m.xy, picr)){
-                               p = subpt(m.xy, picr.min);
-                               p.x /= scale;
-                               p.y /= scale;
-                               keys = keys & 0xff3f0000 | p.x | p.y << 8;
-                               if((m.buttons & 1) != 0)
-                                       keys |= 1<<22;
-                               if((m.buttons & 4) != 0)
-                                       keys |= 1<<23;
-                               if((m.buttons & 2) != 0)
-                                       lastkeys = keys;
-                       }
-                       break;
-               case ARESIZE:
-                       if(getwindow(display, Refnone) < 0)
-                               sysfatal("resize failed: %r");
-                       screeninit();
-                       /* wet floor */
-               case AFLUSH:
-                       if(scale == 1){
-                               loadimage(tmp, tmp->r, pic, 256*239*2);
-                               draw(screen, picr, tmp, nil, ZP);
-                       } else {
-                               Rectangle r;
-                               uchar *s;
-                               int w;
-
-                               s = pic;
-                               r = picr;
-                               w = 256*2*scale;
-                               while(r.min.y < picr.max.y){
-                                       loadimage(tmp, tmp->r, s, w);
-                                       s += w;
-                                       r.max.y = r.min.y+scale;
-                                       draw(screen, r, tmp, nil, ZP);
-                                       r.min.y = r.max.y;
-                               }
-                       }
-                       flushimage(display, 1);
-                       break;
-               case AMSG:
-                       draw(screen, rectaddpt(Rect(10, 10, 200, 30), screen->r.min), bg, nil, ZP);
-                       if(s != nil){
-                               string(screen, addpt(screen->r.min, Pt(10, 10)), display->black, ZP, 
-                                       display->defaultfont, s);
-                               free(s);
-                       }
-                       break;
-               }
-       }
-}
-
-void
-timing(void)
-{
-       static vlong old;
-       vlong new;
-       
-       new = nsec();
-       if(new != old)
-               message("%6.2f%%", 1e11 / (new - old));
-       old = nsec();
-}
-
 void
 threadmain(int argc, char **argv)
 {
        int t;
        extern u16int pc;
 
-       scale = 1;
        hirom = -1;
        ARGBEGIN {
-       case '2':
-               scale = 2;
-               break;
-       case '3':
-               scale = 3;
-               break;
        case 'a':
                audioinit();
                break;
@@ -308,9 +129,6 @@ threadmain(int argc, char **argv)
        case 'h':
                hirom++;
                break;
-       case 'T':
-               profile++;
-               break;
        default:
                goto usage;
        } ARGEND;
@@ -321,16 +139,20 @@ usage:
                threadexitsall("usage");
        }
        loadrom(argv[0]);
-       if(initdraw(nil, nil, argv0) < 0)
-               sysfatal("initdraw: %r");
-       flushc = chancreate(sizeof(ulong), 1);
-       msgc = chancreate(sizeof(char*), 0);
-       mc = initmouse(nil, screen);
-       if(mc == nil)
-               sysfatal("initmouse: %r");
-       screeninit();
-       proccreate(keyproc, 0, 8192);
-       proccreate(screenproc, 0, 8192);
+       initemu(256, 239, 2, RGB15, !mouse, nil);
+       regkey("b", 'z', 1<<31);
+       regkey("a", 'x', 1<<23);
+       regkey("y", 'a', 1<<30);
+       regkey("x", 's', 1<<22);
+       regkey("l1", 'q', 1<<21);
+       regkey("r1", 'w', 1<<20);
+       regkey("control", Kshift, 1<<29);
+       regkey("start", '\n', 1<<28);
+       regkey("up", Kup, 1<<27);
+       regkey("down", Kdown, 1<<26);
+       regkey("left", Kleft, 1<<25);
+       regkey("right", Kright, 1<<24);
+       msgc = chancreate(sizeof(char*), 1);
        loadbat(argv[0]);
        cpureset();
        memreset();
@@ -358,7 +180,6 @@ usage:
                stimerclock += t;
                ppuclock += t;
                dspclock += t;
-               perfclock -= t;
 
                while(ppuclock >= 4){
                        ppustep();
@@ -386,18 +207,43 @@ usage:
                                msgclock = 0;
                        }
                }
-               if(profile && perfclock <= 0){
-                       perfclock = FREQ;
-                       timing();
-               }
        }
 }
 
 void
 flush(void)
 {
-       sendul(flushc, 1);      /* flush screen */
-       audioout();
+       char *s;
+       Mouse m;
+       Point p;
+
+       extern Rectangle picr;
+       extern Mousectl *mc;
+       flushmouse(!mouse);
+       while(nbrecv(mc->c, &m) > 0){
+               if(ptinrect(m.xy, picr)){
+                       p = subpt(m.xy, picr.min);
+                       p.x /= scale;
+                       p.y /= scale;
+                       keys = keys & 0xff3f0000 | p.x | p.y << 8;
+                       if((m.buttons & 1) != 0)
+                               keys |= 1<<22;
+                       if((m.buttons & 4) != 0)
+                               keys |= 1<<23;
+                       if((m.buttons & 2) != 0)
+                               lastkeys = keys;
+               }
+       }
+       flushscreen();
+       while(nbrecv(msgc, &s) > 0){
+               if(s != nil){
+                       string(screen, addpt(screen->r.min, Pt(10, 10)), display->black, ZP, 
+                               display->defaultfont, s);
+                       free(s);
+                       flushimage(display, 1);
+               }
+       }
+       flushaudio(audioout);
 }
 
 void
index 43c1b76959fdc1dbbda38069b30ddc9d5c378e15..a5fc7ab8ae8fc4afef0cd60eb05b48a6d4880495 100644 (file)
@@ -1,6 +1,7 @@
 #include <u.h>
 #include <libc.h>
 #include <thread.h>
+#include <emu.h>
 #include "dat.h"
 #include "fns.h"
 
diff --git a/sys/src/libemu/emu.c b/sys/src/libemu/emu.c
new file mode 100644 (file)
index 0000000..908727b
--- /dev/null
@@ -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();
+}
diff --git a/sys/src/libemu/mkfile b/sys/src/libemu/mkfile
new file mode 100644 (file)
index 0000000..f436124
--- /dev/null
@@ -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