shithub: sms

Download patch

ref: 4ebcf852deee068e350f8f539adba0f23a5fcf14
parent: 4e08bc6d73edea3860b82af0634555f220830611
author: Jean-André Santoni <jean.andre.santoni@gmail.com>
date: Wed Jul 10 10:23:13 EDT 2024

Add md vdp

--- a/Makefile
+++ b/Makefile
@@ -3,7 +3,7 @@
 SHARED := -shared
 CFLAGS += -O3 -fPIC
 
-OBJ = sms.o z80.o mem.o
+OBJ = sms.o z80.o mem.o vdp.o
 
 .DEFAULT_GOAL := $(TARGET)
 
--- a/dat.h
+++ b/dat.h
@@ -13,6 +13,11 @@
 extern uint8_t *rom;
 extern uint8_t *mem;
 
+extern uint16_t vram[32768], vsram[40];
+extern uint32_t cramc[64];
+extern uint16_t vdpstat;
+extern int vdpx, vdpy, frame, intla;
+
 enum {
 	MODE1   = 0x00,
 	MODE2   = 0x01,
--- /dev/null
+++ b/vdp.c
@@ -1,0 +1,377 @@
+#include "dat.h"
+#include "fns.h"
+
+extern uint8_t *pic;
+
+uint16_t vdpstat = 0x3400;
+int vdpx, vdpy, vdpyy, frame, intla;
+uint16_t hctr;
+static int xmax, xdisp;
+static int sx, snx, col, pri, lum;
+enum { DARK, NORM, BRIGHT };
+enum { ymax = 262, yvbl = 234 };
+
+void
+vdpmode(void)
+{
+	if((reg[MODE4] & WIDE) != 0){
+		xmax = 406;
+		xdisp = 320;
+	}else{
+		xdisp = 256;
+		xmax = 342;
+	}
+	intla = (reg[MODE4] & 6) == 6;
+}
+
+static void
+pixeldraw(int x, int y, int v)
+{
+	uint32_t *p;
+	union { uint32_t l; uint8_t b[4]; } u;
+
+	p = (uint32_t *)pic + (x + y * 320);
+	u.b[0] = v >> 16;
+	u.b[1] = v >> 8;
+	u.b[2] = v;
+	u.b[3] = 0;
+	*p = u.l;
+}
+
+static uint32_t
+shade(uint32_t v, int l)
+{
+	if(l == 1)
+		return v;
+	if(l == 2)
+		return v << 1 & 0xefefef;
+	return v >> 1 & 0xf7f7f7;
+}
+
+static void
+pixel(int v, int p)
+{
+	if(p >= pri){
+		col = v;
+		pri = p;
+	}
+}
+
+struct pctxt {
+	uint8_t ws, w, hs, h;
+	uint16_t tx, ty;
+	uint8_t tnx, tny;
+	uint16_t t;
+	uint32_t c;
+} pctxt[3];
+int lwin, rwin;
+
+static void
+tile(struct pctxt *p)
+{
+	uint16_t a;
+	int y;
+	
+	switch(p - pctxt){
+	default: a = (reg[PANT] & 0x38) << 9; break;
+	case 1: a = (reg[PBNT] & 7) << 12; break;
+	case 2: a = (reg[PWNT] & 0x3e) << 9; break;
+	}
+	a += p->ty << p->ws;
+	a += p->tx;
+	p->t = vram[a];
+	y = p->tny;
+	if(intla){
+		if((p->t & 0x1000) != 0)
+			y = 15 - y;
+		a = (p->t & 0x7ff) << 5 | y << 1;
+	}else{
+		if((p->t & 0x1000) != 0)
+			y = 7 - y;
+		a = (p->t & 0x7ff) << 4 | y << 1;
+	}
+	p->c = vram[a] << 16 | vram[a+1];
+}
+
+static void
+planeinit(void)
+{
+	static int szs[] = {5, 6, 6, 7};
+	int v, a, i;
+	struct pctxt *p;
+	
+	pctxt[0].hs = pctxt[1].hs = szs[reg[PLSIZ] >> 4 & 3];
+	pctxt[0].ws = pctxt[1].ws = szs[reg[PLSIZ] & 3];
+	pctxt[2].ws = (reg[MODE4] & WIDE) != 0 ? 6 : 5;
+	pctxt[2].hs = 5;
+	for(i = 0; i <= 2; i++){
+		pctxt[i].h = 1<<pctxt[i].hs;
+		pctxt[i].w = 1<<pctxt[i].ws;
+	}
+	a = reg[HORSCR] << 9 & 0x7fff;
+	switch(reg[MODE3] & 3){
+	case 1: a += vdpy << 1 & 0xe; break;
+	case 2: a += vdpy << 1 & 0xff0; break;
+	case 3: a += vdpy << 1 & 0xffe; break;
+	}
+	for(i = 0; i < 2; i++){
+		p = pctxt + i;
+		v = -(vram[a + i] & 0x3ff);
+		p->tnx = v & 7;
+		p->tx = v >> 3 & pctxt[i].w - 1;
+		if(intla){
+			v = vsram[i] + vdpyy;
+			p->tny = v & 15;
+			p->ty = v >> 4 & pctxt[i].h - 1;
+		}else{
+			v = vsram[i] + vdpy;
+			p->tny = v & 7;
+			p->ty = v >> 3 & pctxt[i].h - 1;
+		}
+		tile(p);
+		if(p->tnx != 0)
+			if((p->t & 0x800) != 0)
+				p->c >>= p->tnx << 2;
+			else
+				p->c <<= p->tnx << 2;
+	}
+	sx = 0;
+	snx = 0;
+	v = reg[WINV] << 3 & 0xf8;
+	if((reg[WINV] & 0x80) != 0 ? vdpy < v : vdpy >= v){
+		lwin = 0;
+		rwin = reg[WINH] << 4 & 0x1f0;
+		if((reg[WINH] & 0x80) != 0){
+			lwin = rwin;
+			rwin = 320;
+		}
+	}else{
+		lwin = 0;
+		rwin = 320;
+	}
+	if(rwin > lwin){
+		p = pctxt + 2;
+		p->tx = lwin >> 3 & pctxt[2].w - 1;
+		p->tnx = lwin & 7;
+		p->tny = vdpy & 7;
+		p->ty = vdpy >> 3 & pctxt[2].h - 1;
+		tile(p);
+	}
+}
+
+static void
+plane(int n, int vis)
+{
+	struct pctxt *p;
+	uint8_t v, pr;
+	
+	p = pctxt + n;
+	if((p->t & 0x800) != 0){
+		v = p->c & 15;
+		p->c >>= 4;
+	}else{
+		v = p->c >> 28;
+		p->c <<= 4;
+	}
+	if(vis != 0){
+		if(v != 0){
+			v |= p->t >> 9 & 48;
+			pr = 2 - (n & 1) + (p->t >> 13 & 4);
+			pixel(v, pr);
+		}
+		lum |= p->t >> 15;
+	}
+	if(++p->tnx == 8){
+		p->tnx = 0;
+		if(++p->tx == p->w)
+			p->tx = 0;
+		tile(pctxt + n);
+	}
+}
+
+static void
+planes(void)
+{
+	int i, w;
+	uint16_t v;
+
+	if((reg[MODE3] & 4) != 0 && ++snx == 16){
+		snx = 0;
+		sx++;
+		for(i = 0; i < 2; i++){
+			v = vsram[sx + i] + vdpy;
+			pctxt[i].tny = v & 7;
+			pctxt[i].ty = v >> 3 & pctxt[i].h - 1;
+		}
+	}
+	w = vdpx < rwin && vdpx >= lwin;
+	plane(0, !w);
+	plane(1, 1);
+	if(w)
+		plane(2, 1);
+}
+
+static struct sprite {
+	uint16_t y, x;
+	uint8_t w, h;
+	uint16_t t;
+	uint32_t c[4];
+} spr[21], *lsp;
+
+static void
+spritesinit(void)
+{
+	uint16_t t, *p, dy, c;
+	uint32_t v;
+	int i, ns, np, nt;
+	struct sprite *q;
+	
+	t = (reg[SPRTAB] << 8 & 0x7f00);
+	p = vram + t;
+	q = spr;
+	ns = (reg[MODE4] & WIDE) != 0 ? 20 : 16;
+	np = 0;
+	nt = 0;
+	do{
+		if(intla){
+			q->y = (p[0] & 0x3ff) - 256;
+			q->h = (p[1] >> 8 & 3) + 1 << 4;
+			dy = vdpyy - q->y;
+		}else{
+			q->y = (p[0] & 0x3ff) - 128;
+			q->h = (p[1] >> 8 & 3) + 1 << 3;
+			dy = vdpy - q->y;
+		}
+		if(dy >= q->h)
+			continue;
+		q->t = p[2];
+		if((q->t & 0x1000) != 0)
+			dy = q->h + ~dy;
+		q->x = (p[3] & 0x3ff) - 128;
+		if(q->x == 0xff80)
+			break;
+		q->w = (p[1] >> 10 & 3) + 1 << 3;
+		c = ((q->t & 0x7ff) << 4+intla) + (dy << 1);
+		for(i = 0; i < q->w >> 3 && np < xdisp; i++){
+			v = vram[c] << 16 | vram[(uint16_t)(c+1)];
+			c += q->h << 1;
+			if((q->t & 0x800) != 0)
+				q->c[(q->w >> 3) - 1 - i] = v;
+			else
+				q->c[i] = v;
+			np += 8;
+		}
+		if((uint16_t)-q->x < q->w){
+			i = -(int16_t)q->x;
+			if((q->t & 0x800) != 0)
+				q->c[i>>3] >>= (i & 7) << 2;
+			else
+				q->c[i>>3] <<= (i & 7) << 2;
+		}
+		if(++q == spr + ns || np >= xdisp){
+			vdpstat |= STATOVR;
+			break;
+		}
+	}while(p = vram + (uint16_t)(t + ((p[1] & 0x7f) << 2)), p - vram != t && ++nt < 80);
+	lsp = q;
+}
+
+static void
+sprites(void)
+{
+	struct sprite *p;
+	uint16_t dx;
+	int v, col, set;
+	uint32_t *c;
+	
+	set = 0;
+	col = 0;
+	for(p = spr; p < lsp; p++){
+		dx = vdpx - p->x;
+		if(dx >= p->w)
+			continue;
+		c = p->c + (dx >> 3);
+		if((p->t & 0x800) != 0){
+			v = *c & 15;
+			*c >>= 4;
+		}else{
+			v = *c >> 28;
+			*c <<= 4;
+		}
+		if(v != 0)
+			if(set != 0)
+				vdpstat |= STATCOLL;
+			else{
+				set = 1 | p->t & 0x8000;
+				col = p->t >> 9 & 48 | v;
+			}
+	}
+	if(set)
+		if((reg[MODE4] & SHI) != 0)
+			if((col & 0xfe) == 0x3e)
+				lum = col & 1;
+			else{
+				pixel(col, set >> 13 | 2);
+				if((col & 0xf) == 0xe)
+					lum = 1;
+				else
+					lum |= set >> 15;
+			}
+		else
+			pixel(col, set >> 13 | 2);
+}
+
+void
+vdpstep(void)
+{
+	uint32_t v;
+
+	if(vdpx == 0){
+		planeinit();
+		spritesinit();
+	}
+	if(vdpx < 320 && vdpy < 224)
+		if(vdpx < xdisp){
+			col = reg[BGCOL] & 0x3f;
+			pri = 0;
+			lum = 0;
+			planes();
+			sprites();
+			if((reg[MODE2] & 0x40) != 0 && (vdpx >= 8 || (reg[MODE1] & 0x20) == 0)){
+				v = cramc[col];
+				if((reg[MODE4] & SHI) != 0)
+					v = shade(v, lum);
+				pixeldraw(vdpx, vdpy, v);
+			}else
+				pixeldraw(vdpx, vdpy, 0);
+		}else
+			pixeldraw(vdpx, vdpy, 0xcccccc);
+	if(++vdpx >= xmax){
+		z80irq = 0;
+		vdpx = 0;
+		if(++vdpy >= ymax){
+			vdpy = 0;
+			irq &= ~INTVBL;
+			vdpstat ^= STATFR;
+			vdpstat &= ~(STATINT | STATVBL | STATOVR | STATCOLL);
+			flush();
+		}
+		if(intla)
+			vdpyy = vdpy << 1 | frame;
+		if(vdpy == 0 || vdpy >= 225)
+			hctr = reg[HORCTR];
+		else
+			if(hctr-- == 0){
+				if((reg[MODE1] & IE1) != 0)
+					irq |= INTHOR;
+				hctr = reg[HORCTR];
+			}
+		if(vdpy == yvbl){
+			vdpstat |= STATVBL | STATINT;
+			frame ^= 1;
+			z80irq = 1;
+			if((reg[MODE2] & IE0) != 0)
+				irq |= INTVBL;
+		}
+	}
+}
--