public void emulateCycle() { if (m_Interrupt != InterruptSignal.None) { m_State = CPUState.interrupt; } switch (m_State) { case CPUState.fetchopcode: m_PC_Start = m_PC; m_Cycle = 1; m_ExtraCycles = false; m_byteDisplacement = 0; m_OpCodePrefix = 0; m_OpCodeIndex = getNextMemByte(); m_oc = m_OpCodes[m_OpCodeIndex]; int iIndexOffset = 0; if (m_OpCodeIndex == 0xCB || // evaluate prefix m_OpCodeIndex == 0xDD || m_OpCodeIndex == 0xED || m_OpCodeIndex == 0xFD) { m_OpCodePrefix = m_OpCodeIndex; iIndexOffset = m_dictOpCodePrefix[m_OpCodePrefix]; m_OpCodeIndex = getNextMemByte(); if (m_OpCodeIndex == 0xCB) // DD CB or FD CB combination { m_OpCodePrefix <<= 8; m_OpCodePrefix |= m_OpCodeIndex; iIndexOffset = m_dictOpCodePrefix[m_OpCodePrefix]; m_byteDisplacement = getNextMemByte(); // contains displacement before OpCode m_OpCodeIndex = getNextMemByte(); } m_oc = m_OpCodes[iIndexOffset + m_OpCodeIndex]; } // check if OpCode is defined if (String.IsNullOrEmpty(m_oc.OpCode) || m_oc.executeOperation == null) { string sMessage; if (m_OpCodePrefix > 0) { sMessage = String.Format("PC {0:X4} : OpCode {1:X2} {2:X2} unknown!!!", m_PC_Start, (byte)m_OpCodePrefix, (byte)m_OpCodeIndex); } else { sMessage = String.Format("PC {0:X4} : OpCode {1:X2} unknown!!!", m_PC_Start, (byte)m_OpCodeIndex); } throw new NotImplementedException(sMessage); } #if CPU_TRACE m_ei.Counter++; m_ei.PC = m_PC_Start; m_ei.Bytes = ""; if (m_OpCodePrefix != 0) { m_ei.Bytes += String.Format("{0:X2} ", m_OpCodePrefix); } m_ei.Bytes += String.Format("{0:X2} ", m_OpCodeIndex); m_ei.OpCode = m_oc.OpCode; m_ei.Op1 = ""; m_ei.Op2 = ""; #endif // increase R register (only bits 6-0) m_reg_R = (byte)((m_reg_R & 0x80) | ((m_reg_R + 1) & 0x7F)); // set for next processing state m_wordValue = 0; m_byteValue = 0; #if NO_CYCLE_FILLUP m_MaxCycles = m_PC - m_PC_Start; #else m_MaxCycles = m_oc.Cycles; #endif m_State = CPUState.addressing; break; case CPUState.interrupt: // interrupt switch (m_Interrupt) { case InterruptSignal.NMI: // perform a RST 66h m_reg_SP -= 2;; writeMemWord(m_reg_SP, m_PC); m_PC = 0x0066; m_State = CPUState.fetchopcode; m_Interrupt = InterruptSignal.None; break; case InterruptSignal.IRQ: switch (m_IM) { case 0: // TODO Z80 implement IM 0 throw new NotImplementedException("Z80 IM 0 not implemented!"); case 1: // IM 1 - perform a RST 38h m_reg_SP -= 2;; writeMemWord(m_reg_SP, m_PC); m_PC = 0x0038; m_State = CPUState.fetchopcode; m_Interrupt = InterruptSignal.None; break; case 2: // IM 2 - jump to interrupt vector m_reg_SP -= 2;; writeMemWord(m_reg_SP, m_PC); m_PC = m_reg_I; m_State = CPUState.fetchopcode; m_Interrupt = InterruptSignal.None; break; } break; } break; case CPUState.addressing: // addressing m_Cycle++; m_oc.executeAddressing(); break; case CPUState.operation: if (m_Cycle >= m_MaxCycles) // emulate cycle exactness by making operation effective on last cycle { m_oc.executeOperation(); if (m_Cycle < m_MaxCycles) { m_Cycle++; // operation executed induced another cycle (e.g. branch operations) } else { m_State = CPUState.fetchopcode; // operation finished -> get next opcode } #if CPU_TRACE //if (m_PC_Start == 0x188) { m_TraceActive = true; m_ei.Counter = 1; } //if (m_PC_Start == 0x18B) m_TraceActive = false; if (m_State == CPUState.fetchopcode && m_TraceActive) { StringBuilder sb = new StringBuilder(); if ((m_ei.Counter % 20) == 1) { sb.Clear(); sb.Append("PC-- "); sb.Append("----------- OpCo Op1,Op2---|"); sb.Append("A F B C D E H L "); //sb.Append("A' F' B' C' D' E' H' L' "); sb.Append("IX IY SP I R |"); sb.Append("SZ5H3vNC|"); sb.Append("Disassembly Check---|"); sb.Append("STACK ---------------"); Debug.WriteLine(sb.ToString()); } sb.Clear(); sb.AppendFormat("{0:X4} ", m_ei.PC); sb.Append(m_ei.Bytes.PadRight(12)); sb.Append(m_ei.OpCode.PadRight(5)); if (!String.IsNullOrEmpty(m_ei.Op1) && !String.IsNullOrEmpty(m_ei.Op2)) { sb.Append((m_ei.Op1 + "," + m_ei.Op2).PadRight(10)); } else { sb.Append((m_ei.Op1 + m_ei.Op2).PadRight(10)); } sb.Append("|"); sb.AppendFormat("{0:X2} ", m_reg_A); sb.AppendFormat("{0:X2} ", Flags); sb.AppendFormat("{0:X2} ", m_reg_B); sb.AppendFormat("{0:X2} ", m_reg_C); sb.AppendFormat("{0:X2} ", m_reg_D); sb.AppendFormat("{0:X2} ", m_reg_E); sb.AppendFormat("{0:X2} ", m_reg_H); sb.AppendFormat("{0:X2} ", m_reg_L); //sb.AppendFormat("{0:X2} ", m_reg_A_Alt); //sb.AppendFormat("{0:X2} ", m_reg_Flags_Alt); //sb.AppendFormat("{0:X2} ", m_reg_B_Alt); //sb.AppendFormat("{0:X2} ", m_reg_C_Alt); //sb.AppendFormat("{0:X2} ", m_reg_D_Alt); //sb.AppendFormat("{0:X2} ", m_reg_E_Alt); //sb.AppendFormat("{0:X2} ", m_reg_H_Alt); //sb.AppendFormat("{0:X2} ", m_reg_L_Alt); sb.AppendFormat("{0:X4} ", m_reg_IX); sb.AppendFormat("{0:X4} ", m_reg_IY); sb.AppendFormat("{0:X4} ", m_reg_SP); sb.AppendFormat("{0:X2} ", m_reg_I); sb.AppendFormat("{0:X2} ", m_reg_R); sb.Append("|"); sb.Append(Convert.ToString(Flags, 2).PadLeft(8, '0')); sb.Append("|"); string strDisassemblyCheck = m_dis.Disassemble(() => readMemByte(m_ei.PC++)); sb.Append(strDisassemblyCheck.PadRight(20)); sb.Append("|"); for (int spDump = m_reg_SP; spDump <= m_reg_SP + 5; spDump++) { sb.AppendFormat("{0:X2} ", readMemByte((UInt16)spDump)); } Debug.WriteLine(sb.ToString()); sb = null; } #endif } else { m_Cycle++; } break; } }
public static void GenerateOpcodeSizes() { Z80_Disassembler disasm = new Z80_Disassembler(); for (int i = 0; i < 256; i++) { int pc = 0; byte[] opcode = { (byte)i, 0, 0, 0 }; disasm.Disassemble(() => opcode[pc++]); opcodeSizes[0, i] = (sbyte)pc; } opcodeSizes[0, 0xCB] = -1; opcodeSizes[0, 0xED] = -2; opcodeSizes[0, 0xDD] = -3; opcodeSizes[0, 0xFD] = -4; for (int i = 0; i < 256; i++) { int pc = 0; byte[] opcode = { 0xCB, (byte)i, 0, 0, 0 }; disasm.Disassemble(() => opcode[pc++]); opcodeSizes[1, i] = (sbyte)pc; } for (int i = 0; i < 256; i++) { int pc = 0; byte[] opcode = { 0xED, (byte)i, 0, 0, 0 }; disasm.Disassemble(() => opcode[pc++]); opcodeSizes[2, i] = (sbyte)pc; } for (int i = 0; i < 256; i++) { int pc = 0; byte[] opcode = { 0xDD, (byte)i, 0, 0, 0 }; disasm.Disassemble(() => opcode[pc++]); opcodeSizes[3, i] = (sbyte)pc; } opcodeSizes[3, 0xCB] = -5; opcodeSizes[3, 0xED] = -2; for (int i = 0; i < 256; i++) { int pc = 0; byte[] opcode = { 0xFD, (byte)i, 0, 0, 0 }; disasm.Disassemble(() => opcode[pc++]); opcodeSizes[4, i] = (sbyte)pc; } opcodeSizes[3, 0xCB] = -6; opcodeSizes[3, 0xED] = -2; for (int i = 0; i < 256; i++) { int pc = 0; byte[] opcode = { 0xDD, 0xCB, (byte)i, 0, 0, 0 }; disasm.Disassemble(() => opcode[pc++]); opcodeSizes[5, i] = (sbyte)pc; } for (int i = 0; i < 256; i++) { int pc = 0; byte[] opcode = { 0xFD, 0xCB, (byte)i, 0, 0, 0 }; disasm.Disassemble(() => opcode[pc++]); opcodeSizes[6, i] = (sbyte)pc; } }