shithub: sms

ref: 3e6ad74336a451061ca2be070565e34f7215c2de
dir: /vdp.c/

View raw version
#include <u.h>
#include <libc.h>
#include <thread.h>
#include "../eui.h"
#include "dat.h"
#include "fns.h"

extern u8int *pic;

u8int vdpcode, vdpstat = 0;
u16int vdpaddr;
u8int vdpbuf;
int vdpx = 0, vdpyy, frame, intla;
int first = 1;
u16int hctr;
static int xmax, xdisp;
enum { ymax = 262, yvbl = 234 };
int vdpy = ymax-1;

void
vdpmode(void)
{
	xmax = 320;
	xdisp = 256;
}

static void
pixeldraw(int x, int y, u32int v)
{
	u32int *p;
	union { u32int l; u8int b[4]; } u;

	p = (u32int *)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 void
planes(void)
{
	u16int screenmap = (reg[PANT] & 0x0e) << 10;

	u8int y = vdpy + reg[VERSCR];
	y %= 224;
	int ty = y >> 3;
	int tyoff = y & 7;

	u8int x = vdpx - reg[HORSCR];
	int tx = x >> 3;
	int txoff = x & 7;

	u16int taddr = screenmap + (((ty << 5) + tx) << 1);
	u16int tidx = vram[taddr];
	u8int info = vram[taddr + 1];

	if ((info & 1) != 0)
		tidx = (tidx | 0x100) & 0x1ff;

	u8int hflip = (info & 1 << 1) != 0;
	u8int vflip = (info & 1 << 2) != 0;
	u8int paloff = (info & 1 << 3) != 0 ? 16 : 0;

	int data = (tidx << 5) + ((vflip ? 7 - tyoff : tyoff) << 2);
	int xx = hflip ? txoff : 7 - txoff;

	int c = ((vram[data] >> xx) & 1) +
			(((vram[data + 1] >> xx) & 1) << 1) +
			(((vram[data + 2] >> xx) & 1) << 2) +
			(((vram[data + 3] >> xx) & 1) << 3);

	pixeldraw(vdpx, vdpy, cramc[c + paloff]);
}

int sprlst[64] = {-1};

static void
spritesinit(void)
{
	u16int t1 = (reg[SPRTAB] << 7 & 0x3f00);
	u16int t2 = t1 + 0x80;

	int bufidx = 0;
	for(int i = bufidx; i < 8; i++)
		sprlst[i] = -1;

	for(int i = 0; i < 64; i++){
		int spridx = t1 + i;

		if(vram[spridx] == 0xd0)
			break;

		int y = vram[spridx] + 1;
		int h = (reg[MODE2] & 1 << 1) != 0 ? 16 : 8;

		if(vdpy >= y && vdpy < y+h && y > 1){
			if(bufidx >= 8){
				if(vdpy < 192)
					vdpstat |= STATOVR;
				break;
			}

			sprlst[bufidx] = i;
			bufidx++;
		}
	}
}

static void
sprites(void)
{
	u16int t1 = (reg[SPRTAB] << 7 & 0x3f00);
	u16int t2 = t1 + 0x80;
	u16int t3 = (reg[SPRADDR] << 11) & 0x2000;

	for(int i = 7; i >= 0; i--){
		if(sprlst[i] < 0) continue;

		int spr = sprlst[i];
		int spridx = t1 + spr;
		int y = vram[spridx] + 1;
		u16int info = t2 + (spr << 1);
		int x = vram[info];
		//int h = (reg[MODE2] & 1 << 1) != 0 ? 16 : 8;

		int t = vram[info + 1];
		t &= (reg[MODE2] & 1 << 1) != 0 ? 0xfe : 0xff;
		int taddr = t3 + (t << 5) +  ((vdpy - y) << 2);

		for(int xx = 0; xx < 8; xx++){
			int c = ((vram[taddr] >> (7 - xx)) & 0x01) +
					(((vram[taddr + 1] >> (7 - xx)) & 0x01) << 1) +
					(((vram[taddr + 2] >> (7 - xx)) & 0x01) << 2) +
					(((vram[taddr + 3] >> (7 - xx)) & 0x01) << 3);

			if(c > 0) pixeldraw(x+xx, vdpy, cramc[c + 16]);
		}
	}
}

void
vdpctrl(u8int v)
{
	// printf("	vdp write to control port %x\n", v);

	if(first){
		// printf("first\n");
		first = 0;
		vdpaddr = (vdpaddr & 0xff00) | v;
		return;
	}

	vdpcode = (v >> 6) & 0x03;
	vdpaddr = (vdpaddr & 0x00ff) | ((v & 0x3f) << 8);

	// printf("vdp code and address %x %x\n", vdpcode, vdpaddr);
	first = 1;

	switch(vdpcode){
		case 0:
			vdpbuf = vram[vdpaddr];
			vdpaddr++;
			vdpaddr &= 0x3fff;
			break;
		case 2: reg[v & 0x0f] = (vdpaddr & 0x00ff); break;
	}
}

void
vdpdata(u8int v)
{
	// printf("	vdp (code: %x) write to data port %x\n", vdpcode, v);
	first = 1;
	vdpbuf = v;
	switch(vdpcode){
		case 0: case 1: case 2:
			vram[vdpaddr] = v;
			// printf("vramwrite %x %x\n", vdpaddr, v);
		break;
		case 3: cramwrite(vdpaddr, v); break;
	}
	vdpaddr++;
	vdpaddr &= 0x3fff;
}

u8int
vdpdataport(void)
{
	u8int v = vdpbuf;
	vdpbuf = vram[vdpaddr];
	vdpaddr++;
	vdpaddr &= 0x3fff;
	// printf("    vdp read from data port %x\n", v);
	first = 1;
	return v;
}

u8int
vdpstatus(void)
{
	u8int v = vdpstat | 0x1f;
	vdpstat = 0;
	z80irq = 0;
	// printf("    vdp read status flags %x\n", v);
	first = 1;
	return v;
}

u8int
vdphcounter(void)
{
	// printf("    vdp read hcounter %x\n", vdpx);
	return vdpx;
}

u8int
vdpvcounter(void)
{
	// printf("    vdp read hcounter %y\n", vdpy);
	if (vdpy > 0xda)
		return vdpy - 0x06;
	return vdpy;
}

void
vdpstep(void)
{
	if(vdpx == 0)
		spritesinit();

	if(vdpx < 320 && vdpy < 192)
		if(vdpx < xdisp){
			int c = (reg[BGCOL] & 0x0f) + 16;
			pixeldraw(vdpx, vdpy, c);
			planes();
			sprites();
		}else
			pixeldraw(vdpx, vdpy, 0xcccccc);
	if(++vdpx >= xmax){
		z80irq = 0;
		vdpx = 0;
		if(++vdpy >= ymax){
			vdpy = 0;
			irq &= ~INTVBL;
			vdpstat &= ~(STATINT | STATOVR | STATCOLL);
			flush();
		}
		if(intla)
			vdpyy = vdpy << 1 | frame;
		if(vdpy == 0 || vdpy > 192)
			hctr = reg[HORCTR];
		else
			if(hctr-- == 0){
				if((reg[MODE1] & IE1) != 0)
					irq |= INTHOR;
				hctr = reg[HORCTR];
			}
		if(vdpy == yvbl){
			vdpstat |= STATINT;
			frame ^= 1;
			z80irq = 1;
			if((reg[MODE2] & IE0) != 0)
				irq |= INTVBL;
		}
	}
}