shithub: riscv

Download patch

ref: 8ebb846fb2b3b6ba6e828be2ba1ed37d6b4847f2
parent: 4950b5468bd60e9821e3aa9c93ec80a16c194230
author: aiju <[email protected]>
date: Fri Apr 6 16:57:45 EDT 2012

more games/gb fun

--- /dev/null
+++ b/sys/src/games/gb/audio.c
@@ -1,0 +1,152 @@
+#include <u.h>
+#include <libc.h>
+#include <thread.h>
+#include <draw.h>
+#include "dat.h"
+#include "fns.h"
+
+static int fd;
+int ch1c, ch2c, ch3c, ch4c, ch4sr = 1;
+
+enum { SAMPLE = 44100 };
+
+static int
+thresh(int f, int b)
+{
+	switch(b){
+	case 0: return f/8;
+	case 1: return f/4;
+	case 2: return f/2;
+	default: return 3*f/4;
+	}
+}
+
+static int
+freq(int lower)
+{
+	int f;
+	
+	f = mem[lower+1] & 7;
+	f = (f << 8) | mem[lower];
+	f = muldiv(2048 - f, SAMPLE, 131072);
+	return f;
+}
+
+static void
+dosample(short *smp)
+{
+	int ch1s, ch2s, ch3s, ch4s, ch1f, ch2f, ch3f, ch4f, k, r, s;
+	u8int f;
+
+	ch4s = 0;
+	
+	ch1f = freq(0xFF13);
+	if(ch1c >= ch1f)
+		ch1c = 0;
+	if(ch1c >= thresh(ch1f, mem[0xFF11] >> 6))
+		ch1s = 1;
+	else
+		ch1s = -1;
+	ch1s *= mem[0xFF12] >> 4;
+	ch1s *= 10000 / 0xF;
+	ch1c++;
+
+	ch2f = freq(0xFF18);
+	if(ch2c >= ch2f)
+		ch2c = 0;
+	if(ch2c >= thresh(ch1f, mem[0xFF16] >> 6))
+		ch2s = 1;
+	else
+		ch2s = -1;
+	ch2s *= mem[0xFF17] >> 4;
+	ch2s *= 10000 / 0xF;
+	ch2c++;
+	
+	ch3f = freq(0xFF1D) * 100 / 32;
+	if(ch3f == 0)
+		ch3f = 1;
+	ch3s = 0;
+	if(mem[0xFF1A] & 0x80){
+		if(ch3c >= freq(0xFF1D))
+			ch3c = 0;
+		k = ch3c * 100 / ch3f;
+		ch3s = mem[0xFF30 + (k >> 1)];
+		if(k & 1)
+			ch3s &= 0xF;
+		else
+			ch3s >>= 4;
+		switch(mem[0xFF1C]){
+		case 0:
+			ch3s = 0;
+			break;
+		case 2:
+			ch3s >>= 1;
+			break;
+		case 3:
+			ch3s >>= 2;
+			break;
+		}
+		ch3s *= 10000 / 0xF;
+		ch3c++;	
+	}
+	
+	r = mem[0xFF22] & 7;
+	s = mem[0xFF22] >> 4;
+	if(r != 0)
+		ch4f = 524288 / r;
+	else
+		ch4f = 524288 * 2;
+	ch4f >>= s+1;
+	if(ch4f == 0)
+		ch4f = 1;
+	ch4f = SAMPLE / ch4f;
+	if(ch4c >= ch4f){
+		ch4sr <<= 1;
+		if(mem[0xFF22] & 4)
+			k = ((ch4sr >> 6) ^ (ch4sr >> 7)) & 1;
+		else
+			k = ((ch4sr >> 14) ^ (ch4sr >> 15)) & 1;
+		ch4sr |= k;
+		ch4c = 0;
+	}
+	if(ch4sr & 1)
+		ch4s = -1;
+	else
+		ch4s = 1;
+	ch4s *= mem[0xFF21] >> 4;
+	ch4s *= 10000 / 0xF;
+	
+	smp[0] = 0;
+	smp[1] = 0;
+	f = mem[0xFF25];
+	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
+audioproc(void *)
+{
+	short samples[10 * 2];
+	int i;
+
+	for(;;){
+		for(i = 0; i < sizeof samples/4; i++)
+			dosample(samples + 2 * i);
+		write(fd, samples, sizeof samples);
+	}
+}
+
+void
+initaudio(void)
+{
+	fd = open("/dev/audio", OWRITE);
+	if(fd < 0)
+		return;
+	proccreate(audioproc, nil, 8192);
+}
--- a/sys/src/games/gb/cpu.c
+++ b/sys/src/games/gb/cpu.c
@@ -793,14 +793,14 @@
 		memwrite(lohi(R[rC], 0xFF), R[rA]);
 		return 8;
 	case 0xE8:
-		val = (schar)fetch8();
-		val32 = (int)sp + val;
+		val = (short)(schar)fetch8();
+		val32 = (uint)sp + (uint)val;
 		Fl = 0;
-		if(val32 > 0xFFFF || val32 < 0)
+		if(((sp & 0xFF) + (val & 0xFF)) > 0xFF)
 			Fl |= FLAGC;
-		if(((sp & 0xFFF) + (val & 0xFFF)) > 0xFFF)
+		if(((sp & 0xF) + (val & 0xF)) > 0xF)
 			Fl |= FLAGH;
-		sp = val;
+		sp = val32;
 		return 16;
 	case 0xE9:
 		pc = lohi(R[rL], R[rH]);
@@ -823,12 +823,15 @@
 		IME= 0;
 		return 4;
 	case 0xF8:
-		val32 = sp + (schar)fetch8();
+		val = (short)(schar)fetch8();
+		val32 = (uint)sp + (uint)val;
+		Fl = 0;
+		if(((sp & 0xFF) + (val & 0xFF)) > 0xFF)
+			Fl |= FLAGC;
+		if(((sp & 0xF) + (val & 0xF)) > 0xF)
+			Fl |= FLAGH;
 		R[rL] = val32;
 		R[rH] = val32 >> 8;
-		Fl = 0;
-		if(val32 < 0 || val32 > 0xFFFF)
-			Fl = FLAGC;
 		return 12;
 	case 0xF9:
 		sp = lohi(R[rL], R[rH]);
--- a/sys/src/games/gb/dat.h
+++ b/sys/src/games/gb/dat.h
@@ -1,7 +1,7 @@
 extern u16int pc, curpc, sp;
 extern u8int R[8], Fl;
 extern int halt, IME, keys;
-extern int clock, ppuclock, divclock, timerclock, syncclock, timerfreq, timer;
+extern int clock, ppuclock, divclock, timerclock, timerfreq, timer;
 extern int rombank, rambank, ramen, battery, ramrom;
 
 extern uchar mem[], *ram;
@@ -72,4 +72,7 @@
 	IF	= 0xFF0F,
 	IE	= 0xFFFF,
 	CPUFREQ = 4194304,
+	
+	MILLION = 1000000,
+	BILLION = 1000000000,
 };
--- a/sys/src/games/gb/fns.h
+++ b/sys/src/games/gb/fns.h
@@ -8,3 +8,4 @@
 void flushram(void);
 void savestate(char *);
 void loadstate(char *);
+void initaudio(void);
\ No newline at end of file
--- 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, msgclock, timerfreq, timer, keys, savefd, savereq, loadreq;
+int mbc, rombanks, rambanks, clock, ppuclock, divclock, timerclock, syncclock, syncfreq, sleeps, checkclock, msgclock, timerfreq, timer, keys, savefd, savereq, loadreq;
 Rectangle picr;
 Image *bg, *tmp;
 Mousectl *mc;
@@ -87,6 +87,11 @@
 	case 0x11: case 0x12:
 		mbc = 3;
 		break;
+	case 0x1B: case 0x1E:
+		battery = 1;
+	case 0x19: case 0x1A: case 0x1C: case 0x1D:
+		mbc = 5;
+		break;
 	default:
 		sysfatal("%s: unknown cartridge type %.2x", file, cart[0x147]);
 	}
@@ -226,6 +231,9 @@
 	Point p;
 
 	ARGBEGIN{
+	case 'a':
+		initaudio();
+		break;
 	default:
 		sysfatal("unknown flag -%c", ARGC());
 	}ARGEND;
@@ -244,6 +252,7 @@
 	if(mc == nil)
 		sysfatal("init mouse: %r");
 	proccreate(keyproc, nil, 8192);
+	syncfreq = CPUFREQ / 50;
 	old = nsec();
 	for(;;){
 		if(savereq){
@@ -260,6 +269,7 @@
 		divclock += t;
 		timerclock += t;
 		syncclock += t;
+		checkclock += t;
 		if(ppuclock >= 456){
 			ppustep();
 			ppuclock -= 456;
@@ -285,15 +295,22 @@
 			}
 			timerclock = 0;
 		}
-		if(syncclock >= CPUFREQ / 100){
+		if(syncclock >= syncfreq){
+			sleep(10);
+			sleeps++;
+			syncclock = 0;
+		}
+		if(checkclock >= CPUFREQ){
 			new = nsec();
-			diff = new - old;
-			diff = 10000000 - diff;
-			diff /= 1000000;
-			if(diff > 0)
-				sleep(diff);
+			diff = new - old - sleeps * 10 * MILLION;
+			diff = BILLION - diff;
+			if(diff <= 0)
+				syncfreq = CPUFREQ;
+			else
+				syncfreq = ((vlong)CPUFREQ) * 10 * MILLION / diff;
 			old = new;
-			syncclock = 0;
+			checkclock = 0;
+			sleeps = 0;
 		}
 		if(msgclock > 0){
 			msgclock -= t;
--- a/sys/src/games/gb/mem.c
+++ b/sys/src/games/gb/mem.c
@@ -117,6 +117,26 @@
 				return;
 			}
 			return;
+		case 5:
+			switch(p >> 13){
+			case 0:
+				if((v & 0x0F) == 0x0A)
+					ramswitch(1, rambank);
+				else
+					ramswitch(0, rambank);
+				return;
+			case 1:
+				romswitch((rombank & 0x100) | v);
+				return;
+			case 2:
+				romswitch((((int)v & 1) << 8) | (rombank & 0xFF));
+				return;
+			case 3:
+				ramswitch(ramen, v & 15);
+				return;
+			
+			}
+			return;
 		default:
 			sysfatal("mbc %d unimplemented", mbc);
 		}
--- a/sys/src/games/gb/mkfile
+++ b/sys/src/games/gb/mkfile
@@ -10,6 +10,7 @@
 	ppu.$O\
 	daa.$O\
 	state.$O\
+	audio.$O\
 
 HFILES=dat.h fns.h
 
--- a/sys/src/games/gb/ppu.c
+++ b/sys/src/games/gb/ppu.c
@@ -79,24 +79,33 @@
 static void
 drawsprites(void)
 {
-	u8int x, y, tnl1, tnl2, dx, ddx, val, pal;
+	u8int y, t, tnl1, tnl2, dx, ddx, val, pal;
 	schar dy;
 	u16int tnli;
-	int i;
+	int i, x, big;
 	struct { u8int y, x, t, f; } *s;
 	
 	y = mem[LY];
+	big = mem[LCDC] & SPRITE16;
 	s = (void*)(mem + 0xFE00);
 	for(i = 0; i < 40; i++, s++){
-		if(s->y == 0 && s->x == 0)
+		if(s->y == 0 || s->x == 0)
 			continue;
 		dy = y - s->y + 16;
-		if(dy < 0 || dy >= 8)
+		if(dy < 0 || dy >= (big ? 16 : 8))
 			continue;
 		pal = (s->f & (1<<4)) ? mem[OBP1] : mem[OBP0];
 		if(s->f & (1<<6))
-			dy = 7 - dy;
-		tnli = 0x8000 + 2 * (u16int)dy + 16 * (u16int) s->t;
+			dy = (big ? 15 : 7) - dy;
+		t = s->t;
+		if(big){
+			if(dy >= 8){
+				t |= 1;
+				dy -= 8;
+			}else
+				t &= ~1;
+		}
+		tnli = 0x8000 + 2 * (u16int)dy + 16 * (u16int) t;
 		tnl1 = mem[tnli];
 		tnl2 = mem[tnli + 1];
 		x = s->x - 9;
@@ -105,14 +114,14 @@
 			if((s->f & (1<<5)) == 0)
 				ddx = 7 - dx;
 			val = ((tnl1 >> ddx) & 1) | (((tnl2 >> ddx) & 1) << 1);
-			if(val == 0)
+			if(x < 0 || val == 0)
 				continue;
 			val = (pal >> (2 * val)) & 3;
 			if(x >= 160)
 				break;
-			if(s->f & (1<<7)){
+			if(s->f & (1<<7))
 				pixelbelow(x, y, val);
-			}else
+			else
 				pixel(x, y, val, 0);
 		}
 	}
@@ -167,8 +176,9 @@
 			interrupt(INTLCDC);
 	}else
 		mem[STAT] &= ~4;
-	if(mem[LY] < 144 && (mem[LCDC] & LCDOP)){
+	if(mem[LY] < 144)
 		mem[STAT] &= ~3;
+	if(mem[LY] < 144 && (mem[LCDC] & LCDOP)){
 		if(mem[LCDC] & BGDISP)
 			drawbg();
 		if(mem[LCDC] & WINDOWDISP)
--- a/sys/src/games/gb/state.c
+++ b/sys/src/games/gb/state.c
@@ -81,7 +81,6 @@
 	clock = get32();
 	ppuclock = get32();
 	divclock = get32();
-	syncclock = get32();
 	timerfreq = get32();
 	timer = get32();
 	rombank = get32();
@@ -114,7 +113,6 @@
 	put32(ppuclock);
 	put32(divclock);
 	put32(timerclock);
-	put32(syncclock);
 	put32(timerfreq);
 	put32(timer);
 	put32(rombank);