PPU working (lots of glitches, but draws correctly)
This commit is contained in:
parent
4341e47e17
commit
0262e8c53c
10 changed files with 326 additions and 52 deletions
|
@ -70,7 +70,8 @@ void CPU::Exec()
|
|||
(this->*_opTable[opCode])();
|
||||
CPU::CycleCount += this->_cycles[opCode];
|
||||
} else {
|
||||
//throw std::exception("Invalid opcode");
|
||||
//std::cout << "Invalid opcode: " << std::hex << (short)opCode;
|
||||
//throw exception("Invalid opcode");
|
||||
}
|
||||
} else {
|
||||
NMI();
|
||||
|
|
|
@ -616,7 +616,7 @@ private:
|
|||
}
|
||||
|
||||
void NMI() {
|
||||
Push((uint16_t)(PC() + 1));
|
||||
Push((uint16_t)(PC()));
|
||||
Push((uint8_t)PS());
|
||||
SetFlags(PSFlags::Interrupt);
|
||||
SetPC(MemoryReadWord(0xFFFA));
|
||||
|
|
|
@ -30,6 +30,8 @@ void Console::Run()
|
|||
|
||||
void Console::RunTest(bool callback(Console*))
|
||||
{
|
||||
Timer timer;
|
||||
uint32_t lastFrameCount = 0;
|
||||
while(true) {
|
||||
if(callback(this)) {
|
||||
break;
|
||||
|
@ -37,28 +39,36 @@ void Console::RunTest(bool callback(Console*))
|
|||
|
||||
_cpu->Exec();
|
||||
_ppu->Exec();
|
||||
|
||||
if(timer.GetElapsedMS() > 5000) {
|
||||
uint32_t frameCount = _ppu->GetFrameCount();
|
||||
std::cout << ((frameCount - lastFrameCount) / (timer.GetElapsedMS() / 1000)) << std::endl;
|
||||
timer.Reset();
|
||||
lastFrameCount = frameCount;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Console::RunTests()
|
||||
{
|
||||
vector<string> testROMs {
|
||||
//"mario"
|
||||
"01-basics",
|
||||
vector<string> testROMs {
|
||||
"dk",
|
||||
"mario",
|
||||
"01-basics",
|
||||
"02-implied",
|
||||
"03-immediate",
|
||||
"04-zero_page",
|
||||
"05-zp_xy",
|
||||
"04-zero_page",
|
||||
"05-zp_xy",
|
||||
"06-absolute",
|
||||
"07-abs_xy",
|
||||
"08-ind_x",
|
||||
"09-ind_y",
|
||||
"07-abs_xy",
|
||||
"08-ind_x",
|
||||
"09-ind_y",
|
||||
"10-branches",
|
||||
"11-stack",
|
||||
"12-jmp_jsr",
|
||||
"13-rts",
|
||||
"11-stack",
|
||||
"12-jmp_jsr",
|
||||
"13-rts",
|
||||
"14-rti",
|
||||
"15-brk",
|
||||
"15-brk",
|
||||
"16-special"
|
||||
};
|
||||
|
||||
|
@ -78,7 +88,7 @@ void Console::RunTests()
|
|||
});
|
||||
} else {
|
||||
console->RunTest([] (Console *console) {
|
||||
static std::ofstream output("test.log", ios::out | ios::binary);
|
||||
//static std::ofstream output("test.log", ios::out | ios::binary);
|
||||
static bool testStarted = false;
|
||||
uint8_t testStatus = console->_memoryManager.Read(0x6000);
|
||||
|
||||
|
|
|
@ -9,6 +9,6 @@ public:
|
|||
virtual vector<std::array<uint16_t, 2>> GetVRAMAddresses() { return{}; }
|
||||
virtual uint8_t ReadRAM(uint16_t addr) = 0;
|
||||
virtual void WriteRAM(uint16_t addr, uint8_t value) = 0;
|
||||
virtual uint8_t ReadVRAM(uint16_t addr) { return 0; }
|
||||
virtual void WriteVRAM(uint16_t addr, uint8_t value) { }
|
||||
virtual uint8_t ReadVRAM(uint16_t addr) { throw exception("Operation not implemented"); }
|
||||
virtual void WriteVRAM(uint16_t addr, uint8_t value) { throw exception("Operation not implemented"); }
|
||||
};
|
|
@ -119,15 +119,36 @@ uint8_t MemoryManager::ReadVRAM(uint16_t addr)
|
|||
if(addr <= 0x1FFF) {
|
||||
return ReadMappedVRAM(addr & 0x1FFF);
|
||||
} else {
|
||||
if(addr >= 0x3F00) {
|
||||
addr &= 0x3F1F;
|
||||
}
|
||||
return _videoRAM[addr & 0x3FFF];
|
||||
}
|
||||
}
|
||||
|
||||
void MemoryManager::WriteVRAM(uint16_t addr, uint8_t value)
|
||||
{
|
||||
addr = addr & 0x3FFF;
|
||||
if(addr <= 0x1FFF) {
|
||||
WriteMappedVRAM(addr, value);
|
||||
} else {
|
||||
_videoRAM[addr & 0x3FFF] = value;
|
||||
if(addr >= 0x3F00) {
|
||||
addr &= 0x3F1F;
|
||||
//std::cout << "palette:" << std::hex << (short)addr << " = " << (short)value << std::endl;
|
||||
}
|
||||
if(addr == 0x2000) {
|
||||
//std::cout << "test" << std::endl;
|
||||
}
|
||||
_videoRAM[addr] = value;
|
||||
|
||||
if(addr >= 0x2000 && addr < 0x2400) {
|
||||
_videoRAM[addr + 0x800] = value;
|
||||
} else if(addr >= 0x2400 && addr < 0x2800) {
|
||||
_videoRAM[addr + 0x800] = value;
|
||||
} else if(addr >= 0x2800 && addr < 0x2C00) {
|
||||
_videoRAM[addr - 0x800] = value;
|
||||
} else if(addr >= 0x2C00 && addr < 0x3000) {
|
||||
_videoRAM[addr - 0x800] = value;
|
||||
}
|
||||
}
|
||||
}
|
239
Core/PPU.cpp
239
Core/PPU.cpp
|
@ -2,6 +2,25 @@
|
|||
#include "PPU.h"
|
||||
#include "CPU.h"
|
||||
|
||||
uint32_t PPU_PALETTE_RGB[] = {
|
||||
0x666666, 0x002A88, 0x1412A7, 0x3B00A4, 0x5C007E,
|
||||
0x6E0040, 0x6C0600, 0x561D00, 0x333500, 0x0B4800,
|
||||
0x005200, 0x004F08, 0x00404D, 0x000000, 0x000000,
|
||||
0x000000, 0xADADAD, 0x155FD9, 0x4240FF, 0x7527FE,
|
||||
0xA01ACC, 0xB71E7B, 0xB53120, 0x994E00, 0x6B6D00,
|
||||
0x388700, 0x0C9300, 0x008F32, 0x007C8D, 0x000000,
|
||||
0x000000, 0x000000, 0xFFFEFF, 0x64B0FF, 0x9290FF,
|
||||
0xC676FF, 0xF36AFF, 0xFE6ECC, 0xFE8170, 0xEA9E22,
|
||||
0xBCBE00, 0x88D800, 0x5CE430, 0x45E082, 0x48CDDE,
|
||||
0x4F4F4F, 0x000000, 0x000000, 0xFFFEFF, 0xC0DFFF,
|
||||
0xD3D2FF, 0xE8C8FF, 0xFBC2FF, 0xFEC4EA, 0xFECCC5,
|
||||
0xF7D8A5, 0xE4E594, 0xCFEF96, 0xBDF4AB, 0xB3F3CC,
|
||||
0xB5EBF2, 0xB8B8B8, 0x000000, 0x000000,
|
||||
};
|
||||
|
||||
uint8_t *PPU::FrameBuffer = new uint8_t[256*240*4];
|
||||
atomic<int> PPU::WaitCounter = 0;
|
||||
|
||||
PPU::PPU(MemoryManager *memoryManager)
|
||||
{
|
||||
_memoryManager = memoryManager;
|
||||
|
@ -54,6 +73,7 @@ uint8_t PPU::ReadRAM(uint16_t addr)
|
|||
|
||||
void PPU::WriteRAM(uint16_t addr, uint8_t value)
|
||||
{
|
||||
static int counter = 0;
|
||||
switch(GetRegisterID(addr)) {
|
||||
case PPURegisters::Control:
|
||||
_state.Control = value;
|
||||
|
@ -72,23 +92,35 @@ void PPU::WriteRAM(uint16_t addr, uint8_t value)
|
|||
break;
|
||||
case PPURegisters::ScrollOffsets:
|
||||
if(_state.WriteToggle) {
|
||||
_state.TmpVideoRamAddr = (_state.TmpVideoRamAddr & ~0x73E0) | ((value & 0xF8) << 2) | ((value & 0x0F) << 12);
|
||||
_state.TmpVideoRamAddr = (_state.TmpVideoRamAddr & ~0x73E0) | ((value & 0xF8) << 2) | ((value & 0x07) << 12);
|
||||
} else {
|
||||
_state.XScroll = value & 0x07;
|
||||
_state.TmpVideoRamAddr = (_state.TmpVideoRamAddr & ~0x00F8) | (value >> 3);
|
||||
_state.TmpVideoRamAddr = (_state.TmpVideoRamAddr & ~0x001F) | (value >> 3);
|
||||
}
|
||||
_state.WriteToggle = !_state.WriteToggle;
|
||||
break;
|
||||
case PPURegisters::VideoMemoryAddr:
|
||||
if(counter < 50) {
|
||||
std::cout << "=> " << std::hex << (short)value << std::endl;
|
||||
}
|
||||
|
||||
if(_state.WriteToggle) {
|
||||
_state.TmpVideoRamAddr |= (_state.TmpVideoRamAddr & ~0xFF00) | (value & 0x3F) << 8;
|
||||
_state.VideoRamAddr = _state.TmpVideoRamAddr;
|
||||
} else {
|
||||
_state.TmpVideoRamAddr = (_state.TmpVideoRamAddr & ~0x00FF) | value;
|
||||
_state.VideoRamAddr = _state.TmpVideoRamAddr;
|
||||
if(counter < 50) {
|
||||
std::cout << std::hex << _state.VideoRamAddr << std::endl;
|
||||
}
|
||||
counter++;
|
||||
|
||||
} else {
|
||||
_state.TmpVideoRamAddr = (_state.TmpVideoRamAddr & ~0xFF00) | ((value & 0x3F) << 8);
|
||||
}
|
||||
_state.WriteToggle = !_state.WriteToggle;
|
||||
break;
|
||||
case PPURegisters::VideoMemoryData:
|
||||
if(_state.VideoRamAddr == 0x2001 || _state.VideoRamAddr == 0x2401 || _state.VideoRamAddr == 0x2801 || _state.VideoRamAddr == 0x2C01) {
|
||||
//std::cout << "test";
|
||||
}
|
||||
_memoryManager->WriteVRAM(_state.VideoRamAddr, value);
|
||||
_state.VideoRamAddr += _flags.VerticalWrite ? 32 : 1;
|
||||
break;
|
||||
|
@ -156,6 +188,7 @@ void PPU::IncVerticalScrolling()
|
|||
y += 1; // increment coarse Y
|
||||
}
|
||||
addr = (addr & ~0x03E0) | (y << 5); // put coarse Y back into v
|
||||
//std::cout << std::endl;
|
||||
}
|
||||
_state.VideoRamAddr = addr;
|
||||
}
|
||||
|
@ -195,8 +228,12 @@ void PPU::UpdateScrolling()
|
|||
} else if(_cycle == 257) {
|
||||
//copy horizontal scrolling value from t
|
||||
_state.VideoRamAddr = (_state.VideoRamAddr & ~0x041F) | (_state.TmpVideoRamAddr & 0x041F);
|
||||
} else if((_cycle % 8 == 0 && _cycle < 256) || _cycle == 328 || _cycle == 336) {
|
||||
} else if((_cycle % 8 == 0 && _cycle > 0 && _cycle < 256) || _cycle == 328 || _cycle == 336) {
|
||||
IncHorizontalScrolling();
|
||||
} else if((_cycle - 1) % 8 == 0 && _cycle < 250) {
|
||||
LoadTileInfo();
|
||||
} else if(_cycle == 321 || _cycle == 329) {
|
||||
LoadTileInfo();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -215,19 +252,87 @@ void PPU::ProcessPrerenderScanline()
|
|||
//copy vertical scrolling value from t
|
||||
_state.VideoRamAddr = (_state.VideoRamAddr & ~0x7BF0) | (_state.TmpVideoRamAddr & 0x7BF0);
|
||||
}
|
||||
} else if(_cycle == 339 && _flags.BackgroundEnabled && (_frameCount % 2 == 1)) {
|
||||
} else if(_cycle == 340 && _flags.BackgroundEnabled && (_frameCount % 2 == 1)) {
|
||||
//Skip a cycle for odd frames, if background drawing is enabled
|
||||
_cycle++;
|
||||
_cycle = 0;
|
||||
_scanline = 0;
|
||||
} else if(_cycle == 321 || _cycle == 329) {
|
||||
LoadTileInfo();
|
||||
}
|
||||
}
|
||||
|
||||
void PPU::LoadTileInfo()
|
||||
{
|
||||
_currentTile = _nextTile;
|
||||
|
||||
uint16_t tileIndex = _memoryManager->ReadVRAM(GetTileAddr());
|
||||
uint16_t tileAddr = (tileIndex << 4) | (_state.VideoRamAddr >> 12) | _flags.BackgroundPatternAddr;
|
||||
|
||||
//std::cout << std::hex << GetAttributeAddr() << " ";
|
||||
uint16_t shift = _state.VideoRamAddr&0x3FF;
|
||||
_nextTile.Attributes = ((_memoryManager->ReadVRAM(GetAttributeAddr()) >> shift) & 0x03) << 2;
|
||||
_nextTile.LowByte = _memoryManager->ReadVRAM(tileAddr);
|
||||
_nextTile.HighByte = _memoryManager->ReadVRAM(tileAddr + 8);
|
||||
|
||||
_state.LowBitShift = (_state.LowBitShift << 8) | _nextTile.LowByte;
|
||||
_state.HighBitShift = (_state.HighBitShift << 8) | _nextTile.HighByte;
|
||||
}
|
||||
|
||||
void PPU::DrawPixel()
|
||||
{
|
||||
uint8_t palette = 0;
|
||||
|
||||
uint8_t tileXPixel = _cycle % 8;
|
||||
uint32_t bufferPosition = _scanline * 256 + _cycle;
|
||||
|
||||
uint8_t fineXScroll = _state.XScroll;
|
||||
|
||||
uint8_t offset = (15 - tileXPixel - fineXScroll);
|
||||
|
||||
uint8_t pixelColor = ((_state.LowBitShift >> offset) & 0x01) | (((_state.HighBitShift >> offset) & 0x01) << 1);
|
||||
|
||||
// If we're grabbing the pixel from the high
|
||||
// part of the shift register, use the buffered
|
||||
// palette, not the current one
|
||||
|
||||
if(pixelColor != 0 && _frameCount > 1000) {
|
||||
//std::cout << std::hex << (short)pixelColor << std::endl;
|
||||
}
|
||||
|
||||
if(offset < 8) {
|
||||
palette = GetBGPaletteEntry(_nextTile.Attributes, pixelColor);
|
||||
} else {
|
||||
palette = GetBGPaletteEntry(_currentTile.Attributes, pixelColor);
|
||||
}
|
||||
/*
|
||||
if(p->palettebuffer[fbRow].value != 0) {
|
||||
// Pixel is already rendered and priority
|
||||
// 1 means show behind background
|
||||
continue;
|
||||
}*/
|
||||
|
||||
//p->palettebuffer[fbRow].color = PPU_PALETTE_RGB[palette % 64];
|
||||
((uint32_t*)_outputBuffer)[bufferPosition] = PPU_PALETTE_RGB[palette % 64] | (0xFF << 24);
|
||||
//p->palettebuffer[fbRow].value = pixel;
|
||||
//p->palettebuffer[fbRow].pindex = -1;
|
||||
}
|
||||
|
||||
void PPU::ProcessVisibleScanline()
|
||||
{
|
||||
if(IsRenderingEnabled()) {
|
||||
UpdateScrolling();
|
||||
}
|
||||
|
||||
if(_cycle <= 254) {
|
||||
DrawPixel();
|
||||
}
|
||||
|
||||
if(_cycle == 254) {
|
||||
//DrawScanline();
|
||||
if(_scanline == 239) {
|
||||
CopyFrame();
|
||||
//std::cout << std::endl << std::endl << std::endl;
|
||||
}
|
||||
if(_flags.BackgroundEnabled) {
|
||||
//Ppu_renderTileRow(p);
|
||||
}
|
||||
|
@ -235,13 +340,120 @@ void PPU::ProcessVisibleScanline()
|
|||
if(_flags.SpritesEnabled) {
|
||||
//Ppu_evaluateScanlineSprites(p, p->scanline);
|
||||
}
|
||||
} else if(_cycle == 256) {
|
||||
if(_flags.BackgroundEnabled) {
|
||||
//Ppu_updateEndScanlineRegisters(p);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void PPU::DrawScanline()
|
||||
{
|
||||
// Generates each tile, one scanline at a time and applies the palette
|
||||
|
||||
// Move first tile into shift registers
|
||||
//PpuTileAttributes tileAttrs;
|
||||
//FetchTileAttributes(&tileAttrs);
|
||||
/* _state.LowBitShift = tileAttrs.low;
|
||||
_state.HighBitShift = tileAttrs.high;
|
||||
uint8_t attr = tileAttrs.attr;
|
||||
|
||||
FetchTileAttributes(&tileAttrs);
|
||||
// Get second tile, move the pixels into the right side of
|
||||
// shift registers
|
||||
_state.LowBitShift = (_state.LowBitShift << 8) | tileAttrs.low;
|
||||
_state.HighBitShift = (_state.HighBitShift << 8) | tileAttrs.high;
|
||||
// Current tile to render is attrBuf
|
||||
uint8_t attrBuf = tileAttrs.attr;
|
||||
|
||||
for(int x = 0; x < 32; x++) {
|
||||
int palette = 0;
|
||||
|
||||
for(unsigned int b = 0; b < 8; b++) {
|
||||
int intB = b;
|
||||
int fbRow = _scanline * 256 + ((x * 8) + intB);
|
||||
|
||||
unsigned int uintFineX = _state.XScroll;
|
||||
uint16_t pixel = (_state.LowBitShift >> (15 - b - uintFineX)) & 0x01;
|
||||
pixel += ((_state.HighBitShift >> (15 - b - uintFineX) & 0x01) << 1);
|
||||
|
||||
// If we're grabbing the pixel from the high
|
||||
// part of the shift register, use the buffered
|
||||
// palette, not the current one
|
||||
if((15 - b - uintFineX) < 8) {
|
||||
palette = GetBGPaletteEntry(attrBuf, pixel);
|
||||
} else {
|
||||
palette = GetBGPaletteEntry(attr, pixel);
|
||||
}
|
||||
|
||||
if(p->palettebuffer[fbRow].value != 0) {
|
||||
// Pixel is already rendered and priority
|
||||
// 1 means show behind background
|
||||
continue;
|
||||
}
|
||||
|
||||
//p->palettebuffer[fbRow].color = PPU_PALETTE_RGB[palette % 64];
|
||||
_outputBuffer[fbRow] = PPU_PALETTE_RGB[palette % 64];
|
||||
//p->palettebuffer[fbRow].value = pixel;
|
||||
//p->palettebuffer[fbRow].pindex = -1;
|
||||
}
|
||||
|
||||
// xcoord = p->registers.vramAddress & 0x1F
|
||||
attr = attrBuf;
|
||||
|
||||
// Shift the first tile out, bring the new tile in
|
||||
FetchTileAttributes(&tileAttrs);
|
||||
_state.LowBitShift = (_state.LowBitShift << 8) | tileAttrs.low;
|
||||
_state.HighBitShift = (_state.HighBitShift << 8) | tileAttrs.high;
|
||||
attrBuf = tileAttrs.attr;
|
||||
}*/
|
||||
}
|
||||
|
||||
uint8_t PPU::GetBGPaletteEntry(uint8_t a, uint16_t pix)
|
||||
{
|
||||
uint16_t baseAddr = 0x3F00;
|
||||
if(pix == 0x0) {
|
||||
return _memoryManager->ReadVRAM(baseAddr);
|
||||
}
|
||||
|
||||
switch(a) {
|
||||
case 0x0:
|
||||
return _memoryManager->ReadVRAM(baseAddr + pix);
|
||||
case 0x4:
|
||||
return _memoryManager->ReadVRAM(baseAddr + 0x04 + pix);
|
||||
case 0x8:
|
||||
return _memoryManager->ReadVRAM(baseAddr + 0x08 + pix);
|
||||
case 0xC:
|
||||
return _memoryManager->ReadVRAM(baseAddr + 0x0C + pix);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void PPU::CopyFrame()
|
||||
{
|
||||
int counter = PPU::WaitCounter.fetch_add(1);
|
||||
if(counter != 0) {
|
||||
//We weren't the first thread to increment the value, wait until other locks are released
|
||||
while(PPU::WaitCounter > 1) {}
|
||||
}
|
||||
|
||||
memcpy(PPU::FrameBuffer, _outputBuffer, 256 * 240 * 4);
|
||||
PPU::WaitCounter--;
|
||||
}
|
||||
|
||||
uint8_t* PPU::GetFrame()
|
||||
{
|
||||
uint8_t *copyBuffer = new uint8_t[256 * 240 * 4];
|
||||
|
||||
int counter = PPU::WaitCounter.fetch_add(1);
|
||||
if(counter != 0) {
|
||||
//We weren't the first thread to increment the value, wait until other locks are released
|
||||
while(PPU::WaitCounter > 1) {}
|
||||
}
|
||||
|
||||
memcpy(copyBuffer, PPU::FrameBuffer, 256 * 240 * 4);
|
||||
PPU::WaitCounter--;
|
||||
|
||||
return copyBuffer;
|
||||
}
|
||||
|
||||
void PPU::BeginVBlank()
|
||||
{
|
||||
if(_cycle == 1) {
|
||||
|
@ -262,12 +474,12 @@ void PPU::EndVBlank()
|
|||
{
|
||||
if(_cycle == 340) {
|
||||
_frameCount++;
|
||||
//std::cout << _frameCount << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
void PPU::Exec()
|
||||
{
|
||||
bool renderingEnabled = IsRenderingEnabled();
|
||||
uint64_t equivalentCycleCount = CPU::GetCycleCount() * 3;
|
||||
while(_cycleCount < equivalentCycleCount) {
|
||||
if(_scanline == -1) {
|
||||
|
@ -286,7 +498,6 @@ void PPU::Exec()
|
|||
|
||||
if(_scanline == 261) {
|
||||
_scanline = -1;
|
||||
_frameCount++;
|
||||
}
|
||||
} else {
|
||||
_cycle++;
|
||||
|
|
33
Core/PPU.h
33
Core/PPU.h
|
@ -51,11 +51,24 @@ struct PPUState
|
|||
uint8_t XScroll;
|
||||
uint16_t TmpVideoRamAddr;
|
||||
bool WriteToggle;
|
||||
|
||||
uint16_t HighBitShift;
|
||||
uint16_t LowBitShift;
|
||||
};
|
||||
|
||||
struct TileInfo
|
||||
{
|
||||
uint8_t LowByte;
|
||||
uint8_t HighByte;
|
||||
uint8_t Attributes;
|
||||
};
|
||||
|
||||
class PPU : public IMemoryHandler
|
||||
{
|
||||
private:
|
||||
static uint8_t *FrameBuffer;
|
||||
static atomic<int> WaitCounter;
|
||||
|
||||
MemoryManager *_memoryManager;
|
||||
|
||||
PPUState _state;
|
||||
|
@ -73,6 +86,9 @@ class PPU : public IMemoryHandler
|
|||
PPUControlFlags _flags;
|
||||
PPUStatusFlags _statusFlags;
|
||||
|
||||
TileInfo _currentTile;
|
||||
TileInfo _nextTile;
|
||||
|
||||
void UpdateStatusFlag();
|
||||
|
||||
void UpdateFlags();
|
||||
|
@ -92,6 +108,14 @@ class PPU : public IMemoryHandler
|
|||
void BeginVBlank();
|
||||
void EndVBlank();
|
||||
|
||||
uint8_t GetBGPaletteEntry(uint8_t a, uint16_t pix);
|
||||
void DrawScanline();
|
||||
|
||||
void LoadTileInfo();
|
||||
void DrawPixel();
|
||||
|
||||
void CopyFrame();
|
||||
|
||||
PPURegisters GetRegisterID(uint16_t addr)
|
||||
{
|
||||
return (PPURegisters)(addr & 0x07);
|
||||
|
@ -110,4 +134,11 @@ class PPU : public IMemoryHandler
|
|||
void WriteRAM(uint16_t addr, uint8_t value);
|
||||
|
||||
void Exec();
|
||||
};
|
||||
|
||||
static uint8_t* GetFrame();
|
||||
|
||||
uint32_t GetFrameCount()
|
||||
{
|
||||
return _frameCount;
|
||||
}
|
||||
};
|
||||
|
|
|
@ -23,6 +23,8 @@
|
|||
#include <array>
|
||||
#include <sstream>
|
||||
|
||||
#include <atomic>
|
||||
|
||||
#include <windows.h>
|
||||
|
||||
using std::vector;
|
||||
|
@ -31,5 +33,5 @@ using std::unique_ptr;
|
|||
using std::ios;
|
||||
using std::ifstream;
|
||||
using std::string;
|
||||
|
||||
// TODO: reference additional headers your program requires here
|
||||
using std::exception;
|
||||
using std::atomic;
|
||||
|
|
|
@ -71,16 +71,16 @@ namespace NES
|
|||
TranslateMessage(&msg);
|
||||
DispatchMessage(&msg);
|
||||
} else {
|
||||
/*_renderer.Render();
|
||||
_renderer.Render();
|
||||
frameCount++;
|
||||
if(frameCount == 500) {
|
||||
double fps = (double)frameCount / (timer.GetElapsedMS() / 1000);
|
||||
OutputDebugString((std::to_wstring((int)fps) + L"\n").c_str());
|
||||
//std::cout << "FPS: " << fps << std::endl;
|
||||
timer.Reset();
|
||||
frameCount = 0;
|
||||
}*/
|
||||
}
|
||||
}
|
||||
std::this_thread::sleep_for(std::chrono::duration<int, std::milli>(50));
|
||||
std::this_thread::sleep_for(std::chrono::duration<int, std::milli>(1));
|
||||
}
|
||||
|
||||
return (int)msg.wParam;
|
||||
|
@ -109,7 +109,7 @@ namespace NES
|
|||
return E_FAIL;
|
||||
|
||||
// Create window
|
||||
RECT rc = { 0, 0, 320, 240 };
|
||||
RECT rc = { 0, 0, 256, 240 };
|
||||
AdjustWindowRect(&rc, WS_OVERLAPPEDWINDOW, FALSE);
|
||||
_hWnd = CreateWindow(L"NESEmu", L"NESEmu",
|
||||
WS_OVERLAPPEDWINDOW,
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
#include "stdafx.h"
|
||||
#include "Renderer.h"
|
||||
#include "DirectXTK\SpriteBatch.h"
|
||||
#include "..\Core\PPU.h"
|
||||
|
||||
namespace NES
|
||||
{
|
||||
|
@ -117,7 +118,7 @@ namespace NES
|
|||
|
||||
_pd3dDevice->CheckMultisampleQualityLevels(DXGI_FORMAT_R8G8B8A8_UNORM, 16, &fred);
|
||||
|
||||
uint16_t screenwidth = 320;
|
||||
uint16_t screenwidth = 256;
|
||||
uint16_t screenheight = 240;
|
||||
|
||||
D3D11_TEXTURE2D_DESC desc;
|
||||
|
@ -141,7 +142,7 @@ namespace NES
|
|||
renderTargetViewDescription.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE2D; // MS;
|
||||
|
||||
_videoRAM = new byte[screenwidth*screenheight * 4];
|
||||
memset(_videoRAM, 0xFF, screenwidth*screenheight);
|
||||
memset(_videoRAM, 0xFF, screenwidth*screenheight*4);
|
||||
|
||||
D3D11_SUBRESOURCE_DATA tbsd;
|
||||
tbsd.pSysMem = (void *)_videoRAM;
|
||||
|
@ -186,23 +187,20 @@ namespace NES
|
|||
// Clear the back buffer
|
||||
//_pImmediateContext->ClearRenderTargetView(_pRenderTargetView, Colors::MidnightBlue);
|
||||
|
||||
UINT screenwidth = 320, screenheight = 240;
|
||||
|
||||
if(rand() % 15 == 0) {
|
||||
for(int i = 0; i < screenwidth*screenheight * 4; i++) {
|
||||
_videoRAM[i] += rand() % 255;
|
||||
}
|
||||
}
|
||||
UINT screenwidth = 256, screenheight = 240;
|
||||
|
||||
D3D11_MAPPED_SUBRESOURCE dd;
|
||||
dd.pData = (void *)_videoRAM;
|
||||
dd.RowPitch = screenwidth * 4;
|
||||
dd.DepthPitch = screenwidth* screenheight * 4;
|
||||
|
||||
uint8_t *frameData = PPU::GetFrame();
|
||||
_pImmediateContext->Map(_pTexture, 0, D3D11_MAP_WRITE_DISCARD, 0, &dd);
|
||||
memcpy(dd.pData, _videoRAM, screenwidth*screenheight * 4);
|
||||
memcpy(dd.pData, frameData, screenwidth*screenheight * 4);
|
||||
_pImmediateContext->Unmap(_pTexture, 0);
|
||||
|
||||
delete[] frameData;
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
D3D11_SHADER_RESOURCE_VIEW_DESC srvDesc;
|
||||
D3D11_TEXTURE2D_DESC desc;
|
||||
|
@ -228,7 +226,7 @@ namespace NES
|
|||
_sprites->Begin();
|
||||
RECT x;
|
||||
x.left = 0;
|
||||
x.right = 320;
|
||||
x.right = 256;
|
||||
x.bottom = 240;
|
||||
x.top = 0;
|
||||
_sprites->Draw(pSRView, x);
|
||||
|
|
Loading…
Add table
Reference in a new issue