public void ExecuteEOR(byte instruction, AddressModes addressMode, int signature) { int val = GetValue(addressMode, signature, cpu.A.Width); cpu.A.Value = cpu.A.Value ^ val; cpu.Flags.SetNZ(cpu.A); }
/// <summary> /// Retrieve final data from memory, based on address mode. /// <para>For immediate addressing, just returns the input value</para> /// <para>For absolute addressing, returns data at address in signature bytes</para> /// <para>For indirect addressing, returns data at address pointed to by address in signature</para> /// <para>For indexed modes, uses appropriate index register to adjust the address</para> /// </summary> /// <param name="mode">Address mode. Direct, Absolute, Immediate, etc. Each mode determines where the data /// is located and how the signature bytes are interpreted.</param> /// <param name="signatureBytes">byte or bytes immediately following the opcode. Varies based on the opcode.</param> /// <param name="isCode">Assume the address is code and uses the Program Bank Register. /// Otherwise uses the Data Bank Register, if appropriate.</param> /// <returns></returns> public int GetValue(AddressModes mode, int signatureBytes, int width) { return(mode switch { AddressModes.Accumulator => cpu.A.Value, AddressModes.Absolute => GetAbsolute(signatureBytes, cpu.DataBank, width), AddressModes.AbsoluteLong => GetAbsoluteLong(signatureBytes), AddressModes.JmpAbsoluteIndirect => GetAbsoluteIndirectAddressLong((cpu.PC & 0xFF_0000) + signatureBytes), // JMP (addr) //return GetAbsoluteIndirectAddress(signatureBytes, cpu.ProgramBank); AddressModes.JmpAbsoluteIndirectLong => GetAbsoluteIndirectAddressLong(signatureBytes), // JMP [addr] - jumps to a 24-bit address pointed to by addr in direct page. AddressModes.JmpAbsoluteIndexedIndirectWithX => GetJumpAbsoluteIndexedIndirect(signatureBytes, cpu.X), // JMP (addr,X) AddressModes.AbsoluteIndexedWithX => GetIndexed(signatureBytes, cpu.DataBank, cpu.X, width), // LDA $2000,X AddressModes.AbsoluteLongIndexedWithX => GetAbsoluteLongIndexed(signatureBytes, cpu.X), // LDA $12D080,X AddressModes.AbsoluteIndexedWithY => GetIndexed(signatureBytes, cpu.DataBank, cpu.Y, width), AddressModes.AbsoluteLongIndexedWithY => GetAbsoluteLongIndexed(signatureBytes, cpu.Y), AddressModes.DirectPage => GetAbsolute(signatureBytes, cpu.DirectPage, width), AddressModes.DirectPageIndexedWithX => GetIndexed(signatureBytes, cpu.DirectPage, cpu.X, width), AddressModes.DirectPageIndexedWithY => GetIndexed(signatureBytes, cpu.DirectPage, cpu.Y, width), AddressModes.DirectPageIndexedIndirectWithX => GetDirectIndexedIndirect(signatureBytes, cpu.X), //LDA(dp, X) AddressModes.DirectPageIndirect => GetDirectIndirect(signatureBytes), //LDA (dp) AddressModes.DirectPageIndirectIndexedWithY => GetDirectPageIndirectIndexed(signatureBytes, cpu.Y), //LDA(dp),Y AddressModes.DirectPageIndirectLong => GetDirectIndirectLong(signatureBytes), AddressModes.DirectPageIndirectLongIndexedWithY => GetDirectPageIndirectIndexedLong(signatureBytes, cpu.Y), AddressModes.ProgramCounterRelative => cpu.PC + 2 + MakeSignedByte((byte)signatureBytes), AddressModes.ProgramCounterRelativeLong => cpu.PC + 3 + MakeSignedWord((UInt16)signatureBytes), AddressModes.StackImplied => cpu.Stack.Value, //case AddressModes.StackAbsolute: // return signatureBytes; AddressModes.StackDirectPageIndirect => throw new NotImplementedException(), AddressModes.StackRelative => GetAbsoluteLong(cpu.Stack.Value + signatureBytes), AddressModes.StackRelativeIndirectIndexedWithY => GetAbsoluteLong(cpu.MemMgr.ReadWord(cpu.Stack.Value + signatureBytes) + cpu.Y.Value), AddressModes.StackProgramCounterRelativeLong => throw new NotImplementedException(), _ => signatureBytes, });
/// <summary> /// Test memory against the Accumulator. Sets Z based on the result of an AND. /// Also sets or clears bits in memory based on the bitmask in the accumulator. /// TSB sets bits in memory based on A. TRB clears bits in memory based on A. /// </summary> /// <param name="instruction"></param> /// <param name="addressMode"></param> /// <param name="signature"></param> public void ExecuteTSBTRB(byte instruction, AddressModes addressMode, int signature) { int val = GetValue(addressMode, signature, cpu.A.Width); int test = val & cpu.A.Value; cpu.Flags.SetZ(test); int addr = GetAddress(addressMode, signature, cpu.DataBank); switch (instruction) { case OpcodeList.TSB_Absolute: case OpcodeList.TSB_DirectPage: cpu.Memory.Write(addr, val | cpu.A.Value, cpu.A.Width); break; case OpcodeList.TRB_Absolute: case OpcodeList.TRB_DirectPage: // reset bits in memory when that bit is 1 in A // AND to get bits that are both 1 // XOR to force thoses off in memory. int mask = val & cpu.A.Value; cpu.Memory.Write(addr, val ^ mask, cpu.A.Width); break; default: throw new NotImplementedException("ExecuteTSBTRB() opcode not implemented: " + instruction.ToString("X2")); } }
public void ExecuteLDX(byte instruction, AddressModes addressMode, int signature) { int val = GetValue(addressMode, signature, cpu.X.Width); cpu.X.Value = val; cpu.Flags.SetNZ(cpu.X.Value, cpu.X.Width); }
public void ExecuteMisc(byte instruction, AddressModes addressMode, int signature) { switch (instruction) { // WDM is a 2-byte NOP and an easter egg. William D Mensch designed the 6502 and 65816. // We will use this to give the simulator commands case OpcodeList.WDM_Implied: OnSimulatorCommand(signature); break; case OpcodeList.NOP_Implied: break; case OpcodeList.STP_Implied: //stop cpu.Halt(); break; case OpcodeList.XBA_Implied: // transfer B into A cpu.A.Swap(); cpu.Flags.Zero = (cpu.A.Low == 0); cpu.Flags.Negative = (cpu.A.Low & 0x80) != 0; break; default: throw new NotImplementedException("ExecuteMisc() opcode not implemented: " + instruction.ToString("X2")); } }
/// <summary> /// Subtract value from accumulator. Carry acts as a "borrow". When Carry is 0, /// subtract one more from Accumulator. Carry will be 0 if result < 0 and 1 if result >= 0. /// </summary> /// <param name="instruction"></param> /// <param name="addressMode"></param> /// <param name="signature"></param> public void ExecuteSBC(byte instruction, AddressModes addressMode, int signature) { int val = GetValue(addressMode, signature, cpu.A.Width); int nv = 0; if (cpu.Flags.Decimal) { nv = HexVal(BCDVal(cpu.A.Value) - BCDVal(val + 1) + cpu.Flags.CarryBit); } else { nv = cpu.A.Value - val - 1 + cpu.Flags.CarryBit; } cpu.Flags.Carry = (nv >= 0 && nv <= cpu.A.MaxUnsigned); if (cpu.A.Width == 1) { cpu.Flags.oVerflow = ((cpu.A.Value ^ nv) & ((256 - val) ^ nv) & 0x80) != 0; } else { cpu.Flags.oVerflow = ((cpu.A.Value ^ nv) & ((65536 - val) ^ nv) & 0x8000) != 0; } cpu.Flags.SetNZ(nv, cpu.A.Width); cpu.A.Value = nv; }
public void ExecuteINCDEC(byte instruction, AddressModes addressMode, int signature) { byte bval = (byte)GetValue(addressMode, signature); int addr = GetAddress(addressMode, signature, cpu.DataBank); switch (instruction) { case OpcodeList.DEC_Accumulator: cpu.A.Value -= 1; cpu.Flags.SetNZ(cpu.A); break; case OpcodeList.DEC_DirectPage: case OpcodeList.DEC_Absolute: case OpcodeList.DEC_DirectPageIndexedWithX: case OpcodeList.DEC_AbsoluteIndexedWithX: bval--; cpu.Memory.WriteByte(addr, bval); cpu.Flags.SetNZ(bval, 1); break; case OpcodeList.INC_Accumulator: cpu.A.Value += 1; cpu.Flags.SetNZ(cpu.A); break; case OpcodeList.INC_DirectPage: case OpcodeList.INC_Absolute: case OpcodeList.INC_DirectPageIndexedWithX: case OpcodeList.INC_AbsoluteIndexedWithX: addr = cpu.DirectPage.GetLongAddress(addr); bval++; cpu.Memory.WriteByte(addr, bval); cpu.Flags.SetNZ(bval, 1); break; case OpcodeList.DEX_Implied: cpu.X.Value -= 1; cpu.Flags.SetNZ(cpu.X); break; case OpcodeList.INX_Implied: cpu.X.Value += 1; cpu.Flags.SetNZ(cpu.X); break; case OpcodeList.DEY_Implied: cpu.Y.Value -= 1; cpu.Flags.SetNZ(cpu.Y); break; case OpcodeList.INY_Implied: cpu.Y.Value += 1; cpu.Flags.SetNZ(cpu.Y); break; default: break; } }
public void ExecuteADC(byte instruction, AddressModes addressMode, int signature) { int val = GetValue(addressMode, signature, cpu.A.Width); int nv = 0; if (cpu.Flags.Decimal) { nv = HexVal(BCDVal(val) + BCDVal(cpu.A.Value) + cpu.Flags.CarryBit); } else { nv = val + cpu.A.Value + cpu.Flags.CarryBit; // We need to detect a wraparound - when the sign changes but there is no overflow if (cpu.A.Width == 1) { cpu.Flags.oVerflow = ((cpu.A.Value ^ nv) & ((val + cpu.Flags.CarryBit) ^ nv) & 0x80) != 0; } else { cpu.Flags.oVerflow = ((cpu.A.Value ^ nv) & ((val + cpu.Flags.CarryBit) ^ nv) & 0x8000) != 0; } } cpu.Flags.Carry = (nv <0 || nv> cpu.A.MaxUnsigned); cpu.Flags.SetNZ(nv, cpu.A.Width); cpu.A.Value = nv; }
public void ExecuteAND(byte instruction, AddressModes addressMode, int signature) { int data = GetValue(addressMode, signature); cpu.A.Value = cpu.A.Value & data; cpu.Flags.SetNZ(cpu.A); }
public void ExecuteLDY(byte instruction, AddressModes addressMode, int signature) { int val = GetValue(addressMode, signature); cpu.Y.Value = val; cpu.Flags.SetNZ(cpu.A); }
public void Compare(AddressModes addressMode, int signature, Register Reg) { int val = GetValue(addressMode, signature, Reg.Width); cpu.Flags.Zero = Reg.Value == val; cpu.Flags.Carry = Reg.Value >= val; cpu.Flags.Negative = Reg.Value < val; }
public void ExecuteTransfer(byte instruction, AddressModes addressMode, int signature) { switch (instruction) { case OpcodeList.TCD_Implied: cpu.DirectPage.Value = cpu.A.Value16; break; case OpcodeList.TDC_Implied: cpu.A.Value16 = cpu.DirectPage.Value; break; case OpcodeList.TCS_Implied: cpu.Stack.Value = cpu.A.Value16; cpu.Stack.TopOfStack = cpu.A.Value16; break; case OpcodeList.TSC_Implied: cpu.A.Value16 = cpu.Stack.Value; break; case OpcodeList.TAX_Implied: cpu.X.Value = cpu.A.Value16; break; case OpcodeList.TAY_Implied: cpu.Y.Value = cpu.A.Value16; break; case OpcodeList.TSX_Implied: cpu.X.Value = cpu.Stack.Value; break; case OpcodeList.TXA_Implied: cpu.A.Value = cpu.X.Value; break; case OpcodeList.TXS_Implied: cpu.Stack.Value = cpu.X.Value; cpu.Stack.TopOfStack = cpu.X.Value; break; case OpcodeList.TXY_Implied: cpu.Y.Value = cpu.X.Value; break; case OpcodeList.TYA_Implied: cpu.A.Value = cpu.Y.Value; break; case OpcodeList.TYX_Implied: cpu.X.Value = cpu.Y.Value; break; default: throw new NotImplementedException("ExecuteTransfer() opcode not implemented: " + instruction.ToString("X2")); } }
public void ExecuteBranch(byte instruction, AddressModes addressMode, int signature) { bool takeBranch = false; switch (instruction) { case OpcodeList.BCC_ProgramCounterRelative: takeBranch = !cpu.Flags.Carry; break; case OpcodeList.BCS_ProgramCounterRelative: takeBranch = cpu.Flags.Carry; break; case OpcodeList.BEQ_ProgramCounterRelative: takeBranch = cpu.Flags.Zero; break; case OpcodeList.BMI_ProgramCounterRelative: takeBranch = cpu.Flags.Negative; break; case OpcodeList.BNE_ProgramCounterRelative: takeBranch = !cpu.Flags.Zero; break; case OpcodeList.BPL_ProgramCounterRelative: takeBranch = !cpu.Flags.Negative; break; case OpcodeList.BRA_ProgramCounterRelative: takeBranch = true; break; case OpcodeList.BVC_ProgramCounterRelative: takeBranch = !cpu.Flags.oVerflow; break; case OpcodeList.BVS_ProgramCounterRelative: takeBranch = cpu.Flags.oVerflow; break; case OpcodeList.BRL_ProgramCounterRelativeLong: takeBranch = false; // we are actually always taking this branch, but the offset is a word int offset = MakeSignedWord((UInt16)signature); cpu.PC += offset; break; default: throw new NotImplementedException("ExecuteBranch() opcode not implemented: " + instruction.ToString("X2")); } if (takeBranch) { BranchNear((byte)signature); } }
public void ExecuteJumpReturn(byte instruction, AddressModes addressMode, int signature) { RegisterBankNumber fakeBank = new RegisterBankNumber { Value = cpu.PC >> 16 }; int addr = GetAddress(addressMode, signature, fakeBank); switch (instruction) { case OpcodeList.JSR_Absolute: case OpcodeList.JSR_AbsoluteIndexedIndirectWithX: cpu.Push(cpu.PC - 1, 2); cpu.JumpLong(addr); return; case OpcodeList.JSR_AbsoluteLong: cpu.Push(cpu.PC - 1, 3); cpu.JumpLong(addr); return; case OpcodeList.JMP_Absolute: case OpcodeList.JMP_AbsoluteLong: case OpcodeList.JMP_AbsoluteIndirect: case OpcodeList.JMP_AbsoluteIndexedIndirectWithX: case OpcodeList.JMP_AbsoluteIndirectLong: cpu.JumpLong(addr); return; // RTS, RTL, RTI case OpcodeList.RTI_StackImplied: cpu.Flags.SetFlags(cpu.Pull(1)); cpu.SyncFlags(); if (cpu.Flags.Emulation) { cpu.JumpShort(cpu.Pull(2)); } else { cpu.JumpLong(cpu.Pull(3)); } return; case OpcodeList.RTS_StackImplied: cpu.JumpShort(cpu.Pull(2) + 1); return; case OpcodeList.RTL_StackImplied: addr = cpu.Pull(3); cpu.JumpLong(addr + 1); return; default: throw new NotImplementedException("ExecuteJumpReturn() opcode not implemented: " + instruction.ToString("X2")); } }
public OpCode(byte Value, string Mnemonic, int Length, AddressModes Mode, ExecuteDelegate newDelegate) { this.Value = Value; this.Length8Bit = Length; this.Mnemonic = Mnemonic; this.AddressMode = Mode; this.ExecuteOp += newDelegate; global::System.Diagnostics.Debug.WriteLine("public const int " + Mnemonic + "_" + Mode.ToString() + "=0x" + Value.ToString("X2") + ";"); }
public void ExecuteStatusReg(byte instruction, AddressModes addressMode, int signature) { switch (instruction) { case OpcodeList.CLC_Implied: cpu.Flags.Carry = false; break; case OpcodeList.SEC_Implied: cpu.Flags.Carry = true; break; case OpcodeList.CLD_Implied: cpu.Flags.Decimal = false; break; case OpcodeList.SED_Implied: cpu.Flags.Decimal = true; break; case OpcodeList.CLI_Implied: cpu.Flags.Irqdisable = false; break; case OpcodeList.SEI_Implied: cpu.Flags.Irqdisable = true; break; case OpcodeList.CLV_Implied: cpu.Flags.oVerflow = false; break; case OpcodeList.REP_Immediate: // reset (clear) flag bits that are 1 in the argument // do this by flipping the argument bits, then ANDing // them to the flag bits int flip = signature ^ 0xff; cpu.Flags.Value = cpu.Flags.Value & flip; break; case OpcodeList.SEP_Immediate: // set flag bits that are 1 in the argument. cpu.Flags.Value = cpu.Flags.Value | signature; break; case OpcodeList.XCE_Implied: cpu.Flags.SwapCE(); break; default: throw new NotImplementedException("Unknown opcode for ExecuteStatusReg: " + instruction.ToString("X2")); } cpu.SyncFlags(); }
public void Compare(AddressModes addressMode, int signature, Register Reg) { int val = GetValue(addressMode, signature, Reg.Width); val = (Reg.Width == 1) ? val & 0xFF : val; int subResult = Reg.Value - val; cpu.Flags.Zero = subResult == 0; cpu.Flags.Carry = Reg.Value >= val; cpu.Flags.Negative = Reg.Width == 1 ? (subResult & 0x80) == 0x80 : (subResult & 0x8000) == 0x8000; }
public void ExecuteLDA(byte instruction, AddressModes addressMode, int signature) { int val = GetValue(addressMode, signature); if (addressMode == AddressModes.AbsoluteIndexedWithX && (val & 0xff) == 0) { global::System.Diagnostics.Debug.WriteLine("break"); } cpu.A.Value = val; cpu.Flags.SetNZ(cpu.A); }
public void ExecuteJumpReturn(byte instruction, AddressModes addressMode, int signature) { int addr = GetAddress(addressMode, signature, cpu.ProgramBank); switch (instruction) { case OpcodeList.JSR_Absolute: case OpcodeList.JSR_AbsoluteIndexedIndirectWithX: cpu.Push(cpu.PC); cpu.JumpShort(addr); return; case OpcodeList.JSR_AbsoluteLong: cpu.Push(cpu.ProgramBank); cpu.Push(cpu.PC); cpu.JumpLong(addr); return; case OpcodeList.JMP_Absolute: case OpcodeList.JMP_AbsoluteLong: case OpcodeList.JMP_AbsoluteIndirect: case OpcodeList.JMP_AbsoluteIndexedIndirectWithX: case OpcodeList.JMP_AbsoluteIndirectLong: cpu.JumpLong(addr); return; case OpcodeList.RTS_StackImplied: cpu.JumpShort(cpu.Pull(2)); return; case OpcodeList.RTI_StackImplied: cpu.Flags.SetFlags(cpu.Pull(1)); int address = cpu.Pull(2); if (!cpu.Flags.Emulation) { cpu.DataBank.Value = cpu.Pull(1); address += (cpu.DataBank.Value << 16); } cpu.JumpLong(address); cpu.SyncFlags(); return; case OpcodeList.RTL_StackImplied: addr = cpu.Pull(3); cpu.JumpLong(addr); return; default: throw new NotImplementedException("ExecuteJumpReturn() opcode not implemented: " + instruction.ToString("X2")); } }
public void ExecuteBranch(byte instruction, AddressModes addressMode, int signature) { bool takeBranch = false; switch (instruction) { case OpcodeList.BCC_ProgramCounterRelative: takeBranch = !cpu.Flags.Carry; break; case OpcodeList.BCS_ProgramCounterRelative: takeBranch = cpu.Flags.Carry; break; case OpcodeList.BEQ_ProgramCounterRelative: takeBranch = cpu.Flags.Zero; break; case OpcodeList.BMI_ProgramCounterRelative: takeBranch = cpu.Flags.Negative; break; case OpcodeList.BNE_ProgramCounterRelative: takeBranch = !cpu.Flags.Zero; break; case OpcodeList.BPL_ProgramCounterRelative: takeBranch = !cpu.Flags.Negative; break; case OpcodeList.BRA_ProgramCounterRelative: takeBranch = true; break; case OpcodeList.BVC_ProgramCounterRelative: takeBranch = !cpu.Flags.oVerflow; break; case OpcodeList.BVS_ProgramCounterRelative: takeBranch = cpu.Flags.oVerflow; break; default: throw new NotImplementedException("ExecuteBranch() opcode not implemented: " + instruction.ToString("X2")); } if (takeBranch) { BranchNear((byte)signature); } }
/// <summary> /// Subtract value from accumulator. Carry acts as a "borrow". When Carry is 0, /// subtract one more from Accumulator. Carry will be 0 if result < 0 and 1 if result >= 0. /// </summary> /// <param name="instruction"></param> /// <param name="addressMode"></param> /// <param name="signature"></param> public void ExecuteSBC(byte instruction, AddressModes addressMode, int signature) { int val = GetValue(addressMode, signature, cpu.A.Width); if (cpu.Flags.Decimal) { val = HexVal(BCDVal(cpu.A.Value) - BCDVal(val + 1) + cpu.Flags.CarryBit); } else { val = cpu.A.Value - val - 1 + cpu.Flags.CarryBit; } cpu.Flags.Carry = (val >= 0 && val <= cpu.A.MaxUnsigned); cpu.Flags.oVerflow = (val <cpu.A.MinSigned || val> cpu.A.MaxSigned); cpu.Flags.SetNZ(val, cpu.A.Width); cpu.A.Value = val; }
/// <summary> /// Block moves. /// <para>C = bytes to move -1 (so if we're moving 20 bytes, C=19</para> /// <para>X=16-bit source address</para> /// <para>Y=16-bit destination address</para> /// <para>Operand bytes are the source and destination banks.</para> /// <para>After the move, the destination bank is stored in the DBR.</para> /// <para>In the assembled code, order is dest,source. In source code, specify source,dest.</para> /// </summary> /// <param name="instruction"></param> /// <param name="addressMode"></param> /// <param name="signature"></param> public void ExecuteBlockMove(byte instruction, AddressModes addressMode, int signature) { int sourceBank = (signature << 16) & 0xff0000; int destBank = (signature << 8) & 0xff0000; int sourceAddr = sourceBank + cpu.X.Value; int destAddr = destBank + cpu.Y.Value; int bytesToMove = cpu.A.Value + 1; int dir = (instruction == OpcodeList.MVP_BlockMove) ? 1 : -1; for (int i = 0; i < bytesToMove; i++) { cpu.Memory[destAddr + i] = cpu.Memory[sourceAddr + i]; cpu.X.Value += dir; cpu.Y.Value += dir; } cpu.A.Value = 0xffff; }
/// <summary> /// BRK and COP instruction. Pushes the Program Bank Register, the Program Counter, and the Flags onto the stack. /// Then switches to the Bank 0 addresses stored in the approriate vector. /// </summary> /// <param name="instruction"></param> /// <param name="addressMode"></param> /// <param name="signature"></param> public void ExecuteInterrupt(byte instruction, AddressModes addressMode, int signature) { cpu.OpcodeLength = 2; cpu.OpcodeCycles = 8; switch (instruction) { case OpcodeList.BRK_Interrupt: cpu.Interrupt(InteruptTypes.BRK); break; case OpcodeList.COP_Interrupt: cpu.Interrupt(InteruptTypes.COP); break; default: throw new NotImplementedException("Unknown opcode for ExecuteInterrupt: " + instruction.ToString("X2")); } }
/// <summary> /// Subtract value from accumulator. Carry acts as a "borrow". When Carry is 0, /// subtract one more from Accumulator. Carry will be 0 if result < 0 and 1 if result >= 0. /// </summary> /// <param name="instruction"></param> /// <param name="addressMode"></param> /// <param name="signature"></param> public void ExecuteSBC(byte instruction, AddressModes addressMode, int signature) { int val = GetValue(addressMode, signature, cpu.A.Width); if (cpu.Flags.Decimal) { throw new NotImplementedException("Decimal mode subtraction not implemented."); } else { val = val - cpu.A.Value - 1 + cpu.Flags.CarryBit; } cpu.Flags.Carry = (val >= 0 && val <= cpu.A.MaxUnsigned); cpu.Flags.oVerflow = (val <cpu.A.MinSigned || val> cpu.A.MaxSigned); cpu.Flags.SetNZ(val, cpu.A.Width); cpu.A.Value = val; }
public void ExecuteBIT(byte instruction, AddressModes addressMode, int signature) { int data = GetValue(addressMode, signature, cpu.A.Width); int result = cpu.A.Value & data; cpu.Flags.SetZ(result); if (addressMode != AddressModes.Immediate) { if (cpu.A.Width == 2) { cpu.Flags.oVerflow = (data & 0x4000) != 0; cpu.Flags.Negative = (data & 0x8000) != 0; } else { cpu.Flags.oVerflow = (data & 0x40) != 0; cpu.Flags.Negative = (data & 0x80) != 0; } } }
public void ExecuteBIT(byte instruction, AddressModes addressMode, int signature) { int data = GetValue(addressMode, signature); int result = cpu.A.Value & data; if (addressMode != AddressModes.Immediate) { cpu.Flags.SetNZ(result, cpu.A.Width); if (cpu.A.Width == 2) { cpu.Flags.oVerflow = (result & 0x4000) == 0x4000; } else { cpu.Flags.oVerflow = (result & 0x400) == 0x40; } } else { cpu.Flags.SetZ(result); } }
/// <summary> /// Block moves. /// <para>C = bytes to move +1 (so if we're moving 20 bytes, C=19</para> /// <para>X=16-bit source address</para> /// <para>Y=16-bit destination address</para> /// <para>Operand bytes are the source and destination banks.</para> /// <para>In the assembled code, order is dest,source. In source code, specify source,dest.</para> /// </summary> /// <param name="instruction"></param> /// <param name="addressMode"></param> /// <param name="signature"></param> public void ExecuteBlockMove(byte instruction, AddressModes addressMode, int signature) { int sourceBank = (signature << 8) & 0xff0000; int destBank = (signature << 16) & 0xff0000; int bytesToMove = cpu.A.Value + 1; // For MVN, X and Y are incremented // For MVP, X and Y are decremented int dir = (instruction == OpcodeList.MVP_BlockMove) ? -1 : 1; while (cpu.A.Value != 0xFFFF) { // The addresses must remain in the correct bank, so the addresses will wrap int sourceAddr = sourceBank + cpu.X.Value; int destAddr = destBank + cpu.Y.Value; cpu.Memory[destAddr] = cpu.Memory[sourceAddr]; cpu.X.Value += dir; cpu.Y.Value += dir; cpu.A.Value--; } }
private int GetAddress(AddressModes addressMode, int SignatureBytes, RegisterBankNumber Bank) { int addr = 0; int ptr = 0; switch (addressMode) { // The address will not be used in Immediate or Implied mode, but case AddressModes.Immediate: return(ADDRESS_IMMEDIATE); case AddressModes.Implied: return(ADDRESS_IMPLIED); case AddressModes.Absolute: return(Bank.GetLongAddress(SignatureBytes)); case AddressModes.AbsoluteLong: return(SignatureBytes); case AddressModes.AbsoluteIndexedWithX: return(Bank.GetLongAddress(SignatureBytes + cpu.X.Value)); case AddressModes.AbsoluteLongIndexedWithX: return(SignatureBytes + cpu.X.Value); case AddressModes.AbsoluteIndexedWithY: return(SignatureBytes + cpu.Y.Value); case AddressModes.AbsoluteLongIndexedWithY: return(Bank.GetLongAddress(SignatureBytes + cpu.X.Value)); case AddressModes.DirectPage: return(cpu.DirectPage.GetLongAddress(SignatureBytes)); case AddressModes.DirectPageIndexedWithX: return(cpu.DirectPage.GetLongAddress(SignatureBytes + cpu.X.Value)); case AddressModes.DirectPageIndexedWithY: return(cpu.DirectPage.GetLongAddress(SignatureBytes + cpu.Y.Value)); case AddressModes.DirectPageIndexedIndirectWithX: addr = cpu.DirectPage.GetLongAddress(SignatureBytes) + cpu.X.Value; ptr = cpu.Memory.ReadWord(addr); return(cpu.ProgramBank.GetLongAddress(ptr)); case AddressModes.DirectPageIndirect: addr = cpu.DirectPage.GetLongAddress(SignatureBytes); ptr = cpu.Memory.ReadWord(addr); return(cpu.ProgramBank.GetLongAddress(ptr)); case AddressModes.DirectPageIndirectIndexedWithY: addr = cpu.DirectPage.GetLongAddress(SignatureBytes); ptr = cpu.Memory.ReadWord(addr) + cpu.Y.Value; return(cpu.ProgramBank.GetLongAddress(ptr)); case AddressModes.DirectPageIndirectLong: addr = cpu.DirectPage.GetLongAddress(SignatureBytes); ptr = cpu.Memory.ReadLong(addr); return(ptr); case AddressModes.DirectPageIndirectLongIndexedWithY: addr = cpu.DirectPage.GetLongAddress(SignatureBytes); ptr = cpu.Memory.ReadLong(addr) + cpu.Y.Value; return(cpu.ProgramBank.GetLongAddress(ptr)); case AddressModes.ProgramCounterRelative: ptr = MakeSignedByte((byte)SignatureBytes); addr = cpu.PC.Value + ptr; return(addr); case AddressModes.ProgramCounterRelativeLong: ptr = MakeSignedInt((UInt16)SignatureBytes); addr = cpu.PC.Value + ptr; return(addr); case AddressModes.StackImplied: //case AddressModes.StackAbsolute: return(0); case AddressModes.StackDirectPageIndirect: return(cpu.DirectPage.GetLongAddress(SignatureBytes)); case AddressModes.StackRelative: return(cpu.Stack.Value + SignatureBytes); case AddressModes.StackRelativeIndirectIndexedWithY: return(cpu.Stack.Value + SignatureBytes + cpu.Y.Value); case AddressModes.StackProgramCounterRelativeLong: return(SignatureBytes); // Jump and JSR indirect references vectors located in Bank 0 case AddressModes.JmpAbsoluteIndirect: addr = SignatureBytes; ptr = cpu.Memory.ReadWord(addr); return(cpu.ProgramBank.GetLongAddress(ptr)); case AddressModes.JmpAbsoluteIndirectLong: addr = SignatureBytes; ptr = cpu.Memory.ReadLong(addr); return(ptr); case AddressModes.JmpAbsoluteIndexedIndirectWithX: addr = SignatureBytes + cpu.X.Value; ptr = cpu.Memory.ReadWord(addr); return(cpu.ProgramBank.GetLongAddress(ptr)); case AddressModes.Accumulator: return(0); default: throw new NotImplementedException("GetAddress() Address mode not implemented: " + addressMode.ToString()); } }
public void ExecuteStack(byte instruction, AddressModes addressMode, int signature) { switch (instruction) { case OpcodeList.PHA_StackImplied: cpu.Push(cpu.A); break; case OpcodeList.PLA_StackImplied: cpu.PullInto(cpu.A); break; case OpcodeList.PHX_StackImplied: cpu.Push(cpu.X); break; case OpcodeList.PLX_StackImplied: cpu.PullInto(cpu.X); break; case OpcodeList.PHY_StackImplied: cpu.Push(cpu.Y); break; case OpcodeList.PLY_StackImplied: cpu.PullInto(cpu.Y); break; case OpcodeList.PHB_StackImplied: cpu.Push(cpu.DataBank); break; case OpcodeList.PLB_StackImplied: cpu.PullInto(cpu.DataBank); break; case OpcodeList.PHD_StackImplied: cpu.Push(cpu.DirectPage); break; case OpcodeList.PLD_StackImplied: cpu.PullInto(cpu.DirectPage); break; case OpcodeList.PHK_StackImplied: cpu.Push(cpu.ProgramBank); break; case OpcodeList.PHP_StackImplied: cpu.Push(cpu.Flags); break; case OpcodeList.PLP_StackImplied: cpu.PullInto(cpu.Flags); cpu.SyncFlags(); break; default: throw new NotImplementedException("ExecuteStack() opcode not implemented: " + instruction.ToString("X2")); } }
public void ExecuteShift(byte instruction, AddressModes addressMode, int signature) { int val = GetValue(addressMode, signature, cpu.A.Width); int addr = GetAddress(addressMode, signature, cpu.DataBank); switch (instruction) { case OpcodeList.ASL_DirectPage: case OpcodeList.ASL_Accumulator: case OpcodeList.ASL_Absolute: case OpcodeList.ASL_DirectPageIndexedWithX: case OpcodeList.ASL_AbsoluteIndexedWithX: val = val << 1; if (cpu.A.Width == 1) { cpu.Flags.Carry = val > 0xff; val = val & 0xff; } else if (cpu.A.Width == 2) { cpu.Flags.Carry = val > 0xffff; val = val & 0xffff; } break; case OpcodeList.LSR_DirectPage: case OpcodeList.LSR_Accumulator: case OpcodeList.LSR_Absolute: case OpcodeList.LSR_DirectPageIndexedWithX: case OpcodeList.LSR_AbsoluteIndexedWithX: cpu.Flags.Carry = (val & 1) == 1; val = val >> 1; break; case OpcodeList.ROL_DirectPage: case OpcodeList.ROL_Accumulator: case OpcodeList.ROL_Absolute: case OpcodeList.ROL_DirectPageIndexedWithX: case OpcodeList.ROL_AbsoluteIndexedWithX: val = val << 1; if (cpu.Flags.Carry) { val += 1; } if (cpu.A.Width == 1) { cpu.Flags.Carry = val > 0xff; val = val & 0xff; } else if (cpu.A.Width == 2) { cpu.Flags.Carry = val > 0xffff; val = val & 0xffff; } break; case OpcodeList.ROR_DirectPage: case OpcodeList.ROR_Accumulator: case OpcodeList.ROR_Absolute: case OpcodeList.ROR_DirectPageIndexedWithX: case OpcodeList.ROR_AbsoluteIndexedWithX: if (cpu.Flags.Carry) { if (cpu.A.Width == 8) { val += 0x100; } else if (cpu.A.Width == 16) { val += 0x10000; } } cpu.Flags.Carry = (val & 1) == 1; val = val >> 1; break; default: throw new NotImplementedException("ExecuteASL() opcode not implemented: " + instruction.ToString("X2")); } cpu.Flags.SetNZ(val, cpu.A.Width); if (addressMode == AddressModes.Accumulator) { cpu.A.Value = val; } else { cpu.Memory.Write(addr, val, cpu.A.Width); } }