Created new functions for serialization and deserialization
This commit is contained in:
parent
17bb8c99d8
commit
4530713b01
17
README.md
17
README.md
|
@ -1,32 +1,33 @@
|
|||
quickerNES
|
||||
============
|
||||
-----------
|
||||
|
||||
quickerNES is an attempt to modernizing and improving the performance of quickNES, the fastest NES emulator in the interwebs (as far as I know). The goals for this project are, in order of importance:
|
||||
quickerNES is an attempt to modernizing and improving the performance of [quickNES](https://github.com/kode54/QuickNES). The goals for this project are, in order of importance:
|
||||
|
||||
- Improve overall emulation performance even more
|
||||
- Improve overall emulation performance for modern (x86) CPUs
|
||||
- Modernize the code base with best programming practices, including CI tests, benchmarks, and coverage analysis
|
||||
- Add support for more mappers, controllers, and features supported by other emulators
|
||||
- Improve accuracy, if possible
|
||||
|
||||
The main aim is to improve the performance of skip (non-rendering, no-audio) frame advances for brute force botting. (See: [JaffarPlus](https://github.com/SergioMartin86/jaffarPlus)). However, if this work might help with homebrew emulation and other people having more fun, then much better!
|
||||
The main aim is to improve the performance of headless re-recording for TASing and botting (See: [JaffarPlus](https://github.com/SergioMartin86/jaffarPlus)) purposes. However, if this work can help regular play emulation, then much better.
|
||||
|
||||
Changes
|
||||
=========
|
||||
--------
|
||||
|
||||
- Optimizations made in the CPU emulation core, including:
|
||||
+ Forced alignment at the start of a page to prevent crossing cache line boundaries
|
||||
+ Simplifying instruction decode
|
||||
+ Simplifying the 6502 CPU instruction fetching and decoding
|
||||
- Minimize compiled code size to reduce pressure on L1i cache
|
||||
- Reduce heap allocations
|
||||
- General code reorganization (make it header only to help compiler optimizations)
|
||||
|
||||
Credits
|
||||
=========
|
||||
---------
|
||||
|
||||
- quickNES was originally by Shay Green (a.k.a. [Blaarg](http://www.slack.net/~ant/)) under the GNU GPLv2 license. The source code is still located [here](https://github.com/kode54/QuickNES)
|
||||
- The code was later improved and maintained by Christopher Snowhill (a.k.a. [kode54](https://kode54.net/))
|
||||
- I could trace further contributions (e.g., new mappers) by retrowertz, CaH4e3, some adaptations from the [FCEUX emulator](https://github.com/TASEmulators/fceux) (see mapper021)
|
||||
- The latest version of the code is maintained by Libretro's community [here](https://github.com/libretro/QuickNES_Core)
|
||||
- For the interactive player, this project uses a modified version of [HeadlessQuickNES (HQN)](https://github.com/Bindernews/HeadlessQuickNes) by Drew (Binder News)
|
||||
- For the interactive player, this project drew some code from [HeadlessQuickNES (HQN)](https://github.com/Bindernews/HeadlessQuickNes) by Drew (Binder News)
|
||||
- We use some of the [NES test rom set](https://github.com/christopherpow/nes-test-roms) made by multiple authors and gathered by Christopher Pow et al.
|
||||
- We also use some movies from the [TASVideos](tasvideos.org) website for testing. These movies are copied into this repository with authorization under the Creative Commons Attribution 2.0 license.
|
||||
|
||||
|
|
|
@ -86,15 +86,13 @@ class EmuInstance
|
|||
}
|
||||
|
||||
inline size_t getStateSize() const { return _stateSize; }
|
||||
inline size_t getLiteStateSize() const { return _liteStateSize; }
|
||||
inline std::string getRomSHA1() const { return _romSHA1String; }
|
||||
|
||||
inline hash_t getStateHash() const
|
||||
{
|
||||
MetroHash128 hash;
|
||||
|
||||
uint8_t stateData[_stateSize];
|
||||
serializeState(stateData);
|
||||
|
||||
hash.Update(getLowMem(), _LOW_MEM_SIZE);
|
||||
hash.Update(getHighMem(), _HIGH_MEM_SIZE);
|
||||
hash.Update(getNametableMem(), _NAMETABLES_MEM_SIZE);
|
||||
|
@ -137,8 +135,11 @@ inline void loadROMFile(const std::string& romFilePath)
|
|||
status = loadROMFileImpl(_romData);
|
||||
if (status == false) EXIT_WITH_ERROR("Could not process ROM file: %s\n", romFilePath.c_str());
|
||||
|
||||
// Detecting state size
|
||||
// Detecting full state size
|
||||
_stateSize = getStateSizeImpl();
|
||||
|
||||
// Detecting lite state size
|
||||
_liteStateSize = getLiteStateSizeImpl();
|
||||
}
|
||||
|
||||
// Virtual functions
|
||||
|
@ -153,16 +154,20 @@ inline void loadROMFile(const std::string& romFilePath)
|
|||
virtual void serializeState(uint8_t* state) const = 0;
|
||||
virtual void deserializeState(const uint8_t* state) = 0;
|
||||
virtual size_t getStateSizeImpl() const = 0;
|
||||
virtual size_t getLiteStateSizeImpl() const { return getStateSizeImpl(); };
|
||||
virtual void doSoftReset() = 0;
|
||||
virtual void doHardReset() = 0;
|
||||
virtual std::string getCoreName() const = 0;
|
||||
virtual void* getInternalEmulatorPointer() const = 0;
|
||||
|
||||
|
||||
protected:
|
||||
|
||||
EmuInstance() = default;
|
||||
|
||||
// Storage for the state
|
||||
// Storage for the light state size
|
||||
size_t _liteStateSize;
|
||||
|
||||
// Storage for the full state size
|
||||
size_t _stateSize;
|
||||
|
||||
// Flag to determine whether to enable/disable rendering
|
||||
|
|
|
@ -16,13 +16,14 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
|
|||
// Nes_Emu 0.7.0
|
||||
|
||||
|
||||
#include <cstdio>
|
||||
#include <string>
|
||||
#include "blargg_common.h"
|
||||
#include "Nes_Apu.h"
|
||||
#include "Nes_Cpu.h"
|
||||
#include "Nes_Ppu.h"
|
||||
#include "Nes_Mapper.h"
|
||||
#include "Nes_State.h"
|
||||
#include <cstdio>
|
||||
|
||||
/*
|
||||
New mapping distribution by Sergio Martin (eien86)
|
||||
|
@ -216,12 +217,321 @@ public:
|
|||
return 0;
|
||||
}
|
||||
|
||||
size_t getLightweightStateSize()
|
||||
size_t getLiteStateSize() const
|
||||
{
|
||||
size_t size = 0;
|
||||
|
||||
size += sizeof(nes_state_t);
|
||||
size += sizeof(registers_t);
|
||||
size += sizeof(ppu_state_t);
|
||||
size += sizeof(Nes_Apu::apu_state_t);
|
||||
size += sizeof(joypad_state_t);
|
||||
size += mapper->state_size;
|
||||
size += low_ram_size;
|
||||
size += Nes_Ppu::spr_ram_size;
|
||||
size_t nametable_size = 0x800;
|
||||
if (ppu.nt_banks [3] >= &ppu.impl->nt_ram [0xC00] ) nametable_size = 0x1000;
|
||||
size += nametable_size;
|
||||
if ( ppu.chr_is_writable ) size += ppu.chr_size;
|
||||
if ( sram_present ) size += impl->sram_size;
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
size_t getStateSize() const
|
||||
{
|
||||
size_t size = 0;
|
||||
|
||||
size += sizeof(char[4]); // NESS Block
|
||||
size += sizeof(uint32_t); // Block Size
|
||||
|
||||
size += sizeof(char[4]); // TIME Block
|
||||
size += sizeof(uint32_t); // Block Size
|
||||
size += sizeof(nes_state_t);
|
||||
|
||||
size += sizeof(char[4]); // CPUR Block
|
||||
size += sizeof(uint32_t); // Block Size
|
||||
size += sizeof(registers_t);
|
||||
|
||||
size += sizeof(char[4]); // PPUR Block
|
||||
size += sizeof(uint32_t); // Block Size
|
||||
size += sizeof(ppu_state_t);
|
||||
|
||||
size += sizeof(char[4]); // APUR Block
|
||||
size += sizeof(uint32_t); // Block Size
|
||||
size += sizeof(Nes_Apu::apu_state_t);
|
||||
|
||||
size += sizeof(char[4]); // CTRL Block
|
||||
size += sizeof(uint32_t); // Block Size
|
||||
size += sizeof(joypad_state_t);
|
||||
|
||||
size += sizeof(char[4]); // MAPR Block
|
||||
size += sizeof(uint32_t); // Block Size
|
||||
size += mapper->state_size;
|
||||
|
||||
size += sizeof(char[4]); // LRAM Block
|
||||
size += sizeof(uint32_t); // Block Size
|
||||
size += low_ram_size;
|
||||
|
||||
size += sizeof(char[4]); // SPRT Block
|
||||
size += sizeof(uint32_t); // Block Size
|
||||
size += Nes_Ppu::spr_ram_size;
|
||||
|
||||
size += sizeof(char[4]); // NTAB Block
|
||||
size += sizeof(uint32_t); // Block Size
|
||||
size_t nametable_size = 0x800;
|
||||
if (ppu.nt_banks [3] >= &ppu.impl->nt_ram [0xC00] ) nametable_size = 0x1000;
|
||||
size += nametable_size;
|
||||
|
||||
if ( ppu.chr_is_writable )
|
||||
{
|
||||
size += sizeof(char[4]); // CHRR Block
|
||||
size += sizeof(uint32_t); // Block Size
|
||||
size += ppu.chr_size;
|
||||
}
|
||||
|
||||
if ( sram_present )
|
||||
{
|
||||
size += sizeof(char[4]); // SRAM Block
|
||||
size += sizeof(uint32_t); // Block Size
|
||||
size += impl->sram_size;
|
||||
}
|
||||
|
||||
size += sizeof(char[4]); // gend Block
|
||||
size += sizeof(uint32_t); // Block Size
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
size_t serializeState(uint8_t* buffer) const
|
||||
{
|
||||
size_t pos = 0;
|
||||
std::string headerCode;
|
||||
const uint32_t headerSize = sizeof(char) * 4;
|
||||
uint32_t blockSize = 0;
|
||||
void* dataSource;
|
||||
|
||||
headerCode = "NESS"; // NESS Block
|
||||
blockSize = 0xFFFFFFFF;
|
||||
memcpy(&buffer[pos], headerCode.data(), headerSize); pos += headerSize;
|
||||
memcpy(&buffer[pos], &blockSize, headerSize); pos += headerSize;
|
||||
|
||||
headerCode = "TIME"; // TIME Block
|
||||
nes_state_t state = nes;
|
||||
state.timestamp *= 5;
|
||||
blockSize = sizeof(nes_state_t);
|
||||
dataSource = (void*) &state;
|
||||
memcpy(&buffer[pos], headerCode.data(), headerSize); pos += headerSize;
|
||||
memcpy(&buffer[pos], &blockSize, headerSize); pos += headerSize;
|
||||
memcpy(&buffer[pos], dataSource, blockSize); pos += blockSize;
|
||||
|
||||
headerCode = "CPUR"; // CPUR Block
|
||||
cpu_state_t s;
|
||||
memset( &s, 0, sizeof s );
|
||||
s.pc = r.pc;
|
||||
s.s = r.sp;
|
||||
s.a = r.a;
|
||||
s.x = r.x;
|
||||
s.y = r.y;
|
||||
s.p = r.status;
|
||||
blockSize = sizeof(cpu_state_t);
|
||||
dataSource = (void*) &s;
|
||||
memcpy(&buffer[pos], headerCode.data(), headerSize); pos += headerSize;
|
||||
memcpy(&buffer[pos], &blockSize, headerSize); pos += headerSize;
|
||||
memcpy(&buffer[pos], dataSource, blockSize); pos += blockSize;
|
||||
|
||||
headerCode = "PPUR"; // PPUR Block
|
||||
blockSize = sizeof(ppu_state_t);
|
||||
dataSource = (void*) &ppu;
|
||||
memcpy(&buffer[pos], headerCode.data(), headerSize); pos += headerSize;
|
||||
memcpy(&buffer[pos], &blockSize, headerSize); pos += headerSize;
|
||||
memcpy(&buffer[pos], dataSource, blockSize); pos += blockSize;
|
||||
|
||||
headerCode = "APUR"; // APUR Block
|
||||
Nes_Apu::apu_state_t apuState;
|
||||
impl->apu.save_state(&apuState);
|
||||
blockSize = sizeof(Nes_Apu::apu_state_t);
|
||||
memcpy(&buffer[pos], headerCode.data(), headerSize); pos += headerSize;
|
||||
memcpy(&buffer[pos], &blockSize, headerSize); pos += headerSize;
|
||||
memcpy(&buffer[pos], &apuState, blockSize); pos += blockSize;
|
||||
|
||||
headerCode = "CTRL"; // CTRL Block
|
||||
blockSize = sizeof(joypad_state_t);
|
||||
dataSource = (void*) &joypad;
|
||||
memcpy(&buffer[pos], headerCode.data(), headerSize); pos += headerSize;
|
||||
memcpy(&buffer[pos], &blockSize, headerSize); pos += headerSize;
|
||||
memcpy(&buffer[pos], dataSource, blockSize); pos += blockSize;
|
||||
|
||||
headerCode = "MAPR"; // MAPR Block
|
||||
blockSize = mapper->state_size;
|
||||
dataSource = (void*) mapper->state;
|
||||
memcpy(&buffer[pos], headerCode.data(), headerSize); pos += headerSize;
|
||||
memcpy(&buffer[pos], &blockSize, headerSize); pos += headerSize;
|
||||
memcpy(&buffer[pos], dataSource, blockSize); pos += blockSize;
|
||||
|
||||
headerCode = "LRAM"; // LRAM Block
|
||||
blockSize = low_ram_size;
|
||||
dataSource = (void*) low_mem;
|
||||
memcpy(&buffer[pos], headerCode.data(), headerSize); pos += headerSize;
|
||||
memcpy(&buffer[pos], &blockSize, headerSize); pos += headerSize;
|
||||
memcpy(&buffer[pos], dataSource, blockSize); pos += blockSize;
|
||||
|
||||
headerCode = "SPRT"; // SPRT Block
|
||||
blockSize = Nes_Ppu::spr_ram_size;
|
||||
dataSource = (void*) ppu.spr_ram;
|
||||
memcpy(&buffer[pos], headerCode.data(), headerSize); pos += headerSize;
|
||||
memcpy(&buffer[pos], &blockSize, headerSize); pos += headerSize;
|
||||
memcpy(&buffer[pos], dataSource, blockSize); pos += blockSize;
|
||||
|
||||
headerCode = "NTAB"; // NTAB Block
|
||||
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;
|
||||
memcpy(&buffer[pos], headerCode.data(), headerSize); pos += headerSize;
|
||||
memcpy(&buffer[pos], &blockSize, headerSize); pos += headerSize;
|
||||
memcpy(&buffer[pos], dataSource, blockSize); pos += blockSize;
|
||||
|
||||
if ( ppu.chr_is_writable )
|
||||
{
|
||||
headerCode = "CHRR"; // CHRR Block
|
||||
blockSize = ppu.chr_size;
|
||||
dataSource = (void*) ppu.impl->chr_ram;
|
||||
memcpy(&buffer[pos], headerCode.data(), headerSize); pos += headerSize;
|
||||
memcpy(&buffer[pos], &blockSize, headerSize); pos += headerSize;
|
||||
memcpy(&buffer[pos], dataSource, blockSize); pos += blockSize;
|
||||
}
|
||||
|
||||
if ( sram_present )
|
||||
{
|
||||
headerCode = "SRAM"; // SRAM Block
|
||||
blockSize = impl->sram_size;
|
||||
dataSource = (void*) impl->sram;
|
||||
memcpy(&buffer[pos], headerCode.data(), headerSize); pos += headerSize;
|
||||
memcpy(&buffer[pos], &blockSize, headerSize); pos += headerSize;
|
||||
memcpy(&buffer[pos], dataSource, blockSize); pos += blockSize;
|
||||
}
|
||||
|
||||
headerCode = "gend"; // gend Block
|
||||
blockSize = 0;
|
||||
memcpy(&buffer[pos], headerCode.data(), headerSize); pos += headerSize;
|
||||
memcpy(&buffer[pos], &blockSize, headerSize); pos += headerSize;
|
||||
|
||||
return pos; // Bytes written
|
||||
}
|
||||
|
||||
size_t deserializeState(const uint8_t* buffer)
|
||||
{
|
||||
disable_rendering();
|
||||
error_count = 0;
|
||||
ppu.burst_phase = 0; // avoids shimmer when seeking to same time over and over
|
||||
|
||||
size_t pos = 0;
|
||||
const uint32_t headerSize = sizeof(char) * 4;
|
||||
uint32_t blockSize = 0;
|
||||
|
||||
// NESS Block
|
||||
pos += headerSize;
|
||||
pos += headerSize;
|
||||
|
||||
// TIME Block
|
||||
nes_state_t nesState;
|
||||
pos += headerSize;
|
||||
pos += headerSize;
|
||||
blockSize = sizeof(nes_state_t);
|
||||
memcpy(&nesState, &buffer[pos], blockSize); pos += blockSize;
|
||||
nes = nesState;
|
||||
nes.timestamp /= 5;
|
||||
|
||||
// CPUR Block
|
||||
cpu_state_t s;
|
||||
blockSize = sizeof(cpu_state_t);
|
||||
pos += headerSize;
|
||||
pos += headerSize;
|
||||
memcpy((void*) &s, &buffer[pos], blockSize); pos += blockSize;
|
||||
r.pc = s.pc;
|
||||
r.sp = s.s;
|
||||
r.a = s.a;
|
||||
r.x = s.x;
|
||||
r.y = s.y;
|
||||
r.status = s.p;
|
||||
|
||||
// PPUR Block
|
||||
blockSize = sizeof(ppu_state_t);
|
||||
pos += headerSize;
|
||||
pos += headerSize;
|
||||
memcpy((void*) &ppu, &buffer[pos], blockSize); pos += blockSize;
|
||||
|
||||
// APUR Block
|
||||
Nes_Apu::apu_state_t apuState;
|
||||
blockSize = sizeof(Nes_Apu::apu_state_t);
|
||||
pos += headerSize;
|
||||
pos += headerSize;
|
||||
memcpy(&apuState, &buffer[pos], blockSize);
|
||||
pos += blockSize;
|
||||
impl->apu.load_state(apuState);
|
||||
impl->apu.end_frame( -(int) nes.timestamp / ppu_overclock );
|
||||
|
||||
// CTRL Block
|
||||
blockSize = sizeof(joypad_state_t);
|
||||
pos += headerSize;
|
||||
pos += headerSize;
|
||||
memcpy((void*) &joypad, &buffer[pos], blockSize); pos += blockSize;
|
||||
|
||||
// MAPR Block
|
||||
mapper->default_reset_state();
|
||||
blockSize = mapper->state_size;
|
||||
pos += headerSize;
|
||||
pos += headerSize;
|
||||
memcpy((void*) mapper->state, &buffer[pos], blockSize); pos += blockSize;
|
||||
mapper->apply_mapping();
|
||||
|
||||
// LRAM Block
|
||||
blockSize = low_ram_size;
|
||||
pos += headerSize;
|
||||
pos += headerSize;
|
||||
memcpy((void*) low_mem, &buffer[pos], blockSize); pos += blockSize;
|
||||
|
||||
// SPRT Block
|
||||
blockSize = Nes_Ppu::spr_ram_size;
|
||||
pos += headerSize;
|
||||
pos += headerSize;
|
||||
memcpy((void*) ppu.spr_ram, &buffer[pos], blockSize); pos += blockSize;
|
||||
|
||||
// NTAB Block
|
||||
size_t nametable_size = 0x800;
|
||||
if (ppu.nt_banks [3] >= &ppu.impl->nt_ram [0xC00] ) nametable_size = 0x1000;
|
||||
blockSize = nametable_size;
|
||||
pos += headerSize;
|
||||
pos += headerSize;
|
||||
memcpy((void*) ppu.impl->nt_ram, &buffer[pos], blockSize); pos += blockSize;
|
||||
|
||||
if ( ppu.chr_is_writable )
|
||||
{
|
||||
// CHRR Block
|
||||
blockSize = ppu.chr_size;
|
||||
pos += headerSize;
|
||||
pos += headerSize;
|
||||
memcpy((void*) ppu.impl->chr_ram, &buffer[pos], blockSize); pos += blockSize;
|
||||
}
|
||||
|
||||
if ( sram_present )
|
||||
{
|
||||
// SRAM Block
|
||||
blockSize = impl->sram_size;
|
||||
pos += headerSize;
|
||||
pos += headerSize;
|
||||
memcpy((void*) impl->sram, &buffer[pos], blockSize); pos += blockSize;
|
||||
enable_sram(true);
|
||||
}
|
||||
|
||||
// headerCode = "gend"; // gend Block
|
||||
pos += headerSize;
|
||||
pos += headerSize;
|
||||
|
||||
return pos; // Bytes read
|
||||
}
|
||||
|
||||
void reset( bool full_reset, bool erase_battery_ram )
|
||||
{
|
||||
if ( full_reset )
|
||||
|
@ -347,50 +657,50 @@ public:
|
|||
|
||||
void load_state( Nes_State_ const& in )
|
||||
{
|
||||
disable_rendering();
|
||||
error_count = 0;
|
||||
// disable_rendering();
|
||||
// error_count = 0;
|
||||
|
||||
if ( in.nes_valid )
|
||||
nes = in.nes;
|
||||
// if ( in.nes_valid )
|
||||
// nes = in.nes;
|
||||
|
||||
// always use frame count
|
||||
ppu.burst_phase = 0; // avoids shimmer when seeking to same time over and over
|
||||
nes.frame_count = in.nes.frame_count;
|
||||
if ( (frame_count_t) nes.frame_count == invalid_frame_count )
|
||||
nes.frame_count = 0;
|
||||
// // always use frame count
|
||||
// ppu.burst_phase = 0; // avoids shimmer when seeking to same time over and over
|
||||
// nes.frame_count = in.nes.frame_count;
|
||||
// if ( (frame_count_t) nes.frame_count == invalid_frame_count )
|
||||
// nes.frame_count = 0;
|
||||
|
||||
if ( in.cpu_valid )
|
||||
cpu::r = *in.cpu;
|
||||
// if ( in.cpu_valid )
|
||||
// cpu::r = *in.cpu;
|
||||
|
||||
if ( in.joypad_valid )
|
||||
joypad = *in.joypad;
|
||||
// if ( in.joypad_valid )
|
||||
// joypad = *in.joypad;
|
||||
|
||||
if ( in.apu_valid )
|
||||
{
|
||||
impl->apu.load_state( *in.apu );
|
||||
// prevent apu from running extra at beginning of frame
|
||||
impl->apu.end_frame( -(int) nes.timestamp / ppu_overclock );
|
||||
}
|
||||
else
|
||||
{
|
||||
impl->apu.reset();
|
||||
}
|
||||
// if ( in.apu_valid )
|
||||
// {
|
||||
// impl->apu.load_state( *in.apu );
|
||||
// // prevent apu from running extra at beginning of frame
|
||||
// impl->apu.end_frame( -(int) nes.timestamp / ppu_overclock );
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
// impl->apu.reset();
|
||||
// }
|
||||
|
||||
ppu.load_state( in );
|
||||
// ppu.load_state( in );
|
||||
|
||||
if ( in.ram_valid )
|
||||
memcpy( cpu::low_mem, in.ram, in.ram_size );
|
||||
// if ( in.ram_valid )
|
||||
// memcpy( cpu::low_mem, in.ram, in.ram_size );
|
||||
|
||||
sram_present = false;
|
||||
if ( in.sram_size )
|
||||
{
|
||||
sram_present = true;
|
||||
memcpy( impl->sram, in.sram, min( (int) in.sram_size, (int) sizeof impl->sram ) );
|
||||
enable_sram( true ); // mapper can override (read-only, unmapped, etc.)
|
||||
}
|
||||
// sram_present = false;
|
||||
// if ( in.sram_size )
|
||||
// {
|
||||
// sram_present = true;
|
||||
// // memcpy( impl->sram, in.sram, min( (int) in.sram_size, (int) sizeof impl->sram ) );
|
||||
// enable_sram( true ); // mapper can override (read-only, unmapped, etc.)
|
||||
// }
|
||||
|
||||
if ( in.mapper_valid ) // restore last since it might reconfigure things
|
||||
mapper->load_state( *in.mapper );
|
||||
// if ( in.mapper_valid ) // restore last since it might reconfigure things
|
||||
// mapper->load_state( *in.mapper );
|
||||
}
|
||||
|
||||
void irq_changed()
|
||||
|
|
|
@ -42,7 +42,8 @@ public:
|
|||
|
||||
const uint8_t* getHostPixels () const { return emu.ppu.host_pixels; }
|
||||
|
||||
size_t getLightweightStateSize() { return emu.getLightweightStateSize(); }
|
||||
size_t getLiteStateSize() const { return emu.getLiteStateSize(); }
|
||||
size_t getStateSize() const { return emu.getStateSize(); }
|
||||
|
||||
// Basic emulation
|
||||
|
||||
|
@ -140,6 +141,8 @@ public:
|
|||
// Save emulator state
|
||||
void save_state( Nes_State* s ) const { emu.save_state( s ); }
|
||||
const char * save_state( Auto_File_Writer ) const;
|
||||
size_t serializeState (uint8_t* buffer) const { return emu.serializeState(buffer); }
|
||||
size_t deserializeState (const uint8_t* buffer) { return emu.deserializeState(buffer); }
|
||||
|
||||
// Load state into emulator
|
||||
void load_state( Nes_State const& );
|
||||
|
|
|
@ -68,6 +68,9 @@ public:
|
|||
// $2006 and $2007 accesses (but not due to PPU scanline rendering).
|
||||
virtual void a12_clocked();
|
||||
|
||||
void* state;
|
||||
unsigned state_size;
|
||||
|
||||
protected:
|
||||
// Services provided for derived mapper classes
|
||||
Nes_Mapper();
|
||||
|
@ -147,9 +150,7 @@ protected:
|
|||
// apply_mapping().
|
||||
virtual void read_state( mapper_state_t const& );
|
||||
|
||||
// Apply current mapping state to hardware. Called after reading mapper state
|
||||
// from a snapshot.
|
||||
virtual void apply_mapping() = 0;
|
||||
|
||||
|
||||
// Called by default reset() before apply_mapping() is called.
|
||||
virtual void reset_state() { }
|
||||
|
@ -161,11 +162,9 @@ protected:
|
|||
Nes_Cart const* cart_;
|
||||
Nes_Core* emu_;
|
||||
|
||||
private:
|
||||
|
||||
void* state;
|
||||
unsigned state_size;
|
||||
|
||||
// Apply current mapping state to hardware. Called after reading mapper state
|
||||
// from a snapshot.
|
||||
virtual void apply_mapping() = 0;
|
||||
|
||||
void default_reset_state();
|
||||
};
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
|
||||
#include "Nes_Ppu_Impl.h"
|
||||
|
||||
#include <cstdio>
|
||||
#include <string.h>
|
||||
#include "blargg_endian.h"
|
||||
#include "Nes_State.h"
|
||||
|
|
|
@ -30,6 +30,10 @@ public:
|
|||
static const uint16_t buffer_height = image_height;
|
||||
enum { spr_ram_size = 0x100 };
|
||||
|
||||
uint8_t* nt_banks [4];
|
||||
bool chr_is_writable;
|
||||
long chr_size;
|
||||
|
||||
int write_2007( int );
|
||||
|
||||
// Host palette
|
||||
|
@ -67,9 +71,10 @@ public:
|
|||
|
||||
uint8_t* getSpriteRAM () { return spr_ram; }
|
||||
uint16_t getSpriteRAMSize () { return spr_ram_size; }
|
||||
|
||||
protected:
|
||||
uint8_t spr_ram [spr_ram_size];
|
||||
void all_tiles_modified();
|
||||
protected:
|
||||
|
||||
void begin_frame();
|
||||
void run_hblank( int );
|
||||
int sprite_height() const { return (w2000 >> 2 & 8) + 8; }
|
||||
|
@ -90,7 +95,6 @@ protected: //friend class Nes_Ppu_Rendering; private:
|
|||
void capture_palette();
|
||||
|
||||
bool any_tiles_modified;
|
||||
bool chr_is_writable;
|
||||
void update_tiles( int first_tile );
|
||||
|
||||
typedef uint32_t cache_t;
|
||||
|
@ -128,7 +132,7 @@ private:
|
|||
|
||||
return ret;
|
||||
}
|
||||
uint8_t* nt_banks [4];
|
||||
|
||||
|
||||
bool mmc24_enabled;
|
||||
uint8_t mmc24_latched [2];
|
||||
|
@ -136,7 +140,6 @@ private:
|
|||
// CHR data
|
||||
uint8_t const* chr_data; // points to chr ram when there is no read-only data
|
||||
uint8_t* chr_ram; // always points to impl->chr_ram; makes write_2007() faster
|
||||
long chr_size;
|
||||
uint8_t const* map_chr( int addr ) { return &chr_data [map_chr_addr( addr )]; }
|
||||
|
||||
// CHR cache
|
||||
|
@ -147,7 +150,7 @@ private:
|
|||
uint8_t modified_tiles [chr_tile_count / 8];
|
||||
uint32_t align_;
|
||||
};
|
||||
void all_tiles_modified();
|
||||
|
||||
void update_tile( int index );
|
||||
};
|
||||
|
||||
|
|
|
@ -113,7 +113,7 @@ const char * Nes_State_::write_blocks( Nes_File_Writer& out ) const
|
|||
s.p = cpu->status;
|
||||
RETURN_ERR( write_nes_state( out, s ) );
|
||||
}
|
||||
|
||||
|
||||
if ( ppu_valid )
|
||||
{
|
||||
ppu_state_t s = *ppu;
|
||||
|
|
|
@ -26,9 +26,6 @@ class QuickerNESInstance : public EmuInstance
|
|||
{
|
||||
// Loading rom data
|
||||
auto result = _nes->load_ines((uint8_t*)romData.data());
|
||||
|
||||
// printf("Lightweight size: %lu vs Full Size: %lu\n", _nes->getLightweightStateSize(), getStateSizeImpl());
|
||||
// exit(0);
|
||||
return result == 0;
|
||||
}
|
||||
|
||||
|
@ -40,16 +37,12 @@ class QuickerNESInstance : public EmuInstance
|
|||
|
||||
void serializeState(uint8_t* state) const
|
||||
{
|
||||
Mem_Writer w(state, _stateSize, 0);
|
||||
Auto_File_Writer a(w);
|
||||
_nes->save_state(a);
|
||||
_nes->serializeState(state);
|
||||
}
|
||||
|
||||
void deserializeState(const uint8_t* state)
|
||||
{
|
||||
Mem_File_Reader r(state, _stateSize);
|
||||
Auto_File_Reader a(r);
|
||||
_nes->load_state(a);
|
||||
_nes->deserializeState(state);
|
||||
}
|
||||
|
||||
void advanceStateImpl(const inputType controller1, const inputType controller2) override
|
||||
|
@ -66,13 +59,14 @@ class QuickerNESInstance : public EmuInstance
|
|||
|
||||
private:
|
||||
|
||||
inline size_t getStateSizeImpl() const
|
||||
inline size_t getStateSizeImpl() const override
|
||||
{
|
||||
// Using dry writer to just obtain the state size
|
||||
Dry_Writer w;
|
||||
Auto_File_Writer a(w);
|
||||
_nes->save_state(a);
|
||||
return w.size();
|
||||
return _nes->getStateSize();
|
||||
}
|
||||
|
||||
inline size_t getLiteStateSizeImpl() const override
|
||||
{
|
||||
return _nes->getLiteStateSize();
|
||||
}
|
||||
|
||||
// Video buffer
|
||||
|
|
|
@ -92,9 +92,12 @@ int main(int argc, char *argv[])
|
|||
// Getting initial hash
|
||||
auto initialHash = e.getStateHash();
|
||||
|
||||
// Getting state size
|
||||
// Getting full state size
|
||||
const auto stateSize = e.getStateSize();
|
||||
|
||||
// Getting lite state size
|
||||
const auto liteStateSize = e.getLiteStateSize();
|
||||
|
||||
// Getting actual ROM SHA1
|
||||
auto romSHA1 = e.getRomSHA1();
|
||||
|
||||
|
@ -124,7 +127,8 @@ int main(int argc, char *argv[])
|
|||
printf("[] Sequence File: '%s'\n", sequenceFilePath.c_str());
|
||||
printf("[] Sequence Length: %lu\n", sequenceLength);
|
||||
printf("[] Initial State Hash: 0x%lX%lX\n", initialHash.first, initialHash.second);
|
||||
printf("[] State Size: %lu bytes\n", stateSize);
|
||||
printf("[] Full State Size: %lu bytes\n", stateSize);
|
||||
printf("[] Lite State Size: %lu bytes\n", liteStateSize);
|
||||
printf("[] ********** Running Test **********\n");
|
||||
|
||||
fflush(stdout);
|
||||
|
|
Loading…
Reference in New Issue