void IBusSlave.Write(ushort address, byte value) { if (address == 0x0000) { _controller.Value = value; UpdateNametableBaseAddress(); UpdateBgPatternTableBaseAddress(); } else if (address == 0x0001) { _mask.Value = value; } else if (address == 0x0003) { _oamAddress = value; } else if (address == 0x0004) { _oamMemory[_oamAddress++] = value; } else if (address == 0x0005) { if (_writingCameraPosY) { _cameraPosY = value; } else { _cameraPosX = value; } _writingCameraPosY = !_writingCameraPosY; } else if (address == 0x0006) { if (_writingPPUAddrLow) { _ppuAddr |= value; } else { _ppuAddr = (ushort)(value << 8); } _writingPPUAddrLow = !_writingPPUAddrLow; } else if (address == 0x0007) { _masterClient.Value = value; _masterClient.Write(_ppuAddr); _ppuAddr += _controller.I ? (byte)32 : (byte)1; } else { throw new NotImplementedException(); } }
void IClockSink.OnTick() { if (_enabled) { _masterClient.Read(_srcAddr++); _masterClient.Write(0x2014); _writeCount++; if (_writeCount == 0) { _enabled = false; _masterClient.Release(); } } }
private void DispatchAddressing() { void ReadSource(AddressOperand addressOperand, ref byte result) { switch (addressOperand) { // In Result case AddressOperand.None: break; case AddressOperand.Memory: if (_addressState.Destination != AddressOperand.PC) { _masterClient.Read(_addressState.MemoryAddress); result = _masterClient.Value; } break; case AddressOperand.X: result = Registers.X; break; case AddressOperand.Y: result = Registers.Y; break; case AddressOperand.A: result = Registers.A; break; default: throw new ArgumentException(nameof(_addressState.SourceA)); } } // Read Source ReadSource(_addressState.SourceA, ref _addressState.ResultA); ReadSource(_addressState.SourceB, ref _addressState.ResultB); // Do Operation switch (_addressState.Operation) { case AddressOperation.None: if (_addressState.AffectFlags) { UpdateNZ(_addressState.ResultA); } break; case AddressOperation.Inc: _addressState.ResultA++; if (_addressState.AffectFlags) { UpdateNZ(_addressState.ResultA); } break; case AddressOperation.Dec: _addressState.ResultA--; if (_addressState.AffectFlags) { UpdateNZ(_addressState.ResultA); } break; case AddressOperation.BitTest: if (_addressState.AffectFlags) { Status.Z = (_addressState.ResultA & _addressState.ResultB) == 0; Status.N = (_addressState.ResultB & 0x80) != 0; Status.V = (_addressState.ResultB & 0x40) != 0; } break; case AddressOperation.Compare: if (_addressState.AffectFlags) { Status.C = _addressState.ResultA >= _addressState.ResultB; UpdateNZ((byte)(_addressState.ResultA - _addressState.ResultB)); } break; case AddressOperation.And: _addressState.ResultA &= _addressState.ResultB; if (_addressState.AffectFlags) { UpdateNZ(_addressState.ResultA); } break; case AddressOperation.Or: _addressState.ResultA |= _addressState.ResultB; if (_addressState.AffectFlags) { UpdateNZ(_addressState.ResultA); } break; case AddressOperation.Adc: { var value = (short)(_addressState.ResultA + _addressState.ResultB + (Status.C ? 1 : 0)); if (_addressState.AffectFlags) { UpdateCV(_addressState.ResultA, _addressState.ResultB, value); } _addressState.ResultA = (byte)value; if (_addressState.AffectFlags) { UpdateNZ(_addressState.ResultA); } } break; case AddressOperation.Rol: { var c = Status.C; if (_addressState.AffectFlags) { Status.C = (_addressState.ResultA & 0x80) != 0; } _addressState.ResultA = (byte)((_addressState.ResultA << 1) | (Status.C ? 1 : 0)); if (_addressState.AffectFlags) { UpdateNZ(_addressState.ResultA); } } break; case AddressOperation.Asl: { if (_addressState.AffectFlags) { Status.C = (_addressState.ResultA & 0x80) != 0; } _addressState.ResultA = (byte)(_addressState.ResultA << 1); if (_addressState.AffectFlags) { UpdateNZ(_addressState.ResultA); } } break; case AddressOperation.Xor: _addressState.ResultA ^= _addressState.ResultB; if (_addressState.AffectFlags) { UpdateNZ(_addressState.ResultA); } break; default: throw new ArgumentException(nameof(_addressState.Operation)); } // Write Destination switch (_addressState.Destination) { case AddressOperand.None: break; case AddressOperand.Memory: _masterClient.Value = _addressState.ResultA; _masterClient.Write(_addressState.MemoryAddress); break; case AddressOperand.X: Registers.X = _addressState.ResultA; break; case AddressOperand.Y: Registers.Y = _addressState.ResultA; break; case AddressOperand.A: Registers.A = _addressState.ResultA; break; case AddressOperand.S: Registers.S = _addressState.ResultA; break; case AddressOperand.PC: Registers.PC = _addressState.MemoryAddress; break; default: throw new ArgumentException(nameof(_addressState.Destination)); } }