367 lines
7.3 KiB
C
367 lines
7.3 KiB
C
#include <u.h>
|
|
#include <libc.h>
|
|
#include <thread.h>
|
|
#include "dat.h"
|
|
#include "fns.h"
|
|
|
|
int region, picidx;
|
|
u16int ppux, ppuy, lastx, wrapx, maxy, lvis, rvis, uvis, dvis, picw, pich, lbord, rbord, ubord, dbord, spr0;
|
|
u16int vc, vcbase, vmli;
|
|
u8int badln, rc, displ, fract, visreg, hbord, vbord, rbord0, lbord0;
|
|
u16int chrp[40];
|
|
u8int pic[400*300*3*3];
|
|
u64int pxs, npxs, npxs0, opxs;
|
|
u8int fg;
|
|
|
|
typedef struct spr spr;
|
|
enum {
|
|
SPRFDMA = 1,
|
|
SPRFYEX = 2,
|
|
SPRFDISP = 4,
|
|
};
|
|
struct spr {
|
|
u8int flags;
|
|
u32int data;
|
|
u8int mc, mcbase, dp;
|
|
u16int x;
|
|
} sp[8];
|
|
|
|
void
|
|
bordset(void)
|
|
{
|
|
int r, c;
|
|
|
|
r = (reg[CTRL1] & RSEL) != 0;
|
|
c = (reg[CTRL2] & CSEL) != 0;
|
|
lbord = c ? 0x14 : 0x1c;
|
|
lbord0 = c ? 0xf0 : 0xe0;
|
|
rbord = c ? 0x154 : 0x14c;
|
|
rbord0 = c ? 0x0f : 0x3f;
|
|
ubord = r ? 0x33 : 0x37;
|
|
dbord = r ? 0xfb : 0xf7;
|
|
if((reg[CTRL1] & DEN) == 0)
|
|
ubord = -1;
|
|
}
|
|
|
|
void
|
|
vicreset(void)
|
|
{
|
|
switch(region){
|
|
case NTSC0:
|
|
lastx = 0x1fc;
|
|
wrapx = 0x19c;
|
|
maxy = 262;
|
|
picw = 412;
|
|
pich = 234;
|
|
spr0 = 0x16c;
|
|
lvis = 0x1e4;
|
|
rvis = 0x184;
|
|
uvis = 41;
|
|
dvis = 13;
|
|
break;
|
|
case NTSC:
|
|
lastx = 0x1fc;
|
|
wrapx = 0x19c;
|
|
maxy = 263;
|
|
picw = 419;
|
|
pich = 235;
|
|
spr0 = 0x174;
|
|
lvis = 0x1e4;
|
|
rvis = 0x18c;
|
|
uvis = 41;
|
|
dvis = 13;
|
|
break;
|
|
case PAL:
|
|
lastx = 0x1f4;
|
|
wrapx = 0x194;
|
|
maxy = 312;
|
|
picw = 404;
|
|
pich = 284;
|
|
spr0 = 0x164;
|
|
lvis = 0x1dc;
|
|
rvis = 0x17c;
|
|
uvis = 16;
|
|
dvis = 300;
|
|
break;
|
|
}
|
|
ppux = 4;
|
|
ppuy = 0;
|
|
bordset();
|
|
}
|
|
|
|
void
|
|
pixeldraw(u64int p, int n)
|
|
{
|
|
int i;
|
|
static u8int cr[] = {0, 255, 136, 170, 204, 0, 0, 238, 221, 102, 255, 51, 119, 170, 0, 187};
|
|
static u8int cg[] = {0, 255, 0, 255, 68, 204, 0, 238, 136, 68, 119, 51, 119, 255, 136, 187};
|
|
static u8int cb[] = {0, 255, 0, 238, 204, 85, 170, 119, 85, 0, 119, 51, 119, 102, 255, 187};
|
|
u8int *q, c;
|
|
|
|
q = pic + picidx * 4;
|
|
for(i = 0; i < n; i++){
|
|
c = p >> 56;
|
|
p <<= 8;
|
|
|
|
q[4 * i] = cb[c];
|
|
q[4 * i + 1] = cg[c];
|
|
q[4 * i + 2] = cr[c];
|
|
}
|
|
picidx += n;
|
|
}
|
|
|
|
void
|
|
pixels(u8int d, u16int c)
|
|
{
|
|
u8int c0, c1, c2, n;
|
|
int i;
|
|
|
|
npxs0 = npxs;
|
|
npxs = 0;
|
|
switch((reg[CTRL1] & (ECM|BMM) | reg[CTRL2] & MCM) >> 4){
|
|
case 0:
|
|
c0 = c >> 8;
|
|
normal:
|
|
fg = d;
|
|
for(i = 0; i < 8; i++){
|
|
npxs = npxs << 8 | ((d & 0x80) != 0 ? c0 : reg[BG0]);
|
|
d <<= 1;
|
|
}
|
|
break;
|
|
case 1:
|
|
c0 = c >> 8 & 7;
|
|
if((c & 0x800) == 0)
|
|
goto normal;
|
|
fg = d & 0xaa | d >> 1 & 0x55;
|
|
for(i = 0; i < 8; i += 2){
|
|
n = d >> 6;
|
|
npxs = npxs << 16 | (n == 3 ? c0 : reg[BG0 + n]) * 0x101;
|
|
d <<= 2;
|
|
}
|
|
break;
|
|
case 2:
|
|
c0 = c & 15;
|
|
c1 = c >> 4 & 15;
|
|
fg = d;
|
|
for(i = 0; i < 8; i++){
|
|
npxs = npxs << 8 | ((d & 0x80) != 0 ? c1 : c0);
|
|
d <<= 1;
|
|
}
|
|
break;
|
|
case 3:
|
|
c0 = c & 15;
|
|
c1 = c >> 4 & 15;
|
|
c2 = c >> 8;
|
|
fg = d & 0xaa | d >> 1 & 0x55;
|
|
for(i = 0; i < 8; i += 2){
|
|
n = d >> 6;
|
|
switch(n){
|
|
default: n = reg[BG0]; break;
|
|
case 1: n = c1; break;
|
|
case 2: n = c0; break;
|
|
case 3: n = c2;
|
|
}
|
|
npxs = npxs << 16 | n * 0x101;
|
|
d <<= 2;
|
|
}
|
|
break;
|
|
case 4:
|
|
c0 = c >> 8;
|
|
fg = d;
|
|
for(i = 0; i < 8; i++){
|
|
npxs = npxs << 8 | ((d & 0x80) != 0 ? c0 : reg[BG0 + (d >> 6 & 3)]);
|
|
d <<= 1;
|
|
}
|
|
break;
|
|
default:
|
|
fg = 0;
|
|
break;
|
|
}
|
|
}
|
|
|
|
void
|
|
bgpixels(void)
|
|
{
|
|
int i, j, x;
|
|
u8int h;
|
|
u8int spract, s, o;
|
|
|
|
h = hbord;
|
|
opxs = 0;
|
|
for(i = 0; i < 8; i++){
|
|
if((reg[CTRL2] + 4 & 7) == i)
|
|
pxs = i >= 4 ? npxs : npxs0;
|
|
o = pxs >> 56;
|
|
pxs <<= 8;
|
|
|
|
x = ppux + i;
|
|
spract = 0;
|
|
for(j = 0; j < 8; j++)
|
|
if((sp[j].flags & SPRFDISP) != 0 && (u16int)(x-sp[j].x) < 48 && (sp[j].data & ((reg[SPRMC]&1<<j)?3:2)<<22) != 0)
|
|
spract |= 1<<j;
|
|
if((spract & spract - 1) != 0 && vbord == 0){
|
|
reg[SPRSPR] |= spract;
|
|
irq |= IRQSPRCOLL;
|
|
}
|
|
if(fg != 0 && spract != 0 && vbord == 0){
|
|
reg[SPRBG] |= spract;
|
|
irq |= IRQBGCOLL;
|
|
}
|
|
s = spract & ~(reg[SPRDP] & ((s8int)fg) >> 7);
|
|
if(s != 0)
|
|
for(j = 0; j < 8; j++)
|
|
if((s & 1<<j) != 0){
|
|
if((reg[SPRMC] & 1<<j) != 0)
|
|
switch(sp[j].data >> 22 & 3){
|
|
case 1: o = reg[SPRMC0]; break;
|
|
case 2: o = reg[SPRCOL+j]; break;
|
|
case 3: o = reg[SPRMC1]; break;
|
|
}
|
|
else
|
|
o = reg[SPRCOL+j];
|
|
break;
|
|
}
|
|
if((h & 0x80) != 0)
|
|
o = reg[EC];
|
|
opxs = opxs << 8 | o;
|
|
h <<= 1;
|
|
fg <<= 1;
|
|
for(j = 0; j < 8; j++)
|
|
if((u16int)(x-sp[j].x) < 48 && ((reg[SPRXE] & 1<<j) == 0 || (x-sp[j].x & 1) != 0))
|
|
if((reg[SPRMC] & 1<<j) != 0){
|
|
if((x-sp[j].x & 1) != 0)
|
|
sp[j].data <<= 2;
|
|
}else
|
|
sp[j].data <<= 1;
|
|
}
|
|
}
|
|
|
|
void
|
|
vicstep(void)
|
|
{
|
|
u16int gaddr;
|
|
int i;
|
|
|
|
if(ppuy == 0x30 && (reg[CTRL1] & DEN) != 0)
|
|
fract = 1;
|
|
badln = ((ppuy ^ reg[CTRL1]) & 7) == 0 && fract;
|
|
hbord = ((s8int)(hbord << 7)) >> 7;
|
|
if(ppux == rbord && hbord == 0)
|
|
hbord = rbord0;
|
|
else if(ppux == lbord){
|
|
if(ppuy == dbord)
|
|
vbord = 1;
|
|
if(ppuy == ubord)
|
|
vbord = 0;
|
|
if(!vbord)
|
|
hbord = lbord0;
|
|
}
|
|
if(badln)
|
|
displ = 1;
|
|
if(ppux == 4){
|
|
vc = vcbase;
|
|
vmli = 0;
|
|
if(badln)
|
|
rc = 0;
|
|
}
|
|
if(ppux == 12)
|
|
for(i = 0; i < 8; i++){
|
|
if((sp[i].flags & SPRFDISP) == 0 || (reg[SPRYE] & 1<<i) != 0 && (sp[i].flags & SPRFYEX) == 0)
|
|
continue;
|
|
sp[i].mcbase += 3;
|
|
if(sp[i].mcbase == 63)
|
|
sp[i].flags &= ~(SPRFDMA|SPRFDISP);
|
|
}
|
|
if(ppux >= 0x14 && ppux <= 0x14c){
|
|
if((reg[CTRL1] & BMM) != 0)
|
|
gaddr = (reg[MEMP] & 0x08) << 10 | vc << 3 | rc;
|
|
else
|
|
gaddr = (reg[MEMP] & 0x0e) << 10 | (chrp[vmli] & 0xff) << 3 | rc;
|
|
if(!displ)
|
|
gaddr = 0x3fff;
|
|
if((reg[CTRL1] & ECM) != 0)
|
|
gaddr &= ~0x600;
|
|
pixels(vmemread(gaddr) & -displ, chrp[vmli] & -displ);
|
|
vmli++;
|
|
vc = vc + 1 & 0x3ff;
|
|
}
|
|
if(visreg && (ppux >= lvis || ppux < rvis)){
|
|
bgpixels();
|
|
pixeldraw(opxs, ppux == lvis ? region == NTSC ? 3 : 4 : 8);
|
|
}
|
|
if(ppux == 0x14c){
|
|
for(i = 0; i < 8; i++){
|
|
if((reg[SPRYE] & 1<<i) != 0)
|
|
sp[i].flags ^= SPRFYEX;
|
|
if((reg[SPREN] & 1<<i) == 0 || reg[2*i+1] != (u8int)ppuy)
|
|
continue;
|
|
sp[i].flags |= SPRFDMA;
|
|
sp[i].mcbase = 0;
|
|
if((reg[SPRYE] & 1<<i) != 0)
|
|
sp[i].flags &= ~SPRFYEX;
|
|
}
|
|
}else if(ppux == 0x154)
|
|
npxs = reg[BG0] * 0x0101010101010101ULL;
|
|
if(badln){
|
|
if(ppux == lastx - 8)
|
|
nrdy = 1;
|
|
else if(ppux >= 0xc && ppux <= 0x144)
|
|
chrp[vmli] = vmemread(vc | (reg[MEMP] & 0xf0) << 6) | cram[vc] << 8;
|
|
else if(ppux == 0x154)
|
|
nrdy = 0;
|
|
}
|
|
if(ppux == 0x164){
|
|
if(displ && rc == 7){
|
|
displ = badln;
|
|
vcbase = vc;
|
|
}
|
|
if(displ)
|
|
rc = rc + 1 & 7;
|
|
for(i = 0; i < 8; i++){
|
|
sp[i].mc = sp[i].mcbase;
|
|
if((sp[i].flags & SPRFDMA) != 0 && reg[2*i+1] == (u8int)ppuy)
|
|
sp[i].flags |= SPRFDISP;
|
|
}
|
|
}
|
|
if((u16int)(ppux - spr0) < 128){
|
|
i = ppux - spr0 >> 4;
|
|
nrdy = (sp[i].flags & SPRFDMA) != 0;
|
|
if((ppux & 8) == 0){
|
|
sp[i].dp = vmemread((reg[MEMP] & 0xf0) << 6 | 0x3f8 | i);
|
|
sp[i].x = nrdy ? reg[2 * i] | reg[MSBX] << 8 - i & 0x100 : -1;
|
|
if(nrdy)
|
|
sp[i].data = vmemread(sp[i].dp << 6 | sp[i].mc++) << 16;
|
|
}else if(nrdy){
|
|
sp[i].data = sp[i].data & 0xff00ff | vmemread(sp[i].dp << 6 | sp[i].mc++) << 8;
|
|
sp[i].data = sp[i].data & 0xffff00 | vmemread(sp[i].dp << 6 | sp[i].mc++);
|
|
}
|
|
}else if(ppux - spr0 == 128)
|
|
nrdy = 0;
|
|
if(ppux == wrapx){
|
|
ppuy++;
|
|
if(ppuy == maxy){
|
|
flush();
|
|
ppuy = 0;
|
|
vcbase = 0;
|
|
}
|
|
if((ppuy & 0xff) == reg[RASTER] && ((ppuy ^ reg[CTRL1] << 1) & 0x100) == 0)
|
|
irq |= IRQRASTER;
|
|
if(ppuy == dbord)
|
|
vbord = 1;
|
|
else if(ppuy == ubord)
|
|
vbord = 0;
|
|
else if(ppuy == dvis)
|
|
visreg = 0;
|
|
if(ppuy == uvis){
|
|
picidx = 0;
|
|
visreg = 1;
|
|
}
|
|
if(ppuy == 0xf7)
|
|
fract = 0;
|
|
}
|
|
if(ppux == lastx)
|
|
ppux = 4;
|
|
else
|
|
ppux += 8;
|
|
}
|