PPU work
This commit is contained in:
parent
630db30484
commit
177d53e8bf
12 changed files with 314 additions and 49 deletions
|
@ -11,18 +11,31 @@ class BaseMapper : public IMemoryHandler
|
|||
vector<MemoryBank> _romBanks;
|
||||
vector<MemoryBank> _vromBanks;
|
||||
|
||||
virtual void InitMapper() = 0;
|
||||
|
||||
public:
|
||||
void Initialize(NESHeader header, vector<MemoryBank> romBanks, vector<MemoryBank> vromBanks)
|
||||
{
|
||||
_header = header;
|
||||
_romBanks = romBanks;
|
||||
_vromBanks = vromBanks;
|
||||
|
||||
InitMapper();
|
||||
}
|
||||
};
|
||||
|
||||
class DefaultMapper : public BaseMapper
|
||||
{
|
||||
vector<MemoryBank*> _mappedRomBanks;
|
||||
private:
|
||||
void InitMapper()
|
||||
{
|
||||
if(_romBanks.size() == 1) {
|
||||
_mappedRomBanks = { &_romBanks[0], &_romBanks[0] };
|
||||
} else {
|
||||
_mappedRomBanks = { &_romBanks[0], &_romBanks[1] };
|
||||
}
|
||||
}
|
||||
|
||||
public:
|
||||
std::array<int, 2> GetIOAddresses()
|
||||
|
@ -32,19 +45,19 @@ class DefaultMapper : public BaseMapper
|
|||
|
||||
uint8_t MemoryRead(uint16_t addr)
|
||||
{
|
||||
return _romBanks[(addr >> 14) & 0x01][addr & 0x3FFF];
|
||||
return (*_mappedRomBanks[(addr >> 14) & 0x01])[addr & 0x3FFF];
|
||||
}
|
||||
|
||||
void MemoryWrite(uint16_t addr, uint8_t value)
|
||||
{
|
||||
_romBanks[(addr >> 14) & 0x01][addr & 0x3FFF] = value;
|
||||
(*_mappedRomBanks[(addr >> 14) & 0x01])[addr & 0x3FFF] = value;
|
||||
}
|
||||
};
|
||||
|
||||
class MapperFactory
|
||||
{
|
||||
public:
|
||||
static shared_ptr<BaseMapper> InitializeFromFile(char *filename)
|
||||
static shared_ptr<BaseMapper> InitializeFromFile(string filename)
|
||||
{
|
||||
ROMLoader loader(filename);
|
||||
|
||||
|
|
29
Core/CPU.cpp
29
Core/CPU.cpp
|
@ -2,6 +2,8 @@
|
|||
#include "CPU.h"
|
||||
#include "Timer.h"
|
||||
|
||||
uint64_t CPU::CycleCount = 0;
|
||||
|
||||
CPU::CPU(MemoryManager *memoryManager) : _memoryManager(memoryManager)
|
||||
{
|
||||
Reset();
|
||||
|
@ -50,6 +52,7 @@ CPU::CPU(MemoryManager *memoryManager) : _memoryManager(memoryManager)
|
|||
|
||||
void CPU::Reset()
|
||||
{
|
||||
CPU::CycleCount = 0;
|
||||
_state.A = 0;
|
||||
_state.PC = MemoryReadWord(0xFFFC);
|
||||
_state.SP = 0xFF;
|
||||
|
@ -60,25 +63,11 @@ void CPU::Reset()
|
|||
|
||||
void CPU::Exec()
|
||||
{
|
||||
uint32_t cycleCount = 0;
|
||||
|
||||
Timer timer;
|
||||
while(true) {
|
||||
_currentPC = _state.PC;
|
||||
uint8_t opCode = ReadByte();
|
||||
if(_opTable[opCode] != nullptr) {
|
||||
(this->*_opTable[opCode])();
|
||||
cycleCount += this->_cycles[opCode];
|
||||
//std::cout << "OPCode: " << std::hex << (short)opCode << " PC:" << _currentPC << std::endl;
|
||||
} else {
|
||||
//std::cout << "Invalid opcode: PC:" << _currentPC << std::endl;
|
||||
throw std::exception("Invalid opcode");
|
||||
}
|
||||
|
||||
if(cycleCount >= 200000000) {
|
||||
break;
|
||||
}
|
||||
uint8_t opCode = ReadByte();
|
||||
if(_opTable[opCode] != nullptr) {
|
||||
(this->*_opTable[opCode])();
|
||||
CPU::CycleCount += this->_cycles[opCode];
|
||||
} else {
|
||||
//throw std::exception("Invalid opcode");
|
||||
}
|
||||
std::wstring result = L"Frequency: " + std::to_wstring((int)(cycleCount / timer.GetElapsedMS() * 1000 / 1000000)) + L"mhz\n";
|
||||
OutputDebugString(result.c_str());
|
||||
}
|
||||
|
|
|
@ -40,6 +40,8 @@ private:
|
|||
|
||||
MemoryManager *_memoryManager = nullptr;
|
||||
|
||||
static uint64_t CycleCount;
|
||||
|
||||
uint16_t _currentPC = 0;
|
||||
uint8_t _cyclePenalty = 0;
|
||||
|
||||
|
@ -599,6 +601,13 @@ private:
|
|||
|
||||
public:
|
||||
CPU(MemoryManager *memoryManager);
|
||||
static uint64_t GetCycleCount() {
|
||||
return CPU::CycleCount;
|
||||
}
|
||||
void Reset();
|
||||
void Exec();
|
||||
State GetState()
|
||||
{
|
||||
return _state;
|
||||
}
|
||||
};
|
|
@ -1,7 +1,8 @@
|
|||
#include "stdafx.h"
|
||||
#include "Console.h"
|
||||
#include "Timer.h"
|
||||
|
||||
Console::Console(char* filename)
|
||||
Console::Console(string filename)
|
||||
{
|
||||
_mapper = MapperFactory::InitializeFromFile(filename);
|
||||
_memoryManager.RegisterIODevice(_mapper.get());
|
||||
|
@ -21,11 +22,61 @@ void Console::Reset()
|
|||
|
||||
void Console::Run()
|
||||
{
|
||||
_cpu->Exec();
|
||||
while(true) {
|
||||
_cpu->Exec();
|
||||
_ppu.Exec();
|
||||
}
|
||||
}
|
||||
|
||||
void Console::RunBenchmark()
|
||||
void Console::RunTest(bool callback(Console*))
|
||||
{
|
||||
Console console("mario.nes");
|
||||
console.Run();
|
||||
while(true) {
|
||||
_cpu->Exec();
|
||||
_ppu.Exec();
|
||||
|
||||
if(callback(this)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Console::RunTests()
|
||||
{
|
||||
/*Console *console = new Console("mario.nes");
|
||||
console->Run();
|
||||
delete console;*/
|
||||
|
||||
vector<std::string> testROMs = { { "nestest", "01-basics", "02-implied", "03-immediate", "04-zero_page", "05-zp_xy", "06-absolute", "07-abs_xy", "08-ind_x", "09-ind_y", "10-branches", "11-stack", "12-jmp_jsr", "13-rts", "14-rti", "15-brk", "16-special" } };
|
||||
|
||||
for(string testROM : testROMs) {
|
||||
Console *console = new Console(string("TestSuite/") + testROM + ".nes");
|
||||
if(testROM == "nestest") {
|
||||
console->RunTest([] (Console *console) {
|
||||
auto state = console->_cpu->GetState();
|
||||
std::stringstream ss;
|
||||
ss << std::hex << (short)state.PC << " A:" << (short)state.A << " X:" << (short)state.X << " Y:" << (short)state.Y << std::endl;
|
||||
OutputDebugStringA(ss.str().c_str());
|
||||
return false;
|
||||
});
|
||||
} else {
|
||||
console->RunTest([] (Console *console) {
|
||||
static bool testStarted = false;
|
||||
uint8_t testStatus = console->_memoryManager.Read(0x6000);
|
||||
if(testStatus == 0x81) {
|
||||
//need reset
|
||||
throw std::exception("reset needed");
|
||||
} else if(testStatus == 0x80) {
|
||||
testStarted = true;
|
||||
} else if(testStatus < 0x80 && testStarted) {
|
||||
char *result = console->_memoryManager.GetTestResult();
|
||||
OutputDebugStringA(result);
|
||||
delete[] result;
|
||||
testStarted = false;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
});
|
||||
}
|
||||
delete console;
|
||||
}
|
||||
}
|
|
@ -13,9 +13,10 @@ class Console
|
|||
MemoryManager _memoryManager;
|
||||
|
||||
public:
|
||||
Console(char* filename);
|
||||
Console(string filename);
|
||||
~Console();
|
||||
void Run();
|
||||
void RunTest(bool callback(Console*));
|
||||
void Reset();
|
||||
static void RunBenchmark();
|
||||
static void RunTests();
|
||||
};
|
||||
|
|
|
@ -21,10 +21,12 @@ MemoryManager::MemoryManager()
|
|||
{
|
||||
_internalRAM = new uint8_t[InternalRAMSize];
|
||||
_SRAM = new uint8_t[SRAMSize];
|
||||
ZeroMemory(_SRAM, SRAMSize);
|
||||
_expansionRAM = new uint8_t[0x2000];
|
||||
ZeroMemory(_internalRAM, InternalRAMSize);
|
||||
ZeroMemory(_SRAM, SRAMSize);
|
||||
ZeroMemory(_expansionRAM, 0x2000);
|
||||
|
||||
for(int i = 0; i < 0xFFFF; i++) {
|
||||
for(int i = 0; i <= 0xFFFF; i++) {
|
||||
_registerHandlers.push_back(nullptr);
|
||||
}
|
||||
}
|
||||
|
@ -33,6 +35,7 @@ MemoryManager::~MemoryManager()
|
|||
{
|
||||
delete[] _internalRAM;
|
||||
delete[] _SRAM;
|
||||
delete[] _expansionRAM;
|
||||
}
|
||||
|
||||
void MemoryManager::RegisterIODevice(IMemoryHandler *handler)
|
||||
|
@ -50,10 +53,9 @@ uint8_t MemoryManager::Read(uint16_t addr)
|
|||
} else if(addr <= 0x401F) {
|
||||
return ReadRegister(addr);
|
||||
} else if(addr <= 0x5FFF) {
|
||||
throw std::exception("Not implemented yet");
|
||||
//return ReadExpansionROM();
|
||||
return _expansionRAM[addr & 0x1FFF];
|
||||
} else if(addr <= 0x7FFF) {
|
||||
return _SRAM[addr];
|
||||
return _SRAM[addr & 0x1FFF];
|
||||
} else {
|
||||
return ReadRegister(addr);
|
||||
}
|
||||
|
@ -61,15 +63,14 @@ uint8_t MemoryManager::Read(uint16_t addr)
|
|||
|
||||
void MemoryManager::Write(uint16_t addr, uint8_t value)
|
||||
{
|
||||
if(addr <= 0x1FFFF) {
|
||||
if(addr <= 0x1FFF) {
|
||||
_internalRAM[addr & 0x07FF] = value;
|
||||
} else if(addr <= 0x401F) {
|
||||
WriteRegister(addr, value);
|
||||
} else if(addr <= 0x5FFF) {
|
||||
throw std::exception("Not implemented yet");
|
||||
//return ReadExpansionROM();
|
||||
_expansionRAM[addr & 0x1FFF] = value;
|
||||
} else if(addr <= 0x7FFF) {
|
||||
_SRAM[addr] = value;
|
||||
_SRAM[addr & 0x1FFF] = value;
|
||||
} else {
|
||||
WriteRegister(addr, value);
|
||||
}
|
||||
|
|
|
@ -7,9 +7,10 @@ class MemoryManager
|
|||
{
|
||||
private:
|
||||
const int InternalRAMSize = 0x800;
|
||||
const int SRAMSize = 0x800;
|
||||
const int SRAMSize = 0x2000;
|
||||
|
||||
uint8_t *_internalRAM;
|
||||
uint8_t *_expansionRAM;
|
||||
uint8_t *_SRAM;
|
||||
|
||||
vector<IMemoryHandler*> _registerHandlers;
|
||||
|
@ -26,5 +27,14 @@ class MemoryManager
|
|||
uint8_t Read(uint16_t addr);
|
||||
void Write(uint16_t addr, uint8_t value);
|
||||
uint16_t ReadWord(uint16_t addr);
|
||||
|
||||
char* GetTestResult()
|
||||
{
|
||||
char *buffer = new char[0x2000];
|
||||
for(int i = 0; i < 0x1000; i++) {
|
||||
buffer[i] = Read(0x6004 + i);
|
||||
}
|
||||
return buffer;
|
||||
}
|
||||
};
|
||||
|
||||
|
|
149
Core/PPU.cpp
149
Core/PPU.cpp
|
@ -1,10 +1,22 @@
|
|||
#include "stdafx.h"
|
||||
#include "PPU.h"
|
||||
#include "CPU.h"
|
||||
|
||||
PPU::PPU()
|
||||
{
|
||||
_state = {};
|
||||
_state.Status |= 0xFF;
|
||||
|
||||
_outputBuffer = new uint8_t[256 * 240 * 4];
|
||||
}
|
||||
|
||||
PPU::~PPU()
|
||||
{
|
||||
delete[] _outputBuffer;
|
||||
}
|
||||
|
||||
bool PPU::CheckFlag(PPUControlFlags flag)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
uint8_t PPU::MemoryRead(uint16_t addr)
|
||||
|
@ -13,18 +25,149 @@ uint8_t PPU::MemoryRead(uint16_t addr)
|
|||
case PPURegisters::Control:
|
||||
return (uint8_t)_state.Control;
|
||||
case PPURegisters::Control2:
|
||||
return (uint8_t)(_state.Control >> 8);
|
||||
return (uint8_t)_state.Control2;
|
||||
case PPURegisters::Status:
|
||||
UpdateStatusFlag();
|
||||
return _state.Status;
|
||||
case PPURegisters::SpriteData:
|
||||
return _spriteRAM[_state.SpriteRamAddr];
|
||||
case PPURegisters::VideoMemoryData:
|
||||
return _videoRAM[_state.VideoRamAddr];
|
||||
uint8_t returnValue = _memoryReadBuffer;
|
||||
_memoryReadBuffer = _videoRAM[_state.VideoRamAddr];
|
||||
return returnValue;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void PPU::MemoryWrite(uint16_t addr, uint8_t value)
|
||||
{
|
||||
static bool videoLow = true;
|
||||
|
||||
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] = value;
|
||||
break;
|
||||
case PPURegisters::ScrollOffsets:
|
||||
break;
|
||||
case PPURegisters::VideoMemoryAddr:
|
||||
if(videoLow) {
|
||||
_state.VideoRamAddr &= 0xFF00;
|
||||
_state.VideoRamAddr |= value;
|
||||
videoLow = false;
|
||||
} else {
|
||||
_state.VideoRamAddr |= value<<8;
|
||||
videoLow = true;
|
||||
}
|
||||
break;
|
||||
case PPURegisters::VideoMemoryData:
|
||||
_videoRAM[_state.VideoRamAddr] = value;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
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) |
|
||||
((uint8_t)_statusFlags.VerticalBlank << 7));
|
||||
}
|
||||
|
||||
void PPU::Exec()
|
||||
{
|
||||
uint64_t equivalentCycleCount = CPU::GetCycleCount() * 3;
|
||||
while(_cycleCount < equivalentCycleCount) {
|
||||
if(_scanline == -1) {
|
||||
if(_cycle == 1) {
|
||||
_statusFlags.SpriteOverflow = false;
|
||||
_statusFlags.Sprite0Hit = false;
|
||||
} else if(_cycle == 304) {
|
||||
// Copy scroll latch into VRAMADDR register
|
||||
if(_flags.BackgroundEnabled || _flags.SpritesEnabled) {
|
||||
//p->registers.vramAddress = p->registers.vramLatch;
|
||||
}
|
||||
}
|
||||
} 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);
|
||||
}
|
||||
}
|
||||
} else if(_scanline == 240) {
|
||||
if(_cycle == 1) {
|
||||
if(!_suppressVBlank) {
|
||||
// We're in VBlank
|
||||
Ppu_setStatus(p, STATUS_VBLANK_STARTED);
|
||||
p->cycleCount = 0;
|
||||
}
|
||||
if(_flags.VBlank && !_suppressNMI) {
|
||||
VBlankInterrupt();
|
||||
}
|
||||
//Ppu_raster(p);
|
||||
}
|
||||
} else if(_scanline == 260) {
|
||||
// End of vblank
|
||||
if(_cycle == 1) {
|
||||
// Clear VBlank flag
|
||||
Ppu_clearStatus(p, STATUS_VBLANK_STARTED);
|
||||
_cycleCount = 0;
|
||||
} else if(_cycle == 341) {
|
||||
_scanline = -1;
|
||||
_cycle = 1;
|
||||
_frameCount++;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if(_cycle == 341) {
|
||||
_cycle = 0;
|
||||
_scanline++;
|
||||
}
|
||||
|
||||
_cycle++;
|
||||
_cycleCount++;
|
||||
}
|
||||
}
|
50
Core/PPU.h
50
Core/PPU.h
|
@ -15,9 +15,36 @@ enum PPURegisters
|
|||
VideoMemoryData = 0x07
|
||||
};
|
||||
|
||||
struct PPUControlFlags
|
||||
{
|
||||
uint16_t NameTableAddr;
|
||||
bool VerticalWrite;
|
||||
uint16_t SpritePatternAddr;
|
||||
uint16_t BackgroundPatternAddr;
|
||||
bool LargeSprites;
|
||||
bool VBlank;
|
||||
|
||||
bool Grayscale;
|
||||
bool BackgroundMask;
|
||||
bool SpriteMask;
|
||||
bool BackgroundEnabled;
|
||||
bool SpritesEnabled;
|
||||
bool IntensifyRed;
|
||||
bool IntensifyGreen;
|
||||
bool IntensifyBlue;
|
||||
};
|
||||
|
||||
struct PPUStatusFlags
|
||||
{
|
||||
bool SpriteOverflow;
|
||||
bool Sprite0Hit;
|
||||
bool VerticalBlank;
|
||||
};
|
||||
|
||||
struct PPUState
|
||||
{
|
||||
uint16_t Control;
|
||||
uint8_t Control;
|
||||
uint8_t Control2;
|
||||
uint8_t Status;
|
||||
uint8_t SpriteRamAddr;
|
||||
uint16_t VideoRamAddr;
|
||||
|
@ -27,9 +54,25 @@ class PPU : public IMemoryHandler
|
|||
{
|
||||
private:
|
||||
PPUState _state;
|
||||
uint64_t _cycleCount;
|
||||
|
||||
uint8_t _memoryReadBuffer;
|
||||
uint8_t _spriteRAM[256];
|
||||
uint8_t _videoRAM[16*1024];
|
||||
|
||||
uint8_t *_outputBuffer;
|
||||
|
||||
int16_t _scanline = -1;
|
||||
uint16_t _cycle = 0;
|
||||
|
||||
PPUControlFlags _flags = {};
|
||||
PPUStatusFlags _statusFlags = {};
|
||||
|
||||
void PPU::UpdateStatusFlag();
|
||||
|
||||
void PPU::UpdateFlags();
|
||||
bool PPU::CheckFlag(PPUControlFlags flag);
|
||||
|
||||
PPURegisters GetRegisterID(uint16_t addr)
|
||||
{
|
||||
return (PPURegisters)(addr & 0x07);
|
||||
|
@ -37,7 +80,8 @@ class PPU : public IMemoryHandler
|
|||
|
||||
public:
|
||||
PPU();
|
||||
|
||||
~PPU();
|
||||
|
||||
std::array<int, 2> GetIOAddresses()
|
||||
{
|
||||
return std::array<int, 2> {{ 0x2000, 0x3FFF }};
|
||||
|
@ -45,4 +89,6 @@ class PPU : public IMemoryHandler
|
|||
|
||||
uint8_t MemoryRead(uint16_t addr);
|
||||
void MemoryWrite(uint16_t addr, uint8_t value);
|
||||
|
||||
void Exec();
|
||||
};
|
|
@ -30,7 +30,7 @@ class ROMLoader
|
|||
vector<MemoryBank> _vromBanks;
|
||||
|
||||
public:
|
||||
ROMLoader(const char* filename)
|
||||
ROMLoader(string filename)
|
||||
{
|
||||
_romBanks.clear();
|
||||
_vromBanks.clear();
|
||||
|
@ -38,7 +38,7 @@ class ROMLoader
|
|||
ifstream romFile(filename, ios::in | ios::binary);
|
||||
|
||||
if(!romFile) {
|
||||
return;
|
||||
throw std::exception("File could not be read");
|
||||
}
|
||||
|
||||
romFile.read((char*)&_header, sizeof(NESHeader));
|
||||
|
|
|
@ -20,6 +20,7 @@
|
|||
#include <thread>
|
||||
#include <vector>
|
||||
#include <array>
|
||||
#include <sstream>
|
||||
|
||||
#include <windows.h>
|
||||
|
||||
|
@ -28,5 +29,6 @@ using std::shared_ptr;
|
|||
using std::unique_ptr;
|
||||
using std::ios;
|
||||
using std::ifstream;
|
||||
using std::string;
|
||||
|
||||
// TODO: reference additional headers your program requires here
|
||||
|
|
|
@ -41,7 +41,7 @@ namespace NES
|
|||
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>(50));
|
||||
}
|
||||
|
||||
return (int)msg.wParam;
|
||||
|
@ -106,7 +106,7 @@ namespace NES
|
|||
|
||||
void MainWindow::RunBenchmark()
|
||||
{
|
||||
std::thread bmThread(&Console::RunBenchmark);
|
||||
std::thread bmThread(&Console::RunTests);
|
||||
bmThread.detach();
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue