//----------------------------------------------------------------------------- //Title: Emulador en Java de un Sinclair ZX Spectrum 48K //Version: 1.0 B //Copyright: Copyright (c) 2004 //Author: Alberto Sánchez Terrén //Clase: Z80.java //Descripción: La clase Z80 es la más extensa de todas ya que debe implementar // la estructura del microprocesador Z80 y la ejecuci�n de todas // las instrucciones del repertorio del mismo. //----------------------------------------------------------------------------- /* * Versión: 2.0 * Autor: José Luis Sánchez Villanueva * * Notas: 09/01/2008 pasa los 68 tests de ZEXALL, con lo que se supone * que realiza una implementación correcta de la Z80. * * 14/01/2008 pasa también los tests de fuse 0.10, exceptuando * los que fuse no implementa bien (BIT n,(HL)). * Del resto, cumple con los contenidos de los registros, flags, * y t-estados. * * 15/01/2008 faltaban los flags de las instrucciones IN r,(C). * * 03/12/2008 se descomponen las instrucciones para poder * implementar la contended-memory del Spectrum. * * 21/09/2009 modificación a lo bestia del emulador. Los flags * se convierten de boolean a bits en un int. El único * que se deja como estaba es el carryFlag. Ahora los * flags se sacan de tablas precalculadas. * * 22/09/2009 Optimizado el tratamiento del HALFCARRY_FLAG en los * métodos add16/add/sub/cp. * * 23/09/2009 Los métodos de más 8000 bytecodes no son compilados * por el JIT a menos que se obliguemos a ello, cosa poco aconsejable. * El método decodeDDFDCD original tenía más de 12000 bytecodes, así que * se subdivide en 2 métodos que procesan los códigos por rangos: * 0x00-0x7F y 0x80-0xFF quedando todos por debajo de los 7000 bytecodes. * * 25/09/2009 Se completa la emulación del registro interno MEMPTR. * Ahora el core-Z80 supera todos los test de MEMPTR del z80tests.tap. * (http://homepage.ntlworld.com/mark.woodmass/z80tests.tap) * Mis agradecimientos a "The Woodster" por el programa, a Boo-boo que * investigo el funcionamiento de MEMPTR y a Vladimir Kladov por * traducir al inglés el documento original. * * 02/10/2009 Se modifica el core para que soporte el retriggering de * interrupciones, cosa que en realidad, estaba pensada desde el * principio. * * 28/03/2010 Se corrige un problema con el manejo de las interrupciones. * Para ello es necesario introducir el flag 'halted'. El problema surgía * únicamente cuando la INT se producía cuando la instrucción a la que * apunta PC es un HALT pero éste aún no se ha ejecutado. En ese caso, * el HALT se ejecutará a la vuelta de la interrupción. Hasta ahora, * la dirección de retorno de la INT que se guardaba en el stack era la * de PC+1 como si el HALT ya se hubiera ejecutado, cuando esto último * era falso. Gracias a Woodster por el programa de test y por informarme * del fallo. Thanks!, Woodster. :) * Creo también los métodos isHalted/setHalted para acceder al flag. De paso, * duplico el método push para que tenga dos parámetros y poder usarla así * con los registros de propósito general, para que sea más rápido. * * 23/08/2010 Increíble!. Después de tanto tiempo, aún he tenido que * corregir la instrucción LD SP, IX(IY) que realizaba los 2 estados de * contención sobre PC en lugar de sobre IR que es lo correcto. De paso * he verificado que todos los usos de getRegIR() son correctos. * * 29/05/2011 Corregida la inicialización de los registros dependiendo * de si es por un reset a través de dicho pin o si es por inicio de * alimentación al chip. * * 04/06/2011 Creados los métodos de acceso al registro oculto MEMPTR * para que puedar cargarse/guardarse en los snapshots de tipo SZX. * * 06/06/2011 Pequeñas optimizaciones en LDI/LDD y CPI/CPD. Se eliminan * los métodos set/reset porque, al no afectar a los flags, es más * rápido aplicar la operación lógica con la máscara donde proceda que * llamar a un método pasándole dos parámetros. Se elimina también el * método EXX y su código se pone en el switch principal. * * 07/06/2011 En las instrucciones INC/DEC (HL) el estado adicional * estaba mal puesto, ya que va después del read y no antes. Corregido. * * 04/07/2011 Se elimina el método push añadido el 28/03/2010 y se usa * el que queda en todos los casos. El código de RETI se unifica con * RETN y sus códigos duplicados. Ligeras modificaciones en DJNZ y en * LDI/LDD/CPI/CPD. Se optimiza el tratamiento del registro MEMPTR. * * 11/07/2011 Se optimiza el tratamiento del carryFlag en las instrucciones * SUB/SBC/SBC16/CP. Se optimiza el tratamiento del HalfCarry en las * instruciones ADC/ADC16/SBC/SBC16. * * 25/09/2011 Introducidos los métodos get/setTimeout. De esa forma, * además de recibir una notificación después de cada instrucción ejecutada * se puede recibir tras N ciclos. En cualquier caso, execDone será llamada * con el número de ciclos ejecutados, sea tras una sola instrucción o tras * expirar el timeout programado. Si hay un timeout, éste seguirá vigente * hasta que se programe otro o se ponga a false execDone. Si el timeout * se programa a cero, se llamará a execDone tras cada instrucción. * * 08/10/2011 En los métodos xor, or y cp se aseguran de que valores > 0xff * pasados como parámetro no le afecten. * * 11/10/2011 Introducida la nueva funcionalidad que permite definir * breakpoints. Cuando se va a ejecutar el opcode que está en esa dirección * se llama al método atAddress. Se separan en dos interfaces las llamadas a * los accesos a memoria de las llamadas de notificación. * * 13/10/2011 Corregido un error en la emulación de las instrucciones * DD/FD que no van seguidas de un código de instrucción adecuado a IX o IY. * Tal y como se trataban hasta ahora, se comprobaban las interrupciones entre * el/los códigos DD/FD y el código de instrucción que le seguía. * * 02/12/2011 Creados los métodos necesarios para poder grabar y cargar el * estado de la CPU de una sola vez a través de la clase Z80State. Los modos * de interrupción pasan a estar en una enumeración. Se proporcionan métodos de * acceso a los registros alternativos de 8 bits. * * 03/06/2012 Eliminada la adición del 25/09/2011. El núcleo de la Z80 no tiene * que preocuparse por timeouts ni zarandajas semejantes. Eso ahora es * responsabilidad de la clase Clock. Se mantiene la funcionalidad del execDone * por si fuera necesario en algún momento avisar tras cada ejecución de * instrucción (para un depurador, por ejemplo). * * 10/12/2012 Actualizada la emulación con las últimas investigaciones llevadas a * cabo por Patrik Rak, respecto al comportamiento de los bits 3 y 5 del registro F * en las instrucciones CCF/SCF. Otro de los tests de Patrik demuestra que, además, * la emulación de MEMPTR era incompleta (por no estar completamente descrita). * El comportamiento coincide con el de un Z80 de Zilog, no con los clónicos NEC. * * 25/01/2018 Una secuencia potencialmente infinita de DD/FD acaba por provocar un * error de Stack Overflow. Se modifica el core para que se trate como lo que es, * un prefijo del código que viene detrás. * Se cambia también el lugar de comprobación de la INT a donde corresponde, el final * de la ejecución de la instrucción. * La activación de INT depende ahora de Clock, no del Spectrum en sí mismo. * * 27/01/2018 Generalizo la solución de los prefijos para que se pueda aplicar también a * CB y ED. Se elimina el miembro opCode y se convierte en variable local. * * 27/01/2018 (reloaded) Estrictamente hablando, al final del ciclo de máquina de la * instrucción se comprueban, por este orden, BUSRQ, NMI e INT. La primera no la * emulamos y la segunda, si la movemos a su sitio, nos ahorramos una comparación. * Se reorganizan también las comparaciones de la INT, así solo se llama al método de Clock * si las interrupciones están habilitadas y no hay pendiente un EI. * * 29/01/2018 CB es el único prefijo de instrucción cuyo byte siguiente produce SIEMPRE un * código de instrucción válido, de modo que no merece la pena dividirlo en dos y es mejor * que se ejecute como una unidad indivisible. */ package z80core; import java.util.Arrays; public class Z80 { private MemIoOps MemIoImpl; private NotifyOps NotifyImpl; // Se está ejecutando una instrucción DDXX, EDXX o FDXX // Solo puede (debería) contener uno de 4 valores [0x00, 0xDD, 0xED, 0xFD] private int prefixOpcode = 0x00; // Subsistema de notificaciones private boolean execDone = false; // Posiciones de los flags private static final int CARRY_MASK = 0x01; private static final int ADDSUB_MASK = 0x02; private static final int PARITY_MASK = 0x04; private static final int OVERFLOW_MASK = 0x04; // alias de PARITY_MASK private static final int BIT3_MASK = 0x08; private static final int HALFCARRY_MASK = 0x10; private static final int BIT5_MASK = 0x20; private static final int ZERO_MASK = 0x40; private static final int SIGN_MASK = 0x80; // Máscaras de conveniencia private static final int FLAG_53_MASK = BIT5_MASK | BIT3_MASK; private static final int FLAG_SZ_MASK = SIGN_MASK | ZERO_MASK; private static final int FLAG_SZHN_MASK = FLAG_SZ_MASK | HALFCARRY_MASK | ADDSUB_MASK; private static final int FLAG_SZP_MASK = FLAG_SZ_MASK | PARITY_MASK; private static final int FLAG_SZHP_MASK = FLAG_SZP_MASK | HALFCARRY_MASK; // Acumulador y resto de registros de 8 bits private int regA, regB, regC, regD, regE, regH, regL; // Flags sIGN, zERO, 5, hALFCARRY, 3, pARITY y ADDSUB (n) private int sz5h3pnFlags; // El flag Carry es el único que se trata aparte private boolean carryFlag; /* Flags para indicar la modificación del registro F en la instrucción actual * y en la anterior. * Son necesarios para emular el comportamiento de los bits 3 y 5 del * registro F con las instrucciones CCF/SCF. * * http://www.worldofspectrum.org/forums/showthread.php?t=41834 * http://www.worldofspectrum.org/forums/showthread.php?t=41704 * * Thanks to Patrik Rak for his tests and investigations. */ private boolean flagQ, lastFlagQ; // Acumulador alternativo y flags -- 8 bits private int regAx; private int regFx; // Registros alternativos private int regBx, regCx, regDx, regEx, regHx, regLx; // Registros de propósito específico // *PC -- Program Counter -- 16 bits* private int regPC; // *IX -- Registro de índice -- 16 bits* private int regIX; // *IY -- Registro de índice -- 16 bits* private int regIY; // *SP -- Stack Pointer -- 16 bits* private int regSP; // *I -- Vector de interrupción -- 8 bits* private int regI; // *R -- Refresco de memoria -- 7 bits* private int regR; // *R7 -- Refresco de memoria -- 1 bit* (bit superior de R) private boolean regRbit7; //Flip-flops de interrupción private boolean ffIFF1 = false; private boolean ffIFF2 = false; // EI solo habilita las interrupciones DESPUES de ejecutar la // siguiente instrucción (excepto si la siguiente instrucción es un EI...) private boolean pendingEI = false; // Estado de la línea NMI private boolean activeNMI = false; // Si está activa la línea INT // En el 48 y los +2a/+3 la línea INT se activa durante 32 ciclos de reloj // En el 128 y +2, se activa 36 ciclos de reloj private boolean activeINT = false; // Modos de interrupción public enum IntMode { IM0, IM1, IM2 }; // Modo de interrupción private IntMode modeINT = IntMode.IM0; // halted == true cuando la CPU está ejecutando un HALT (28/03/2010) private boolean halted = false; // pinReset == true, se ha producido un reset a través de la patilla private boolean pinReset = false; /* * Registro interno que usa la CPU de la siguiente forma * * ADD HL,xx = Valor del registro H antes de la suma * LD r,(IX/IY+d) = Byte superior de la suma de IX/IY+d * JR d = Byte superior de la dirección de destino del salto * * 04/12/2008 No se vayan todavía, aún hay más. Con lo que se ha * implementado hasta ahora parece que funciona. El resto de * la historia está contada en: * http://zx.pk.ru/attachment.php?attachmentid=2989 * * 25/09/2009 Se ha completado la emulación de MEMPTR. A señalar que * no se puede comprobar si MEMPTR se ha emulado bien hasta * que no se emula el comportamiento del registro en las * instrucciones CPI y CPD. Sin ello, todos los tests de * z80tests.tap fallarán aunque se haya emulado bien al * registro en TODAS las otras instrucciones. * Shit yourself, little parrot. */ private int memptr; /* Algunos flags se precalculan para un tratamiento más rápido * Concretamente, SIGN, ZERO, los bits 3, 5, PARITY y ADDSUB: * sz53n_addTable tiene el ADDSUB flag a 0 y paridad sin calcular * sz53pn_addTable tiene el ADDSUB flag a 0 y paridad calculada * sz53n_subTable tiene el ADDSUB flag a 1 y paridad sin calcular * sz53pn_subTable tiene el ADDSUB flag a 1 y paridad calculada * El resto de bits están a 0 en las cuatro tablas lo que es * importante para muchas operaciones que ponen ciertos flags a 0 por real * decreto. Si lo ponen a 1 por el mismo método basta con hacer un OR con * la máscara correspondiente. */ private static final int sz53n_addTable[] = new int[256]; private static final int sz53pn_addTable[] = new int[256]; private static final int sz53n_subTable[] = new int[256]; private static final int sz53pn_subTable[] = new int[256]; static { boolean evenBits; for (int idx = 0; idx < 256; idx++) { if (idx > 0x7f) { sz53n_addTable[idx] |= SIGN_MASK; } evenBits = true; for (int mask = 0x01; mask < 0x100; mask <<= 1) { if ((idx & mask) != 0) { evenBits = !evenBits; } } sz53n_addTable[idx] |= (idx & FLAG_53_MASK); sz53n_subTable[idx] = sz53n_addTable[idx] | ADDSUB_MASK; if (evenBits) { sz53pn_addTable[idx] = sz53n_addTable[idx] | PARITY_MASK; sz53pn_subTable[idx] = sz53n_subTable[idx] | PARITY_MASK; } else { sz53pn_addTable[idx] = sz53n_addTable[idx]; sz53pn_subTable[idx] = sz53n_subTable[idx]; } } sz53n_addTable[0] |= ZERO_MASK; sz53pn_addTable[0] |= ZERO_MASK; sz53n_subTable[0] |= ZERO_MASK; sz53pn_subTable[0] |= ZERO_MASK; } // Un true en una dirección indica que se debe notificar que se va a // ejecutar la instrucción que está en esa direción. private final boolean breakpointAt[] = new boolean[65536]; // Constructor de la clase public Z80(MemIoOps memory, NotifyOps notify) { MemIoImpl = memory; NotifyImpl = notify; execDone = false; Arrays.fill(breakpointAt, false); reset(); } public void setMemIoHandler(MemIoOps memIo) { MemIoImpl = memIo; } public void setNotifyHandler(NotifyOps notify) { NotifyImpl = notify; } // Acceso a registros de 8 bits public final int getRegA() { return regA; } public final void setRegA(int value) { regA = value & 0xff; } public final int getRegB() { return regB; } public final void setRegB(int value) { regB = value & 0xff; } public final int getRegC() { return regC; } public final void setRegC(int value) { regC = value & 0xff; } public final int getRegD() { return regD; } public final void setRegD(int value) { regD = value & 0xff; } public final int getRegE() { return regE; } public final void setRegE(int value) { regE = value & 0xff; } public final int getRegH() { return regH; } public final void setRegH(int value) { regH = value & 0xff; } public final int getRegL() { return regL; } public final void setRegL(int value) { regL = value & 0xff; } // Acceso a registros alternativos de 8 bits public final int getRegAx() { return regAx; } public final void setRegAx(int value) { regAx = value & 0xff; } public final int getRegFx() { return regFx; } public final void setRegFx(int value) { regFx = value & 0xff; } public final int getRegBx() { return regBx; } public final void setRegBx(int value) { regBx = value & 0xff; } public final int getRegCx() { return regCx; } public final void setRegCx(int value) { regCx = value & 0xff; } public final int getRegDx() { return regDx; } public final void setRegDx(int value) { regDx = value & 0xff; } public final int getRegEx() { return regEx; } public final void setRegEx(int value) { regEx = value & 0xff; } public final int getRegHx() { return regHx; } public final void setRegHx(int value) { regHx = value & 0xff; } public final int getRegLx() { return regLx; } public final void setRegLx(int value) { regLx = value & 0xff; } // Acceso a registros de 16 bits public final int getRegAF() { return (regA << 8) | (carryFlag ? sz5h3pnFlags | CARRY_MASK : sz5h3pnFlags); } public final void setRegAF(int word) { regA = (word >>> 8) & 0xff; sz5h3pnFlags = word & 0xfe; carryFlag = (word & CARRY_MASK) != 0; } public final int getRegAFx() { return (regAx << 8) | regFx; } public final void setRegAFx(int word) { regAx = (word >>> 8) & 0xff; regFx = word & 0xff; } public final int getRegBC() { return (regB << 8) | regC; } public final void setRegBC(int word) { regB = (word >>> 8) & 0xff; regC = word & 0xff; } private void incRegBC() { if (++regC < 0x100) { return; } regC = 0; if (++regB < 0x100) { return; } regB = 0; } private void decRegBC() { if (--regC >= 0) { return; } regC = 0xff; if (--regB >= 0) { return; } regB = 0xff; } public final int getRegBCx() { return (regBx << 8) | regCx; } public final void setRegBCx(int word) { regBx = (word >>> 8) & 0xff; regCx = word & 0xff; } public final int getRegDE() { return (regD << 8) | regE; } public final void setRegDE(int word) { regD = (word >>> 8) & 0xff; regE = word & 0xff; } private void incRegDE() { if (++regE < 0x100) { return; } regE = 0; if (++regD < 0x100) { return; } regD = 0; } private void decRegDE() { if (--regE >= 0) { return; } regE = 0xff; if (--regD >= 0) { return; } regD = 0xff; } public final int getRegDEx() { return (regDx << 8) | regEx; } public final void setRegDEx(int word) { regDx = (word >>> 8) & 0xff; regEx = word & 0xff; } public final int getRegHL() { return (regH << 8) | regL; } public final void setRegHL(int word) { regH = (word >>> 8) & 0xff; regL = word & 0xff; } /* Las funciones incRegXX y decRegXX están escritas pensando en que * puedan aprovechar el camino más corto aunque tengan un poco más de * código (al menos en bytecodes lo tienen) */ private void incRegHL() { if (++regL < 0x100) { return; } regL = 0; if (++regH < 0x100) { return; } regH = 0; } private void decRegHL() { if (--regL >= 0) { return; } regL = 0xff; if (--regH >= 0) { return; } regH = 0xff; } public final int getRegHLx() { return (regHx << 8) | regLx; } public final void setRegHLx(int word) { regHx = (word >>> 8) & 0xff; regLx = word & 0xff; } // Acceso a registros de propósito específico public final int getRegPC() { return regPC; } public final void setRegPC(int address) { regPC = address & 0xffff; } public final int getRegSP() { return regSP; } public final void setRegSP(int word) { regSP = word & 0xffff; } public final int getRegIX() { return regIX; } public final void setRegIX(int word) { regIX = word & 0xffff; } public final int getRegIY() { return regIY; } public final void setRegIY(int word) { regIY = word & 0xffff; } public final int getRegI() { return regI; } public final void setRegI(int value) { regI = value & 0xff; } public final int getRegR() { return regRbit7 ? (regR & 0x7f) | SIGN_MASK : regR & 0x7f; } public final void setRegR(int value) { regR = value & 0x7f; regRbit7 = (value > 0x7f); } public final int getPairIR() { if (regRbit7) { return (regI << 8) | ((regR & 0x7f) | SIGN_MASK); } return (regI << 8) | (regR & 0x7f); } // Acceso al registro oculto MEMPTR public final int getMemPtr() { return memptr & 0xffff; } public final void setMemPtr(int word) { memptr = word & 0xffff; } // Acceso a los flags uno a uno public final boolean isCarryFlag() { return carryFlag; } public final void setCarryFlag(boolean state) { carryFlag = state; } public final boolean isAddSubFlag() { return (sz5h3pnFlags & ADDSUB_MASK) != 0; } public final void setAddSubFlag(boolean state) { if (state) { sz5h3pnFlags |= ADDSUB_MASK; } else { sz5h3pnFlags &= ~ADDSUB_MASK; } } public final boolean isParOverFlag() { return (sz5h3pnFlags & PARITY_MASK) != 0; } public final void setParOverFlag(boolean state) { if (state) { sz5h3pnFlags |= PARITY_MASK; } else { sz5h3pnFlags &= ~PARITY_MASK; } } public final boolean isBit3Flag() { return (sz5h3pnFlags & BIT3_MASK) != 0; } public final void setBit3Fag(boolean state) { if (state) { sz5h3pnFlags |= BIT3_MASK; } else { sz5h3pnFlags &= ~BIT3_MASK; } } public final boolean isHalfCarryFlag() { return (sz5h3pnFlags & HALFCARRY_MASK) != 0; } public final void setHalfCarryFlag(boolean state) { if (state) { sz5h3pnFlags |= HALFCARRY_MASK; } else { sz5h3pnFlags &= ~HALFCARRY_MASK; } } public final boolean isBit5Flag() { return (sz5h3pnFlags & BIT5_MASK) != 0; } public final void setBit5Flag(boolean state) { if (state) { sz5h3pnFlags |= BIT5_MASK; } else { sz5h3pnFlags &= ~BIT5_MASK; } } public final boolean isZeroFlag() { return (sz5h3pnFlags & ZERO_MASK) != 0; } public final void setZeroFlag(boolean state) { if (state) { sz5h3pnFlags |= ZERO_MASK; } else { sz5h3pnFlags &= ~ZERO_MASK; } } public final boolean isSignFlag() { return sz5h3pnFlags >= SIGN_MASK; } public final void setSignFlag(boolean state) { if (state) { sz5h3pnFlags |= SIGN_MASK; } else { sz5h3pnFlags &= ~SIGN_MASK; } } // Acceso a los flags F public final int getFlags() { return carryFlag ? sz5h3pnFlags | CARRY_MASK : sz5h3pnFlags; } public final void setFlags(int regF) { sz5h3pnFlags = regF & 0xfe; carryFlag = (regF & CARRY_MASK) != 0; } // Acceso a los flip-flops de interrupción public final boolean isIFF1() { return ffIFF1; } public final void setIFF1(boolean state) { ffIFF1 = state; } public final boolean isIFF2() { return ffIFF2; } public final void setIFF2(boolean state) { ffIFF2 = state; } public final boolean isNMI() { return activeNMI; } public final void setNMI(boolean nmi) { activeNMI = nmi; } // La línea de NMI se activa por impulso, no por nivel public final void triggerNMI() { activeNMI = true; } // La línea INT se activa por nivel public final boolean isINTLine() { return activeINT; } public final void setINTLine(boolean intLine) { activeINT = intLine; } //Acceso al modo de interrupción public final IntMode getIM() { return modeINT; } public final void setIM(IntMode mode) { modeINT = mode; } public final boolean isHalted() { return halted; } public void setHalted(boolean state) { halted = state; } public void setPinReset() { pinReset = true; } public final boolean isPendingEI() { return pendingEI; } public final void setPendingEI(boolean state) { pendingEI = state; } public final Z80State getZ80State() { Z80State state = new Z80State(); state.setRegA(regA); state.setRegF(getFlags()); state.setRegB(regB); state.setRegC(regC); state.setRegD(regD); state.setRegE(regE); state.setRegH(regH); state.setRegL(regL); state.setRegAx(regAx); state.setRegFx(regFx); state.setRegBx(regBx); state.setRegCx(regCx); state.setRegDx(regDx); state.setRegEx(regEx); state.setRegHx(regHx); state.setRegLx(regLx); state.setRegIX(regIX); state.setRegIY(regIY); state.setRegSP(regSP); state.setRegPC(regPC); state.setRegI(regI); state.setRegR(getRegR()); state.setMemPtr(memptr); state.setHalted(halted); state.setIFF1(ffIFF1); state.setIFF2(ffIFF2); state.setIM(modeINT); state.setINTLine(activeINT); state.setPendingEI(pendingEI); state.setNMI(activeNMI); state.setFlagQ(lastFlagQ); return state; } public final void setZ80State(Z80State state) { regA = state.getRegA(); setFlags(state.getRegF()); regB = state.getRegB(); regC = state.getRegC(); regD = state.getRegD(); regE = state.getRegE(); regH = state.getRegH(); regL = state.getRegL(); regAx = state.getRegAx(); regFx = state.getRegFx(); regBx = state.getRegBx(); regCx = state.getRegCx(); regDx = state.getRegDx(); regEx = state.getRegEx(); regHx = state.getRegHx(); regLx = state.getRegLx(); regIX = state.getRegIX(); regIY = state.getRegIY(); regSP = state.getRegSP(); regPC = state.getRegPC(); regI = state.getRegI(); setRegR(state.getRegR()); memptr = state.getMemPtr(); halted = state.isHalted(); ffIFF1 = state.isIFF1(); ffIFF2 = state.isIFF2(); modeINT = state.getIM(); activeINT = state.isINTLine(); pendingEI = state.isPendingEI(); activeNMI = state.isNMI(); flagQ = false; lastFlagQ = state.isFlagQ(); } // Reset /* Según el documento de Sean Young, que se encuentra en * [http://www.myquest.com/z80undocumented], la mejor manera de emular el * reset es poniendo PC, IFF1, IFF2, R e IM0 a 0 y todos los demás registros * a 0xFFFF. * * 29/05/2011: cuando la CPU recibe alimentación por primera vez, los * registros PC e IR se inicializan a cero y el resto a 0xFF. * Si se produce un reset a través de la patilla correspondiente, * los registros PC e IR se inicializan a 0 y el resto se preservan. * En cualquier caso, todo parece depender bastante del modelo * concreto de Z80, así que se escoge el comportamiento del * modelo Zilog Z8400APS. Z80A CPU. * http://www.worldofspectrum.org/forums/showthread.php?t=34574 */ public final void reset() { if (pinReset) { pinReset = false; } else { regA = regAx = 0xff; setFlags(0xff); regFx = 0xff; regB = regBx = 0xff; regC = regCx = 0xff; regD = regDx = 0xff; regE = regEx = 0xff; regH = regHx = 0xff; regL = regLx = 0xff; regIX = regIY = 0xffff; regSP = 0xffff; memptr = 0xffff; } regPC = 0; regI = regR = 0; regRbit7 = false; ffIFF1 = false; ffIFF2 = false; pendingEI = false; activeNMI = false; activeINT = false; halted = false; setIM(IntMode.IM0); lastFlagQ = false; prefixOpcode = 0x00; } // Rota a la izquierda el valor del argumento // El bit 0 y el flag C toman el valor del bit 7 antes de la operación private int rlc(int oper8) { carryFlag = (oper8 > 0x7f); oper8 = (oper8 << 1) & 0xfe; if (carryFlag) { oper8 |= CARRY_MASK; } sz5h3pnFlags = sz53pn_addTable[oper8]; flagQ = true; return oper8; } // Rota a la izquierda el valor del argumento // El bit 7 va al carry flag // El bit 0 toma el valor del flag C antes de la operación private int rl(int oper8) { boolean carry = carryFlag; carryFlag = (oper8 > 0x7f); oper8 = (oper8 << 1) & 0xfe; if (carry) { oper8 |= CARRY_MASK; } sz5h3pnFlags = sz53pn_addTable[oper8]; flagQ = true; return oper8; } // Rota a la izquierda el valor del argumento // El bit 7 va al carry flag // El bit 0 toma el valor 0 private int sla(int oper8) { carryFlag = (oper8 > 0x7f); oper8 = (oper8 << 1) & 0xfe; sz5h3pnFlags = sz53pn_addTable[oper8]; flagQ = true; return oper8; } // Rota a la izquierda el valor del argumento (como sla salvo por el bit 0) // El bit 7 va al carry flag // El bit 0 toma el valor 1 // Instrucción indocumentada private int sll(int oper8) { carryFlag = (oper8 > 0x7f); oper8 = ((oper8 << 1) | CARRY_MASK) & 0xff; sz5h3pnFlags = sz53pn_addTable[oper8]; flagQ = true; return oper8; } // Rota a la derecha el valor del argumento // El bit 7 y el flag C toman el valor del bit 0 antes de la operación private int rrc(int oper8) { carryFlag = (oper8 & CARRY_MASK) != 0; oper8 >>>= 1; if (carryFlag) { oper8 |= SIGN_MASK; } sz5h3pnFlags = sz53pn_addTable[oper8]; flagQ = true; return oper8; } // Rota a la derecha el valor del argumento // El bit 0 va al carry flag // El bit 7 toma el valor del flag C antes de la operación private int rr(int oper8) { boolean carry = carryFlag; carryFlag = (oper8 & CARRY_MASK) != 0; oper8 >>>= 1; if (carry) { oper8 |= SIGN_MASK; } sz5h3pnFlags = sz53pn_addTable[oper8]; flagQ = true; return oper8; } // A = A7 A6 A5 A4 (HL)3 (HL)2 (HL)1 (HL)0 // (HL) = A3 A2 A1 A0 (HL)7 (HL)6 (HL)5 (HL)4 // Los bits 3,2,1 y 0 de (HL) se copian a los bits 3,2,1 y 0 de A. // Los 4 bits bajos que había en A se copian a los bits 7,6,5 y 4 de (HL). // Los 4 bits altos que había en (HL) se copian a los 4 bits bajos de (HL) // Los 4 bits superiores de A no se tocan. ¡p'habernos matao! private void rrd() { int aux = (regA & 0x0f) << 4; memptr = getRegHL(); int memHL = MemIoImpl.peek8(memptr); regA = (regA & 0xf0) | (memHL & 0x0f); MemIoImpl.addressOnBus(memptr, 4); MemIoImpl.poke8(memptr, (memHL >>> 4) | aux); sz5h3pnFlags = sz53pn_addTable[regA]; memptr++; flagQ = true; } // A = A7 A6 A5 A4 (HL)7 (HL)6 (HL)5 (HL)4 // (HL) = (HL)3 (HL)2 (HL)1 (HL)0 A3 A2 A1 A0 // Los 4 bits bajos que había en (HL) se copian a los bits altos de (HL). // Los 4 bits altos que había en (HL) se copian a los 4 bits bajos de A // Los bits 3,2,1 y 0 de A se copian a los bits 3,2,1 y 0 de (HL). // Los 4 bits superiores de A no se tocan. ¡p'habernos matao! private void rld() { int aux = regA & 0x0f; memptr = getRegHL(); int memHL = MemIoImpl.peek8(memptr); regA = (regA & 0xf0) | (memHL >>> 4); MemIoImpl.addressOnBus(memptr, 4); MemIoImpl.poke8(memptr, ((memHL << 4) | aux) & 0xff); sz5h3pnFlags = sz53pn_addTable[regA]; memptr++; flagQ = true; } // Rota a la derecha 1 bit el valor del argumento // El bit 0 pasa al carry. // El bit 7 conserva el valor que tenga private int sra(int oper8) { int sign = oper8 & SIGN_MASK; carryFlag = (oper8 & CARRY_MASK) != 0; oper8 = (oper8 >> 1) | sign; sz5h3pnFlags = sz53pn_addTable[oper8]; flagQ = true; return oper8; } // Rota a la derecha 1 bit el valor del argumento // El bit 0 pasa al carry. // El bit 7 toma el valor 0 private int srl(int oper8) { carryFlag = (oper8 & CARRY_MASK) != 0; oper8 >>>= 1; sz5h3pnFlags = sz53pn_addTable[oper8]; flagQ = true; return oper8; } /* * Half-carry flag: * * FLAG = (A^B^RESULT)&0x10 for any operation * * Overflow flag: * * FLAG = ~(A^B)&(B^RESULT)&0x80 for addition [ADD/ADC] * FLAG = (A^B)&(A^RESULT)&0x80 for subtraction [SUB/SBC] * * For INC/DEC, you can use following simplifications: * * INC: * H_FLAG = (RESULT&0x0F)==0x00 * V_FLAG = RESULT==0x80 * * DEC: * H_FLAG = (RESULT&0x0F)==0x0F * V_FLAG = RESULT==0x7F */ // Incrementa un valor de 8 bits modificando los flags oportunos private int inc8(int oper8) { oper8 = (oper8 + 1) & 0xff; sz5h3pnFlags = sz53n_addTable[oper8]; if ((oper8 & 0x0f) == 0) { sz5h3pnFlags |= HALFCARRY_MASK; } if (oper8 == 0x80) { sz5h3pnFlags |= OVERFLOW_MASK; } flagQ = true; return oper8; } // Decrementa un valor de 8 bits modificando los flags oportunos private int dec8(int oper8) { oper8 = (oper8 - 1) & 0xff; sz5h3pnFlags = sz53n_subTable[oper8]; if ((oper8 & 0x0f) == 0x0f) { sz5h3pnFlags |= HALFCARRY_MASK; } if (oper8 == 0x7f) { sz5h3pnFlags |= OVERFLOW_MASK; } flagQ = true; return oper8; } // Suma de 8 bits afectando a los flags private void add(int oper8) { int res = regA + oper8; carryFlag = res > 0xff; res &= 0xff; sz5h3pnFlags = sz53n_addTable[res]; /* El módulo 16 del resultado será menor que el módulo 16 del registro A * si ha habido HalfCarry. Sucede lo mismo para todos los métodos suma * SIN carry */ if ((res & 0x0f) < (regA & 0x0f)) { sz5h3pnFlags |= HALFCARRY_MASK; } if (((regA ^ ~oper8) & (regA ^ res)) > 0x7f) { sz5h3pnFlags |= OVERFLOW_MASK; } regA = res; flagQ = true; } // Suma con acarreo de 8 bits private void adc(int oper8) { int res = regA + oper8; if (carryFlag) { res++; } carryFlag = res > 0xff; res &= 0xff; sz5h3pnFlags = sz53n_addTable[res]; if (((regA ^ oper8 ^ res) & 0x10) != 0) { sz5h3pnFlags |= HALFCARRY_MASK; } if (((regA ^ ~oper8) & (regA ^ res)) > 0x7f) { sz5h3pnFlags |= OVERFLOW_MASK; } regA = res; flagQ = true; } // Suma dos operandos de 16 bits sin carry afectando a los flags private int add16(int reg16, int oper16) { oper16 += reg16; carryFlag = oper16 > 0xffff; sz5h3pnFlags = (sz5h3pnFlags & FLAG_SZP_MASK) | ((oper16 >>> 8) & FLAG_53_MASK); oper16 &= 0xffff; if ((oper16 & 0x0fff) < (reg16 & 0x0fff)) { sz5h3pnFlags |= HALFCARRY_MASK; } memptr = reg16 + 1; flagQ = true; return oper16; } // Suma con acarreo de 16 bits private void adc16(int reg16) { int regHL = getRegHL(); memptr = regHL + 1; int res = regHL + reg16; if (carryFlag) { res++; } carryFlag = res > 0xffff; res &= 0xffff; setRegHL(res); sz5h3pnFlags = sz53n_addTable[regH]; if (res != 0) { sz5h3pnFlags &= ~ZERO_MASK; } if (((res ^ regHL ^ reg16) & 0x1000) != 0) { sz5h3pnFlags |= HALFCARRY_MASK; } if (((regHL ^ ~reg16) & (regHL ^ res)) > 0x7fff) { sz5h3pnFlags |= OVERFLOW_MASK; } flagQ = true; } // Resta de 8 bits private void sub(int oper8) { int res = regA - oper8; carryFlag = res < 0; res &= 0xff; sz5h3pnFlags = sz53n_subTable[res]; /* El módulo 16 del resultado será mayor que el módulo 16 del registro A * si ha habido HalfCarry. Sucede lo mismo para todos los métodos resta * SIN carry, incluido cp */ if ((res & 0x0f) > (regA & 0x0f)) { sz5h3pnFlags |= HALFCARRY_MASK; } if (((regA ^ oper8) & (regA ^ res)) > 0x7f) { sz5h3pnFlags |= OVERFLOW_MASK; } regA = res; flagQ = true; } // Resta con acarreo de 8 bits private void sbc(int oper8) { int res = regA - oper8; if (carryFlag) { res--; } carryFlag = res < 0; res &= 0xff; sz5h3pnFlags = sz53n_subTable[res]; if (((regA ^ oper8 ^ res) & 0x10) != 0) { sz5h3pnFlags |= HALFCARRY_MASK; } if (((regA ^ oper8) & (regA ^ res)) > 0x7f) { sz5h3pnFlags |= OVERFLOW_MASK; } regA = res; flagQ = true; } // Resta con acarreo de 16 bits private void sbc16(int reg16) { int regHL = getRegHL(); memptr = regHL + 1; int res = regHL - reg16; if (carryFlag) { res--; } carryFlag = res < 0; res &= 0xffff; setRegHL(res); sz5h3pnFlags = sz53n_subTable[regH]; if (res != 0) { sz5h3pnFlags &= ~ZERO_MASK; } if (((res ^ regHL ^ reg16) & 0x1000) != 0) { sz5h3pnFlags |= HALFCARRY_MASK; } if (((regHL ^ reg16) & (regHL ^ res)) > 0x7fff) { sz5h3pnFlags |= OVERFLOW_MASK; } flagQ = true; } // Operación AND lógica private void and(int oper8) { regA &= oper8; carryFlag = false; sz5h3pnFlags = sz53pn_addTable[regA] | HALFCARRY_MASK; flagQ = true; } // Operación XOR lógica private void xor(int oper8) { regA = (regA ^ oper8) & 0xff; carryFlag = false; sz5h3pnFlags = sz53pn_addTable[regA]; flagQ = true; } // Operación OR lógica private void or(int oper8) { regA = (regA | oper8) & 0xff; carryFlag = false; sz5h3pnFlags = sz53pn_addTable[regA]; flagQ = true; } // Operación de comparación con el registro A // es como SUB, pero solo afecta a los flags // Los flags SIGN y ZERO se calculan a partir del resultado // Los flags 3 y 5 se copian desde el operando (sigh!) private void cp(int oper8) { int res = regA - (oper8 & 0xff); carryFlag = res < 0; res &= 0xff; sz5h3pnFlags = (sz53n_addTable[oper8] & FLAG_53_MASK) | // No necesito preservar H, pero está a 0 en la tabla de todas formas (sz53n_subTable[res] & FLAG_SZHN_MASK); if ((res & 0x0f) > (regA & 0x0f)) { sz5h3pnFlags |= HALFCARRY_MASK; } if (((regA ^ oper8) & (regA ^ res)) > 0x7f) { sz5h3pnFlags |= OVERFLOW_MASK; } flagQ = true; } // DAA private void daa() { int suma = 0; boolean carry = carryFlag; if ((sz5h3pnFlags & HALFCARRY_MASK) != 0 || (regA & 0x0f) > 0x09) { suma = 6; } if (carry || (regA > 0x99)) { suma |= 0x60; } if (regA > 0x99) { carry = true; } if ((sz5h3pnFlags & ADDSUB_MASK) != 0) { sub(suma); sz5h3pnFlags = (sz5h3pnFlags & HALFCARRY_MASK) | sz53pn_subTable[regA]; } else { add(suma); sz5h3pnFlags = (sz5h3pnFlags & HALFCARRY_MASK) | sz53pn_addTable[regA]; } carryFlag = carry; // Los add/sub ya ponen el resto de los flags flagQ = true; } // POP private int pop() { int word = MemIoImpl.peek16(regSP); regSP = (regSP + 2) & 0xffff; return word; } // PUSH private void push(int word) { regSP = (regSP - 1) & 0xffff; MemIoImpl.poke8(regSP, word >>> 8); regSP = (regSP - 1) & 0xffff; MemIoImpl.poke8(regSP, word); } // LDI private void ldi() { int work8 = MemIoImpl.peek8(getRegHL()); int regDE = getRegDE(); MemIoImpl.poke8(regDE, work8); MemIoImpl.addressOnBus(regDE, 2); incRegHL(); incRegDE(); decRegBC(); work8 += regA; sz5h3pnFlags = (sz5h3pnFlags & FLAG_SZ_MASK) | (work8 & BIT3_MASK); if ((work8 & ADDSUB_MASK) != 0) { sz5h3pnFlags |= BIT5_MASK; } if (regC != 0 || regB != 0) { sz5h3pnFlags |= PARITY_MASK; } flagQ = true; } // LDD private void ldd() { int work8 = MemIoImpl.peek8(getRegHL()); int regDE = getRegDE(); MemIoImpl.poke8(regDE, work8); MemIoImpl.addressOnBus(regDE, 2); decRegHL(); decRegDE(); decRegBC(); work8 += regA; sz5h3pnFlags = (sz5h3pnFlags & FLAG_SZ_MASK) | (work8 & BIT3_MASK); if ((work8 & ADDSUB_MASK) != 0) { sz5h3pnFlags |= BIT5_MASK; } if (regC != 0 || regB != 0) { sz5h3pnFlags |= PARITY_MASK; } flagQ = true; } // CPI private void cpi() { int regHL = getRegHL(); int memHL = MemIoImpl.peek8(regHL); boolean carry = carryFlag; // lo guardo porque cp lo toca cp(memHL); carryFlag = carry; MemIoImpl.addressOnBus(regHL, 5); incRegHL(); decRegBC(); memHL = regA - memHL - ((sz5h3pnFlags & HALFCARRY_MASK) != 0 ? 1 : 0); sz5h3pnFlags = (sz5h3pnFlags & FLAG_SZHN_MASK) | (memHL & BIT3_MASK); if ((memHL & ADDSUB_MASK) != 0) { sz5h3pnFlags |= BIT5_MASK; } if (regC != 0 || regB != 0) { sz5h3pnFlags |= PARITY_MASK; } memptr++; flagQ = true; } // CPD private void cpd() { int regHL = getRegHL(); int memHL = MemIoImpl.peek8(regHL); boolean carry = carryFlag; // lo guardo porque cp lo toca cp(memHL); carryFlag = carry; MemIoImpl.addressOnBus(regHL, 5); decRegHL(); decRegBC(); memHL = regA - memHL - ((sz5h3pnFlags & HALFCARRY_MASK) != 0 ? 1 : 0); sz5h3pnFlags = (sz5h3pnFlags & FLAG_SZHN_MASK) | (memHL & BIT3_MASK); if ((memHL & ADDSUB_MASK) != 0) { sz5h3pnFlags |= BIT5_MASK; } if (regC != 0 || regB != 0) { sz5h3pnFlags |= PARITY_MASK; } memptr--; flagQ = true; } // INI private void ini() { memptr = getRegBC(); MemIoImpl.addressOnBus(getPairIR(), 1); int work8 = MemIoImpl.inPort(memptr); MemIoImpl.poke8(getRegHL(), work8); memptr++; regB = (regB - 1) & 0xff; incRegHL(); sz5h3pnFlags = sz53pn_addTable[regB]; if (work8 > 0x7f) { sz5h3pnFlags |= ADDSUB_MASK; } carryFlag = false; int tmp = work8 + ((regC + 1) & 0xff); if (tmp > 0xff) { sz5h3pnFlags |= HALFCARRY_MASK; carryFlag = true; } if ((sz53pn_addTable[((tmp & 0x07) ^ regB)] & PARITY_MASK) == PARITY_MASK) { sz5h3pnFlags |= PARITY_MASK; } else { sz5h3pnFlags &= ~PARITY_MASK; } flagQ = true; } // IND private void ind() { memptr = getRegBC(); MemIoImpl.addressOnBus(getPairIR(), 1); int work8 = MemIoImpl.inPort(memptr); MemIoImpl.poke8(getRegHL(), work8); memptr--; regB = (regB - 1) & 0xff; decRegHL(); sz5h3pnFlags = sz53pn_addTable[regB]; if (work8 > 0x7f) { sz5h3pnFlags |= ADDSUB_MASK; } carryFlag = false; int tmp = work8 + ((regC - 1) & 0xff); if (tmp > 0xff) { sz5h3pnFlags |= HALFCARRY_MASK; carryFlag = true; } if ((sz53pn_addTable[((tmp & 0x07) ^ regB)] & PARITY_MASK) == PARITY_MASK) { sz5h3pnFlags |= PARITY_MASK; } else { sz5h3pnFlags &= ~PARITY_MASK; } flagQ = true; } // OUTI private void outi() { MemIoImpl.addressOnBus(getPairIR(), 1); regB = (regB - 1) & 0xff; memptr = getRegBC(); int work8 = MemIoImpl.peek8(getRegHL()); MemIoImpl.outPort(memptr, work8); memptr++; incRegHL(); carryFlag = false; if (work8 > 0x7f) { sz5h3pnFlags = sz53n_subTable[regB]; } else { sz5h3pnFlags = sz53n_addTable[regB]; } if ((regL + work8) > 0xff) { sz5h3pnFlags |= HALFCARRY_MASK; carryFlag = true; } if ((sz53pn_addTable[(((regL + work8) & 0x07) ^ regB)] & PARITY_MASK) == PARITY_MASK) { sz5h3pnFlags |= PARITY_MASK; } flagQ = true; } // OUTD private void outd() { MemIoImpl.addressOnBus(getPairIR(), 1); regB = (regB - 1) & 0xff; memptr = getRegBC(); int work8 = MemIoImpl.peek8(getRegHL()); MemIoImpl.outPort(memptr, work8); memptr--; decRegHL(); carryFlag = false; if (work8 > 0x7f) { sz5h3pnFlags = sz53n_subTable[regB]; } else { sz5h3pnFlags = sz53n_addTable[regB]; } if ((regL + work8) > 0xff) { sz5h3pnFlags |= HALFCARRY_MASK; carryFlag = true; } if ((sz53pn_addTable[(((regL + work8) & 0x07) ^ regB)] & PARITY_MASK) == PARITY_MASK) { sz5h3pnFlags |= PARITY_MASK; } flagQ = true; } // Pone a 1 el Flag Z si el bit b del registro // r es igual a 0 /* * En contra de lo que afirma el Z80-Undocumented, los bits 3 y 5 toman * SIEMPRE el valor de los bits correspondientes del valor a comparar para * las instrucciones BIT n,r. Para BIT n,(HL) toman el valor del registro * escondido (memptr), y para las BIT n, (IX/IY+n) toman el valor de los * bits superiores de la dirección indicada por IX/IY+n. * * 04/12/08 Confirmado el comentario anterior: * http://scratchpad.wikia.com/wiki/Z80 */ private void bit(int mask, int reg) { boolean zeroFlag = (mask & reg) == 0; sz5h3pnFlags = (sz53n_addTable[reg] & ~FLAG_SZP_MASK) | HALFCARRY_MASK; if (zeroFlag) { sz5h3pnFlags |= (PARITY_MASK | ZERO_MASK); } if (mask == SIGN_MASK && !zeroFlag) { sz5h3pnFlags |= SIGN_MASK; } flagQ = true; } //Interrupción /* Desglose de la interrupción, según el modo: * IM0: * M1: 7 T-Estados -> reconocer INT y decSP * M2: 3 T-Estados -> escribir byte alto y decSP * M3: 3 T-Estados -> escribir byte bajo y salto a N * IM1: * M1: 7 T-Estados -> reconocer INT y decSP * M2: 3 T-Estados -> escribir byte alto PC y decSP * M3: 3 T-Estados -> escribir byte bajo PC y PC=0x0038 * IM2: * M1: 7 T-Estados -> reconocer INT y decSP * M2: 3 T-Estados -> escribir byte alto y decSP * M3: 3 T-Estados -> escribir byte bajo * M4: 3 T-Estados -> leer byte bajo del vector de INT * M5: 3 T-Estados -> leer byte alto y saltar a la rutina de INT */ private void interruption() { //System.out.println(String.format("INT at %d T-States", tEstados)); // int tmp = tEstados; // peek8 modifica los tEstados lastFlagQ = false; // Si estaba en un HALT esperando una INT, lo saca de la espera if (halted) { halted = false; regPC = (regPC + 1) & 0xffff; } MemIoImpl.interruptHandlingTime(7); regR++; ffIFF1 = ffIFF2 = false; push(regPC); // el push a�adir� 6 t-estados (+contended si toca) if (modeINT == IntMode.IM2) { regPC = MemIoImpl.peek16((regI << 8) | 0xff); // +6 t-estados } else { regPC = 0x0038; } memptr = regPC; //System.out.println(String.format("Coste INT: %d", tEstados-tmp)); } //Interrupción NMI, no utilizado por ahora /* Desglose de ciclos de máquina y T-Estados * M1: 5 T-Estados -> extraer opcode (pá ná, es tontería) y decSP * M2: 3 T-Estados -> escribe byte alto de PC y decSP * M3: 3 T-Estados -> escribe byte bajo de PC y PC=0x0066 */ private void nmi() { lastFlagQ = false; // Esta lectura consigue dos cosas: // 1.- La lectura del opcode del M1 que se descarta // 2.- Si estaba en un HALT esperando una INT, lo saca de la espera MemIoImpl.fetchOpcode(regPC); MemIoImpl.interruptHandlingTime(1); if (halted) { halted = false; regPC = (regPC + 1) & 0xffff; } regR++; ffIFF1 = false; push(regPC); // 3+3 t-estados + contended si procede regPC = memptr = 0x0066; } public final boolean isBreakpoint(int address) { return breakpointAt[address & 0xffff]; } public final void setBreakpoint(int address, boolean state) { breakpointAt[address & 0xffff] = state; } public void resetBreakpoints() { Arrays.fill(breakpointAt, false); } public boolean isExecDone() { return execDone; } public void setExecDone(boolean state) { execDone = state; } /* Los tEstados transcurridos se calculan teniendo en cuenta el número de * ciclos de máquina reales que se ejecutan. Esa es la única forma de poder * simular la contended memory del Spectrum. */ public final void execute() { int opCode = MemIoImpl.fetchOpcode(regPC); regR++; if (prefixOpcode == 0 && breakpointAt[regPC]) { opCode = NotifyImpl.breakpoint(regPC, opCode); } regPC = (regPC + 1) & 0xffff; flagQ = false; // El prefijo 0xCB no cuenta para esta guerra. // En CBxx todas las xx producen un código válido // de instrucción, incluyendo CBCB. switch (prefixOpcode) { case 0x00: decodeOpcode(opCode); break; case 0xDD: regIX = decodeDDFD(opCode, regIX); break; case 0xED: decodeED(opCode); break; case 0xFD: regIY = decodeDDFD(opCode, regIY); break; default: System.out.println(String.format("ERROR!: prefixOpcode = %02x, opCode = %02x", prefixOpcode, opCode)); } if (prefixOpcode != 0x00) { return; } lastFlagQ = flagQ; // Si está pendiente la activación de la interrupción y el // código que se acaba de ejecutar no es el propio EI if (pendingEI && opCode != 0xFB) { pendingEI = false; } if (execDone) { NotifyImpl.execDone(); } // Primero se comprueba NMI // Si se activa NMI no se comprueba INT porque la siguiente // instrucción debe ser la de 0x0066. if (activeNMI) { activeNMI = false; nmi(); return; } // Ahora se comprueba si hay una INT if (ffIFF1 && !pendingEI && MemIoImpl.isActiveINT()) { interruption(); } } private void decodeOpcode(int opCode) { switch (opCode) { // case 0x00: /* NOP */ // break; case 0x01: { /* LD BC,nn */ setRegBC(MemIoImpl.peek16(regPC)); regPC = (regPC + 2) & 0xffff; break; } case 0x02: { /* LD (BC),A */ MemIoImpl.poke8(getRegBC(), regA); memptr = (regA << 8) | ((regC + 1) & 0xff); break; } case 0x03: { /* INC BC */ MemIoImpl.addressOnBus(getPairIR(), 2); incRegBC(); break; } case 0x04: { /* INC B */ regB = inc8(regB); break; } case 0x05: { /* DEC B */ regB = dec8(regB); break; } case 0x06: { /* LD B,n */ regB = MemIoImpl.peek8(regPC); regPC = (regPC + 1) & 0xffff; break; } case 0x07: { /* RLCA */ carryFlag = (regA > 0x7f); regA = (regA << 1) & 0xff; if (carryFlag) { regA |= CARRY_MASK; } sz5h3pnFlags = (sz5h3pnFlags & FLAG_SZP_MASK) | (regA & FLAG_53_MASK); flagQ = true; break; } case 0x08: { /* EX AF,AF' */ int work8 = regA; regA = regAx; regAx = work8; work8 = getFlags(); setFlags(regFx); regFx = work8; break; } case 0x09: { /* ADD HL,BC */ MemIoImpl.addressOnBus(getPairIR(), 7); setRegHL(add16(getRegHL(), getRegBC())); break; } case 0x0A: { /* LD A,(BC) */ memptr = getRegBC(); regA = MemIoImpl.peek8(memptr++); break; } case 0x0B: { /* DEC BC */ MemIoImpl.addressOnBus(getPairIR(), 2); decRegBC(); break; } case 0x0C: { /* INC C */ regC = inc8(regC); break; } case 0x0D: { /* DEC C */ regC = dec8(regC); break; } case 0x0E: { /* LD C,n */ regC = MemIoImpl.peek8(regPC); regPC = (regPC + 1) & 0xffff; break; } case 0x0F: { /* RRCA */ carryFlag = (regA & CARRY_MASK) != 0; regA >>>= 1; if (carryFlag) { regA |= SIGN_MASK; } sz5h3pnFlags = (sz5h3pnFlags & FLAG_SZP_MASK) | (regA & FLAG_53_MASK); flagQ = true; break; } case 0x10: { /* DJNZ e */ MemIoImpl.addressOnBus(getPairIR(), 1); byte offset = (byte) MemIoImpl.peek8(regPC); regB--; if (regB != 0) { regB &= 0xff; MemIoImpl.addressOnBus(regPC, 5); regPC = memptr = (regPC + offset + 1) & 0xffff; } else { regPC = (regPC + 1) & 0xffff; } break; } case 0x11: { /* LD DE,nn */ setRegDE(MemIoImpl.peek16(regPC)); regPC = (regPC + 2) & 0xffff; break; } case 0x12: { /* LD (DE),A */ MemIoImpl.poke8(getRegDE(), regA); memptr = (regA << 8) | ((regE + 1) & 0xff); break; } case 0x13: { /* INC DE */ MemIoImpl.addressOnBus(getPairIR(), 2); incRegDE(); break; } case 0x14: { /* INC D */ regD = inc8(regD); break; } case 0x15: { /* DEC D */ regD = dec8(regD); break; } case 0x16: { /* LD D,n */ regD = MemIoImpl.peek8(regPC); regPC = (regPC + 1) & 0xffff; break; } case 0x17: { /* RLA */ boolean oldCarry = carryFlag; carryFlag = (regA > 0x7f); regA = (regA << 1) & 0xff; if (oldCarry) { regA |= CARRY_MASK; } sz5h3pnFlags = (sz5h3pnFlags & FLAG_SZP_MASK) | (regA & FLAG_53_MASK); flagQ = true; break; } case 0x18: { /* JR e */ byte offset = (byte) MemIoImpl.peek8(regPC); MemIoImpl.addressOnBus(regPC, 5); regPC = memptr = (regPC + offset + 1) & 0xffff; break; } case 0x19: { /* ADD HL,DE */ MemIoImpl.addressOnBus(getPairIR(), 7); setRegHL(add16(getRegHL(), getRegDE())); break; } case 0x1A: { /* LD A,(DE) */ memptr = getRegDE(); regA = MemIoImpl.peek8(memptr++); break; } case 0x1B: { /* DEC DE */ MemIoImpl.addressOnBus(getPairIR(), 2); decRegDE(); break; } case 0x1C: { /* INC E */ regE = inc8(regE); break; } case 0x1D: { /* DEC E */ regE = dec8(regE); break; } case 0x1E: { /* LD E,n */ regE = MemIoImpl.peek8(regPC); regPC = (regPC + 1) & 0xffff; break; } case 0x1F: { /* RRA */ boolean oldCarry = carryFlag; carryFlag = (regA & CARRY_MASK) != 0; regA >>>= 1; if (oldCarry) { regA |= SIGN_MASK; } sz5h3pnFlags = (sz5h3pnFlags & FLAG_SZP_MASK) | (regA & FLAG_53_MASK); flagQ = true; break; } case 0x20: { /* JR NZ,e */ byte offset = (byte) MemIoImpl.peek8(regPC); if ((sz5h3pnFlags & ZERO_MASK) == 0) { MemIoImpl.addressOnBus(regPC, 5); regPC += offset; memptr = regPC + 1; } regPC = (regPC + 1) & 0xffff; break; } case 0x21: { /* LD HL,nn */ setRegHL(MemIoImpl.peek16(regPC)); regPC = (regPC + 2) & 0xffff; break; } case 0x22: { /* LD (nn),HL */ memptr = MemIoImpl.peek16(regPC); MemIoImpl.poke16(memptr++, getRegHL()); regPC = (regPC + 2) & 0xffff; break; } case 0x23: { /* INC HL */ MemIoImpl.addressOnBus(getPairIR(), 2); incRegHL(); break; } case 0x24: { /* INC H */ regH = inc8(regH); break; } case 0x25: { /* DEC H */ regH = dec8(regH); break; } case 0x26: { /* LD H,n */ regH = MemIoImpl.peek8(regPC); regPC = (regPC + 1) & 0xffff; break; } case 0x27: { /* DAA */ daa(); break; } case 0x28: { /* JR Z,e */ byte offset = (byte) MemIoImpl.peek8(regPC); if ((sz5h3pnFlags & ZERO_MASK) != 0) { MemIoImpl.addressOnBus(regPC, 5); regPC += offset; memptr = regPC + 1; } regPC = (regPC + 1) & 0xffff; break; } case 0x29: { /* ADD HL,HL */ MemIoImpl.addressOnBus(getPairIR(), 7); int work16 = getRegHL(); setRegHL(add16(work16, work16)); break; } case 0x2A: { /* LD HL,(nn) */ memptr = MemIoImpl.peek16(regPC); setRegHL(MemIoImpl.peek16(memptr++)); regPC = (regPC + 2) & 0xffff; break; } case 0x2B: { /* DEC HL */ MemIoImpl.addressOnBus(getPairIR(), 2); decRegHL(); break; } case 0x2C: { /* INC L */ regL = inc8(regL); break; } case 0x2D: { /* DEC L */ regL = dec8(regL); break; } case 0x2E: { /* LD L,n */ regL = MemIoImpl.peek8(regPC); regPC = (regPC + 1) & 0xffff; break; } case 0x2F: { /* CPL */ regA ^= 0xff; sz5h3pnFlags = (sz5h3pnFlags & FLAG_SZP_MASK) | HALFCARRY_MASK | (regA & FLAG_53_MASK) | ADDSUB_MASK; flagQ = true; break; } case 0x30: { /* JR NC,e */ byte offset = (byte) MemIoImpl.peek8(regPC); if (!carryFlag) { MemIoImpl.addressOnBus(regPC, 5); regPC += offset; memptr = regPC + 1; } regPC = (regPC + 1) & 0xffff; break; } case 0x31: { /* LD SP,nn */ regSP = MemIoImpl.peek16(regPC); regPC = (regPC + 2) & 0xffff; break; } case 0x32: { /* LD (nn),A */ memptr = MemIoImpl.peek16(regPC); MemIoImpl.poke8(memptr, regA); memptr = (regA << 8) | ((memptr + 1) & 0xff); regPC = (regPC + 2) & 0xffff; break; } case 0x33: { /* INC SP */ MemIoImpl.addressOnBus(getPairIR(), 2); regSP = (regSP + 1) & 0xffff; break; } case 0x34: { /* INC (HL) */ int work16 = getRegHL(); int work8 = inc8(MemIoImpl.peek8(work16)); MemIoImpl.addressOnBus(work16, 1); MemIoImpl.poke8(work16, work8); break; } case 0x35: { /* DEC (HL) */ int work16 = getRegHL(); int work8 = dec8(MemIoImpl.peek8(work16)); MemIoImpl.addressOnBus(work16, 1); MemIoImpl.poke8(work16, work8); break; } case 0x36: { /* LD (HL),n */ MemIoImpl.poke8(getRegHL(), MemIoImpl.peek8(regPC)); regPC = (regPC + 1) & 0xffff; break; } case 0x37: { /* SCF */ int regQ = lastFlagQ ? sz5h3pnFlags : 0; carryFlag = true; sz5h3pnFlags = (sz5h3pnFlags & FLAG_SZP_MASK) | (((regQ ^ sz5h3pnFlags) | regA) & FLAG_53_MASK); flagQ = true; break; } case 0x38: { /* JR C,e */ byte offset = (byte) MemIoImpl.peek8(regPC); if (carryFlag) { MemIoImpl.addressOnBus(regPC, 5); regPC += offset; memptr = regPC + 1; } regPC = (regPC + 1) & 0xffff; break; } case 0x39: { /* ADD HL,SP */ MemIoImpl.addressOnBus(getPairIR(), 7); setRegHL(add16(getRegHL(), regSP)); break; } case 0x3A: { /* LD A,(nn) */ memptr = MemIoImpl.peek16(regPC); regA = MemIoImpl.peek8(memptr++); regPC = (regPC + 2) & 0xffff; break; } case 0x3B: { /* DEC SP */ MemIoImpl.addressOnBus(getPairIR(), 2); regSP = (regSP - 1) & 0xffff; break; } case 0x3C: { /* INC A */ regA = inc8(regA); break; } case 0x3D: { /* DEC A */ regA = dec8(regA); break; } case 0x3E: { /* LD A,n */ regA = MemIoImpl.peek8(regPC); regPC = (regPC + 1) & 0xffff; break; } case 0x3F: { /* CCF */ int regQ = lastFlagQ ? sz5h3pnFlags : 0; sz5h3pnFlags = (sz5h3pnFlags & FLAG_SZP_MASK) | (((regQ ^ sz5h3pnFlags) | regA) & FLAG_53_MASK); if (carryFlag) { sz5h3pnFlags |= HALFCARRY_MASK; } carryFlag = !carryFlag; flagQ = true; break; } // case 0x40: { /* LD B,B */ // break; // } case 0x41: { /* LD B,C */ regB = regC; break; } case 0x42: { /* LD B,D */ regB = regD; break; } case 0x43: { /* LD B,E */ regB = regE; break; } case 0x44: { /* LD B,H */ regB = regH; break; } case 0x45: { /* LD B,L */ regB = regL; break; } case 0x46: { /* LD B,(HL) */ regB = MemIoImpl.peek8(getRegHL()); break; } case 0x47: { /* LD B,A */ regB = regA; break; } case 0x48: { /* LD C,B */ regC = regB; break; } // case 0x49: { /* LD C,C */ // break; // } case 0x4A: { /* LD C,D */ regC = regD; break; } case 0x4B: { /* LD C,E */ regC = regE; break; } case 0x4C: { /* LD C,H */ regC = regH; break; } case 0x4D: { /* LD C,L */ regC = regL; break; } case 0x4E: { /* LD C,(HL) */ regC = MemIoImpl.peek8(getRegHL()); break; } case 0x4F: { /* LD C,A */ regC = regA; break; } case 0x50: { /* LD D,B */ regD = regB; break; } case 0x51: { /* LD D,C */ regD = regC; break; } // case 0x52: { /* LD D,D */ // break; // } case 0x53: { /* LD D,E */ regD = regE; break; } case 0x54: { /* LD D,H */ regD = regH; break; } case 0x55: { /* LD D,L */ regD = regL; break; } case 0x56: { /* LD D,(HL) */ regD = MemIoImpl.peek8(getRegHL()); break; } case 0x57: { /* LD D,A */ regD = regA; break; } case 0x58: { /* LD E,B */ regE = regB; break; } case 0x59: { /* LD E,C */ regE = regC; break; } case 0x5A: { /* LD E,D */ regE = regD; break; } // case 0x5B: { /* LD E,E */ // break; // } case 0x5C: { /* LD E,H */ regE = regH; break; } case 0x5D: { /* LD E,L */ regE = regL; break; } case 0x5E: { /* LD E,(HL) */ regE = MemIoImpl.peek8(getRegHL()); break; } case 0x5F: { /* LD E,A */ regE = regA; break; } case 0x60: { /* LD H,B */ regH = regB; break; } case 0x61: { /* LD H,C */ regH = regC; break; } case 0x62: { /* LD H,D */ regH = regD; break; } case 0x63: { /* LD H,E */ regH = regE; break; } // case 0x64: { /* LD H,H */ // break; // } case 0x65: { /* LD H,L */ regH = regL; break; } case 0x66: { /* LD H,(HL) */ regH = MemIoImpl.peek8(getRegHL()); break; } case 0x67: { /* LD H,A */ regH = regA; break; } case 0x68: { /* LD L,B */ regL = regB; break; } case 0x69: { /* LD L,C */ regL = regC; break; } case 0x6A: { /* LD L,D */ regL = regD; break; } case 0x6B: { /* LD L,E */ regL = regE; break; } case 0x6C: { /* LD L,H */ regL = regH; break; } // case 0x6D: { /* LD L,L */ // break; // } case 0x6E: { /* LD L,(HL) */ regL = MemIoImpl.peek8(getRegHL()); break; } case 0x6F: { /* LD L,A */ regL = regA; break; } case 0x70: { /* LD (HL),B */ MemIoImpl.poke8(getRegHL(), regB); break; } case 0x71: { /* LD (HL),C */ MemIoImpl.poke8(getRegHL(), regC); break; } case 0x72: { /* LD (HL),D */ MemIoImpl.poke8(getRegHL(), regD); break; } case 0x73: { /* LD (HL),E */ MemIoImpl.poke8(getRegHL(), regE); break; } case 0x74: { /* LD (HL),H */ MemIoImpl.poke8(getRegHL(), regH); break; } case 0x75: { /* LD (HL),L */ MemIoImpl.poke8(getRegHL(), regL); break; } case 0x76: { /* HALT */ regPC = (regPC - 1) & 0xffff; halted = true; break; } case 0x77: { /* LD (HL),A */ MemIoImpl.poke8(getRegHL(), regA); break; } case 0x78: { /* LD A,B */ regA = regB; break; } case 0x79: { /* LD A,C */ regA = regC; break; } case 0x7A: { /* LD A,D */ regA = regD; break; } case 0x7B: { /* LD A,E */ regA = regE; break; } case 0x7C: { /* LD A,H */ regA = regH; break; } case 0x7D: { /* LD A,L */ regA = regL; break; } case 0x7E: { /* LD A,(HL) */ regA = MemIoImpl.peek8(getRegHL()); break; } // case 0x7F: { /* LD A,A */ // break; // } case 0x80: { /* ADD A,B */ add(regB); break; } case 0x81: { /* ADD A,C */ add(regC); break; } case 0x82: { /* ADD A,D */ add(regD); break; } case 0x83: { /* ADD A,E */ add(regE); break; } case 0x84: { /* ADD A,H */ add(regH); break; } case 0x85: { /* ADD A,L */ add(regL); break; } case 0x86: { /* ADD A,(HL) */ add(MemIoImpl.peek8(getRegHL())); break; } case 0x87: { /* ADD A,A */ add(regA); break; } case 0x88: { /* ADC A,B */ adc(regB); break; } case 0x89: { /* ADC A,C */ adc(regC); break; } case 0x8A: { /* ADC A,D */ adc(regD); break; } case 0x8B: { /* ADC A,E */ adc(regE); break; } case 0x8C: { /* ADC A,H */ adc(regH); break; } case 0x8D: { /* ADC A,L */ adc(regL); break; } case 0x8E: { /* ADC A,(HL) */ adc(MemIoImpl.peek8(getRegHL())); break; } case 0x8F: { /* ADC A,A */ adc(regA); break; } case 0x90: { /* SUB B */ sub(regB); break; } case 0x91: { /* SUB C */ sub(regC); break; } case 0x92: { /* SUB D */ sub(regD); break; } case 0x93: { /* SUB E */ sub(regE); break; } case 0x94: { /* SUB H */ sub(regH); break; } case 0x95: { /* SUB L */ sub(regL); break; } case 0x96: { /* SUB (HL) */ sub(MemIoImpl.peek8(getRegHL())); break; } case 0x97: { /* SUB A */ sub(regA); break; } case 0x98: { /* SBC A,B */ sbc(regB); break; } case 0x99: { /* SBC A,C */ sbc(regC); break; } case 0x9A: { /* SBC A,D */ sbc(regD); break; } case 0x9B: { /* SBC A,E */ sbc(regE); break; } case 0x9C: { /* SBC A,H */ sbc(regH); break; } case 0x9D: { /* SBC A,L */ sbc(regL); break; } case 0x9E: { /* SBC A,(HL) */ sbc(MemIoImpl.peek8(getRegHL())); break; } case 0x9F: { /* SBC A,A */ sbc(regA); break; } case 0xA0: { /* AND B */ and(regB); break; } case 0xA1: { /* AND C */ and(regC); break; } case 0xA2: { /* AND D */ and(regD); break; } case 0xA3: { /* AND E */ and(regE); break; } case 0xA4: { /* AND H */ and(regH); break; } case 0xA5: { /* AND L */ and(regL); break; } case 0xA6: { /* AND (HL) */ and(MemIoImpl.peek8(getRegHL())); break; } case 0xA7: { /* AND A */ and(regA); break; } case 0xA8: { /* XOR B */ xor(regB); break; } case 0xA9: { /* XOR C */ xor(regC); break; } case 0xAA: { /* XOR D */ xor(regD); break; } case 0xAB: { /* XOR E */ xor(regE); break; } case 0xAC: { /* XOR H */ xor(regH); break; } case 0xAD: { /* XOR L */ xor(regL); break; } case 0xAE: { /* XOR (HL) */ xor(MemIoImpl.peek8(getRegHL())); break; } case 0xAF: { /* XOR A */ xor(regA); break; } case 0xB0: { /* OR B */ or(regB); break; } case 0xB1: { /* OR C */ or(regC); break; } case 0xB2: { /* OR D */ or(regD); break; } case 0xB3: { /* OR E */ or(regE); break; } case 0xB4: { /* OR H */ or(regH); break; } case 0xB5: { /* OR L */ or(regL); break; } case 0xB6: { /* OR (HL) */ or(MemIoImpl.peek8(getRegHL())); break; } case 0xB7: { /* OR A */ or(regA); break; } case 0xB8: { /* CP B */ cp(regB); break; } case 0xB9: { /* CP C */ cp(regC); break; } case 0xBA: { /* CP D */ cp(regD); break; } case 0xBB: { /* CP E */ cp(regE); break; } case 0xBC: { /* CP H */ cp(regH); break; } case 0xBD: { /* CP L */ cp(regL); break; } case 0xBE: { /* CP (HL) */ cp(MemIoImpl.peek8(getRegHL())); break; } case 0xBF: { /* CP A */ cp(regA); break; } case 0xC0: { /* RET NZ */ MemIoImpl.addressOnBus(getPairIR(), 1); if ((sz5h3pnFlags & ZERO_MASK) == 0) { regPC = memptr = pop(); } break; } case 0xC1: { /* POP BC */ setRegBC(pop()); break; } case 0xC2: { /* JP NZ,nn */ memptr = MemIoImpl.peek16(regPC); if ((sz5h3pnFlags & ZERO_MASK) == 0) { regPC = memptr; break; } regPC = (regPC + 2) & 0xffff; break; } case 0xC3: { /* JP nn */ memptr = regPC = MemIoImpl.peek16(regPC); break; } case 0xC4: { /* CALL NZ,nn */ memptr = MemIoImpl.peek16(regPC); if ((sz5h3pnFlags & ZERO_MASK) == 0) { MemIoImpl.addressOnBus((regPC + 1) & 0xffff, 1); push(regPC + 2); regPC = memptr; break; } regPC = (regPC + 2) & 0xffff; break; } case 0xC5: { /* PUSH BC */ MemIoImpl.addressOnBus(getPairIR(), 1); push(getRegBC()); break; } case 0xC6: { /* ADD A,n */ add(MemIoImpl.peek8(regPC)); regPC = (regPC + 1) & 0xffff; break; } case 0xC7: { /* RST 00H */ MemIoImpl.addressOnBus(getPairIR(), 1); push(regPC); regPC = memptr = 0x00; break; } case 0xC8: { /* RET Z */ MemIoImpl.addressOnBus(getPairIR(), 1); if ((sz5h3pnFlags & ZERO_MASK) != 0) { regPC = memptr = pop(); } break; } case 0xC9: { /* RET */ regPC = memptr = pop(); break; } case 0xCA: { /* JP Z,nn */ memptr = MemIoImpl.peek16(regPC); if ((sz5h3pnFlags & ZERO_MASK) != 0) { regPC = memptr; break; } regPC = (regPC + 2) & 0xffff; break; } case 0xCB: { /* Subconjunto de instrucciones */ decodeCB(); break; } case 0xCC: { /* CALL Z,nn */ memptr = MemIoImpl.peek16(regPC); if ((sz5h3pnFlags & ZERO_MASK) != 0) { MemIoImpl.addressOnBus((regPC + 1) & 0xffff, 1); push(regPC + 2); regPC = memptr; break; } regPC = (regPC + 2) & 0xffff; break; } case 0xCD: { /* CALL nn */ memptr = MemIoImpl.peek16(regPC); MemIoImpl.addressOnBus((regPC + 1) & 0xffff, 1); push(regPC + 2); regPC = memptr; break; } case 0xCE: { /* ADC A,n */ adc(MemIoImpl.peek8(regPC)); regPC = (regPC + 1) & 0xffff; break; } case 0xCF: { /* RST 08H */ MemIoImpl.addressOnBus(getPairIR(), 1); push(regPC); regPC = memptr = 0x08; break; } case 0xD0: { /* RET NC */ MemIoImpl.addressOnBus(getPairIR(), 1); if (!carryFlag) { regPC = memptr = pop(); } break; } case 0xD1: { /* POP DE */ setRegDE(pop()); break; } case 0xD2: { /* JP NC,nn */ memptr = MemIoImpl.peek16(regPC); if (!carryFlag) { regPC = memptr; break; } regPC = (regPC + 2) & 0xffff; break; } case 0xD3: { /* OUT (n),A */ int work8 = MemIoImpl.peek8(regPC); memptr = regA << 8; MemIoImpl.outPort(memptr | work8, regA); memptr |= ((work8 + 1) & 0xff); regPC = (regPC + 1) & 0xffff; break; } case 0xD4: { /* CALL NC,nn */ memptr = MemIoImpl.peek16(regPC); if (!carryFlag) { MemIoImpl.addressOnBus((regPC + 1) & 0xffff, 1); push(regPC + 2); regPC = memptr; break; } regPC = (regPC + 2) & 0xffff; break; } case 0xD5: { /* PUSH DE */ MemIoImpl.addressOnBus(getPairIR(), 1); push(getRegDE()); break; } case 0xD6: { /* SUB n */ sub(MemIoImpl.peek8(regPC)); regPC = (regPC + 1) & 0xffff; break; } case 0xD7: { /* RST 10H */ MemIoImpl.addressOnBus(getPairIR(), 1); push(regPC); regPC = memptr = 0x10; break; } case 0xD8: { /* RET C */ MemIoImpl.addressOnBus(getPairIR(), 1); if (carryFlag) { regPC = memptr = pop(); } break; } case 0xD9: { /* EXX */ int work8 = regB; regB = regBx; regBx = work8; work8 = regC; regC = regCx; regCx = work8; work8 = regD; regD = regDx; regDx = work8; work8 = regE; regE = regEx; regEx = work8; work8 = regH; regH = regHx; regHx = work8; work8 = regL; regL = regLx; regLx = work8; break; } case 0xDA: { /* JP C,nn */ memptr = MemIoImpl.peek16(regPC); if (carryFlag) { regPC = memptr; break; } regPC = (regPC + 2) & 0xffff; break; } case 0xDB: { /* IN A,(n) */ memptr = (regA << 8) | MemIoImpl.peek8(regPC); regA = MemIoImpl.inPort(memptr++); regPC = (regPC + 1) & 0xffff; break; } case 0xDC: { /* CALL C,nn */ memptr = MemIoImpl.peek16(regPC); if (carryFlag) { MemIoImpl.addressOnBus((regPC + 1) & 0xffff, 1); push(regPC + 2); regPC = memptr; break; } regPC = (regPC + 2) & 0xffff; break; } case 0xDD: { /* Subconjunto de instrucciones */ prefixOpcode = 0xDD; break; } case 0xDE: { /* SBC A,n */ sbc(MemIoImpl.peek8(regPC)); regPC = (regPC + 1) & 0xffff; break; } case 0xDF: { /* RST 18H */ MemIoImpl.addressOnBus(getPairIR(), 1); push(regPC); regPC = memptr = 0x18; break; } case 0xE0: /* RET PO */ MemIoImpl.addressOnBus(getPairIR(), 1); if ((sz5h3pnFlags & PARITY_MASK) == 0) { regPC = memptr = pop(); } break; case 0xE1: /* POP HL */ setRegHL(pop()); break; case 0xE2: /* JP PO,nn */ memptr = MemIoImpl.peek16(regPC); if ((sz5h3pnFlags & PARITY_MASK) == 0) { regPC = memptr; break; } regPC = (regPC + 2) & 0xffff; break; case 0xE3: { /* EX (SP),HL */ // Instrucción de ejecución sutil. int work16 = regH; int work8 = regL; setRegHL(MemIoImpl.peek16(regSP)); MemIoImpl.addressOnBus((regSP + 1) & 0xffff, 1); // No se usa poke16 porque el Z80 escribe los bytes AL REVES MemIoImpl.poke8((regSP + 1) & 0xffff, work16); MemIoImpl.poke8(regSP, work8); MemIoImpl.addressOnBus(regSP, 2); memptr = getRegHL(); break; } case 0xE4: /* CALL PO,nn */ memptr = MemIoImpl.peek16(regPC); if ((sz5h3pnFlags & PARITY_MASK) == 0) { MemIoImpl.addressOnBus((regPC + 1) & 0xffff, 1); push(regPC + 2); regPC = memptr; break; } regPC = (regPC + 2) & 0xffff; break; case 0xE5: /* PUSH HL */ MemIoImpl.addressOnBus(getPairIR(), 1); push(getRegHL()); break; case 0xE6: /* AND n */ and(MemIoImpl.peek8(regPC)); regPC = (regPC + 1) & 0xffff; break; case 0xE7: /* RST 20H */ MemIoImpl.addressOnBus(getPairIR(), 1); push(regPC); regPC = memptr = 0x20; break; case 0xE8: /* RET PE */ MemIoImpl.addressOnBus(getPairIR(), 1); if ((sz5h3pnFlags & PARITY_MASK) != 0) { regPC = memptr = pop(); } break; case 0xE9: /* JP (HL) */ regPC = getRegHL(); break; case 0xEA: /* JP PE,nn */ memptr = MemIoImpl.peek16(regPC); if ((sz5h3pnFlags & PARITY_MASK) != 0) { regPC = memptr; break; } regPC = (regPC + 2) & 0xffff; break; case 0xEB: { /* EX DE,HL */ int work8 = regH; regH = regD; regD = work8; work8 = regL; regL = regE; regE = work8; break; } case 0xEC: /* CALL PE,nn */ memptr = MemIoImpl.peek16(regPC); if ((sz5h3pnFlags & PARITY_MASK) != 0) { MemIoImpl.addressOnBus((regPC + 1) & 0xffff, 1); push(regPC + 2); regPC = memptr; break; } regPC = (regPC + 2) & 0xffff; break; case 0xED: /*Subconjunto de instrucciones*/ prefixOpcode = 0xED; break; case 0xEE: /* XOR n */ xor(MemIoImpl.peek8(regPC)); regPC = (regPC + 1) & 0xffff; break; case 0xEF: /* RST 28H */ MemIoImpl.addressOnBus(getPairIR(), 1); push(regPC); regPC = memptr = 0x28; break; case 0xF0: /* RET P */ MemIoImpl.addressOnBus(getPairIR(), 1); if (sz5h3pnFlags < SIGN_MASK) { regPC = memptr = pop(); } break; case 0xF1: /* POP AF */ setRegAF(pop()); break; case 0xF2: /* JP P,nn */ memptr = MemIoImpl.peek16(regPC); if (sz5h3pnFlags < SIGN_MASK) { regPC = memptr; break; } regPC = (regPC + 2) & 0xffff; break; case 0xF3: /* DI */ ffIFF1 = ffIFF2 = false; break; case 0xF4: /* CALL P,nn */ memptr = MemIoImpl.peek16(regPC); if (sz5h3pnFlags < SIGN_MASK) { MemIoImpl.addressOnBus((regPC + 1) & 0xffff, 1); push(regPC + 2); regPC = memptr; break; } regPC = (regPC + 2) & 0xffff; break; case 0xF5: /* PUSH AF */ MemIoImpl.addressOnBus(getPairIR(), 1); push(getRegAF()); break; case 0xF6: /* OR n */ or(MemIoImpl.peek8(regPC)); regPC = (regPC + 1) & 0xffff; break; case 0xF7: /* RST 30H */ MemIoImpl.addressOnBus(getPairIR(), 1); push(regPC); regPC = memptr = 0x30; break; case 0xF8: /* RET M */ MemIoImpl.addressOnBus(getPairIR(), 1); if (sz5h3pnFlags > 0x7f) { regPC = memptr = pop(); } break; case 0xF9: /* LD SP,HL */ MemIoImpl.addressOnBus(getPairIR(), 2); regSP = getRegHL(); break; case 0xFA: /* JP M,nn */ memptr = MemIoImpl.peek16(regPC); if (sz5h3pnFlags > 0x7f) { regPC = memptr; break; } regPC = (regPC + 2) & 0xffff; break; case 0xFB: /* EI */ ffIFF1 = ffIFF2 = true; pendingEI = true; break; case 0xFC: /* CALL M,nn */ memptr = MemIoImpl.peek16(regPC); if (sz5h3pnFlags > 0x7f) { MemIoImpl.addressOnBus((regPC + 1) & 0xffff, 1); push(regPC + 2); regPC = memptr; break; } regPC = (regPC + 2) & 0xffff; break; case 0xFD: /* Subconjunto de instrucciones */ prefixOpcode = 0xFD; break; case 0xFE: /* CP n */ cp(MemIoImpl.peek8(regPC)); regPC = (regPC + 1) & 0xffff; break; case 0xFF: /* RST 38H */ MemIoImpl.addressOnBus(getPairIR(), 1); push(regPC); regPC = memptr = 0x38; } /* del switch( codigo ) */ } //Subconjunto de instrucciones 0xCB private void decodeCB() { int opCode = MemIoImpl.fetchOpcode(regPC); regPC = (regPC + 1) & 0xffff; regR++; switch (opCode) { case 0x00: { /* RLC B */ regB = rlc(regB); break; } case 0x01: { /* RLC C */ regC = rlc(regC); break; } case 0x02: { /* RLC D */ regD = rlc(regD); break; } case 0x03: { /* RLC E */ regE = rlc(regE); break; } case 0x04: { /* RLC H */ regH = rlc(regH); break; } case 0x05: { /* RLC L */ regL = rlc(regL); break; } case 0x06: { /* RLC (HL) */ int work16 = getRegHL(); int work8 = rlc(MemIoImpl.peek8(work16)); MemIoImpl.addressOnBus(work16, 1); MemIoImpl.poke8(work16, work8); break; } case 0x07: { /* RLC A */ regA = rlc(regA); break; } case 0x08: { /* RRC B */ regB = rrc(regB); break; } case 0x09: { /* RRC C */ regC = rrc(regC); break; } case 0x0A: { /* RRC D */ regD = rrc(regD); break; } case 0x0B: { /* RRC E */ regE = rrc(regE); break; } case 0x0C: { /* RRC H */ regH = rrc(regH); break; } case 0x0D: { /* RRC L */ regL = rrc(regL); break; } case 0x0E: { /* RRC (HL) */ int work16 = getRegHL(); int work8 = rrc(MemIoImpl.peek8(work16)); MemIoImpl.addressOnBus(work16, 1); MemIoImpl.poke8(work16, work8); break; } case 0x0F: { /* RRC A */ regA = rrc(regA); break; } case 0x10: { /* RL B */ regB = rl(regB); break; } case 0x11: { /* RL C */ regC = rl(regC); break; } case 0x12: { /* RL D */ regD = rl(regD); break; } case 0x13: { /* RL E */ regE = rl(regE); break; } case 0x14: { /* RL H */ regH = rl(regH); break; } case 0x15: { /* RL L */ regL = rl(regL); break; } case 0x16: { /* RL (HL) */ int work16 = getRegHL(); int work8 = rl(MemIoImpl.peek8(work16)); MemIoImpl.addressOnBus(work16, 1); MemIoImpl.poke8(work16, work8); break; } case 0x17: { /* RL A */ regA = rl(regA); break; } case 0x18: { /* RR B */ regB = rr(regB); break; } case 0x19: { /* RR C */ regC = rr(regC); break; } case 0x1A: { /* RR D */ regD = rr(regD); break; } case 0x1B: { /* RR E */ regE = rr(regE); break; } case 0x1C: { /*RR H*/ regH = rr(regH); break; } case 0x1D: { /* RR L */ regL = rr(regL); break; } case 0x1E: { /* RR (HL) */ int work16 = getRegHL(); int work8 = rr(MemIoImpl.peek8(work16)); MemIoImpl.addressOnBus(work16, 1); MemIoImpl.poke8(work16, work8); break; } case 0x1F: { /* RR A */ regA = rr(regA); break; } case 0x20: { /* SLA B */ regB = sla(regB); break; } case 0x21: { /* SLA C */ regC = sla(regC); break; } case 0x22: { /* SLA D */ regD = sla(regD); break; } case 0x23: { /* SLA E */ regE = sla(regE); break; } case 0x24: { /* SLA H */ regH = sla(regH); break; } case 0x25: { /* SLA L */ regL = sla(regL); break; } case 0x26: { /* SLA (HL) */ int work16 = getRegHL(); int work8 = sla(MemIoImpl.peek8(work16)); MemIoImpl.addressOnBus(work16, 1); MemIoImpl.poke8(work16, work8); break; } case 0x27: { /* SLA A */ regA = sla(regA); break; } case 0x28: { /* SRA B */ regB = sra(regB); break; } case 0x29: { /* SRA C */ regC = sra(regC); break; } case 0x2A: { /* SRA D */ regD = sra(regD); break; } case 0x2B: { /* SRA E */ regE = sra(regE); break; } case 0x2C: { /* SRA H */ regH = sra(regH); break; } case 0x2D: { /* SRA L */ regL = sra(regL); break; } case 0x2E: { /* SRA (HL) */ int work16 = getRegHL(); int work8 = sra(MemIoImpl.peek8(work16)); MemIoImpl.addressOnBus(work16, 1); MemIoImpl.poke8(work16, work8); break; } case 0x2F: { /* SRA A */ regA = sra(regA); break; } case 0x30: { /* SLL B */ regB = sll(regB); break; } case 0x31: { /* SLL C */ regC = sll(regC); break; } case 0x32: { /* SLL D */ regD = sll(regD); break; } case 0x33: { /* SLL E */ regE = sll(regE); break; } case 0x34: { /* SLL H */ regH = sll(regH); break; } case 0x35: { /* SLL L */ regL = sll(regL); break; } case 0x36: { /* SLL (HL) */ int work16 = getRegHL(); int work8 = sll(MemIoImpl.peek8(work16)); MemIoImpl.addressOnBus(work16, 1); MemIoImpl.poke8(work16, work8); break; } case 0x37: { /* SLL A */ regA = sll(regA); break; } case 0x38: { /* SRL B */ regB = srl(regB); break; } case 0x39: { /* SRL C */ regC = srl(regC); break; } case 0x3A: { /* SRL D */ regD = srl(regD); break; } case 0x3B: { /* SRL E */ regE = srl(regE); break; } case 0x3C: { /* SRL H */ regH = srl(regH); break; } case 0x3D: { /* SRL L */ regL = srl(regL); break; } case 0x3E: { /* SRL (HL) */ int work16 = getRegHL(); int work8 = srl(MemIoImpl.peek8(work16)); MemIoImpl.addressOnBus(work16, 1); MemIoImpl.poke8(work16, work8); break; } case 0x3F: { /* SRL A */ regA = srl(regA); break; } case 0x40: { /* BIT 0,B */ bit(0x01, regB); break; } case 0x41: { /* BIT 0,C */ bit(0x01, regC); break; } case 0x42: { /* BIT 0,D */ bit(0x01, regD); break; } case 0x43: { /* BIT 0,E */ bit(0x01, regE); break; } case 0x44: { /* BIT 0,H */ bit(0x01, regH); break; } case 0x45: { /* BIT 0,L */ bit(0x01, regL); break; } case 0x46: { /* BIT 0,(HL) */ int work16 = getRegHL(); bit(0x01, MemIoImpl.peek8(work16)); sz5h3pnFlags = (sz5h3pnFlags & FLAG_SZHP_MASK) | ((memptr >>> 8) & FLAG_53_MASK); MemIoImpl.addressOnBus(work16, 1); break; } case 0x47: { /* BIT 0,A */ bit(0x01, regA); break; } case 0x48: { /* BIT 1,B */ bit(0x02, regB); break; } case 0x49: { /* BIT 1,C */ bit(0x02, regC); break; } case 0x4A: { /* BIT 1,D */ bit(0x02, regD); break; } case 0x4B: { /* BIT 1,E */ bit(0x02, regE); break; } case 0x4C: { /* BIT 1,H */ bit(0x02, regH); break; } case 0x4D: { /* BIT 1,L */ bit(0x02, regL); break; } case 0x4E: { /* BIT 1,(HL) */ int work16 = getRegHL(); bit(0x02, MemIoImpl.peek8(work16)); sz5h3pnFlags = (sz5h3pnFlags & FLAG_SZHP_MASK) | ((memptr >>> 8) & FLAG_53_MASK); MemIoImpl.addressOnBus(work16, 1); break; } case 0x4F: { /* BIT 1,A */ bit(0x02, regA); break; } case 0x50: { /* BIT 2,B */ bit(0x04, regB); break; } case 0x51: { /* BIT 2,C */ bit(0x04, regC); break; } case 0x52: { /* BIT 2,D */ bit(0x04, regD); break; } case 0x53: { /* BIT 2,E */ bit(0x04, regE); break; } case 0x54: { /* BIT 2,H */ bit(0x04, regH); break; } case 0x55: { /* BIT 2,L */ bit(0x04, regL); break; } case 0x56: { /* BIT 2,(HL) */ int work16 = getRegHL(); bit(0x04, MemIoImpl.peek8(work16)); sz5h3pnFlags = (sz5h3pnFlags & FLAG_SZHP_MASK) | ((memptr >>> 8) & FLAG_53_MASK); MemIoImpl.addressOnBus(work16, 1); break; } case 0x57: { /* BIT 2,A */ bit(0x04, regA); break; } case 0x58: { /* BIT 3,B */ bit(0x08, regB); break; } case 0x59: { /* BIT 3,C */ bit(0x08, regC); break; } case 0x5A: { /* BIT 3,D */ bit(0x08, regD); break; } case 0x5B: { /* BIT 3,E */ bit(0x08, regE); break; } case 0x5C: { /* BIT 3,H */ bit(0x08, regH); break; } case 0x5D: { /* BIT 3,L */ bit(0x08, regL); break; } case 0x5E: { /* BIT 3,(HL) */ int work16 = getRegHL(); bit(0x08, MemIoImpl.peek8(work16)); sz5h3pnFlags = (sz5h3pnFlags & FLAG_SZHP_MASK) | ((memptr >>> 8) & FLAG_53_MASK); MemIoImpl.addressOnBus(work16, 1); break; } case 0x5F: { /* BIT 3,A */ bit(0x08, regA); break; } case 0x60: { /* BIT 4,B */ bit(0x10, regB); break; } case 0x61: { /* BIT 4,C */ bit(0x10, regC); break; } case 0x62: { /* BIT 4,D */ bit(0x10, regD); break; } case 0x63: { /* BIT 4,E */ bit(0x10, regE); break; } case 0x64: { /* BIT 4,H */ bit(0x10, regH); break; } case 0x65: { /* BIT 4,L */ bit(0x10, regL); break; } case 0x66: { /* BIT 4,(HL) */ int work16 = getRegHL(); bit(0x10, MemIoImpl.peek8(work16)); sz5h3pnFlags = (sz5h3pnFlags & FLAG_SZHP_MASK) | ((memptr >>> 8) & FLAG_53_MASK); MemIoImpl.addressOnBus(work16, 1); break; } case 0x67: { /* BIT 4,A */ bit(0x10, regA); break; } case 0x68: { /* BIT 5,B */ bit(0x20, regB); break; } case 0x69: { /* BIT 5,C */ bit(0x20, regC); break; } case 0x6A: { /* BIT 5,D */ bit(0x20, regD); break; } case 0x6B: { /* BIT 5,E */ bit(0x20, regE); break; } case 0x6C: { /* BIT 5,H */ bit(0x20, regH); break; } case 0x6D: { /* BIT 5,L */ bit(0x20, regL); break; } case 0x6E: { /* BIT 5,(HL) */ int work16 = getRegHL(); bit(0x20, MemIoImpl.peek8(work16)); sz5h3pnFlags = (sz5h3pnFlags & FLAG_SZHP_MASK) | ((memptr >>> 8) & FLAG_53_MASK); MemIoImpl.addressOnBus(work16, 1); break; } case 0x6F: { /* BIT 5,A */ bit(0x20, regA); break; } case 0x70: { /* BIT 6,B */ bit(0x40, regB); break; } case 0x71: { /* BIT 6,C */ bit(0x40, regC); break; } case 0x72: { /* BIT 6,D */ bit(0x40, regD); break; } case 0x73: { /* BIT 6,E */ bit(0x40, regE); break; } case 0x74: { /* BIT 6,H */ bit(0x40, regH); break; } case 0x75: { /* BIT 6,L */ bit(0x40, regL); break; } case 0x76: { /* BIT 6,(HL) */ int work16 = getRegHL(); bit(0x40, MemIoImpl.peek8(work16)); sz5h3pnFlags = (sz5h3pnFlags & FLAG_SZHP_MASK) | ((memptr >>> 8) & FLAG_53_MASK); MemIoImpl.addressOnBus(work16, 1); break; } case 0x77: { /* BIT 6,A */ bit(0x40, regA); break; } case 0x78: { /* BIT 7,B */ bit(0x80, regB); break; } case 0x79: { /* BIT 7,C */ bit(0x80, regC); break; } case 0x7A: { /* BIT 7,D */ bit(0x80, regD); break; } case 0x7B: { /* BIT 7,E */ bit(0x80, regE); break; } case 0x7C: { /* BIT 7,H */ bit(0x80, regH); break; } case 0x7D: { /* BIT 7,L */ bit(0x80, regL); break; } case 0x7E: { /* BIT 7,(HL) */ int work16 = getRegHL(); bit(0x80, MemIoImpl.peek8(work16)); sz5h3pnFlags = (sz5h3pnFlags & FLAG_SZHP_MASK) | ((memptr >>> 8) & FLAG_53_MASK); MemIoImpl.addressOnBus(work16, 1); break; } case 0x7F: { /* BIT 7,A */ bit(0x80, regA); break; } case 0x80: { /* RES 0,B */ regB &= 0xFE; break; } case 0x81: { /* RES 0,C */ regC &= 0xFE; break; } case 0x82: { /* RES 0,D */ regD &= 0xFE; break; } case 0x83: { /* RES 0,E */ regE &= 0xFE; break; } case 0x84: { /* RES 0,H */ regH &= 0xFE; break; } case 0x85: { /* RES 0,L */ regL &= 0xFE; break; } case 0x86: { /* RES 0,(HL) */ int work16 = getRegHL(); int work8 = MemIoImpl.peek8(work16) & 0xFE; MemIoImpl.addressOnBus(work16, 1); MemIoImpl.poke8(work16, work8); break; } case 0x87: { /* RES 0,A */ regA &= 0xFE; break; } case 0x88: { /* RES 1,B */ regB &= 0xFD; break; } case 0x89: { /* RES 1,C */ regC &= 0xFD; break; } case 0x8A: { /* RES 1,D */ regD &= 0xFD; break; } case 0x8B: { /* RES 1,E */ regE &= 0xFD; break; } case 0x8C: { /* RES 1,H */ regH &= 0xFD; break; } case 0x8D: { /* RES 1,L */ regL &= 0xFD; break; } case 0x8E: { /* RES 1,(HL) */ int work16 = getRegHL(); int work8 = MemIoImpl.peek8(work16) & 0xFD; MemIoImpl.addressOnBus(work16, 1); MemIoImpl.poke8(work16, work8); break; } case 0x8F: { /* RES 1,A */ regA &= 0xFD; break; } case 0x90: { /* RES 2,B */ regB &= 0xFB; break; } case 0x91: { /* RES 2,C */ regC &= 0xFB; break; } case 0x92: { /* RES 2,D */ regD &= 0xFB; break; } case 0x93: { /* RES 2,E */ regE &= 0xFB; break; } case 0x94: { /* RES 2,H */ regH &= 0xFB; break; } case 0x95: { /* RES 2,L */ regL &= 0xFB; break; } case 0x96: { /* RES 2,(HL) */ int work16 = getRegHL(); int work8 = MemIoImpl.peek8(work16) & 0xFB; MemIoImpl.addressOnBus(work16, 1); MemIoImpl.poke8(work16, work8); break; } case 0x97: { /* RES 2,A */ regA &= 0xFB; break; } case 0x98: { /* RES 3,B */ regB &= 0xF7; break; } case 0x99: { /* RES 3,C */ regC &= 0xF7; break; } case 0x9A: { /* RES 3,D */ regD &= 0xF7; break; } case 0x9B: { /* RES 3,E */ regE &= 0xF7; break; } case 0x9C: { /* RES 3,H */ regH &= 0xF7; break; } case 0x9D: { /* RES 3,L */ regL &= 0xF7; break; } case 0x9E: { /* RES 3,(HL) */ int work16 = getRegHL(); int work8 = MemIoImpl.peek8(work16) & 0xF7; MemIoImpl.addressOnBus(work16, 1); MemIoImpl.poke8(work16, work8); break; } case 0x9F: { /* RES 3,A */ regA &= 0xF7; break; } case 0xA0: { /* RES 4,B */ regB &= 0xEF; break; } case 0xA1: { /* RES 4,C */ regC &= 0xEF; break; } case 0xA2: { /* RES 4,D */ regD &= 0xEF; break; } case 0xA3: { /* RES 4,E */ regE &= 0xEF; break; } case 0xA4: { /* RES 4,H */ regH &= 0xEF; break; } case 0xA5: { /* RES 4,L */ regL &= 0xEF; break; } case 0xA6: { /* RES 4,(HL) */ int work16 = getRegHL(); int work8 = MemIoImpl.peek8(work16) & 0xEF; MemIoImpl.addressOnBus(work16, 1); MemIoImpl.poke8(work16, work8); break; } case 0xA7: { /* RES 4,A */ regA &= 0xEF; break; } case 0xA8: { /* RES 5,B */ regB &= 0xDF; break; } case 0xA9: { /* RES 5,C */ regC &= 0xDF; break; } case 0xAA: { /* RES 5,D */ regD &= 0xDF; break; } case 0xAB: { /* RES 5,E */ regE &= 0xDF; break; } case 0xAC: { /* RES 5,H */ regH &= 0xDF; break; } case 0xAD: { /* RES 5,L */ regL &= 0xDF; break; } case 0xAE: { /* RES 5,(HL) */ int work16 = getRegHL(); int work8 = MemIoImpl.peek8(work16) & 0xDF; MemIoImpl.addressOnBus(work16, 1); MemIoImpl.poke8(work16, work8); break; } case 0xAF: { /* RES 5,A */ regA &= 0xDF; break; } case 0xB0: { /* RES 6,B */ regB &= 0xBF; break; } case 0xB1: { /* RES 6,C */ regC &= 0xBF; break; } case 0xB2: { /* RES 6,D */ regD &= 0xBF; break; } case 0xB3: { /* RES 6,E */ regE &= 0xBF; break; } case 0xB4: { /* RES 6,H */ regH &= 0xBF; break; } case 0xB5: { /* RES 6,L */ regL &= 0xBF; break; } case 0xB6: { /* RES 6,(HL) */ int work16 = getRegHL(); int work8 = MemIoImpl.peek8(work16) & 0xBF; MemIoImpl.addressOnBus(work16, 1); MemIoImpl.poke8(work16, work8); break; } case 0xB7: { /* RES 6,A */ regA &= 0xBF; break; } case 0xB8: { /* RES 7,B */ regB &= 0x7F; break; } case 0xB9: { /* RES 7,C */ regC &= 0x7F; break; } case 0xBA: { /* RES 7,D */ regD &= 0x7F; break; } case 0xBB: { /* RES 7,E */ regE &= 0x7F; break; } case 0xBC: { /* RES 7,H */ regH &= 0x7F; break; } case 0xBD: { /* RES 7,L */ regL &= 0x7F; break; } case 0xBE: { /* RES 7,(HL) */ int work16 = getRegHL(); int work8 = MemIoImpl.peek8(work16) & 0x7F; MemIoImpl.addressOnBus(work16, 1); MemIoImpl.poke8(work16, work8); break; } case 0xBF: { /* RES 7,A */ regA &= 0x7F; break; } case 0xC0: { /* SET 0,B */ regB |= 0x01; break; } case 0xC1: { /* SET 0,C */ regC |= 0x01; break; } case 0xC2: { /* SET 0,D */ regD |= 0x01; break; } case 0xC3: { /* SET 0,E */ regE |= 0x01; break; } case 0xC4: { /* SET 0,H */ regH |= 0x01; break; } case 0xC5: { /* SET 0,L */ regL |= 0x01; break; } case 0xC6: { /* SET 0,(HL) */ int work16 = getRegHL(); int work8 = MemIoImpl.peek8(work16) | 0x01; MemIoImpl.addressOnBus(work16, 1); MemIoImpl.poke8(work16, work8); break; } case 0xC7: { /* SET 0,A */ regA |= 0x01; break; } case 0xC8: { /* SET 1,B */ regB |= 0x02; break; } case 0xC9: { /* SET 1,C */ regC |= 0x02; break; } case 0xCA: { /* SET 1,D */ regD |= 0x02; break; } case 0xCB: { /* SET 1,E */ regE |= 0x02; break; } case 0xCC: { /* SET 1,H */ regH |= 0x02; break; } case 0xCD: { /* SET 1,L */ regL |= 0x02; break; } case 0xCE: { /* SET 1,(HL) */ int work16 = getRegHL(); int work8 = MemIoImpl.peek8(work16) | 0x02; MemIoImpl.addressOnBus(work16, 1); MemIoImpl.poke8(work16, work8); break; } case 0xCF: { /* SET 1,A */ regA |= 0x02; break; } case 0xD0: { /* SET 2,B */ regB |= 0x04; break; } case 0xD1: { /* SET 2,C */ regC |= 0x04; break; } case 0xD2: { /* SET 2,D */ regD |= 0x04; break; } case 0xD3: { /* SET 2,E */ regE |= 0x04; break; } case 0xD4: { /* SET 2,H */ regH |= 0x04; break; } case 0xD5: { /* SET 2,L */ regL |= 0x04; break; } case 0xD6: { /* SET 2,(HL) */ int work16 = getRegHL(); int work8 = MemIoImpl.peek8(work16) | 0x04; MemIoImpl.addressOnBus(work16, 1); MemIoImpl.poke8(work16, work8); break; } case 0xD7: { /* SET 2,A */ regA |= 0x04; break; } case 0xD8: { /* SET 3,B */ regB |= 0x08; break; } case 0xD9: { /* SET 3,C */ regC |= 0x08; break; } case 0xDA: { /* SET 3,D */ regD |= 0x08; break; } case 0xDB: { /* SET 3,E */ regE |= 0x08; break; } case 0xDC: { /* SET 3,H */ regH |= 0x08; break; } case 0xDD: { /* SET 3,L */ regL |= 0x08; break; } case 0xDE: { /* SET 3,(HL) */ int work16 = getRegHL(); int work8 = MemIoImpl.peek8(work16) | 0x08; MemIoImpl.addressOnBus(work16, 1); MemIoImpl.poke8(work16, work8); break; } case 0xDF: { /* SET 3,A */ regA |= 0x08; break; } case 0xE0: { /* SET 4,B */ regB |= 0x10; break; } case 0xE1: { /* SET 4,C */ regC |= 0x10; break; } case 0xE2: { /* SET 4,D */ regD |= 0x10; break; } case 0xE3: { /* SET 4,E */ regE |= 0x10; break; } case 0xE4: { /* SET 4,H */ regH |= 0x10; break; } case 0xE5: { /* SET 4,L */ regL |= 0x10; break; } case 0xE6: { /* SET 4,(HL) */ int work16 = getRegHL(); int work8 = MemIoImpl.peek8(work16) | 0x10; MemIoImpl.addressOnBus(work16, 1); MemIoImpl.poke8(work16, work8); break; } case 0xE7: { /* SET 4,A */ regA |= 0x10; break; } case 0xE8: { /* SET 5,B */ regB |= 0x20; break; } case 0xE9: { /* SET 5,C */ regC |= 0x20; break; } case 0xEA: { /* SET 5,D */ regD |= 0x20; break; } case 0xEB: { /* SET 5,E */ regE |= 0x20; break; } case 0xEC: { /* SET 5,H */ regH |= 0x20; break; } case 0xED: { /* SET 5,L */ regL |= 0x20; break; } case 0xEE: { /* SET 5,(HL) */ int work16 = getRegHL(); int work8 = MemIoImpl.peek8(work16) | 0x20; MemIoImpl.addressOnBus(work16, 1); MemIoImpl.poke8(work16, work8); break; } case 0xEF: { /* SET 5,A */ regA |= 0x20; break; } case 0xF0: { /* SET 6,B */ regB |= 0x40; break; } case 0xF1: { /* SET 6,C */ regC |= 0x40; break; } case 0xF2: { /* SET 6,D */ regD |= 0x40; break; } case 0xF3: { /* SET 6,E */ regE |= 0x40; break; } case 0xF4: { /* SET 6,H */ regH |= 0x40; break; } case 0xF5: { /* SET 6,L */ regL |= 0x40; break; } case 0xF6: { /* SET 6,(HL) */ int work16 = getRegHL(); int work8 = MemIoImpl.peek8(work16) | 0x40; MemIoImpl.addressOnBus(work16, 1); MemIoImpl.poke8(work16, work8); break; } case 0xF7: { /* SET 6,A */ regA |= 0x40; break; } case 0xF8: { /* SET 7,B */ regB |= 0x80; break; } case 0xF9: { /* SET 7,C */ regC |= 0x80; break; } case 0xFA: { /* SET 7,D */ regD |= 0x80; break; } case 0xFB: { /* SET 7,E */ regE |= 0x80; break; } case 0xFC: { /* SET 7,H */ regH |= 0x80; break; } case 0xFD: { /* SET 7,L */ regL |= 0x80; break; } case 0xFE: { /* SET 7,(HL) */ int work16 = getRegHL(); int work8 = MemIoImpl.peek8(work16) | 0x80; MemIoImpl.addressOnBus(work16, 1); MemIoImpl.poke8(work16, work8); break; } case 0xFF: { /* SET 7,A */ regA |= 0x80; break; } default: { // System.out.println("Error instrucción CB " + Integer.toHexString(opCode)); break; } } } //Subconjunto de instrucciones 0xDD / 0xFD /* * Hay que tener en cuenta el manejo de secuencias códigos DD/FD que no * hacen nada. Según el apartado 3.7 del documento * [http://www.myquest.nl/z80undocumented/z80-documented-v0.91.pdf] * secuencias de códigos como FD DD 00 21 00 10 NOP NOP NOP LD HL,1000h * activan IY con el primer FD, IX con el segundo DD y vuelven al * registro HL con el código NOP. Es decir, si detrás del código DD/FD no * viene una instrucción que maneje el registro HL, el código DD/FD * "se olvida" y hay que procesar la instrucción como si nunca se * hubiera visto el prefijo (salvo por los 4 t-estados que ha costado). * Naturalmente, en una serie repetida de DDFD no hay que comprobar las * interrupciones entre cada prefijo. */ private int decodeDDFD(int opCode, int regIXY) { prefixOpcode = 0; switch (opCode) { case 0x09: { /* ADD IX,BC */ MemIoImpl.addressOnBus(getPairIR(), 7); regIXY = add16(regIXY, getRegBC()); break; } case 0x19: { /* ADD IX,DE */ MemIoImpl.addressOnBus(getPairIR(), 7); regIXY = add16(regIXY, getRegDE()); break; } case 0x21: { /* LD IX,nn */ regIXY = MemIoImpl.peek16(regPC); regPC = (regPC + 2) & 0xffff; break; } case 0x22: { /* LD (nn),IX */ memptr = MemIoImpl.peek16(regPC); MemIoImpl.poke16(memptr++, regIXY); regPC = (regPC + 2) & 0xffff; break; } case 0x23: { /* INC IX */ MemIoImpl.addressOnBus(getPairIR(), 2); regIXY = (regIXY + 1) & 0xffff; break; } case 0x24: { /* INC IXh */ regIXY = (inc8(regIXY >>> 8) << 8) | (regIXY & 0xff); break; } case 0x25: { /* DEC IXh */ regIXY = (dec8(regIXY >>> 8) << 8) | (regIXY & 0xff); break; } case 0x26: { /* LD IXh,n */ regIXY = (MemIoImpl.peek8(regPC) << 8) | (regIXY & 0xff); regPC = (regPC + 1) & 0xffff; break; } case 0x29: { /* ADD IX,IX */ MemIoImpl.addressOnBus(getPairIR(), 7); regIXY = add16(regIXY, regIXY); break; } case 0x2A: { /* LD IX,(nn) */ memptr = MemIoImpl.peek16(regPC); regIXY = MemIoImpl.peek16(memptr++); regPC = (regPC + 2) & 0xffff; break; } case 0x2B: { /* DEC IX */ MemIoImpl.addressOnBus(getPairIR(), 2); regIXY = (regIXY - 1) & 0xffff; break; } case 0x2C: { /* INC IXl */ regIXY = (regIXY & 0xff00) | inc8(regIXY & 0xff); break; } case 0x2D: { /* DEC IXl */ regIXY = (regIXY & 0xff00) | dec8(regIXY & 0xff); break; } case 0x2E: { /* LD IXl,n */ regIXY = (regIXY & 0xff00) | MemIoImpl.peek8(regPC); regPC = (regPC + 1) & 0xffff; break; } case 0x34: { /* INC (IX+d) */ memptr = (regIXY + (byte) MemIoImpl.peek8(regPC)) & 0xffff; MemIoImpl.addressOnBus(regPC, 5); int work8 = MemIoImpl.peek8(memptr); MemIoImpl.addressOnBus(memptr, 1); MemIoImpl.poke8(memptr, inc8(work8)); regPC = (regPC + 1) & 0xffff; break; } case 0x35: { /* DEC (IX+d) */ memptr = (regIXY + (byte) MemIoImpl.peek8(regPC)) & 0xffff; MemIoImpl.addressOnBus(regPC, 5); int work8 = MemIoImpl.peek8(memptr); MemIoImpl.addressOnBus(memptr, 1); MemIoImpl.poke8(memptr, dec8(work8)); regPC = (regPC + 1) & 0xffff; break; } case 0x36: { /* LD (IX+d),n */ memptr = (regIXY + (byte) MemIoImpl.peek8(regPC)) & 0xffff; regPC = (regPC + 1) & 0xffff; int work8 = MemIoImpl.peek8(regPC); MemIoImpl.addressOnBus(regPC, 2); regPC = (regPC + 1) & 0xffff; MemIoImpl.poke8(memptr, work8); break; } case 0x39: { /* ADD IX,SP */ MemIoImpl.addressOnBus(getPairIR(), 7); regIXY = add16(regIXY, regSP); break; } case 0x44: { /* LD B,IXh */ regB = regIXY >>> 8; break; } case 0x45: { /* LD B,IXl */ regB = regIXY & 0xff; break; } case 0x46: { /* LD B,(IX+d) */ memptr = (regIXY + (byte) MemIoImpl.peek8(regPC)) & 0xffff; MemIoImpl.addressOnBus(regPC, 5); regB = MemIoImpl.peek8(memptr); regPC = (regPC + 1) & 0xffff; break; } case 0x4C: { /* LD C,IXh */ regC = regIXY >>> 8; break; } case 0x4D: { /* LD C,IXl */ regC = regIXY & 0xff; break; } case 0x4E: { /* LD C,(IX+d) */ memptr = (regIXY + (byte) MemIoImpl.peek8(regPC)) & 0xffff; MemIoImpl.addressOnBus(regPC, 5); regC = MemIoImpl.peek8(memptr); regPC = (regPC + 1) & 0xffff; break; } case 0x54: { /* LD D,IXh */ regD = regIXY >>> 8; break; } case 0x55: { /* LD D,IXl */ regD = regIXY & 0xff; break; } case 0x56: { /* LD D,(IX+d) */ memptr = (regIXY + (byte) MemIoImpl.peek8(regPC)) & 0xffff; MemIoImpl.addressOnBus(regPC, 5); regD = MemIoImpl.peek8(memptr); regPC = (regPC + 1) & 0xffff; break; } case 0x5C: { /* LD E,IXh */ regE = regIXY >>> 8; break; } case 0x5D: { /* LD E,IXl */ regE = regIXY & 0xff; break; } case 0x5E: { /* LD E,(IX+d) */ memptr = (regIXY + (byte) MemIoImpl.peek8(regPC)) & 0xffff; MemIoImpl.addressOnBus(regPC, 5); regE = MemIoImpl.peek8(memptr); regPC = (regPC + 1) & 0xffff; break; } case 0x60: { /* LD IXh,B */ regIXY = (regIXY & 0x00ff) | (regB << 8); break; } case 0x61: { /* LD IXh,C */ regIXY = (regIXY & 0x00ff) | (regC << 8); break; } case 0x62: { /* LD IXh,D */ regIXY = (regIXY & 0x00ff) | (regD << 8); break; } case 0x63: { /* LD IXh,E */ regIXY = (regIXY & 0x00ff) | (regE << 8); break; } case 0x64: { /* LD IXh,IXh */ break; } case 0x65: { /* LD IXh,IXl */ regIXY = (regIXY & 0x00ff) | ((regIXY & 0xff) << 8); break; } case 0x66: { /* LD H,(IX+d) */ memptr = (regIXY + (byte) MemIoImpl.peek8(regPC)) & 0xffff; MemIoImpl.addressOnBus(regPC, 5); regH = MemIoImpl.peek8(memptr); regPC = (regPC + 1) & 0xffff; break; } case 0x67: { /* LD IXh,A */ regIXY = (regIXY & 0x00ff) | (regA << 8); break; } case 0x68: { /* LD IXl,B */ regIXY = (regIXY & 0xff00) | regB; break; } case 0x69: { /* LD IXl,C */ regIXY = (regIXY & 0xff00) | regC; break; } case 0x6A: { /* LD IXl,D */ regIXY = (regIXY & 0xff00) | regD; break; } case 0x6B: { /* LD IXl,E */ regIXY = (regIXY & 0xff00) | regE; break; } case 0x6C: { /* LD IXl,IXh */ regIXY = (regIXY & 0xff00) | (regIXY >>> 8); break; } case 0x6D: { /* LD IXl,IXl */ break; } case 0x6E: { /* LD L,(IX+d) */ memptr = (regIXY + (byte) MemIoImpl.peek8(regPC)) & 0xffff; MemIoImpl.addressOnBus(regPC, 5); regL = MemIoImpl.peek8(memptr); regPC = (regPC + 1) & 0xffff; break; } case 0x6F: { /* LD IXl,A */ regIXY = (regIXY & 0xff00) | regA; break; } case 0x70: { /* LD (IX+d),B */ memptr = (regIXY + (byte) MemIoImpl.peek8(regPC)) & 0xffff; MemIoImpl.addressOnBus(regPC, 5); MemIoImpl.poke8(memptr, regB); regPC = (regPC + 1) & 0xffff; break; } case 0x71: { /* LD (IX+d),C */ memptr = (regIXY + (byte) MemIoImpl.peek8(regPC)) & 0xffff; MemIoImpl.addressOnBus(regPC, 5); MemIoImpl.poke8(memptr, regC); regPC = (regPC + 1) & 0xffff; break; } case 0x72: { /* LD (IX+d),D */ memptr = (regIXY + (byte) MemIoImpl.peek8(regPC)) & 0xffff; MemIoImpl.addressOnBus(regPC, 5); MemIoImpl.poke8(memptr, regD); regPC = (regPC + 1) & 0xffff; break; } case 0x73: { /* LD (IX+d),E */ memptr = (regIXY + (byte) MemIoImpl.peek8(regPC)) & 0xffff; MemIoImpl.addressOnBus(regPC, 5); MemIoImpl.poke8(memptr, regE); regPC = (regPC + 1) & 0xffff; break; } case 0x74: { /* LD (IX+d),H */ memptr = (regIXY + (byte) MemIoImpl.peek8(regPC)) & 0xffff; MemIoImpl.addressOnBus(regPC, 5); MemIoImpl.poke8(memptr, regH); regPC = (regPC + 1) & 0xffff; break; } case 0x75: { /* LD (IX+d),L */ memptr = (regIXY + (byte) MemIoImpl.peek8(regPC)) & 0xffff; MemIoImpl.addressOnBus(regPC, 5); MemIoImpl.poke8(memptr, regL); regPC = (regPC + 1) & 0xffff; break; } case 0x77: { /* LD (IX+d),A */ memptr = (regIXY + (byte) MemIoImpl.peek8(regPC)) & 0xffff; MemIoImpl.addressOnBus(regPC, 5); MemIoImpl.poke8(memptr, regA); regPC = (regPC + 1) & 0xffff; break; } case 0x7C: { /* LD A,IXh */ regA = regIXY >>> 8; break; } case 0x7D: { /* LD A,IXl */ regA = regIXY & 0xff; break; } case 0x7E: { /* LD A,(IX+d) */ memptr = (regIXY + (byte) MemIoImpl.peek8(regPC)) & 0xffff; MemIoImpl.addressOnBus(regPC, 5); regA = MemIoImpl.peek8(memptr); regPC = (regPC + 1) & 0xffff; break; } case 0x84: { /* ADD A,IXh */ add(regIXY >>> 8); break; } case 0x85: { /* ADD A,IXl */ add(regIXY & 0xff); break; } case 0x86: { /* ADD A,(IX+d) */ memptr = (regIXY + (byte) MemIoImpl.peek8(regPC)) & 0xffff; MemIoImpl.addressOnBus(regPC, 5); add(MemIoImpl.peek8(memptr)); regPC = (regPC + 1) & 0xffff; break; } case 0x8C: { /* ADC A,IXh */ adc(regIXY >>> 8); break; } case 0x8D: { /* ADC A,IXl */ adc(regIXY & 0xff); break; } case 0x8E: { /* ADC A,(IX+d) */ memptr = (regIXY + (byte) MemIoImpl.peek8(regPC)) & 0xffff; MemIoImpl.addressOnBus(regPC, 5); adc(MemIoImpl.peek8(memptr)); regPC = (regPC + 1) & 0xffff; break; } case 0x94: { /* SUB IXh */ sub(regIXY >>> 8); break; } case 0x95: { /* SUB IXl */ sub(regIXY & 0xff); break; } case 0x96: { /* SUB (IX+d) */ memptr = (regIXY + (byte) MemIoImpl.peek8(regPC)) & 0xffff; MemIoImpl.addressOnBus(regPC, 5); sub(MemIoImpl.peek8(memptr)); regPC = (regPC + 1) & 0xffff; break; } case 0x9C: { /* SBC A,IXh */ sbc(regIXY >>> 8); break; } case 0x9D: { /* SBC A,IXl */ sbc(regIXY & 0xff); break; } case 0x9E: { /* SBC A,(IX+d) */ memptr = (regIXY + (byte) MemIoImpl.peek8(regPC)) & 0xffff; MemIoImpl.addressOnBus(regPC, 5); sbc(MemIoImpl.peek8(memptr)); regPC = (regPC + 1) & 0xffff; break; } case 0xA4: { /* AND IXh */ and(regIXY >>> 8); break; } case 0xA5: { /* AND IXl */ and(regIXY & 0xff); break; } case 0xA6: { /* AND (IX+d) */ memptr = (regIXY + (byte) MemIoImpl.peek8(regPC)) & 0xffff; MemIoImpl.addressOnBus(regPC, 5); and(MemIoImpl.peek8(memptr)); regPC = (regPC + 1) & 0xffff; break; } case 0xAC: { /* XOR IXh */ xor(regIXY >>> 8); break; } case 0xAD: { /* XOR IXl */ xor(regIXY & 0xff); break; } case 0xAE: { /* XOR (IX+d) */ memptr = (regIXY + (byte) MemIoImpl.peek8(regPC)) & 0xffff; MemIoImpl.addressOnBus(regPC, 5); xor(MemIoImpl.peek8(memptr)); regPC = (regPC + 1) & 0xffff; break; } case 0xB4: { /* OR IXh */ or(regIXY >>> 8); break; } case 0xB5: { /* OR IXl */ or(regIXY & 0xff); break; } case 0xB6: { /* OR (IX+d) */ memptr = (regIXY + (byte) MemIoImpl.peek8(regPC)) & 0xffff; MemIoImpl.addressOnBus(regPC, 5); or(MemIoImpl.peek8(memptr)); regPC = (regPC + 1) & 0xffff; break; } case 0xBC: { /* CP IXh */ cp(regIXY >>> 8); break; } case 0xBD: { /* CP IXl */ cp(regIXY & 0xff); break; } case 0xBE: { /* CP (IX+d) */ memptr = (regIXY + (byte) MemIoImpl.peek8(regPC)) & 0xffff; MemIoImpl.addressOnBus(regPC, 5); cp(MemIoImpl.peek8(memptr)); regPC = (regPC + 1) & 0xffff; break; } case 0xCB: { /* Subconjunto de instrucciones */ memptr = (regIXY + (byte) MemIoImpl.peek8(regPC)) & 0xffff; regPC = (regPC + 1) & 0xffff; opCode = MemIoImpl.peek8(regPC); MemIoImpl.addressOnBus(regPC, 2); regPC = (regPC + 1) & 0xffff; if (opCode < 0x80) { decodeDDFDCBto7F(opCode, memptr); } else { decodeDDFDCBtoFF(opCode, memptr); } break; } case 0xDD: { prefixOpcode = 0xDD; break; } case 0xE1: { /* POP IX */ regIXY = pop(); break; } case 0xE3: { /* EX (SP),IX */ // Instrucción de ejecución sutil como pocas... atento al dato. int work16 = regIXY; regIXY = MemIoImpl.peek16(regSP); MemIoImpl.addressOnBus((regSP + 1) & 0xffff, 1); MemIoImpl.poke8((regSP + 1) & 0xffff, work16 >>> 8); MemIoImpl.poke8(regSP, work16); MemIoImpl.addressOnBus(regSP, 2); memptr = regIXY; break; } case 0xE5: { /* PUSH IX */ MemIoImpl.addressOnBus(getPairIR(), 1); push(regIXY); break; } case 0xE9: { /* JP (IX) */ regPC = regIXY; break; } case 0xED: { prefixOpcode = 0xED; break; } case 0xF9: { /* LD SP,IX */ MemIoImpl.addressOnBus(getPairIR(), 2); regSP = regIXY; break; } case 0xFD: { prefixOpcode = 0xFD; break; } default: { // Detrás de un DD/FD o varios en secuencia venía un código // que no correspondía con una instrucción que involucra a // IX o IY. Se trata como si fuera un código normal. // Sin esto, además de emular mal, falla el test // ld , de ZEXALL. // System.out.println("Error instrucción DD/FD" + Integer.toHexString(opCode)); if (breakpointAt[regPC]) { opCode = NotifyImpl.breakpoint(regPC, opCode); } decodeOpcode(opCode); break; } } return regIXY; } // Subconjunto de instrucciones 0xDDCB desde el código 0x00 hasta el 0x7F private void decodeDDFDCBto7F(int opCode, int address) { switch (opCode) { case 0x00: { /* RLC (IX+d),B */ regB = rlc(MemIoImpl.peek8(address)); MemIoImpl.addressOnBus(address, 1); MemIoImpl.poke8(address, regB); break; } case 0x01: { /* RLC (IX+d),C */ regC = rlc(MemIoImpl.peek8(address)); MemIoImpl.addressOnBus(address, 1); MemIoImpl.poke8(address, regC); break; } case 0x02: { /* RLC (IX+d),D */ regD = rlc(MemIoImpl.peek8(address)); MemIoImpl.addressOnBus(address, 1); MemIoImpl.poke8(address, regD); break; } case 0x03: { /* RLC (IX+d),E */ regE = rlc(MemIoImpl.peek8(address)); MemIoImpl.addressOnBus(address, 1); MemIoImpl.poke8(address, regE); break; } case 0x04: { /* RLC (IX+d),H */ regH = rlc(MemIoImpl.peek8(address)); MemIoImpl.addressOnBus(address, 1); MemIoImpl.poke8(address, regH); break; } case 0x05: { /* RLC (IX+d),L */ regL = rlc(MemIoImpl.peek8(address)); MemIoImpl.addressOnBus(address, 1); MemIoImpl.poke8(address, regL); break; } case 0x06: { /* RLC (IX+d) */ int work8 = rlc(MemIoImpl.peek8(address)); MemIoImpl.addressOnBus(address, 1); MemIoImpl.poke8(address, work8); break; } case 0x07: { /* RLC (IX+d),A */ regA = rlc(MemIoImpl.peek8(address)); MemIoImpl.addressOnBus(address, 1); MemIoImpl.poke8(address, regA); break; } case 0x08: { /* RRC (IX+d),B */ regB = rrc(MemIoImpl.peek8(address)); MemIoImpl.addressOnBus(address, 1); MemIoImpl.poke8(address, regB); break; } case 0x09: { /* RRC (IX+d),C */ regC = rrc(MemIoImpl.peek8(address)); MemIoImpl.addressOnBus(address, 1); MemIoImpl.poke8(address, regC); break; } case 0x0A: { /* RRC (IX+d),D */ regD = rrc(MemIoImpl.peek8(address)); MemIoImpl.addressOnBus(address, 1); MemIoImpl.poke8(address, regD); break; } case 0x0B: { /* RRC (IX+d),E */ regE = rrc(MemIoImpl.peek8(address)); MemIoImpl.addressOnBus(address, 1); MemIoImpl.poke8(address, regE); break; } case 0x0C: { /* RRC (IX+d),H */ regH = rrc(MemIoImpl.peek8(address)); MemIoImpl.addressOnBus(address, 1); MemIoImpl.poke8(address, regH); break; } case 0x0D: { /* RRC (IX+d),L */ regL = rrc(MemIoImpl.peek8(address)); MemIoImpl.addressOnBus(address, 1); MemIoImpl.poke8(address, regL); break; } case 0x0E: { /* RRC (IX+d) */ int work8 = rrc(MemIoImpl.peek8(address)); MemIoImpl.addressOnBus(address, 1); MemIoImpl.poke8(address, work8); break; } case 0x0F: { /* RRC (IX+d),A */ regA = rrc(MemIoImpl.peek8(address)); MemIoImpl.addressOnBus(address, 1); MemIoImpl.poke8(address, regA); break; } case 0x10: { /* RL (IX+d),B */ regB = rl(MemIoImpl.peek8(address)); MemIoImpl.addressOnBus(address, 1); MemIoImpl.poke8(address, regB); break; } case 0x11: { /* RL (IX+d),C */ regC = rl(MemIoImpl.peek8(address)); MemIoImpl.addressOnBus(address, 1); MemIoImpl.poke8(address, regC); break; } case 0x12: { /* RL (IX+d),D */ regD = rl(MemIoImpl.peek8(address)); MemIoImpl.addressOnBus(address, 1); MemIoImpl.poke8(address, regD); break; } case 0x13: { /* RL (IX+d),E */ regE = rl(MemIoImpl.peek8(address)); MemIoImpl.addressOnBus(address, 1); MemIoImpl.poke8(address, regE); break; } case 0x14: { /* RL (IX+d),H */ regH = rl(MemIoImpl.peek8(address)); MemIoImpl.addressOnBus(address, 1); MemIoImpl.poke8(address, regH); break; } case 0x15: { /* RL (IX+d),L */ regL = rl(MemIoImpl.peek8(address)); MemIoImpl.addressOnBus(address, 1); MemIoImpl.poke8(address, regL); break; } case 0x16: { /* RL (IX+d) */ int work8 = rl(MemIoImpl.peek8(address)); MemIoImpl.addressOnBus(address, 1); MemIoImpl.poke8(address, work8); break; } case 0x17: { /* RL (IX+d),A */ regA = rl(MemIoImpl.peek8(address)); MemIoImpl.addressOnBus(address, 1); MemIoImpl.poke8(address, regA); break; } case 0x18: { /* RR (IX+d),B */ regB = rr(MemIoImpl.peek8(address)); MemIoImpl.addressOnBus(address, 1); MemIoImpl.poke8(address, regB); break; } case 0x19: { /* RR (IX+d),C */ regC = rr(MemIoImpl.peek8(address)); MemIoImpl.addressOnBus(address, 1); MemIoImpl.poke8(address, regC); break; } case 0x1A: { /* RR (IX+d),D */ regD = rr(MemIoImpl.peek8(address)); MemIoImpl.addressOnBus(address, 1); MemIoImpl.poke8(address, regD); break; } case 0x1B: { /* RR (IX+d),E */ regE = rr(MemIoImpl.peek8(address)); MemIoImpl.addressOnBus(address, 1); MemIoImpl.poke8(address, regE); break; } case 0x1C: { /* RR (IX+d),H */ regH = rr(MemIoImpl.peek8(address)); MemIoImpl.addressOnBus(address, 1); MemIoImpl.poke8(address, regH); break; } case 0x1D: { /* RR (IX+d),L */ regL = rr(MemIoImpl.peek8(address)); MemIoImpl.addressOnBus(address, 1); MemIoImpl.poke8(address, regL); break; } case 0x1E: { /* RR (IX+d) */ int work8 = rr(MemIoImpl.peek8(address)); MemIoImpl.addressOnBus(address, 1); MemIoImpl.poke8(address, work8); break; } case 0x1F: { /* RR (IX+d),A */ regA = rr(MemIoImpl.peek8(address)); MemIoImpl.addressOnBus(address, 1); MemIoImpl.poke8(address, regA); break; } case 0x20: { /* SLA (IX+d),B */ regB = sla(MemIoImpl.peek8(address)); MemIoImpl.addressOnBus(address, 1); MemIoImpl.poke8(address, regB); break; } case 0x21: { /* SLA (IX+d),C */ regC = sla(MemIoImpl.peek8(address)); MemIoImpl.addressOnBus(address, 1); MemIoImpl.poke8(address, regC); break; } case 0x22: { /* SLA (IX+d),D */ regD = sla(MemIoImpl.peek8(address)); MemIoImpl.addressOnBus(address, 1); MemIoImpl.poke8(address, regD); break; } case 0x23: { /* SLA (IX+d),E */ regE = sla(MemIoImpl.peek8(address)); MemIoImpl.addressOnBus(address, 1); MemIoImpl.poke8(address, regE); break; } case 0x24: { /* SLA (IX+d),H */ regH = sla(MemIoImpl.peek8(address)); MemIoImpl.addressOnBus(address, 1); MemIoImpl.poke8(address, regH); break; } case 0x25: { /* SLA (IX+d),L */ regL = sla(MemIoImpl.peek8(address)); MemIoImpl.addressOnBus(address, 1); MemIoImpl.poke8(address, regL); break; } case 0x26: { /* SLA (IX+d) */ int work8 = sla(MemIoImpl.peek8(address)); MemIoImpl.addressOnBus(address, 1); MemIoImpl.poke8(address, work8); break; } case 0x27: { /* SLA (IX+d),A */ regA = sla(MemIoImpl.peek8(address)); MemIoImpl.addressOnBus(address, 1); MemIoImpl.poke8(address, regA); break; } case 0x28: { /* SRA (IX+d),B */ regB = sra(MemIoImpl.peek8(address)); MemIoImpl.addressOnBus(address, 1); MemIoImpl.poke8(address, regB); break; } case 0x29: { /* SRA (IX+d),C */ regC = sra(MemIoImpl.peek8(address)); MemIoImpl.addressOnBus(address, 1); MemIoImpl.poke8(address, regC); break; } case 0x2A: { /* SRA (IX+d),D */ regD = sra(MemIoImpl.peek8(address)); MemIoImpl.addressOnBus(address, 1); MemIoImpl.poke8(address, regD); break; } case 0x2B: { /* SRA (IX+d),E */ regE = sra(MemIoImpl.peek8(address)); MemIoImpl.addressOnBus(address, 1); MemIoImpl.poke8(address, regE); break; } case 0x2C: { /* SRA (IX+d),H */ regH = sra(MemIoImpl.peek8(address)); MemIoImpl.addressOnBus(address, 1); MemIoImpl.poke8(address, regH); break; } case 0x2D: { /* SRA (IX+d),L */ regL = sra(MemIoImpl.peek8(address)); MemIoImpl.addressOnBus(address, 1); MemIoImpl.poke8(address, regL); break; } case 0x2E: { /* SRA (IX+d) */ int work8 = sra(MemIoImpl.peek8(address)); MemIoImpl.addressOnBus(address, 1); MemIoImpl.poke8(address, work8); break; } case 0x2F: { /* SRA (IX+d),A */ regA = sra(MemIoImpl.peek8(address)); MemIoImpl.addressOnBus(address, 1); MemIoImpl.poke8(address, regA); break; } case 0x30: { /* SLL (IX+d),B */ regB = sll(MemIoImpl.peek8(address)); MemIoImpl.addressOnBus(address, 1); MemIoImpl.poke8(address, regB); break; } case 0x31: { /* SLL (IX+d),C */ regC = sll(MemIoImpl.peek8(address)); MemIoImpl.addressOnBus(address, 1); MemIoImpl.poke8(address, regC); break; } case 0x32: { /* SLL (IX+d),D */ regD = sll(MemIoImpl.peek8(address)); MemIoImpl.addressOnBus(address, 1); MemIoImpl.poke8(address, regD); break; } case 0x33: { /* SLL (IX+d),E */ regE = sll(MemIoImpl.peek8(address)); MemIoImpl.addressOnBus(address, 1); MemIoImpl.poke8(address, regE); break; } case 0x34: { /* SLL (IX+d),H */ regH = sll(MemIoImpl.peek8(address)); MemIoImpl.addressOnBus(address, 1); MemIoImpl.poke8(address, regH); break; } case 0x35: { /* SLL (IX+d),L */ regL = sll(MemIoImpl.peek8(address)); MemIoImpl.addressOnBus(address, 1); MemIoImpl.poke8(address, regL); break; } case 0x36: { /* SLL (IX+d) */ int work8 = sll(MemIoImpl.peek8(address)); MemIoImpl.addressOnBus(address, 1); MemIoImpl.poke8(address, work8); break; } case 0x37: { /* SLL (IX+d),A */ regA = sll(MemIoImpl.peek8(address)); MemIoImpl.addressOnBus(address, 1); MemIoImpl.poke8(address, regA); break; } case 0x38: { /* SRL (IX+d),B */ regB = srl(MemIoImpl.peek8(address)); MemIoImpl.addressOnBus(address, 1); MemIoImpl.poke8(address, regB); break; } case 0x39: { /* SRL (IX+d),C */ regC = srl(MemIoImpl.peek8(address)); MemIoImpl.addressOnBus(address, 1); MemIoImpl.poke8(address, regC); break; } case 0x3A: { /* SRL (IX+d),D */ regD = srl(MemIoImpl.peek8(address)); MemIoImpl.addressOnBus(address, 1); MemIoImpl.poke8(address, regD); break; } case 0x3B: { /* SRL (IX+d),E */ regE = srl(MemIoImpl.peek8(address)); MemIoImpl.addressOnBus(address, 1); MemIoImpl.poke8(address, regE); break; } case 0x3C: { /* SRL (IX+d),H */ regH = srl(MemIoImpl.peek8(address)); MemIoImpl.addressOnBus(address, 1); MemIoImpl.poke8(address, regH); break; } case 0x3D: { /* SRL (IX+d),L */ regL = srl(MemIoImpl.peek8(address)); MemIoImpl.addressOnBus(address, 1); MemIoImpl.poke8(address, regL); break; } case 0x3E: { /* SRL (IX+d) */ int work8 = srl(MemIoImpl.peek8(address)); MemIoImpl.addressOnBus(address, 1); MemIoImpl.poke8(address, work8); break; } case 0x3F: { /* SRL (IX+d),A */ regA = srl(MemIoImpl.peek8(address)); MemIoImpl.addressOnBus(address, 1); MemIoImpl.poke8(address, regA); break; } case 0x40: case 0x41: case 0x42: case 0x43: case 0x44: case 0x45: case 0x46: case 0x47: { /* BIT 0,(IX+d) */ bit(0x01, MemIoImpl.peek8(address)); sz5h3pnFlags = (sz5h3pnFlags & FLAG_SZHP_MASK) | ((address >>> 8) & FLAG_53_MASK); MemIoImpl.addressOnBus(address, 1); break; } case 0x48: case 0x49: case 0x4A: case 0x4B: case 0x4C: case 0x4D: case 0x4E: case 0x4F: { /* BIT 1,(IX+d) */ bit(0x02, MemIoImpl.peek8(address)); sz5h3pnFlags = (sz5h3pnFlags & FLAG_SZHP_MASK) | ((address >>> 8) & FLAG_53_MASK); MemIoImpl.addressOnBus(address, 1); break; } case 0x50: case 0x51: case 0x52: case 0x53: case 0x54: case 0x55: case 0x56: case 0x57: { /* BIT 2,(IX+d) */ bit(0x04, MemIoImpl.peek8(address)); sz5h3pnFlags = (sz5h3pnFlags & FLAG_SZHP_MASK) | ((address >>> 8) & FLAG_53_MASK); MemIoImpl.addressOnBus(address, 1); break; } case 0x58: case 0x59: case 0x5A: case 0x5B: case 0x5C: case 0x5D: case 0x5E: case 0x5F: { /* BIT 3,(IX+d) */ bit(0x08, MemIoImpl.peek8(address)); sz5h3pnFlags = (sz5h3pnFlags & FLAG_SZHP_MASK) | ((address >>> 8) & FLAG_53_MASK); MemIoImpl.addressOnBus(address, 1); break; } case 0x60: case 0x61: case 0x62: case 0x63: case 0x64: case 0x65: case 0x66: case 0x67: { /* BIT 4,(IX+d) */ bit(0x10, MemIoImpl.peek8(address)); sz5h3pnFlags = (sz5h3pnFlags & FLAG_SZHP_MASK) | ((address >>> 8) & FLAG_53_MASK); MemIoImpl.addressOnBus(address, 1); break; } case 0x68: case 0x69: case 0x6A: case 0x6B: case 0x6C: case 0x6D: case 0x6E: case 0x6F: { /* BIT 5,(IX+d) */ bit(0x20, MemIoImpl.peek8(address)); sz5h3pnFlags = (sz5h3pnFlags & FLAG_SZHP_MASK) | ((address >>> 8) & FLAG_53_MASK); MemIoImpl.addressOnBus(address, 1); break; } case 0x70: case 0x71: case 0x72: case 0x73: case 0x74: case 0x75: case 0x76: case 0x77: { /* BIT 6,(IX+d) */ bit(0x40, MemIoImpl.peek8(address)); sz5h3pnFlags = (sz5h3pnFlags & FLAG_SZHP_MASK) | ((address >>> 8) & FLAG_53_MASK); MemIoImpl.addressOnBus(address, 1); break; } case 0x78: case 0x79: case 0x7A: case 0x7B: case 0x7C: case 0x7D: case 0x7E: case 0x7F: { /* BIT 7,(IX+d) */ bit(0x80, MemIoImpl.peek8(address)); sz5h3pnFlags = (sz5h3pnFlags & FLAG_SZHP_MASK) | ((address >>> 8) & FLAG_53_MASK); MemIoImpl.addressOnBus(address, 1); break; } } } // Subconjunto de instrucciones 0xDDCB desde el código 0x80 hasta el 0xFF private void decodeDDFDCBtoFF(int opCode, int address) { switch (opCode) { case 0x80: { /* RES 0,(IX+d),B */ regB = MemIoImpl.peek8(address) & 0xFE; MemIoImpl.addressOnBus(address, 1); MemIoImpl.poke8(address, regB); break; } case 0x81: { /* RES 0,(IX+d),C */ regC = MemIoImpl.peek8(address) & 0xFE; MemIoImpl.addressOnBus(address, 1); MemIoImpl.poke8(address, regC); break; } case 0x82: { /* RES 0,(IX+d),D */ regD = MemIoImpl.peek8(address) & 0xFE; MemIoImpl.addressOnBus(address, 1); MemIoImpl.poke8(address, regD); break; } case 0x83: { /* RES 0,(IX+d),E */ regE = MemIoImpl.peek8(address) & 0xFE; MemIoImpl.addressOnBus(address, 1); MemIoImpl.poke8(address, regE); break; } case 0x84: { /* RES 0,(IX+d),H */ regH = MemIoImpl.peek8(address) & 0xFE; MemIoImpl.addressOnBus(address, 1); MemIoImpl.poke8(address, regH); break; } case 0x85: { /* RES 0,(IX+d),L */ regL = MemIoImpl.peek8(address) & 0xFE; MemIoImpl.addressOnBus(address, 1); MemIoImpl.poke8(address, regL); break; } case 0x86: { /* RES 0,(IX+d) */ int work8 = MemIoImpl.peek8(address) & 0xFE; MemIoImpl.addressOnBus(address, 1); MemIoImpl.poke8(address, work8); break; } case 0x87: { /* RES 0,(IX+d),A */ regA = MemIoImpl.peek8(address) & 0xFE; MemIoImpl.addressOnBus(address, 1); MemIoImpl.poke8(address, regA); break; } case 0x88: { /* RES 1,(IX+d),B */ regB = MemIoImpl.peek8(address) & 0xFD; MemIoImpl.addressOnBus(address, 1); MemIoImpl.poke8(address, regB); break; } case 0x89: { /* RES 1,(IX+d),C */ regC = MemIoImpl.peek8(address) & 0xFD; MemIoImpl.addressOnBus(address, 1); MemIoImpl.poke8(address, regC); break; } case 0x8A: { /* RES 1,(IX+d),D */ regD = MemIoImpl.peek8(address) & 0xFD; MemIoImpl.addressOnBus(address, 1); MemIoImpl.poke8(address, regD); break; } case 0x8B: { /* RES 1,(IX+d),E */ regE = MemIoImpl.peek8(address) & 0xFD; MemIoImpl.addressOnBus(address, 1); MemIoImpl.poke8(address, regE); break; } case 0x8C: { /* RES 1,(IX+d),H */ regH = MemIoImpl.peek8(address) & 0xFD; MemIoImpl.addressOnBus(address, 1); MemIoImpl.poke8(address, regH); break; } case 0x8D: { /* RES 1,(IX+d),L */ regL = MemIoImpl.peek8(address) & 0xFD; MemIoImpl.addressOnBus(address, 1); MemIoImpl.poke8(address, regL); break; } case 0x8E: { /* RES 1,(IX+d) */ int work8 = MemIoImpl.peek8(address) & 0xFD; MemIoImpl.addressOnBus(address, 1); MemIoImpl.poke8(address, work8); break; } case 0x8F: { /* RES 1,(IX+d),A */ regA = MemIoImpl.peek8(address) & 0xFD; MemIoImpl.addressOnBus(address, 1); MemIoImpl.poke8(address, regA); break; } case 0x90: { /* RES 2,(IX+d),B */ regB = MemIoImpl.peek8(address) & 0xFB; MemIoImpl.addressOnBus(address, 1); MemIoImpl.poke8(address, regB); break; } case 0x91: { /* RES 2,(IX+d),C */ regC = MemIoImpl.peek8(address) & 0xFB; MemIoImpl.addressOnBus(address, 1); MemIoImpl.poke8(address, regC); break; } case 0x92: { /* RES 2,(IX+d),D */ regD = MemIoImpl.peek8(address) & 0xFB; MemIoImpl.addressOnBus(address, 1); MemIoImpl.poke8(address, regD); break; } case 0x93: { /* RES 2,(IX+d),E */ regE = MemIoImpl.peek8(address) & 0xFB; MemIoImpl.addressOnBus(address, 1); MemIoImpl.poke8(address, regE); break; } case 0x94: { /* RES 2,(IX+d),H */ regH = MemIoImpl.peek8(address) & 0xFB; MemIoImpl.addressOnBus(address, 1); MemIoImpl.poke8(address, regH); break; } case 0x95: { /* RES 2,(IX+d),L */ regL = MemIoImpl.peek8(address) & 0xFB; MemIoImpl.addressOnBus(address, 1); MemIoImpl.poke8(address, regL); break; } case 0x96: { /* RES 2,(IX+d) */ int work8 = MemIoImpl.peek8(address) & 0xFB; MemIoImpl.addressOnBus(address, 1); MemIoImpl.poke8(address, work8); break; } case 0x97: { /* RES 2,(IX+d),A */ regA = MemIoImpl.peek8(address) & 0xFB; MemIoImpl.addressOnBus(address, 1); MemIoImpl.poke8(address, regA); break; } case 0x98: { /* RES 3,(IX+d),B */ regB = MemIoImpl.peek8(address) & 0xF7; MemIoImpl.addressOnBus(address, 1); MemIoImpl.poke8(address, regB); break; } case 0x99: { /* RES 3,(IX+d),C */ regC = MemIoImpl.peek8(address) & 0xF7; MemIoImpl.addressOnBus(address, 1); MemIoImpl.poke8(address, regC); break; } case 0x9A: { /* RES 3,(IX+d),D */ regD = MemIoImpl.peek8(address) & 0xF7; MemIoImpl.addressOnBus(address, 1); MemIoImpl.poke8(address, regD); break; } case 0x9B: { /* RES 3,(IX+d),E */ regE = MemIoImpl.peek8(address) & 0xF7; MemIoImpl.addressOnBus(address, 1); MemIoImpl.poke8(address, regE); break; } case 0x9C: { /* RES 3,(IX+d),H */ regH = MemIoImpl.peek8(address) & 0xF7; MemIoImpl.addressOnBus(address, 1); MemIoImpl.poke8(address, regH); break; } case 0x9D: { /* RES 3,(IX+d),L */ regL = MemIoImpl.peek8(address) & 0xF7; MemIoImpl.addressOnBus(address, 1); MemIoImpl.poke8(address, regL); break; } case 0x9E: { /* RES 3,(IX+d) */ int work8 = MemIoImpl.peek8(address) & 0xF7; MemIoImpl.addressOnBus(address, 1); MemIoImpl.poke8(address, work8); break; } case 0x9F: { /* RES 3,(IX+d),A */ regA = MemIoImpl.peek8(address) & 0xF7; MemIoImpl.addressOnBus(address, 1); MemIoImpl.poke8(address, regA); break; } case 0xA0: { /* RES 4,(IX+d),B */ regB = MemIoImpl.peek8(address) & 0xEF; MemIoImpl.addressOnBus(address, 1); MemIoImpl.poke8(address, regB); break; } case 0xA1: { /* RES 4,(IX+d),C */ regC = MemIoImpl.peek8(address) & 0xEF; MemIoImpl.addressOnBus(address, 1); MemIoImpl.poke8(address, regC); break; } case 0xA2: { /* RES 4,(IX+d),D */ regD = MemIoImpl.peek8(address) & 0xEF; MemIoImpl.addressOnBus(address, 1); MemIoImpl.poke8(address, regD); break; } case 0xA3: { /* RES 4,(IX+d),E */ regE = MemIoImpl.peek8(address) & 0xEF; MemIoImpl.addressOnBus(address, 1); MemIoImpl.poke8(address, regE); break; } case 0xA4: { /* RES 4,(IX+d),H */ regH = MemIoImpl.peek8(address) & 0xEF; MemIoImpl.addressOnBus(address, 1); MemIoImpl.poke8(address, regH); break; } case 0xA5: { /* RES 4,(IX+d),L */ regL = MemIoImpl.peek8(address) & 0xEF; MemIoImpl.addressOnBus(address, 1); MemIoImpl.poke8(address, regL); break; } case 0xA6: { /* RES 4,(IX+d) */ int work8 = MemIoImpl.peek8(address) & 0xEF; MemIoImpl.addressOnBus(address, 1); MemIoImpl.poke8(address, work8); break; } case 0xA7: { /* RES 4,(IX+d),A */ regA = MemIoImpl.peek8(address) & 0xEF; MemIoImpl.addressOnBus(address, 1); MemIoImpl.poke8(address, regA); break; } case 0xA8: { /* RES 5,(IX+d),B */ regB = MemIoImpl.peek8(address) & 0xDF; MemIoImpl.addressOnBus(address, 1); MemIoImpl.poke8(address, regB); break; } case 0xA9: { /* RES 5,(IX+d),C */ regC = MemIoImpl.peek8(address) & 0xDF; MemIoImpl.addressOnBus(address, 1); MemIoImpl.poke8(address, regC); break; } case 0xAA: { /* RES 5,(IX+d),D */ regD = MemIoImpl.peek8(address) & 0xDF; MemIoImpl.addressOnBus(address, 1); MemIoImpl.poke8(address, regD); break; } case 0xAB: { /* RES 5,(IX+d),E */ regE = MemIoImpl.peek8(address) & 0xDF; MemIoImpl.addressOnBus(address, 1); MemIoImpl.poke8(address, regE); break; } case 0xAC: { /* RES 5,(IX+d),H */ regH = MemIoImpl.peek8(address) & 0xDF; MemIoImpl.addressOnBus(address, 1); MemIoImpl.poke8(address, regH); break; } case 0xAD: { /* RES 5,(IX+d),L */ regL = MemIoImpl.peek8(address) & 0xDF; MemIoImpl.addressOnBus(address, 1); MemIoImpl.poke8(address, regL); break; } case 0xAE: { /* RES 5,(IX+d) */ int work8 = MemIoImpl.peek8(address) & 0xDF; MemIoImpl.addressOnBus(address, 1); MemIoImpl.poke8(address, work8); break; } case 0xAF: { /* RES 5,(IX+d),A */ regA = MemIoImpl.peek8(address) & 0xDF; MemIoImpl.addressOnBus(address, 1); MemIoImpl.poke8(address, regA); break; } case 0xB0: { /* RES 6,(IX+d),B */ regB = MemIoImpl.peek8(address) & 0xBF; MemIoImpl.addressOnBus(address, 1); MemIoImpl.poke8(address, regB); break; } case 0xB1: { /* RES 6,(IX+d),C */ regC = MemIoImpl.peek8(address) & 0xBF; MemIoImpl.addressOnBus(address, 1); MemIoImpl.poke8(address, regC); break; } case 0xB2: { /* RES 6,(IX+d),D */ regD = MemIoImpl.peek8(address) & 0xBF; MemIoImpl.addressOnBus(address, 1); MemIoImpl.poke8(address, regD); break; } case 0xB3: { /* RES 6,(IX+d),E */ regE = MemIoImpl.peek8(address) & 0xBF; MemIoImpl.addressOnBus(address, 1); MemIoImpl.poke8(address, regE); break; } case 0xB4: { /* RES 6,(IX+d),H */ regH = MemIoImpl.peek8(address) & 0xBF; MemIoImpl.addressOnBus(address, 1); MemIoImpl.poke8(address, regH); break; } case 0xB5: { /* RES 6,(IX+d),L */ regL = MemIoImpl.peek8(address) & 0xBF; MemIoImpl.addressOnBus(address, 1); MemIoImpl.poke8(address, regL); break; } case 0xB6: { /* RES 6,(IX+d) */ int work8 = MemIoImpl.peek8(address) & 0xBF; MemIoImpl.addressOnBus(address, 1); MemIoImpl.poke8(address, work8); break; } case 0xB7: { /* RES 6,(IX+d),A */ regA = MemIoImpl.peek8(address) & 0xBF; MemIoImpl.addressOnBus(address, 1); MemIoImpl.poke8(address, regA); break; } case 0xB8: { /* RES 7,(IX+d),B */ regB = MemIoImpl.peek8(address) & 0x7F; MemIoImpl.addressOnBus(address, 1); MemIoImpl.poke8(address, regB); break; } case 0xB9: { /* RES 7,(IX+d),C */ regC = MemIoImpl.peek8(address) & 0x7F; MemIoImpl.addressOnBus(address, 1); MemIoImpl.poke8(address, regC); break; } case 0xBA: { /* RES 7,(IX+d),D */ regD = MemIoImpl.peek8(address) & 0x7F; MemIoImpl.addressOnBus(address, 1); MemIoImpl.poke8(address, regD); break; } case 0xBB: { /* RES 7,(IX+d),E */ regE = MemIoImpl.peek8(address) & 0x7F; MemIoImpl.addressOnBus(address, 1); MemIoImpl.poke8(address, regE); break; } case 0xBC: { /* RES 7,(IX+d),H */ regH = MemIoImpl.peek8(address) & 0x7F; MemIoImpl.addressOnBus(address, 1); MemIoImpl.poke8(address, regH); break; } case 0xBD: { /* RES 7,(IX+d),L */ regL = MemIoImpl.peek8(address) & 0x7F; MemIoImpl.addressOnBus(address, 1); MemIoImpl.poke8(address, regL); break; } case 0xBE: { /* RES 7,(IX+d) */ int work8 = MemIoImpl.peek8(address) & 0x7F; MemIoImpl.addressOnBus(address, 1); MemIoImpl.poke8(address, work8); break; } case 0xBF: { /* RES 7,(IX+d),A */ regA = MemIoImpl.peek8(address) & 0x7F; MemIoImpl.addressOnBus(address, 1); MemIoImpl.poke8(address, regA); break; } case 0xC0: { /* SET 0,(IX+d),B */ regB = MemIoImpl.peek8(address) | 0x01; MemIoImpl.addressOnBus(address, 1); MemIoImpl.poke8(address, regB); break; } case 0xC1: { /* SET 0,(IX+d),C */ regC = MemIoImpl.peek8(address) | 0x01; MemIoImpl.addressOnBus(address, 1); MemIoImpl.poke8(address, regC); break; } case 0xC2: { /* SET 0,(IX+d),D */ regD = MemIoImpl.peek8(address) | 0x01; MemIoImpl.addressOnBus(address, 1); MemIoImpl.poke8(address, regD); break; } case 0xC3: { /* SET 0,(IX+d),E */ regE = MemIoImpl.peek8(address) | 0x01; MemIoImpl.addressOnBus(address, 1); MemIoImpl.poke8(address, regE); break; } case 0xC4: { /* SET 0,(IX+d),H */ regH = MemIoImpl.peek8(address) | 0x01; MemIoImpl.addressOnBus(address, 1); MemIoImpl.poke8(address, regH); break; } case 0xC5: { /* SET 0,(IX+d),L */ regL = MemIoImpl.peek8(address) | 0x01; MemIoImpl.addressOnBus(address, 1); MemIoImpl.poke8(address, regL); break; } case 0xC6: { /* SET 0,(IX+d) */ int work8 = MemIoImpl.peek8(address) | 0x01; MemIoImpl.addressOnBus(address, 1); MemIoImpl.poke8(address, work8); break; } case 0xC7: { /* SET 0,(IX+d),A */ regA = MemIoImpl.peek8(address) | 0x01; MemIoImpl.addressOnBus(address, 1); MemIoImpl.poke8(address, regA); break; } case 0xC8: { /* SET 1,(IX+d),B */ regB = MemIoImpl.peek8(address) | 0x02; MemIoImpl.addressOnBus(address, 1); MemIoImpl.poke8(address, regB); break; } case 0xC9: { /* SET 1,(IX+d),C */ regC = MemIoImpl.peek8(address) | 0x02; MemIoImpl.addressOnBus(address, 1); MemIoImpl.poke8(address, regC); break; } case 0xCA: { /* SET 1,(IX+d),D */ regD = MemIoImpl.peek8(address) | 0x02; MemIoImpl.addressOnBus(address, 1); MemIoImpl.poke8(address, regD); break; } case 0xCB: { /* SET 1,(IX+d),E */ regE = MemIoImpl.peek8(address) | 0x02; MemIoImpl.addressOnBus(address, 1); MemIoImpl.poke8(address, regE); break; } case 0xCC: { /* SET 1,(IX+d),H */ regH = MemIoImpl.peek8(address) | 0x02; MemIoImpl.addressOnBus(address, 1); MemIoImpl.poke8(address, regH); break; } case 0xCD: { /* SET 1,(IX+d),L */ regL = MemIoImpl.peek8(address) | 0x02; MemIoImpl.addressOnBus(address, 1); MemIoImpl.poke8(address, regL); break; } case 0xCE: { /* SET 1,(IX+d) */ int work8 = MemIoImpl.peek8(address) | 0x02; MemIoImpl.addressOnBus(address, 1); MemIoImpl.poke8(address, work8); break; } case 0xCF: { /* SET 1,(IX+d),A */ regA = MemIoImpl.peek8(address) | 0x02; MemIoImpl.addressOnBus(address, 1); MemIoImpl.poke8(address, regA); break; } case 0xD0: { /* SET 2,(IX+d),B */ regB = MemIoImpl.peek8(address) | 0x04; MemIoImpl.addressOnBus(address, 1); MemIoImpl.poke8(address, regB); break; } case 0xD1: { /* SET 2,(IX+d),C */ regC = MemIoImpl.peek8(address) | 0x04; MemIoImpl.addressOnBus(address, 1); MemIoImpl.poke8(address, regC); break; } case 0xD2: { /* SET 2,(IX+d),D */ regD = MemIoImpl.peek8(address) | 0x04; MemIoImpl.addressOnBus(address, 1); MemIoImpl.poke8(address, regD); break; } case 0xD3: { /* SET 2,(IX+d),E */ regE = MemIoImpl.peek8(address) | 0x04; MemIoImpl.addressOnBus(address, 1); MemIoImpl.poke8(address, regE); break; } case 0xD4: { /* SET 2,(IX+d),H */ regH = MemIoImpl.peek8(address) | 0x04; MemIoImpl.addressOnBus(address, 1); MemIoImpl.poke8(address, regH); break; } case 0xD5: { /* SET 2,(IX+d),L */ regL = MemIoImpl.peek8(address) | 0x04; MemIoImpl.addressOnBus(address, 1); MemIoImpl.poke8(address, regL); break; } case 0xD6: { /* SET 2,(IX+d) */ int work8 = MemIoImpl.peek8(address) | 0x04; MemIoImpl.addressOnBus(address, 1); MemIoImpl.poke8(address, work8); break; } case 0xD7: { /* SET 2,(IX+d),A */ regA = MemIoImpl.peek8(address) | 0x04; MemIoImpl.addressOnBus(address, 1); MemIoImpl.poke8(address, regA); break; } case 0xD8: { /* SET 3,(IX+d),B */ regB = MemIoImpl.peek8(address) | 0x08; MemIoImpl.addressOnBus(address, 1); MemIoImpl.poke8(address, regB); break; } case 0xD9: { /* SET 3,(IX+d),C */ regC = MemIoImpl.peek8(address) | 0x08; MemIoImpl.addressOnBus(address, 1); MemIoImpl.poke8(address, regC); break; } case 0xDA: { /* SET 3,(IX+d),D */ regD = MemIoImpl.peek8(address) | 0x08; MemIoImpl.addressOnBus(address, 1); MemIoImpl.poke8(address, regD); break; } case 0xDB: { /* SET 3,(IX+d),E */ regE = MemIoImpl.peek8(address) | 0x08; MemIoImpl.addressOnBus(address, 1); MemIoImpl.poke8(address, regE); break; } case 0xDC: { /* SET 3,(IX+d),H */ regH = MemIoImpl.peek8(address) | 0x08; MemIoImpl.addressOnBus(address, 1); MemIoImpl.poke8(address, regH); break; } case 0xDD: { /* SET 3,(IX+d),L */ regL = MemIoImpl.peek8(address) | 0x08; MemIoImpl.addressOnBus(address, 1); MemIoImpl.poke8(address, regL); break; } case 0xDE: { /* SET 3,(IX+d) */ int work8 = MemIoImpl.peek8(address) | 0x08; MemIoImpl.addressOnBus(address, 1); MemIoImpl.poke8(address, work8); break; } case 0xDF: { /* SET 3,(IX+d),A */ regA = MemIoImpl.peek8(address) | 0x08; MemIoImpl.addressOnBus(address, 1); MemIoImpl.poke8(address, regA); break; } case 0xE0: { /* SET 4,(IX+d),B */ regB = MemIoImpl.peek8(address) | 0x10; MemIoImpl.addressOnBus(address, 1); MemIoImpl.poke8(address, regB); break; } case 0xE1: { /* SET 4,(IX+d),C */ regC = MemIoImpl.peek8(address) | 0x10; MemIoImpl.addressOnBus(address, 1); MemIoImpl.poke8(address, regC); break; } case 0xE2: { /* SET 4,(IX+d),D */ regD = MemIoImpl.peek8(address) | 0x10; MemIoImpl.addressOnBus(address, 1); MemIoImpl.poke8(address, regD); break; } case 0xE3: { /* SET 4,(IX+d),E */ regE = MemIoImpl.peek8(address) | 0x10; MemIoImpl.addressOnBus(address, 1); MemIoImpl.poke8(address, regE); break; } case 0xE4: { /* SET 4,(IX+d),H */ regH = MemIoImpl.peek8(address) | 0x10; MemIoImpl.addressOnBus(address, 1); MemIoImpl.poke8(address, regH); break; } case 0xE5: { /* SET 4,(IX+d),L */ regL = MemIoImpl.peek8(address) | 0x10; MemIoImpl.addressOnBus(address, 1); MemIoImpl.poke8(address, regL); break; } case 0xE6: { /* SET 4,(IX+d) */ int work8 = MemIoImpl.peek8(address) | 0x10; MemIoImpl.addressOnBus(address, 1); MemIoImpl.poke8(address, work8); break; } case 0xE7: { /* SET 4,(IX+d),A */ regA = MemIoImpl.peek8(address) | 0x10; MemIoImpl.addressOnBus(address, 1); MemIoImpl.poke8(address, regA); break; } case 0xE8: { /* SET 5,(IX+d),B */ regB = MemIoImpl.peek8(address) | 0x20; MemIoImpl.addressOnBus(address, 1); MemIoImpl.poke8(address, regB); break; } case 0xE9: { /* SET 5,(IX+d),C */ regC = MemIoImpl.peek8(address) | 0x20; MemIoImpl.addressOnBus(address, 1); MemIoImpl.poke8(address, regC); break; } case 0xEA: { /* SET 5,(IX+d),D */ regD = MemIoImpl.peek8(address) | 0x20; MemIoImpl.addressOnBus(address, 1); MemIoImpl.poke8(address, regD); break; } case 0xEB: { /* SET 5,(IX+d),E */ regE = MemIoImpl.peek8(address) | 0x20; MemIoImpl.addressOnBus(address, 1); MemIoImpl.poke8(address, regE); break; } case 0xEC: { /* SET 5,(IX+d),H */ regH = MemIoImpl.peek8(address) | 0x20; MemIoImpl.addressOnBus(address, 1); MemIoImpl.poke8(address, regH); break; } case 0xED: { /* SET 5,(IX+d),L */ regL = MemIoImpl.peek8(address) | 0x20; MemIoImpl.addressOnBus(address, 1); MemIoImpl.poke8(address, regL); break; } case 0xEE: { /* SET 5,(IX+d) */ int work8 = MemIoImpl.peek8(address) | 0x20; MemIoImpl.addressOnBus(address, 1); MemIoImpl.poke8(address, work8); break; } case 0xEF: { /* SET 5,(IX+d),A */ regA = MemIoImpl.peek8(address) | 0x20; MemIoImpl.addressOnBus(address, 1); MemIoImpl.poke8(address, regA); break; } case 0xF0: { /* SET 6,(IX+d),B */ regB = MemIoImpl.peek8(address) | 0x40; MemIoImpl.addressOnBus(address, 1); MemIoImpl.poke8(address, regB); break; } case 0xF1: { /* SET 6,(IX+d),C */ regC = MemIoImpl.peek8(address) | 0x40; MemIoImpl.addressOnBus(address, 1); MemIoImpl.poke8(address, regC); break; } case 0xF2: { /* SET 6,(IX+d),D */ regD = MemIoImpl.peek8(address) | 0x40; MemIoImpl.addressOnBus(address, 1); MemIoImpl.poke8(address, regD); break; } case 0xF3: { /* SET 6,(IX+d),E */ regE = MemIoImpl.peek8(address) | 0x40; MemIoImpl.addressOnBus(address, 1); MemIoImpl.poke8(address, regE); break; } case 0xF4: { /* SET 6,(IX+d),H */ regH = MemIoImpl.peek8(address) | 0x40; MemIoImpl.addressOnBus(address, 1); MemIoImpl.poke8(address, regH); break; } case 0xF5: { /* SET 6,(IX+d),L */ regL = MemIoImpl.peek8(address) | 0x40; MemIoImpl.addressOnBus(address, 1); MemIoImpl.poke8(address, regL); break; } case 0xF6: { /* SET 6,(IX+d) */ int work8 = MemIoImpl.peek8(address) | 0x40; MemIoImpl.addressOnBus(address, 1); MemIoImpl.poke8(address, work8); break; } case 0xF7: { /* SET 6,(IX+d),A */ regA = MemIoImpl.peek8(address) | 0x40; MemIoImpl.addressOnBus(address, 1); MemIoImpl.poke8(address, regA); break; } case 0xF8: { /* SET 7,(IX+d),B */ regB = MemIoImpl.peek8(address) | 0x80; MemIoImpl.addressOnBus(address, 1); MemIoImpl.poke8(address, regB); break; } case 0xF9: { /* SET 7,(IX+d),C */ regC = MemIoImpl.peek8(address) | 0x80; MemIoImpl.addressOnBus(address, 1); MemIoImpl.poke8(address, regC); break; } case 0xFA: { /* SET 7,(IX+d),D */ regD = MemIoImpl.peek8(address) | 0x80; MemIoImpl.addressOnBus(address, 1); MemIoImpl.poke8(address, regD); break; } case 0xFB: { /* SET 7,(IX+d),E */ regE = MemIoImpl.peek8(address) | 0x80; MemIoImpl.addressOnBus(address, 1); MemIoImpl.poke8(address, regE); break; } case 0xFC: { /* SET 7,(IX+d),H */ regH = MemIoImpl.peek8(address) | 0x80; MemIoImpl.addressOnBus(address, 1); MemIoImpl.poke8(address, regH); break; } case 0xFD: { /* SET 7,(IX+d),L */ regL = MemIoImpl.peek8(address) | 0x80; MemIoImpl.addressOnBus(address, 1); MemIoImpl.poke8(address, regL); break; } case 0xFE: { /* SET 7,(IX+d) */ int work8 = MemIoImpl.peek8(address) | 0x80; MemIoImpl.addressOnBus(address, 1); MemIoImpl.poke8(address, work8); break; } case 0xFF: { /* SET 7,(IX+d),A */ regA = MemIoImpl.peek8(address) | 0x80; MemIoImpl.addressOnBus(address, 1); MemIoImpl.poke8(address, regA); break; } } } //Subconjunto de instrucciones 0xED private void decodeED(int opCode) { prefixOpcode = 0; switch (opCode) { case 0x40: { /* IN B,(C) */ memptr = getRegBC(); regB = MemIoImpl.inPort(memptr++); sz5h3pnFlags = sz53pn_addTable[regB]; flagQ = true; break; } case 0x41: { /* OUT (C),B */ memptr = getRegBC(); MemIoImpl.outPort(memptr++, regB); break; } case 0x42: { /* SBC HL,BC */ MemIoImpl.addressOnBus(getPairIR(), 7); sbc16(getRegBC()); break; } case 0x43: { /* LD (nn),BC */ memptr = MemIoImpl.peek16(regPC); MemIoImpl.poke16(memptr++, getRegBC()); regPC = (regPC + 2) & 0xffff; break; } case 0x44: case 0x4C: case 0x54: case 0x5C: case 0x64: case 0x6C: case 0x74: case 0x7C: { /* NEG */ int aux = regA; regA = 0; sub(aux); break; } case 0x45: case 0x4D: /* RETI */ case 0x55: case 0x5D: case 0x65: case 0x6D: case 0x75: case 0x7D: { /* RETN */ ffIFF1 = ffIFF2; regPC = memptr = pop(); break; } case 0x46: case 0x4E: case 0x66: case 0x6E: { /* IM 0 */ setIM(IntMode.IM0); break; } case 0x47: { /* LD I,A */ /* * El contended-tstate se produce con el contenido de I *antes* * de ser copiado el del registro A. Detalle importante. */ MemIoImpl.addressOnBus(getPairIR(), 1); regI = regA; break; } case 0x48: { /* IN C,(C) */ memptr = getRegBC(); regC = MemIoImpl.inPort(memptr++); sz5h3pnFlags = sz53pn_addTable[regC]; flagQ = true; break; } case 0x49: { /* OUT (C),C */ memptr = getRegBC(); MemIoImpl.outPort(memptr++, regC); break; } case 0x4A: { /* ADC HL,BC */ MemIoImpl.addressOnBus(getPairIR(), 7); adc16(getRegBC()); break; } case 0x4B: { /* LD BC,(nn) */ memptr = MemIoImpl.peek16(regPC); setRegBC(MemIoImpl.peek16(memptr++)); regPC = (regPC + 2) & 0xffff; break; } case 0x4F: { /* LD R,A */ MemIoImpl.addressOnBus(getPairIR(), 1); setRegR(regA); break; } case 0x50: { /* IN D,(C) */ memptr = getRegBC(); regD = MemIoImpl.inPort(memptr++); sz5h3pnFlags = sz53pn_addTable[regD]; flagQ = true; break; } case 0x51: { /* OUT (C),D */ memptr = getRegBC(); MemIoImpl.outPort(memptr++, regD); break; } case 0x52: { /* SBC HL,DE */ MemIoImpl.addressOnBus(getPairIR(), 7); sbc16(getRegDE()); break; } case 0x53: { /* LD (nn),DE */ memptr = MemIoImpl.peek16(regPC); MemIoImpl.poke16(memptr++, getRegDE()); regPC = (regPC + 2) & 0xffff; break; } case 0x56: case 0x76: { /* IM 1 */ setIM(IntMode.IM1); break; } case 0x57: { /* LD A,I */ MemIoImpl.addressOnBus(getPairIR(), 1); regA = regI; sz5h3pnFlags = sz53n_addTable[regA]; if (ffIFF2 && !MemIoImpl.isActiveINT()) { sz5h3pnFlags |= PARITY_MASK; } flagQ = true; break; } case 0x58: { /* IN E,(C) */ memptr = getRegBC(); regE = MemIoImpl.inPort(memptr++); sz5h3pnFlags = sz53pn_addTable[regE]; flagQ = true; break; } case 0x59: { /* OUT (C),E */ memptr = getRegBC(); MemIoImpl.outPort(memptr++, regE); break; } case 0x5A: { /* ADC HL,DE */ MemIoImpl.addressOnBus(getPairIR(), 7); adc16(getRegDE()); break; } case 0x5B: { /* LD DE,(nn) */ memptr = MemIoImpl.peek16(regPC); setRegDE(MemIoImpl.peek16(memptr++)); regPC = (regPC + 2) & 0xffff; break; } case 0x5E: case 0x7E: { /* IM 2 */ setIM(IntMode.IM2); break; } case 0x5F: { /* LD A,R */ MemIoImpl.addressOnBus(getPairIR(), 1); regA = getRegR(); sz5h3pnFlags = sz53n_addTable[regA]; if (ffIFF2 && !MemIoImpl.isActiveINT()) { sz5h3pnFlags |= PARITY_MASK; } flagQ = true; break; } case 0x60: { /* IN H,(C) */ memptr = getRegBC(); regH = MemIoImpl.inPort(memptr++); sz5h3pnFlags = sz53pn_addTable[regH]; flagQ = true; break; } case 0x61: { /* OUT (C),H */ memptr = getRegBC(); MemIoImpl.outPort(memptr++, regH); break; } case 0x62: { /* SBC HL,HL */ MemIoImpl.addressOnBus(getPairIR(), 7); sbc16(getRegHL()); break; } case 0x63: { /* LD (nn),HL */ memptr = MemIoImpl.peek16(regPC); MemIoImpl.poke16(memptr++, getRegHL()); regPC = (regPC + 2) & 0xffff; break; } case 0x67: { /* RRD */ rrd(); break; } case 0x68: { /* IN L,(C) */ memptr = getRegBC(); regL = MemIoImpl.inPort(memptr++); sz5h3pnFlags = sz53pn_addTable[regL]; flagQ = true; break; } case 0x69: { /* OUT (C),L */ memptr = getRegBC(); MemIoImpl.outPort(memptr++, regL); break; } case 0x6A: { /* ADC HL,HL */ MemIoImpl.addressOnBus(getPairIR(), 7); adc16(getRegHL()); break; } case 0x6B: { /* LD HL,(nn) */ memptr = MemIoImpl.peek16(regPC); setRegHL(MemIoImpl.peek16(memptr++)); regPC = (regPC + 2) & 0xffff; break; } case 0x6F: { /* RLD */ rld(); break; } case 0x70: { /* IN (C) */ memptr = getRegBC(); int inPort = MemIoImpl.inPort(memptr++); sz5h3pnFlags = sz53pn_addTable[inPort]; flagQ = true; break; } case 0x71: { /* OUT (C),0 */ memptr = getRegBC(); MemIoImpl.outPort(memptr++, 0x00); break; } case 0x72: { /* SBC HL,SP */ MemIoImpl.addressOnBus(getPairIR(), 7); sbc16(regSP); break; } case 0x73: { /* LD (nn),SP */ memptr = MemIoImpl.peek16(regPC); MemIoImpl.poke16(memptr++, regSP); regPC = (regPC + 2) & 0xffff; break; } case 0x78: { /* IN A,(C) */ memptr = getRegBC(); regA = MemIoImpl.inPort(memptr++); sz5h3pnFlags = sz53pn_addTable[regA]; flagQ = true; break; } case 0x79: { /* OUT (C),A */ memptr = getRegBC(); MemIoImpl.outPort(memptr++, regA); break; } case 0x7A: { /* ADC HL,SP */ MemIoImpl.addressOnBus(getPairIR(), 7); adc16(regSP); break; } case 0x7B: { /* LD SP,(nn) */ memptr = MemIoImpl.peek16(regPC); regSP = MemIoImpl.peek16(memptr++); regPC = (regPC + 2) & 0xffff; break; } case 0xA0: { /* LDI */ ldi(); break; } case 0xA1: { /* CPI */ cpi(); break; } case 0xA2: { /* INI */ ini(); break; } case 0xA3: { /* OUTI */ outi(); break; } case 0xA8: { /* LDD */ ldd(); break; } case 0xA9: { /* CPD */ cpd(); break; } case 0xAA: { /* IND */ ind(); break; } case 0xAB: { /* OUTD */ outd(); break; } case 0xB0: { /* LDIR */ ldi(); if ((sz5h3pnFlags & PARITY_MASK) == PARITY_MASK) { regPC = (regPC - 2) & 0xffff; memptr = regPC + 1; MemIoImpl.addressOnBus((getRegDE() - 1) & 0xffff, 5); } break; } case 0xB1: { /* CPIR */ cpi(); if ((sz5h3pnFlags & PARITY_MASK) == PARITY_MASK && (sz5h3pnFlags & ZERO_MASK) == 0) { regPC = (regPC - 2) & 0xffff; memptr = regPC + 1; MemIoImpl.addressOnBus((getRegHL() - 1) & 0xffff, 5); } break; } case 0xB2: { /* INIR */ ini(); if (regB != 0) { regPC = (regPC - 2) & 0xffff; MemIoImpl.addressOnBus((getRegHL() - 1) & 0xffff, 5); } break; } case 0xB3: { /* OTIR */ outi(); if (regB != 0) { regPC = (regPC - 2) & 0xffff; MemIoImpl.addressOnBus(getRegBC(), 5); } break; } case 0xB8: { /* LDDR */ ldd(); if ((sz5h3pnFlags & PARITY_MASK) == PARITY_MASK) { regPC = (regPC - 2) & 0xffff; memptr = regPC + 1; MemIoImpl.addressOnBus((getRegDE() + 1) & 0xffff, 5); } break; } case 0xB9: { /* CPDR */ cpd(); if ((sz5h3pnFlags & PARITY_MASK) == PARITY_MASK && (sz5h3pnFlags & ZERO_MASK) == 0) { regPC = (regPC - 2) & 0xffff; memptr = regPC + 1; MemIoImpl.addressOnBus((getRegHL() + 1) & 0xffff, 5); } break; } case 0xBA: { /* INDR */ ind(); if (regB != 0) { regPC = (regPC - 2) & 0xffff; MemIoImpl.addressOnBus((getRegHL() + 1) & 0xffff, 5); } break; } case 0xBB: { /* OTDR */ outd(); if (regB != 0) { regPC = (regPC - 2) & 0xffff; MemIoImpl.addressOnBus(getRegBC(), 5); } break; } case 0xDD: prefixOpcode = 0xDD; break; case 0xED: prefixOpcode = 0xED; break; case 0xFD: prefixOpcode = 0xFD; break; default: { // System.out.println("Error instrucción ED " + Integer.toHexString(opCode)); break; } } } }