2011-02-27 09:45:50 +00:00
|
|
|
|
//http://nesdev.parodius.com/bbs/viewtopic.php?p=4571&sid=db4c7e35316cc5d734606dd02f11dccb
|
|
|
|
|
|
|
|
|
|
using System;
|
|
|
|
|
using System.Globalization;
|
|
|
|
|
using System.IO;
|
|
|
|
|
using System.Collections.Generic;
|
|
|
|
|
using BizHawk.Emulation.CPUs.M6502;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
namespace BizHawk.Emulation.Consoles.Nintendo
|
|
|
|
|
{
|
|
|
|
|
partial class NES
|
|
|
|
|
{
|
2011-02-28 09:13:27 +00:00
|
|
|
|
public partial class PPU
|
2011-02-27 09:45:50 +00:00
|
|
|
|
{
|
2011-03-28 16:43:15 +00:00
|
|
|
|
public MemoryDomain.FreezeData[] ppubus_freeze = new MemoryDomain.FreezeData[16384];
|
|
|
|
|
|
|
|
|
|
//when the ppu issues a write it goes through here and into the game board
|
2011-03-06 02:36:49 +00:00
|
|
|
|
public void ppubus_write(int addr, byte value)
|
2011-02-27 09:45:50 +00:00
|
|
|
|
{
|
2011-06-06 10:27:42 +00:00
|
|
|
|
nes.board.AddressPPU(addr);
|
2011-02-27 09:45:50 +00:00
|
|
|
|
nes.board.WritePPU(addr, value);
|
|
|
|
|
}
|
|
|
|
|
|
2011-02-28 06:16:20 +00:00
|
|
|
|
//when the ppu issues a read it goes through here and into the game board
|
2011-03-06 02:36:49 +00:00
|
|
|
|
public byte ppubus_read(int addr)
|
2011-02-27 09:45:50 +00:00
|
|
|
|
{
|
2011-06-06 10:27:42 +00:00
|
|
|
|
nes.board.AddressPPU(addr);
|
2011-03-28 16:43:15 +00:00
|
|
|
|
//apply freeze
|
|
|
|
|
if (ppubus_freeze[addr].IsFrozen)
|
|
|
|
|
return ppubus_freeze[addr].value;
|
|
|
|
|
else
|
|
|
|
|
return nes.board.ReadPPU(addr);
|
2011-02-27 09:45:50 +00:00
|
|
|
|
}
|
|
|
|
|
|
2011-03-13 19:35:50 +00:00
|
|
|
|
//debug tools peek into the ppu through this
|
|
|
|
|
public byte ppubus_peek(int addr)
|
|
|
|
|
{
|
|
|
|
|
return nes.board.PeekPPU(addr);
|
|
|
|
|
}
|
|
|
|
|
|
2011-02-27 09:45:50 +00:00
|
|
|
|
enum PPUPHASE {
|
|
|
|
|
VBL, BG, OBJ
|
|
|
|
|
};
|
|
|
|
|
PPUPHASE ppuphase;
|
|
|
|
|
|
|
|
|
|
NES nes;
|
|
|
|
|
public PPU(NES nes)
|
|
|
|
|
{
|
|
|
|
|
this.nes = nes;
|
|
|
|
|
Reset();
|
|
|
|
|
}
|
|
|
|
|
|
2011-03-01 09:32:12 +00:00
|
|
|
|
//state
|
2011-02-27 09:45:50 +00:00
|
|
|
|
int ppudead; //measured in frames
|
|
|
|
|
bool idleSynch;
|
|
|
|
|
|
2011-04-17 22:51:53 +00:00
|
|
|
|
public void SyncState(Serializer ser)
|
2011-03-01 09:32:12 +00:00
|
|
|
|
{
|
2011-04-17 22:51:53 +00:00
|
|
|
|
ser.Sync("ppudead", ref ppudead);
|
|
|
|
|
ser.Sync("idleSynch", ref idleSynch);
|
|
|
|
|
ser.Sync("Reg2002_objoverflow", ref Reg2002_objoverflow);
|
|
|
|
|
ser.Sync("Reg2002_objhit", ref Reg2002_objhit);
|
|
|
|
|
ser.Sync("Reg2002_vblank_active", ref Reg2002_vblank_active);
|
|
|
|
|
ser.Sync("PPUGenLatch", ref PPUGenLatch);
|
|
|
|
|
ser.Sync("reg_2003", ref reg_2003);
|
|
|
|
|
ser.Sync("OAM", ref OAM, false);
|
|
|
|
|
ser.Sync("PALRAM", ref PALRAM, false);
|
|
|
|
|
ser.Sync("vtoggle", ref vtoggle);
|
|
|
|
|
ser.Sync("VRAMBuffer", ref VRAMBuffer);
|
|
|
|
|
ppur.SyncState(ser);
|
|
|
|
|
|
|
|
|
|
if(ser.IsText)
|
|
|
|
|
ser.Sync("xbuf", ref xbuf, false);
|
|
|
|
|
|
|
|
|
|
byte temp;
|
|
|
|
|
|
|
|
|
|
temp = reg_2000.Value; ser.Sync("reg_2000.Value", ref temp); reg_2000.Value = temp;
|
|
|
|
|
temp = reg_2001.Value; ser.Sync("reg_2001.Value", ref temp); reg_2001.Value = temp;
|
2011-03-01 09:32:12 +00:00
|
|
|
|
}
|
|
|
|
|
|
2011-02-27 09:45:50 +00:00
|
|
|
|
public void Reset()
|
|
|
|
|
{
|
|
|
|
|
regs_reset();
|
|
|
|
|
ppudead = 2;
|
|
|
|
|
idleSynch = true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void TriggerNMI()
|
|
|
|
|
{
|
|
|
|
|
nes.cpu.NMI = true;
|
|
|
|
|
}
|
|
|
|
|
|
2011-06-06 10:27:42 +00:00
|
|
|
|
public void TickCpu()
|
|
|
|
|
{
|
|
|
|
|
if (NMI_PendingCycles > 0)
|
|
|
|
|
{
|
|
|
|
|
NMI_PendingCycles--;
|
|
|
|
|
if (NMI_PendingCycles == 0)
|
|
|
|
|
{
|
|
|
|
|
TriggerNMI();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2011-02-27 09:45:50 +00:00
|
|
|
|
void runppu(int x)
|
|
|
|
|
{
|
|
|
|
|
//pputime+=x;
|
|
|
|
|
|
|
|
|
|
//DON'T LIKE THIS....
|
2011-03-16 06:30:25 +00:00
|
|
|
|
ppur.status.cycle += x;
|
2011-06-06 10:27:42 +00:00
|
|
|
|
while(ppur.status.cycle >= ppur.status.end_cycle)
|
2011-03-16 06:30:25 +00:00
|
|
|
|
ppur.status.cycle -= ppur.status.end_cycle;
|
2011-06-06 10:27:42 +00:00
|
|
|
|
|
|
|
|
|
if(x == 0) return;
|
|
|
|
|
|
|
|
|
|
nes.RunCpu(1);
|
|
|
|
|
x--;
|
|
|
|
|
|
|
|
|
|
if (Reg2002_vblank_active_pending)
|
|
|
|
|
{
|
|
|
|
|
if (Reg2002_vblank_active_pending)
|
|
|
|
|
Reg2002_vblank_active = 1;
|
|
|
|
|
Reg2002_vblank_active_pending = false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (Reg2002_vblank_clear_pending)
|
|
|
|
|
{
|
|
|
|
|
Reg2002_vblank_active = 0;
|
|
|
|
|
Reg2002_vblank_clear_pending = false;
|
|
|
|
|
}
|
|
|
|
|
|
2011-03-16 06:30:25 +00:00
|
|
|
|
|
2011-06-06 10:27:42 +00:00
|
|
|
|
if (x == 0) return;
|
2011-02-27 09:45:50 +00:00
|
|
|
|
nes.RunCpu(x);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//hack
|
2011-02-28 09:13:27 +00:00
|
|
|
|
public bool PAL = false;
|
2011-02-27 09:45:50 +00:00
|
|
|
|
bool SPRITELIMIT = true;
|
|
|
|
|
const int MAXSPRITES = 8;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|