private void RTS(OpcodeInfo op, TextWriter w) { w.WriteLine(Spaces + "PC = ReadMemory((ushort)(++S + 0x100));"); w.WriteLine(Spaces + "PC |= (ushort)(ReadMemory((ushort)(++S + 0x100)) << 8);"); w.WriteLine(Spaces + "PC++;"); w.WriteLine(Spaces + "PendingCycles -= {0}; TotalExecutedCycles += {0};", op.Cycles); }
private void AND(OpcodeInfo op, TextWriter w) { GetValue8(op, w, "value8"); w.WriteLine(Spaces + "A &= value8;"); w.WriteLine(Spaces + SetNZ("A")); w.WriteLine(Spaces + "PendingCycles -= {0}; TotalExecutedCycles += {0};", op.Cycles); }
private void GetValue8(OpcodeInfo op, TextWriter w, string dest) { switch (op.AddressMode) { case AddrMode.Immediate: w.WriteLine(Spaces + dest + " = ReadMemory(PC++);"); break; case AddrMode.ZeroPage: w.WriteLine(Spaces + dest + " = ReadMemory(ReadMemory(PC++));"); break; case AddrMode.ZeroPageX: w.WriteLine(Spaces + dest + " = ReadMemory((byte)(ReadMemory(PC++)+X));"); break; case AddrMode.ZeroPageY: w.WriteLine(Spaces + dest + " = ReadMemory((byte)(ReadMemory(PC++)+Y));"); break; case AddrMode.Absolute: w.WriteLine(Spaces + dest + " = ReadMemory(ReadWord(PC)); PC += 2;"); break; case AddrMode.AbsoluteX_P: w.WriteLine(Spaces + "temp16 = ReadWord(PC);"); w.WriteLine(Spaces + dest + " = ReadMemory((ushort)(temp16+X));"); w.WriteLine(Spaces + "if ((temp16 & 0xFF00) != ((temp16 + X) & 0xFF00)) "); w.WriteLine(Spaces + " { PendingCycles--; TotalExecutedCycles++; }"); w.WriteLine(Spaces + "PC += 2;"); break; case AddrMode.AbsoluteX: w.WriteLine(Spaces + dest + " = ReadMemory((ushort)(ReadWord(PC)+X));"); w.WriteLine(Spaces + "PC += 2;"); break; case AddrMode.AbsoluteY_P: w.WriteLine(Spaces + "temp16 = ReadWord(PC);"); w.WriteLine(Spaces + dest + " = ReadMemory((ushort)(temp16+Y));"); w.WriteLine(Spaces + "if ((temp16 & 0xFF00) != ((temp16 + Y) & 0xFF00)) "); w.WriteLine(Spaces + " { PendingCycles--; TotalExecutedCycles++; }"); w.WriteLine(Spaces + "PC += 2;"); break; case AddrMode.AbsoluteY: w.WriteLine(Spaces + dest + " = ReadMemory((ushort)(ReadWord(PC)+Y));"); w.WriteLine(Spaces + "PC += 2;"); break; case AddrMode.IndirectX: w.WriteLine(Spaces + dest + " = ReadMemory(ReadWordPageWrap((byte)(ReadMemory(PC++)+X)));"); break; case AddrMode.IndirectY: w.WriteLine(Spaces + dest + " = ReadMemory(ReadWordPageWrap((byte)(ReadMemory(PC++)+Y)));"); break; case AddrMode.IndirectY_P: w.WriteLine(Spaces + "temp16 = ReadWordPageWrap(ReadMemory(PC++));"); w.WriteLine(Spaces + dest + " = ReadMemory((ushort)(temp16+Y));"); w.WriteLine(Spaces + "if ((temp16 & 0xFF00) != ((temp16+Y) & 0xFF00)) "); w.WriteLine(Spaces + " { PendingCycles--; TotalExecutedCycles++; }"); break; } }
private void CMP_reg(OpcodeInfo op, TextWriter w, string reg) { GetValue8(op, w, "value8"); w.WriteLine(Spaces + "value16 = (ushort) (" + reg + " - value8);"); w.WriteLine(Spaces + "FlagC = (" + reg + " >= value8);"); w.WriteLine(Spaces + SetNZ("(byte)value16")); w.WriteLine(Spaces + "PendingCycles -= {0}; TotalExecutedCycles += {0};", op.Cycles); }
private void JSR(OpcodeInfo op, TextWriter w) { w.WriteLine(Spaces + "temp16 = (ushort)(PC+1);"); w.WriteLine(Spaces + "WriteMemory((ushort)(S-- + 0x100), (byte)(temp16 >> 8));"); w.WriteLine(Spaces + "WriteMemory((ushort)(S-- + 0x100), (byte)temp16);"); w.WriteLine(Spaces + "PC = ReadWord(PC);"); w.WriteLine(Spaces + "PendingCycles -= {0}; TotalExecutedCycles += {0};", op.Cycles); }
private void INC(OpcodeInfo op, TextWriter w) { GetAddress(op, w, "value16"); w.WriteLine(Spaces + "value8 = (byte)(ReadMemory(value16) + 1);"); w.WriteLine(Spaces + "WriteMemory(value16, value8);"); w.WriteLine(Spaces + SetNZ("value8")); w.WriteLine(Spaces + "PendingCycles -= {0}; TotalExecutedCycles += {0};", op.Cycles); }
private void BIT(OpcodeInfo op, TextWriter w) { GetValue8(op, w, "value8"); w.WriteLine(Spaces + "FlagN = (value8 & 0x80) != 0;"); w.WriteLine(Spaces + "FlagV = (value8 & 0x40) != 0;"); w.WriteLine(Spaces + "FlagZ = (A & value8) == 0;"); w.WriteLine(Spaces + "PendingCycles -= {0}; TotalExecutedCycles += {0};", op.Cycles); }
private void RTI(OpcodeInfo op, TextWriter w) { w.WriteLine(Spaces + "P = ReadMemory((ushort)(++S + 0x100));"); w.WriteLine("FlagT = true;// this seems wrong");//this seems wrong w.WriteLine(Spaces + "PC = ReadMemory((ushort)(++S + 0x100));"); w.WriteLine(Spaces + "PC |= (ushort)(ReadMemory((ushort)(++S + 0x100)) << 8);"); w.WriteLine(Spaces + "PendingCycles -= {0}; TotalExecutedCycles += {0};", op.Cycles); }
private void SBC(OpcodeInfo op, TextWriter w) { GetValue8(op, w, "value8"); w.WriteLine(Spaces + "temp = A - value8 - (FlagC?0:1);"); w.WriteLine(Spaces + "FlagV = ((A ^ value8) & (A ^ temp) & 0x80) != 0;"); w.WriteLine(Spaces + "FlagC = temp >= 0;"); w.WriteLine(Spaces + "A = (byte)temp;"); w.WriteLine(Spaces + SetNZ("A")); w.WriteLine(Spaces + "PendingCycles -= {0}; TotalExecutedCycles += {0};", op.Cycles); }
private void JMP(OpcodeInfo op, TextWriter w) { switch (op.AddressMode) { case AddrMode.Absolute: w.WriteLine(Spaces + "PC = ReadWord(PC);"); break; case AddrMode.Indirect: w.WriteLine(Spaces + "PC = ReadWordPageWrap(ReadWord(PC));"); break; } w.WriteLine(Spaces + "PendingCycles -= {0}; TotalExecutedCycles += {0};", op.Cycles); }
private void ADC(OpcodeInfo op, TextWriter w) { GetValue8(op, w, "value8"); w.WriteLine(Spaces + "temp = value8 + A + (FlagC ? 1 : 0);"); w.WriteLine(Spaces + "FlagV = (~(A ^ value8) & (A ^ temp) & 0x80) != 0;"); w.WriteLine(Spaces + "FlagC = temp > 0xFF;"); w.WriteLine(Spaces + "A = (byte)temp;"); w.WriteLine(Spaces + SetNZ("A")); w.WriteLine(Spaces + "PendingCycles -= {0}; TotalExecutedCycles += {0};", op.Cycles); }
private void Branch(OpcodeInfo op, TextWriter w, string flag, bool cond) { GetAddress(op, w, "value16"); w.WriteLine(Spaces + "if (Flag" + flag + " == " + cond.ToString().ToLower() + ") {"); w.WriteLine(Spaces + " PendingCycles--; TotalExecutedCycles++;"); w.WriteLine(Spaces + " if ((PC & 0xFF00) != (value16 & 0xFF00)) "); w.WriteLine(Spaces + " { PendingCycles--; TotalExecutedCycles++; }"); w.WriteLine(Spaces + " PC = value16;"); w.WriteLine(Spaces + "}"); w.WriteLine(Spaces + "PendingCycles -= {0}; TotalExecutedCycles += {0};", op.Cycles); }
private void NOP(OpcodeInfo op, TextWriter w) { // This code is quite insufficient, but at least, we have to increment program counter appropriately. // For immediate addressing mode, it will be correct, and it will fix desyncs of "Puzznic (J)" and "Puzznic (U)". // For other addressing modes, I don't know whether they access memory, so further investigation will be needed. if (op.Size > 1) { w.WriteLine(Spaces + "PC += {0};", op.Size - 1); } w.WriteLine(Spaces + "PendingCycles -= {0}; TotalExecutedCycles += {0};", op.Cycles); }
private void Branch(OpcodeInfo op, TextWriter w, string flag, bool cond) { GetAddress(op, w, "value16"); w.WriteLine(Spaces + "if (Flag"+flag+" == "+cond.ToString().ToLower()+") {"); w.WriteLine(Spaces + " PendingCycles--; TotalExecutedCycles++;"); w.WriteLine(Spaces + " if ((PC & 0xFF00) != (value16 & 0xFF00)) "); w.WriteLine(Spaces + " { PendingCycles--; TotalExecutedCycles++; }"); w.WriteLine(Spaces + " PC = value16;"); w.WriteLine(Spaces + "}"); w.WriteLine(Spaces + "PendingCycles -= {0}; TotalExecutedCycles += {0};", op.Cycles); }
private void Set(byte value, string instr, AddrMode addressMode, int cycles) { var op = new OpcodeInfo(); op.Instruction = instr; op.AddressMode = addressMode; op.Cycles = cycles; if (Opcodes[value] != null) { throw new Exception("opcode " + value + " already assigned"); } Opcodes[value] = op; }
private void PLP(OpcodeInfo op, TextWriter w) { w.WriteLine(Spaces + "//handle I flag differently. sort of a sloppy way to do the job, but it does finish it off."); w.WriteLine(Spaces + "value8 = ReadMemory((ushort)(++S + 0x100));"); w.WriteLine(Spaces + "if ((value8 & 0x04) != 0 && !FlagI)"); w.WriteLine(Spaces + "\tSEI_Pending = true;"); w.WriteLine(Spaces + "if ((value8 & 0x04) == 0 && FlagI)"); w.WriteLine(Spaces + "\tCLI_Pending = true;"); w.WriteLine(Spaces + "value8 &= unchecked((byte)~0x04);"); w.WriteLine(Spaces + "P &= 0x04;"); w.WriteLine(Spaces + "P |= value8;"); w.WriteLine("FlagT = true;//this seems wrong");//this seems wrong w.WriteLine(Spaces + "PendingCycles -= {0}; TotalExecutedCycles += {0};", op.Cycles); }
private void ASL(OpcodeInfo op, TextWriter w) { if (op.AddressMode == AddrMode.Accumulator) { w.WriteLine(Spaces + "FlagC = (A & 0x80) != 0;"); w.WriteLine(Spaces + "A = (byte) (A << 1);"); w.WriteLine(Spaces + SetNZ("A")); } else { GetAddress(op, w, "value16"); w.WriteLine(Spaces + "value8 = ReadMemory(value16);"); w.WriteLine(Spaces + "FlagC = (value8 & 0x80) != 0;"); w.WriteLine(Spaces + "value8 = (byte)(value8 << 1);"); w.WriteLine(Spaces + "WriteMemory(value16, value8);"); w.WriteLine(Spaces + SetNZ("value8")); } w.WriteLine(Spaces + "PendingCycles -= {0}; TotalExecutedCycles += {0};", op.Cycles); }
private void ROR(OpcodeInfo op, TextWriter w) { if (op.AddressMode == AddrMode.Accumulator) { w.WriteLine(Spaces + "temp8 = A;"); w.WriteLine(Spaces + "A = (byte)((A >> 1) | ((P & 1)<<7));"); w.WriteLine(Spaces + "FlagC = (temp8 & 1) != 0;"); w.WriteLine(Spaces + SetNZ("A")); } else { GetAddress(op, w, "value16"); w.WriteLine(Spaces + "value8 = temp8 = ReadMemory(value16);"); w.WriteLine(Spaces + "value8 = (byte)((value8 >> 1) | ((P & 1)<<7));"); w.WriteLine(Spaces + "WriteMemory(value16, value8);"); w.WriteLine(Spaces + "FlagC = (temp8 & 1) != 0;"); w.WriteLine(Spaces + SetNZ("value8")); } w.WriteLine(Spaces + "PendingCycles -= {0}; TotalExecutedCycles += {0};", op.Cycles); }
private void GetAddress(OpcodeInfo op, TextWriter w, string dest) { // TODO it APPEARS that the +1 opcode penalty applies to all AbsoluteX, AbsoluteY, and IndirectY // but this is not completely clear. the doc has some exceptions, but are they real? switch (op.AddressMode) { case AddrMode.ZeroPage: w.WriteLine(Spaces + dest + " = ReadMemory(PC++);"); break; case AddrMode.ZeroPageX: w.WriteLine(Spaces + dest + " = (byte)(ReadMemory(PC++)+X);"); break; case AddrMode.ZeroPageY: w.WriteLine(Spaces + dest + " = (byte)(ReadMemory(PC++)+Y);"); break; case AddrMode.Absolute: w.WriteLine(Spaces + dest + " = ReadWord(PC); PC += 2;"); break; case AddrMode.AbsoluteX: w.WriteLine(Spaces + dest + " = (ushort)(ReadWord(PC)+X);"); w.WriteLine(Spaces + "PC += 2;"); break; case AddrMode.AbsoluteX_P: w.WriteLine(Spaces + "temp16 = ReadWord(PC);"); w.WriteLine(Spaces + dest + " = (ushort)(temp16+X);"); w.WriteLine(Spaces + "if ((temp16 & 0xFF00) != ((temp16 + X) & 0xFF00)) "); w.WriteLine(Spaces + " { PendingCycles--; TotalExecutedCycles++; }"); w.WriteLine(Spaces + "PC += 2;"); break; case AddrMode.AbsoluteY: w.WriteLine(Spaces + dest + " = (ushort)(ReadWord(PC)+Y);"); w.WriteLine(Spaces + "PC += 2;"); break; case AddrMode.AbsoluteY_P: w.WriteLine(Spaces + "temp16 = ReadWord(PC);"); w.WriteLine(Spaces + dest + " = (ushort)(temp16+Y);"); w.WriteLine(Spaces + "if ((temp16 & 0xFF00) != ((temp16 + Y) & 0xFF00)) "); w.WriteLine(Spaces + " { PendingCycles--; TotalExecutedCycles++; }"); w.WriteLine(Spaces + "PC += 2;"); break; case AddrMode.IndirectX: w.WriteLine(Spaces + "temp8 = (byte)(ReadMemory(PC++) + X);"); w.WriteLine(Spaces + dest + " = ReadWordPageWrap(temp8);"); break; case AddrMode.IndirectY: w.WriteLine(Spaces + "temp16 = ReadWordPageWrap(ReadMemory(PC++));"); w.WriteLine(Spaces + dest + " = (ushort)(temp16+Y);"); break; case AddrMode.IndirectY_P: w.WriteLine(Spaces + "temp16 = ReadWordPageWrap(ReadMemory(PC++));"); w.WriteLine(Spaces + dest + " = (ushort)(temp16+Y);"); w.WriteLine(Spaces + "if ((temp16 & 0xFF00) != ((temp16+Y) & 0xFF00)) "); w.WriteLine(Spaces + " { PendingCycles--; TotalExecutedCycles++; }"); break; case AddrMode.Relative: w.WriteLine(Spaces + "rel8 = (sbyte)ReadMemory(PC++);"); w.WriteLine(Spaces + dest + " = (ushort)(PC+rel8);"); break; } }
private void TYA(OpcodeInfo op, TextWriter w) { w.WriteLine(Spaces + "A = Y;"); w.WriteLine(Spaces + SetNZ("A")); w.WriteLine(Spaces + "PendingCycles -= {0}; TotalExecutedCycles += {0};", op.Cycles); }
private void STY(OpcodeInfo op, TextWriter w) { GetAddress(op, w, "value16"); w.WriteLine(Spaces + "WriteMemory(value16, Y);"); w.WriteLine(Spaces + "PendingCycles -= {0}; TotalExecutedCycles += {0};", op.Cycles); }
private void PLA(OpcodeInfo op, TextWriter w) { w.WriteLine(Spaces + "A = ReadMemory((ushort)(++S + 0x100));"); w.WriteLine(Spaces + SetNZ("A")); w.WriteLine(Spaces + "PendingCycles -= {0}; TotalExecutedCycles += {0};", op.Cycles); }
private void PHA(OpcodeInfo op, TextWriter w) { w.WriteLine(Spaces + "WriteMemory((ushort)(S-- + 0x100), A);"); w.WriteLine(Spaces + "PendingCycles -= {0}; TotalExecutedCycles += {0};", op.Cycles); }
private void CLV(OpcodeInfo op, TextWriter w) { w.WriteLine(Spaces + "FlagV = false;"); w.WriteLine(Spaces + "PendingCycles -= {0}; TotalExecutedCycles += {0};", op.Cycles); }
private void TXS(OpcodeInfo op, TextWriter w) { w.WriteLine(Spaces + "S = X;"); w.WriteLine(Spaces + "PendingCycles -= {0}; TotalExecutedCycles += {0};", op.Cycles); }
private void PHP(OpcodeInfo op, TextWriter w) { w.WriteLine(Spaces + "FlagB = true; //why would it do this?? how weird"); w.WriteLine(Spaces + "WriteMemory((ushort)(S-- + 0x100), P);"); w.WriteLine(Spaces + "PendingCycles -= {0}; TotalExecutedCycles += {0};", op.Cycles); }
private void GetAddress(OpcodeInfo op, TextWriter w, string dest) { // TODO it APPEARS that the +1 opcode penalty applies to all AbsoluteX, AbsoluteY, and IndirectY // but this is not completely clear. the doc has some exceptions, but are they real? switch (op.AddressMode) { case AddrMode.ZeroPage: w.WriteLine(Spaces + dest + " = ReadMemory(PC++);"); break; case AddrMode.ZeroPageX: w.WriteLine(Spaces + dest + " = (byte)(ReadMemory(PC++)+X);"); break; case AddrMode.ZeroPageY: w.WriteLine(Spaces + dest + " = (byte)(ReadMemory(PC++)+Y);"); break; case AddrMode.Absolute: w.WriteLine(Spaces + dest + " = ReadWord(PC); PC += 2;"); break; case AddrMode.AbsoluteX: w.WriteLine(Spaces + dest + " = (ushort)(ReadWord(PC)+X);"); w.WriteLine(Spaces + "PC += 2;"); break; case AddrMode.AbsoluteX_P: w.WriteLine(Spaces + "temp16 = ReadWord(PC);"); w.WriteLine(Spaces + dest + " = (ushort)(temp16+X);"); w.WriteLine(Spaces + "if ((temp16 & 0xFF00) != ((temp16 + X) & 0xFF00)) "); w.WriteLine(Spaces + " { PendingCycles--; TotalExecutedCycles++; }"); w.WriteLine(Spaces + "PC += 2;"); break; case AddrMode.AbsoluteY: w.WriteLine(Spaces + dest + " = (ushort)(ReadWord(PC)+Y);"); w.WriteLine(Spaces + "PC += 2;"); break; case AddrMode.AbsoluteY_P: w.WriteLine(Spaces + "temp16 = ReadWord(PC);"); w.WriteLine(Spaces + dest + " = (ushort)(temp16+Y);"); w.WriteLine(Spaces + "if ((temp16 & 0xFF00) != ((temp16 + Y) & 0xFF00)) "); w.WriteLine(Spaces + " { PendingCycles--; TotalExecutedCycles++; }"); w.WriteLine(Spaces + "PC += 2;"); break; case AddrMode.IndirectX: w.WriteLine(Spaces + "temp8 = (byte)(ReadMemory(PC++) + X);"); w.WriteLine(Spaces + dest + " = ReadWordPageWrap(temp8);"); break; case AddrMode.IndirectY: w.WriteLine(Spaces + "temp16 = ReadWordPageWrap(ReadMemory(PC++));"); w.WriteLine(Spaces + dest + " = (ushort)(temp16+Y);"); break; case AddrMode.IndirectY_P: w.WriteLine(Spaces + "temp16 = ReadWordPageWrap(ReadMemory(PC++));"); w.WriteLine(Spaces + dest + " = (ushort)(temp16+Y);"); w.WriteLine(Spaces + "if ((temp16 & 0xFF00) != ((temp16+Y) & 0xFF00)) "); w.WriteLine(Spaces + " { PendingCycles--; TotalExecutedCycles++; }"); break; case AddrMode.Relative: w.WriteLine(Spaces + "rel8 = (sbyte)ReadMemory(PC++);"); w.WriteLine(Spaces + dest +" = (ushort)(PC+rel8);"); break; } }
private void JMP(OpcodeInfo op, TextWriter w) { switch (op.AddressMode) { case AddrMode.Absolute: w.WriteLine(Spaces+"PC = ReadWord(PC);"); break; case AddrMode.Indirect: w.WriteLine(Spaces+"PC = ReadWordPageWrap(ReadWord(PC));"); break; } w.WriteLine(Spaces + "PendingCycles -= {0}; TotalExecutedCycles += {0};", op.Cycles); }
private void Set(byte value, string instr, AddrMode addressMode, int cycles) { var op = new OpcodeInfo(); op.Instruction = instr; op.AddressMode = addressMode; op.Cycles = cycles; if (Opcodes[value] != null) throw new Exception("opcode "+value+" already assigned"); Opcodes[value] = op; }
private void CLI(OpcodeInfo op, TextWriter w) { w.WriteLine(Spaces + "//FlagI = false;"); w.WriteLine(Spaces + "CLI_Pending = true;"); w.WriteLine(Spaces + "PendingCycles -= {0}; TotalExecutedCycles += {0};", op.Cycles); }
private void NOP(OpcodeInfo op, TextWriter w) { // This code is quite insufficient, but at least, we have to increment program counter appropriately. // For immediate addressing mode, it will be correct, and it will fix desyncs of "Puzznic (J)" and "Puzznic (U)". // For other addressing modes, I don't know whether they access memory, so further investigation will be needed. if (op.Size > 1) w.WriteLine(Spaces+"PC += {0};", op.Size-1); w.WriteLine(Spaces+"PendingCycles -= {0}; TotalExecutedCycles += {0};", op.Cycles); }