ref: e90ba58902d0f695732b76fe86acedf3a4d1be74
dir: /vdp.c/
#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, ydisp;
enum { ymax = 262, yvbl = 234 };
int vdpy = ymax-1;
static u8int scrollx;
static int scrolly;
void
vdpmode(void)
{
xmax = 320;
xdisp = 256;
ydisp = 224;
}
static void
pixeldraw(int x, int y, u32int v)
{
((u32int *)pic)[x + y * xdisp] = v;
}
static void
planes(void)
{
int ext224 = ((reg[MODE1] & 0x06) == 0x06) && ((reg[MODE2] & 0x18) == 0x10);
u16int screenmap = (reg[PANT] & (ext224 ? 0x0c : 0x0e)) << 10;
if(ext224)
screenmap |= 0x700;
if((reg[MODE1] & 1 << 5) && vdpx < 8){
int c = (reg[BGCOL] & 0x0f) + 16;
pixeldraw(vdpx, vdpy, cramc[c]);
return;
}
int y = vdpy;
if(!((reg[MODE1] & 1 << 7) && vdpx >= 192))
y += scrolly;
if(ext224)
y &= 0xff;
else if(y >= 224)
y -= 224;
int ty = y >> 3;
int tyoff = y & 7;
u8int hscr = ((reg[MODE1] & 1 << 6) && vdpy < 16) ? 0 : scrollx;
u8int x = vdpx - hscr;
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);
int disph = ((reg[MODE1] & 0x06) == 0x06) && ((reg[MODE2] & 0x18) == 0x10) ? 224 : 192;
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 < disph)
vdpstat |= STATOVR;
break;
}
sprlst[bufidx] = i;
bufidx++;
}
}
}
static void
sprites(void)
{
u16int t1, t2, t3;
t1 = (reg[SPRTAB] << 7 & 0x3f00);
t2 = t1 + 0x80;
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)
{
if(first){
first = 0;
vdpaddr = (vdpaddr & 0xff00) | v;
return;
}
vdpcode = (v >> 6) & 0x03;
vdpaddr = (vdpaddr & 0x00ff) | ((v & 0x3f) << 8);
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)
{
first = 1;
vdpbuf = v;
switch(vdpcode){
case 0: case 1: case 2:
vram[vdpaddr] = v;
break;
case 3: cramwrite(vdpaddr, v); break;
}
vdpaddr++;
vdpaddr &= 0x3fff;
}
u8int
vdpdataport(void)
{
u8int v;
v = vdpbuf;
vdpbuf = vram[vdpaddr];
vdpaddr++;
vdpaddr &= 0x3fff;
first = 1;
return v;
}
u8int
vdpstatus(void)
{
u8int v;
v = vdpstat | 0x1f;
vdpstat = 0;
z80irq = 0;
first = 1;
return v;
}
u8int
vdphcounter(void)
{
return vdpx;
}
u8int
vdpvcounter(void)
{
if (vdpy > 0xda)
return vdpy - 0x06;
return vdpy;
}
void
vdpstep(void)
{
int disph = ((reg[MODE1] & 0x06) == 0x06) && ((reg[MODE2] & 0x18) == 0x10) ? 224 : 192;
if(vdpx == 0)
spritesinit();
if(vdpx == 0){
scrollx = reg[HORSCR];
if(vdpy == 0)
scrolly = reg[VERSCR];
}
if(vdpx < xdisp && vdpy < disph){
planes();
if(vdpx == xdisp - 1) sprites();
}
if(++vdpx >= xmax){
z80irq = 0;
vdpx = 0;
if(++vdpy >= ymax){
vdpy = 0;
scrolly = reg[VERSCR];
irq &= ~INTVBL;
vdpstat &= ~(STATINT | STATOVR | STATCOLL);
flush();
}
if(intla)
vdpyy = vdpy << 1 | frame;
if(vdpy == 0 || vdpy > disph)
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;
}
}
}