BBC Basic in Z80 emulation on the mbed, USB serial terminal output only. LOAD and SAVE work on the local file system but there is no error signalling.
Diff: z80/edops.h
- Revision:
- 0:806c2f2a7d47
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/z80/edops.h Wed Jun 29 14:25:56 2011 +0000 @@ -0,0 +1,590 @@ +/* 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) { var=in(c);\ + 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;\ + } + +#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++; + +// IN B,(C) + switch(op){ +instr(0x40,8); + input(b); +endinstr; + +// OUT (C),B +instr(0x41,8); + out(c,b); +endinstr; + +// SBC HL,BC +instr(0x42,11); + sbchl(bc); +endinstr; + +// LD (nn),BC +instr(0x43,16); + {unsigned short addr=fetch2(pc); + pc+=2; + store2b(addr,b,c); + } +endinstr; + +// NEG +instr(0x44,4); + neg; +endinstr; + +// RETN +instr(0x45,4); + iff1=iff2; + ret; +endinstr; + +// IM 0 +instr(0x46,4); + im=0; +endinstr; + +// LD I,A +instr(0x47,5); + i=a; +endinstr; + +// IN C,(C) +instr(0x48,8); + input(c); +endinstr; + +// OUT (C),C +instr(0x49,8); + out(c,c); +endinstr; + +// ADC HL,BC +instr(0x4a,11); + adchl(bc); +endinstr; + +// LD BC,(nn) +instr(0x4b,16); + {unsigned short addr=fetch2(pc); + pc+=2; + c=fetch(addr); + b=fetch(addr+1); + } +endinstr; + +// ? +instr(0x4c,4); + neg; +endinstr; + +// RETI +instr(0x4d,4); + ret; +endinstr; + +// ? +instr(0x4e,4); + im=1; +endinstr; + +// ? +instr(0x4f,5); + r=a; +endinstr; + +// IN D,(C) +instr(0x50,8); + input(d); +endinstr; + +// OUT (C),D +instr(0x51,8); + out(c,d); +endinstr; + +// SBC HL,DE +instr(0x52,11); + sbchl(de); +endinstr; + +// LD (nn),DE +instr(0x53,16); + {unsigned short addr=fetch2(pc); + pc+=2; + store2b(addr,d,e); + } +endinstr; + +// ? +instr(0x54,4); + neg; +endinstr; + +// my opcode for replacing the MOS routines +instr(0x55,4); + // printf("@ %04x Illegal opcode ED55 (MOS) \n\r",pc); + do_mos(); // + ret; +endinstr; + +// IM 1 +instr(0x56,4); + im=1; +endinstr; + +// LD A,I +instr(0x57,5); + a=i; + f=(f&1)|(a&0xa8)|((!a)<<6)|(iff2<<2); +endinstr; + +// IN E,(C) +instr(0x58,8); + input(e); +endinstr; + +// OUT (C),E +instr(0x59,8); + out(c,e); +endinstr; + +// ADC HL,DE +instr(0x5a,11); + adchl(de); +endinstr; + +// LD DE,(nn) +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; + +// IM 2 +instr(0x5e,4); + im=2; +endinstr; + +// LDA A,R (unecessary on static memory) +instr(0x5f,5); + a=r; + f=(f&1)|(a&0xa8)|((!a)<<6)|(iff2<<2); +endinstr; + +// IN H,(C) +instr(0x60,8); + input(h); +endinstr; + +// OUT (C),H +instr(0x61,8); + out(c,h); +endinstr; + +// SBC HL,HL +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; + +// ? illegal instruction ED65 +instr(0x65,4); + ret; +endinstr; + +// ? +instr(0x66,4); + ret; + // was im=0; +endinstr; + +// RRD +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; + +// IN L,(C) +instr(0x68,8); + input(l); +endinstr; + +// OUT (C),L +instr(0x69,8); + out(c,l); +endinstr; + +// ADC HL,HL +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; + ret; +endinstr; + +// RLD +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);} +endinstr; + +// ? +instr(0x71,8); + out(c,0); +endinstr; + +// SBC HL,SP +instr(0x72,11); + sbchl(sp); +endinstr; + +// LD (nn),SP +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; + +// IN A,(C) +instr(0x78,8); + input(a); +endinstr; + +// OUT (C),A +instr(0x79,8); + out(c,a); +endinstr; + +// ADC HL,SP +instr(0x7a,11); + adchl(sp); +endinstr; + +// LD SP,(nn) +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; + +// LDI +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; + +// CPI +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; + +// INI +instr(0xa2,12); + {unsigned char t=in(c); + store(hl,t); + if(!++l)h++; + b--; + f=(b&0xa8)|((!b)<<6)|2|((parity(b)^c)&4); + } +endinstr; + +// OUTI +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); + // printf("OUTI %02x %02x\n\r",c,x); + out(c,x); + if(!++l)h++; + b--; + f=(f&1)|0x12|(b&0xa8)|((!b)<<6); + // f=(f & 0xBF)|2|((b==0)<<6); + + } +endinstr; + +// LDD +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; + +// CPD +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; + +// IND +instr(0xaa,12); + {unsigned char t=in(c); + store(hl,t); + if(!l--)h--; + b--; +// f=(f & 0xBF)|2|((!b)<<6); + + f=(b&0xa8)|((b>0)<<6)|2|((parity(b)^c^4)&4); + } +endinstr; + +// OUTD +instr(0xab,12); + {unsigned char x=fetch(hl); + out(c,x); + if(!l--)h--; + b--; + f=(f&1)|0x12|(b&0xa8)|((!b)<<6); + } +endinstr; + +/* Note: the Z80 implements "*R" as "*" followed by JR -2. No reason + to change this... */ + +// LDIR +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; + } +endinstr; + +// CPIR +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; + } +endinstr; + +// INIR +instr(0xb2,12); + {unsigned char t=in(c); + store(hl,t); + if(!++l)h++; + b--; + f=(b&0xa8)|((!b)<<6)|2|((parity(b)^c)&4); + // f=(f & 0xBF)|2|((!b)<<6); + if(b)pc-=2; + } +endinstr; + +// OTIR +instr(0xb3,12); + {unsigned char x=fetch(hl); + out(c,x); + if(!++l)h++; + b--; + f=(f&1)|0x12|(b&0xa8)|((!b)<<6); + if(b)pc-=2; + } +endinstr; + +// LDDR +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; + } +endinstr; + +// CPDR +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; + } +endinstr; + +// INDR +instr(0xba,12); + {unsigned char t=in(c); + store(hl,t); + if(!l--)h--; + b--; + f=(b&0xa8)|((!b)<<6)|2|((parity(b)^c^4)&4); + // f=(f & 0xBF)|2|((!b)<<6); + + if(b)pc-=2; + } +endinstr; + +// OTDR +instr(0xbb,12); + {unsigned char x=fetch(hl); + out(c,x); + if(!l--)h--; + b--; + f=(f&1)|0x12|(b&0xa8)|((!b)<<6); + if(b)pc-=2; + } +endinstr; + +}}