/* * Simulator of microcontrollers (inst_ed.cc) * ED escaped multi-byte opcodes for Z80. * * Copyright (C) 1999,99 Drotos Daniel, Talker Bt. * * To contact author send email to drdani@mazsola.iit.uni-miskolc.hu * */ /* This file is part of microcontroller simulator: ucsim. UCSIM 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. UCSIM 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 UCSIM; see the file COPYING. If not, write to the Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /*@1@*/ #include "ddconfig.h" // local #include "z80cl.h" #include "regsz80.h" #include "z80mac.h" #define tst_A_bytereg(br) { \ ubtmp = regs.raf.A & (br); \ regs.raf.F &= ~(BIT_ALL); /* clear these */ \ regs.raf.F |= BIT_A; \ if (ubtmp == 0) regs.raf.F |= BIT_Z; \ if (ubtmp & 0x80) regs.raf.F |= BIT_S; \ if (parity(ubtmp)) regs.raf.F |= BIT_P; \ } int cl_z80::inst_ed_(t_mem code) { unsigned short tw; u8_t ubtmp; if (code < 0x40) { if (!(type->type & (CPU_Z180 | CPU_EZ80))) return resINV_INST; switch ( code & 0x07 ) { case 0: // IN0 ubtmp = fetch1( ); reg_g_store( (code >> 3) & 0x07, in_byte( ubtmp ) ); return resGO; case 1: // OUT0 ubtmp = fetch1( ); out_byte( ubtmp, reg_g_read( (code >> 3) & 0x07 ) ); return resGO; case 4: // TST tst_A_bytereg(reg_g_read( (code >> 3) & 0x07 )); return resGO; default: return resINV_INST; } } switch(code) { #if 0 case 0x40: // IN B,(C) return(resGO); case 0x41: // OUT (C),B return(resGO); #endif case 0x42: // SBC HL,BC sbc_HL_wordreg(regs.BC); return(resGO); case 0x43: // LD (nnnn),BC tw = fetch2(); store2(tw, regs.BC); vc.wr+= 2; return(resGO); case 0x44: // NEG regs.raf.F &= ~(BIT_ALL); /* clear these */ if (regs.raf.A != 0) regs.raf.F |= BIT_C; if (regs.raf.A == 0x80) regs.raf.F |= BIT_P; if ((regs.raf.A & 0x0F) != 0) regs.raf.F |= BIT_A; regs.raf.A = 0 - regs.raf.A; regs.raf.F |= BIT_N; /* not addition */ if (regs.raf.A == 0) regs.raf.F |= BIT_Z; if (regs.raf.A & 0x80) regs.raf.F |= BIT_S; return(resGO); case 0x45: // RETN (return from non-maskable interrupt) pop2(PC); vc.rd+= 2; return(resGO); #if 0 case 0x46: // IM 0 /* interrupt device puts opcode on data bus */ return(resGO); #endif case 0x47: // LD IV,A regs.iv = regs.raf.A; return(resGO); case 0x48: // IN C,(C) vc.rd++; return(resGO); case 0x49: // OUT (C),C vc.wr++; return(resGO); case 0x4A: // ADC HL,BC adc_HL_wordreg(regs.BC); return(resGO); case 0x4B: // LD BC,(nnnn) tw = fetch2(); regs.BC = get2(tw); vc.rd+= 2; return(resGO); case 0x4C: // MLT BC if (!(type->type & (CPU_Z180 | CPU_EZ80))) return(resINV_INST); regs.BC = (unsigned long)(regs.bc.h) * (unsigned long)(regs.bc.l); return(resGO); case 0x4D: // RETI (return from interrupt) pop2(PC); vc.rd+= 2; return(resGO); case 0x4F: // LD R,A /* Load "refresh" register(whats that?) */ return(resGO); case 0x50: // IN D,(C) vc.rd++; return(resGO); case 0x51: // OUT (C),D vc.wr++; return(resGO); case 0x52: // SBC HL,DE sbc_HL_wordreg(regs.DE); return(resGO); case 0x53: // LD (nnnn),DE tw = fetch2(); store2(tw, regs.DE); vc.wr+= 2; return(resGO); #if 0 case 0x56: // IM 1 return(resGO); #endif case 0x57: // LD A,IV regs.raf.A = regs.iv; return(resGO); case 0x58: // IN E,(C) vc.rd++; return(resGO); case 0x59: // OUT (C),E vc.wr++; return(resGO); case 0x5A: // ADC HL,DE adc_HL_wordreg(regs.DE); return(resGO); case 0x5B: // LD DE,(nnnn) tw = fetch2(); regs.DE = get2(tw); vc.rd+= 2; return(resGO); case 0x5C: // MLT DE if (!(type->type & (CPU_Z180 | CPU_EZ80))) return(resINV_INST); regs.DE = (unsigned long)(regs.de.h) * (unsigned long)(regs.de.l); return(resGO); #if 0 case 0x5E: // IM 2 return(resGO); case 0x5F: // LD A,R return(resGO); case 0x60: // IN H,(C) vc.rd++; return(resGO); case 0x61: // OUT (C),H vc.wr++; return(resGO); #endif case 0x62: // SBC HL,HL sbc_HL_wordreg(regs.HL); return(resGO); case 0x63: // LD (nnnn),HL opcode 22 does the same faster tw = fetch2(); store2(tw, regs.HL); vc.wr+= 2; return(resGO); case 0x64: if (!(type->type & (CPU_Z180 | CPU_EZ80))) return(resINV_INST); ubtmp = fetch(); // TST A,n tst_A_bytereg(ubtmp); return(resGO); case 0x67: // RRD ubtmp = get1(regs.HL); store1(regs.HL, (ubtmp >> 4) | (regs.raf.A << 4)); regs.raf.A = (regs.raf.A & 0xf0) | (ubtmp & 0x0f); return(resGO); case 0x68: // IN L,(C) vc.rd++; return(resGO); case 0x69: // OUT (C),L vc.wr++; return(resGO); case 0x6A: // ADC HL,HL adc_HL_wordreg(regs.HL); return(resGO); case 0x6B: // LD HL,(nnnn) opcode 2A does the same faster tw = fetch2(); regs.HL = get2(tw); vc.rd+= 2; return(resGO); case 0x6C: // MLT HL if (!(type->type & (CPU_Z180 | CPU_EZ80))) return(resINV_INST); regs.HL = (unsigned long)(regs.hl.h) * (unsigned long)(regs.hl.l); return(resGO); case 0x6F: // RLD ubtmp = get1(regs.HL); store1(regs.HL, (ubtmp << 4) | (regs.raf.A & 0x0f)); regs.raf.A = (regs.raf.A & 0xf0) | (ubtmp >> 4); return(resGO); case 0x70: // IN (C) set flags only (TSTI) vc.rd++; return(resGO); case 0x71: // OUT (C),0 vc.wr++; return(resGO); case 0x72: // SBC HL,SP sbc_HL_wordreg(regs.SP); return(resGO); case 0x73: // LD (nnnn),SP tw = fetch2(); store2(tw, regs.SP); vc.wr+= 2; return(resGO); case 0x78: // IN A,(C) vc.rd++; return(resGO); case 0x79: // OUT (C),A vc.wr++; return(resGO); case 0x7A: // ADC HL,SP adc_HL_wordreg(regs.SP); return(resGO); case 0x7B: // LD SP,(nnnn) tw = fetch2(); regs.SP = get2(tw); vc.rd+= 2; return(resGO); case 0x7C: // MLT SP //if(type != CPU_Z180) return(resINV_INST); //regs.SP = (unsigned long)(regs.sp.h) * (unsigned long)(regs.sp.l); return(resGO); case 0xA0: // LDI // BC - count, sourc=HL, dest=DE. *DE++ = *HL++, --BC until zero regs.raf.F &= ~(BIT_P | BIT_N | BIT_A); /* clear these */ store1(regs.DE, get1(regs.HL)); ++regs.HL; ++regs.DE; --regs.BC; if (regs.BC != 0) regs.raf.F |= BIT_P; return(resGO); case 0xA1: // CPI // compare acc with mem(HL), if ACC=0 set Z flag. Incr HL, decr BC. { unsigned char tmp; tmp = get1(regs.HL); cp_bytereg(tmp); ++regs.HL; --regs.BC; if (regs.BC != 0) regs.raf.F |= BIT_P; } return(resGO); case 0xA2: // INI return(resGO); case 0xA3: // OUTI return(resGO); case 0xA8: // LDD // BC - count, source=HL, dest=DE. *DE-- = *HL--, --BC until zero regs.raf.F &= ~(BIT_P | BIT_N | BIT_A); /* clear these */ store1(regs.DE, get1(regs.HL)); --regs.HL; --regs.DE; --regs.BC; if (regs.BC != 0) regs.raf.F |= BIT_P; vc.rd++; vc.wr++; return(resGO); case 0xA9: // CPD /* fixme: checkme, compare to other emul. */ regs.raf.F &= ~(BIT_ALL); /* clear these */ if ((regs.raf.A - get1(regs.HL)) == 0) { regs.raf.F |= (BIT_Z | BIT_P); } ++regs.HL; --regs.BC; if (regs.BC != 0) regs.raf.F |= BIT_P; vc.rd++; return(resGO); case 0xAA: // IND return(resGO); case 0xAB: // OUTD return(resGO); case 0xB0: // LDIR // BC - count, sourc=HL, dest=DE. *DE++ = *HL++, --BC until zero regs.raf.F &= ~(BIT_P | BIT_N | BIT_A); /* clear these */ do { store1(regs.DE, get1(regs.HL)); ++regs.HL; ++regs.DE; --regs.BC; vc.rd++; vc.wr++; } while (regs.BC != 0); return(resGO); case 0xB1: // CPIR // compare acc with mem(HL), if ACC=0 set Z flag. Incr HL, decr BC. regs.raf.F &= ~(BIT_P | BIT_A | BIT_Z | BIT_S); /* clear these */ regs.raf.F |= BIT_N; do { if((regs.raf.A - get1(regs.HL)) == 0) regs.raf.F |= BIT_Z; else regs.raf.F &= ~BIT_Z; if((regs.raf.A - get1(regs.HL)) & 0x80) regs.raf.F |= BIT_S; else regs.raf.F &= ~BIT_S; /* fixme: set BIT_A correctly. */ ++regs.HL; --regs.BC; vc.rd++; } while (regs.BC != 0 && (regs.raf.F & BIT_Z) == 0); if(regs.BC != 0) regs.raf.F |= BIT_P; return(resGO); #if 0 case 0xB2: // INIR return(resGO); case 0xB3: // OTIR return(resGO); #endif case 0xB8: // LDDR // BC - count, source=HL, dest=DE. *DE-- = *HL--, --BC until zero regs.raf.F &= ~(BIT_P | BIT_N | BIT_A); /* clear these */ do { store1(regs.DE, get1(regs.HL)); --regs.HL; --regs.DE; --regs.BC; vc.rd++; vc.wr++; } while (regs.BC != 0); return(resGO); case 0xB9: // CPDR // compare acc with mem(HL), if ACC=0 set Z flag. Incr HL, decr BC. regs.raf.F &= ~(BIT_ALL); /* clear these */ do { if ((regs.raf.A - get1(regs.HL)) == 0) { regs.raf.F |= (BIT_Z | BIT_P); break; } --regs.HL; --regs.BC; vc.rd++; } while (regs.BC != 0); return(resGO); #if 0 case 0xBA: // INDR return(resGO); case 0xBB: // OTDR return(resGO); #endif default: return(resINV_INST); } return(resGO); } /******** start ED codes *****************/ int cl_z80::inst_ed(t_mem prefix) { t_mem code; if (fetch(&code)) return(resBREAKPOINT); return inst_ed_(code); } /* End of z80.src/inst_ed.cc */