private void initOpCodes() { // ---------------------------------------------------------------------------------------------- // reinitialize OpCode table for additional 4 Z80 prefixes - none, CB, DD, ED, FD // - combinations DD, FD, CB m_OpCodes = new OperationCode[0x100 * 7]; m_dictOpCodePrefix = new Dictionary <int, int>(6); m_dictOpCodePrefix.Add(0xCB, 0x100); m_dictOpCodePrefix.Add(0xDD, 0x200); m_dictOpCodePrefix.Add(0xED, 0x300); m_dictOpCodePrefix.Add(0xFD, 0x400); m_dictOpCodePrefix.Add(0xDDCB, 0x500); m_dictOpCodePrefix.Add(0xFDCB, 0x600); // ---------------------------------------------------------------------------------------------- // OpCode initialization (ordered according to Zilog Z80 CPU Specifications by Sean Young) initOpCodes8BitLoadGroup(); // 8 bit Load group initOpCodes16BitLoadGroup(); // 16 bit Load group initOpCodesExchangeGroup(); // Exchange group initOpCodesBlockTransferGroup(); // Block Transfer group initOpCodesSearchGroup(); // Search group initOpCodes8BitArithLogGroup(); // 8 bit Arithmetic & Logical group initOpCodes16BitArithLogGroup(); // 16 bit Arithmetic & Logical group initOpCodesJumpGroup(); // Jump group initOpCodesCallAndReturnGroup(); // Call and Return group initOpCodesGenPurposeArithGroup(); // General Purpose Arithmetic group initOpCodesRotateAndShiftGroup(); // Rotate and Shift group initOpCodesCPUControlGroup(); // CPU control group initOpCodesBITManipulationGroup(); // Bit Manipulation group initOpCodesInputAndOutputGroup(); // Input and Output group }
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; } }
private StringBuilder m_sbDebug; // build operations debug string #endif public MOS6502() : base() { // initialize OpCode table // reference see http://homepage.ntlworld.com/cyborgsystems/CS_Main/6502/6502.htm m_OpCodes[0x00] = new OperationCode("BRK", 1, 7, _ADDR_IMP, _BRK); m_OpCodes[0x01] = new OperationCode("ORA", 2, 6, _ADDR_INDX_1, _ORA); m_OpCodes[0x05] = new OperationCode("ORA", 2, 3, _ADDR_ZP, _ORA); m_OpCodes[0x06] = new OperationCode("ASL", 2, 5, _ADDR_ZP, _ASL); m_OpCodes[0x08] = new OperationCode("PHP", 1, 3, _ADDR_IMP, _PHP); m_OpCodes[0x09] = new OperationCode("ORA", 2, 2, _ADDR_IMM, _ORA); m_OpCodes[0x0a] = new OperationCode("ASL", 1, 2, _ADDR_ACC, _ASL); m_OpCodes[0x0d] = new OperationCode("ORA", 3, 4, _ADDR_ABS, _ORA); m_OpCodes[0x0e] = new OperationCode("ASL", 3, 6, _ADDR_ABS, _ASL); m_OpCodes[0x10] = new OperationCode("BPL", 2, 2, _ADDR_REL_1, _BPL); m_OpCodes[0x11] = new OperationCode("ORA", 2, 5, _ADDR_INDY_1, _ORA); m_OpCodes[0x15] = new OperationCode("ORA", 2, 4, _ADDR_ZPX_1, _ORA); m_OpCodes[0x16] = new OperationCode("ASL", 2, 6, _ADDR_ZPX_1, _ASL); m_OpCodes[0x18] = new OperationCode("CLC", 1, 2, _ADDR_IMP, _CLC); m_OpCodes[0x19] = new OperationCode("ORA", 3, 4, _ADDR_ABSY_1, _ORA); m_OpCodes[0x1d] = new OperationCode("ORA", 3, 4, _ADDR_ABSX_1, _ORA); m_OpCodes[0x1e] = new OperationCode("ASL", 3, 7, _ADDR_ABSX_1, _ASL); m_OpCodes[0x20] = new OperationCode("JSR", 3, 6, _ADDR_ABS, _JSR); m_OpCodes[0x21] = new OperationCode("AND", 2, 6, _ADDR_INDX_1, _AND); m_OpCodes[0x24] = new OperationCode("BIT", 2, 3, _ADDR_ZP, _BIT); m_OpCodes[0x25] = new OperationCode("AND", 2, 3, _ADDR_ZP, _AND); m_OpCodes[0x26] = new OperationCode("ROL", 2, 5, _ADDR_ZP, _ROL); m_OpCodes[0x28] = new OperationCode("PLP", 1, 4, _ADDR_IMP, _PLP); m_OpCodes[0x29] = new OperationCode("AND", 2, 2, _ADDR_IMM, _AND); m_OpCodes[0x2a] = new OperationCode("ROL", 1, 2, _ADDR_ACC, _ROL); m_OpCodes[0x2c] = new OperationCode("BIT", 3, 4, _ADDR_ABS, _BIT); m_OpCodes[0x2d] = new OperationCode("AND", 3, 4, _ADDR_ABS, _AND); m_OpCodes[0x2e] = new OperationCode("ROL", 3, 6, _ADDR_ABS, _ROL); m_OpCodes[0x30] = new OperationCode("BMI", 2, 2, _ADDR_REL_1, _BMI); m_OpCodes[0x31] = new OperationCode("AND", 2, 5, _ADDR_INDY_1, _AND); m_OpCodes[0x35] = new OperationCode("AND", 2, 4, _ADDR_ZPX_1, _AND); m_OpCodes[0x36] = new OperationCode("ROL", 2, 6, _ADDR_ZPX_1, _ROL); m_OpCodes[0x38] = new OperationCode("SEC", 1, 2, _ADDR_IMP, _SEC); m_OpCodes[0x39] = new OperationCode("AND", 3, 4, _ADDR_ABSY_1, _AND); m_OpCodes[0x3d] = new OperationCode("AND", 3, 4, _ADDR_ABSX_1, _AND); m_OpCodes[0x3e] = new OperationCode("ROL", 3, 7, _ADDR_ABSX_1, _ROL); m_OpCodes[0x40] = new OperationCode("RTI", 1, 6, _ADDR_IMP, _RTI); m_OpCodes[0x41] = new OperationCode("EOR", 2, 6, _ADDR_INDX_1, _EOR); m_OpCodes[0x45] = new OperationCode("EOR", 2, 3, _ADDR_ZP, _EOR); m_OpCodes[0x46] = new OperationCode("LSR", 2, 5, _ADDR_ZP, _LSR); m_OpCodes[0x48] = new OperationCode("PHA", 1, 3, _ADDR_IMP, _PHA); m_OpCodes[0x49] = new OperationCode("EOR", 2, 2, _ADDR_IMM, _EOR); m_OpCodes[0x4a] = new OperationCode("LSR", 1, 2, _ADDR_ACC, _LSR); m_OpCodes[0x4c] = new OperationCode("JMP", 3, 3, _ADDR_ABS, _JMP); m_OpCodes[0x4d] = new OperationCode("EOR", 3, 4, _ADDR_ABS, _EOR); m_OpCodes[0x4e] = new OperationCode("LSR", 3, 6, _ADDR_ABS, _LSR); m_OpCodes[0x50] = new OperationCode("BVC", 2, 2, _ADDR_REL_1, _BVC); m_OpCodes[0x51] = new OperationCode("EOR", 2, 5, _ADDR_INDY_1, _EOR); m_OpCodes[0x55] = new OperationCode("EOR", 2, 4, _ADDR_ZPX_1, _EOR); m_OpCodes[0x56] = new OperationCode("LSR", 2, 6, _ADDR_ZPX_1, _LSR); m_OpCodes[0x58] = new OperationCode("CLI", 1, 2, _ADDR_IMP, _CLI); m_OpCodes[0x59] = new OperationCode("EOR", 3, 4, _ADDR_ABSY_1, _EOR); m_OpCodes[0x5d] = new OperationCode("EOR", 3, 4, _ADDR_ABSX_1, _EOR); m_OpCodes[0x5e] = new OperationCode("LSR", 3, 7, _ADDR_ABSX_1, _LSR); m_OpCodes[0x60] = new OperationCode("RTS", 1, 6, _ADDR_IMP, _RTS); m_OpCodes[0x61] = new OperationCode("ADC", 2, 6, _ADDR_INDX_1, _ADC); m_OpCodes[0x65] = new OperationCode("ADC", 2, 3, _ADDR_ZP, _ADC); m_OpCodes[0x66] = new OperationCode("ROR", 2, 5, _ADDR_ZP, _ROR); m_OpCodes[0x68] = new OperationCode("PLA", 1, 4, _ADDR_IMP, _PLA); m_OpCodes[0x69] = new OperationCode("ADC", 2, 2, _ADDR_IMM, _ADC); m_OpCodes[0x6a] = new OperationCode("ROR", 1, 2, _ADDR_ACC, _ROR); m_OpCodes[0x6c] = new OperationCode("JMP", 3, 5, _ADDR_IND_1, _JMP); m_OpCodes[0x6d] = new OperationCode("ADC", 3, 4, _ADDR_ABS, _ADC); m_OpCodes[0x6e] = new OperationCode("ROR", 3, 6, _ADDR_ABS, _ROR); m_OpCodes[0x70] = new OperationCode("BVS", 2, 2, _ADDR_REL_1, _BVS); m_OpCodes[0x71] = new OperationCode("ADC", 2, 5, _ADDR_INDY_1, _ADC); m_OpCodes[0x75] = new OperationCode("ADC", 2, 4, _ADDR_ZPX_1, _ADC); m_OpCodes[0x76] = new OperationCode("ROR", 2, 6, _ADDR_ZPX_1, _ROR); m_OpCodes[0x78] = new OperationCode("SEI", 1, 2, _ADDR_IMP, _SEI); m_OpCodes[0x79] = new OperationCode("ADC", 3, 4, _ADDR_ABSY_1, _ADC); m_OpCodes[0x7d] = new OperationCode("ADC", 3, 4, _ADDR_ABSX_1, _ADC); m_OpCodes[0x7e] = new OperationCode("ROR", 3, 7, _ADDR_ABSX_1, _ROR); m_OpCodes[0x81] = new OperationCode("STA", 2, 6, _ADDR_INDX_1, _STA); m_OpCodes[0x84] = new OperationCode("STY", 2, 3, _ADDR_ZP, _STY); m_OpCodes[0x85] = new OperationCode("STA", 2, 3, _ADDR_ZP, _STA); m_OpCodes[0x86] = new OperationCode("STX", 2, 3, _ADDR_ZP, _STX); m_OpCodes[0x88] = new OperationCode("DEY", 1, 2, _ADDR_IMP, _DEY); m_OpCodes[0x8a] = new OperationCode("TXA", 1, 2, _ADDR_IMP, _TXA); m_OpCodes[0x8c] = new OperationCode("STY", 3, 4, _ADDR_ABS, _STY); m_OpCodes[0x8d] = new OperationCode("STA", 3, 4, _ADDR_ABS, _STA); m_OpCodes[0x8e] = new OperationCode("STX", 3, 4, _ADDR_ABS, _STX); m_OpCodes[0x90] = new OperationCode("BCC", 2, 2, _ADDR_REL_1, _BCC); m_OpCodes[0x91] = new OperationCode("STA", 2, 6, _ADDR_INDY_1, _STA); m_OpCodes[0x94] = new OperationCode("STY", 2, 4, _ADDR_ZPX_1, _STY); m_OpCodes[0x95] = new OperationCode("STA", 2, 4, _ADDR_ZPX_1, _STA); m_OpCodes[0x96] = new OperationCode("STX", 2, 4, _ADDR_ZPY_1, _STX); m_OpCodes[0x98] = new OperationCode("TYA", 1, 2, _ADDR_IMP, _TYA); m_OpCodes[0x99] = new OperationCode("STA", 3, 5, _ADDR_ABSY_1, _STA); m_OpCodes[0x9a] = new OperationCode("TXS", 1, 2, _ADDR_IMP, _TXS); m_OpCodes[0x9d] = new OperationCode("STA", 3, 5, _ADDR_ABSX_1, _STA); m_OpCodes[0xa0] = new OperationCode("LDY", 2, 2, _ADDR_IMM, _LDY); m_OpCodes[0xa1] = new OperationCode("LDA", 2, 6, _ADDR_INDX_1, _LDA); m_OpCodes[0xa2] = new OperationCode("LDX", 2, 2, _ADDR_IMM, _LDX); m_OpCodes[0xa4] = new OperationCode("LDY", 2, 3, _ADDR_ZP, _LDY); m_OpCodes[0xa5] = new OperationCode("LDA", 2, 3, _ADDR_ZP, _LDA); m_OpCodes[0xa6] = new OperationCode("LDX", 2, 3, _ADDR_ZP, _LDX); m_OpCodes[0xa8] = new OperationCode("TAY", 1, 2, _ADDR_IMP, _TAY); m_OpCodes[0xa9] = new OperationCode("LDA", 2, 2, _ADDR_IMM, _LDA); m_OpCodes[0xaa] = new OperationCode("TAX", 1, 2, _ADDR_IMP, _TAX); m_OpCodes[0xac] = new OperationCode("LDY", 3, 4, _ADDR_ABS, _LDY); m_OpCodes[0xad] = new OperationCode("LDA", 3, 4, _ADDR_ABS, _LDA); m_OpCodes[0xae] = new OperationCode("LDX", 3, 4, _ADDR_ABS, _LDX); m_OpCodes[0xB0] = new OperationCode("BCS", 2, 2, _ADDR_REL_1, _BCS); m_OpCodes[0xb1] = new OperationCode("LDA", 2, 5, _ADDR_INDY_1, _LDA); m_OpCodes[0xb4] = new OperationCode("LDY", 2, 4, _ADDR_ZPX_1, _LDY); m_OpCodes[0xb5] = new OperationCode("LDA", 2, 4, _ADDR_ZPX_1, _LDA); m_OpCodes[0xb6] = new OperationCode("LDX", 2, 4, _ADDR_ZPY_1, _LDX); m_OpCodes[0xb8] = new OperationCode("CLV", 1, 2, _ADDR_IMP, _CLV); m_OpCodes[0xb9] = new OperationCode("LDA", 3, 4, _ADDR_ABSY_1, _LDA); m_OpCodes[0xba] = new OperationCode("TSX", 1, 2, _ADDR_IMP, _TSX); m_OpCodes[0xbc] = new OperationCode("LDY", 3, 4, _ADDR_ABSX_1, _LDY); m_OpCodes[0xbd] = new OperationCode("LDA", 3, 4, _ADDR_ABSX_1, _LDA); m_OpCodes[0xbe] = new OperationCode("LDX", 3, 4, _ADDR_ABSY_1, _LDX); m_OpCodes[0xc0] = new OperationCode("CPY", 2, 2, _ADDR_IMM, _CPY); m_OpCodes[0xc1] = new OperationCode("CMP", 2, 6, _ADDR_INDX_1, _CMP); m_OpCodes[0xc4] = new OperationCode("CPY", 2, 3, _ADDR_ZP, _CPY); m_OpCodes[0xc5] = new OperationCode("CMP", 2, 3, _ADDR_ZP, _CMP); m_OpCodes[0xc6] = new OperationCode("DEC", 2, 5, _ADDR_ZP, _DEC); m_OpCodes[0xc8] = new OperationCode("INY", 1, 2, _ADDR_IMP, _INY); m_OpCodes[0xc9] = new OperationCode("CMP", 2, 2, _ADDR_IMM, _CMP); m_OpCodes[0xca] = new OperationCode("DEX", 1, 2, _ADDR_IMP, _DEX); m_OpCodes[0xcc] = new OperationCode("CPY", 3, 4, _ADDR_ABS, _CPY); m_OpCodes[0xcd] = new OperationCode("CMP", 3, 4, _ADDR_ABS, _CMP); m_OpCodes[0xce] = new OperationCode("DEC", 3, 6, _ADDR_ABS, _DEC); m_OpCodes[0xD0] = new OperationCode("BNE", 2, 2, _ADDR_REL_1, _BNE); m_OpCodes[0xd1] = new OperationCode("CMP", 2, 5, _ADDR_INDY_1, _CMP); m_OpCodes[0xd5] = new OperationCode("CMP", 2, 4, _ADDR_ZPX_1, _CMP); m_OpCodes[0xd6] = new OperationCode("DEC", 2, 6, _ADDR_ZPX_1, _DEC); m_OpCodes[0xd8] = new OperationCode("CLD", 1, 2, _ADDR_IMP, _CLD); m_OpCodes[0xd9] = new OperationCode("CMP", 3, 4, _ADDR_ABSY_1, _CMP); m_OpCodes[0xdd] = new OperationCode("CMP", 3, 4, _ADDR_ABSX_1, _CMP); m_OpCodes[0xde] = new OperationCode("DEC", 3, 7, _ADDR_ABSX_1, _DEC); m_OpCodes[0xe0] = new OperationCode("CPX", 2, 2, _ADDR_IMM, _CPX); m_OpCodes[0xe1] = new OperationCode("SBC", 2, 6, _ADDR_INDX_1, _SBC); m_OpCodes[0xe4] = new OperationCode("CPX", 2, 3, _ADDR_ZP, _CPX); m_OpCodes[0xe5] = new OperationCode("SBC", 2, 3, _ADDR_ZP, _SBC); m_OpCodes[0xe6] = new OperationCode("INC", 2, 5, _ADDR_ZP, _INC); m_OpCodes[0xe8] = new OperationCode("INX", 1, 2, _ADDR_IMP, _INX); m_OpCodes[0xe9] = new OperationCode("SBC", 2, 2, _ADDR_IMM, _SBC); m_OpCodes[0xea] = new OperationCode("NOP", 1, 2, _ADDR_IMP, _NOP); m_OpCodes[0xec] = new OperationCode("CPX", 3, 4, _ADDR_ABS, _CPX); m_OpCodes[0xed] = new OperationCode("SBC", 3, 4, _ADDR_ABS, _SBC); m_OpCodes[0xee] = new OperationCode("INC", 3, 6, _ADDR_ABS, _INC); m_OpCodes[0xF0] = new OperationCode("BEQ", 2, 2, _ADDR_REL_1, _BEQ); m_OpCodes[0xf1] = new OperationCode("SBC", 2, 5, _ADDR_INDY_1, _SBC); m_OpCodes[0xf5] = new OperationCode("SBC", 2, 4, _ADDR_ZPX_1, _SBC); m_OpCodes[0xf6] = new OperationCode("INC", 2, 6, _ADDR_ZPX_1, _INC); m_OpCodes[0xf8] = new OperationCode("SED", 1, 2, _ADDR_IMP, _SED); m_OpCodes[0xf9] = new OperationCode("SBC", 3, 4, _ADDR_ABSY_1, _SBC); m_OpCodes[0xfd] = new OperationCode("SBC", 3, 4, _ADDR_ABSX_1, _SBC); m_OpCodes[0xfe] = new OperationCode("INC", 3, 7, _ADDR_ABSX_1, _INC); }
protected CPUState m_State; // current state of the CPU public CPU8Bit() : base() { m_PC = 0x0000; // Program counter starts at $0 m_OpCodes = new OperationCode[0x100]; }
public void emulateCycle() { switch (m_State) { case CPUState.fetchopcode: // check and process Interrupt (only when in OpCode fetch) if (m_Interrupt) { m_MaxCycles = 7; m_Cycle = 1; m_address = 0; m_addr = Addressing._not_set_; m_OperandValue = 0; m_State = CPUState.interrupt; break; } // save current PC for debugging / tracing m_PC_Start = m_PC; // get the next byte and then move the program counter forward byte opCode = getNextMemByte(); // get from OpCode table m_oc = m_OpCodes[opCode]; // check if OpCode is defined if (String.IsNullOrEmpty(m_oc.OpCode) || m_oc.executeOperation == null || m_oc.executeAddressing == null) { string sMessage = String.Format("PC {0:X4} : OpCode {1:X2} unknown!!!", m_PC_Start, opCode); throw new NotImplementedException(sMessage); } #if CPU_TRACE m_sbDebug = new StringBuilder(); m_sbDebug.AppendFormat("{0:X4}:{1:X2} {2} ", m_PC_Start, opCode, m_oc.OpCode); #endif m_MaxCycles = m_oc.Cycles; m_Cycle = 1; m_address = 0; m_addr = Addressing._not_set_; m_OperandValue = 0; m_State = CPUState.addressing; break; case CPUState.addressing: // addressing m_oc.executeAddressing(); m_Cycle++; 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 m_sbDebug.AppendFormat("\tPC:{0:X4} A:{1:X2} X:{2:X2} Y:{3:X2} SP:{4:X4} |{5}| STACK: {6:X2} {7:X2} {8:X2} {9:X2}", m_PC, m_reg_A, m_reg_X, m_reg_Y, Reg_SP, StatusString, m_ram[m_StackPtr - m_ramOffset], m_ram[m_StackPtr + 1 - m_ramOffset], m_ram[m_StackPtr + 2 - m_ramOffset], m_ram[m_StackPtr + 3 - m_ramOffset]); Debug.WriteLine(m_sbDebug.ToString()); #endif } } else { m_Cycle++; } break; case CPUState.interrupt: if (m_Cycle == m_MaxCycles) // emulate cycle exactness by making operation effective on last cycle { push_stack((byte)(m_PC >> 8)); push_stack((byte)m_PC); push_stack(m_reg_SR); Flag_I = true; m_PC = readMemWord(0xFFFE); // fetch IRQ vector m_State = CPUState.fetchopcode; m_Interrupt = false; } else { m_Cycle++; } break; } }