2024-01-10 18:48:57 +00:00
|
|
|
#pragma once
|
|
|
|
|
2024-01-10 19:11:49 +00:00
|
|
|
#include <utils.hpp>
|
2024-01-12 18:14:57 +00:00
|
|
|
#include "sha1/sha1.hpp"
|
2024-01-10 18:48:57 +00:00
|
|
|
|
|
|
|
#define _LOW_MEM_SIZE 0x800
|
|
|
|
#define _HIGH_MEM_SIZE 0x2000
|
2024-01-12 20:13:51 +00:00
|
|
|
#define _NAMETABLES_MEM_SIZE 0x1000
|
2024-01-10 18:48:57 +00:00
|
|
|
|
2024-01-15 19:56:58 +00:00
|
|
|
// Size of image generated in graphics buffer
|
|
|
|
static const uint16_t image_width = 256;
|
|
|
|
static const uint16_t image_height = 240;
|
|
|
|
|
2024-01-10 18:48:57 +00:00
|
|
|
class EmuInstance
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
|
|
|
|
typedef uint8_t inputType;
|
|
|
|
|
2024-01-10 19:11:49 +00:00
|
|
|
// Deleting default constructors
|
2024-01-16 21:39:18 +00:00
|
|
|
virtual ~EmuInstance() = default;
|
2024-01-10 19:11:49 +00:00
|
|
|
|
2024-01-10 18:48:57 +00:00
|
|
|
// Controller input bits
|
|
|
|
// 0 - A / 1
|
|
|
|
// 1 - B / 2
|
|
|
|
// 2 - Select / 4
|
|
|
|
// 3 - Start / 8
|
|
|
|
// 4 - Up / 16
|
|
|
|
// 5 - Down / 32
|
|
|
|
// 6 - Left / 64
|
|
|
|
// 7 - Right / 128
|
|
|
|
|
|
|
|
// Move Format:
|
|
|
|
// RLDUTSBA
|
|
|
|
// ........
|
|
|
|
|
|
|
|
static inline inputType moveStringToCode(const std::string& move)
|
|
|
|
{
|
|
|
|
inputType moveCode = 0;
|
|
|
|
|
|
|
|
for (size_t i = 0; i < move.size(); i++) switch(move[i])
|
|
|
|
{
|
|
|
|
case 'U': moveCode |= 0b00010000; break;
|
|
|
|
case 'D': moveCode |= 0b00100000; break;
|
|
|
|
case 'L': moveCode |= 0b01000000; break;
|
|
|
|
case 'R': moveCode |= 0b10000000; break;
|
|
|
|
case 'S': moveCode |= 0b00001000; break;
|
|
|
|
case 's': moveCode |= 0b00000100; break;
|
|
|
|
case 'B': moveCode |= 0b00000010; break;
|
|
|
|
case 'A': moveCode |= 0b00000001; break;
|
2024-01-13 08:55:07 +00:00
|
|
|
case 'r': break;
|
2024-01-10 18:48:57 +00:00
|
|
|
case '.': break;
|
|
|
|
case '|': break;
|
|
|
|
default: EXIT_WITH_ERROR("Move provided cannot be parsed: '%s', unrecognized character: '%c'\n", move.c_str(), move[i]);
|
|
|
|
}
|
|
|
|
|
|
|
|
return moveCode;
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline std::string moveCodeToString(const inputType move)
|
|
|
|
{
|
|
|
|
#ifndef _NES_PLAYER_2
|
|
|
|
std::string moveString = "|..|";
|
|
|
|
#else
|
|
|
|
std::string moveString = "|..|........|";
|
|
|
|
#endif
|
|
|
|
|
|
|
|
if (move & 0b00010000) moveString += 'U'; else moveString += '.';
|
|
|
|
if (move & 0b00100000) moveString += 'D'; else moveString += '.';
|
|
|
|
if (move & 0b01000000) moveString += 'L'; else moveString += '.';
|
|
|
|
if (move & 0b10000000) moveString += 'R'; else moveString += '.';
|
|
|
|
if (move & 0b00001000) moveString += 'S'; else moveString += '.';
|
|
|
|
if (move & 0b00000100) moveString += 's'; else moveString += '.';
|
|
|
|
if (move & 0b00000010) moveString += 'B'; else moveString += '.';
|
|
|
|
if (move & 0b00000001) moveString += 'A'; else moveString += '.';
|
|
|
|
|
|
|
|
moveString += "|";
|
|
|
|
return moveString;
|
|
|
|
}
|
2024-01-15 19:56:58 +00:00
|
|
|
|
|
|
|
inline void advanceState(const std::string& move)
|
2024-01-10 18:48:57 +00:00
|
|
|
{
|
2024-01-15 19:56:58 +00:00
|
|
|
if (move.find("r") != std::string::npos) doSoftReset();
|
2024-01-13 08:55:07 +00:00
|
|
|
|
2024-01-15 19:56:58 +00:00
|
|
|
advanceStateImpl(moveStringToCode(move), 0);
|
2024-01-10 18:48:57 +00:00
|
|
|
}
|
|
|
|
|
2024-01-15 19:56:58 +00:00
|
|
|
inline size_t getStateSize() const { return _stateSize; }
|
2024-01-18 18:56:30 +00:00
|
|
|
inline size_t getLiteStateSize() const { return _liteStateSize; }
|
2024-01-15 19:56:58 +00:00
|
|
|
inline std::string getRomSHA1() const { return _romSHA1String; }
|
|
|
|
|
|
|
|
inline hash_t getStateHash() const
|
2024-01-10 18:48:57 +00:00
|
|
|
{
|
2024-01-15 19:56:58 +00:00
|
|
|
MetroHash128 hash;
|
2024-01-10 18:48:57 +00:00
|
|
|
|
2024-01-15 19:56:58 +00:00
|
|
|
hash.Update(getLowMem(), _LOW_MEM_SIZE);
|
|
|
|
hash.Update(getHighMem(), _HIGH_MEM_SIZE);
|
|
|
|
hash.Update(getNametableMem(), _NAMETABLES_MEM_SIZE);
|
|
|
|
hash.Update(getChrMem(), getChrMemSize());
|
2024-01-10 18:48:57 +00:00
|
|
|
|
2024-01-15 19:56:58 +00:00
|
|
|
hash_t result;
|
|
|
|
hash.Finalize(reinterpret_cast<uint8_t *>(&result));
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
inline void enableRendering() { _doRendering = true; };
|
|
|
|
inline void disableRendering() { _doRendering = false; };
|
2024-01-14 05:12:32 +00:00
|
|
|
|
2024-01-15 19:56:58 +00:00
|
|
|
inline void loadStateFile(const std::string& stateFilePath)
|
2024-01-10 18:48:57 +00:00
|
|
|
{
|
2024-01-15 19:56:58 +00:00
|
|
|
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());
|
2024-01-10 18:48:57 +00:00
|
|
|
}
|
|
|
|
|
2024-01-15 19:56:58 +00:00
|
|
|
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());
|
2024-01-10 18:48:57 +00:00
|
|
|
|
2024-01-18 18:56:30 +00:00
|
|
|
// Detecting full state size
|
2024-01-15 19:56:58 +00:00
|
|
|
_stateSize = getStateSizeImpl();
|
2024-01-18 18:56:30 +00:00
|
|
|
|
|
|
|
// Detecting lite state size
|
|
|
|
_liteStateSize = getLiteStateSizeImpl();
|
2024-01-15 19:56:58 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// 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;
|
2024-01-18 18:56:30 +00:00
|
|
|
virtual size_t getLiteStateSizeImpl() const { return getStateSizeImpl(); };
|
2024-01-15 19:56:58 +00:00
|
|
|
virtual void doSoftReset() = 0;
|
|
|
|
virtual void doHardReset() = 0;
|
|
|
|
virtual std::string getCoreName() const = 0;
|
|
|
|
virtual void* getInternalEmulatorPointer() const = 0;
|
2024-01-18 18:56:30 +00:00
|
|
|
|
2024-01-15 19:56:58 +00:00
|
|
|
protected:
|
|
|
|
|
|
|
|
EmuInstance() = default;
|
|
|
|
|
2024-01-18 18:56:30 +00:00
|
|
|
// Storage for the light state size
|
|
|
|
size_t _liteStateSize;
|
|
|
|
|
|
|
|
// Storage for the full state size
|
2024-01-10 18:48:57 +00:00
|
|
|
size_t _stateSize;
|
|
|
|
|
2024-01-15 19:56:58 +00:00
|
|
|
// Flag to determine whether to enable/disable rendering
|
|
|
|
bool _doRendering = true;
|
|
|
|
|
|
|
|
private:
|
|
|
|
|
|
|
|
// Storage for the ROM data
|
|
|
|
std::string _romData;
|
|
|
|
|
2024-01-12 18:14:57 +00:00
|
|
|
// SHA1 rom hash
|
|
|
|
std::string _romSHA1String;
|
2024-01-10 18:48:57 +00:00
|
|
|
};
|