/// <summary> /// BRK Force Break /// </summary> /// <param name="mem"></param> private void brk(MemoryInfo mem) { Push16(pc_register); php(mem); sei(mem); pc_register = Read16(0xFFFE); }
/// <summary> /// Add memory to accumulator with carry /// </summary> /// <param name="mem"></param> private void adc(MemoryInfo mem) { byte acc = accumulator; byte value = RAM.ReadMemory(mem.Address); byte carry = carry_flag; accumulator = (byte)(accumulator + value + carry); setZero(accumulator); setSign(accumulator); int sum = accumulator + value + carry; if (sum > 0xFF) { carry_flag = 1; } else { carry_flag = 0; } if (((acc ^ value) & 0x80) == 0 && ((acc ^ accumulator) & 0x80) != 0) { overflow_flag = 1; } else { overflow_flag = 0; } }
/// <summary> /// SBC Subtract memory from accumulator with borrow /// </summary> /// <param name="mem"></param> private void sbc(MemoryInfo mem) { byte acc = accumulator; byte value = RAM.ReadMemory(mem.Address); byte carry = carry_flag; accumulator = (byte)(accumulator - value - (1 - carry)); setZero(accumulator); setSign(accumulator); int diff = accumulator - value - (1 - carry); if (diff >= 0) { carry_flag = 1; } else { carry_flag = 0; } if (((acc ^ value) & 0x80) != 0 && ((acc ^ accumulator) & 0x80) != 0) { overflow_flag = 1; } else { overflow_flag = 0; } }
/// <summary> /// BVS Branch on overflow set /// </summary> /// <param name="mem"></param> private void bvs(MemoryInfo mem) { if (overflow_flag != 0) { pc_register = mem.Address; addCycles(mem); } }
/// <summary> /// INC Increment memory by one /// </summary> /// <param name="mem"></param> private void inc(MemoryInfo mem) { byte value = (byte)(RAM.ReadMemory(mem.Address) + 1); RAM.WriteMemory(mem.Address, value); setZero(value); setSign(value); }
/// <summary> /// BIT Test bits in memory with accumulator /// </summary> /// <param name="mem"></param> private void bit(MemoryInfo mem) { byte value = RAM.ReadMemory(mem.Address); overflow_flag = (byte)((value >> 6) & 1); setZero((byte)(value & accumulator)); setSign(value); }
/// <summary> /// BPL Branch on result plus /// </summary> /// <param name="mem"></param> private void bpl(MemoryInfo mem) { if (sign_flag == 0) { pc_register = mem.Address; addCycles(mem); } }
/// <summary> /// BCS Branch on carry set /// </summary> /// <param name="mem"></param> private void bcs(MemoryInfo mem) { if (carry_flag != 0) { pc_register = mem.Address; addCycles(mem); } }
/// <summary> /// /// </summary> /// <param name="mem"></param> private void addCycles(MemoryInfo mem) { Cycle++; if (pagesDiffer(mem.PC_register, mem.Address)) { Cycle++; } }
/// <summary> /// BNE Branch on result not zero /// </summary> /// <param name="mem"></param> private void bne(MemoryInfo mem) { if (zero_flag == 0) { pc_register = mem.Address; addCycles(mem); } }
/// <summary> /// ASL Shift Left One Bit (Memory or Accumulator) /// </summary> /// <param name="mem"></param> private void asl(MemoryInfo mem) { if (mem.Addr_mode == (int)AddressingMode.Accumulator) { carry_flag = (byte)((accumulator >> 7) & 1); accumulator <<= 1; setZero(accumulator); setSign(accumulator); } else { byte value = RAM.ReadMemory(mem.Address); carry_flag = (byte)((value >> 7) & 1); value <<= 1; RAM.WriteMemory(mem.Address, value); setZero(value); setSign(value); } }
/// <summary> /// ROR Rotate one bit right (memory or accumulator) /// </summary> /// <param name="mem"></param> private void ror(MemoryInfo mem) { if (mem.Addr_mode == (int)AddressingMode.Accumulator) { byte carry = carry_flag; carry_flag = (byte)(accumulator & 1); accumulator = (byte)((accumulator >> 1) | (carry << 7)); setZero(accumulator); setSign(accumulator); } else { byte carry = carry_flag; byte value = RAM.ReadMemory(mem.Address); carry_flag = (byte)(value & 1); value = (byte)((value >> 1) | (carry << 7)); RAM.WriteMemory(mem.Address, value); setZero(value); setSign(value); } }
/// <summary> /// "AND" memory with accumulator /// </summary> /// <param name="mem"></param> private void and(MemoryInfo mem) { accumulator = (byte)(accumulator & RAM.ReadMemory(mem.Address)); setZero(accumulator); setSign(accumulator); }
/// <summary> /// Executes the next instruction at the location of PC in the memory /// </summary> public uint Tick() { if (Stall > 0) { Stall--; return(1); } uint cycles = Cycle; switch (interrupt) { case (InterruptMode.IRQInterrupt): irq(); break; case (InterruptMode.NMIInterrupt): nmi(); break; default: break; } interrupt = InterruptMode.NoneInterrupt; byte opcode = RAM.ReadMemory(pc_register); //Console.Write(instructions[opcode]); if (inject) { opcode = injectVal; inject = false; } int addrMode = addressingMode[opcode]; currentInstruction = opcode; ushort addr = 0; bool pageCrossed = false; switch (addrMode) { case ((int)AddressingMode.Absolute): addr = Read16((ushort)(pc_register + 1)); break; case ((int)AddressingMode.AbsoluteX): addr = (ushort)(Read16((ushort)(pc_register + 1)) + reg_x); pageCrossed = pagesDiffer((ushort)(addr - reg_x), addr); break; case ((int)AddressingMode.AbsoluteY): addr = (ushort)(Read16((ushort)(pc_register + 1)) + reg_y); pageCrossed = pagesDiffer((ushort)(addr - reg_y), addr); break; case ((int)AddressingMode.Accumulator): addr = 0; break; case ((int)AddressingMode.Immediate): addr = (ushort)(pc_register + 1); break; case ((int)AddressingMode.Implied): addr = 0; break; case ((int)AddressingMode.IndirectX): addr = errorRead16((ushort)(RAM.ReadMemory((ushort)(pc_register + 1)) + reg_x)); break; case ((int)AddressingMode.Indirect): addr = errorRead16(Read16((ushort)(pc_register + 1))); break; case ((int)AddressingMode.IndirectY): addr = (ushort)(errorRead16(RAM.ReadMemory((ushort)(pc_register + 1))) + reg_y); pageCrossed = pagesDiffer((ushort)(addr - reg_y), addr); break; case ((int)AddressingMode.Relative): ushort offset = RAM.ReadMemory((ushort)(pc_register + 1)); if (offset < 0x80) { addr = (ushort)(pc_register + 2 + offset); } else { addr = (ushort)(pc_register + 2 + offset - 0x100); } break; case ((int)AddressingMode.ZeroPage): addr = RAM.ReadMemory((ushort)(pc_register + 1)); break; case ((int)AddressingMode.ZeroPageX): addr = (ushort)(RAM.ReadMemory((ushort)(pc_register + 1)) + reg_x); break; case ((int)AddressingMode.ZeroPageY): addr = (ushort)(RAM.ReadMemory((ushort)(pc_register + 1)) + reg_y); break; } //sw.WriteLine(instructions[opcode] + " " + pc_register.ToString("X4") + " " + addr.ToString("X4")); pc_register += instructionSize[opcode]; Cycle += instructionCycles[opcode]; if (pageCrossed) { Cycle += pageCrossedCycle[opcode]; } //Console.WriteLine(addr); MemoryInfo mem = new MemoryInfo(addr, pc_register, addrMode); CurrentAddress = addr; instructionAction[opcode](mem); return(Cycle - cycles); }
/// <summary> /// TYA Transfer index Y to accumulator /// </summary> /// <param name="mem"></param> private void tya(MemoryInfo mem) { accumulator = reg_y; setZero(accumulator); setSign(accumulator); }
private void xaa(MemoryInfo mem) { }
private void dcp(MemoryInfo mem) { }
private void axs(MemoryInfo mem) { }
private void anc(MemoryInfo mem) { }
private void isc(MemoryInfo mem) { }
private void shy(MemoryInfo mem) { }
private void sax(MemoryInfo mem) { }
private void rra(MemoryInfo mem) { }
private void kil(MemoryInfo mem) { }
/// <summary> /// Transfer the value stored at X to the stack pointer /// </summary> /// <param name="mem"></param> private void txs(MemoryInfo mem) { stack_pointer = reg_x; }
private void arr(MemoryInfo mem) { }
private void sre(MemoryInfo mem) { }
private void tas(MemoryInfo mem) { }
private void slo(MemoryInfo mem) { }
/// <summary> /// Illegal Opcodes below /// These options were not implemented in the NES. However they can be /// implemented to provide a complete 6502 CPU implementation. /// http://nesdev.com/undocumented_opcodes.txt /// </summary> private void ahx(MemoryInfo mem) { }