games/md: add z80, audio support
This commit is contained in:
parent
26d2fbaec1
commit
7c25ae8a34
9 changed files with 1515 additions and 45 deletions
|
@ -19,7 +19,7 @@ extern u32int irql[8];
|
|||
u32int irqla[8];
|
||||
u16int rS;
|
||||
static u32int op;
|
||||
int trace;
|
||||
int trace, tim;
|
||||
#define ra (r+8)
|
||||
|
||||
static void
|
||||
|
@ -99,16 +99,21 @@ amode(int m, int n, int s)
|
|||
case 1:
|
||||
return ~(n+8);
|
||||
case 2:
|
||||
tim += s == 2 ? 8 : 4;
|
||||
return ra[n];
|
||||
case 3:
|
||||
v = ra[n];
|
||||
ra[n] += 1<<s;
|
||||
tim += s == 2 ? 8 : 4;
|
||||
return v;
|
||||
case 4:
|
||||
tim += s == 2 ? 10 : 6;
|
||||
return ra[n] -= 1<<s;
|
||||
case 5:
|
||||
tim += s == 2 ? 12 : 8;
|
||||
return (u32int)(ra[n] + (s16int)fetch16());
|
||||
case 6:
|
||||
tim += s == 2 ? 14 : 10;
|
||||
w = fetch16();
|
||||
v = r[w >> 12];
|
||||
if((w & 1<<11) == 0)
|
||||
|
@ -117,19 +122,24 @@ amode(int m, int n, int s)
|
|||
case 7:
|
||||
switch(n){
|
||||
case 0:
|
||||
tim += s == 2 ? 12 : 8;
|
||||
return (u32int)(s16int)fetch16();
|
||||
case 1:
|
||||
tim += s == 2 ? 16 : 12;
|
||||
return fetch32();
|
||||
case 2:
|
||||
tim += s == 2 ? 12 : 8;
|
||||
v = fetch16();
|
||||
return (u32int)(pc + (s16int)v - 2);
|
||||
case 3:
|
||||
tim += s == 2 ? 14 : 4;
|
||||
w = fetch16();
|
||||
v = r[w >> 12];
|
||||
if((w & 1<<11) == 0)
|
||||
v = (s16int)v;
|
||||
return (u32int)(pc + v + (s8int)w - 2);
|
||||
case 4:
|
||||
tim += s == 2 ? 8 : 4;
|
||||
v = pc;
|
||||
pc += 1<<s;
|
||||
if(s == 0)
|
||||
|
@ -367,11 +377,13 @@ rot(u32int v, int m, int n, int s)
|
|||
}else
|
||||
v |= x;
|
||||
vf |= x ^ (v & msb) != 0;
|
||||
tim += 2;
|
||||
}
|
||||
nz(v, s);
|
||||
rS |= l;
|
||||
if(m <= 1 && vf)
|
||||
rS |= FLAGV;
|
||||
tim += s == 2 ? 8 : 6;
|
||||
return v;
|
||||
}
|
||||
|
||||
|
@ -414,6 +426,30 @@ subbcd(u8int a, u8int b)
|
|||
return x;
|
||||
}
|
||||
|
||||
static void
|
||||
dtime(u16int op, u8int s)
|
||||
{
|
||||
if((op & 0x100) != 0){
|
||||
if(s == 2)
|
||||
if((op & 0x30) == 0 || (op & 0x3f) == 0x3c)
|
||||
tim += 8;
|
||||
else
|
||||
tim += 6;
|
||||
else
|
||||
tim += 4;
|
||||
}else
|
||||
tim += s == 2 ? 12 : 8;
|
||||
}
|
||||
|
||||
static void
|
||||
stime(int a, u8int s)
|
||||
{
|
||||
if(a)
|
||||
tim += s == 2 ? 6 : 4;
|
||||
else
|
||||
tim += s == 2 ? 12 : 8;
|
||||
}
|
||||
|
||||
static void
|
||||
trap(int n, u32int pcv)
|
||||
{
|
||||
|
@ -428,8 +464,16 @@ trap(int n, u32int pcv)
|
|||
v = intack(l);
|
||||
rS = rS & ~0x700 | l << 8;
|
||||
irq = 0;
|
||||
}else
|
||||
tim += 44;
|
||||
}else{
|
||||
switch(n){
|
||||
case 2: case 3: tim += 50; break;
|
||||
case 5: tim += 38; break;
|
||||
case 6: tim += 40; break;
|
||||
default: tim += 34; break;
|
||||
}
|
||||
v = n;
|
||||
}
|
||||
if((rS & FLAGS) == 0){
|
||||
t = asp;
|
||||
asp = ra[7];
|
||||
|
@ -456,7 +500,7 @@ cpureset(void)
|
|||
irqla[i] = v |= irql[i];
|
||||
}
|
||||
|
||||
void
|
||||
int
|
||||
step(void)
|
||||
{
|
||||
u32int v, w;
|
||||
|
@ -465,17 +509,18 @@ step(void)
|
|||
int n, m, d;
|
||||
static int cnt;
|
||||
|
||||
if(0 && pc == 0x200){
|
||||
if(0 && pc == 0x1300){
|
||||
trace++;
|
||||
print("%x\n", curpc);
|
||||
}
|
||||
tim = 0;
|
||||
curpc = pc;
|
||||
if(irq && (irqla[(rS >> 8) & 7] & irq) != 0){
|
||||
trap(-1, curpc);
|
||||
return;
|
||||
return tim;
|
||||
}
|
||||
if(stop)
|
||||
return;
|
||||
return 1;
|
||||
op = fetch16();
|
||||
if(trace)
|
||||
print("%.6ux %.6uo %.4ux %.8ux | %.8ux %.8ux %.8ux %.8ux | %.8ux %.8ux %.8ux\n", curpc, op, rS, memread(ra[7])<<16|memread(ra[7]+2), r[0], r[1], r[2], r[3], ra[0], ra[1], ra[7]);
|
||||
|
@ -504,6 +549,7 @@ step(void)
|
|||
ra[7] = asp;
|
||||
asp = v;
|
||||
}
|
||||
tim += 20;
|
||||
break;
|
||||
}
|
||||
if((op & 0x13f) == 0x108){ /* MOVEP */
|
||||
|
@ -513,23 +559,27 @@ step(void)
|
|||
v = (u8int)rmode(a, 0) << 8;
|
||||
v |= (u8int)rmode(a + 2, 0);
|
||||
r[n] = r[n] & 0xff00 | v;
|
||||
tim += 16;
|
||||
break;
|
||||
case 1:
|
||||
v = (u8int)rmode(a, 0) << 24;
|
||||
v |= (u8int)rmode(a + 2, 0) << 16;
|
||||
v |= (u8int)rmode(a + 4, 0) << 8;
|
||||
v |= (u8int)rmode(a + 6, 0);
|
||||
tim += 24;
|
||||
r[n] = v;
|
||||
break;
|
||||
case 2:
|
||||
wmode(a, 0, r[n] >> 8);
|
||||
wmode(a + 2, 0, r[n]);
|
||||
tim += 16;
|
||||
break;
|
||||
case 3:
|
||||
wmode(a, 0, r[n] >> 24);
|
||||
wmode(a + 2, 0, r[n] >> 16);
|
||||
wmode(a + 4, 0, r[n] >> 8);
|
||||
wmode(a + 6, 0, r[n]);
|
||||
tim += 24;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
@ -553,11 +603,17 @@ step(void)
|
|||
rS |= FLAGZ;
|
||||
switch(s){
|
||||
case 1: v ^= w; break;
|
||||
case 2: v &= ~w; break;
|
||||
case 2: v &= ~w; if(n == 2) tim += 2; break;
|
||||
case 3: v |= w; break;
|
||||
}
|
||||
if(s != 0)
|
||||
if(s != 0){
|
||||
wmode(a, n, v);
|
||||
tim += (op & 0x100) != 0 ? 8 : 12;
|
||||
}else{
|
||||
tim += (op & 0x100) != 0 ? 4 : 8;
|
||||
if(n == 2)
|
||||
tim += 2;
|
||||
}
|
||||
break;
|
||||
}
|
||||
switch(s){
|
||||
|
@ -576,6 +632,10 @@ step(void)
|
|||
case 6: rS |= FLAGZ; sub(v, w, 0, s); break;
|
||||
default: undef();
|
||||
}
|
||||
if(a < 0)
|
||||
tim += s == 2 ? (n == 1 || n == 6 ? 14 : 16) : 8;
|
||||
else
|
||||
tim += s == 2 ? 20 : 12;
|
||||
if(n != 6)
|
||||
wmode(a, s, v);
|
||||
break;
|
||||
|
@ -592,14 +652,21 @@ step(void)
|
|||
wmode(amode(op >> 6, op >> 9, s), s, v);
|
||||
if((op & 0x1c0) != 0x40)
|
||||
nz(v, s);
|
||||
tim += 4;
|
||||
break;
|
||||
case 4:
|
||||
if((op & 0x1c0) == 0x1c0){ /* LEA */
|
||||
ra[n] = amode(op >> 3, op, 2);
|
||||
break;
|
||||
}
|
||||
if((op & 0x1c0) == 0x180) /* CHK */
|
||||
undef();
|
||||
if((op & 0x1c0) == 0x180){ /* CHK */
|
||||
a = amode(op >> 3, op, s);
|
||||
v = rmode(a, s);
|
||||
if((s32int)r[n] < 0 || (s32int)r[n] > (s32int)v)
|
||||
trap(6, curpc);
|
||||
else
|
||||
tim += 10;
|
||||
}
|
||||
if((op & 0xb80) == 0x880 && (op & 0x38) >= 0x10){ /* MOVEM */
|
||||
s = (op >> 6 & 1) + 1;
|
||||
w = fetch16();
|
||||
|
@ -610,10 +677,12 @@ step(void)
|
|||
if((w & 1) != 0){
|
||||
r[m] = rmode(a, s);
|
||||
a += 1<<s;
|
||||
tim += 2<<s;
|
||||
}
|
||||
w >>= 1;
|
||||
}
|
||||
ra[n] = a;
|
||||
tim += 12;
|
||||
break;
|
||||
}
|
||||
if((op & 0x38) == 0x20){
|
||||
|
@ -623,10 +692,12 @@ step(void)
|
|||
if((w & 1) != 0){
|
||||
a -= 1<<s;
|
||||
wmode(a, s, r[15 - m]);
|
||||
tim += 2<<s;
|
||||
}
|
||||
w >>= 1;
|
||||
}
|
||||
ra[n] = a;
|
||||
tim += 8;
|
||||
break;
|
||||
}
|
||||
a = amode(op >> 3, op, s);
|
||||
|
@ -637,17 +708,21 @@ step(void)
|
|||
else
|
||||
wmode(a, s, r[m]);
|
||||
a += 1<<s;
|
||||
tim += 2<<s;
|
||||
}
|
||||
w >>= 1;
|
||||
}
|
||||
tim += (op & 0x400) != 0 ? 8 : 12;
|
||||
break;
|
||||
}
|
||||
switch(op >> 8 & 0xf){
|
||||
case 0:
|
||||
if(s == 3){ /* MOVE from SR */
|
||||
if((rS & FLAGS) != 0)
|
||||
wmode(amode(op >> 3, op, 1), 1, rS);
|
||||
else
|
||||
if((rS & FLAGS) != 0){
|
||||
a = amode(op >> 3, op, 1);
|
||||
wmode(a, 1, rS);
|
||||
tim += a < 0 ? 6 : 8;
|
||||
}else
|
||||
trap(8, curpc);
|
||||
break;
|
||||
} /* NEGX */
|
||||
|
@ -666,20 +741,25 @@ step(void)
|
|||
rS &= ~FLAGZ;
|
||||
}
|
||||
wmode(a, s, v);
|
||||
stime(a < 0, s);
|
||||
break;
|
||||
case 2: /* CLR */
|
||||
wmode(amode(op >> 3, op, s), s, 0);
|
||||
a = amode(op >> 3, op, s);
|
||||
wmode(a, s, 0);
|
||||
nz(0, 0);
|
||||
stime(a < 0, s);
|
||||
break;
|
||||
case 4:
|
||||
if(s == 3){ /* MOVE to CCR */
|
||||
rS = rS & 0xff00 | rmode(amode(op >> 3, op, 1), 1);
|
||||
tim += 12;
|
||||
break;
|
||||
} /* NEG */
|
||||
a = amode(op >> 3, op, s);
|
||||
v = -rmode(a, s);
|
||||
nz(v, s);
|
||||
wmode(a, s, v);
|
||||
stime(a < 0, s);
|
||||
break;
|
||||
case 6:
|
||||
if(s == 3){ /* MOVE to SR */
|
||||
|
@ -690,6 +770,7 @@ step(void)
|
|||
asp = ra[7];
|
||||
ra[7] = v;
|
||||
}
|
||||
tim += 12;
|
||||
}else
|
||||
trap(8, curpc);
|
||||
break;
|
||||
|
@ -698,6 +779,7 @@ step(void)
|
|||
v = ~rmode(a, s);
|
||||
nz(v, s);
|
||||
wmode(a, s, v);
|
||||
stime(a < 0, s);
|
||||
break;
|
||||
case 8:
|
||||
n = op & 7;
|
||||
|
@ -706,18 +788,27 @@ step(void)
|
|||
a = amode(op >> 3, op, 0);
|
||||
v = rmode(a, 0);
|
||||
wmode(a, 0, subbcd(0, v));
|
||||
if(a < 0)
|
||||
tim += 8;
|
||||
else
|
||||
tim += 6;
|
||||
break;
|
||||
case 1:
|
||||
if((op >> 3 & 7) != 0)
|
||||
if((op >> 3 & 7) != 0){
|
||||
push32(amode(op >> 3, op, 0)); /* PEA */
|
||||
else
|
||||
tim += 8;
|
||||
}else{
|
||||
nz(r[n] = r[n] >> 16 | r[n] << 16, 2); /* SWAP */
|
||||
tim += 4;
|
||||
}
|
||||
break;
|
||||
case 2: /* EXT */
|
||||
nz(r[n] = r[n] & 0xffff0000 | (u16int)(s8int)r[n], 1);
|
||||
tim += 4;
|
||||
break;
|
||||
case 3: /* EXT */
|
||||
nz(r[n] = (s16int)r[n], 2);
|
||||
tim += 4;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
@ -727,10 +818,12 @@ step(void)
|
|||
v = rmode(a, 0);
|
||||
nz(v, 0);
|
||||
wmode(a, s, v | 0x80);
|
||||
tim += a < 0 ? 4 : 14;
|
||||
break;
|
||||
} /* TST */
|
||||
a = amode(op >> 3, op, s);
|
||||
nz(rmode(a, s), s);
|
||||
tim += 4;
|
||||
break;
|
||||
case 14:
|
||||
v = op >> 4 & 0xf;
|
||||
|
@ -743,9 +836,11 @@ step(void)
|
|||
push32(ra[n]);
|
||||
ra[n] = ra[7];
|
||||
ra[7] += (s16int)fetch16();
|
||||
tim += 16;
|
||||
}else{ /* UNLK */
|
||||
ra[7] = ra[n];
|
||||
ra[n] = pop32();
|
||||
tim += 12;
|
||||
}
|
||||
break;
|
||||
}else if(v == 6){ /* MOVE USP */
|
||||
|
@ -754,29 +849,33 @@ step(void)
|
|||
ra[n] = asp;
|
||||
else
|
||||
asp = ra[n];
|
||||
tim += 4;
|
||||
}else
|
||||
trap(8, curpc);
|
||||
break;
|
||||
}
|
||||
if((op & 0xc0) == 0xc0){ /* JMP */
|
||||
pc = amode(op >> 3, op, 2);
|
||||
tim += 4;
|
||||
break;
|
||||
}
|
||||
if((op & 0xc0) == 0x80){ /* JSR */
|
||||
a = amode(op >> 3, op, 2);
|
||||
push32(pc);
|
||||
pc = a;
|
||||
tim += 12;
|
||||
break;
|
||||
}
|
||||
switch(op){
|
||||
case 0x4e70: break; /* RESET */
|
||||
case 0x4e71: break; /* NOP */
|
||||
case 0x4e70: tim += 132; break; /* RESET */
|
||||
case 0x4e71: tim += 4; break; /* NOP */
|
||||
case 0x4e72: /* STOP */
|
||||
if((rS & FLAGS) != 0){
|
||||
rS = fetch16();
|
||||
stop = 1;
|
||||
}else
|
||||
trap(8, curpc);
|
||||
tim += 4;
|
||||
break;
|
||||
case 0x4e73: /* RTE */
|
||||
if((rS & FLAGS) != 0){
|
||||
|
@ -788,14 +887,16 @@ step(void)
|
|||
asp = ra[7];
|
||||
ra[7] = v;
|
||||
}
|
||||
tim += 20;
|
||||
}else
|
||||
trap(8, curpc);
|
||||
break;
|
||||
case 0x4e75: pc = pop32(); break; /* RTS */
|
||||
case 0x4e76: if((rS & FLAGV) != 0) trap(7, curpc); break; /* TRAPV */
|
||||
case 0x4e75: pc = pop32(); tim += 16; break; /* RTS */
|
||||
case 0x4e76: if((rS & FLAGV) != 0) trap(7, curpc); tim += 4; break; /* TRAPV */
|
||||
case 0x4e77: /* RTR */
|
||||
rS = rS & 0xff00 | fetch16() & 0xff;
|
||||
pc = pop32();
|
||||
tim += 20;
|
||||
break;
|
||||
default: undef();
|
||||
}
|
||||
|
@ -812,14 +913,23 @@ step(void)
|
|||
if((u16int)r[n] != 0){
|
||||
r[n]--;
|
||||
pc = pc + v - 2;
|
||||
}else
|
||||
tim += 10;
|
||||
}else{
|
||||
r[n] |= 0xffff;
|
||||
}
|
||||
tim += 14;
|
||||
}
|
||||
}else
|
||||
tim += 12;
|
||||
break;
|
||||
}
|
||||
if(s == 3){ /* Scc */
|
||||
a = amode(op >> 3, op, 0);
|
||||
wmode(a, 0, -cond(op >> 8 & 0xf));
|
||||
v = cond(op >> 8 & 0xf);
|
||||
wmode(a, 0, -v);
|
||||
if(a < 0)
|
||||
tim += 4 + 2 * v;
|
||||
else
|
||||
tim += 8;
|
||||
break;
|
||||
} /* ADDQ, SUBQ */
|
||||
rS |= FLAGZ;
|
||||
|
@ -833,6 +943,10 @@ step(void)
|
|||
v = add(v, n, 0, s);
|
||||
else
|
||||
v = sub(v, n, 0, s);
|
||||
if(a < 0)
|
||||
tim += s == 2 || (op & 0x130) == 0x110 ? 8 : 4;
|
||||
else
|
||||
tim += s == 2 ? 12 : 8;
|
||||
wmode(a, s, v);
|
||||
break;
|
||||
case 6: /* BRA */
|
||||
|
@ -844,14 +958,19 @@ step(void)
|
|||
if((op & 0xf00) == 0x100){ /* BSR */
|
||||
push32(pc);
|
||||
pc = curpc + 2 + v;
|
||||
tim += 18;
|
||||
break;
|
||||
}
|
||||
if(cond((op >> 8) & 0xf))
|
||||
if(cond((op >> 8) & 0xf)){
|
||||
pc = curpc + 2 + v;
|
||||
tim += 10;
|
||||
}else
|
||||
tim += (u8int)(op + 1) <= 1 ? 12 : 8;
|
||||
break;
|
||||
case 7: /* MOVEQ */
|
||||
r[n] = (s8int)op;
|
||||
nz(r[n], 0);
|
||||
tim += 4;
|
||||
break;
|
||||
case 8:
|
||||
if(s == 3){ /* DIVU, DIVS */
|
||||
|
@ -870,6 +989,7 @@ step(void)
|
|||
rS = rS & ~FLAGC | FLAGV;
|
||||
break;
|
||||
}
|
||||
tim += 158;
|
||||
}else{
|
||||
w = r[n] % (u16int)v;
|
||||
v = r[n] / (u16int)v;
|
||||
|
@ -877,6 +997,7 @@ step(void)
|
|||
rS = rS & ~FLAGC | FLAGV;
|
||||
break;
|
||||
}
|
||||
tim += 140;
|
||||
}
|
||||
r[n] = (u16int)v | w << 16;
|
||||
nz(v, 1);
|
||||
|
@ -891,8 +1012,11 @@ step(void)
|
|||
w = rmode(amode(4, m, 0), 0);
|
||||
v = subbcd(v, w);
|
||||
wmode(a, 0, v);
|
||||
}else
|
||||
tim += 18;
|
||||
}else{
|
||||
r[n] = r[n] & 0xffffff00 | subbcd((u8int)r[n], (u8int)r[m]);
|
||||
tim += 6;
|
||||
}
|
||||
break;
|
||||
}
|
||||
logic: /* OR, EOR, AND */
|
||||
|
@ -908,6 +1032,7 @@ step(void)
|
|||
a = ~n;
|
||||
wmode(a, s, v);
|
||||
nz(v, s);
|
||||
dtime(op, s);
|
||||
break;
|
||||
case 11:
|
||||
if(s == 3){ /* CMPA */
|
||||
|
@ -915,18 +1040,21 @@ step(void)
|
|||
a = amode(op >> 3, op, s);
|
||||
rS |= FLAGZ;
|
||||
sub(ra[n], rmode(a, s), 0, 2);
|
||||
tim += 6;
|
||||
break;
|
||||
}
|
||||
if((op & 0x138) == 0x108){ /* CMPM */
|
||||
m = op & 7;
|
||||
rS |= FLAGZ;
|
||||
sub(rmode(amode(3, n, s), s), rmode(amode(3, m, s), s), 0, s);
|
||||
tim += s == 2 ? 20 : 12;
|
||||
break;
|
||||
}
|
||||
if((op & 0x100) == 0){ /* CMP */
|
||||
a = amode(op >> 3, op, s);
|
||||
rS |= FLAGZ;
|
||||
sub(r[n], rmode(a, s), 0, s);
|
||||
tim += s == 2 ? 6 : 4;
|
||||
break;
|
||||
}
|
||||
goto logic;
|
||||
|
@ -940,6 +1068,7 @@ step(void)
|
|||
v = (u16int)v * (u16int)r[n];
|
||||
r[n] = v;
|
||||
nz(v, 1);
|
||||
tim += 70;
|
||||
break;
|
||||
}
|
||||
if((op & 0x1f0) == 0x100){ /* ABCD */
|
||||
|
@ -951,8 +1080,11 @@ step(void)
|
|||
w = rmode(amode(4, m, 0), 0);
|
||||
v = addbcd(v, w);
|
||||
wmode(a, 0, v);
|
||||
}else
|
||||
tim += 18;
|
||||
}else{
|
||||
r[n] = r[n] & 0xffffff00 | addbcd((u8int)r[n], (u8int)r[m]);
|
||||
tim += 6;
|
||||
}
|
||||
break;
|
||||
|
||||
}
|
||||
|
@ -963,15 +1095,20 @@ step(void)
|
|||
v = r[n];
|
||||
r[n] = r[m];
|
||||
r[m] = v;
|
||||
tim += 6;
|
||||
break;
|
||||
}
|
||||
goto logic;
|
||||
case 9:
|
||||
case 13:
|
||||
if(s == 3){ /* ADDA, SUBA */
|
||||
s = 1;
|
||||
if((op & 0x100) != 0)
|
||||
s++;
|
||||
if((op & 0x100) != 0){
|
||||
s = 2;
|
||||
tim += 6;
|
||||
}else{
|
||||
s = 1;
|
||||
tim += 8;
|
||||
}
|
||||
a = amode(op >> 3, op, s);
|
||||
if((op >> 12) == 13)
|
||||
ra[n] += rmode(a, s);
|
||||
|
@ -985,10 +1122,12 @@ step(void)
|
|||
a = ra[n] -= 1<<s;
|
||||
v = rmode(a, s);
|
||||
w = rmode(ra[m] -= 1<<s, s);
|
||||
tim += s == 2 ? 30 : 18;
|
||||
}else{
|
||||
v = r[n];
|
||||
w = r[m];
|
||||
a = ~n;
|
||||
tim += s == 2 ? 8 : 4;
|
||||
}
|
||||
if((op >> 12) == 13)
|
||||
v = add(v, w, (rS & FLAGX) != 0, s);
|
||||
|
@ -1010,6 +1149,7 @@ step(void)
|
|||
if(d)
|
||||
a = ~n;
|
||||
wmode(a, s, v);
|
||||
dtime(op, s);
|
||||
break;
|
||||
case 14: /* shifts */
|
||||
if(s == 3){
|
||||
|
@ -1037,4 +1177,5 @@ step(void)
|
|||
default:
|
||||
undef();
|
||||
}
|
||||
return tim;
|
||||
}
|
||||
|
|
|
@ -3,12 +3,13 @@ typedef signed short s16int;
|
|||
typedef signed long s32int;
|
||||
|
||||
extern u32int curpc, irq;
|
||||
extern int trace;
|
||||
extern int trace, debug;
|
||||
|
||||
extern u8int reg[32];
|
||||
extern u8int dma;
|
||||
|
||||
extern u8int z80bus;
|
||||
extern u8int z80bus, z80irq;
|
||||
extern u16int spc, scurpc;
|
||||
|
||||
extern u16int ram[32768];
|
||||
extern u16int *prg;
|
||||
|
@ -21,6 +22,8 @@ extern u32int cramc[64];
|
|||
extern u16int vdpstat;
|
||||
extern int vdpx, vdpy;
|
||||
|
||||
extern u8int ym[512];
|
||||
|
||||
enum {
|
||||
MODE1 = 0x00,
|
||||
MODE2 = 0x01,
|
||||
|
@ -66,3 +69,14 @@ enum {
|
|||
INTVBL = 1,
|
||||
INTHOR = 2,
|
||||
};
|
||||
|
||||
enum {
|
||||
FREQ = 53203400,
|
||||
YMDIV = 7 * 6,
|
||||
CPUDIV = 7,
|
||||
Z80DIV = 15,
|
||||
RATE = 44100,
|
||||
SAMPDIV = FREQ / RATE,
|
||||
MILLION = 1000 * 1000,
|
||||
BILLION = 1000 * 1000 * 1000,
|
||||
};
|
||||
|
|
|
@ -1,12 +1,20 @@
|
|||
u16int memread(u32int);
|
||||
void memwrite(u32int, u16int, u16int);
|
||||
void cpureset(void);
|
||||
void step(void);
|
||||
int step(void);
|
||||
int z80step(void);
|
||||
u8int z80read(u16int);
|
||||
void z80write(u16int, u8int);
|
||||
u8int z80in(u8int);
|
||||
void z80out(u8int, u8int);
|
||||
int intack(int);
|
||||
void vdpstep(void);
|
||||
void flush(void);
|
||||
void dmastep(void);
|
||||
void vdpmode(void);
|
||||
void ymwrite(u8int, u8int, u8int);
|
||||
void initaudio(void);
|
||||
void audiosample(void);
|
||||
int audioout(void);
|
||||
void ymreset(void);
|
||||
void ymstep(void);
|
||||
|
|
|
@ -7,11 +7,15 @@
|
|||
#include "dat.h"
|
||||
#include "fns.h"
|
||||
|
||||
int debug;
|
||||
|
||||
u16int *prg;
|
||||
int nprg;
|
||||
|
||||
int keys;
|
||||
|
||||
int dmaclock, vdpclock, z80clock, audioclock, ymclock;
|
||||
|
||||
int scale, paused;
|
||||
QLock pauselock;
|
||||
Mousectl *mc;
|
||||
|
@ -100,6 +104,7 @@ keyproc(void *)
|
|||
k = 0xc00;
|
||||
while(*s != 0){
|
||||
s += chartorune(&r, s);
|
||||
if(r >= '0' && r <= '9') debug = r - '0';
|
||||
switch(r){
|
||||
case Kdel: close(fd); threadexitsall(nil);
|
||||
case 'c': k |= 0x0020; break;
|
||||
|
@ -126,8 +131,13 @@ keyproc(void *)
|
|||
void
|
||||
threadmain(int argc, char **argv)
|
||||
{
|
||||
int t;
|
||||
|
||||
scale = 1;
|
||||
ARGBEGIN{
|
||||
case 'a':
|
||||
initaudio();
|
||||
break;
|
||||
case '2':
|
||||
scale = 2;
|
||||
break;
|
||||
|
@ -152,17 +162,39 @@ threadmain(int argc, char **argv)
|
|||
screeninit();
|
||||
cpureset();
|
||||
vdpmode();
|
||||
ymreset();
|
||||
for(;;){
|
||||
if(paused != 0){
|
||||
qlock(&pauselock);
|
||||
qunlock(&pauselock);
|
||||
}
|
||||
if(dma != 1)
|
||||
step();
|
||||
if(dma != 0)
|
||||
if(dma != 1){
|
||||
t = step() * CPUDIV;
|
||||
if(dma != 0)
|
||||
dmastep();
|
||||
}else{
|
||||
t = CPUDIV;
|
||||
dmastep();
|
||||
z80step();
|
||||
vdpstep();
|
||||
}
|
||||
z80clock -= t;
|
||||
vdpclock -= t;
|
||||
audioclock += t;
|
||||
ymclock += t;
|
||||
|
||||
while(vdpclock < 0){
|
||||
vdpstep();
|
||||
vdpclock += 8;
|
||||
}
|
||||
while(z80clock < 0)
|
||||
z80clock += z80step() * Z80DIV;
|
||||
while(audioclock >= SAMPDIV){
|
||||
audiosample();
|
||||
audioclock -= SAMPDIV;
|
||||
}
|
||||
while(ymclock >= YMDIV){
|
||||
ymstep();
|
||||
ymclock -= YMDIV;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -174,7 +206,8 @@ flush(void)
|
|||
Rectangle r;
|
||||
uchar *s;
|
||||
int w;
|
||||
|
||||
static vlong old, delta;
|
||||
vlong new, diff;
|
||||
|
||||
if(nbrecvul(mc->resizec) > 0){
|
||||
if(getwindow(display, Refnone) < 0)
|
||||
|
@ -199,4 +232,18 @@ flush(void)
|
|||
}
|
||||
}
|
||||
flushimage(display, 1);
|
||||
if(audioout() < 0){
|
||||
new = nsec();
|
||||
diff = 0;
|
||||
if(old != 0){
|
||||
diff = BILLION/60 - (new - old) - delta;
|
||||
if(diff >= MILLION)
|
||||
sleep(diff/MILLION);
|
||||
}
|
||||
old = nsec();
|
||||
if(diff != 0){
|
||||
diff = (old - new) - (diff / MILLION) * MILLION;
|
||||
delta += (diff - delta) / 100;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -15,6 +15,8 @@ u8int dma;
|
|||
u8int vdplatch;
|
||||
u16int vdpaddr, vdpdata;
|
||||
|
||||
u8int yma1, yma2;
|
||||
|
||||
u8int z80bus = RESET;
|
||||
u16int z80bank;
|
||||
|
||||
|
@ -38,7 +40,8 @@ regread(u16int a)
|
|||
return ctl[1] & 0xc0 | 0x3f;
|
||||
case 0x0009: case 0x000b: case 0x000d:
|
||||
return ctl[a-3>>1];
|
||||
case 0x1101: return (~z80bus & BUSACK) << 7;
|
||||
case 0x1101:
|
||||
return (~z80bus & BUSACK) >> 1;
|
||||
}
|
||||
sysfatal("read from 0xa1%.4ux (pc=%#.6ux)", a, curpc);
|
||||
return 0;
|
||||
|
@ -53,10 +56,10 @@ regwrite(u16int a, u16int v)
|
|||
ctl[a-3>>1] = v;
|
||||
return;
|
||||
case 0x1101:
|
||||
z80bus = z80bus & ~BUSREQ | v >> 8 & BUSREQ;
|
||||
z80bus = z80bus & ~BUSREQ | v & BUSREQ;
|
||||
return;
|
||||
case 0x1201:
|
||||
if((v & 1<<8) == 0){
|
||||
if((v & 1) == 0){
|
||||
z80bus |= RESET;
|
||||
z80bus &= ~BUSACK;
|
||||
}else
|
||||
|
@ -187,7 +190,7 @@ memwrite(u32int a, u16int v, u16int m)
|
|||
switch(a >> 16 & 0xff){
|
||||
case 0xa0:
|
||||
if((z80bus & BUSACK) != 0)
|
||||
z80write(a & 0x7fff, v >> 8);
|
||||
z80write(a & 0xffff, v >> 8);
|
||||
return;
|
||||
case 0xa1:
|
||||
regwrite(a, v >> 8);
|
||||
|
@ -318,15 +321,27 @@ dmastep(void)
|
|||
u8int
|
||||
z80read(u16int a)
|
||||
{
|
||||
u16int v;
|
||||
|
||||
switch(a >> 13){
|
||||
case 0:
|
||||
case 1:
|
||||
return zram[a & 0x1fff];
|
||||
case 2:
|
||||
return 0;
|
||||
case 3:
|
||||
sysfatal("z80 read from %#.4x\n", a);
|
||||
if(a >= 0x7f00){
|
||||
v = memread(0xc00000 | a & 0x7e);
|
||||
if((a & 1) == 0)
|
||||
v >>= 8;
|
||||
return v;
|
||||
}
|
||||
sysfatal("z80 read from %#.4x (pc=%#.4x)", a, scurpc);
|
||||
default:
|
||||
return memread(z80bank << 15 | a & 0x7fff);
|
||||
v = memread(z80bank << 15 | a & 0x7ffe);
|
||||
if((a & 1) == 0)
|
||||
v >>= 8;
|
||||
return v;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -339,13 +354,38 @@ z80write(u16int a, u8int v)
|
|||
zram[a & 0x1fff] = v;
|
||||
return;
|
||||
case 2:
|
||||
switch(a & 3){
|
||||
case 0: yma1 = v; return;
|
||||
case 1: ymwrite(yma1, v, 0); return;
|
||||
case 2: yma2 = v; return;
|
||||
case 3: ymwrite(yma2, v, 3); return;
|
||||
}
|
||||
case 3:
|
||||
sysfatal("z80 write to %#.4x\n", a);
|
||||
if(a < 0x6100){
|
||||
z80bank = z80bank >> 1 | v << 8 & 0x100;
|
||||
return;
|
||||
}
|
||||
if(a >= 0x7f00){
|
||||
memwrite(0xc00000 | a & 0x7e, v | v << 8, (a & 1) != 0 ? 0xff : 0xff00);
|
||||
return;
|
||||
}
|
||||
sysfatal("z80 write to %#.4x (pc=%#.4x)", a, scurpc);
|
||||
default:
|
||||
memwrite(z80bank << 15 | a & 0x7ffe, v << 8 | v, (a & 1) != 0 ? 0xff : 0xff00);
|
||||
}
|
||||
}
|
||||
|
||||
u8int
|
||||
z80in(u8int)
|
||||
{
|
||||
return 0xff;
|
||||
}
|
||||
|
||||
void
|
||||
z80out(u8int, u8int)
|
||||
{
|
||||
}
|
||||
|
||||
u32int irql[8] = {[6] INTVBL, [4] INTHOR};
|
||||
|
||||
int
|
||||
|
|
|
@ -8,6 +8,7 @@ OFILES=\
|
|||
md.$O\
|
||||
vdp.$O\
|
||||
z80.$O\
|
||||
ym.$O\
|
||||
|
||||
HFILES=dat.h fns.h
|
||||
|
||||
|
|
|
@ -310,6 +310,7 @@ vdpstep(void)
|
|||
}else
|
||||
pixeldraw(vdpx, vdpy, 0xcccccc);
|
||||
if(++vdpx >= xmax){
|
||||
z80irq = 0;
|
||||
vdpx = 0;
|
||||
if(++vdpy >= ymax){
|
||||
vdpy = 0;
|
||||
|
@ -328,6 +329,7 @@ vdpstep(void)
|
|||
}
|
||||
if(vdpy == yvbl){
|
||||
vdpstat |= STATVBL | STATINT;
|
||||
z80irq = 1;
|
||||
if((reg[MODE2] & IE0) != 0)
|
||||
irq |= INTVBL;
|
||||
}
|
||||
|
|
420
sys/src/games/md/ym.c
Normal file
420
sys/src/games/md/ym.c
Normal file
|
@ -0,0 +1,420 @@
|
|||
#include <u.h>
|
||||
#include <libc.h>
|
||||
#include <thread.h>
|
||||
#include "dat.h"
|
||||
#include "fns.h"
|
||||
|
||||
extern int debug;
|
||||
|
||||
u8int ym[512];
|
||||
enum {
|
||||
MODE = 0x27,
|
||||
FDIV = 1048576 * 2 * 144,
|
||||
};
|
||||
|
||||
#define min(a, b) ((a)<=(b)?(a):(b))
|
||||
|
||||
typedef struct oper oper;
|
||||
typedef struct fm fm;
|
||||
|
||||
struct oper {
|
||||
enum {OFF, ATTACK, DECAY, SUSTAIN, RELEASE} st;
|
||||
u8int *r;
|
||||
int env;
|
||||
u8int ar, sr, dr, rs, rr, mult;
|
||||
u16int tl, sl;
|
||||
u8int keyon, keyoff, rate;
|
||||
int det;
|
||||
u8int kc;
|
||||
u32int phi, amp, dp;
|
||||
int val, val0;
|
||||
};
|
||||
|
||||
struct fm {
|
||||
oper op[4];
|
||||
u8int st, alg, en, fbs;
|
||||
float samp;
|
||||
} fms[6];
|
||||
static u32int cyc;
|
||||
|
||||
static short sbuf[2 * 2000], *sbufp;
|
||||
static int fd;
|
||||
static int sint[256], expt[256];
|
||||
|
||||
static void
|
||||
calcfreq(int n)
|
||||
{
|
||||
int i, fr;
|
||||
fm *f;
|
||||
oper *p;
|
||||
uchar *r;
|
||||
static u8int det[4][32] = {
|
||||
{0},
|
||||
{0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2,
|
||||
2, 3, 3, 3, 4, 4, 4, 5, 5, 6, 6, 7, 8, 8, 8, 8},
|
||||
{1, 1, 1, 1, 2, 2, 2, 2, 2, 3, 3, 3, 4, 4, 4, 5,
|
||||
5, 6, 6, 7, 8, 8, 9,10,11,12,13,14,16,16,16,16},
|
||||
{2, 2, 2, 2, 2, 3, 3, 3, 4, 4, 4, 5, 5, 6, 6, 7,
|
||||
8, 8, 9,10,11,12,13,14,16,17,19,20,22,22,22,22}
|
||||
};
|
||||
|
||||
r = ym;
|
||||
f = &fms[n];
|
||||
if(n >= 3){
|
||||
n -= 3;
|
||||
r += 0x100;
|
||||
}
|
||||
fr = r[0xa0 + n] | r[0xa4 + n] << 8 & 0x3f00;
|
||||
for(i = 0; i < 3; i++){
|
||||
p = &f->op[i];
|
||||
if(n == 2 && (ym[MODE] & 0xc0) == 0x40 && i != 0)
|
||||
fr = r[0xa7+i] | r[0xab+i] << 8 & 0x3f00;
|
||||
p->kc = fr >> 9 & 0x1e;
|
||||
if((fr & 0x780) >= 0x380 && (fr & 0x780) != 0x400)
|
||||
p->kc |= 1;
|
||||
p->dp = ((fr & 0x7ff) << (fr >> 11)) >> 1;
|
||||
if((p->det & 4) != 0)
|
||||
p->dp -= det[p->det & 3][p->kc];
|
||||
else
|
||||
p->dp += det[p->det][p->kc];
|
||||
if(p->mult != 0)
|
||||
p->dp = (p->dp & 0x1ffff) * p->mult;
|
||||
else
|
||||
p->dp = (u16int)(p->dp >> 1);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
ymwrite(u8int a, u8int v, u8int c)
|
||||
{
|
||||
int ch, i;
|
||||
oper *p;
|
||||
fm *f;
|
||||
|
||||
ym[c ? a|0x100 : a] = v;
|
||||
if(a >= 0x30 && a < 0xa0){
|
||||
ch = a & 3;
|
||||
if(ch == 3)
|
||||
return;
|
||||
ch += c;
|
||||
f = &fms[ch];
|
||||
i = a >> 3 & 1 | a >> 1 & 2;
|
||||
p = &f->op[i];
|
||||
switch(a & 0xf0){
|
||||
case 0x30:
|
||||
p->mult = v & 0x0f;
|
||||
p->det = v >> 4 & 7;
|
||||
calcfreq(ch);
|
||||
break;
|
||||
case 0x40:
|
||||
p->tl = v << 3 & 0x3f8;
|
||||
break;
|
||||
case 0x50:
|
||||
p->ar = v << 1 & 0x3e;
|
||||
p->rs = 3 - (v >> 6);
|
||||
break;
|
||||
case 0x60:
|
||||
p->dr = v << 1 & 0x3e;
|
||||
break;
|
||||
case 0x70:
|
||||
p->sr = v << 1 & 0x3e;
|
||||
break;
|
||||
case 0x80:
|
||||
p->sl = v << 2 & 0x3c0;
|
||||
p->rr = v << 2 & 0x3c | 0x02;
|
||||
break;
|
||||
};
|
||||
}else{
|
||||
ch = c + (a & 3);
|
||||
switch(a){
|
||||
case MODE:
|
||||
calcfreq(2);
|
||||
calcfreq(5);
|
||||
break;
|
||||
case 0x28:
|
||||
ch = v & 3;
|
||||
if(ch == 3)
|
||||
break;
|
||||
if((v & 4) != 0)
|
||||
ch += 3;
|
||||
f = &fms[ch];
|
||||
for(i = 0; i < 4; i++){
|
||||
p = &f->op[i];
|
||||
if((v & 1<<4+i) != 0){
|
||||
if(p->st == OFF || p->st == RELEASE)
|
||||
p->keyon++;
|
||||
}else
|
||||
if(p->st != OFF)
|
||||
p->keyoff++;
|
||||
}
|
||||
break;
|
||||
case 0xa0: case 0xa1: case 0xa2:
|
||||
case 0xa4: case 0xa5: case 0xa6:
|
||||
calcfreq(ch);
|
||||
break;
|
||||
case 0xa8: case 0xa9: case 0xaa:
|
||||
case 0xac: case 0xad: case 0xae:
|
||||
calcfreq((a & 0x100) != 0 ? 5 : 2);
|
||||
break;
|
||||
case 0xb0: case 0xb1: case 0xb2:
|
||||
fms[ch].alg = v & 7;
|
||||
fms[ch].fbs = 7 - (v >> 3 & 7);
|
||||
break;
|
||||
case 0xb4: case 0xb5: case 0xb6:
|
||||
fms[ch].en = v;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
tables(void)
|
||||
{
|
||||
int i;
|
||||
double x;
|
||||
|
||||
for(i = 0; i < 256; i++){
|
||||
x = sin(((i << 1) + 1) * PI / 1024);
|
||||
x = -log(x)/log(2);
|
||||
sint[i] = x * 256 + 0.5;
|
||||
}
|
||||
for(i = 0; i < 256; i++){
|
||||
x = pow(2, -(i+1)/256.0);
|
||||
expt[i] = x * 2048 + 0.5;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
ymreset(void)
|
||||
{
|
||||
int i, j;
|
||||
|
||||
for(i = 0; i < 6; i++){
|
||||
fms[i].en = 0xc0;
|
||||
for(j = 0; j < 4; j++)
|
||||
fms[i].op[j].rs = 3;
|
||||
}
|
||||
tables();
|
||||
}
|
||||
|
||||
static u8int
|
||||
rate(oper *p, u8int r)
|
||||
{
|
||||
if(r == 0)
|
||||
return 0;
|
||||
r += p->kc >> p->rs;
|
||||
if(r > 63)
|
||||
return 63;
|
||||
return r;
|
||||
}
|
||||
|
||||
static void
|
||||
env(oper *p)
|
||||
{
|
||||
int v, sh, ai;
|
||||
static u8int ait[64][8] = {
|
||||
{0,0,0,0,0,0,0,0}, {0,0,0,0,0,0,0,0}, {0,1,0,1,0,1,0,1}, {0,1,0,1,0,1,0,1},
|
||||
{0,1,0,1,0,1,0,1}, {0,1,0,1,0,1,0,1}, {0,1,1,1,0,1,1,1}, {0,1,1,1,0,1,1,1},
|
||||
{0,1,0,1,0,1,0,1}, {0,1,0,1,1,1,0,1}, {0,1,1,1,0,1,1,1}, {0,1,1,1,1,1,1,1},
|
||||
{0,1,0,1,0,1,0,1}, {0,1,0,1,1,1,0,1}, {0,1,1,1,0,1,1,1}, {0,1,1,1,1,1,1,1},
|
||||
{0,1,0,1,0,1,0,1}, {0,1,0,1,1,1,0,1}, {0,1,1,1,0,1,1,1}, {0,1,1,1,1,1,1,1},
|
||||
{0,1,0,1,0,1,0,1}, {0,1,0,1,1,1,0,1}, {0,1,1,1,0,1,1,1}, {0,1,1,1,1,1,1,1},
|
||||
{0,1,0,1,0,1,0,1}, {0,1,0,1,1,1,0,1}, {0,1,1,1,0,1,1,1}, {0,1,1,1,1,1,1,1},
|
||||
{0,1,0,1,0,1,0,1}, {0,1,0,1,1,1,0,1}, {0,1,1,1,0,1,1,1}, {0,1,1,1,1,1,1,1},
|
||||
{0,1,0,1,0,1,0,1}, {0,1,0,1,1,1,0,1}, {0,1,1,1,0,1,1,1}, {0,1,1,1,1,1,1,1},
|
||||
{0,1,0,1,0,1,0,1}, {0,1,0,1,1,1,0,1}, {0,1,1,1,0,1,1,1}, {0,1,1,1,1,1,1,1},
|
||||
{0,1,0,1,0,1,0,1}, {0,1,0,1,1,1,0,1}, {0,1,1,1,0,1,1,1}, {0,1,1,1,1,1,1,1},
|
||||
{0,1,0,1,0,1,0,1}, {0,1,0,1,1,1,0,1}, {0,1,1,1,0,1,1,1}, {0,1,1,1,1,1,1,1},
|
||||
{1,1,1,1,1,1,1,1}, {1,1,1,2,1,1,1,2}, {1,2,1,2,1,2,1,2}, {1,2,2,2,1,2,2,2},
|
||||
{2,2,2,2,2,2,2,2}, {2,2,2,4,2,2,2,4}, {2,4,2,4,2,4,2,4}, {2,4,4,4,2,4,4,4},
|
||||
{4,4,4,4,4,4,4,4}, {4,4,4,8,4,4,4,8}, {4,8,4,8,4,8,4,8}, {4,8,8,8,4,8,8,8},
|
||||
{8,8,8,8,8,8,8,8}, {8,8,8,8,8,8,8,8}, {8,8,8,8,8,8,8,8}, {8,8,8,8,8,8,8,8},
|
||||
};
|
||||
if(p->keyon > 0){
|
||||
p->st = ATTACK;
|
||||
p->rate = rate(p, p->ar);
|
||||
p->env = 0;
|
||||
p->keyon = 0;
|
||||
}else if(p->keyoff > 0){
|
||||
p->st = RELEASE;
|
||||
p->rate = rate(p, p->rr);
|
||||
p->keyoff = 0;
|
||||
}
|
||||
if(p->rate > 0){
|
||||
sh = p->rate >> 2;
|
||||
if(sh < 11)
|
||||
sh = 11 - sh;
|
||||
else
|
||||
sh = 0;
|
||||
if((cyc & (1 << sh) - 1) == 0){
|
||||
ai = ait[p->rate][(cyc >> sh) & 7];
|
||||
switch(p->st){
|
||||
case ATTACK:
|
||||
p->env += ai * ((1024 - p->env >> 4) + 1);
|
||||
if(p->env >= 1024){
|
||||
p->env = 0;
|
||||
p->st = DECAY;
|
||||
p->rate = rate(p, p->dr);
|
||||
}
|
||||
break;
|
||||
case DECAY:
|
||||
p->env += ai;
|
||||
if(p->env >= 1024)
|
||||
p->env = 1023;
|
||||
if(p->env >= p->sl){
|
||||
p->st = SUSTAIN;
|
||||
p->rate = rate(p, p->sr);
|
||||
}
|
||||
break;
|
||||
case SUSTAIN:
|
||||
case RELEASE:
|
||||
p->env += ai;
|
||||
if(p->env >= 1024){
|
||||
p->env = 1023;
|
||||
p->st = OFF;
|
||||
p->rate = 0;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if(p->st == OFF){
|
||||
p->amp = 1023;
|
||||
return;
|
||||
}
|
||||
v = p->env;
|
||||
if(p->st == ATTACK)
|
||||
v ^= 1023;
|
||||
v += p->tl;
|
||||
if(v > 1023)
|
||||
p->amp = 1023;
|
||||
else
|
||||
p->amp = v;
|
||||
}
|
||||
|
||||
static void
|
||||
opr(oper *p, int inp)
|
||||
{
|
||||
int v, x, r;
|
||||
|
||||
p->phi += p->dp;
|
||||
v = (p->phi >> 10) + inp;
|
||||
if((v & 0x100) != 0)
|
||||
v ^= 0xff;
|
||||
x = sint[v & 0xff] + (p->amp << 2);
|
||||
r = expt[x & 0xff] << 2 >> (x >> 8);
|
||||
p->val0 = p->val;
|
||||
if((v & 0x200) != 0)
|
||||
p->val = -r;
|
||||
else
|
||||
p->val = r;
|
||||
}
|
||||
|
||||
void
|
||||
ymstep(void)
|
||||
{
|
||||
static int ymch, ymop, ymcyc;
|
||||
fm *f;
|
||||
oper *p;
|
||||
int x;
|
||||
|
||||
f = fms + ymch;
|
||||
p = f->op + ymop;
|
||||
x = 0;
|
||||
if(ymop == 0){
|
||||
if(f->fbs != 7)
|
||||
x = p->val + p->val0 >> f->fbs + 2;
|
||||
}else{
|
||||
switch(f->alg << 4 | ymop){
|
||||
default: x = p[-1].val; break;
|
||||
case 0x11: break;
|
||||
case 0x12: x = f->op[0].val + f->op[1].val; break;
|
||||
case 0x21: break;
|
||||
case 0x23: x = f->op[0].val + f->op[2].val; break;
|
||||
case 0x32: break;
|
||||
case 0x33: x = f->op[1].val + f->op[2].val; break;
|
||||
case 0x42: break;
|
||||
case 0x52: case 0x53: x = f->op[0].val; break;
|
||||
case 0x62: case 0x63: break;
|
||||
case 0x71: case 0x72: case 0x73: break;
|
||||
}
|
||||
x >>= 1;
|
||||
}
|
||||
if(ymcyc == 0)
|
||||
env(p);
|
||||
opr(p, x);
|
||||
if(ymop == 3){
|
||||
switch(f->alg){
|
||||
default: x = p->val >> 5; break;
|
||||
case 4: x = (f->op[1].val >> 5) + (p->val >> 5); break;
|
||||
case 5: case 6: x = (f->op[1].val >> 5) + (f->op[2].val >> 5) + (p->val >> 5); break;
|
||||
case 7: x = (f->op[0].val >> 5) + (f->op[1].val >> 5) + (f->op[2].val >> 5) + (p->val >> 5); break;
|
||||
}
|
||||
if(x > 256) x = 256;
|
||||
if(x < -256) x = -256;
|
||||
f->samp = x / 256.0;
|
||||
if(++ymch == 6){
|
||||
ymch = 0;
|
||||
if(++ymcyc == 3){
|
||||
cyc++;
|
||||
ymcyc = 0;
|
||||
}
|
||||
}
|
||||
ymop = 0;
|
||||
}else
|
||||
ymop++;
|
||||
}
|
||||
|
||||
void
|
||||
audiosample(void)
|
||||
{
|
||||
int i;
|
||||
u8int x;
|
||||
float v, vl, vr;
|
||||
|
||||
if(sbufp == nil)
|
||||
return;
|
||||
vl = vr = 0;
|
||||
for(i = 0; i < 6; i++){
|
||||
if(i == 5 && (ym[0x2b] & 0x80) != 0)
|
||||
v = ym[0x2a] / 255.0;
|
||||
else
|
||||
v = fms[i].samp;
|
||||
x = fms[i].en;
|
||||
if((x & 0x80) != 0)
|
||||
vl += v;
|
||||
if((x & 0x40) != 0)
|
||||
vr += v;
|
||||
}
|
||||
if(sbufp < sbuf + nelem(sbuf) - 1){
|
||||
*sbufp++ = vl * 5000;
|
||||
*sbufp++ = vr * 5000;
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
audioout(void)
|
||||
{
|
||||
int rc;
|
||||
|
||||
if(sbufp == nil)
|
||||
return -1;
|
||||
if(sbufp == sbuf)
|
||||
return 0;
|
||||
rc = write(fd, sbuf, (sbufp - sbuf) * 2);
|
||||
if(rc > 0)
|
||||
sbufp -= (rc+1)/2;
|
||||
if(sbufp < sbuf)
|
||||
sbufp = sbuf;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
initaudio(void)
|
||||
{
|
||||
fd = open("/dev/audio", OWRITE);
|
||||
if(fd < 0)
|
||||
return;
|
||||
sbufp = sbuf;
|
||||
}
|
|
@ -4,10 +4,593 @@
|
|||
#include "dat.h"
|
||||
#include "fns.h"
|
||||
|
||||
u8int s[16], ipage, intm, z80irq;
|
||||
u16int ix[2];
|
||||
u16int spc, scurpc, sp;
|
||||
int halt;
|
||||
|
||||
enum {
|
||||
FLAGC = 0x01,
|
||||
FLAGN = 0x02,
|
||||
FLAGV = 0x04,
|
||||
FLAGH = 0x10,
|
||||
FLAGZ = 0x40,
|
||||
FLAGS = 0x80
|
||||
};
|
||||
enum { rB, rC, rD, rE, rH, rL, rHL, rA, rF = rHL };
|
||||
#define BC() (s[rB] << 8 | s[rC])
|
||||
#define DE() (s[rD] << 8 | s[rE])
|
||||
#define HL() (s[rH] << 8 | s[rL])
|
||||
|
||||
static u8int
|
||||
fetch8(void)
|
||||
{
|
||||
return z80read(spc++);
|
||||
}
|
||||
|
||||
static u16int
|
||||
fetch16(void)
|
||||
{
|
||||
u16int u;
|
||||
|
||||
u = z80read(spc++);
|
||||
return u | z80read(spc++) << 8;
|
||||
}
|
||||
|
||||
static void
|
||||
push8(u8int u)
|
||||
{
|
||||
z80write(--sp, u);
|
||||
}
|
||||
|
||||
static void
|
||||
push16(u16int u)
|
||||
{
|
||||
z80write(--sp, u >> 8);
|
||||
z80write(--sp, u);
|
||||
}
|
||||
|
||||
static u8int
|
||||
pop8(void)
|
||||
{
|
||||
return z80read(sp++);
|
||||
}
|
||||
|
||||
static u16int
|
||||
pop16(void)
|
||||
{
|
||||
u16int v;
|
||||
|
||||
v = z80read(sp++);
|
||||
return v | z80read(sp++) << 8;
|
||||
}
|
||||
|
||||
static u16int
|
||||
read16(u16int n)
|
||||
{
|
||||
return z80read(n) | z80read(n+1) << 8;
|
||||
}
|
||||
|
||||
static void
|
||||
write16(u16int n, u16int v)
|
||||
{
|
||||
z80write(n++, v);
|
||||
z80write(n, v >> 8);
|
||||
}
|
||||
|
||||
static int
|
||||
parity(u8int v)
|
||||
{
|
||||
return (((v * 0x0101010101010101ULL) & 0x8040201008040201ULL) % 0x1FF) & 1;
|
||||
}
|
||||
|
||||
static int
|
||||
move(u8int dst, u8int src)
|
||||
{
|
||||
if(dst == rHL){
|
||||
if(src == rHL){
|
||||
halt = 1;
|
||||
return 4;
|
||||
}
|
||||
z80write(HL(), s[src]);
|
||||
return 7;
|
||||
}
|
||||
if(src == rHL){
|
||||
s[dst] = z80read(HL());
|
||||
return 7;
|
||||
}
|
||||
s[dst] = s[src];
|
||||
return 4;
|
||||
}
|
||||
|
||||
static int
|
||||
alu(u8int op, u8int n)
|
||||
{
|
||||
u8int v4;
|
||||
u8int u;
|
||||
u16int v;
|
||||
int t;
|
||||
|
||||
switch(n){
|
||||
case 8: u = fetch8(); t = 3; break;
|
||||
case 10: u = ix[0]; t = 4; break;
|
||||
case 11: u = ix[1]; t = 4; break;
|
||||
case 12: u = ix[0] >> 8; t = 4; break;
|
||||
case 13: u = ix[1] >> 8; t = 4; break;
|
||||
case 14: u = z80read(ix[0] + fetch8()); t = 15; break;
|
||||
case 15: u = z80read(ix[1] + fetch8()); t = 15; break;
|
||||
case rHL:
|
||||
u = z80read(HL());
|
||||
t = 3;
|
||||
break;
|
||||
default:
|
||||
u = s[n];
|
||||
t = 0;
|
||||
}
|
||||
v4 = 0;
|
||||
switch(op){
|
||||
default:
|
||||
v4 = (s[rA] & 0x0f) + (u & 0x0f);
|
||||
v = s[rA] + u;
|
||||
break;
|
||||
case 1:
|
||||
v4 = (s[rA] & 0x0f) + (u & 0x0f) + (s[rF] & 1);
|
||||
v = s[rA] + u + (s[rF] & 1);
|
||||
break;
|
||||
case 2:
|
||||
case 7:
|
||||
v4 = (s[rA] & 0x0f) + (~u & 0x0f) + 1;
|
||||
v = s[rA] + (u ^ 0xff) + 1;
|
||||
break;
|
||||
case 3:
|
||||
v4 = (s[rA] & 0x0f) + (~u & 0x0f) + (~s[rF] & 1);
|
||||
v = s[rA] + (u ^ 0xff) + (~s[rF] & 1);
|
||||
break;
|
||||
case 4: v = s[rA] & u; break;
|
||||
case 5: v = s[rA] ^ u; break;
|
||||
case 6: v = s[rA] | u; break;
|
||||
}
|
||||
s[rF] = 0;
|
||||
if((u8int)v == 0)
|
||||
s[rF] |= FLAGZ;
|
||||
if((v & 0x80) != 0)
|
||||
s[rF] |= FLAGS;
|
||||
if(op < 2){
|
||||
if((v & 0x100) != 0)
|
||||
s[rF] |= FLAGC;
|
||||
if((v4 & 0x10) != 0)
|
||||
s[rF] |= FLAGH;
|
||||
if((~(s[rA] ^ u) & (s[rA] ^ v) & 0x80) != 0)
|
||||
s[rF] |= FLAGV;
|
||||
}else if(op < 4 || op == 7){
|
||||
s[rF] |= FLAGN;
|
||||
if((v & 0x100) == 0)
|
||||
s[rF] |= FLAGC;
|
||||
if((v4 & 0x10) == 0)
|
||||
s[rF] |= FLAGH;
|
||||
if(((s[rA] ^ u) & (s[rA] ^ v) & 0x80) != 0)
|
||||
s[rF] |= FLAGV;
|
||||
}else{
|
||||
if(!parity(v))
|
||||
s[rF] |= FLAGV;
|
||||
if(op == 4)
|
||||
s[rF] |= FLAGH;
|
||||
}
|
||||
if(op != 7)
|
||||
s[rA] = v;
|
||||
return 4+t;
|
||||
}
|
||||
|
||||
static int
|
||||
branch(int cc, int t)
|
||||
{
|
||||
u16int v;
|
||||
|
||||
v = (s8int)fetch8();
|
||||
if(!cc)
|
||||
return t + 7;
|
||||
spc += v;
|
||||
return t + 12;
|
||||
}
|
||||
|
||||
static u8int
|
||||
inc(u8int v)
|
||||
{
|
||||
s[rF] &= FLAGC;
|
||||
++v;
|
||||
if(v == 0)
|
||||
s[rF] |= FLAGZ;
|
||||
if((v & 0x80) != 0)
|
||||
s[rF] |= FLAGS;
|
||||
if(v == 0x80)
|
||||
s[rF] |= FLAGV;
|
||||
if((v & 0xf) == 0)
|
||||
s[rF] |= FLAGH;
|
||||
return v;
|
||||
}
|
||||
|
||||
static u8int
|
||||
dec(u8int v)
|
||||
{
|
||||
--v;
|
||||
s[rF] = s[rF] & FLAGC | FLAGN;
|
||||
if(v == 0)
|
||||
s[rF] |= FLAGZ;
|
||||
if((v & 0x80) != 0)
|
||||
s[rF] |= FLAGS;
|
||||
if(v == 0x7f)
|
||||
s[rF] |= FLAGV;
|
||||
if((v & 0xf) == 0xf)
|
||||
s[rF] |= FLAGH;
|
||||
return v;
|
||||
}
|
||||
|
||||
static int
|
||||
addhl(u16int u)
|
||||
{
|
||||
u32int v;
|
||||
|
||||
s[rF] &= ~(FLAGN|FLAGC|FLAGH);
|
||||
v = HL() + u;
|
||||
if((v & 0x10000) != 0)
|
||||
s[rF] |= FLAGC;
|
||||
if((HL() & 0xfff) + (u & 0xfff) >= 0x1000)
|
||||
s[rF] |= FLAGH;
|
||||
s[rL] = v;
|
||||
s[rH] = v >> 8;
|
||||
return 11;
|
||||
}
|
||||
|
||||
static void
|
||||
adchl(u16int u)
|
||||
{
|
||||
u32int v, v4;
|
||||
|
||||
v = HL() + u + (s[rF] & FLAGC);
|
||||
v4 = (HL() & 0xfff) + (u & 0xfff) + (s[rF] & FLAGC);
|
||||
s[rF] = 0;
|
||||
if((v & 0x10000) != 0)
|
||||
s[rF] |= FLAGC;
|
||||
if((v4 & 0x1000) != 0)
|
||||
s[rF] |= FLAGH;
|
||||
if((u16int)v == 0)
|
||||
s[rF] |= FLAGZ;
|
||||
if((v & 0x8000) != 0)
|
||||
s[rF] |= FLAGS;
|
||||
if((~(HL() ^ u) & (HL() ^ v) & 0x8000) != 0)
|
||||
s[rF] |= FLAGV;
|
||||
s[rL] = v;
|
||||
s[rH] = v >> 8;
|
||||
}
|
||||
|
||||
static void
|
||||
sbchl(u16int u)
|
||||
{
|
||||
u32int v, v4;
|
||||
|
||||
v = HL() + (u16int)~u + (~s[rF] & FLAGC);
|
||||
v4 = (HL() & 0xfff) + (~u & 0xfff) + (~s[rF] & FLAGC);
|
||||
s[rF] = FLAGN;
|
||||
if((v & 0x10000) == 0)
|
||||
s[rF] |= FLAGC;
|
||||
if((v4 & 0x1000) == 0)
|
||||
s[rF] |= FLAGH;
|
||||
if((u16int)v == 0)
|
||||
s[rF] |= FLAGZ;
|
||||
if((v & 0x8000) != 0)
|
||||
s[rF] |= FLAGS;
|
||||
if(((HL() ^ u) & (HL() ^ v) & 0x8000) != 0)
|
||||
s[rF] |= FLAGV;
|
||||
s[rL] = v;
|
||||
s[rH] = v >> 8;
|
||||
}
|
||||
|
||||
static int
|
||||
addindex(int n, u16int u)
|
||||
{
|
||||
u32int v;
|
||||
|
||||
s[rF] &= ~(FLAGN|FLAGC|FLAGH);
|
||||
v = ix[n] + u;
|
||||
if((v & 0x10000) != 0)
|
||||
s[rF] |= FLAGC;
|
||||
if((ix[n] & 0xfff) + (u & 0xfff) >= 0x1000)
|
||||
s[rF] |= FLAGH;
|
||||
ix[n] = v;
|
||||
return 15;
|
||||
}
|
||||
|
||||
static int
|
||||
jump(int cc)
|
||||
{
|
||||
u16int v;
|
||||
|
||||
v = fetch16();
|
||||
if(cc)
|
||||
spc = v;
|
||||
return 10;
|
||||
}
|
||||
|
||||
static int
|
||||
call(u16int a, int cc)
|
||||
{
|
||||
if(!cc)
|
||||
return 10;
|
||||
push16(spc);
|
||||
spc = a;
|
||||
return 17;
|
||||
}
|
||||
|
||||
static void
|
||||
swap(u8int a)
|
||||
{
|
||||
u8int v;
|
||||
|
||||
v = s[a];
|
||||
s[a] = s[a + 8];
|
||||
s[a + 8] = v;
|
||||
}
|
||||
|
||||
static int
|
||||
bits(int i)
|
||||
{
|
||||
u8int op, v, n, m, c;
|
||||
u16int a;
|
||||
int t;
|
||||
|
||||
SET(a, v, t);
|
||||
if(i >= 0){
|
||||
a = ix[i] + fetch8();
|
||||
v = z80read(a);
|
||||
t = 23;
|
||||
}
|
||||
op = fetch8();
|
||||
n = op & 7;
|
||||
m = op >> 3 & 7;
|
||||
if(i < 0){
|
||||
a = HL();
|
||||
if(n == 6){
|
||||
v = z80read(a);
|
||||
t = 15;
|
||||
}else{
|
||||
v = s[n];
|
||||
t = 8;
|
||||
}
|
||||
}
|
||||
switch(op >> 6){
|
||||
case 0:
|
||||
c = s[rF] & FLAGC;
|
||||
switch(m){
|
||||
default: s[rF] = v >> 7; v = v << 1 | v >> 7; break;
|
||||
case 1: s[rF] = v & 1; v = v >> 1 | v << 7; break;
|
||||
case 2: s[rF] = v >> 7; v = v << 1 | c; break;
|
||||
case 3: s[rF] = v & 1; v = v >> 1 | c << 7; break;
|
||||
case 4: s[rF] = v >> 7; v = v << 1; break;
|
||||
case 5: s[rF] = v & 1; v = v & 0x80 | v >> 1; break;
|
||||
case 6: s[rF] = v >> 7; v = v << 1 | 1; break;
|
||||
case 7: s[rF] = v & 1; v >>= 1; break;
|
||||
}
|
||||
if(v == 0)
|
||||
s[rF] |= FLAGZ;
|
||||
if((v & 0x80) != 0)
|
||||
s[rF] |= FLAGS;
|
||||
if(!parity(v))
|
||||
s[rF] |= FLAGV;
|
||||
break;
|
||||
case 1:
|
||||
s[rF] = s[rF] & ~(FLAGN|FLAGZ) | FLAGH;
|
||||
if((v & 1<<m) == 0)
|
||||
s[rF] |= FLAGZ;
|
||||
return t;
|
||||
case 2:
|
||||
v &= ~(1<<m);
|
||||
break;
|
||||
case 3:
|
||||
v |= (1<<m);
|
||||
}
|
||||
if(n == 6)
|
||||
z80write(a, v);
|
||||
else
|
||||
s[n] = v;
|
||||
return t;
|
||||
}
|
||||
|
||||
static int
|
||||
ed(void)
|
||||
{
|
||||
u8int op, v, u, l;
|
||||
u16int a;
|
||||
|
||||
op = fetch8();
|
||||
switch(op){
|
||||
case 0xa0: case 0xa1: case 0xa8: case 0xa9:
|
||||
case 0xb0: case 0xb1: case 0xb8: case 0xb9:
|
||||
switch(op & 3){
|
||||
default:
|
||||
z80write(DE(), z80read(HL()));
|
||||
s[rF] &= ~(FLAGN|FLAGH);
|
||||
l = 1;
|
||||
break;
|
||||
case 1:
|
||||
u = z80read(HL());
|
||||
v = s[rA] - u;
|
||||
s[rF] = s[rF] & ~(FLAGS|FLAGZ|FLAGH) | FLAGN;
|
||||
l = v != 0;
|
||||
if((v & 0x80) != 0)
|
||||
s[rF] |= FLAGS;
|
||||
if(v == 0)
|
||||
s[rF] |= FLAGZ;
|
||||
if((s[rA] & 0xf) < (u & 0xf))
|
||||
s[rF] |= FLAGH;
|
||||
break;
|
||||
}
|
||||
if((op & 8) != 0){
|
||||
if((op & 3) == 0 && s[rE]-- == 0)
|
||||
s[rD]--;
|
||||
if(s[rL]-- == 0)
|
||||
s[rH]--;
|
||||
}else{
|
||||
if((op & 3) == 0 && ++s[rE] == 0)
|
||||
s[rD]++;
|
||||
if(++s[rL] == 0)
|
||||
s[rH]++;
|
||||
}
|
||||
if(s[rC]-- == 0)
|
||||
s[rB]--;
|
||||
if((s[rC] | s[rB]) != 0){
|
||||
s[rF] |= FLAGV;
|
||||
if((op & 0x10) != 0 && l){
|
||||
spc -= 2;
|
||||
return 21;
|
||||
}
|
||||
}else
|
||||
s[rF] &= ~FLAGV;
|
||||
return 16;
|
||||
case 0x42: sbchl(BC()); return 15;
|
||||
case 0x52: sbchl(DE()); return 15;
|
||||
case 0x62: sbchl(HL()); return 15;
|
||||
case 0x72: sbchl(sp); return 15;
|
||||
case 0x43: write16(fetch16(), BC()); return 20;
|
||||
case 0x53: write16(fetch16(), DE()); return 20;
|
||||
case 0x63: write16(fetch16(), HL()); return 20;
|
||||
case 0x73: write16(fetch16(), sp); return 20;
|
||||
case 0x44:
|
||||
s[rA] = -s[rA];
|
||||
s[rF] = FLAGN;
|
||||
if(s[rA] == 0)
|
||||
s[rF] |= FLAGZ;
|
||||
else
|
||||
s[rF] |= FLAGC;
|
||||
if((s[rA] & 0x80) != 0)
|
||||
s[rF] |= FLAGS;
|
||||
if(s[rA] == 0x80)
|
||||
s[rF] |= FLAGV;
|
||||
if((s[rA] & 0xf) != 0)
|
||||
s[rF] |= FLAGH;
|
||||
return 8;
|
||||
case 0x46: intm &= 0xc0; return 8;
|
||||
case 0x56: intm = intm & 0xc0 | 1; return 8;
|
||||
case 0x47: ipage = s[rA]; return 9;
|
||||
case 0x57: s[rA] = ipage; return 9;
|
||||
case 0x67:
|
||||
v = z80read(HL());
|
||||
z80write(HL(), v >> 4 | s[rA] << 4);
|
||||
s[rA] = s[rA] & 0xf0 | v & 0x0f;
|
||||
if(0){
|
||||
case 0x6f:
|
||||
v = z80read(HL());
|
||||
z80write(HL(), v << 4 | s[rA] & 0xf);
|
||||
s[rA] = s[rA] & 0xf0 | v >> 4;
|
||||
}
|
||||
s[rF] &= FLAGC;
|
||||
if(s[rA] == 0)
|
||||
s[rF] |= FLAGZ;
|
||||
if((s[rA] & 0x80) != 0)
|
||||
s[rF] |= FLAGS;
|
||||
if(!parity(s[rA]))
|
||||
s[rF] |= FLAGV;
|
||||
return 18;
|
||||
case 0x4a: adchl(BC()); return 15;
|
||||
case 0x5a: adchl(DE()); return 15;
|
||||
case 0x6a: adchl(HL()); return 15;
|
||||
case 0x7a: adchl(sp); return 15;
|
||||
case 0x4b: a = fetch16(); s[rC] = z80read(a++); s[rB] = z80read(a); return 20;
|
||||
case 0x5b: a = fetch16(); s[rE] = z80read(a++); s[rD] = z80read(a); return 20;
|
||||
case 0x6b: a = fetch16(); s[rL] = z80read(a++); s[rH] = z80read(a); return 20;
|
||||
case 0x7b: sp = read16(fetch16()); return 20;
|
||||
case 0x5e: intm = intm & 0xc0 | 2; return 8;
|
||||
case 0x4f: return 9;
|
||||
}
|
||||
sysfatal("undefined z80 opcode ed%.2x at pc=%#.4x", op, scurpc);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
index(int n)
|
||||
{
|
||||
u8int op;
|
||||
u16int v;
|
||||
|
||||
op = fetch8();
|
||||
switch(op){
|
||||
case 0x40: case 0x41: case 0x42: case 0x43: case 0x47:
|
||||
case 0x48: case 0x49: case 0x4a: case 0x4b: case 0x4f:
|
||||
case 0x50: case 0x51: case 0x52: case 0x53: case 0x57:
|
||||
case 0x58: case 0x59: case 0x5a: case 0x5b: case 0x5f:
|
||||
case 0x78: case 0x79: case 0x7a: case 0x7b: case 0x7f:
|
||||
s[op >> 3 & 7] = s[op & 7];
|
||||
return 8;
|
||||
case 0x60: case 0x61: case 0x62: case 0x63: case 0x67:
|
||||
ix[n] = ix[n] & 0xff | s[op & 7] << 8;
|
||||
return 8;
|
||||
case 0x68: case 0x69: case 0x6a: case 0x6b: case 0x6f:
|
||||
ix[n] = ix[n] & 0xff00 | s[op & 7];
|
||||
return 8;
|
||||
case 0x65: ix[n] = ix[n] << 8 | ix[n] & 0xff; return 8;
|
||||
case 0x6c: ix[n] = ix[n] >> 8 | ix[n] & 0xff00; return 8;
|
||||
case 0x64: case 0x6d: return 8;
|
||||
case 0x70: case 0x71: case 0x72: case 0x73:
|
||||
case 0x74: case 0x75: case 0x77:
|
||||
z80write(ix[n] + fetch8(), s[op & 7]);
|
||||
return 19;
|
||||
case 0x44: case 0x4c: case 0x54: case 0x5c: case 0x7c:
|
||||
s[op >> 3 & 7] = ix[n] >> 8;
|
||||
return 8;
|
||||
case 0x45: case 0x4d: case 0x55: case 0x5d: case 0x7d:
|
||||
s[op >> 3 & 7] = ix[n];
|
||||
return 8;
|
||||
case 0x46: case 0x4e: case 0x56: case 0x5e: case 0x66: case 0x6e: case 0x7e:
|
||||
s[op >> 3 & 7] = z80read(ix[n] + fetch8());
|
||||
return 19;
|
||||
case 0x84: case 0x8c: case 0x94: case 0x9c:
|
||||
case 0xa4: case 0xac: case 0xb4: case 0xbc:
|
||||
return alu(op >> 3 & 7, 12 + n);
|
||||
case 0x85: case 0x8d: case 0x95: case 0x9d:
|
||||
case 0xa5: case 0xad: case 0xb5: case 0xbd:
|
||||
return alu(op >> 3 & 7, 10 + n);
|
||||
case 0x86: case 0x8e: case 0x96: case 0x9e:
|
||||
case 0xa6: case 0xae: case 0xb6: case 0xbe:
|
||||
return alu(op >> 3 & 7, 14 + n);
|
||||
|
||||
case 0x21: ix[n] = fetch16(); return 14;
|
||||
case 0xe1: ix[n] = pop16(); return 14;
|
||||
case 0x22: write16(fetch16(), ix[n]); return 20;
|
||||
case 0x23: ix[n]++; return 10;
|
||||
case 0xe3: v = ix[n]; ix[n] = read16(sp); write16(sp, v); return 23;
|
||||
case 0x24: inc(ix[n] >> 8); ix[n] += 0x100; return 8;
|
||||
case 0x34: v = ix[n] + fetch8(); z80write(v, inc(z80read(v))); return 23;
|
||||
case 0x25: dec(ix[n] >> 8); ix[n] -= 0x100; return 8;
|
||||
case 0x35: v = ix[n] + fetch8(); z80write(v, dec(z80read(v))); return 23;
|
||||
case 0xe5: push16(ix[n]); return 15;
|
||||
case 0x26: ix[n] = ix[n] & 0xff | fetch8() << 8; return 11;
|
||||
case 0x36: v = ix[n] + fetch8(); z80write(v, fetch8()); return 19;
|
||||
case 0x09: return addindex(n, BC());
|
||||
case 0x19: return addindex(n, DE());
|
||||
case 0x29: return addindex(n, ix[n]);
|
||||
case 0x39: return addindex(n, sp);
|
||||
case 0xe9: spc = ix[n]; return 8;
|
||||
case 0xf9: sp = ix[n]; return 10;
|
||||
case 0x2a: ix[n] = read16(fetch16()); return 20;
|
||||
case 0x2b: ix[n]--; return 10;
|
||||
case 0xcb: return bits(n);
|
||||
case 0x2c: inc(ix[n]++); return 8;
|
||||
case 0x2d: dec(ix[n]--); return 8;
|
||||
case 0x2e: ix[n] = ix[n] & 0xff00 | fetch8(); return 11;
|
||||
}
|
||||
sysfatal("undefined z80 opcode %.2x%.2x at pc=%#.4x", n ? 0xfd : 0xdd, op, scurpc);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
z80step(void)
|
||||
{
|
||||
u8int op;
|
||||
u16int v, w;
|
||||
|
||||
if((z80bus & RESET) != 0){
|
||||
scurpc = spc = 0;
|
||||
intm = 0;
|
||||
ipage = 0;
|
||||
return 1;
|
||||
}
|
||||
if((z80bus & BUSACK) != 0){
|
||||
|
@ -19,5 +602,219 @@ z80step(void)
|
|||
z80bus |= BUSACK;
|
||||
return 1;
|
||||
}
|
||||
if(z80irq != 0 && (intm & 0x80) != 0){
|
||||
push16(spc);
|
||||
intm &= 0x3f;
|
||||
switch(intm & 3){
|
||||
case 1:
|
||||
spc = 0x38;
|
||||
return 2;
|
||||
default:
|
||||
sysfatal("z80 interrupt in mode %d", intm & 3);
|
||||
}
|
||||
}
|
||||
scurpc = spc;
|
||||
if(0)
|
||||
print("%x AF %.2x%.2x BC %.2x%.2x DE %.2x%.2x HL %.2x%.2x IX %.4x IY %.4x\n", scurpc, s[rA], s[rF], s[rB], s[rC], s[rD], s[rE], s[rH], s[rL], ix[0], ix[1]);
|
||||
op = fetch8();
|
||||
switch(op >> 6){
|
||||
case 1: return move(op >> 3 & 7, op & 7);
|
||||
case 2: return alu(op >> 3 & 7, op & 7);
|
||||
}
|
||||
switch(op){
|
||||
case 0x00: return 4;
|
||||
case 0x10: return branch(--s[rB] != 0, 1);
|
||||
case 0x20: return branch((s[rF] & FLAGZ) == 0, 0);
|
||||
case 0x30: return branch((s[rF] & FLAGC) == 0, 0);
|
||||
case 0x01: s[rC] = fetch8(); s[rB] = fetch8(); return 10;
|
||||
case 0x11: s[rE] = fetch8(); s[rD] = fetch8(); return 10;
|
||||
case 0x21: s[rL] = fetch8(); s[rH] = fetch8(); return 10;
|
||||
case 0x31: sp = fetch16(); return 10;
|
||||
case 0x02: z80write(BC(), s[rA]); return 7;
|
||||
case 0x12: z80write(DE(), s[rA]); return 7;
|
||||
case 0x22: v = fetch16(); z80write(v++, s[rL]); z80write(v, s[rH]); return 16;
|
||||
case 0x32: z80write(fetch16(), s[rA]); return 13;
|
||||
case 0x03: if(++s[rC] == 0) s[rB]++; return 6;
|
||||
case 0x13: if(++s[rE] == 0) s[rD]++; return 6;
|
||||
case 0x23: if(++s[rL] == 0) s[rH]++; return 6;
|
||||
case 0x33: sp++; return 6;
|
||||
case 0x04: inc(s[rB]++); return 4;
|
||||
case 0x14: inc(s[rD]++); return 4;
|
||||
case 0x24: inc(s[rH]++); return 4;
|
||||
case 0x34: z80write(HL(), inc(z80read(HL()))); return 11;
|
||||
case 0x05: dec(s[rB]--); return 4;
|
||||
case 0x15: dec(s[rD]--); return 4;
|
||||
case 0x25: dec(s[rH]--); return 4;
|
||||
case 0x35: z80write(HL(), dec(z80read(HL()))); return 11;
|
||||
case 0x06: s[rB] = fetch8(); return 7;
|
||||
case 0x16: s[rD] = fetch8(); return 7;
|
||||
case 0x26: s[rH] = fetch8(); return 7;
|
||||
case 0x36: z80write(HL(), fetch8()); return 10;
|
||||
case 0x07:
|
||||
s[rF] = s[rF] & ~(FLAGC|FLAGN|FLAGH) | s[rA] >> 7;
|
||||
s[rA] = s[rA] << 1 | s[rA] >> 7;
|
||||
return 4;
|
||||
case 0x17:
|
||||
v = s[rF] & FLAGC;
|
||||
s[rF] = s[rF] & ~(FLAGC|FLAGN|FLAGH) | s[rA] >> 7;
|
||||
s[rA] = s[rA] << 1 | v;
|
||||
return 4;
|
||||
case 0x27:
|
||||
if(s[rA] > 0x99 || (s[rF] & FLAGC) != 0){
|
||||
s[rF] |= FLAGC;
|
||||
v = 0x60;
|
||||
}else{
|
||||
s[rF] &= ~FLAGC;
|
||||
v = 0;
|
||||
}
|
||||
if((s[rA] & 0xf) > 9 || (s[rF] & FLAGH) != 0)
|
||||
v |= 6;
|
||||
w = s[rA];
|
||||
if((s[rF] & FLAGN) != 0)
|
||||
s[rA] -= v;
|
||||
else
|
||||
s[rA] += v;
|
||||
s[rF] &= ~(FLAGV|FLAGS|FLAGZ|FLAGH);
|
||||
if(((s[rA] ^ w) & 0x10) != 0)
|
||||
s[rF] |= FLAGH;
|
||||
if(!parity(s[rA]))
|
||||
s[rF] |= FLAGV;
|
||||
if(s[rA] == 0)
|
||||
s[rF] |= FLAGZ;
|
||||
if((s[rA] & 0x80) != 0)
|
||||
s[rF] |= FLAGS;
|
||||
return 4;
|
||||
case 0x37: s[rF] = s[rF] & ~(FLAGN | FLAGH) | FLAGC; return 4;
|
||||
case 0x08:
|
||||
swap(rA);
|
||||
swap(rF);
|
||||
return 4;
|
||||
case 0x18: return branch(1, 0);
|
||||
case 0x28: return branch((s[rF] & FLAGZ) != 0, 0);
|
||||
case 0x38: return branch((s[rF] & FLAGC) != 0, 0);
|
||||
case 0x09: return addhl(BC());
|
||||
case 0x19: return addhl(DE());
|
||||
case 0x29: return addhl(HL());
|
||||
case 0x39: return addhl(sp);
|
||||
case 0x0a: s[rA] = z80read(BC()); return 7;
|
||||
case 0x1a: s[rA] = z80read(DE()); return 7;
|
||||
case 0x2a: v = fetch16(); s[rL] = z80read(v++); s[rH] = z80read(v); return 16;
|
||||
case 0x3a: s[rA] = z80read(fetch16()); return 13;
|
||||
case 0x0b: if(s[rC]-- == 0) s[rB]--; return 6;
|
||||
case 0x1b: if(s[rE]-- == 0) s[rD]--; return 6;
|
||||
case 0x2b: if(s[rL]-- == 0) s[rH]--; return 6;
|
||||
case 0x3b: sp--; return 6;
|
||||
case 0x0c: inc(s[rC]++); return 4;
|
||||
case 0x1c: inc(s[rE]++); return 4;
|
||||
case 0x2c: inc(s[rL]++); return 4;
|
||||
case 0x3c: inc(s[rA]++); return 4;
|
||||
case 0x0d: dec(s[rC]--); return 4;
|
||||
case 0x1d: dec(s[rE]--); return 4;
|
||||
case 0x2d: dec(s[rL]--); return 4;
|
||||
case 0x3d: dec(s[rA]--); return 4;
|
||||
case 0x0e: s[rC] = fetch8(); return 7;
|
||||
case 0x1e: s[rE] = fetch8(); return 7;
|
||||
case 0x2e: s[rL] = fetch8(); return 7;
|
||||
case 0x3e: s[rA] = fetch8(); return 7;
|
||||
case 0x0f:
|
||||
s[rF] = s[rF] & ~(FLAGC|FLAGN|FLAGH) | s[rA] & 1;
|
||||
s[rA] = s[rA] >> 1 | s[rA] << 7;
|
||||
return 4;
|
||||
case 0x1f:
|
||||
v = s[rF] << 7;
|
||||
s[rF] = s[rF] & ~(FLAGC|FLAGN|FLAGH) | s[rA] & 1;
|
||||
s[rA] = s[rA] >> 1 | v;
|
||||
return 4;
|
||||
case 0x2f:
|
||||
s[rF] |= FLAGN|FLAGH;
|
||||
s[rA] ^= 0xff;
|
||||
return 4;
|
||||
case 0x3f:
|
||||
s[rF] = s[rF] & ~(FLAGN|FLAGH) ^ FLAGC | s[rF] << 4 & FLAGH;
|
||||
return 4;
|
||||
case 0xc0: if((s[rF] & FLAGZ) == 0) {spc = pop16(); return 11;} return 5;
|
||||
case 0xd0: if((s[rF] & FLAGC) == 0) {spc = pop16(); return 11;} return 5;
|
||||
case 0xe0: if((s[rF] & FLAGV) == 0) {spc = pop16(); return 11;} return 5;
|
||||
case 0xf0: if((s[rF] & FLAGS) == 0) {spc = pop16(); return 11;} return 5;
|
||||
case 0xc1: s[rC] = pop8(); s[rB] = pop8(); return 10;
|
||||
case 0xd1: s[rE] = pop8(); s[rD] = pop8(); return 10;
|
||||
case 0xe1: s[rL] = pop8(); s[rH] = pop8(); return 10;
|
||||
case 0xf1: s[rF] = pop8(); s[rA] = pop8(); return 10;
|
||||
case 0xc2: return jump((s[rF] & FLAGZ) == 0);
|
||||
case 0xd2: return jump((s[rF] & FLAGC) == 0);
|
||||
case 0xe2: return jump((s[rF] & FLAGV) == 0);
|
||||
case 0xf2: return jump((s[rF] & FLAGS) == 0);
|
||||
case 0xc3: return jump(1);
|
||||
case 0xd3: z80out(fetch8(), s[rA]); return 11;
|
||||
case 0xe3:
|
||||
v = HL();
|
||||
s[rL] = z80read(sp);
|
||||
s[rH] = z80read(sp + 1);
|
||||
write16(sp, v);
|
||||
return 19;
|
||||
case 0xf3: intm &= 0x3f; return 4;
|
||||
case 0xc4: return call(fetch16(), (s[rF] & FLAGZ) == 0);
|
||||
case 0xd4: return call(fetch16(), (s[rF] & FLAGC) == 0);
|
||||
case 0xe4: return call(fetch16(), (s[rF] & FLAGV) == 0);
|
||||
case 0xf4: return call(fetch16(), (s[rF] & FLAGS) == 0);
|
||||
case 0xc5: push8(s[rB]); push8(s[rC]); return 11;
|
||||
case 0xd5: push8(s[rD]); push8(s[rE]); return 11;
|
||||
case 0xe5: push8(s[rH]); push8(s[rL]); return 11;
|
||||
case 0xf5: push8(s[rA]); push8(s[rF]); return 11;
|
||||
case 0xc6: return alu(0, 8);
|
||||
case 0xd6: return alu(2, 8);
|
||||
case 0xe6: return alu(4, 8);
|
||||
case 0xf6: return alu(6, 8);
|
||||
case 0xc7: return call(0x00, 1);
|
||||
case 0xd7: return call(0x10, 1);
|
||||
case 0xe7: return call(0x20, 1);
|
||||
case 0xf7: return call(0x30, 1);
|
||||
case 0xc8: if((s[rF] & FLAGZ) != 0) {spc = pop16(); return 11;} return 5;
|
||||
case 0xd8: if((s[rF] & FLAGC) != 0) {spc = pop16(); return 11;} return 5;
|
||||
case 0xe8: if((s[rF] & FLAGV) != 0) {spc = pop16(); return 11;} return 5;
|
||||
case 0xf8: if((s[rF] & FLAGS) != 0) {spc = pop16(); return 11;} return 5;
|
||||
case 0xc9: spc = pop16(); return 10;
|
||||
case 0xd9:
|
||||
swap(rB);
|
||||
swap(rC);
|
||||
swap(rD);
|
||||
swap(rE);
|
||||
swap(rH);
|
||||
swap(rL);
|
||||
return 4;
|
||||
case 0xe9: spc = HL(); return 4;
|
||||
case 0xf9: sp = HL(); return 6;
|
||||
case 0xca: return jump((s[rF] & FLAGZ) != 0);
|
||||
case 0xda: return jump((s[rF] & FLAGC) != 0);
|
||||
case 0xea: return jump((s[rF] & FLAGV) != 0);
|
||||
case 0xfa: return jump((s[rF] & FLAGS) != 0);
|
||||
case 0xcb: return bits(-1);
|
||||
case 0xdb: s[rA] = z80in(fetch8()); return 11;
|
||||
case 0xeb:
|
||||
v = DE();
|
||||
s[rD] = s[rH];
|
||||
s[rE] = s[rL];
|
||||
s[rH] = v >> 8;
|
||||
s[rL] = v;
|
||||
return 4;
|
||||
case 0xfb: intm |= 0xc0; return 4;
|
||||
case 0xcc: return call(fetch16(), (s[rF] & FLAGZ) != 0);
|
||||
case 0xdc: return call(fetch16(), (s[rF] & FLAGC) != 0);
|
||||
case 0xec: return call(fetch16(), (s[rF] & FLAGV) != 0);
|
||||
case 0xfc: return call(fetch16(), (s[rF] & FLAGS) != 0);
|
||||
case 0xcd: return call(fetch16(), 1);
|
||||
case 0xdd: return index(0);
|
||||
case 0xed: return ed();
|
||||
case 0xfd: return index(1);
|
||||
case 0xce: return alu(1, 8);
|
||||
case 0xde: return alu(3, 8);
|
||||
case 0xee: return alu(5, 8);
|
||||
case 0xfe: return alu(7, 8);
|
||||
case 0xcf: return call(0x08, 1);
|
||||
case 0xdf: return call(0x18, 1);
|
||||
case 0xef: return call(0x28, 1);
|
||||
case 0xff: return call(0x38, 1);
|
||||
}
|
||||
sysfatal("undefined z80 opcode %#.2x at pc=%#.4x", op, scurpc);
|
||||
return 0;
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue