ref: 0bc05e8fa07ce2c45198698c6b4a1680240fab72
dir: /vdp.c/
#include <stdint.h>
#include <stdio.h>
#include "dat.h"
#include "fns.h"
extern uint8_t *pic;
uint8_t vdpcode, vdpstat = 0;
uint16_t vdpaddr;
uint8_t vdpbuf;
int vdpx = 0, vdpy, vdpyy, frame, intla;
int first = 1;
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)
{
// printf("planeinit\n");
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;
uint8_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;
int sprlst[64] = {-1};
static void
spritesinit(void)
{
printf("spritesinit\n");
uint16_t t1 = (reg[SPRTAB] << 7 & 0x3f00);
uint16_t 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[1] & 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)
{
if (vdpy > 192) return;
uint16_t t1 = (reg[SPRTAB] << 7 & 0x3f00);
uint16_t t2 = t1 + 0x80;
uint16_t t3 = (reg[6] << 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;
uint16_t info = t2 + (spr << 1);
int x = vram[info];
int h = (reg[1] & 1 << 1) != 0 ? 16 : 8;
if (x >= 256) continue;
int t = vram[info + 1];
t &= (reg[1] & 1 << 1) != 0 ? 0xfe : 0xff;
int taddr = t3 + (t << 5) + ((vdpy - y) << 2);
for (int xx = 0; xx < 8; xx++){
if (x+xx > 256) continue;
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) continue;
pixeldraw(x+xx, vdpy, cramc[c + 16]);
}
}
}
void
vdpctrl(uint8_t 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(uint8_t 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;
}
uint8_t
vdpdataport(void)
{
uint8_t v = vdpbuf;
vdpbuf = vram[vdpaddr];
vdpaddr++;
vdpaddr &= 0x3fff;
printf(" vdp read from data port %x\n", v);
first = 1;
return v;
}
uint8_t
vdpstatus(void)
{
uint8_t v = vdpstat | 0x1f;
vdpstat = 0;
z80irq = 0;
printf(" vdp read status flags %x\n", v);
first = 1;
return v;
}
uint8_t
vdphcounter(void)
{
printf(" vdp read hcounter %x\n", vdpx);
return vdpx;
}
uint8_t
vdpvcounter(void)
{
printf(" vdp read vcounter %x\n", vdpy);
return vdpy;
}
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;
}
}
}