#include <u.h>
#include <libc.h>
#include <thread.h>
#include "../eui.h"
#include "dat.h"
#include "fns.h"
u8int pla;
u8int ram[65536], krom[8192], brom[8192], crom[4096], cart[16384], cram[1024];
u8int reg[47];
u16int vicbank;
u8int cia[32];
u16int timer[4], timrel[4];
enum {
TIMEREN = 1,
TIMERUND = 2,
TIMERSTOP = 8,
TIMERASRC = 0x20,
TIMERBSRC = 0x60,
TIMERBSYS = 0,
TIMERBA = 0x40,
};
u8int
ciaread(int n, u8int a)
{
u8int r;
int i;
switch(a){
case 0:
return (cia[0] | ~cia[2]) & (~joys >> 5 | 0xe0);
case 1:
if(!n){
r = 0;
for(i = 0; i < 8; i++)
if((cia[0] & 1<<i) == 0)
r |= keys >> 8 * i;
return (cia[1] | ~cia[3]) & ~r & (~joys | 0xe0);
}
break;
case 4: return timer[n*2];
case 5: return timer[n*2] >> 8;
case 6: return timer[n*2+1];
case 7: return timer[n*2+1] >> 8;
case 13:
if(n){
r = nmi >> 4 & 0x1f | ((nmi & nmien & 0x1f0) != 0) << 7;
nmi &= ~0x1f0;
return r;
}else{
r = irq >> 4 & 0x1f | ((irq & irqen & 0x1f0) != 0) << 7;
irq &= ~0x1f0;
return r;
}
}
return cia[n * 16 + a];
}
void
ciawrite(int n, u8int a, u8int v)
{
switch(a){
case 0:
if(n)
vicbank = (~v & 3) << 14;
break;
case 4: timrel[n*2] = v | timrel[n*2] & 0xff00; break;
case 5: timrel[n*2] = v << 8 | timrel[n*2] & 0xff; break;
case 6: timrel[n*2+1] = v | timrel[n*2+1] & 0xff00; break;
case 7: timrel[n*2+1] = v << 8 | timrel[n*2+1] & 0xff; break;
case 13:
if(n)
if((v & 0x80) != 0)
nmien |= v << 4 & 0x1f0;
else
nmien &= ~(v << 4 & 0x1f0);
else
if((v & 0x80) != 0)
irqen |= v << 4 & 0x1f0;
else
irqen &= ~(v << 4 & 0x1f0);
break;
case 14: case 15:
if((v & 0x10) != 0){
timer[n * 2 + (a & 1)] = timrel[n * 2 + (a & 1)];
v &= ~0x10;
}
break;
}
cia[n * 16 + a] = v;
}
u8int
mioread(u16int a)
{
u8int b, v;
switch(a & 0xc00){
case 0:
b = a & 63;
switch(b){
case CTRL1:
return reg[b] & 0x7f | ppuy >> 1 & 0x80;
case RASTER:
return ppuy;
case IRQLATCH:
return irq & 0xf | (irq & irqen & 0xf) + 0x7f & 0x80;
case IRQEN:
return irqen & 0xf;
case SPRSPR:
case SPRBG:
v = reg[b];
reg[b] = 0;
return v;
}
if(b >= 0x20)
return reg[b] | 0xf0;
if(b >= 47)
return 0xff;
return reg[b];
case 0x800:
return cram[a & 0x3ff];
case 0xc00:
if((a & 0x200) == 0)
return ciaread(a >> 8 & 1, a & 0xf);
default:
return 0xff;
}
}
void
miowrite(u16int a, u8int v)
{
u8int b;
switch(a & 0xc00){
case 0:
b = a & 63;
if(b >= 0x20)
v &= 0xf;
switch(b){
case CTRL2: v |= 0xc0; break;
case IRQLATCH:
v |= 0xf0;
irq &= ~(v & 0xf);
break;
case IRQEN:
irqen = irqen & ~0xf | v & 0xf;
v |= 0xf0;
break;
}
if(b < 47)
reg[b] = v;
if(b == CTRL1 || b == CTRL2)
bordset();
return;
case 0x800:
cram[a & 0x3ff] = v & 0xf;
return;
case 0xc00:
if((a & 0x200) == 0)
ciawrite(a >> 8 & 1, a & 0xf, v);
return;
}
}
void
tapestep(void)
{
static int tapectr;
static int idx;
if((ram[1] & 1<<5) != 0)
return;
if(tapectr == 0){
if(idx >= tapelen){
progress(0, 0);
tapeplay = 0;
idx = 0;
return;
}
tapectr = tape[idx++] << 3;
if(tapever == 1 && tapectr == 0){
tapectr = tape[idx++];
tapectr |= tape[idx++] << 8;
tapectr |= tape[idx++] << 16;
}
progress(idx, tapelen);
}else{
tapectr--;
if(tapectr == 0)
irq |= IRQFLAG;
}
}
void
timerstep(void)
{
int i, at;
u8int a, b;
u16int *t;
for(i = 0; i < 2; i++){
a = cia[i * 16 + 14];
b = cia[i * 16 + 15];
at = 0;
t = &timer[2 * i];
if((a & (TIMEREN|TIMERASRC)) == TIMEREN){
t[0]--;
if(t[0] == 0){
at = 1;
if(i)
nmi |= IRQTIMERA;
else
irq |= IRQTIMERA;
if((a & TIMERSTOP) != 0)
cia[i * 16 + 14] &= ~TIMEREN;
t[0] = timrel[2 * i];
}
}
if((b & TIMEREN) != 0 && ((b & TIMERBSRC) == TIMERBSYS || (b & TIMERBSRC) == TIMERBA && at)){
t[1]--;
if(t[1] == 0){
if(i)
nmi |= IRQTIMERB;
else
irq |= IRQTIMERB;
if((b & TIMERSTOP) == 0)
cia[i * 16 + 15] &= ~TIMEREN;
t[1] = timrel[2 * i + 1];
}
}
}
if(tapeplay)
tapestep();
}
void
io(void)
{
vicstep();
timerstep();
}
u8int
memread(u16int a)
{
io();
if(a == 1)
return ram[1] & ~(1<<4) | (tapeplay ^ 1) << 4;
switch(a >> 12){
case 8: case 9:
if((pla & (EXROM|GAME)) == EXROM || (pla & (EXROM|HIRAM|LORAM)) == (HIRAM|LORAM))
return cart[a & 0x1fff];
goto def;
case 10: case 11:
if((pla & (GAME|HIRAM|LORAM)) == (GAME|HIRAM|LORAM))
return brom[a & 0x1fff];
if((pla & (EXROM|GAME|HIRAM)) == HIRAM)
return cart[8192 + (a & 0x1fff)];
goto def;
case 13:
if((pla & (HIRAM|LORAM)) == 0 || pla == 1)
goto def;
if((pla & CHAREN) == 0 && (pla & (EXROM|GAME)) != EXROM)
return crom[a & 0xfff];
return mioread(a & 0xfff);
case 14: case 15:
if((pla & (EXROM|GAME)) == EXROM)
return cart[8192 + (a & 0x1fff)];
if((pla & HIRAM) == HIRAM)
return krom[a & 0x1fff];
def:
default:
return ram[a];
}
}
void
memwrite(u16int a, u8int v)
{
if(a >> 12 == 13 && !((pla & (HIRAM|LORAM)) == 0 || pla == 1 || (pla & CHAREN) == 0 && (pla & (EXROM|GAME)) != EXROM)){
miowrite(a & 0xfff, v);
io();
return;
}
ram[a] = v;
if(a == 1)
pla = pla & ~7 | v & 7;
io();
}
u8int
vmemread(u16int a)
{
a |= vicbank;
if((a & 0x7000) == 0x1000)
return crom[a & 0xfff];
return ram[a];
}
void
memreset(void)
{
pla = 0x1f;
}