From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from wopr.sciops.net ([216.126.196.60]) by ewsd; Fri May 11 16:18:26 EDT 2018 Received: (qmail 58454 invoked from network); 11 May 2018 13:18:12 -0700 X-Spam-Checker-Version: SpamAssassin 3.4.1 (2015-04-28) on wopr.sciops.net X-Spam-Level: *** X-Spam-Status: No, score=3.7 required=5.0 tests=BAYES_00,RCVD_IN_PBL, RCVD_IN_RP_RNBL,RDNS_DYNAMIC,TVD_RCVD_IP autolearn=no autolearn_force=no version=3.4.1 Received: from 89.43.136.77.rev.sfr.net (HELO u25.nope) (qwx@77.136.43.89) by wopr.sciops.net with ESMTPS (ECDHE-RSA-AES128-GCM-SHA256 encrypted); 11 May 2018 13:18:12 -0700 Message-ID: From: qwx Date: Fri, 11 May 2018 22:18:08 +0200 To: 9front@9front.org Subject: Re: [9front] proposal: move common code from md, nes, snes, gb, gba, c64 to a libemu In-Reply-To: alpine.LNX.2.00.1805111137160.15422@phi MIME-Version: 1.0 Content-Type: multipart/mixed; boundary="upas-blwtxtmwydeqcgtlxogcpbscxi" List-ID: <9front.9front.org> List-Help: X-Glyph: ➈ X-Bullshit: mobile extension CSS database framework This is a multi-part message in MIME format. --upas-blwtxtmwydeqcgtlxogcpbscxi Content-Disposition: inline Content-Type: text/plain; charset="US-ASCII" Content-Transfer-Encoding: 7bit Hello, Attached is an amended version of libemu. Changes over last: - fullspeed emulation toggled with ` instead of space - signed typedefs assumed in /$objtype/include/u.h, see previous patch sent - all used keys are now registered with regkey() on startup Thanks, qwx --upas-blwtxtmwydeqcgtlxogcpbscxi Content-Disposition: attachment; filename=mail.diff Content-Type: text/plain; charset="US-ASCII" Content-Transfer-Encoding: 7bit diff -r abfb40232967 sys/man/1/nintendo --- a/sys/man/1/nintendo Fri May 11 16:16:37 2018 +0200 +++ b/sys/man/1/nintendo Fri May 11 22:11:38 2018 +0200 @@ -4,7 +4,7 @@ .SH SYNOPSIS .B games/gb [ -.B -23acdT +.B -acdT ] [ .B -C @@ -14,7 +14,7 @@ .br .B games/gba [ -.B -23aT +.B -aT ] [ .B -b .I biosfile @@ -26,13 +26,13 @@ .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 @@ .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 @@ .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: diff -r abfb40232967 sys/man/1/sega --- a/sys/man/1/sega Fri May 11 16:16:37 2018 +0200 +++ b/sys/man/1/sega Fri May 11 22:11:38 2018 +0200 @@ -4,14 +4,14 @@ .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 @@ .PP Command line options: .TP -.B -2 -3 -Scale the screen by the given factor. -.TP .B -a Enable audio output. .SH SOURCE diff -r abfb40232967 sys/man/2/emu --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/sys/man/2/emu Fri May 11 22:11:38 2018 +0200 @@ -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 +#include +#include +.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. diff -r abfb40232967 sys/src/games/c64/c64.c --- a/sys/src/games/c64/c64.c Fri May 11 16:16:37 2018 +0200 +++ b/sys/src/games/c64/c64.c Fri May 11 22:11:38 2018 +0200 @@ -4,18 +4,15 @@ #include #include #include +#include #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 @@ { static int cur; int w; - + + extern Image *bg; if(b == 0 || a == 0){ if(cur != 0){ draw(screen, progr, bg, nil, ZP); @@ -212,21 +210,6 @@ } 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) { fprint(2, "usage: %s [ -23a ] [ rom ]\n", argv0); @@ -236,17 +219,9 @@ 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 @@ 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 @@ 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 @@ 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); } diff -r abfb40232967 sys/src/games/c64/cpu.c --- a/sys/src/games/c64/cpu.c Fri May 11 16:16:37 2018 +0200 +++ b/sys/src/games/c64/cpu.c Fri May 11 22:11:38 2018 +0200 @@ -1,5 +1,6 @@ #include #include +#include #include "dat.h" #include "fns.h" @@ -289,8 +290,6 @@ rP |= FLAGI; } -int trace; - void step(void) { diff -r abfb40232967 sys/src/games/c64/dat.h --- a/sys/src/games/c64/dat.h Fri May 11 16:16:37 2018 +0200 +++ b/sys/src/games/c64/dat.h Fri May 11 22:11:38 2018 +0200 @@ -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 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 { - BILLION = 1000*1000*1000, - MILLION = 1000*1000, HZ = 3579545, RATE = 44100, SAMPDIV = HZ / 3 / RATE, diff -r abfb40232967 sys/src/games/c64/mem.c --- a/sys/src/games/c64/mem.c Fri May 11 16:16:37 2018 +0200 +++ b/sys/src/games/c64/mem.c Fri May 11 22:11:38 2018 +0200 @@ -1,6 +1,7 @@ #include #include #include +#include #include "dat.h" #include "fns.h" diff -r abfb40232967 sys/src/games/c64/vic.c --- a/sys/src/games/c64/vic.c Fri May 11 16:16:37 2018 +0200 +++ b/sys/src/games/c64/vic.c Fri May 11 22:11:38 2018 +0200 @@ -1,6 +1,7 @@ #include #include #include +#include #include "dat.h" #include "fns.h" @@ -9,7 +10,6 @@ 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 @@ 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; } diff -r abfb40232967 sys/src/games/gb/apu.c --- a/sys/src/games/gb/apu.c Fri May 11 16:16:37 2018 +0200 +++ b/sys/src/games/gb/apu.c Fri May 11 22:11:38 2018 +0200 @@ -1,6 +1,7 @@ #include #include #include +#include #include "dat.h" #include "fns.h" @@ -475,7 +476,7 @@ 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) diff -r abfb40232967 sys/src/games/gb/cpu.c --- a/sys/src/games/gb/cpu.c Fri May 11 16:16:37 2018 +0200 +++ b/sys/src/games/gb/cpu.c Fri May 11 22:11:38 2018 +0200 @@ -1,6 +1,7 @@ #include #include #include +#include #include "dat.h" #include "fns.h" diff -r abfb40232967 sys/src/games/gb/dat.h --- a/sys/src/games/gb/dat.h Fri May 11 16:16:37 2018 +0200 +++ b/sys/src/games/gb/dat.h Fri May 11 22:11:38 2018 +0200 @@ -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 mode; extern u8int mbc, feat; -extern int keys, scale; enum { JOYP = 0x00, @@ -129,8 +124,6 @@ TIMERSIZ = 18, PICW = 160, PICH = 144, - MILLION = 1000000, - BILLION = 1000000000, FREQ = 1<<23 }; diff -r abfb40232967 sys/src/games/gb/gb.c --- a/sys/src/games/gb/gb.c Fri May 11 16:16:37 2018 +0200 +++ b/sys/src/games/gb/gb.c Fri May 11 22:11:38 2018 +0200 @@ -2,34 +2,28 @@ #include #include #include -#include #include +#include #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 @@ -204,174 +198,14 @@ } 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 @@ 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 @@ 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(); diff -r abfb40232967 sys/src/games/gb/mem.c --- a/sys/src/games/gb/mem.c Fri May 11 16:16:37 2018 +0200 +++ b/sys/src/games/gb/mem.c Fri May 11 22:11:38 2018 +0200 @@ -1,6 +1,7 @@ #include #include #include +#include #include "dat.h" #include "fns.h" diff -r abfb40232967 sys/src/games/gb/ppu.c --- a/sys/src/games/gb/ppu.c Fri May 11 16:16:37 2018 +0200 +++ b/sys/src/games/gb/ppu.c Fri May 11 22:11:38 2018 +0200 @@ -1,11 +1,11 @@ #include #include #include +#include #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 @@ } 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 @@ 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 @@ 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; + } } } diff -r abfb40232967 sys/src/games/gba/apu.c --- a/sys/src/games/gba/apu.c Fri May 11 16:16:37 2018 +0200 +++ b/sys/src/games/gba/apu.c Fri May 11 22:11:38 2018 +0200 @@ -1,6 +1,7 @@ #include #include #include +#include #include "dat.h" #include "fns.h" @@ -350,7 +351,7 @@ 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 @@ 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) diff -r abfb40232967 sys/src/games/gba/cpu.c --- a/sys/src/games/gba/cpu.c Fri May 11 16:16:37 2018 +0200 +++ b/sys/src/games/gba/cpu.c Fri May 11 22:11:38 2018 +0200 @@ -1,6 +1,7 @@ #include #include #include +#include #include "dat.h" #include "fns.h" @@ -34,7 +35,7 @@ int irq; u32int instr0, instr1, pipel = -1; -int cyc, trace; +int cyc; Var cpuvars[] = { ARR(r), VAR(cpsr), VAR(spsr), ARR(saver), VAR(irq), diff -r abfb40232967 sys/src/games/gba/dat.h --- a/sys/src/games/gba/dat.h Fri May 11 16:16:37 2018 +0200 +++ b/sys/src/games/gba/dat.h Fri May 11 22:11:38 2018 +0200 @@ -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 hblank, ppuy; extern int clock; -extern int scale; typedef struct Event Event; struct Event { @@ -141,8 +135,6 @@ KB = 1024, BACKTYPELEN = 64, HZ = 16777216, - MILLION = 1000000, - BILLION = 1000000000, }; typedef struct Var Var; diff -r abfb40232967 sys/src/games/gba/gba.c --- a/sys/src/games/gba/gba.c Fri May 11 16:16:37 2018 +0200 +++ b/sys/src/games/gba/gba.c Fri May 11 22:11:38 2018 +0200 @@ -2,36 +2,19 @@ #include #include #include -#include #include +#include #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) { @@ -212,172 +195,14 @@ } 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 @@ 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 @@ 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 @@ case 'b': biosfile = strdup(EARGF(usage())); break; - case 'T': - profile++; - break; default: usage(); } ARGEND; @@ -436,16 +251,17 @@ 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(); diff -r abfb40232967 sys/src/games/gba/mem.c --- a/sys/src/games/gba/mem.c Fri May 11 16:16:37 2018 +0200 +++ b/sys/src/games/gba/mem.c Fri May 11 22:11:38 2018 +0200 @@ -1,6 +1,7 @@ #include #include #include +#include #include "dat.h" #include "fns.h" diff -r abfb40232967 sys/src/games/gba/ppu.c --- a/sys/src/games/gba/ppu.c Fri May 11 16:16:37 2018 +0200 +++ b/sys/src/games/gba/ppu.c Fri May 11 22:11:38 2018 +0200 @@ -1,6 +1,7 @@ #include #include #include +#include #include "dat.h" #include "fns.h" @@ -11,7 +12,6 @@ u32int pixcol[480]; u8int pixpri[480]; u8int pixwin[240]; -uchar pic[240*160*3*2]; int objalpha; typedef struct bg bg; @@ -643,40 +643,6 @@ } 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) { int i; @@ -725,6 +691,43 @@ } 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 *) { extern Event evhblank; @@ -755,7 +758,7 @@ }else{ syncppu(240); if(ppuy < 160) - linecopy(); + linecopy(pixcol, ppuy); addevent(&evhblank, 68*4); hblank = 1; if((stat & IRQHBLEN) != 0) diff -r abfb40232967 sys/src/games/md/cpu.c --- a/sys/src/games/md/cpu.c Fri May 11 16:16:37 2018 +0200 +++ b/sys/src/games/md/cpu.c Fri May 11 22:11:38 2018 +0200 @@ -1,6 +1,7 @@ #include #include #include +#include #include "dat.h" #include "fns.h" @@ -19,7 +20,7 @@ u32int irqla[8]; u16int rS; static u32int op; -int trace, tim; +int tim; #define ra (r+8) static void diff -r abfb40232967 sys/src/games/md/dat.h --- a/sys/src/games/md/dat.h Fri May 11 16:16:37 2018 +0200 +++ b/sys/src/games/md/dat.h Fri May 11 22:11:38 2018 +0200 @@ -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 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 @@ RATE = 44100, SAMPDIV = FREQ / RATE, SAVEFREQ = FREQ / 4, - MILLION = 1000 * 1000, - BILLION = 1000 * 1000 * 1000, }; enum { diff -r abfb40232967 sys/src/games/md/md.c --- a/sys/src/games/md/md.c Fri May 11 16:16:37 2018 +0200 +++ b/sys/src/games/md/md.c Fri May 11 22:11:38 2018 +0200 @@ -3,29 +3,18 @@ #include #include #include -#include +#include #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) { @@ -114,146 +103,14 @@ } 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 @@ 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 @@ 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); } diff -r abfb40232967 sys/src/games/md/mem.c --- a/sys/src/games/md/mem.c Fri May 11 16:16:37 2018 +0200 +++ b/sys/src/games/md/mem.c Fri May 11 22:11:38 2018 +0200 @@ -1,6 +1,7 @@ #include #include #include +#include #include "dat.h" #include "fns.h" @@ -31,7 +32,7 @@ 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; diff -r abfb40232967 sys/src/games/md/vdp.c --- a/sys/src/games/md/vdp.c Fri May 11 16:16:37 2018 +0200 +++ b/sys/src/games/md/vdp.c Fri May 11 22:11:38 2018 +0200 @@ -1,10 +1,10 @@ #include #include #include +#include #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 @@ 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; } } diff -r abfb40232967 sys/src/games/md/ym.c --- a/sys/src/games/md/ym.c Fri May 11 16:16:37 2018 +0200 +++ b/sys/src/games/md/ym.c Fri May 11 22:11:38 2018 +0200 @@ -1,11 +1,10 @@ #include #include #include +#include #include "dat.h" #include "fns.h" -extern int debug; - u8int ym[512]; enum { MODE = 0x27, @@ -436,7 +435,7 @@ 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) diff -r abfb40232967 sys/src/games/nes/apu.c --- a/sys/src/games/nes/apu.c Fri May 11 16:16:37 2018 +0200 +++ b/sys/src/games/nes/apu.c Fri May 11 22:11:38 2018 +0200 @@ -2,6 +2,7 @@ #include #include #include +#include #include "dat.h" #include "fns.h" @@ -279,7 +280,7 @@ 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) diff -r abfb40232967 sys/src/games/nes/dat.h --- a/sys/src/games/nes/dat.h Fri May 11 16:16:37 2018 +0200 +++ b/sys/src/games/nes/dat.h Fri May 11 22:11:38 2018 +0200 @@ -6,14 +6,14 @@ 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 { FREQ = 21477272, - MILLION = 1000000, - BILLION = 1000000000, APUDIV = 89490, RATE = 44100, SAMPDIV = FREQ / RATE, diff -r abfb40232967 sys/src/games/nes/mem.c --- a/sys/src/games/nes/mem.c Fri May 11 16:16:37 2018 +0200 +++ b/sys/src/games/nes/mem.c Fri May 11 22:11:38 2018 +0200 @@ -2,6 +2,7 @@ #include #include #include +#include #include "dat.h" #include "fns.h" diff -r abfb40232967 sys/src/games/nes/nes.c --- a/sys/src/games/nes/nes.c Fri May 11 16:16:37 2018 +0200 +++ b/sys/src/games/nes/nes.c Fri May 11 22:11:38 2018 +0200 @@ -2,22 +2,17 @@ #include #include #include -#include #include +#include #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 @@ 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 @@ 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 @@ 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; } } diff -r abfb40232967 sys/src/games/nes/ppu.c --- a/sys/src/games/nes/ppu.c Fri May 11 16:16:37 2018 +0200 +++ b/sys/src/games/nes/ppu.c Fri May 11 22:11:38 2018 +0200 @@ -3,18 +3,17 @@ #include #include #include +#include #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 @@ 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 @@ 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 diff -r abfb40232967 sys/src/games/snes/cpu.c --- a/sys/src/games/snes/cpu.c Fri May 11 16:16:37 2018 +0200 +++ b/sys/src/games/snes/cpu.c Fri May 11 22:11:38 2018 +0200 @@ -1,6 +1,7 @@ #include #include #include +#include #include "dat.h" #include "fns.h" @@ -640,8 +641,6 @@ rP = 0x35; } -int trace; - int cpustep(void) { diff -r abfb40232967 sys/src/games/snes/dat.h --- a/sys/src/games/snes/dat.h Fri May 11 16:16:37 2018 +0200 +++ b/sys/src/games/snes/dat.h Fri May 11 22:11:38 2018 +0200 @@ -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 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, diff -r abfb40232967 sys/src/games/snes/dsp.c --- a/sys/src/games/snes/dsp.c Fri May 11 16:16:37 2018 +0200 +++ b/sys/src/games/snes/dsp.c Fri May 11 22:11:38 2018 +0200 @@ -1,6 +1,7 @@ #include #include #include +#include #include "dat.h" #include "fns.h" @@ -77,7 +78,7 @@ 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) diff -r abfb40232967 sys/src/games/snes/mem.c --- a/sys/src/games/snes/mem.c Fri May 11 16:16:37 2018 +0200 +++ b/sys/src/games/snes/mem.c Fri May 11 22:11:38 2018 +0200 @@ -1,6 +1,7 @@ #include #include #include +#include #include "dat.h" #include "fns.h" diff -r abfb40232967 sys/src/games/snes/ppu.c --- a/sys/src/games/snes/ppu.c Fri May 11 16:16:37 2018 +0200 +++ b/sys/src/games/snes/ppu.c Fri May 11 22:11:38 2018 +0200 @@ -1,6 +1,7 @@ #include #include #include +#include #include "dat.h" #include "fns.h" @@ -8,7 +9,6 @@ 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 @@ 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; } } diff -r abfb40232967 sys/src/games/snes/snes.c --- a/sys/src/games/snes/snes.c Fri May 11 16:16:37 2018 +0200 +++ b/sys/src/games/snes/snes.c Fri May 11 22:11:38 2018 +0200 @@ -4,21 +4,16 @@ #include #include #include -#include +#include #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) @@ -114,187 +109,13 @@ } 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 @@ case 'h': hirom++; break; - case 'T': - profile++; - break; default: goto usage; } ARGEND; @@ -321,16 +139,20 @@ 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 @@ stimerclock += t; ppuclock += t; dspclock += t; - perfclock -= t; while(ppuclock >= 4){ ppustep(); @@ -386,18 +207,43 @@ 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 diff -r abfb40232967 sys/src/games/snes/spc.c --- a/sys/src/games/snes/spc.c Fri May 11 16:16:37 2018 +0200 +++ b/sys/src/games/snes/spc.c Fri May 11 22:11:38 2018 +0200 @@ -1,6 +1,7 @@ #include #include #include +#include #include "dat.h" #include "fns.h" diff -r abfb40232967 sys/src/libemu/emu.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/sys/src/libemu/emu.c Fri May 11 22:11:38 2018 +0200 @@ -0,0 +1,315 @@ +#include +#include +#include +#include +#include +#include +#include + +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 -r abfb40232967 sys/src/libemu/mkfile --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/sys/src/libemu/mkfile Fri May 11 22:11:38 2018 +0200 @@ -0,0 +1,20 @@ +