mirror of https://github.com/wwarthen/RomWBW.git
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
572 lines
10 KiB
572 lines
10 KiB
/* Emulations of the ED operations of the Z80 instruction set.
|
|
* Copyright (C) 1994 Ian Collier.
|
|
*
|
|
* This program is free software; you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation; either version 2 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program; if not, write to the Free Software
|
|
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
|
*/
|
|
|
|
#define input(var) { unsigned short u;\
|
|
var=u=in(tstates,b,c);\
|
|
tstates+=u>>8;\
|
|
f=(f&1)|(var&0xa8)|((!var)<<6)|parity(var);\
|
|
}
|
|
#define sbchl(x) { unsigned short z=(x);\
|
|
unsigned long t=(hl-z-cy)&0x1ffff;\
|
|
f=((t>>8)&0xa8)|(t>>16)|2|\
|
|
(((hl&0xfff)<(z&0xfff)+cy)<<4)|\
|
|
(((hl^z)&(hl^t)&0x8000)>>13)|\
|
|
((!(t&0xffff))<<6)|2;\
|
|
l=t;\
|
|
h=t>>8;\
|
|
}
|
|
|
|
#define adchl(x) { unsigned short z=(x);\
|
|
unsigned long t=hl+z+cy;\
|
|
f=((t>>8)&0xa8)|(t>>16)|\
|
|
(((hl&0xfff)+(z&0xfff)+cy>0xfff)<<4)|\
|
|
(((~hl^z)&(hl^t)&0x8000)>>13)|\
|
|
((!(t&0xffff))<<6)/*|2*/;\
|
|
l=t;\
|
|
h=t>>8;\
|
|
}
|
|
/* [JCE] The "|2" should not be there, at least according to my tests on
|
|
* a PCW16. The PCW16's ADC always resets that bit. */
|
|
|
|
|
|
#define neg (a=-a,\
|
|
f=(a&0xa8)|((!a)<<6)|(((a&15)>0)<<4)|((a==128)<<2)|2|(a>0))
|
|
|
|
{
|
|
unsigned char op=fetch(pc);
|
|
pc++;
|
|
radjust++;
|
|
switch(op){
|
|
instr(0x40,8);
|
|
input(b);
|
|
endinstr;
|
|
|
|
instr(0x41,8);
|
|
tstates+=out(tstates,b,c,b);
|
|
endinstr;
|
|
|
|
instr(0x42,11);
|
|
sbchl(bc);
|
|
endinstr;
|
|
|
|
instr(0x43,16);
|
|
{unsigned short addr=fetch2(pc);
|
|
pc+=2;
|
|
store2b(addr,b,c);
|
|
}
|
|
endinstr;
|
|
|
|
instr(0x44,4);
|
|
neg;
|
|
endinstr;
|
|
|
|
instr(0x45,4);
|
|
iff1=iff2;
|
|
ret;
|
|
endinstr;
|
|
|
|
instr(0x46,4);
|
|
im=0;
|
|
endinstr;
|
|
|
|
instr(0x47,5);
|
|
i=a;
|
|
endinstr;
|
|
|
|
instr(0x48,8);
|
|
input(c);
|
|
endinstr;
|
|
|
|
instr(0x49,8);
|
|
tstates+=out(tstates,b,c,c);
|
|
endinstr;
|
|
|
|
instr(0x4a,11);
|
|
adchl(bc);
|
|
endinstr;
|
|
|
|
instr(0x4b,16);
|
|
{unsigned short addr=fetch2(pc);
|
|
pc+=2;
|
|
c=fetch(addr);
|
|
b=fetch(addr+1);
|
|
}
|
|
endinstr;
|
|
|
|
instr(0x4c,4);
|
|
neg;
|
|
endinstr;
|
|
|
|
instr(0x4d,4);
|
|
ret;
|
|
endinstr;
|
|
|
|
instr(0x4e,4);
|
|
im=1;
|
|
endinstr;
|
|
|
|
instr(0x4f,5);
|
|
r=a;
|
|
radjust=r;
|
|
endinstr;
|
|
|
|
instr(0x50,8);
|
|
input(d);
|
|
endinstr;
|
|
|
|
instr(0x51,8);
|
|
tstates+=out(tstates,b,c,d);
|
|
endinstr;
|
|
|
|
instr(0x52,11);
|
|
sbchl(de);
|
|
endinstr;
|
|
|
|
instr(0x53,16);
|
|
{unsigned short addr=fetch2(pc);
|
|
pc+=2;
|
|
store2b(addr,d,e);
|
|
}
|
|
endinstr;
|
|
|
|
instr(0x54,4);
|
|
neg;
|
|
endinstr;
|
|
|
|
instr(0x55,4);
|
|
ret;
|
|
endinstr;
|
|
|
|
instr(0x56,4);
|
|
im=2;
|
|
endinstr;
|
|
|
|
instr(0x57,5);
|
|
a=i;
|
|
f=(f&1)|(a&0xa8)|((!a)<<6)|(iff2<<2);
|
|
endinstr;
|
|
|
|
instr(0x58,8);
|
|
input(e);
|
|
endinstr;
|
|
|
|
instr(0x59,8);
|
|
tstates+=out(tstates,b,c,e);
|
|
endinstr;
|
|
|
|
instr(0x5a,11);
|
|
adchl(de);
|
|
endinstr;
|
|
|
|
instr(0x5b,16);
|
|
{unsigned short addr=fetch2(pc);
|
|
pc+=2;
|
|
e=fetch(addr);
|
|
d=fetch(addr+1);
|
|
}
|
|
endinstr;
|
|
|
|
instr(0x5c,4);
|
|
neg;
|
|
endinstr;
|
|
|
|
instr(0x5d,4);
|
|
ret;
|
|
endinstr;
|
|
|
|
instr(0x5e,4);
|
|
im=3;
|
|
endinstr;
|
|
|
|
instr(0x5f,5);
|
|
r=(r&0x80)|(radjust&0x7f);
|
|
a=r;
|
|
f=(f&1)|(a&0xa8)|((!a)<<6)|(iff2<<2);
|
|
endinstr;
|
|
|
|
instr(0x60,8);
|
|
input(h);
|
|
endinstr;
|
|
|
|
instr(0x61,8);
|
|
tstates+=out(tstates,b,c,h);
|
|
endinstr;
|
|
|
|
instr(0x62,11);
|
|
sbchl(hl);
|
|
endinstr;
|
|
|
|
instr(0x63,16);
|
|
{unsigned short addr=fetch2(pc);
|
|
pc+=2;
|
|
store2b(addr,h,l);
|
|
}
|
|
endinstr;
|
|
|
|
instr(0x64,4);
|
|
neg;
|
|
endinstr;
|
|
|
|
instr(0x65,4);
|
|
ret;
|
|
endinstr;
|
|
|
|
instr(0x66,4);
|
|
im=0;
|
|
endinstr;
|
|
|
|
instr(0x67,14);
|
|
{unsigned char t=fetch(hl);
|
|
unsigned char u=(a<<4)|(t>>4);
|
|
a=(a&0xf0)|(t&0x0f);
|
|
store(hl,u);
|
|
f=(f&1)|(a&0xa8)|((!a)<<6)|parity(a);
|
|
}
|
|
endinstr;
|
|
|
|
instr(0x68,8);
|
|
input(l);
|
|
endinstr;
|
|
|
|
instr(0x69,8);
|
|
tstates+=out(tstates,b,c,l);
|
|
endinstr;
|
|
|
|
instr(0x6a,11);
|
|
adchl(hl);
|
|
endinstr;
|
|
|
|
instr(0x6b,16);
|
|
{unsigned short addr=fetch2(pc);
|
|
pc+=2;
|
|
l=fetch(addr);
|
|
h=fetch(addr+1);
|
|
}
|
|
endinstr;
|
|
|
|
instr(0x6c,4);
|
|
neg;
|
|
endinstr;
|
|
|
|
instr(0x6d,4);
|
|
ret;
|
|
endinstr;
|
|
|
|
instr(0x6e,4);
|
|
im=1;
|
|
endinstr;
|
|
|
|
instr(0x6f,5);
|
|
{unsigned char t=fetch(hl);
|
|
unsigned char u=(a&0x0f)|(t<<4);
|
|
a=(a&0xf0)|(t>>4);
|
|
store(hl,u);
|
|
f=(f&1)|(a&0xa8)|((!a)<<6)|parity(a);
|
|
}
|
|
endinstr;
|
|
|
|
instr(0x70,8);
|
|
{unsigned char x;
|
|
input(x);
|
|
store(hl,x);
|
|
}
|
|
endinstr;
|
|
|
|
instr(0x71,8);
|
|
{unsigned char x=fetch(hl);
|
|
tstates+=out(tstates,b,c,x);
|
|
}
|
|
endinstr;
|
|
|
|
instr(0x72,11);
|
|
sbchl(sp);
|
|
endinstr;
|
|
|
|
instr(0x73,16);
|
|
{unsigned short addr=fetch2(pc);
|
|
pc+=2;
|
|
store2(addr,sp);
|
|
}
|
|
endinstr;
|
|
|
|
instr(0x74,4);
|
|
neg;
|
|
endinstr;
|
|
|
|
instr(0x75,4);
|
|
ret;
|
|
endinstr;
|
|
|
|
instr(0x76,4);
|
|
im=2;
|
|
endinstr;
|
|
|
|
instr(0x78,8);
|
|
input(a);
|
|
endinstr;
|
|
|
|
instr(0x79,8);
|
|
tstates+=out(tstates,b,c,a);
|
|
endinstr;
|
|
|
|
instr(0x7a,11);
|
|
adchl(sp);
|
|
endinstr;
|
|
|
|
instr(0x7b,16);
|
|
{unsigned short addr=fetch2(pc);
|
|
pc+=2;
|
|
sp=fetch2(addr);
|
|
}
|
|
endinstr;
|
|
|
|
instr(0x7c,4);
|
|
neg;
|
|
endinstr;
|
|
|
|
instr(0x7d,4);
|
|
ret;
|
|
endinstr;
|
|
|
|
instr(0x7e,4);
|
|
im=3;
|
|
endinstr;
|
|
|
|
instr(0xa0,12);
|
|
{unsigned char x=fetch(hl);
|
|
store(de,x);
|
|
if(!++l)h++;
|
|
if(!++e)d++;
|
|
if(!c--)b--;
|
|
f=(f&0xc1)|(x&0x28)|(((b|c)>0)<<2);
|
|
}
|
|
endinstr;
|
|
|
|
instr(0xa1,12);
|
|
{unsigned char carry=cy;
|
|
cpa(fetch(hl));
|
|
if(!++l)h++;
|
|
if(!c--)b--;
|
|
f=(f&0xfa)|carry|(((b|c)>0)<<2);
|
|
}
|
|
endinstr;
|
|
|
|
instr(0xa2,12);
|
|
{unsigned short t=in(tstates,b,c);
|
|
store(hl,t);
|
|
tstates+=t>>8;
|
|
if(!++l)h++;
|
|
b--;
|
|
f=(b&0xa8)|((b==0)<<6)|2|((parity(b)^c)&4);
|
|
}
|
|
endinstr;
|
|
|
|
instr(0xa3,12); /* I can't determine the correct flags outcome for the
|
|
block OUT instructions. Spec says that the carry
|
|
flag is left unchanged and N is set to 1, but that
|
|
doesn't seem to be the case... */
|
|
{unsigned char x=fetch(hl);
|
|
tstates+=out(tstates,b,c,x);
|
|
if(!++l)h++;
|
|
b--;
|
|
f=(f&1)|0x12|(b&0xa8)|((b==0)<<6);
|
|
}
|
|
endinstr;
|
|
|
|
instr(0xa8,12);
|
|
{unsigned char x=fetch(hl);
|
|
store(de,x);
|
|
if(!l--)h--;
|
|
if(!e--)d--;
|
|
if(!c--)b--;
|
|
f=(f&0xc1)|(x&0x28)|(((b|c)>0)<<2);
|
|
}
|
|
endinstr;
|
|
|
|
instr(0xa9,12);
|
|
{unsigned char carry=cy;
|
|
cpa(fetch(hl));
|
|
if(!l--)h--;
|
|
if(!c--)b--;
|
|
f=(f&0xfa)|carry|(((b|c)>0)<<2);
|
|
}
|
|
endinstr;
|
|
|
|
instr(0xaa,12);
|
|
{unsigned short t=in(tstates,b,c);
|
|
store(hl,t);
|
|
tstates+=t>>8;
|
|
if(!l--)h--;
|
|
b--;
|
|
f=(b&0xa8)|((b==0)<<6)|2|((parity(b)^c^4)&4);
|
|
}
|
|
endinstr;
|
|
|
|
instr(0xab,12);
|
|
{unsigned char x=fetch(hl);
|
|
tstates+=out(tstates,b,c,x);
|
|
if(!l--)h--;
|
|
b--;
|
|
f=(f&1)|0x12|(b&0xa8)|((b==0)<<6);
|
|
}
|
|
endinstr;
|
|
|
|
/* Note: the Z80 implements "*R" as "*" followed by JR -2. No reason
|
|
to change this... */
|
|
|
|
instr(0xb0,12);
|
|
{unsigned char x=fetch(hl);
|
|
store(de,x);
|
|
if(!++l)h++;
|
|
if(!++e)d++;
|
|
if(!c--)b--;
|
|
f=(f&0xc1)|(x&0x28)|(((b|c)>0)<<2);
|
|
if(b|c)pc-=2,tstates+=5;
|
|
}
|
|
endinstr;
|
|
|
|
instr(0xb1,12);
|
|
{unsigned char carry=cy;
|
|
cpa(fetch(hl));
|
|
if(!++l)h++;
|
|
if(!c--)b--;
|
|
f=(f&0xfa)|carry|(((b|c)>0)<<2);
|
|
if((f&0x44)==4)pc-=2,tstates+=5;
|
|
}
|
|
endinstr;
|
|
|
|
instr(0xb2,12);
|
|
{unsigned short t=in(tstates,b,c);
|
|
store(hl,t);
|
|
tstates+=t>>8;
|
|
if(!++l)h++;
|
|
b--;
|
|
f=(b&0xa8)|((b==0)<<6)|2|((parity(b)^c)&4);
|
|
if(b)pc-=2,tstates+=5;
|
|
}
|
|
endinstr;
|
|
|
|
instr(0xb3,12);
|
|
{unsigned char x=fetch(hl);
|
|
tstates+=out(tstates,b,c,x);
|
|
if(!++l)h++;
|
|
b--;
|
|
f=(f&1)|0x12|(b&0xa8)|((b==0)<<6);
|
|
if(b)pc-=2,tstates+=5;
|
|
}
|
|
endinstr;
|
|
|
|
instr(0xb8,12);
|
|
{unsigned char x=fetch(hl);
|
|
store(de,x);
|
|
if(!l--)h--;
|
|
if(!e--)d--;
|
|
if(!c--)b--;
|
|
f=(f&0xc1)|(x&0x28)|(((b|c)>0)<<2);
|
|
if(b|c)pc-=2,tstates+=5;
|
|
}
|
|
endinstr;
|
|
|
|
instr(0xb9,12);
|
|
{unsigned char carry=cy;
|
|
cpa(fetch(hl));
|
|
if(!l--)h--;
|
|
if(!c--)b--;
|
|
f=(f&0xfa)|carry|(((b|c)>0)<<2);
|
|
if((f&0x44)==4)pc-=2,tstates+=5;
|
|
}
|
|
endinstr;
|
|
|
|
instr(0xba,12);
|
|
{unsigned short t=in(tstates,b,c);
|
|
store(hl,t);
|
|
tstates+=t>>8;
|
|
if(!l--)h--;
|
|
b--;
|
|
f=(b&0xa8)|((b==0)<<6)|2|((parity(b)^c^4)&4);
|
|
if(b)pc-=2,tstates+=5;
|
|
}
|
|
endinstr;
|
|
|
|
instr(0xbb,12);
|
|
{unsigned char x=fetch(hl);
|
|
tstates+=out(tstates,b,c,x);
|
|
if(!l--)h--;
|
|
b--;
|
|
f=(f&1)|0x12|(b&0xa8)|((b==0)<<6);
|
|
if(b)pc-=2,tstates+=5;
|
|
}
|
|
endinstr;
|
|
|
|
/* XZ80 Pseudo-ops
|
|
instr(0xfb,4);
|
|
multiloader(hl,a);
|
|
endinstr;
|
|
|
|
instr(0xfc,4);
|
|
{ int ans;
|
|
stopwatch();
|
|
ans=loader(pc,ix,de,a,cy);
|
|
if(ans>=0){
|
|
if(ans==1)pc=0x0806;
|
|
else if(ans==2)f&=254;
|
|
else f|=1;
|
|
ix+=de;
|
|
d=e=0;
|
|
if(ans!=1)ret;
|
|
}
|
|
startwatch(1);
|
|
}
|
|
endinstr;
|
|
|
|
instr(0xfd,4);
|
|
{ int ans;
|
|
stopwatch();
|
|
ans=saver(pc,ix,de,a);
|
|
if(ans>0)pc=0x0806;
|
|
else if(ans==0){
|
|
ix+=de;
|
|
d=e=0;
|
|
ret;
|
|
}
|
|
startwatch(1);
|
|
}
|
|
endinstr;
|
|
*/
|
|
|
|
/* ZXCC pseudo-op */
|
|
instr(0xfe, 4);
|
|
{
|
|
/* Create copies of the registers here so we can take their addresses
|
|
* and not lose register optimisation in the rest of the CPU code */
|
|
byte xa,xb,xc,xd,xe,xf,xxh,xxl;
|
|
word xp,xx,xy;
|
|
|
|
xa = a; xb = b; xc = c; xd = d; xe = e; xf = f; xxh = h; xxl = l;
|
|
xp = pc; xx = ix; xy = iy;
|
|
|
|
ed_fe(&xa,&xb,&xc,&xd,&xe,&xf,&xxh,&xxl,&xp,&xx,&xy);
|
|
|
|
a = xa; b = xb; c = xc; d = xd; e = xe; f = xf; h = xxh; l = xxl;
|
|
pc = xp; ix = xx; iy = xy;
|
|
}
|
|
endinstr;
|
|
|
|
default: tstates+=4;
|
|
|
|
}}
|
|
|