Adding configurable light states
This commit is contained in:
parent
9eccd5084b
commit
0afe500701
|
@ -154,6 +154,9 @@ class EmuInstance
|
|||
virtual void deserializeLiteState(const uint8_t *state) = 0;
|
||||
virtual size_t getFullStateSize() const = 0;
|
||||
virtual size_t getLiteStateSize() const = 0;
|
||||
virtual void enableLiteStateBlock(const std::string& block) = 0;
|
||||
virtual void disableLiteStateBlock(const std::string& block) = 0;
|
||||
|
||||
virtual void doSoftReset() = 0;
|
||||
virtual void doHardReset() = 0;
|
||||
virtual std::string getCoreName() const = 0;
|
||||
|
|
|
@ -49,6 +49,9 @@ class QuickNESInstance : public EmuInstance
|
|||
void deserializeLiteState(const uint8_t *state) override { deserializeFullState(state); }
|
||||
inline size_t getLiteStateSize() const override { return getFullStateSize(); }
|
||||
|
||||
void enableLiteStateBlock(const std::string& block) override {};
|
||||
void disableLiteStateBlock(const std::string& block) override {};
|
||||
|
||||
void serializeFullState(uint8_t *state) const override
|
||||
{
|
||||
Mem_Writer w(state, _fullStateSize, 0);
|
||||
|
|
|
@ -80,6 +80,20 @@ class Core : private Cpu
|
|||
typedef Cpu cpu;
|
||||
|
||||
public:
|
||||
|
||||
// Flags for lite state storage
|
||||
bool TIMEBlockEnabled = true;
|
||||
bool CPURBlockEnabled = true;
|
||||
bool PPURBlockEnabled = true;
|
||||
bool APURBlockEnabled = true;
|
||||
bool CTRLBlockEnabled = true;
|
||||
bool MAPRBlockEnabled = true;
|
||||
bool LRAMBlockEnabled = true;
|
||||
bool SPRTBlockEnabled = true;
|
||||
bool NTABBlockEnabled = true;
|
||||
bool CHRRBlockEnabled = true;
|
||||
bool SRAMBlockEnabled = true;
|
||||
|
||||
Core() : ppu(this)
|
||||
{
|
||||
cart = NULL;
|
||||
|
@ -412,12 +426,54 @@ class Core : private Cpu
|
|||
return pos; // Bytes read
|
||||
}
|
||||
|
||||
void enableLiteStateBlock(const std::string& block)
|
||||
{
|
||||
bool recognizedBlock = false;
|
||||
|
||||
if (block == "TIME") { TIMEBlockEnabled = true; recognizedBlock = true; }
|
||||
if (block == "CPUR") { CPURBlockEnabled = true; recognizedBlock = true; }
|
||||
if (block == "PPUR") { PPURBlockEnabled = true; recognizedBlock = true; }
|
||||
if (block == "APUR") { APURBlockEnabled = true; recognizedBlock = true; }
|
||||
if (block == "CTRL") { CTRLBlockEnabled = true; recognizedBlock = true; }
|
||||
if (block == "MAPR") { MAPRBlockEnabled = true; recognizedBlock = true; }
|
||||
if (block == "LRAM") { LRAMBlockEnabled = true; recognizedBlock = true; }
|
||||
if (block == "SPRT") { SPRTBlockEnabled = true; recognizedBlock = true; }
|
||||
if (block == "NTAB") { NTABBlockEnabled = true; recognizedBlock = true; }
|
||||
if (block == "CHRR") { CHRRBlockEnabled = true; recognizedBlock = true; }
|
||||
if (block == "SRAM") { SRAMBlockEnabled = true; recognizedBlock = true; }
|
||||
|
||||
if (recognizedBlock == false) { fprintf(stderr, "Unrecognized block type: %s\n", block.c_str()); exit(-1);}
|
||||
};
|
||||
|
||||
|
||||
void disableLiteStateBlock(const std::string& block)
|
||||
{
|
||||
bool recognizedBlock = false;
|
||||
|
||||
if (block == "TIME") { TIMEBlockEnabled = false; recognizedBlock = true; }
|
||||
if (block == "CPUR") { CPURBlockEnabled = false; recognizedBlock = true; }
|
||||
if (block == "PPUR") { PPURBlockEnabled = false; recognizedBlock = true; }
|
||||
if (block == "APUR") { APURBlockEnabled = false; recognizedBlock = true; }
|
||||
if (block == "CTRL") { CTRLBlockEnabled = false; recognizedBlock = true; }
|
||||
if (block == "MAPR") { MAPRBlockEnabled = false; recognizedBlock = true; }
|
||||
if (block == "LRAM") { LRAMBlockEnabled = false; recognizedBlock = true; }
|
||||
if (block == "SPRT") { SPRTBlockEnabled = false; recognizedBlock = true; }
|
||||
if (block == "NTAB") { NTABBlockEnabled = false; recognizedBlock = true; }
|
||||
if (block == "CHRR") { CHRRBlockEnabled = false; recognizedBlock = true; }
|
||||
if (block == "SRAM") { SRAMBlockEnabled = false; recognizedBlock = true; }
|
||||
|
||||
if (recognizedBlock == false) { fprintf(stderr, "Unrecognized block type: %s\n", block.c_str()); exit(-1);}
|
||||
};
|
||||
|
||||
|
||||
size_t serializeLiteState(uint8_t *buffer) const
|
||||
{
|
||||
size_t pos = 0;
|
||||
uint32_t blockSize = 0;
|
||||
void *dataSource;
|
||||
|
||||
if (TIMEBlockEnabled == true)
|
||||
{
|
||||
nes_state_lite_t state;
|
||||
state.timestamp = nes.timestamp;
|
||||
state.frame_count = (uint8_t)nes.frame_count;
|
||||
|
@ -426,50 +482,77 @@ size_t serializeLiteState(uint8_t *buffer) const
|
|||
dataSource = (void *)&state;
|
||||
if (buffer != nullptr) memcpy(&buffer[pos], dataSource, blockSize);
|
||||
pos += blockSize;
|
||||
}
|
||||
|
||||
if (CPURBlockEnabled == true)
|
||||
{
|
||||
blockSize = sizeof(cpu::registers_t);
|
||||
dataSource = (void *)&r;
|
||||
if (buffer != nullptr) memcpy(&buffer[pos], dataSource, blockSize);
|
||||
pos += blockSize;
|
||||
}
|
||||
|
||||
if (PPURBlockEnabled == true)
|
||||
{
|
||||
blockSize = sizeof(ppu_state_t);
|
||||
dataSource = (void *)&ppu;
|
||||
if (buffer != nullptr) memcpy(&buffer[pos], dataSource, blockSize);
|
||||
pos += blockSize;
|
||||
}
|
||||
|
||||
if (APURBlockEnabled == true)
|
||||
{
|
||||
Apu::apu_state_t apuState;
|
||||
impl->apu.save_state(&apuState);
|
||||
blockSize = sizeof(Apu::apu_state_t);
|
||||
if (buffer != nullptr) memcpy(&buffer[pos], &apuState, blockSize);
|
||||
pos += blockSize;
|
||||
}
|
||||
|
||||
if (CTRLBlockEnabled == true)
|
||||
{
|
||||
blockSize = sizeof(joypad_state_t);
|
||||
dataSource = (void *)&joypad;
|
||||
if (buffer != nullptr) memcpy(&buffer[pos], dataSource, blockSize);
|
||||
pos += blockSize;
|
||||
}
|
||||
|
||||
if (MAPRBlockEnabled == true)
|
||||
{
|
||||
blockSize = mapper->state_size;
|
||||
dataSource = (void *)mapper->state;
|
||||
if (buffer != nullptr) memcpy(&buffer[pos], dataSource, blockSize);
|
||||
pos += blockSize;
|
||||
}
|
||||
|
||||
if (LRAMBlockEnabled == true)
|
||||
{
|
||||
blockSize = low_ram_size;
|
||||
dataSource = (void *)low_mem;
|
||||
if (buffer != nullptr) memcpy(&buffer[pos], dataSource, blockSize);
|
||||
pos += blockSize;
|
||||
}
|
||||
|
||||
if (SPRTBlockEnabled == true)
|
||||
{
|
||||
blockSize = Ppu::spr_ram_size;
|
||||
dataSource = (void *)ppu.spr_ram;
|
||||
if (buffer != nullptr) memcpy(&buffer[pos], dataSource, blockSize);
|
||||
pos += blockSize;
|
||||
}
|
||||
|
||||
if (NTABBlockEnabled == true)
|
||||
{
|
||||
size_t nametable_size = 0x800;
|
||||
if (ppu.nt_banks[3] >= &ppu.impl->nt_ram[0xC00]) nametable_size = 0x1000;
|
||||
blockSize = nametable_size;
|
||||
dataSource = (void *)ppu.impl->nt_ram;
|
||||
if (buffer != nullptr) memcpy(&buffer[pos], dataSource, blockSize);
|
||||
pos += blockSize;
|
||||
}
|
||||
|
||||
if (CHRRBlockEnabled == true)
|
||||
{
|
||||
if (ppu.chr_is_writable)
|
||||
{
|
||||
blockSize = ppu.chr_size;
|
||||
|
@ -477,7 +560,10 @@ size_t serializeLiteState(uint8_t *buffer) const
|
|||
if (buffer != nullptr) memcpy(&buffer[pos], dataSource, blockSize);
|
||||
pos += blockSize;
|
||||
}
|
||||
}
|
||||
|
||||
if (SRAMBlockEnabled == true)
|
||||
{
|
||||
if (sram_present)
|
||||
{
|
||||
blockSize = impl->sram_size;
|
||||
|
@ -485,6 +571,7 @@ size_t serializeLiteState(uint8_t *buffer) const
|
|||
if (buffer != nullptr) memcpy(&buffer[pos], dataSource, blockSize);
|
||||
pos += blockSize;
|
||||
}
|
||||
}
|
||||
|
||||
return pos; // Bytes written
|
||||
}
|
||||
|
@ -499,6 +586,8 @@ size_t serializeLiteState(uint8_t *buffer) const
|
|||
uint32_t blockSize = 0;
|
||||
|
||||
// TIME Block
|
||||
if (TIMEBlockEnabled == true)
|
||||
{
|
||||
nes_state_lite_t nesState;
|
||||
blockSize = sizeof(nes_state_lite_t);
|
||||
memcpy(&nesState, &buffer[pos], blockSize);
|
||||
|
@ -506,54 +595,81 @@ size_t serializeLiteState(uint8_t *buffer) const
|
|||
nes.frame_count = nesState.frame_count;
|
||||
nes.timestamp = nesState.timestamp;
|
||||
nes.timestamp /= 5;
|
||||
}
|
||||
|
||||
// CPUR Block
|
||||
if (CPURBlockEnabled == true)
|
||||
{
|
||||
blockSize = sizeof(cpu::registers_t);
|
||||
memcpy((void *)&r, &buffer[pos], blockSize);
|
||||
pos += blockSize;
|
||||
}
|
||||
|
||||
// PPUR Block
|
||||
if (PPURBlockEnabled == true)
|
||||
{
|
||||
blockSize = sizeof(ppu_state_t);
|
||||
memcpy((void *)&ppu, &buffer[pos], blockSize);
|
||||
pos += blockSize;
|
||||
}
|
||||
|
||||
// APUR Block
|
||||
if (APURBlockEnabled == true)
|
||||
{
|
||||
Apu::apu_state_t apuState;
|
||||
blockSize = sizeof(Apu::apu_state_t);
|
||||
memcpy(&apuState, &buffer[pos], blockSize);
|
||||
pos += blockSize;
|
||||
impl->apu.load_state(apuState);
|
||||
impl->apu.end_frame(-(int)nes.timestamp / ppu_overclock);
|
||||
}
|
||||
|
||||
// CTRL Block
|
||||
if (CTRLBlockEnabled == true)
|
||||
{
|
||||
blockSize = sizeof(joypad_state_t);
|
||||
memcpy((void *)&joypad, &buffer[pos], blockSize);
|
||||
pos += blockSize;
|
||||
}
|
||||
|
||||
// MAPR Block
|
||||
if (MAPRBlockEnabled == true)
|
||||
{
|
||||
mapper->default_reset_state();
|
||||
blockSize = mapper->state_size;
|
||||
memcpy((void *)mapper->state, &buffer[pos], blockSize);
|
||||
pos += blockSize;
|
||||
mapper->apply_mapping();
|
||||
}
|
||||
|
||||
// LRAM Block
|
||||
if (LRAMBlockEnabled == true)
|
||||
{
|
||||
blockSize = low_ram_size;
|
||||
memcpy((void *)low_mem, &buffer[pos], blockSize);
|
||||
pos += blockSize;
|
||||
}
|
||||
|
||||
// SPRT Block
|
||||
if (SPRTBlockEnabled == true)
|
||||
{
|
||||
blockSize = Ppu::spr_ram_size;
|
||||
memcpy((void *)ppu.spr_ram, &buffer[pos], blockSize);
|
||||
pos += blockSize;
|
||||
}
|
||||
|
||||
// NTAB Block
|
||||
if (NTABBlockEnabled == true)
|
||||
{
|
||||
size_t nametable_size = 0x800;
|
||||
if (ppu.nt_banks[3] >= &ppu.impl->nt_ram[0xC00]) nametable_size = 0x1000;
|
||||
blockSize = nametable_size;
|
||||
memcpy((void *)ppu.impl->nt_ram, &buffer[pos], blockSize);
|
||||
pos += blockSize;
|
||||
}
|
||||
|
||||
if (CHRRBlockEnabled == true)
|
||||
{
|
||||
if (ppu.chr_is_writable)
|
||||
{
|
||||
// CHRR Block
|
||||
|
@ -561,15 +677,20 @@ size_t serializeLiteState(uint8_t *buffer) const
|
|||
memcpy((void *)ppu.impl->chr_ram, &buffer[pos], blockSize);
|
||||
pos += blockSize;
|
||||
}
|
||||
}
|
||||
|
||||
if (SRAMBlockEnabled == true)
|
||||
{
|
||||
if (sram_present)
|
||||
{
|
||||
// SRAM Block
|
||||
blockSize = impl->sram_size;
|
||||
memcpy((void *)impl->sram, &buffer[pos], blockSize);
|
||||
pos += blockSize;
|
||||
enable_sram(true);
|
||||
}
|
||||
}
|
||||
|
||||
if (sram_present) enable_sram(true);
|
||||
|
||||
return pos; // Bytes read
|
||||
}
|
||||
|
|
|
@ -54,6 +54,9 @@ class Emu
|
|||
size_t getLiteStateSize() const { return emu.serializeLiteState(nullptr); }
|
||||
size_t getFullStateSize() const { return emu.serializeFullState(nullptr); }
|
||||
|
||||
void enableLiteStateBlock(const std::string& block) { emu.enableLiteStateBlock(block); };
|
||||
void disableLiteStateBlock(const std::string& block) { emu.disableLiteStateBlock(block); };
|
||||
|
||||
// Basic emulation
|
||||
|
||||
// Emulate one video frame using joypad1 and joypad2 as input. Afterwards, image
|
||||
|
|
|
@ -45,6 +45,9 @@ class QuickerNESInstance : public EmuInstance
|
|||
size_t getFullStateSize() const override { return _nes->getFullStateSize(); }
|
||||
size_t getLiteStateSize() const override { return _nes->getLiteStateSize(); }
|
||||
|
||||
void enableLiteStateBlock(const std::string& block) override { _nes->enableLiteStateBlock(block); };
|
||||
void disableLiteStateBlock(const std::string& block) override { _nes->disableLiteStateBlock(block); };
|
||||
|
||||
void advanceStateImpl(const inputType controller1, const inputType controller2) override
|
||||
{
|
||||
if (_doRendering == true) _nes->emulate_frame(controller1, controller2);
|
||||
|
|
|
@ -4,6 +4,8 @@
|
|||
#include "utils.hpp"
|
||||
#include <chrono>
|
||||
#include <sstream>
|
||||
#include <vector>
|
||||
#include <string>
|
||||
|
||||
#ifdef _USE_QUICKNES
|
||||
#include "quickNESInstance.hpp"
|
||||
|
@ -76,6 +78,18 @@ int main(int argc, char *argv[])
|
|||
if (scriptJson["Expected ROM SHA1"].is_string() == false) EXIT_WITH_ERROR("Script file 'Expected ROM SHA1' entry is not a string\n");
|
||||
std::string expectedROMSHA1 = scriptJson["Expected ROM SHA1"].get<std::string>();
|
||||
|
||||
// Parsing disabled blocks in lite state serialization
|
||||
std::vector<std::string> liteStateDisabledBlocks;
|
||||
std::string liteStateDisabledBlocksOutput;
|
||||
if (scriptJson.contains("Disable Lite State Blocks") == false) EXIT_WITH_ERROR("Script file missing 'Disable Lite State Blocks' entry\n");
|
||||
if (scriptJson["Disable Lite State Blocks"].is_array() == false) EXIT_WITH_ERROR("Script file 'Disable Lite State Blocks' is not an array\n");
|
||||
for (const auto& entry : scriptJson["Disable Lite State Blocks"])
|
||||
{
|
||||
if (entry.is_string() == false) EXIT_WITH_ERROR("Script file 'Disable Lite State Blocks' entry is not a string\n");
|
||||
liteStateDisabledBlocks.push_back(entry.get<std::string>());
|
||||
liteStateDisabledBlocksOutput += entry.get<std::string>() + std::string(" ");
|
||||
}
|
||||
|
||||
// Creating emulator instance
|
||||
#ifdef _USE_QUICKNES
|
||||
auto e = QuickNESInstance();
|
||||
|
@ -134,6 +148,7 @@ int main(int argc, char *argv[])
|
|||
printf("[] Initial State Hash: 0x%lX%lX\n", initialHash.first, initialHash.second);
|
||||
printf("[] Full State Size: %lu bytes\n", fullStateSize);
|
||||
printf("[] Lite State Size: %lu bytes\n", liteStateSize);
|
||||
printf("[] Lite State Disabled Blocks: [ %s ]\n", liteStateDisabledBlocksOutput.c_str());
|
||||
printf("[] ********** Running Test **********\n");
|
||||
|
||||
fflush(stdout);
|
||||
|
|
|
@ -2,5 +2,6 @@
|
|||
"Rom File": "../roms/Arkanoid (U) [!].nes",
|
||||
"Expected ROM SHA1": "B2B30C4F30DD853C215C17B0C67CFE63D61A3062",
|
||||
"Initial State File": "",
|
||||
"Sequence File": "warpless.sol"
|
||||
"Sequence File": "warpless.sol",
|
||||
"Disable Lite State Blocks": [ ]
|
||||
}
|
||||
|
|
|
@ -15,6 +15,7 @@ subdir('ninjaGaiden2')
|
|||
subdir('ironSword')
|
||||
subdir('solarJetman')
|
||||
subdir('tennis')
|
||||
subdir('metroid')
|
||||
subdir('nigelMansell')
|
||||
subdir('galaga')
|
||||
subdir('saintSeiyaOugonDensetsu')
|
||||
|
|
|
@ -0,0 +1,4 @@
|
|||
game = 'metroid'
|
||||
|
||||
goal = 'playaround'
|
||||
test(goal, bash, workdir : meson.current_source_dir(), timeout: testTimeout, args : [ testCommands, goal + '.test', '--cycleType', 'Full'], suite: [ game, goal ] )
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,6 @@
|
|||
{
|
||||
"Rom File": "../roms/Metroid (U) (PRG0) [!].nes",
|
||||
"Expected ROM SHA1": "ECF39EC5A33E6A6F832F03E8FFC61C5D53F4F90B",
|
||||
"Initial State File": "",
|
||||
"Sequence File": "playaround.sol"
|
||||
}
|
Loading…
Reference in New Issue