157 lines
2.2 KiB
C++
157 lines
2.2 KiB
C++
![]() |
#include "PPU.hpp"
|
||
|
#include "Log.hpp"
|
||
|
#include "Bus.hpp"
|
||
|
|
||
|
PPU::PPU(Bus* bus) :
|
||
|
bus(bus), ppuctrl{0}, ppustatus{0}
|
||
|
{
|
||
|
}
|
||
|
|
||
|
void PPU::Powerup()
|
||
|
{
|
||
|
ppuctrl.Raw = 0b00000000;
|
||
|
ppumask.Raw = 0b00000000;
|
||
|
ppustatus.Raw = 0b10100000;
|
||
|
ppuscroll.x = 0x00;
|
||
|
ppuscroll.y = 0x00;
|
||
|
ppuaddr.Raw = 0x0000;
|
||
|
|
||
|
x = 0;
|
||
|
y = 0;
|
||
|
addressLatch = 0;
|
||
|
}
|
||
|
|
||
|
void PPU::Reset()
|
||
|
{
|
||
|
ppuctrl.Raw = 0b00000000;
|
||
|
ppumask.Raw = 0b00000000;
|
||
|
ppuscroll.x = 0x00;
|
||
|
ppuscroll.y = 0x00;
|
||
|
|
||
|
x = 0;
|
||
|
y = 0;
|
||
|
addressLatch = 1;
|
||
|
}
|
||
|
|
||
|
void PPU::Tick()
|
||
|
{
|
||
|
if (y == 241 && x == 1)
|
||
|
{
|
||
|
ppustatus.Flag.VBlankStarted = 1;
|
||
|
if (ppuctrl.Flag.VBlankNMI)
|
||
|
bus->NMI();
|
||
|
|
||
|
isFrameDone = true;
|
||
|
}
|
||
|
|
||
|
if (y == 261 && x == 1)
|
||
|
ppustatus.Flag.VBlankStarted = 0;
|
||
|
|
||
|
x++;
|
||
|
if (x > 340)
|
||
|
{
|
||
|
x = 0;
|
||
|
y++;
|
||
|
if (y > 261)
|
||
|
y = 0;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
Byte PPU::ReadRegister(Byte id)
|
||
|
{
|
||
|
Byte returnVal = 0x00;
|
||
|
|
||
|
switch (id)
|
||
|
{
|
||
|
case 0:
|
||
|
returnVal = ppuctrl.Raw;
|
||
|
break;
|
||
|
|
||
|
case 1:
|
||
|
returnVal = ppumask.Raw;
|
||
|
break;
|
||
|
|
||
|
case 2:
|
||
|
returnVal = ppustatus.Raw;
|
||
|
ppustatus.Flag.VBlankStarted = 0;
|
||
|
addressLatch = 0;
|
||
|
break;
|
||
|
|
||
|
case 5:
|
||
|
returnVal = 0x00;
|
||
|
break;
|
||
|
|
||
|
case 6:
|
||
|
returnVal = 0x00;
|
||
|
break;
|
||
|
|
||
|
case 7:
|
||
|
returnVal = bus->ReadPPU(ppuaddr.Raw);
|
||
|
ppuaddr.Raw += (ppuctrl.Flag.VRAMAddrIncrement ? 32 : 1);
|
||
|
break;
|
||
|
|
||
|
default:
|
||
|
LOG_CORE_WARN("Tried to read unimplemented PPU register $20{0:02X}", (Word)id);
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
return returnVal;
|
||
|
}
|
||
|
|
||
|
void PPU::WriteRegister(Byte id, Byte val)
|
||
|
{
|
||
|
switch (id)
|
||
|
{
|
||
|
case 0:
|
||
|
ppuctrl.Raw = val;
|
||
|
break;
|
||
|
|
||
|
case 1:
|
||
|
ppumask.Raw = val;
|
||
|
break;
|
||
|
|
||
|
case 2:
|
||
|
ppustatus.Raw = val;
|
||
|
break;
|
||
|
|
||
|
case 5:
|
||
|
if (addressLatch == 0)
|
||
|
ppuscroll.x = val;
|
||
|
else
|
||
|
ppuscroll.y = val;
|
||
|
|
||
|
addressLatch = 1 - addressLatch;
|
||
|
break;
|
||
|
|
||
|
case 6:
|
||
|
if (addressLatch == 0)
|
||
|
ppuaddr.Bytes.hi = val;
|
||
|
else
|
||
|
ppuaddr.Bytes.lo = val;
|
||
|
|
||
|
addressLatch = 1 - addressLatch;
|
||
|
break;
|
||
|
|
||
|
case 7:
|
||
|
bus->WritePPU(ppuaddr.Raw, val);
|
||
|
ppuaddr.Raw += (ppuctrl.Flag.VRAMAddrIncrement ? 32 : 1);
|
||
|
break;
|
||
|
|
||
|
default:
|
||
|
LOG_CORE_WARN("Tried to write unimplemented PPU register $20{0:02X}", (Word)id);
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
ppustatus.Flag.Unused = val & 0x1F;
|
||
|
}
|
||
|
|
||
|
Byte PPU::Read(Word addr)
|
||
|
{
|
||
|
return bus->ReadPPU(addr);
|
||
|
}
|
||
|
|
||
|
void PPU::Write(Word addr, Byte val)
|
||
|
{
|
||
|
bus->WritePPU(addr, val);
|
||
|
}
|