public PPU(CPU cpu) { this.cpu = cpu; latch = 0; frameCount = 0; tReg = new LoopyRegister(); vReg = new LoopyRegister(); // Two adjacent 16 * 16 2D arrays of 8 * 8 tiles. Used only for testing PatternMemory = new Color[2, (16 * 8), (16 * 8)]; #if LOGGING //CSV log - file creation csvLogs = new DirectoryInfo(@"/Users/alexwright/Documents/MSc Files/Project/csv_logs"); dateTime = DateTime.UtcNow; cultInfo = CultureInfo.CreateSpecificCulture("en-UK"); csvFileName = $"project_nes_ppu_log_{dateTime.ToString("o", cultInfo)}.csv"; filePath = $"{csvLogs.FullName}/{csvFileName}"; using (File.Create(filePath)) { } using (StreamWriter file = new StreamWriter(filePath, true)) file.WriteLine( $"frameCount," + $"scanLine," + $"cycle," + $"vReg.Address," + $"read(address)," + $"ppuData," + $"patternShifterHi," + $"patternShifterLo," + $"attribShifterHi," + $"attribShifterLo," + $"tileID," + $"tileAttrib," + $"tileMSB," + $"tileLSB" ); #endif }
public void WriteDataFromBus(uint address, byte data) { switch (address) { case 0x2000: // Control registerControl = data; registerT.NameTableX = HasControlFlag(Control.NameTableX) ? (byte)1 : (byte)0; registerT.NameTableY = HasControlFlag(Control.NameTableY) ? (byte)1 : (byte)0; spriteSize = HasControlFlag(Control.SpriteSize) ? (byte)16 : (byte)8; return; case 0x2001: // Mask registerMask = data; return; case 0x2002: // Status (read-only) return; case 0x2003: // OAM Address oamAddress = data; return; case 0x2004: // OAM Data mainOAM[oamAddress++] = data; return; case 0x2005: // Scroll if (!byteLatch) { fineX = (byte)(data & 0x07); registerT.CoarseX = (byte)(data >> 3); } else { registerT.FineY = (byte)(data & 0x07); registerT.CoarseY = (byte)(data >> 3); } byteLatch = !byteLatch; return; case 0x2006: // PPU Address if (!byteLatch) { registerT.Reg = (ushort)((registerT.Reg & 0x00FF) | (data << 8)); } else { registerT.Reg = (ushort)((registerT.Reg & 0xFF00) | data); registerV = registerT; } byteLatch = !byteLatch; return; case 0x2007: // PPU Data WritePPUData(registerV.Reg, data); if (registerV.Reg >= 0x3F00 && registerV.Reg <= 0x3F03) { patternTableDisplay[0].DataChanged(); patternTableDisplay[1].DataChanged(); } registerV.Reg += (ushort)(HasControlFlag(Control.IncrementMode) ? 32 : 1); return; } }
public void CpuWrite(ushort address, byte data) { switch (address) { case 0x0000: // Control _control.reg = data; _tRamAddress.SetFlag(LoopyRegister.Flags.NameTableX, _control.GetFlag(Control.Flags.NameTableX)); _tRamAddress.SetFlag(LoopyRegister.Flags.NameTableY, _control.GetFlag(Control.Flags.NameTableY)); break; case 0x0001: // Mask _mask.reg = data; break; case 0x0002: // Status break; case 0x0003: // OAM Address break; case 0x0004: // OAM Data break; case 0x0005: // Scroll if (_addressLatch == 0) { _fineX = (byte)(data & 0x07); _tRamAddress.SetCoarseX((byte)(data >> 3)); _ppuAddress = (ushort)((_ppuAddress & 0xFF00) | data << 8); _addressLatch = 1; } else { _tRamAddress.SetFineY((byte)(data & 0x07)); _tRamAddress.SetCoarseY((byte)(data >> 3)); _addressLatch = 0; } break; case 0x0006: // PPU Address if (_addressLatch == 0) { _tRamAddress.reg = (ushort)((data & 0x3F) << 8 | _tRamAddress.reg & 0x00FF); _addressLatch = 1; } else { _tRamAddress.reg = (ushort)(_tRamAddress.reg & 0xFF00 | data); _vRamAddress = _tRamAddress; _addressLatch = 0; } break; case 0x0007: // PPU Data PpuWrite(_vRamAddress.reg, data); var inclementModeFlagValue = _control.GetFlag(Control.Flags.IncrementMode); if (inclementModeFlagValue) { _vRamAddress.reg += 1; } else { _vRamAddress.reg += 32; } break; } }