![](/media/cache/profiles/f93486bfff38ca69d76d85c089569a09.50x50_q85.jpg)
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.
z80/edops.h
- Committer:
- gertk
- Date:
- 2011-06-29
- Revision:
- 0:806c2f2a7d47
File content as of revision 0:806c2f2a7d47:
/* 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; }}