Creating emulator interface class to mix both versions. This will be useful for verification purposes. Also fixed mapper070 for quicknes
This commit is contained in:
parent
ad9858a564
commit
a254482102
|
@ -1,3 +1,3 @@
|
|||
[submodule "extern/QuickNES_Core"]
|
||||
path = extern/QuickNES_Core
|
||||
path = source/quickNES/QuickNES_Core
|
||||
url = https://github.com/libretro/QuickNES_Core.git
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
#ifndef __HQN_H__
|
||||
#define __HQN_H__
|
||||
|
||||
#include <core/Nes_Emu.h>
|
||||
#include <Nes_Emu.h>
|
||||
#include <cstdint>
|
||||
#include <stdio.h>
|
||||
|
||||
|
@ -46,6 +46,8 @@ public:
|
|||
HQNState();
|
||||
~HQNState();
|
||||
|
||||
void setEmulatorPointer(void* const emuPtr) { m_emu = (Nes_Emu*)emuPtr; }
|
||||
|
||||
/*
|
||||
The joypad data for the two joypads available to an NES.
|
||||
This is directly available because I'm lazy.
|
||||
|
@ -148,7 +150,7 @@ void printUsage(const char *filename);
|
|||
} // end namespace hqn
|
||||
|
||||
// Copied from bizinterface.cpp in BizHawk/quicknes
|
||||
inline void saveBlit(const Nes_Emu *e, int32_t *dest, const int32_t *colors, int cropleft, int croptop, int cropright, int cropbottom)
|
||||
inline void saveBlit(const void *ePtr, int32_t *dest, const int32_t *colors, int cropleft, int croptop, int cropright, int cropbottom)
|
||||
{
|
||||
// what is the point of the 256 color bitmap and the dynamic color allocation to it?
|
||||
// why not just render directly to a 512 color bitmap with static palette positions?
|
||||
|
@ -172,6 +174,7 @@ inline void saveBlit(const Nes_Emu *e, int32_t *dest, const int32_t *colors, int
|
|||
// }
|
||||
// }
|
||||
|
||||
const Nes_Emu *e = (Nes_Emu*) ePtr;
|
||||
const unsigned char *in_pixels = e->frame().pixels;
|
||||
if (in_pixels == NULL) return;
|
||||
int32_t *out_pixels = dest;
|
||||
|
|
|
@ -9,7 +9,6 @@ pageSize = get_option('CPUFunctionAlignment')
|
|||
|
||||
# Loading dependencies
|
||||
subdir('source')
|
||||
subdir('extern')
|
||||
|
||||
# Common application flags
|
||||
commonCompileArgs = [ '-Wfatal-errors', '-Wall', '-Wno-multichar' ]
|
||||
|
@ -27,7 +26,7 @@ quickerNESPlayerSrc = [
|
|||
executable('player',
|
||||
'source/player.cpp',
|
||||
cpp_args : [ commonCompileArgs, '-DNCURSES' ],
|
||||
dependencies : [ quickerNESCoreDependency, quickerNESApplicationDependency, dependency('sdl2'), dependency('SDL2_image') ],
|
||||
dependencies : [ quickerNESDependency, toolDependency, dependency('sdl2'), dependency('SDL2_image') ],
|
||||
include_directories : include_directories(['source']),
|
||||
link_args : [ '-lncurses' ],
|
||||
sources : quickerNESPlayerSrc
|
||||
|
@ -38,7 +37,7 @@ executable('player',
|
|||
quickerNESTester = executable('quickerNESTester',
|
||||
'source/tester.cpp',
|
||||
cpp_args : [ commonCompileArgs, '-Werror' ],
|
||||
dependencies : [ quickerNESCoreDependency, quickerNESApplicationDependency ],
|
||||
dependencies : [ quickerNESDependency, toolDependency ],
|
||||
include_directories : include_directories(['../extern/json'])
|
||||
)
|
||||
|
||||
|
@ -47,7 +46,7 @@ quickerNESTester = executable('quickerNESTester',
|
|||
quickNESTester = executable('quickNESTester',
|
||||
'source/tester.cpp',
|
||||
cpp_args : [ commonCompileArgs ],
|
||||
dependencies : [ quickNESCoreDependency, quickerNESApplicationDependency ],
|
||||
dependencies : [ quickNESDependency, toolDependency ],
|
||||
include_directories : include_directories(['../extern/json'])
|
||||
)
|
||||
|
||||
|
|
|
@ -1,20 +1,16 @@
|
|||
#pragma once
|
||||
|
||||
#include <Nes_Emu.h>
|
||||
#include <Nes_State.h>
|
||||
#include <string>
|
||||
#include <utils.hpp>
|
||||
#include "sha1/sha1.hpp"
|
||||
|
||||
#ifdef USE_ORIGINAL_QUICKNES
|
||||
extern void register_misc_mappers();
|
||||
extern void register_extra_mappers();
|
||||
#endif
|
||||
|
||||
#define _LOW_MEM_SIZE 0x800
|
||||
#define _HIGH_MEM_SIZE 0x2000
|
||||
#define _NAMETABLES_MEM_SIZE 0x1000
|
||||
|
||||
// Size of image generated in graphics buffer
|
||||
static const uint16_t image_width = 256;
|
||||
static const uint16_t image_height = 240;
|
||||
|
||||
class EmuInstance
|
||||
{
|
||||
public:
|
||||
|
@ -22,117 +18,8 @@ class EmuInstance
|
|||
typedef uint8_t inputType;
|
||||
|
||||
// Deleting default constructors
|
||||
EmuInstance() = delete;
|
||||
EmuInstance(EmuInstance& e) = delete;
|
||||
~EmuInstance() = default;
|
||||
|
||||
EmuInstance(const std::string& romFilePath, const std::string& stateFilePath)
|
||||
{
|
||||
// Creating new emulator
|
||||
_nes = new Nes_Emu;
|
||||
|
||||
// If running the original QuickNES, register extra mappers now
|
||||
#ifdef USE_ORIGINAL_QUICKNES
|
||||
register_misc_mappers();
|
||||
register_extra_mappers();
|
||||
#endif
|
||||
|
||||
// Loading ROM
|
||||
std::string romData;
|
||||
bool status = loadStringFromFile(romData, romFilePath.c_str());
|
||||
if (status == false) EXIT_WITH_ERROR("Could not find/read state file: %s\n", romFilePath.c_str());
|
||||
|
||||
// Calculating ROM hash value
|
||||
_romSHA1String = SHA1::GetHash((uint8_t*)romData.data(), romData.size());
|
||||
|
||||
// Loading the rom into the emulator
|
||||
#ifdef USE_ORIGINAL_QUICKNES
|
||||
Mem_File_Reader romReader(romData.data(), (int)romData.size());
|
||||
Auto_File_Reader romFile(romReader);
|
||||
auto result = _nes->load_ines(romFile);
|
||||
if (result != 0) EXIT_WITH_ERROR("Could not initialize emulator with rom file: %s\n", romFilePath.c_str());
|
||||
#else
|
||||
auto result = _nes->load_ines((const uint8_t*) romData.data());
|
||||
if (result != 0) EXIT_WITH_ERROR("Could not initialize emulator with rom file: %s\n", romFilePath.c_str());
|
||||
#endif
|
||||
|
||||
|
||||
// Getting state size to use
|
||||
_stateSize = getStateSizeImpl();
|
||||
|
||||
// Loading state file, if specified
|
||||
if (stateFilePath != "") loadStateFile(stateFilePath);
|
||||
}
|
||||
|
||||
uint8_t* getLowMem() { return _nes->low_mem(); };
|
||||
uint8_t* getNametableMem() { return _nes->nametable_mem(); };
|
||||
uint8_t* getHighMem() { return _nes->high_mem();};
|
||||
const uint8_t* getChrMem() { return _nes->chr_mem();};
|
||||
size_t getChrMemSize() { return _nes->chr_size();};
|
||||
// uint8_t* getSpriteRAM() { return _nes->spr_mem(); }
|
||||
// uint16_t getSpriteRAMSize() { return _nes->spr_mem_size(); }
|
||||
|
||||
const std::string getRomSHA1() const { return _romSHA1String; };
|
||||
|
||||
void loadStateFile(const std::string& stateFilePath)
|
||||
{
|
||||
// Loading state data
|
||||
std::string stateData;
|
||||
bool status = loadStringFromFile(stateData, stateFilePath.c_str());
|
||||
|
||||
if (status == false) EXIT_WITH_ERROR("Could not find/read state file: %s\n", stateFilePath.c_str());
|
||||
Mem_File_Reader stateReader(stateData.data(), (int)stateData.size());
|
||||
Auto_File_Reader stateFile(stateReader);
|
||||
|
||||
// Loading state data into state object
|
||||
Nes_State state;
|
||||
state.read(stateFile);
|
||||
|
||||
// Loading state object into the emulator
|
||||
_nes->load_state(state);
|
||||
}
|
||||
|
||||
inline size_t getStateSize() const { return _stateSize; }
|
||||
|
||||
inline hash_t getStateHash()
|
||||
{
|
||||
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);
|
||||
hash.Update(getChrMem(), getChrMemSize());
|
||||
|
||||
hash_t result;
|
||||
hash.Finalize(reinterpret_cast<uint8_t *>(&result));
|
||||
return result;
|
||||
}
|
||||
|
||||
void saveStateFile(const std::string& stateFilePath) const
|
||||
{
|
||||
std::string stateData;
|
||||
stateData.resize(_stateSize);
|
||||
serializeState((uint8_t*)stateData.data());
|
||||
saveStringToFile(stateData, stateFilePath.c_str());
|
||||
}
|
||||
|
||||
void serializeState(uint8_t* state) const
|
||||
{
|
||||
Mem_Writer w(state, _stateSize, 0);
|
||||
Auto_File_Writer a(w);
|
||||
_nes->save_state(a);
|
||||
}
|
||||
|
||||
void deserializeState(const uint8_t* state)
|
||||
{
|
||||
Mem_File_Reader r(state, _stateSize);
|
||||
Auto_File_Reader a(r);
|
||||
_nes->load_state(a);
|
||||
}
|
||||
|
||||
// Controller input bits
|
||||
// 0 - A / 1
|
||||
// 1 - B / 2
|
||||
|
@ -191,54 +78,101 @@ class EmuInstance
|
|||
return moveString;
|
||||
}
|
||||
|
||||
void enableRendering() { _doRendering = true; }
|
||||
void disableRendering() { _doRendering = false; }
|
||||
|
||||
void advanceState(const std::string& move)
|
||||
inline void advanceState(const std::string& move)
|
||||
{
|
||||
if (move.find("r") != std::string::npos) _nes->reset(false);
|
||||
if (move.find("r") != std::string::npos) doSoftReset();
|
||||
|
||||
advanceState(moveStringToCode(move), 0);
|
||||
advanceStateImpl(moveStringToCode(move), 0);
|
||||
}
|
||||
|
||||
void advanceState(const inputType controller1, const inputType controller2)
|
||||
inline size_t getStateSize() const { return _stateSize; }
|
||||
inline std::string getRomSHA1() const { return _romSHA1String; }
|
||||
|
||||
inline hash_t getStateHash() const
|
||||
{
|
||||
if (_doRendering == true) _nes->emulate_frame(controller1, controller2);
|
||||
if (_doRendering == false) _nes->emulate_skip_frame(controller1, controller2);
|
||||
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);
|
||||
hash.Update(getChrMem(), getChrMemSize());
|
||||
|
||||
hash_t result;
|
||||
hash.Finalize(reinterpret_cast<uint8_t *>(&result));
|
||||
return result;
|
||||
}
|
||||
|
||||
Nes_Emu* getInternalEmulator() const { return _nes; }
|
||||
inline void enableRendering() { _doRendering = true; };
|
||||
inline void disableRendering() { _doRendering = false; };
|
||||
|
||||
private:
|
||||
inline void loadStateFile(const std::string& stateFilePath)
|
||||
{
|
||||
std::string stateData;
|
||||
bool status = loadStringFromFile(stateData, stateFilePath);
|
||||
if (status == false) EXIT_WITH_ERROR("Could not find/read state file: %s\n", stateFilePath.c_str());
|
||||
deserializeState((uint8_t*)stateData.data());
|
||||
}
|
||||
|
||||
inline void saveStateFile(const std::string& stateFilePath) const
|
||||
{
|
||||
std::string stateData;
|
||||
stateData.resize(_stateSize);
|
||||
serializeState((uint8_t*)stateData.data());
|
||||
saveStringToFile(stateData, stateFilePath.c_str());
|
||||
}
|
||||
|
||||
inline void loadROMFile(const std::string& romFilePath)
|
||||
{
|
||||
// Loading ROM data
|
||||
bool status = loadStringFromFile(_romData, romFilePath);
|
||||
if (status == false) EXIT_WITH_ERROR("Could not find/read ROM file: %s\n", romFilePath.c_str());
|
||||
|
||||
// Calculating ROM hash value
|
||||
_romSHA1String = SHA1::GetHash((uint8_t*)_romData.data(), _romData.size());
|
||||
|
||||
// Actually loading rom file
|
||||
status = loadROMFileImpl(_romData);
|
||||
if (status == false) EXIT_WITH_ERROR("Could not process ROM file: %s\n", romFilePath.c_str());
|
||||
|
||||
// Detecting state size
|
||||
_stateSize = getStateSizeImpl();
|
||||
}
|
||||
|
||||
// Virtual functions
|
||||
|
||||
virtual bool loadROMFileImpl(const std::string& romFilePath) = 0;
|
||||
virtual void advanceStateImpl(const inputType controller1, const inputType controller2) = 0;
|
||||
virtual uint8_t* getLowMem() const = 0;
|
||||
virtual uint8_t* getNametableMem() const = 0;
|
||||
virtual uint8_t* getHighMem() const = 0;
|
||||
virtual const uint8_t* getChrMem() const = 0;
|
||||
virtual size_t getChrMemSize() const = 0;
|
||||
virtual void serializeState(uint8_t* state) const = 0;
|
||||
virtual void deserializeState(const uint8_t* state) = 0;
|
||||
virtual size_t getStateSizeImpl() const = 0;
|
||||
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
|
||||
size_t _stateSize;
|
||||
|
||||
// Flag to determine whether to enable/disable rendering
|
||||
bool _doRendering = true;
|
||||
|
||||
inline size_t getStateSizeImpl() const
|
||||
{
|
||||
#ifdef USE_ORIGINAL_QUICKNES
|
||||
#define _DUMMY_SIZE 65536
|
||||
uint8_t data[_DUMMY_SIZE];
|
||||
Mem_Writer w(data, _DUMMY_SIZE);
|
||||
Auto_File_Writer a(w);
|
||||
_nes->save_state(a);
|
||||
return w.size();
|
||||
#else
|
||||
// Using dry writer to just obtain the state size
|
||||
Dry_Writer w;
|
||||
Auto_File_Writer a(w);
|
||||
_nes->save_state(a);
|
||||
return w.size();
|
||||
#endif
|
||||
}
|
||||
private:
|
||||
|
||||
// Emulator instance
|
||||
Nes_Emu* _nes;
|
||||
|
||||
// State size for the given rom
|
||||
size_t _stateSize;
|
||||
// Storage for the ROM data
|
||||
std::string _romData;
|
||||
|
||||
// SHA1 rom hash
|
||||
std::string _romSHA1String;
|
||||
|
||||
};
|
||||
|
|
|
@ -1,9 +1,10 @@
|
|||
# Getting core configuration
|
||||
subdir('core')
|
||||
# Getting core configurations
|
||||
subdir('quickNES')
|
||||
subdir('quickerNES')
|
||||
|
||||
# quickerNES Application Configuration
|
||||
# Tool Configuration
|
||||
|
||||
quickerNESApplicationDependency = declare_dependency(
|
||||
toolDependency = declare_dependency(
|
||||
include_directories : include_directories(['.', '../extern']),
|
||||
sources : [ '../extern/metrohash128/metrohash128.cpp' ]
|
||||
)
|
|
@ -11,6 +11,8 @@
|
|||
|
||||
#define _INVERSE_FRAME_RATE 16667
|
||||
|
||||
class Nes_Emu;
|
||||
|
||||
struct stepData_t
|
||||
{
|
||||
std::string input;
|
||||
|
@ -37,8 +39,11 @@ class PlaybackInstance
|
|||
// Initializes the playback module instance
|
||||
PlaybackInstance(EmuInstance* emu, const std::vector<std::string>& sequence, const std::string& overlayPath = "") : _emu(emu)
|
||||
{
|
||||
// Enabling emulation rendering
|
||||
_emu->enableRendering();
|
||||
|
||||
// Loading Emulator instance HQN
|
||||
_hqnState.m_emu = _emu->getInternalEmulator();
|
||||
_hqnState.setEmulatorPointer(_emu->getInternalEmulatorPointer());
|
||||
static uint8_t video_buffer[Nes_Emu::image_width * Nes_Emu::image_height];
|
||||
_hqnState.m_emu->set_pixels(video_buffer, Nes_Emu::image_width+8);
|
||||
|
||||
|
@ -149,7 +154,7 @@ class PlaybackInstance
|
|||
// Since we do not store the blit information (too much memory), we need to load the previous frame and re-run the input
|
||||
|
||||
// If its the first step, then simply reset
|
||||
if (stepId == 0) _emu->getInternalEmulator()->reset();
|
||||
if (stepId == 0) _emu->doHardReset();
|
||||
|
||||
// Else we load the previous frame
|
||||
if (stepId > 0)
|
||||
|
@ -161,7 +166,7 @@ class PlaybackInstance
|
|||
|
||||
// Updating image
|
||||
int32_t curBlit[BLIT_SIZE];
|
||||
saveBlit(_emu->getInternalEmulator(), curBlit, hqn::HQNState::NES_VIDEO_PALETTE, 0, 0, 0, 0);
|
||||
saveBlit(_emu->getInternalEmulatorPointer(), curBlit, hqn::HQNState::NES_VIDEO_PALETTE, 0, 0, 0, 0);
|
||||
_hqnGUI->update_blit(curBlit, _overlayBaseSurface, overlayButtonASurface, overlayButtonBSurface, overlayButtonSelectSurface, overlayButtonStartSurface, overlayButtonLeftSurface, overlayButtonRightSurface, overlayButtonUpSurface, overlayButtonDownSurface);
|
||||
}
|
||||
|
||||
|
|
|
@ -4,6 +4,14 @@
|
|||
#include "emuInstance.hpp"
|
||||
#include "playbackInstance.hpp"
|
||||
|
||||
#ifdef _USE_QUICKNES
|
||||
#include "quickNESInstance.hpp"
|
||||
#endif
|
||||
|
||||
#ifdef _USE_QUICKERNES
|
||||
#include "quickerNESInstance.hpp"
|
||||
#endif
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
// Parsing command line arguments
|
||||
|
@ -71,7 +79,13 @@ int main(int argc, char *argv[])
|
|||
refreshTerminal();
|
||||
|
||||
// Creating emulator instance
|
||||
auto e = EmuInstance(romFilePath, stateFilePath);
|
||||
#ifdef _USE_QUICKNES
|
||||
auto e = QuickNESInstance();
|
||||
#endif
|
||||
|
||||
#ifdef _USE_QUICKERNES
|
||||
auto e = QuickerNESInstance();
|
||||
#endif
|
||||
|
||||
// Creating playback instance
|
||||
auto p = PlaybackInstance(&e, sequence);
|
||||
|
|
|
@ -0,0 +1,80 @@
|
|||
/* Copyright notice for this file:
|
||||
* Copyright (C) 2018
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*
|
||||
* This mapper was added by retrowertz for Libretro port of QuickNES.
|
||||
*
|
||||
* Mapper 180 Crazy Climber
|
||||
*
|
||||
*/
|
||||
|
||||
#include "Nes_Mapper.h"
|
||||
|
||||
template < bool _is152 >
|
||||
class Mapper_74x161x162x32 : public Nes_Mapper {
|
||||
public:
|
||||
Mapper_74x161x162x32()
|
||||
{
|
||||
register_state( &bank, 1 );
|
||||
}
|
||||
|
||||
virtual void reset_state()
|
||||
{
|
||||
if ( _is152 == 0 )
|
||||
bank = ~0;
|
||||
}
|
||||
|
||||
virtual void apply_mapping()
|
||||
{
|
||||
if ( _is152 )
|
||||
write( 0, 0, bank );
|
||||
else
|
||||
{
|
||||
intercept_writes( 0x6000, 1 );
|
||||
write_intercepted( 0, 0x6000, bank );
|
||||
}
|
||||
}
|
||||
|
||||
virtual bool write_intercepted( nes_time_t, nes_addr_t addr, int data )
|
||||
{
|
||||
if ( ( addr != 0x6000 ) || _is152 )
|
||||
return false;
|
||||
|
||||
bank = data;
|
||||
set_prg_bank( 0x8000, bank_32k, ( bank >> 4 ) & 0x03 );
|
||||
set_chr_bank( 0x0000, bank_8k, ( ( bank >> 4 ) & 0x04 ) | ( bank & 0x03 ) );
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
virtual void write( nes_time_t, nes_addr_t addr, int data )
|
||||
{
|
||||
if ( _is152 == 0) return;
|
||||
|
||||
bank = handle_bus_conflict (addr, data );
|
||||
set_prg_bank( 0x8000, bank_16k, ( bank >> 4 ) & 0x07 );
|
||||
set_chr_bank( 0x0000, bank_8k, bank & 0x0F );
|
||||
mirror_single( ( bank >> 7) & 0x01 );
|
||||
}
|
||||
|
||||
uint8_t bank;
|
||||
};
|
||||
|
||||
void register_mapper_70();
|
||||
void register_mapper_70()
|
||||
{
|
||||
register_mapper< Mapper_74x161x162x32 <true> > ( 70 );
|
||||
}
|
|
@ -1,6 +1,6 @@
|
|||
# quickNES Core sources
|
||||
|
||||
quickNESCoreSrc = [
|
||||
quickNESSrc = [
|
||||
'QuickNES_Core/nes_emu/abstract_file.cpp',
|
||||
'QuickNES_Core/nes_emu/apu_state.cpp',
|
||||
'QuickNES_Core/nes_emu/Blip_Buffer.cpp',
|
||||
|
@ -64,13 +64,15 @@ quickNESCoreSrc = [
|
|||
'QuickNES_Core/nes_emu/Mapper_TaitoX1005.cpp',
|
||||
'QuickNES_Core/nes_emu/Mapper_TaitoTC0190.cpp',
|
||||
'QuickNES_Core/nes_emu/Mapper_Un1rom.cpp',
|
||||
'QuickNES_Core/nes_emu/nes_ntsc.cpp'
|
||||
'QuickNES_Core/nes_emu/nes_ntsc.cpp',
|
||||
'Mapper_70.cpp',
|
||||
'quickNESInstance.hpp'
|
||||
]
|
||||
|
||||
# quickNES Core Configuration
|
||||
|
||||
quickNESCoreDependency = declare_dependency(
|
||||
compile_args : [ '-DUSE_ORIGINAL_QUICKNES'],
|
||||
include_directories : include_directories(['QuickNES_Core/nes_emu']),
|
||||
sources : [ quickNESCoreSrc ]
|
||||
quickNESDependency = declare_dependency(
|
||||
compile_args : [ '-D_USE_QUICKNES' ],
|
||||
include_directories : include_directories(['.', 'QuickNES_Core/nes_emu']),
|
||||
sources : [ quickNESSrc ]
|
||||
)
|
|
@ -0,0 +1,89 @@
|
|||
#pragma once
|
||||
|
||||
#include <Nes_Emu.h>
|
||||
#include <Nes_State.h>
|
||||
#include <emuInstance.hpp>
|
||||
|
||||
#define _DUMMY_SIZE 65536
|
||||
|
||||
extern void register_misc_mappers();
|
||||
extern void register_extra_mappers();
|
||||
extern void register_mapper_70();
|
||||
|
||||
class QuickNESInstance : public EmuInstance
|
||||
{
|
||||
public:
|
||||
|
||||
QuickNESInstance() : EmuInstance()
|
||||
{
|
||||
// Creating new emulator
|
||||
_nes = new Nes_Emu;
|
||||
|
||||
// Setting video buffer
|
||||
_nes->set_pixels(video_buffer, image_width+8);
|
||||
|
||||
// If running the original QuickNES, register extra mappers now
|
||||
register_misc_mappers();
|
||||
register_extra_mappers();
|
||||
register_mapper_70();
|
||||
}
|
||||
|
||||
virtual bool loadROMFileImpl(const std::string& romData) override
|
||||
{
|
||||
// Loading rom data
|
||||
Mem_File_Reader romReader(romData.data(), (int)romData.size());
|
||||
Auto_File_Reader romFile(romReader);
|
||||
auto result = _nes->load_ines(romFile);
|
||||
return result == 0;
|
||||
}
|
||||
|
||||
uint8_t* getLowMem() const override { return _nes->low_mem(); };
|
||||
uint8_t* getNametableMem() const override { return _nes->nametable_mem(); };
|
||||
uint8_t* getHighMem() const override { return _nes->high_mem();};
|
||||
const uint8_t* getChrMem() const override { return _nes->chr_mem();};
|
||||
size_t getChrMemSize() const override { return _nes->chr_size();};
|
||||
|
||||
void serializeState(uint8_t* state) const override
|
||||
{
|
||||
Mem_Writer w(state, _stateSize, 0);
|
||||
Auto_File_Writer a(w);
|
||||
_nes->save_state(a);
|
||||
}
|
||||
|
||||
void deserializeState(const uint8_t* state) override
|
||||
{
|
||||
Mem_File_Reader r(state, _stateSize);
|
||||
Auto_File_Reader a(r);
|
||||
_nes->load_state(a);
|
||||
}
|
||||
|
||||
void advanceStateImpl(const inputType controller1, const inputType controller2) override
|
||||
{
|
||||
if (_doRendering == true) _nes->emulate_frame(controller1, controller2);
|
||||
if (_doRendering == false) _nes->emulate_skip_frame(controller1, controller2);
|
||||
}
|
||||
|
||||
std::string getCoreName() const override { return "QuickNES"; }
|
||||
void doSoftReset() override { _nes->reset(false); }
|
||||
void doHardReset() override { _nes->reset(true); }
|
||||
|
||||
void* getInternalEmulatorPointer() const override { return _nes; }
|
||||
|
||||
private:
|
||||
|
||||
inline size_t getStateSizeImpl() const override
|
||||
{
|
||||
uint8_t* data = (uint8_t*) malloc (_DUMMY_SIZE);
|
||||
Mem_Writer w(data, _DUMMY_SIZE);
|
||||
Auto_File_Writer a(w);
|
||||
_nes->save_state(a);
|
||||
free(data);
|
||||
return w.size();
|
||||
}
|
||||
|
||||
// Video buffer
|
||||
uint8_t video_buffer[image_width * image_height];
|
||||
|
||||
// Emulator instance
|
||||
Nes_Emu* _nes;
|
||||
};
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue