shithub: riscv

Download patch

ref: ff5ac0c5cb11cf2770a44157107abff8536a0edc
parent: c65a3809dade0640fe6247fecb9461515857aec2
author: aiju <devnull@localhost>
date: Thu Feb 27 14:52:02 EST 2014

games/nes: improved time synchronization
games/gb: added some games/nes improvements

--- a/sys/src/games/gb/audio.c
+++ b/sys/src/games/gb/audio.c
@@ -9,7 +9,7 @@
 static int sc, ch1c, ch2c, ch3c, ch4c, ch4sr = 1, ch1vec, ch2vec, ch4vec, ch1v, ch2v, ch4v;
 extern int paused;
 
-enum { SAMPLE = 44100 };
+static short sbuf[2*2000], *sbufp;
 
 static int
 thresh(int f, int b)
@@ -84,12 +84,14 @@
 	(*c)++;
 }
 
-static void
-dosample(short *smp)
+void
+audiosample(void)
 {
 	int ch1s, ch2s, ch3s, ch4s, ch1f, ch2f, ch3f, ch4f, k, r, s;
 	u8int f;
 	
+	if(sbufp == nil)
+		return;
 	if(sc >= SAMPLE/256){
 		soundlen(0xFF11, 0xFF14, 0);
 		soundlen(0xFF16, 0xFF19, 1);
@@ -179,51 +181,40 @@
 	ch4s *= ch4v >> 4;
 	ch4s *= 8000 / 0xF;
 	
-	smp[0] = 0;
-	smp[1] = 0;
 	f = mem[0xFF25];
 	r = mem[0xFF26] & 15;
 	r = r | (r << 4);
 	f &= r;
-	if(f & 0x01) smp[0] += ch1s;
-	if(f & 0x02) smp[0] += ch2s;
-	if(f & 0x04) smp[0] += ch3s;
-	if(f & 0x08) smp[0] += ch4s;
-	if(f & 0x10) smp[1] += ch1s;
-	if(f & 0x20) smp[1] += ch2s;
-	if(f & 0x40) smp[1] += ch3s;
-	if(f & 0x80) smp[1] += ch4s;
-}
-
-void
-setpri(int pri)
-{
-	char buf[64];
-	int fd;
-
-	snprint(buf, sizeof(buf), "/proc/%d/ctl", getpid());
-	if((fd = open(buf, OWRITE)) >= 0){
-		fprint(fd, "pri %d\n", pri);
-		close(fd);
+	if(sbufp < sbuf + nelem(sbuf) - 1){
+		*sbufp = 0;
+		if(f & 0x01) *sbufp += ch1s;
+		if(f & 0x02) *sbufp += ch2s;
+		if(f & 0x04) *sbufp += ch3s;
+		if(f & 0x08) *sbufp += ch4s;
+		*++sbufp = 0;
+		if(f & 0x10) *sbufp += ch1s;
+		if(f & 0x20) *sbufp += ch2s;
+		if(f & 0x40) *sbufp += ch3s;
+		if(f & 0x80) *sbufp += ch4s;
+		sbufp++;
 	}
 }
 
-void
-audioproc(void *)
+int
+audioout(void)
 {
-	short samples[10 * 2];
-	int i;
+	int rc;
 
-	setpri(13);
-
-	for(;;){
-		if(paused)
-			memset(samples, 0, sizeof samples);
-		else
-			for(i = 0; i < sizeof samples/4; i++)
-				dosample(samples + 2 * i);
-		write(fd, samples, sizeof samples);
-	}
+	if(sbufp == nil)
+		return -1;
+	if(sbufp == sbuf)
+		return 0;
+	rc = write(fd, sbuf, (sbufp - sbuf) * 2);
+	if(rc > 0)
+		sbufp -= (rc+1)/2;
+	if(sbufp < sbuf)
+		sbufp = sbuf;
+	return 0;
 }
 
 void
@@ -236,5 +227,5 @@
 	fd = open("/dev/audio", OWRITE);
 	if(fd < 0)
 		return;
-	proccreate(audioproc, nil, 8192);
+	sbufp = sbuf;
 }
--- a/sys/src/games/gb/dat.h
+++ b/sys/src/games/gb/dat.h
@@ -77,4 +77,5 @@
 	
 	MILLION = 1000000,
 	BILLION = 1000000000,
+	SAMPLE = 44100,
 };
--- a/sys/src/games/gb/fns.h
+++ b/sys/src/games/gb/fns.h
@@ -8,4 +8,7 @@
 void flushram(void);
 void savestate(char *);
 void loadstate(char *);
-void initaudio(void);
\ No newline at end of file
+void initaudio(void);
+void audiosample(void);
+int audioout(void);
+void flush(void);
--- a/sys/src/games/gb/gb.c
+++ b/sys/src/games/gb/gb.c
@@ -9,7 +9,7 @@
 #include "fns.h"
 
 uchar *cart, *ram;
-int mbc, rombanks, rambanks, clock, ppuclock, divclock, timerclock, syncclock, syncfreq, sleeps, checkclock, msgclock, timerfreq, timer, keys, savefd, savereq, loadreq, scale, paused;
+int mbc, rombanks, rambanks, clock, ppuclock, divclock, timerclock, audioclock, msgclock, timerfreq, timer, keys, savefd, savereq, loadreq, scale, paused;
 Rectangle picr;
 Image *bg, *tmp;
 Mousectl *mc;
@@ -143,8 +143,7 @@
 	p = divpt(addpt(screen->r.min, screen->r.max), 2);
 	picr = (Rectangle){subpt(p, Pt(scale * 80, scale * 72)), addpt(p, Pt(scale * 80, scale * 72))};
 	bg = allocimage(display, Rect(0, 0, 1, 1), screen->chan, 1, 0xCCCCCCFF);
-	if(screen->chan != XRGB32 || screen->chan != XBGR32)
-		tmp = allocimage(display, Rect(0, 0, scale * 160, scale * 144), XRGB32, 0, 0);
+	tmp = allocimage(display, Rect(0, 0, scale * 160, scale * 144), XRGB32, 0, 0);
 	draw(screen, screen->r, bg, nil, ZP);
 	
 	if(ram && battery){
@@ -234,9 +233,6 @@
 threadmain(int argc, char** argv)
 {
 	int t;
-	vlong old, new, diff;
-	Mouse m;
-	Point p;
 
 	scale = 1;
 	ARGBEGIN{
@@ -267,8 +263,6 @@
 	if(mc == nil)
 		sysfatal("init mouse: %r");
 	proccreate(keyproc, nil, 8192);
-	syncfreq = CPUFREQ / 50;
-	old = nsec();
 	for(;;){
 		if(savereq){
 			savestate("gb.save");
@@ -286,26 +280,20 @@
 		clock += t;
 		ppuclock += t;
 		divclock += t;
+		audioclock += t;
 		timerclock += t;
-		syncclock += t;
-		checkclock += t;
 		if(ppuclock >= 456){
 			ppustep();
 			ppuclock -= 456;
-			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 * 80, scale * 72)), addpt(p, Pt(scale * 80, scale * 72))};
-				bg = allocimage(display, Rect(0, 0, 1, 1), screen->chan, 1, 0xCCCCCCFF);
-			}
 		}
 		if(divclock >= 256){
 			mem[DIV]++;
 			divclock = 0;
 		}
+		if(audioclock >= CPUFREQ / SAMPLE){
+			audiosample();
+			audioclock -= CPUFREQ / SAMPLE;
+		}
 		if(timer && timerclock >= timerfreq){
 			mem[TIMA]++;
 			if(mem[TIMA] == 0){
@@ -314,23 +302,6 @@
 			}
 			timerclock = 0;
 		}
-		if(syncclock >= syncfreq){
-			sleep(10);
-			sleeps++;
-			syncclock = 0;
-		}
-		if(checkclock >= CPUFREQ){
-			new = nsec();
-			diff = new - old - sleeps * 10 * MILLION;
-			diff = BILLION - diff;
-			if(diff <= 0)
-				syncfreq = CPUFREQ;
-			else
-				syncfreq = ((vlong)CPUFREQ) * 10 * MILLION / diff;
-			old = new;
-			checkclock = 0;
-			sleeps = 0;
-		}
 		if(msgclock > 0){
 			msgclock -= t;
 			if(msgclock <= 0){
@@ -338,5 +309,45 @@
 				msgclock = 0;
 			}
 		}
+	}
+}
+
+void
+flush(void)
+{
+	extern uchar pic[160*144*4*3*3];
+	Mouse m;
+	Point p;
+	static vlong old;
+	vlong new, diff;
+
+	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 * 80, scale * 72)), addpt(p, Pt(scale * 80, scale * 72))};
+		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){
+		loadimage(tmp, tmp->r, pic, 160*144*4*scale*scale);
+		draw(screen, picr, tmp, nil, ZP);
+	}else
+		loadimage(screen, picr, pic, 160*144*4*scale*scale);
+	flushimage(display, 1);
+	memset(pic, sizeof pic, 0);
+	if(audioout() < 0){
+		new = nsec();
+		if(old != 0){
+			diff = BILLION/60 - (new - old);
+			if(diff >= MILLION)
+				sleep(diff/MILLION);
+		}
+		old = nsec();
 	}
 }
--- a/sys/src/games/gb/ppu.c
+++ b/sys/src/games/gb/ppu.c
@@ -177,9 +177,6 @@
 void
 ppustep(void)
 {
-	extern Rectangle picr;
-	extern Image *tmp;
-
 	if(mem[LY] == 144){
 		mem[STAT] &= ~3;
 		mem[STAT] |= 1;
@@ -204,14 +201,8 @@
 	mem[LY]++;
 	if(mem[LY] > 160){
 		mem[LY] = 0;
-		if(mem[LCDC] & LCDOP){
-			if(tmp){
-				loadimage(tmp, tmp->r, pic, 160*144*4*scale*scale);
-				draw(screen, picr, tmp, nil, ZP);
-			}else
-				loadimage(screen, picr, pic, 160*144*4*scale*scale);
-			flushimage(display, 1);
-			memset(pic, sizeof pic, 0);
-		}
+		if((mem[LCDC] & LCDOP) == 0)
+			memset(pic, 0, sizeof(pic));
+		flush();
 	}
 }
--- a/sys/src/games/nes/ppu.c
+++ b/sys/src/games/nes/ppu.c
@@ -255,8 +255,8 @@
 	extern Rectangle picr;
 	extern Image *tmp, *bg;
 	extern Mousectl *mc;
-	static vlong old, diff;
-	vlong new;
+	static vlong old, delta;
+	vlong new, diff;
 	Mouse m;
 	Point p;
 	int h;
@@ -286,12 +286,17 @@
 	memset(pic, sizeof pic, 0);
 	if(audioout() < 0){
 		new = nsec();
+		diff = 0;
 		if(old != 0){
-			diff = BILLION/60 - (new - old);
+			diff = BILLION/60 - (new - old) - delta;
 			if(diff >= MILLION)
 				sleep(diff/MILLION);
 		}
-		old = new;
+		old = nsec();
+		if(diff != 0){
+			diff = (old - new) - (diff / MILLION) * MILLION;
+			delta += (diff - delta) / 100;
+		}
 	}
 }