Mesen-X/Core/PPU.cpp

187 lines
4.7 KiB
C++
Raw Normal View History

2014-06-14 11:27:55 -04:00
#include "stdafx.h"
#include "PPU.h"
2014-06-14 18:20:56 -04:00
#include "CPU.h"
2014-06-14 11:27:55 -04:00
2014-06-15 21:45:36 -04:00
PPU::PPU(MemoryManager *memoryManager)
2014-06-14 11:27:55 -04:00
{
2014-06-15 21:45:36 -04:00
_memoryManager = memoryManager;
2014-06-14 11:27:55 -04:00
_state = {};
2014-06-15 09:35:17 -04:00
_flags = {};
_statusFlags = {};
2014-06-14 18:20:56 -04:00
_outputBuffer = new uint8_t[256 * 240 * 4];
}
PPU::~PPU()
{
delete[] _outputBuffer;
}
bool PPU::CheckFlag(PPUControlFlags flag)
{
return false;
2014-06-14 11:27:55 -04:00
}
2014-06-15 21:45:36 -04:00
uint8_t PPU::ReadRAM(uint16_t addr)
2014-06-14 11:27:55 -04:00
{
switch(GetRegisterID(addr)) {
case PPURegisters::Control:
return (uint8_t)_state.Control;
case PPURegisters::Control2:
2014-06-14 18:20:56 -04:00
return (uint8_t)_state.Control2;
2014-06-14 11:27:55 -04:00
case PPURegisters::Status:
_writeLow = true;
2014-06-14 18:20:56 -04:00
UpdateStatusFlag();
2014-06-14 11:27:55 -04:00
return _state.Status;
case PPURegisters::SpriteData:
return _spriteRAM[_state.SpriteRamAddr];
case PPURegisters::VideoMemoryData:
2014-06-14 18:20:56 -04:00
uint8_t returnValue = _memoryReadBuffer;
2014-06-15 21:45:36 -04:00
_memoryReadBuffer = _memoryManager->ReadVRAM(_state.VideoRamAddr);
_state.VideoRamAddr += _flags.VerticalWrite ? 32 : 1;
2014-06-14 18:20:56 -04:00
return returnValue;
2014-06-14 11:27:55 -04:00
}
return 0;
}
2014-06-15 21:45:36 -04:00
void PPU::WriteRAM(uint16_t addr, uint8_t value)
2014-06-14 11:27:55 -04:00
{
2014-06-14 18:20:56 -04:00
switch(GetRegisterID(addr)) {
case PPURegisters::Control:
_state.Control = value;
UpdateFlags();
break;
case PPURegisters::Control2:
_state.Control2 = value;
UpdateFlags();
break;
case PPURegisters::SpriteAddr:
_state.SpriteRamAddr = value;
break;
case PPURegisters::SpriteData:
_spriteRAM[_state.SpriteRamAddr&0xFF] = value;
2014-06-14 18:20:56 -04:00
break;
case PPURegisters::ScrollOffsets:
_writeLow = !_writeLow;
2014-06-14 18:20:56 -04:00
break;
case PPURegisters::VideoMemoryAddr:
if(_writeLow) {
2014-06-14 18:20:56 -04:00
_state.VideoRamAddr &= 0xFF00;
_state.VideoRamAddr |= value;
} else {
_state.VideoRamAddr |= value<<8;
}
_writeLow = !_writeLow;
2014-06-14 18:20:56 -04:00
break;
case PPURegisters::VideoMemoryData:
2014-06-15 21:45:36 -04:00
_memoryManager->WriteVRAM(_state.VideoRamAddr, value);
_state.VideoRamAddr += _flags.VerticalWrite ? 32 : 1;
2014-06-14 18:20:56 -04:00
break;
}
}
2014-06-14 11:27:55 -04:00
2014-06-14 18:20:56 -04:00
void PPU::UpdateFlags()
{
uint8_t nameTable = (_state.Control & 0x03);
switch(nameTable) {
case 0: _flags.NameTableAddr = 0x2000; break;
case 1: _flags.NameTableAddr = 0x2400; break;
case 2: _flags.NameTableAddr = 0x2800; break;
case 3: _flags.NameTableAddr = 0x2C00; break;
}
_flags.VerticalWrite = (_state.Control & 0x04) == 0x04;
_flags.SpritePatternAddr = ((_state.Control & 0x08) == 0x08) ? 0x1000 : 0x0000;
_flags.BackgroundPatternAddr = ((_state.Control & 0x10) == 0x10) ? 0x1000 : 0x0000;
_flags.LargeSprites = (_state.Control & 0x20) == 0x20;
_flags.VBlank = (_state.Control & 0x80) == 0x80;
_flags.Grayscale = (_state.Control2 & 0x01) == 0x01;
_flags.BackgroundMask = (_state.Control2 & 0x02) == 0x02;
_flags.SpriteMask = (_state.Control2 & 0x04) == 0x04;
_flags.BackgroundEnabled = (_state.Control2 & 0x08) == 0x08;
_flags.SpritesEnabled = (_state.Control2 & 0x10) == 0x10;
_flags.IntensifyRed = (_state.Control2 & 0x20) == 0x20;
_flags.IntensifyGreen = (_state.Control2 & 0x40) == 0x40;
_flags.IntensifyBlue = (_state.Control2 & 0x80) == 0x80;
}
void PPU::UpdateStatusFlag()
{
_state.Status = ((uint8_t)_statusFlags.SpriteOverflow << 5) |
((uint8_t)_statusFlags.Sprite0Hit << 6) |
2014-06-15 09:35:17 -04:00
((uint8_t)_statusFlags.VerticalBlank << 7);
_statusFlags.VerticalBlank = false;
2014-06-14 18:20:56 -04:00
}
void PPU::Exec()
{
uint64_t equivalentCycleCount = CPU::GetCycleCount() * 3;
while(_cycleCount < equivalentCycleCount) {
if(_scanline == -1) {
2014-06-15 09:35:17 -04:00
//Pre-render scanline
2014-06-14 18:20:56 -04:00
if(_cycle == 1) {
_statusFlags.SpriteOverflow = false;
_statusFlags.Sprite0Hit = false;
2014-06-15 09:35:17 -04:00
_statusFlags.VerticalBlank = false;
2014-06-14 18:20:56 -04:00
} else if(_cycle == 304) {
// Copy scroll latch into VRAMADDR register
2014-06-15 09:35:17 -04:00
/*if(_flags.BackgroundEnabled || _flags.SpritesEnabled) {
2014-06-14 18:20:56 -04:00
//p->registers.vramAddress = p->registers.vramLatch;
2014-06-15 09:35:17 -04:00
}*/
2014-06-15 21:45:36 -04:00
} else if(_cycle == 339 && _flags.BackgroundEnabled && (_frameCount % 2 == 1)) {
//Skip a cycle for odd frames, if background drawing is enabled
2014-06-15 09:35:17 -04:00
_cycle++;
2014-06-14 18:20:56 -04:00
}
} else if(_scanline < 240) {
if(_cycle == 254) {
if(_flags.BackgroundEnabled) {
//Ppu_renderTileRow(p);
}
if(_flags.SpritesEnabled) {
//Ppu_evaluateScanlineSprites(p, p->scanline);
}
} else if(_cycle == 256) {
if(_flags.BackgroundEnabled) {
//Ppu_updateEndScanlineRegisters(p);
}
}
2014-06-15 09:35:17 -04:00
} else if(_scanline == 241) {
//Start of VBlank
2014-06-14 18:20:56 -04:00
if(_cycle == 1) {
2014-06-15 09:35:17 -04:00
_statusFlags.VerticalBlank = true;
/*if(!_suppressVBlank) {
2014-06-14 18:20:56 -04:00
// We're in VBlank
Ppu_setStatus(p, STATUS_VBLANK_STARTED);
p->cycleCount = 0;
2014-06-15 09:35:17 -04:00
}*/
if(_flags.VBlank) {
CPU::SetNMIFlag();
2014-06-14 18:20:56 -04:00
}
2014-06-15 09:35:17 -04:00
/*if(_flags.VBlank && !_suppressNMI) {
2014-06-14 18:20:56 -04:00
VBlankInterrupt();
2014-06-15 09:35:17 -04:00
}*/
2014-06-14 18:20:56 -04:00
//Ppu_raster(p);
}
} else if(_scanline == 260) {
2014-06-15 09:35:17 -04:00
//End of VBlank
if(_cycle == 340) {
2014-06-14 18:20:56 -04:00
_frameCount++;
}
}
2014-06-15 09:35:17 -04:00
if(_cycle == 340) {
2014-06-14 18:20:56 -04:00
_cycle = 0;
_scanline++;
2014-06-15 09:35:17 -04:00
if(_scanline == 261) {
_scanline = -1;
_frameCount++;
}
} else {
_cycle++;
2014-06-14 18:20:56 -04:00
}
_cycleCount++;
}
2014-06-14 11:27:55 -04:00
}