Merge branch 'main' into mergeTASEmulators

This commit is contained in:
Sergio Martin 2024-08-11 14:31:45 +02:00 committed by GitHub
commit e8ab40c227
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
115 changed files with 15887 additions and 1997 deletions

View File

@ -22,7 +22,7 @@ jobs:
- name: Installing apt packages
run: sudo apt install libgtest-dev gcovr libtbb-dev libsdl2-dev libsdl2-image-dev
- name: Run meson configuration
run: meson setup build -DonlyOpenSource=true
run: meson setup build -DonlyOpenSource=true -DenableArkanoidInputs=true
- name: Building project
run: ninja -C build
- name: Running tests

4
extern/hqn/hqn.cpp vendored
View File

@ -79,13 +79,13 @@ error_t HQNState::advanceFrame(bool sleep)
SDL_Delay(wantTicks - ticks);
}
// m_frameTime = wantTicks - m_prevFrame;
error_t result = m_emu->emulate_frame(joypad[0], joypad[1]);
// error_t result = m_emu->emulate_frame(joypad[0], joypad[1]);
if (m_listener)
m_listener->onAdvanceFrame(this);
ticks = SDL_GetTicks();
m_frameTime = ticks - m_prevFrame;
m_prevFrame = ticks;
return result;
return 0;
}
void HQNState::setFramerate(int fps)

2
extern/jaffarCommon vendored

@ -1 +1 @@
Subproject commit b7c82dffab2329b332a4d21e37c5b25a2088d29c
Subproject commit e7fd15b6e3ffed9bd718c0bfc0b0a6247e5dfe76

View File

@ -8,6 +8,11 @@ project('quickerNES','c','cpp',
# Loading dependencies
subdir('source')
# Grabbing hqn dependency
hqnSubproject = subproject('hqn')
hqnDependency = hqnSubproject.get_variable('hqnDependency')
# Do not build any targets if this is a subproject
if meson.is_subproject() == false
@ -19,11 +24,6 @@ commonCompileArgs = [ '-Wfatal-errors', '-Wall']
jaffarCommonSubproject = subproject('jaffarCommon')
jaffarCommonDependency = jaffarCommonSubproject.get_variable('jaffarCommonDependency')
# Grabbing hqn dependency
hqnSubproject = subproject('hqn')
hqnDependency = hqnSubproject.get_variable('hqnDependency')
# Building playback tool
if get_option('buildPlayer') == true
executable('player',

View File

@ -26,3 +26,9 @@ option('onlyOpenSource',
yield: true
)
option('enableArkanoidInputs',
type : 'boolean',
value : false,
description : 'Build tests',
yield: true
)

View File

@ -1,213 +0,0 @@
#pragma once
// Base controller class
// by eien86
#include <cstdint>
#include <string>
#include <sstream>
namespace quickNES
{
class Controller
{
public:
enum controller_t { none, joypad, fourscore1, fourscore2 };
typedef uint32_t port_t;
struct input_t
{
bool power = false;
bool reset = false;
port_t port1 = 0;
port_t port2 = 0;
};
inline bool parseInputString(const std::string& input)
{
// Parse valid flag
bool isValid = true;
// Converting input into a stream for parsing
std::istringstream ss(input);
// Start separator
if (ss.get() != '|') isValid = false;
// Parsing console inputs
isValid &= parseConsoleInputs(_input.reset, _input.power, ss);
// Parsing controller 1 inputs
isValid &= parseControllerInputs(_controller1Type, _input.port1, ss);
// Parsing controller 1 inputs
isValid &= parseControllerInputs(_controller2Type, _input.port2, ss);
// End separator
if (ss.get() != '|') isValid = false;
// If its not the end of the stream, then extra values remain and its invalid
ss.get();
if (ss.eof() == false) isValid = false;
// Returning valid flag
return isValid;
};
inline void setController1Type(const controller_t type) { _controller1Type = type; }
inline void setController2Type(const controller_t type) { _controller2Type = type; }
inline bool getPowerButtonState() { return _input.power; }
inline bool getResetButtonState() { return _input.reset; }
inline port_t getController1Code() { return _input.port1; }
inline port_t getController2Code() { return _input.port2; }
private:
static bool parseJoyPadInput(uint8_t& code, std::istringstream& ss)
{
// Currently read character
char c;
// Cleaning code
code = 0;
// Up
c = ss.get();
if (c != '.' && c != 'U') return false;
if (c == 'U') code |= 0b00010000;
// Down
c = ss.get();
if (c != '.' && c != 'D') return false;
if (c == 'D') code |= 0b00100000;
// Left
c = ss.get();
if (c != '.' && c != 'L') return false;
if (c == 'L') code |= 0b01000000;
// Right
c = ss.get();
if (c != '.' && c != 'R') return false;
if (c == 'R') code |= 0b10000000;
// Start
c = ss.get();
if (c != '.' && c != 'S') return false;
if (c == 'S') code |= 0b00001000;
// Select
c = ss.get();
if (c != '.' && c != 's') return false;
if (c == 's') code |= 0b00000100;
// B
c = ss.get();
if (c != '.' && c != 'B') return false;
if (c == 'B') code |= 0b00000010;
// A
c = ss.get();
if (c != '.' && c != 'A') return false;
if (c == 'A') code |= 0b00000001;
return true;
}
static bool parseControllerInputs(const controller_t type, port_t& port, std::istringstream& ss)
{
// Parse valid flag
bool isValid = true;
// If no controller assigned then, its port is all zeroes.
if (type == controller_t::none) { port = 0; return true; }
// Controller separator
if (ss.get() != '|') isValid = false;
// If normal joypad, parse its code now
if (type == controller_t::joypad)
{
// Storage for joypad's code
uint8_t code = 0;
// Parsing joypad code
isValid &= parseJoyPadInput(code, ss);
// Pushing input code into the port
port = code;
// Adding joypad signature
// Per https://www.nesdev.org/wiki/Standard_controller, the joypad reports 1s after the first 8 bits
port |= ~0xFF;
}
// If its fourscore, its like two joypads separated by a |
if (type == controller_t::fourscore1 || type == controller_t::fourscore2)
{
// Storage for joypad's code
uint8_t code1 = 0;
uint8_t code2 = 0;
// Parsing joypad code1
isValid &= parseJoyPadInput(code1, ss);
// Separator
if (ss.get() != '|') return false;
// Parsing joypad code1
isValid &= parseJoyPadInput(code2, ss);
// Creating code
port = code1;
port |= (uint32_t)0 | code2 << 8;
if (type == controller_t::fourscore1) port |= (uint32_t)0 | 1 << 19;
if (type == controller_t::fourscore2) port |= (uint32_t)0 | 1 << 18;
port |= (uint32_t)0 | 1 << 24;
port |= (uint32_t)0 | 1 << 25;
port |= (uint32_t)0 | 1 << 26;
port |= (uint32_t)0 | 1 << 27;
port |= (uint32_t)0 | 1 << 28;
port |= (uint32_t)0 | 1 << 29;
port |= (uint32_t)0 | 1 << 30;
port |= (uint32_t)0 | 1 << 31;
}
// Return valid flag
return isValid;
}
static bool parseConsoleInputs(bool& reset, bool& power, std::istringstream& ss)
{
// Parse valid flag
bool isValid = true;
// Currently read character
char c;
// Power trigger
c = ss.get();
if (c != '.' && c != 'P') isValid = false;
if (c == 'P') power = true;
if (c == '.') power = false;
// Reset trigger
c = ss.get();
if (c != '.' && c != 'r') isValid = false;
if (c == 'r') reset = true;
if (c == '.') reset = false;
// Return valid flag
return isValid;
}
input_t _input;
controller_t _controller1Type;
controller_t _controller2Type;
}; // class Controller
} // namespace quickNES

353
source/inputParser.hpp Normal file
View File

@ -0,0 +1,353 @@
#pragma once
// Base controller class
// by eien86
#include <cstdint>
#include <jaffarCommon/exceptions.hpp>
#include <jaffarCommon/json.hpp>
#include <sstream>
#include <string>
namespace jaffar
{
typedef uint32_t port_t;
struct input_t
{
bool power = false;
bool reset = false;
port_t port1 = 0;
port_t port2 = 0;
port_t arkanoidLatch = 0;
uint8_t arkanoidFire = 0;
};
class InputParser
{
public:
enum controller_t
{
none,
joypad,
fourscore1,
fourscore2,
arkanoidNES,
arkanoidFamicom
};
controller_t _controller1Type;
controller_t _controller2Type;
InputParser(const nlohmann::json &config)
{
// Parsing controller 1 type
{
bool isTypeRecognized = false;
const auto controller1Type = jaffarCommon::json::getString(config, "Controller 1 Type");
if (controller1Type == "None")
{
_controller1Type = controller_t::none;
isTypeRecognized = true;
}
if (controller1Type == "Joypad")
{
_controller1Type = controller_t::joypad;
isTypeRecognized = true;
}
if (controller1Type == "FourScore1")
{
_controller1Type = controller_t::fourscore1;
isTypeRecognized = true;
}
if (controller1Type == "FourScore2")
{
_controller1Type = controller_t::fourscore2;
isTypeRecognized = true;
}
#ifdef _QUICKERNES_SUPPORT_ARKANOID_INPUTS
if (controller1Type == "ArkanoidNES")
{
_controller1Type = controller_t::arkanoidNES;
isTypeRecognized = true;
}
if (controller1Type == "ArkanoidFamicom")
{
_controller1Type = controller_t::arkanoidFamicom;
isTypeRecognized = true;
}
#endif
if (isTypeRecognized == false) JAFFAR_THROW_LOGIC("Controller 1 type not recognized: '%s'\n", controller1Type.c_str());
}
// Parsing controller 2 type
{
bool isTypeRecognized = false;
const auto controller2Type = jaffarCommon::json::getString(config, "Controller 2 Type");
if (controller2Type == "None")
{
_controller2Type = controller_t::none;
isTypeRecognized = true;
}
if (controller2Type == "Joypad")
{
_controller2Type = controller_t::joypad;
isTypeRecognized = true;
}
if (controller2Type == "FourScore1")
{
_controller2Type = controller_t::fourscore1;
isTypeRecognized = true;
}
if (controller2Type == "FourScore2")
{
_controller2Type = controller_t::fourscore2;
isTypeRecognized = true;
}
if (isTypeRecognized == false) JAFFAR_THROW_LOGIC("Controller 2 type not recognized: '%s'\n", controller2Type.c_str());
}
}
inline input_t parseInputString(const std::string &inputString) const
{
// Storage for the input
input_t input;
// Converting input into a stream for parsing
std::istringstream ss(inputString);
// Start separator
if (ss.get() != '|') reportBadInputString(inputString);
// Parsing console inputs
parseConsoleInputs(input.reset, input.power, ss, inputString);
// Parsing controller 1 inputs
if (_controller1Type == arkanoidNES) parseArkanoidNESInput(input, ss, inputString);
if (_controller1Type == arkanoidFamicom) parseArkanoidFamicomInput(input, ss, inputString);
if (_controller1Type == joypad || _controller1Type == fourscore1) parseControllerInputs(_controller1Type, input.port1, ss, inputString);
// Parsing controller 2 inputs
if (_controller2Type == joypad || _controller2Type == fourscore2) parseControllerInputs(_controller2Type, input.port2, ss, inputString);
// End separator
if (ss.get() != '|') reportBadInputString(inputString);
// If its not the end of the stream, then extra values remain and its invalid
ss.get();
if (ss.eof() == false) reportBadInputString(inputString);
return input;
}
private:
static inline void reportBadInputString(const std::string &inputString)
{
JAFFAR_THROW_LOGIC("Could not decode input string: '%s'\n", inputString.c_str());
}
static void parseJoyPadInput(uint8_t &code, std::istringstream &ss, const std::string &inputString)
{
// Currently read character
char c;
// Cleaning code
code = 0;
// Up
c = ss.get();
if (c != '.' && c != 'U') reportBadInputString(inputString);
if (c == 'U') code |= 0b00010000;
// Down
c = ss.get();
if (c != '.' && c != 'D') reportBadInputString(inputString);
if (c == 'D') code |= 0b00100000;
// Left
c = ss.get();
if (c != '.' && c != 'L') reportBadInputString(inputString);
if (c == 'L') code |= 0b01000000;
// Right
c = ss.get();
if (c != '.' && c != 'R') reportBadInputString(inputString);
if (c == 'R') code |= 0b10000000;
// Start
c = ss.get();
if (c != '.' && c != 'S') reportBadInputString(inputString);
if (c == 'S') code |= 0b00001000;
// Select
c = ss.get();
if (c != '.' && c != 's') reportBadInputString(inputString);
if (c == 's') code |= 0b00000100;
// B
c = ss.get();
if (c != '.' && c != 'B') reportBadInputString(inputString);
if (c == 'B') code |= 0b00000010;
// A
c = ss.get();
if (c != '.' && c != 'A') reportBadInputString(inputString);
if (c == 'A') code |= 0b00000001;
}
static inline void parseArkanoidInput(input_t& input, std::istringstream& ss, const std::string& inputString)
{
uint8_t potentiometer = 0;
uint8_t fire = 0;
// Controller separator
if (ss.get() != '|') reportBadInputString(inputString);
if (ss.get() != ' ') reportBadInputString(inputString);
if (ss.get() != ' ') reportBadInputString(inputString);
char c = ss.get(); // Hundreds
if (c != ' ' && c < 48 && c > 57) reportBadInputString(inputString);
if (c != ' ') potentiometer += 100 * ( (uint8_t)c - 48 );
c = ss.get(); // Tenths
if (c != ' ' && c < 48 && c > 57) reportBadInputString(inputString);
if (c != ' ') potentiometer += 10 * ( (uint8_t)c - 48 );
c = ss.get(); // Units
if (c != ' ' && c < 48 && c > 57) reportBadInputString(inputString);
if (c != ' ') potentiometer += (uint8_t)c - 48;
// Comma
if (ss.get() != ',') reportBadInputString(inputString);
// Fire
c = ss.get();
if (c != '.' && c != 'F') reportBadInputString(inputString);
if (c == 'F') fire = 1;
// Fire is encoded in port 1
input.arkanoidFire = fire;
// Potentiometer is encoded in port 2 - MSB and adding one bit for signalling the presence of the potentiometer, subtracted from 173
uint8_t subtracter = 171 - potentiometer;
input.arkanoidLatch = 0;
if ((subtracter & 128) > 0) input.arkanoidLatch += 1;
if ((subtracter & 64) > 0) input.arkanoidLatch += 2;
if ((subtracter & 32) > 0) input.arkanoidLatch += 4;
if ((subtracter & 16) > 0) input.arkanoidLatch += 8;
if ((subtracter & 8) > 0) input.arkanoidLatch += 16;
if ((subtracter & 4) > 0) input.arkanoidLatch += 32;
if ((subtracter & 2) > 0) input.arkanoidLatch += 64;
if ((subtracter & 1) > 0) input.arkanoidLatch += 128;
}
static void parseControllerInputs(const controller_t type, port_t &port, std::istringstream &ss, const std::string &inputString)
{
// If no controller assigned then, its port is all zeroes.
if (type == controller_t::none)
{
port = 0;
return;
}
// Controller separator
if (ss.get() != '|') reportBadInputString(inputString);
// If normal joypad, parse its code now
if (type == controller_t::joypad)
{
// Storage for joypad's code
uint8_t code = 0;
// Parsing joypad code
parseJoyPadInput(code, ss, inputString);
// Pushing input code into the port
port = code;
// Adding joypad signature
// Per https://www.nesdev.org/wiki/Standard_controller, the joypad reports 1s after the first 8 bits
port |= ~0xFF;
}
// If its fourscore, its like two joypads separated by a |
if (type == controller_t::fourscore1 || type == controller_t::fourscore2)
{
// Storage for joypad's code
uint8_t code1 = 0;
uint8_t code2 = 0;
// Parsing joypad code1
parseJoyPadInput(code1, ss, inputString);
// Separator
if (ss.get() != '|') reportBadInputString(inputString);
// Parsing joypad code1
parseJoyPadInput(code2, ss, inputString);
// Creating code
port = code1;
port |= (uint32_t)0 | code2 << 8;
if (type == controller_t::fourscore1) port |= (uint32_t)0 | 1 << 19;
if (type == controller_t::fourscore2) port |= (uint32_t)0 | 1 << 18;
port |= (uint32_t)0 | 1 << 24;
port |= (uint32_t)0 | 1 << 25;
port |= (uint32_t)0 | 1 << 26;
port |= (uint32_t)0 | 1 << 27;
port |= (uint32_t)0 | 1 << 28;
port |= (uint32_t)0 | 1 << 29;
port |= (uint32_t)0 | 1 << 30;
port |= (uint32_t)0 | 1 << 31;
}
}
static inline void parseArkanoidNESInput(input_t& input, std::istringstream& ss, const std::string& inputString)
{
// Simply parse the arkanoid controller input
parseArkanoidInput(input, ss, inputString);
}
static inline void parseArkanoidFamicomInput(input_t& input, std::istringstream& ss, const std::string& inputString)
{
// Parsing joypad controller
parseControllerInputs(controller_t::joypad, input.port1, ss, inputString);
// Controller separator
if (ss.get() != '|') reportBadInputString(inputString);
// Advancing 7 positions (this input is not supported)
for (size_t i = 0; i < 7; i++) if (ss.get() != '.') reportBadInputString(inputString);
// Then, parse the arkanoid controller input
parseArkanoidInput(input, ss, inputString);
}
static void parseConsoleInputs(bool &reset, bool &power, std::istringstream &ss, const std::string &inputString)
{
// Currently read character
char c;
// Power trigger
c = ss.get();
if (c != '.' && c != 'P') reportBadInputString(inputString);
if (c == 'P') power = true;
if (c == '.') power = false;
// Reset trigger
c = ss.get();
if (c != '.' && c != 'r') reportBadInputString(inputString);
if (c == 'r') reset = true;
if (c == '.') reset = false;
}
}; // class InputParser
} // namespace jaffar

View File

@ -1,9 +1,10 @@
#pragma once
#include "inputParser.hpp"
#include "jaffarCommon/logger.hpp"
#include "jaffarCommon/serializers/contiguous.hpp"
#include "jaffarCommon/serializers/differential.hpp"
#include "jaffarCommon/logger.hpp"
#include "controller.hpp"
#include "jaffarCommon/deserializers/base.hpp"
// Size of image generated in graphics buffer
static const uint16_t image_width = 256;
@ -12,51 +13,14 @@ static const uint16_t image_height = 240;
class NESInstanceBase
{
public:
NESInstanceBase(const nlohmann::json &config)
{
_inputParser = std::make_unique<jaffar::InputParser>(config);
}
NESInstanceBase() = default;
virtual ~NESInstanceBase() = default;
inline void advanceState(const std::string &move)
{
bool isInputValid = _controller.parseInputString(move);
if (isInputValid == false) JAFFAR_THROW_LOGIC("Move provided cannot be parsed: '%s'\n", move.c_str());
// Parsing power
if (_controller.getPowerButtonState() == true) JAFFAR_THROW_LOGIC("Power button pressed, but not supported: '%s'\n", move.c_str());
// Parsing reset
if (_controller.getResetButtonState() == true) doSoftReset();
// Parsing Controllers
const auto controller1 = _controller.getController1Code();
const auto controller2 = _controller.getController2Code();
advanceStateImpl(controller1, controller2);
}
inline void setController1Type(const std::string& type)
{
bool isTypeRecognized = false;
if (type == "None") { _controller.setController1Type(quickNES::Controller::controller_t::none); isTypeRecognized = true; }
if (type == "Joypad") { _controller.setController1Type(quickNES::Controller::controller_t::joypad); isTypeRecognized = true; }
if (type == "FourScore1") { _controller.setController1Type(quickNES::Controller::controller_t::fourscore1); isTypeRecognized = true; }
if (type == "FourScore2") { _controller.setController1Type(quickNES::Controller::controller_t::fourscore2); isTypeRecognized = true; }
if (isTypeRecognized == false) JAFFAR_THROW_LOGIC("Input type not recognized: '%s'\n", type.c_str());
}
inline void setController2Type(const std::string& type)
{
bool isTypeRecognized = false;
if (type == "None") { _controller.setController2Type(quickNES::Controller::controller_t::none); isTypeRecognized = true; }
if (type == "Joypad") { _controller.setController2Type(quickNES::Controller::controller_t::joypad); isTypeRecognized = true; }
if (type == "FourScore1") { _controller.setController2Type(quickNES::Controller::controller_t::fourscore1); isTypeRecognized = true; }
if (type == "FourScore2") { _controller.setController2Type(quickNES::Controller::controller_t::fourscore2); isTypeRecognized = true; }
if (isTypeRecognized == false) JAFFAR_THROW_LOGIC("Input type not recognized: '%s'\n", type.c_str());
}
virtual void advanceState(const jaffar::input_t &input) = 0;
inline void enableRendering() { _doRendering = true; };
inline void disableRendering() { _doRendering = false; };
@ -93,6 +57,7 @@ class NESInstanceBase
virtual size_t getFullStateSize() const = 0;
virtual size_t getDifferentialStateSize() const = 0;
inline jaffar::InputParser *getInputParser() const { return _inputParser.get(); }
// Virtual functions
@ -106,13 +71,12 @@ class NESInstanceBase
virtual void doHardReset() = 0;
virtual std::string getCoreName() const = 0;
virtual void *getInternalEmulatorPointer() = 0;
virtual void setNTABBlockSize(const size_t size) {};
protected:
virtual void enableStateBlockImpl(const std::string &block) = 0;
virtual void disableStateBlockImpl(const std::string &block) = 0;
virtual bool loadROMImpl(const uint8_t *romData, const size_t romSize) = 0;
virtual void advanceStateImpl(const quickNES::Controller::port_t controller1, const quickNES::Controller::port_t controller2) = 0;
// Storage for the light state size
size_t _stateSize;
@ -120,8 +84,6 @@ class NESInstanceBase
// Flag to determine whether to enable/disable rendering
bool _doRendering = true;
private:
// Controller class for input parsing
quickNES::Controller _controller;
// Input parser instance
std::unique_ptr<jaffar::InputParser> _inputParser;
};

View File

@ -1,21 +1,22 @@
#pragma once
#include <string>
#include <unistd.h>
#include "nesInstance.hpp"
#include <SDL.h>
#include <SDL_image.h>
#include <extern/hqn/hqn.h>
#include <extern/hqn/hqn_gui_controller.h>
#include <jaffarCommon/serializers/contiguous.hpp>
#include <jaffarCommon/deserializers/contiguous.hpp>
#include <jaffarCommon/hash.hpp>
#include "nesInstance.hpp"
#include <jaffarCommon/serializers/contiguous.hpp>
#include <string>
#include <unistd.h>
#define _INVERSE_FRAME_RATE 16667
struct stepData_t
{
std::string input;
std::string inputString;
jaffar::input_t decodedInput;
uint8_t *stateData;
jaffarCommon::hash::hash_t hash;
};
@ -26,10 +27,11 @@ class PlaybackInstance
static const uint16_t image_height = 240;
public:
void addStep(const std::string &input)
void addStep(const std::string &inputString, const jaffar::input_t decodedInput)
{
stepData_t step;
step.input = input;
step.inputString = inputString;
step.decodedInput = decodedInput;
step.stateData = (uint8_t *)malloc(_emu->getFullStateSize());
jaffarCommon::serializer::Contiguous serializer(step.stateData);
@ -92,18 +94,24 @@ class PlaybackInstance
void initialize(const std::vector<std::string> &sequence)
{
// Getting input decoder
auto inputParser = _emu->getInputParser();
// Building sequence information
for (const auto &input : sequence)
{
// Getting decoded input
const auto decodedInput = inputParser->parseInputString(input);
// Adding new step
addStep(input);
addStep(input, decodedInput);
// Advance state based on the input received
_emu->advanceState(input);
_emu->advanceState(decodedInput);
}
// Adding last step with no input
addStep("<End Of Sequence>");
addStep("<End Of Sequence>", jaffar::input_t());
}
void enableRendering(SDL_Window *window)
@ -149,14 +157,14 @@ class PlaybackInstance
// Load correct overlay images, if using overlay
if (_useOverlay == true)
{
if (step.input.find("A") != std::string::npos) overlayButtonASurface = _overlayButtonASurface;
if (step.input.find("B") != std::string::npos) overlayButtonBSurface = _overlayButtonBSurface;
if (step.input.find("S") != std::string::npos) overlayButtonSelectSurface = _overlayButtonSelectSurface;
if (step.input.find("T") != std::string::npos) overlayButtonStartSurface = _overlayButtonStartSurface;
if (step.input.find("L") != std::string::npos) overlayButtonLeftSurface = _overlayButtonLeftSurface;
if (step.input.find("R") != std::string::npos) overlayButtonRightSurface = _overlayButtonRightSurface;
if (step.input.find("U") != std::string::npos) overlayButtonUpSurface = _overlayButtonUpSurface;
if (step.input.find("D") != std::string::npos) overlayButtonDownSurface = _overlayButtonDownSurface;
if (step.inputString.find("A") != std::string::npos) overlayButtonASurface = _overlayButtonASurface;
if (step.inputString.find("B") != std::string::npos) overlayButtonBSurface = _overlayButtonBSurface;
if (step.inputString.find("S") != std::string::npos) overlayButtonSelectSurface = _overlayButtonSelectSurface;
if (step.inputString.find("T") != std::string::npos) overlayButtonStartSurface = _overlayButtonStartSurface;
if (step.inputString.find("L") != std::string::npos) overlayButtonLeftSurface = _overlayButtonLeftSurface;
if (step.inputString.find("R") != std::string::npos) overlayButtonRightSurface = _overlayButtonRightSurface;
if (step.inputString.find("U") != std::string::npos) overlayButtonUpSurface = _overlayButtonUpSurface;
if (step.inputString.find("D") != std::string::npos) overlayButtonDownSurface = _overlayButtonDownSurface;
}
// Since we do not store the blit information (too much memory), we need to load the previous frame and re-run the input
@ -170,7 +178,7 @@ class PlaybackInstance
const auto stateData = getStateData(stepId - 1);
jaffarCommon::deserializer::Contiguous deserializer(stateData);
_emu->deserializeState(deserializer);
_emu->advanceState(getStateInput(stepId - 1));
_emu->advanceState(getDecodedInput(stepId - 1));
}
// Updating image
@ -184,7 +192,7 @@ class PlaybackInstance
return _stepSequence.size();
}
const std::string getInput(const size_t stepId) const
const std::string getInputString(const size_t stepId) const
{
// Checking the required step id does not exceed contents of the sequence
if (stepId > _stepSequence.size()) JAFFAR_THROW_LOGIC("[Error] Attempting to render a step larger than the step sequence");
@ -193,7 +201,19 @@ class PlaybackInstance
const auto &step = _stepSequence[stepId];
// Returning step input
return step.input;
return step.inputString;
}
const jaffar::input_t getDecodedInput(const size_t stepId) const
{
// Checking the required step id does not exceed contents of the sequence
if (stepId > _stepSequence.size()) JAFFAR_THROW_LOGIC("[Error] Attempting to render a step larger than the step sequence");
// Getting step information
const auto &step = _stepSequence[stepId];
// Returning step input
return step.decodedInput;
}
const uint8_t *getStateData(const size_t stepId) const
@ -220,20 +240,8 @@ class PlaybackInstance
return step.hash;
}
const std::string getStateInput(const size_t stepId) const
{
// Checking the required step id does not exceed contents of the sequence
if (stepId > _stepSequence.size()) JAFFAR_THROW_LOGIC("[Error] Attempting to render a step larger than the step sequence");
// Getting step information
const auto &step = _stepSequence[stepId];
// Returning step input
return step.input;
}
private:
// Internal sequence information
std::vector<stepData_t> _stepSequence;

View File

@ -1,12 +1,12 @@
#include <cstdlib>
#include "argparse/argparse.hpp"
#include "jaffarCommon/serializers/contiguous.hpp"
#include "jaffarCommon/deserializers/contiguous.hpp"
#include "jaffarCommon/file.hpp"
#include "jaffarCommon/logger.hpp"
#include "jaffarCommon/serializers/contiguous.hpp"
#include "jaffarCommon/string.hpp"
#include "nesInstance.hpp"
#include "playbackInstance.hpp"
#include <cstdlib>
SDL_Window *launchOutputWindow()
{
@ -97,7 +97,7 @@ int main(int argc, char *argv[])
if (status == false) JAFFAR_THROW_LOGIC("[ERROR] Could not find or read from sequence file: %s\n", sequenceFilePath.c_str());
// Building sequence information
const auto sequence = jaffarCommon::string::split(inputSequence, ' ');
const auto sequence = jaffarCommon::string::split(inputSequence, '\n');
// Initializing terminal
jaffarCommon::logger::initializeTerminal();
@ -112,11 +112,10 @@ int main(int argc, char *argv[])
jaffarCommon::logger::refreshTerminal();
// Creating emulator instance
NESInstance e;
// Setting controller types
e.setController1Type(controller1Type);
e.setController2Type(controller2Type);
nlohmann::json emulatorConfig;
emulatorConfig["Controller 1 Type"] = controller1Type;
emulatorConfig["Controller 2 Type"] = controller2Type;
NESInstance e(emulatorConfig);
// Loading ROM File
std::string romFileData;
@ -166,7 +165,7 @@ int main(int argc, char *argv[])
if (disableRender == false) p.renderFrame(currentStep);
// Getting input
const auto &input = p.getStateInput(currentStep);
const auto &inputString = p.getInputString(currentStep);
// Getting state hash
const auto hash = p.getStateHash(currentStep);
@ -181,8 +180,9 @@ int main(int argc, char *argv[])
jaffarCommon::logger::log("[] ----------------------------------------------------------------\n");
jaffarCommon::logger::log("[] Current Step #: %lu / %lu\n", currentStep + 1, sequenceLength);
jaffarCommon::logger::log("[] Input: %s\n", input.c_str());
jaffarCommon::logger::log("[] Input: %s\n", inputString.c_str());
jaffarCommon::logger::log("[] State Hash: 0x%lX%lX\n", hash.first, hash.second);
jaffarCommon::logger::log("[] Paddle X: %u\n", e.getLowMem()[0x11A]);
// Only print commands if not in reproduce mode
if (isReproduce == false) jaffarCommon::logger::log("[] Commands: n: -1 m: +1 | h: -10 | j: +10 | y: -100 | u: +100 | k: -1000 | i: +1000 | s: quicksave | p: play | q: quit\n");

View File

@ -73,5 +73,8 @@ quickNESSrc = [
quickNESDependency = declare_dependency(
compile_args : [ ],
include_directories : include_directories(['.', 'core/nes_emu']),
sources : [ quickNESSrc ]
sources : [ quickNESSrc ],
dependencies : [
dependency('sdl2'),
]
)

View File

@ -1,10 +1,10 @@
#pragma once
#include "jaffarCommon/serializers/base.hpp"
#include "jaffarCommon/deserializers/base.hpp"
#include "../nesInstanceBase.hpp"
#include "core/nes_emu/Nes_Emu.h"
#include "core/nes_emu/Nes_State.h"
#include "../nesInstanceBase.hpp"
#include "jaffarCommon/deserializers/base.hpp"
#include "jaffarCommon/serializers/base.hpp"
#define _DUMMY_SIZE 65536
@ -17,7 +17,7 @@ extern void register_mapper_70();
class NESInstance final : public NESInstanceBase
{
public:
NESInstance() : NESInstanceBase()
NESInstance(const nlohmann::json &config) : NESInstanceBase(config)
{
// If running the original QuickNES, register extra mappers now
register_misc_mappers();
@ -60,8 +60,13 @@ class NESInstance final : public NESInstanceBase
void *getInternalEmulatorPointer() override { return &_nes; }
protected:
void advanceState(const jaffar::input_t &input) override
{
if (_doRendering == true) _nes.emulate_frame(input.port1, input.port2);
if (_doRendering == false) _nes.emulate_skip_frame(input.port1, input.port2);
}
protected:
bool loadROMImpl(const uint8_t *romData, const size_t romSize) override
{
// Loading rom data
@ -74,14 +79,7 @@ class NESInstance final : public NESInstanceBase
void enableStateBlockImpl(const std::string &block) override {};
void disableStateBlockImpl(const std::string &block) override {};
void advanceStateImpl(const quickNES::Controller::port_t controller1, const quickNES::Controller::port_t controller2) override
{
if (_doRendering == true) _nes.emulate_frame(controller1, controller2);
if (_doRendering == false) _nes.emulate_skip_frame(controller1, controller2);
}
private:
// Emulator instance
emulator_t _nes;
};

View File

@ -82,4 +82,4 @@ void Nes_Effects_Buffer::RestoreAudioBufferState()
{
}
} // namespace quickNES
} // namespace quickerNES

View File

@ -3,8 +3,8 @@
// Effects_Buffer with non-linear sound
// Nes_Emu 0.7.0
#include "effectsBuffer.hpp"
#include "buffer.hpp"
#include "effectsBuffer.hpp"
namespace quickerNES
{
@ -38,4 +38,4 @@ class Nes_Effects_Buffer : public Effects_Buffer
friend Multi_Buffer *set_apu(Nes_Effects_Buffer *, Apu *);
};
} // namespace quickNES
} // namespace quickerNES

View File

@ -372,4 +372,4 @@ int Apu::read_status(nes_time_t time)
return result;
}
} // namespace quickNES
} // namespace quickerNES

View File

@ -3,9 +3,9 @@
// NES 2A03 APU sound chip emulator
// Snd_Emu 0.1.7
#include "oscs.hpp"
#include <climits>
#include <cstdint>
#include "oscs.hpp"
namespace quickerNES
{
@ -360,4 +360,4 @@ inline void Apu::load_state(apu_state_t const &state)
dmc.run(last_time, last_time);
}
} // namespace quickNES
} // namespace quickerNES

View File

@ -1,11 +1,11 @@
// Blip_Buffer 0.4.0. http://www.slack.net/~ant/
#include "blipBuffer.hpp"
#include <climits>
#include <cmath>
#include <cstdlib>
#include <cstring>
#include "blipBuffer.hpp"
/* Copyright (C) 2003-2006 Shay Green. This module is free software; you
can redistribute it and/or modify it under the terms of the GNU Lesser
@ -419,4 +419,4 @@ void Blip_Buffer::RestoreAudioBufferState()
memcpy(buffer_, extra_buffer, sizeof(extra_buffer));
}
} // namespace quickNES
} // namespace quickerNES

View File

@ -377,4 +377,4 @@ inline int Blip_Reader::begin(Blip_Buffer &blip_buf)
int const blip_max_length = 0;
int const blip_default_length = 250;
} // namespace quickNES
} // namespace quickerNES

View File

@ -227,4 +227,4 @@ void Nonlinearizer::RestoreAudioBufferState()
prev = extra_prev;
}
} // namespace quickNES
} // namespace quickerNES

View File

@ -3,8 +3,8 @@
// NES non-linear audio buffer
// Emu 0.7.0
#include <cstdint>
#include "multiBuffer.hpp"
#include <cstdint>
namespace quickerNES
{
@ -79,4 +79,4 @@ class Buffer : public Multi_Buffer
virtual void RestoreAudioBufferState();
};
} // namespace quickNES
} // namespace quickerNES

View File

@ -1,7 +1,7 @@
// Game_Music_Emu 0.3.0. http://www.slack.net/~ant/
#include <cstring>
#include "effectsBuffer.hpp"
#include <cstring>
/* Copyright (C) 2003-2006 Shay Green. This module is free software; you
can redistribute it and/or modify it under the terms of the GNU Lesser
@ -515,4 +515,4 @@ void Effects_Buffer::mix_enhanced(blip_sample_t *out, long count)
r2.end(bufs[6]);
}
} // namespace quickNES
} // namespace quickerNES

View File

@ -3,8 +3,8 @@
// Multi-channel effects buffer with panning, echo and reverb
// Game_Music_Emu 0.3.0
#include <stdint.h>
#include "multiBuffer.hpp"
#include <stdint.h>
namespace quickerNES
{
@ -101,4 +101,4 @@ inline Effects_Buffer::channel_t Effects_Buffer::channel(int i)
return channels[i % chan_count];
}
} // namespace quickNES
} // namespace quickerNES

View File

@ -105,4 +105,4 @@ void Fme7_Apu::run_until(blip_time_t end_time)
last_time = end_time;
}
} // namespace quickNES
} // namespace quickerNES

View File

@ -3,8 +3,8 @@
// Sunsoft FME-7 sound emulator
// Emu 0.7.0
#include <cstdint>
#include "../blipBuffer.hpp"
#include <cstdint>
namespace quickerNES
{
@ -152,4 +152,4 @@ inline void Fme7_Apu::load_state(fme7_apu_state_t const &in)
run_until(last_time);
}
} // namespace quickNES
} // namespace quickerNES

View File

@ -1,8 +1,8 @@
// Blip_Buffer 0.4.0. http://www.slack.net/~ant/
#include <cstdint>
#include "multiBuffer.hpp"
#include <cstdint>
/* Copyright (C) 2003-2006 Shay Green. This module is free software; you
can redistribute it and/or modify it under the terms of the GNU Lesser
@ -284,4 +284,4 @@ void Stereo_Buffer::RestoreAudioBufferState()
right()->RestoreAudioBufferState();
}
} // namespace quickNES
} // namespace quickerNES

View File

@ -199,4 +199,4 @@ inline long Mono_Buffer::read_samples(blip_sample_t *p, long s) { return buf.rea
inline long Mono_Buffer::samples_avail() const { return buf.samples_avail(); }
} // namespace quickNES
} // namespace quickerNES

View File

@ -180,4 +180,4 @@ void Namco_Apu::load_state(namco_state_t const &in)
run_until(last_time);
}
} // namespace quickNES
} // namespace quickerNES

View File

@ -3,8 +3,8 @@
// Namco 106 sound chip emulator
// Snd_Emu 0.1.7
#include <cstdint>
#include "../apu.hpp"
#include <cstdint>
namespace quickerNES
{
@ -112,4 +112,4 @@ inline void Namco_Apu::write_data(nes_time_t time, int data)
access() = data;
}
} // namespace quickNES
} // namespace quickerNES

View File

@ -679,4 +679,4 @@ void Noise::run(nes_time_t time, nes_time_t end_time)
delay = time - end_time;
}
} // namespace quickNES
} // namespace quickerNES

View File

@ -169,4 +169,4 @@ struct Dmc : Osc
nes_time_t next_read_time() const;
};
} // namespace quickNES
} // namespace quickerNES

View File

@ -212,4 +212,4 @@ void Vrc6_Apu::run_saw(nes_time_t end_time)
osc.last_amp = last_amp;
}
} // namespace quickNES
} // namespace quickerNES

View File

@ -4,9 +4,9 @@
// Konami VRC6 sound chip emulator
// Snd_Emu 0.1.7
#include <cstdint>
#include "../blipBuffer.hpp"
#include "../apu.hpp"
#include "../blipBuffer.hpp"
#include <cstdint>
namespace quickerNES
{
@ -109,4 +109,4 @@ inline void Vrc6_Apu::treble_eq(blip_eq_t const &eq)
square_synth.treble_eq(eq);
}
} // namespace quickNES
} // namespace quickerNES

View File

@ -1,6 +1,6 @@
#include <cstring>
#include "apu_vrc7.hpp"
#include "emu2413.hpp"
#include <cstring>
namespace quickerNES
{
@ -208,4 +208,4 @@ void Vrc7::update_last_amp()
}
}
} // namespace quickNES
} // namespace quickerNES

View File

@ -4,9 +4,9 @@
// Konami VRC7 sound chip emulator
// Snd_Emu 0.1.7. Copyright (C) 2003-2005 Shay Green. GNU LGPL license.
#include <cstdint>
#include "../blipBuffer.hpp"
#include "emu2413_state.hpp"
#include <cstdint>
namespace quickerNES
{
@ -76,4 +76,4 @@ inline void Vrc7::osc_output(int i, Blip_Buffer *buf)
oscs[i].output = buf;
}
} // namespace quickNES
} // namespace quickerNES

View File

@ -1152,4 +1152,4 @@ void OPLL_writeIO(OPLL *opll, e_uint32 adr, e_uint32 val)
opll->adr = val;
}
} // namespace quickNES
} // namespace quickerNES

View File

@ -220,4 +220,4 @@ extern "C"
}
#endif
} // namespace quickNES
} // namespace quickerNES

View File

@ -38,4 +38,4 @@ extern "C"
}
#endif
} // namespace quickNES
} // namespace quickerNES

View File

@ -114,4 +114,4 @@ class Cart
unsigned mapper;
};
} // namespace quickNES
} // namespace quickerNES

View File

@ -15,15 +15,16 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
// Emu 0.7.0
#include <stdexcept>
#include "cpu.hpp"
#include "apu/apu.hpp"
#include "cpu.hpp"
#include "mappers/mapper.hpp"
#include "ppu/ppu.hpp"
#include <cstdint>
#include <cstdio>
#include <string>
#include <jaffarCommon/serializers/base.hpp>
#include <jaffarCommon/deserializers/base.hpp>
#include <jaffarCommon/serializers/base.hpp>
#include <stdexcept>
#include <string>
namespace quickerNES
{
@ -57,14 +58,17 @@ struct nes_state_lite_t
uint8_t frame_count; // number of frames emulated since power-up
};
struct joypad_state_t
struct input_state_t
{
uint32_t joypad_latches[2]; // joypad 1 & 2 shift registers
uint32_t joypad_latches[2]; // input_state 1 & 2 shift registers
#ifdef _QUICKERNES_SUPPORT_ARKANOID_INPUTS
uint32_t arkanoid_latch; // arkanoid latch
uint8_t arkanoid_fire; // arkanoid latch
#endif
uint8_t w4016; // strobe
uint8_t unused[3];
};
static_assert(sizeof(joypad_state_t) == 12);
struct cpu_state_t
{
@ -83,6 +87,7 @@ class Core : private Cpu
typedef Cpu cpu;
public:
size_t _NTABBlockSize = 0x1000;
// Flags for lite state storage
bool TIMEBlockEnabled = true;
@ -97,13 +102,22 @@ class Core : private Cpu
bool CHRRBlockEnabled = true;
bool SRAMBlockEnabled = true;
// APU and Joypad
enum controllerType_t
{
none_t,
joypad_t,
arkanoidNES_t,
arkanoidFamicom_t,
};
Core() : ppu(this)
{
cart = NULL;
impl = NULL;
mapper = NULL;
memset(&nes, 0, sizeof nes);
memset(&joypad, 0, sizeof joypad);
memset(&input_state, 0, sizeof input_state);
}
~Core()
@ -205,8 +219,8 @@ class Core : private Cpu
// CTRL Block
if (CTRLBlockEnabled == true)
{
const auto inputDataSize = sizeof(joypad_state_t);
const auto inputData = (uint8_t *)&joypad;
const auto inputDataSize = sizeof(input_state_t);
const auto inputData = (uint8_t *)&input_state;
serializer.pushContiguous(inputData, inputDataSize);
}
@ -237,9 +251,7 @@ class Core : private Cpu
// NTAB Block
if (NTABBlockEnabled == true)
{
size_t nametable_size = 0x1000;
const auto inputDataSize = nametable_size;
const auto inputDataSize = _NTABBlockSize;
const auto inputData = (uint8_t *)ppu.impl->nt_ram;
serializer.push(inputData, inputDataSize);
}
@ -324,8 +336,8 @@ class Core : private Cpu
// CTRL Block
if (CTRLBlockEnabled == true)
{
const auto outputData = (uint8_t*) &joypad;
const auto inputDataSize = sizeof(joypad_state_t);
const auto outputData = (uint8_t *)&input_state;
const auto inputDataSize = sizeof(input_state_t);
deserializer.popContiguous(outputData, inputDataSize);
}
@ -360,10 +372,8 @@ class Core : private Cpu
// NTAB Block
if (NTABBlockEnabled == true)
{
size_t nametable_size = 0x1000;
const auto outputData = (uint8_t *)ppu.impl->nt_ram;
const auto inputDataSize = nametable_size;
const auto inputDataSize = _NTABBlockSize;
deserializer.pop(outputData, inputDataSize);
}
@ -394,46 +404,142 @@ class Core : private Cpu
if (sram_present) enable_sram(true);
}
void setNTABBlockSize(const size_t size) { _NTABBlockSize = size; }
void enableStateBlock(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 (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);}
if (recognizedBlock == false)
{
fprintf(stderr, "Unrecognized block type: %s\n", block.c_str());
exit(-1);
}
};
void disableStateBlock(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 (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);}
if (recognizedBlock == false)
{
fprintf(stderr, "Unrecognized block type: %s\n", block.c_str());
exit(-1);
}
};
void reset(bool full_reset, bool erase_battery_ram)
{
if (full_reset)
@ -456,8 +562,13 @@ void disableStateBlock(const std::string& block)
if (!cart->has_battery_ram() || erase_battery_ram)
memset(impl->sram, 0xFF, impl->sram_size);
joypad.joypad_latches[0] = 0;
joypad.joypad_latches[1] = 0;
input_state.joypad_latches[0] = 0;
input_state.joypad_latches[1] = 0;
#ifdef _QUICKERNES_SUPPORT_ARKANOID_INPUTS
input_state.arkanoid_latch = 0;
input_state.arkanoid_fire = 0;
#endif
nes.frame_count = 0;
}
@ -479,7 +590,7 @@ void disableStateBlock(const std::string& block)
error_count = 0;
}
nes_time_t emulate_frame(uint32_t joypad1, uint32_t joypad2)
nes_time_t emulate_frame(uint32_t joypad1, uint32_t joypad2, uint32_t arkanoid_latch, uint8_t arkanoid_fire)
{
#ifdef _QUICKERNES_DETECT_JOYPAD_READS
joypad_read_count = 0;
@ -487,6 +598,8 @@ void disableStateBlock(const std::string& block)
current_joypad[0] = joypad1;
current_joypad[1] = joypad2;
current_arkanoid_latch = arkanoid_latch;
current_arkanoid_fire = arkanoid_fire;
cpu_time_offset = ppu.begin_frame(nes.timestamp) - 1;
ppu_2002_time = 0;
@ -556,6 +669,8 @@ void disableStateBlock(const std::string& block)
public:
uint32_t current_joypad[2];
uint32_t current_arkanoid_latch;
uint8_t current_arkanoid_fire;
Cart const *cart;
Mapper *mapper;
nes_state_t nes;
@ -604,9 +719,14 @@ void disableStateBlock(const std::string& block)
return t;
}
// APU and Joypad
joypad_state_t joypad;
controllerType_t _controllerType = controllerType_t::none_t;
input_state_t input_state;
void setControllerType(controllerType_t type) { _controllerType = type; }
#ifdef _QUICKERNES_SUPPORT_ARKANOID_INPUTS
int read_io(nes_addr_t addr)
{
if ((addr & 0xFFFE) == 0x4016)
@ -616,12 +736,81 @@ void disableStateBlock(const std::string& block)
joypad_read_count++;
#endif
// If write flag is put into w4016, reading from it returns nothing
if (input_state.w4016 & 1) return 0;
// Proceed depending on input type
switch(_controllerType)
{
case controllerType_t::joypad_t:
{
const uint8_t result = input_state.joypad_latches[addr & 1] & 1;
input_state.joypad_latches[addr & 1] >>= 1;
return result;
}
case controllerType_t::arkanoidNES_t:
{
if (addr == 0x4017)
{
// latch 0 encodes fire, latch 1 encodes potentiometer
const uint8_t result = (input_state.arkanoid_latch & 1) * 16 + input_state.arkanoid_fire * 8;
// Advancing latch 1
input_state.arkanoid_latch >>= 1;
return result;
}
}
case controllerType_t::arkanoidFamicom_t:
{
if (addr == 0x4016)
{
// latch 0 encodes fire
uint8_t result = (input_state.arkanoid_fire & 1) * 2;
// latch 0 also encodes input_state 1
result += (input_state.joypad_latches[0] & 1) & 1;
// Advancing input_state latch
input_state.joypad_latches[0] >>= 1;
return result;
}
if (addr == 0x4017)
{
// latch 1 encodes potentiometer
const uint8_t result = (input_state.arkanoid_latch & 1) * 2;
// Advancing latch 1
input_state.arkanoid_latch >>= 1;
return result;
}
}
default:
return 0;
}
}
if (addr == Apu::status_addr)
return impl->apu.read_status(clock());
return addr >> 8; // simulate open bus
}
#else
int read_io(nes_addr_t addr)
{
if ((addr & 0xFFFE) == 0x4016)
{
// to do: to aid with recording, doesn't emulate transparent latch,
// so a game that held strobe at 1 and read $4016 or $4017 would not get
// the current A status as occurs on a NES
if (joypad.w4016 & 1) return 0;
const uint8_t result = joypad.joypad_latches[addr & 1] & 1;
joypad.joypad_latches[addr & 1] >>= 1;
if (input_state.w4016 & 1) return 0;
const uint8_t result = input_state.joypad_latches[addr & 1] & 1;
input_state.joypad_latches[addr & 1] >>= 1;
return result;
}
@ -630,6 +819,7 @@ void disableStateBlock(const std::string& block)
return addr >> 8; // simulate open bus
}
#endif
void write_io(nes_addr_t addr, int data)
{
@ -641,16 +831,21 @@ void disableStateBlock(const std::string& block)
return;
}
// joypad strobe
// input_state strobe
if (addr == 0x4016)
{
// if strobe goes low, latch data
if (joypad.w4016 & 1 & ~data)
if (input_state.w4016 & 1 & ~data)
{
joypad.joypad_latches[0] = current_joypad[0];
joypad.joypad_latches[1] = current_joypad[1];
input_state.joypad_latches[0] = current_joypad[0];
input_state.joypad_latches[1] = current_joypad[1];
#ifdef _QUICKERNES_SUPPORT_ARKANOID_INPUTS
input_state.arkanoid_latch = current_arkanoid_latch;
input_state.arkanoid_fire = current_arkanoid_fire;
#endif
}
joypad.w4016 = data;
input_state.w4016 = data;
return;
}
@ -1000,4 +1195,4 @@ inline void Core::cpu_write(nes_addr_t addr, int data, nes_time_t time)
static_cast<Core &>(*cpu).cpu_write(addr, data, time); \
}
} // namespace quickNES
} // namespace quickerNES

View File

@ -1,10 +1,10 @@
// Emu 0.7.0. http://www.slack.net/~ant/nes-emu/
#include <cstring>
#include <climits>
#include <cstdio>
#include "cpu.hpp"
#include "core.hpp"
#include <climits>
#include <cstdio>
#include <cstring>
/**
* Optimizations by Sergio Martin (eien86) 2023-2024
@ -44,9 +44,12 @@ namespace quickerNES
#define HANDLE_PAGE_CROSSING(lsb) clock_count += (lsb) >> 8;
#define INC_DEC_XY( reg, n ) reg = uint8_t (nz = reg + n); goto loop;
#define INC_DEC_XY(reg, n) \
reg = uint8_t(nz = reg + n); \
goto loop;
#define IND_Y(r,c) { \
#define IND_Y(r, c) \
{ \
int32_t temp = READ_LOW(data) + y; \
data = temp + 0x100 * READ_LOW(uint8_t(data + 1)); \
if (c) HANDLE_PAGE_CROSSING(temp); \
@ -54,7 +57,8 @@ namespace quickerNES
READ(data - (temp & 0x100)); \
}
#define IND_X { \
#define IND_X \
{ \
int32_t temp = data + x; \
data = 0x100 * READ_LOW(uint8_t(temp + 1)) + READ_LOW(uint8_t(temp)); \
}
@ -76,7 +80,8 @@ case op + 0x14: /* abs,Y */ \
goto ind##op; \
case op + 0x18: /* abs,X */ \
data += x; \
ind##op: { \
ind##op: \
{ \
HANDLE_PAGE_CROSSING(data); \
uint32_t temp = data; \
ADD_PAGE \
@ -86,10 +91,9 @@ ind##op: { \
} \
case op + 0x08: /* abs */ \
ADD_PAGE \
ptr##op: \
data = READ( data ); \
ptr##op : data = READ(data); \
case op + 0x04: /* imm */ \
imm##op: \
imm##op:
#define ARITH_ADDR_MODES_PTR(op) \
case op - 0x04: /* (ind,x) */ \
@ -106,7 +110,8 @@ case op + 0x14: /* abs,Y */ \
goto ind##op; \
case op + 0x18: /* abs,X */ \
data += x; \
ind##op: { \
ind##op: \
{ \
uint32_t temp = data; \
ADD_PAGE \
READ(data - (temp & 0x100)); \
@ -115,7 +120,7 @@ ind##op: { \
case op + 0x08: /* abs */ \
ADD_PAGE \
case op + 0x00: /* zp */ \
imm##op: \
imm##op:
// Adding likely to fail because typically for loops exit conditions fail until the last one
#define BRANCH(cond) \
@ -123,14 +128,17 @@ imm##op: \
pc++; \
int offset = (int8_t)data; \
int extra_clock = (pc & 0xFF) + offset; \
if ( !(cond) ) {clock_count--; goto loop; } \
if (!(cond)) \
{ \
clock_count--; \
goto loop; \
} \
pc += offset; \
pc = uint16_t(pc); \
clock_count += (extra_clock >> 8) & 1; \
goto loop; \
}
void Cpu::reset(void const *unmapped_page)
{
r.status = 0;
@ -163,7 +171,10 @@ void Cpu::reset( void const* unmapped_page )
#define READ_LIKELY_PPU(addr) (NES_CPU_READ_PPU(this, (addr), (clock_count)))
#define READ(addr) (NES_CPU_READ(this, (addr), (clock_count)))
#define WRITE( addr, data ) {NES_CPU_WRITE( this, (addr), (data), (clock_count) );}
#define WRITE(addr, data) \
{ \
NES_CPU_WRITE(this, (addr), (data), (clock_count)); \
}
#define READ_LOW(addr) (low_mem[int32_t(addr)])
#define WRITE_LOW(addr, data) (void)(READ_LOW(addr) = (data))
@ -177,14 +188,16 @@ void Cpu::reset( void const* unmapped_page )
#define IS_NEG (nz & 0x880)
#define CALC_STATUS( out ) do { \
#define CALC_STATUS(out) \
do { \
out = status & (st_v | st_d | st_i); \
out |= (c >> 8) & st_c; \
if (IS_NEG) out |= st_n; \
if (!(nz & 0xFF)) out |= st_z; \
} while (0)
#define SET_STATUS( in ) do { \
#define SET_STATUS(in) \
do { \
status = in & (st_v | st_d | st_i); \
c = in << 8; \
nz = (in << 4) & 0x800; \
@ -204,25 +217,271 @@ inline void Cpu::write( nes_addr_t addr, int value )
// status flags
uint8_t clock_table[256] = {
// 0 1 2 3 4 5 6 7 8 9 A B C D E F
7,6,2,8,3,3,5,5,3,2,2,2,4,4,6,6,// 0
3,5,2,8,4,4,6,6,2,4,2,7,4,4,7,7,// 1
6,6,2,8,3,3,5,5,4,2,2,2,4,4,6,6,// 2
3,5,2,8,4,4,6,6,2,4,2,7,4,4,7,7,// 3
6,6,2,8,3,3,5,5,3,2,2,2,3,4,6,6,// 4
3,5,2,8,4,4,6,6,2,4,2,7,4,4,7,7,// 5
6,6,2,8,3,3,5,5,4,2,2,2,5,4,6,6,// 6
3,5,2,8,4,4,6,6,2,4,2,7,4,4,7,7,// 7
2,6,2,6,3,3,3,3,2,2,2,2,4,4,4,4,// 8
3,6,2,6,4,4,4,4,2,5,2,5,5,5,5,5,// 9
2,6,2,6,3,3,3,3,2,2,2,2,4,4,4,4,// A
3,5,2,5,4,4,4,4,2,4,2,4,4,4,4,4,// B
2,6,2,8,3,3,5,5,2,2,2,2,4,4,6,6,// C
3,5,2,8,4,4,6,6,2,4,2,7,4,4,7,7,// D
2,6,2,8,3,3,5,5,2,2,2,2,4,4,6,6,// E
3,5,2,8,4,4,6,6,2,4,2,7,4,4,7,7 // F
7,
6,
2,
8,
3,
3,
5,
5,
3,
2,
2,
2,
4,
4,
6,
6, // 0
3,
5,
2,
8,
4,
4,
6,
6,
2,
4,
2,
7,
4,
4,
7,
7, // 1
6,
6,
2,
8,
3,
3,
5,
5,
4,
2,
2,
2,
4,
4,
6,
6, // 2
3,
5,
2,
8,
4,
4,
6,
6,
2,
4,
2,
7,
4,
4,
7,
7, // 3
6,
6,
2,
8,
3,
3,
5,
5,
3,
2,
2,
2,
3,
4,
6,
6, // 4
3,
5,
2,
8,
4,
4,
6,
6,
2,
4,
2,
7,
4,
4,
7,
7, // 5
6,
6,
2,
8,
3,
3,
5,
5,
4,
2,
2,
2,
5,
4,
6,
6, // 6
3,
5,
2,
8,
4,
4,
6,
6,
2,
4,
2,
7,
4,
4,
7,
7, // 7
2,
6,
2,
6,
3,
3,
3,
3,
2,
2,
2,
2,
4,
4,
4,
4, // 8
3,
6,
2,
6,
4,
4,
4,
4,
2,
5,
2,
5,
5,
5,
5,
5, // 9
2,
6,
2,
6,
3,
3,
3,
3,
2,
2,
2,
2,
4,
4,
4,
4, // A
3,
5,
2,
5,
4,
4,
4,
4,
2,
4,
2,
4,
4,
4,
4,
4, // B
2,
6,
2,
8,
3,
3,
5,
5,
2,
2,
2,
2,
4,
4,
6,
6, // C
3,
5,
2,
8,
4,
4,
6,
6,
2,
4,
2,
7,
4,
4,
7,
7, // D
2,
6,
2,
8,
3,
3,
5,
5,
2,
2,
2,
2,
4,
4,
6,
6, // E
3,
5,
2,
8,
4,
4,
6,
6,
2,
4,
2,
7,
4,
4,
7,
7 // F
};
Cpu::result_t Cpu::run ( nes_time_t end )
// This optimization is only possible with the GNU compiler -- MSVC does not allow function alignment
#ifdef __GNUC__
__attribute__((optimize("align-functions=1024")))
#endif
Cpu::result_t
Cpu::run(nes_time_t end)
{
set_end_time_(end);
clock_count = 0;
@ -256,7 +515,8 @@ loop:
opcode = page[pc++];
data = page[pc];
if ( clock_count >= clock_limit ) [[unlikely]] goto stop;
if (clock_count >= clock_limit) [[unlikely]]
goto stop;
// If traceback support is enabled, trigger it here
#ifdef _QUICKERNES_ENABLE_TRACEBACK_SUPPORT
@ -278,7 +538,6 @@ loop:
switch (opcode)
{
// Often-Used
case 0xB5: // LDA zp,x
@ -291,7 +550,8 @@ loop:
case 0xD0: // BNE
BRANCH((uint8_t)nz);
case 0x20: { // JSR
case 0x20:
{ // JSR
int32_t temp = pc + 1;
pc = GET_OPERAND16(pc);
WRITE_LOW(0x100 | (sp - 1), temp >> 8);
@ -376,7 +636,8 @@ loop:
case 0xB9: // LDA abs,Y
data += y;
data -= x;
case 0xBD:{// LDA abs,X
case 0xBD:
{ // LDA abs,X
pc++;
uint32_t msb = GET_OPERAND(pc);
data += x;
@ -394,7 +655,8 @@ loop:
goto loop;
}
case 0xB1:{// LDA (ind),Y
case 0xB1:
{ // LDA (ind),Y
uint32_t msb = READ_LOW((uint8_t)(data + 1));
data = READ_LOW(data) + y;
// indexed common
@ -478,7 +740,8 @@ loop:
case 0xBC: // LDY abs,X
data += x;
HANDLE_PAGE_CROSSING(data);
case 0xAC:{// LDY abs
case 0xAC:
{ // LDY abs
pc++;
uint32_t addr = data + 0x100 * GET_OPERAND(pc);
if (data & 0x100)
@ -491,7 +754,8 @@ loop:
case 0xBE: // LDX abs,y
data += y;
HANDLE_PAGE_CROSSING(data);
case 0xAE:{// LDX abs
case 0xAE:
{ // LDX abs
pc++;
uint32_t addr = data + 0x100 * GET_OPERAND(pc);
pc++;
@ -518,7 +782,8 @@ loop:
// Compare
case 0xEC:{// CPX abs
case 0xEC:
{ // CPX abs
uint32_t addr = GET_ADDR();
pc++;
data = READ(addr);
@ -535,7 +800,8 @@ loop:
nz &= 0xFF;
goto loop;
case 0xCC:{// CPY abs
case 0xCC:
{ // CPY abs
uint32_t addr = GET_ADDR();
pc++;
data = READ(addr);
@ -569,7 +835,8 @@ loop:
pc++;
goto loop;
case 0x2C:{// BIT abs
case 0x2C:
{ // BIT abs
uint32_t addr = GET_ADDR();
pc += 2;
status &= ~st_v;
@ -601,7 +868,8 @@ loop:
goto adc_imm;
ARITH_ADDR_MODES(0x65) // ADC
adc_imm: {
adc_imm:
{
int32_t carry = (c >> 8) & 1;
int32_t ov = (a ^ 0x80) + carry + (int8_t)data; // sign-extend
status &= ~st_v;
@ -630,7 +898,8 @@ loop:
a = (uint8_t)nz;
goto loop;
case 0x2A: { // ROL A
case 0x2A:
{ // ROL A
nz = a << 1;
int32_t temp = (c >> 8) & 1;
c = nz;
@ -648,7 +917,8 @@ loop:
case 0x0E: // ASL abs
c = 0;
case 0x2E: // ROL abs
rol_abs: {
rol_abs:
{
int32_t temp = data;
ADD_PAGE
if (opcode == 0x1E || opcode == 0x3E) READ(data - (temp & 0x100));
@ -670,7 +940,8 @@ loop:
case 0x4E: // LSR abs
c = 0;
case 0x6E: // ROR abs
ror_abs: {
ror_abs:
{
int32_t temp = data;
ADD_PAGE
if (opcode == 0x5E || opcode == 0x7E) READ(data - (temp & 0x100));
@ -689,7 +960,8 @@ loop:
case 0x46: // LSR zp
c = 0;
case 0x66: // ROR zp
ror_zp: {
ror_zp:
{
int32_t temp = READ_LOW(data);
nz = ((c >> 1) & 0x80) | (temp >> 1);
c = temp << 8;
@ -733,7 +1005,8 @@ loop:
WRITE_LOW(data, nz);
goto loop;
case 0xFE: { // INC abs,x
case 0xFE:
{ // INC abs,x
int32_t temp = data + x;
data = x + GET_ADDR();
READ(data - (temp & 0x100));
@ -746,7 +1019,8 @@ loop:
nz = 1;
goto inc_common;
case 0xDE: { // DEC abs,x
case 0xDE:
{ // DEC abs,x
int32_t temp = data + x;
data = x + GET_ADDR();
READ(data - (temp & 0x100));
@ -757,7 +1031,8 @@ loop:
data = GET_ADDR();
dec_ptr:
nz = -1;
inc_common: {
inc_common:
{
int32_t temp;
WRITE(data, temp = READ(data));
nz += temp;
@ -816,7 +1091,8 @@ loop:
clock_limit = irq_time_;
goto loop;
case 0x28:{// PLP
case 0x28:
{ // PLP
int32_t temp = READ_LOW(sp);
sp = (sp - 0xFF) | 0x100;
data = status;
@ -828,7 +1104,8 @@ loop:
goto handle_sei;
}
case 0x08: { // PHP
case 0x08:
{ // PHP
int32_t temp;
CALC_STATUS(temp);
PUSH(temp | st_b | st_r);
@ -841,7 +1118,8 @@ loop:
pc |= READ((data & 0xFF00) | ((data + 1) & 0xFF)) << 8;
goto loop;
case 0x00: { // BRK
case 0x00:
{ // BRK
pc++;
WRITE_LOW(0x100 | (sp - 1), pc >> 8);
WRITE_LOW(0x100 | (sp - 2), pc);
@ -910,7 +1188,13 @@ loop:
goto end;
// Unofficial
case 0x1C: case 0x3C: case 0x5C: case 0x7C: case 0xDC: case 0xFC: { // SKW
case 0x1C:
case 0x3C:
case 0x5C:
case 0x7C:
case 0xDC:
case 0xFC:
{ // SKW
data += x;
HANDLE_PAGE_CROSSING(data);
int32_t addr = GET_ADDR() + x;
@ -920,10 +1204,28 @@ loop:
}
case 0x0C: // SKW
pc++;
case 0x74: case 0x04: case 0x14: case 0x34: case 0x44: case 0x54: case 0x64: // SKB
case 0x80: case 0x82: case 0x89: case 0xC2: case 0xD4: case 0xE2: case 0xF4:
case 0x74:
case 0x04:
case 0x14:
case 0x34:
case 0x44:
case 0x54:
case 0x64: // SKB
case 0x80:
case 0x82:
case 0x89:
case 0xC2:
case 0xD4:
case 0xE2:
case 0xF4:
pc++;
case 0xEA: case 0x1A: case 0x3A: case 0x5A: case 0x7A: case 0xDA: case 0xFA: // NOP
case 0xEA:
case 0x1A:
case 0x3A:
case 0x5A:
case 0x7A:
case 0xDA:
case 0xFA: // NOP
goto loop;
ARITH_ADDR_MODES_PTR(0xC7) // DCP
@ -943,7 +1245,8 @@ loop:
data = nz ^ 0xFF;
goto adc_imm;
ARITH_ADDR_MODES_PTR( 0x27 ) { // RLA
ARITH_ADDR_MODES_PTR(0x27)
{ // RLA
WRITE(data, nz = READ(data));
int32_t temp = c;
c = nz << 1;
@ -954,7 +1257,8 @@ loop:
goto loop;
}
ARITH_ADDR_MODES_PTR( 0x67 ) { // RRA
ARITH_ADDR_MODES_PTR(0x67)
{ // RRA
int32_t temp;
WRITE(data, temp = READ(data));
nz = ((c >> 1) & 0x80) | (temp >> 1);
@ -1023,7 +1327,8 @@ loop:
data = READ_LOW(data);
goto lax_imm;
case 0xBF: {
case 0xBF:
{
data += y;
HANDLE_PAGE_CROSSING(data);
int32_t temp = data;
@ -1073,7 +1378,8 @@ loop:
WRITE(data, uint8_t(a & x & ((data >> 8) + 1)));
goto loop;
case 0x9F: { // SHA abs,Y
case 0x9F:
{ // SHA abs,Y
data += y;
int32_t temp = data;
ADD_PAGE
@ -1083,7 +1389,8 @@ loop:
goto loop;
}
case 0x9E: { // SHX abs,Y
case 0x9E:
{ // SHX abs,Y
data += y;
int32_t temp = data;
ADD_PAGE
@ -1094,7 +1401,8 @@ loop:
goto loop;
}
case 0x9C: { // SHY abs,X
case 0x9C:
{ // SHY abs,X
data += x;
int32_t temp = data;
ADD_PAGE
@ -1105,7 +1413,8 @@ loop:
goto loop;
}
case 0x9B: { // SHS abs,Y
case 0x9B:
{ // SHS abs,Y
data += y;
int32_t temp = data;
ADD_PAGE
@ -1116,7 +1425,8 @@ loop:
goto loop;
}
case 0xBB: { // LAS abs,Y
case 0xBB:
{ // LAS abs,Y
data += y;
HANDLE_PAGE_CROSSING(data);
int32_t temp = data;
@ -1171,6 +1481,7 @@ end:
r.status = temp;
}
this->clock_count = clock_count;
r.pc = pc;
r.sp = GET_SP();
r.a = a;
@ -1181,5 +1492,4 @@ end:
return result;
}
} // namespace quickNES
} // namespace quickerNES

View File

@ -14,7 +14,6 @@ typedef unsigned nes_addr_t; // 16-bit address
class Cpu
{
public:
void set_tracecb(void (*cb)(unsigned int *data))
{
tracecb = cb;
@ -163,4 +162,4 @@ class Cpu
}
};
} // namespace quickNES
} // namespace quickerNES

View File

@ -1,10 +1,10 @@
// Emu 0.7.0. http://www.slack.net/~ant/
#include <cstring>
#include "mappers/mapper.hpp"
#include "emu.hpp"
#include "apu/NESEffectsBuffer.hpp"
#include "apu/buffer.hpp"
#include "mappers/mapper.hpp"
#include <cstring>
/* Copyright (C) 2004-2006 Shay Green. This module is free software; you
can redistribute it and/or modify it under the terms of the GNU Lesser
@ -71,7 +71,6 @@ inline const char * Emu::auto_init()
return 0;
}
inline void Emu::clear_sound_buf()
{
fade_sound_out = false;
@ -105,16 +104,16 @@ void Emu::set_palette_range( int begin, int end )
host_palette_size = end - emu.ppu.palette_begin;
}
const char * Emu::emulate_skip_frame( uint32_t joypad1, uint32_t joypad2 )
const char *Emu::emulate_skip_frame(uint32_t joypad1, uint32_t joypad2, uint32_t arkanoid_latch, uint8_t arkanoid_fire)
{
char *old_host_pixels = host_pixels;
host_pixels = NULL;
emu.emulate_frame(joypad1, joypad2);
emu.emulate_frame(joypad1, joypad2, arkanoid_latch, arkanoid_fire);
host_pixels = old_host_pixels;
return 0;
}
const char * Emu::emulate_frame( uint32_t joypad1, uint32_t joypad2 )
const char *Emu::emulate_frame(uint32_t joypad1, uint32_t joypad2, uint32_t arkanoid_latch, uint8_t arkanoid_fire)
{
emu.ppu.host_pixels = NULL;
@ -145,7 +144,7 @@ const char * Emu::emulate_frame( uint32_t joypad1, uint32_t joypad2 )
if (sound_buf->samples_avail())
clear_sound_buf();
nes_time_t frame_len = emu.emulate_frame(joypad1, joypad2);
nes_time_t frame_len = emu.emulate_frame(joypad1, joypad2, arkanoid_latch, arkanoid_fire);
sound_buf->end_frame(frame_len, false);
f = frame_;
@ -160,7 +159,7 @@ const char * Emu::emulate_frame( uint32_t joypad1, uint32_t joypad2 )
else
{
emu.ppu.max_palette_size = 0;
emu.emulate_frame(joypad1, joypad2);
emu.emulate_frame(joypad1, joypad2, arkanoid_latch, arkanoid_fire);
}
return 0;
@ -311,136 +310,519 @@ long Emu::read_samples( short* out, long out_size )
Emu::rgb_t const Emu::nes_colors[color_table_size] =
{
// generated with nes_ntsc default settings
{102,102,102},{ 0, 42,136},{ 20, 18,168},{ 59, 0,164},
{ 92, 0,126},{110, 0, 64},{108, 7, 0},{ 87, 29, 0},
{ 52, 53, 0},{ 12, 73, 0},{ 0, 82, 0},{ 0, 79, 8},
{ 0, 64, 78},{ 0, 0, 0},{ 0, 0, 0},{ 0, 0, 0},
{174,174,174},{ 21, 95,218},{ 66, 64,254},{118, 39,255},
{161, 27,205},{184, 30,124},{181, 50, 32},{153, 79, 0},
{108,110, 0},{ 56,135, 0},{ 13,148, 0},{ 0,144, 50},
{ 0,124,142},{ 0, 0, 0},{ 0, 0, 0},{ 0, 0, 0},
{254,254,254},{100,176,254},{147,144,254},{199,119,254},
{243,106,254},{254,110,205},{254,130,112},{235,159, 35},
{189,191, 0},{137,217, 0},{ 93,229, 48},{ 69,225,130},
{ 72,206,223},{ 79, 79, 79},{ 0, 0, 0},{ 0, 0, 0},
{254,254,254},{193,224,254},{212,211,254},{233,200,254},
{251,195,254},{254,197,235},{254,205,198},{247,217,166},
{229,230,149},{208,240,151},{190,245,171},{180,243,205},
{181,236,243},{184,184,184},{ 0, 0, 0},{ 0, 0, 0},
{102, 102, 102},
{0, 42, 136},
{20, 18, 168},
{59, 0, 164},
{92, 0, 126},
{110, 0, 64},
{108, 7, 0},
{87, 29, 0},
{52, 53, 0},
{12, 73, 0},
{0, 82, 0},
{0, 79, 8},
{0, 64, 78},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{174, 174, 174},
{21, 95, 218},
{66, 64, 254},
{118, 39, 255},
{161, 27, 205},
{184, 30, 124},
{181, 50, 32},
{153, 79, 0},
{108, 110, 0},
{56, 135, 0},
{13, 148, 0},
{0, 144, 50},
{0, 124, 142},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{254, 254, 254},
{100, 176, 254},
{147, 144, 254},
{199, 119, 254},
{243, 106, 254},
{254, 110, 205},
{254, 130, 112},
{235, 159, 35},
{189, 191, 0},
{137, 217, 0},
{93, 229, 48},
{69, 225, 130},
{72, 206, 223},
{79, 79, 79},
{0, 0, 0},
{0, 0, 0},
{254, 254, 254},
{193, 224, 254},
{212, 211, 254},
{233, 200, 254},
{251, 195, 254},
{254, 197, 235},
{254, 205, 198},
{247, 217, 166},
{229, 230, 149},
{208, 240, 151},
{190, 245, 171},
{180, 243, 205},
{181, 236, 243},
{184, 184, 184},
{0, 0, 0},
{0, 0, 0},
{114, 83, 79},{ 0, 23,113},{ 32, 0,145},{ 71, 0,141},
{104, 0,103},{122, 0, 41},{120, 0, 0},{ 99, 10, 0},
{ 64, 34, 0},{ 24, 54, 0},{ 0, 63, 0},{ 0, 60, 0},
{ 0, 45, 54},{ 0, 0, 0},{ 0, 0, 0},{ 0, 0, 0},
{190,148,143},{ 37, 69,187},{ 83, 38,228},{134, 13,224},
{177, 1,174},{200, 4, 92},{198, 24, 1},{170, 53, 0},
{124, 84, 0},{ 73,109, 0},{ 30,122, 0},{ 6,118, 19},
{ 9, 98,110},{ 0, 0, 0},{ 0, 0, 0},{ 0, 0, 0},
{254,222,215},{122,142,254},{168,110,254},{220, 85,254},
{254, 72,247},{254, 76,164},{254, 96, 71},{254,125, 0},
{210,157, 0},{158,183, 0},{114,195, 7},{ 90,191, 89},
{ 93,172,182},{ 79, 79, 79},{ 0, 0, 0},{ 0, 0, 0},
{254,222,215},{214,190,233},{233,177,250},{254,166,248},
{254,161,228},{254,163,194},{254,171,157},{254,183,125},
{250,196,108},{229,206,110},{211,211,130},{201,210,164},
{203,202,202},{184,184,184},{ 0, 0, 0},{ 0, 0, 0},
{ 75,106, 64},{ 0, 46, 98},{ 0, 22,130},{ 32, 3,126},
{ 65, 0, 88},{ 82, 0, 26},{ 80, 11, 0},{ 59, 34, 0},
{ 24, 58, 0},{ 0, 77, 0},{ 0, 86, 0},{ 0, 83, 0},
{ 0, 68, 39},{ 0, 0, 0},{ 0, 0, 0},{ 0, 0, 0},
{136,180,122},{ 0,101,166},{ 29, 69,208},{ 80, 44,203},
{123, 32,153},{146, 36, 72},{144, 55, 0},{116, 84, 0},
{ 70,116, 0},{ 19,141, 0},{ 0,153, 0},{ 0,149, 0},
{ 0,130, 90},{ 0, 0, 0},{ 0, 0, 0},{ 0, 0, 0},
{207,254,188},{ 51,183,233},{ 98,151,254},{150,126,254},
{193,113,220},{217,117,137},{214,137, 45},{186,166, 0},
{140,198, 0},{ 88,224, 0},{ 44,236, 0},{ 20,232, 63},
{ 23,213,155},{ 79, 79, 79},{ 0, 0, 0},{ 0, 0, 0},
{207,254,188},{144,231,207},{163,218,224},{184,207,222},
{201,202,201},{211,204,168},{210,212,130},{198,224, 99},
{180,237, 81},{159,247, 83},{141,252,104},{131,251,137},
{132,243,175},{184,184,184},{ 0, 0, 0},{ 0, 0, 0},
{ 83, 83, 55},{ 0, 23, 89},{ 0, 0,121},{ 40, 0,117},
{ 73, 0, 79},{ 90, 0, 17},{ 88, 0, 0},{ 67, 10, 0},
{ 32, 34, 0},{ 0, 53, 0},{ 0, 63, 0},{ 0, 60, 0},
{ 0, 45, 30},{ 0, 0, 0},{ 0, 0, 0},{ 0, 0, 0},
{147,148,110},{ 0, 69,154},{ 40, 38,196},{ 91, 12,191},
{134, 0,141},{157, 4, 60},{155, 23, 0},{127, 52, 0},
{ 81, 84, 0},{ 30,109, 0},{ 0,121, 0},{ 0,117, 0},
{ 0, 98, 78},{ 0, 0, 0},{ 0, 0, 0},{ 0, 0, 0},
{221,222,173},{ 65,142,217},{112,110,254},{164, 84,255},
{208, 72,204},{231, 76,122},{229, 95, 29},{200,125, 0},
{154,157, 0},{102,182, 0},{ 58,195, 0},{ 34,191, 47},
{ 37,171,140},{ 79, 79, 79},{ 0, 0, 0},{ 0, 0, 0},
{221,222,173},{158,189,191},{177,176,208},{198,166,206},
{216,161,185},{225,163,152},{224,171,114},{213,183, 83},
{194,195, 66},{173,206, 68},{155,211, 88},{145,209,122},
{146,201,159},{184,184,184},{ 0, 0, 0},{ 0, 0, 0},
{ 87, 87,133},{ 0, 26,167},{ 5, 2,198},{ 44, 0,195},
{ 77, 0,157},{ 95, 0, 94},{ 93, 0, 25},{ 71, 14, 0},
{ 36, 38, 0},{ 0, 57, 0},{ 0, 66, 0},{ 0, 63, 38},
{ 0, 49,108},{ 0, 0, 0},{ 0, 0, 0},{ 0, 0, 0},
{153,153,216},{ 0, 74,254},{ 46, 43,254},{ 97, 17,254},
{140, 5,247},{164, 9,165},{161, 28, 74},{133, 57, 0},
{ 87, 89, 0},{ 36,114, 0},{ 0,126, 10},{ 0,122, 92},
{ 0,103,183},{ 0, 0, 0},{ 0, 0, 0},{ 0, 0, 0},
{229,228,254},{ 74,148,254},{120,116,254},{172, 91,254},
{216, 78,254},{239, 82,254},{237,102,166},{208,131, 89},
{162,163, 46},{110,189, 51},{ 66,201,102},{ 42,197,184},
{ 45,178,254},{ 79, 79, 79},{ 0, 0, 0},{ 0, 0, 0},
{229,228,254},{166,196,254},{185,183,254},{206,172,254},
{224,167,254},{233,169,254},{232,177,252},{221,189,220},
{202,202,203},{181,212,205},{163,217,226},{153,216,254},
{154,208,254},{184,184,184},{ 0, 0, 0},{ 0, 0, 0},
{ 90, 71, 97},{ 0, 11,130},{ 8, 0,162},{ 47, 0,158},
{ 80, 0,120},{ 98, 0, 58},{ 96, 0, 0},{ 74, 0, 0},
{ 39, 22, 0},{ 0, 42, 0},{ 0, 51, 0},{ 0, 48, 2},
{ 0, 33, 72},{ 0, 0, 0},{ 0, 0, 0},{ 0, 0, 0},
{158,132,166},{ 4, 53,210},{ 50, 22,252},{101, 0,247},
{144, 0,197},{168, 0,116},{165, 7, 25},{137, 36, 0},
{ 91, 68, 0},{ 40, 93, 0},{ 0,105, 0},{ 0,101, 42},
{ 0, 82,134},{ 0, 0, 0},{ 0, 0, 0},{ 0, 0, 0},
{234,201,246},{ 79,121,254},{125, 89,254},{177, 63,254},
{221, 51,254},{245, 55,195},{242, 74,102},{214,104, 24},
{167,136, 0},{115,161, 0},{ 71,174, 37},{ 48,170,120},
{ 50,150,213},{ 79, 79, 79},{ 0, 0, 0},{ 0, 0, 0},
{234,201,246},{171,168,254},{190,155,254},{211,145,254},
{229,140,254},{239,142,225},{237,150,187},{226,162,156},
{207,174,139},{186,185,141},{168,190,161},{159,188,195},
{160,180,232},{184,184,184},{ 0, 0, 0},{ 0, 0, 0},
{ 66, 85, 88},{ 0, 25,121},{ 0, 1,153},{ 23, 0,149},
{ 56, 0,111},{ 74, 0, 49},{ 72, 0, 0},{ 51, 12, 0},
{ 16, 36, 0},{ 0, 55, 0},{ 0, 65, 0},{ 0, 62, 0},
{ 0, 47, 63},{ 0, 0, 0},{ 0, 0, 0},{ 0, 0, 0},
{125,151,154},{ 0, 72,198},{ 17, 40,240},{ 69, 15,235},
{112, 3,185},{135, 7,104},{132, 26, 12},{104, 55, 0},
{ 59, 87, 0},{ 7,112, 0},{ 0,124, 0},{ 0,120, 30},
{ 0,101,121},{ 0, 0, 0},{ 0, 0, 0},{ 0, 0, 0},
{192,225,230},{ 37,145,254},{ 83,114,254},{135, 88,254},
{179, 76,254},{202, 80,179},{200, 99, 86},{171,129, 8},
{125,160, 0},{ 73,186, 0},{ 29,198, 21},{ 5,194,104},
{ 8,175,197},{ 79, 79, 79},{ 0, 0, 0},{ 0, 0, 0},
{192,225,230},{129,193,248},{148,180,254},{169,170,254},
{187,165,242},{196,166,209},{195,174,171},{184,186,140},
{165,199,123},{144,209,125},{126,214,145},{116,213,179},
{118,205,216},{184,184,184},{ 0, 0, 0},{ 0, 0, 0},
{ 69, 69, 69},{ 0, 16,110},{ 0, 0,142},{ 33, 0,138},
{ 66, 0,100},{ 84, 0, 38},{ 82, 0, 0},{ 60, 3, 0},
{ 25, 27, 0},{ 0, 46, 0},{ 0, 56, 0},{ 0, 53, 0},
{ 0, 38, 51},{ 0, 0, 0},{ 0, 0, 0},{ 0, 0, 0},
{134,134,134},{ 0, 64,187},{ 35, 32,228},{ 86, 7,223},
{129, 0,174},{153, 0, 92},{150, 18, 1},{122, 47, 0},
{ 76, 79, 0},{ 25,104, 0},{ 0,116, 0},{ 0,112, 19},
{ 0, 93,110},{ 0, 0, 0},{ 0, 0, 0},{ 0, 0, 0},
{207,207,207},{ 60,136,254},{107,104,254},{159, 79,254},
{203, 66,248},{226, 70,165},{224, 90, 72},{195,119, 0},
{149,151, 0},{ 97,177, 0},{ 53,189, 8},{ 29,185, 91},
{ 32,166,183},{ 79, 79, 79},{ 0, 0, 0},{ 0, 0, 0},
{207,207,207},{148,178,229},{166,165,246},{188,155,244},
{205,150,224},{215,152,190},{214,159,152},{202,171,121},
{183,184,104},{162,195,106},{145,200,126},{135,198,160},
{136,190,197},{184,184,184},{ 0, 0, 0},{ 0, 0, 0}
};
{114, 83, 79},
{0, 23, 113},
{32, 0, 145},
{71, 0, 141},
{104, 0, 103},
{122, 0, 41},
{120, 0, 0},
{99, 10, 0},
{64, 34, 0},
{24, 54, 0},
{0, 63, 0},
{0, 60, 0},
{0, 45, 54},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{190, 148, 143},
{37, 69, 187},
{83, 38, 228},
{134, 13, 224},
{177, 1, 174},
{200, 4, 92},
{198, 24, 1},
{170, 53, 0},
{124, 84, 0},
{73, 109, 0},
{30, 122, 0},
{6, 118, 19},
{9, 98, 110},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{254, 222, 215},
{122, 142, 254},
{168, 110, 254},
{220, 85, 254},
{254, 72, 247},
{254, 76, 164},
{254, 96, 71},
{254, 125, 0},
{210, 157, 0},
{158, 183, 0},
{114, 195, 7},
{90, 191, 89},
{93, 172, 182},
{79, 79, 79},
{0, 0, 0},
{0, 0, 0},
{254, 222, 215},
{214, 190, 233},
{233, 177, 250},
{254, 166, 248},
{254, 161, 228},
{254, 163, 194},
{254, 171, 157},
{254, 183, 125},
{250, 196, 108},
{229, 206, 110},
{211, 211, 130},
{201, 210, 164},
{203, 202, 202},
{184, 184, 184},
{0, 0, 0},
{0, 0, 0},
{75, 106, 64},
{0, 46, 98},
{0, 22, 130},
{32, 3, 126},
{65, 0, 88},
{82, 0, 26},
{80, 11, 0},
{59, 34, 0},
{24, 58, 0},
{0, 77, 0},
{0, 86, 0},
{0, 83, 0},
{0, 68, 39},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{136, 180, 122},
{0, 101, 166},
{29, 69, 208},
{80, 44, 203},
{123, 32, 153},
{146, 36, 72},
{144, 55, 0},
{116, 84, 0},
{70, 116, 0},
{19, 141, 0},
{0, 153, 0},
{0, 149, 0},
{0, 130, 90},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{207, 254, 188},
{51, 183, 233},
{98, 151, 254},
{150, 126, 254},
{193, 113, 220},
{217, 117, 137},
{214, 137, 45},
{186, 166, 0},
{140, 198, 0},
{88, 224, 0},
{44, 236, 0},
{20, 232, 63},
{23, 213, 155},
{79, 79, 79},
{0, 0, 0},
{0, 0, 0},
{207, 254, 188},
{144, 231, 207},
{163, 218, 224},
{184, 207, 222},
{201, 202, 201},
{211, 204, 168},
{210, 212, 130},
{198, 224, 99},
{180, 237, 81},
{159, 247, 83},
{141, 252, 104},
{131, 251, 137},
{132, 243, 175},
{184, 184, 184},
{0, 0, 0},
{0, 0, 0},
{83, 83, 55},
{0, 23, 89},
{0, 0, 121},
{40, 0, 117},
{73, 0, 79},
{90, 0, 17},
{88, 0, 0},
{67, 10, 0},
{32, 34, 0},
{0, 53, 0},
{0, 63, 0},
{0, 60, 0},
{0, 45, 30},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{147, 148, 110},
{0, 69, 154},
{40, 38, 196},
{91, 12, 191},
{134, 0, 141},
{157, 4, 60},
{155, 23, 0},
{127, 52, 0},
{81, 84, 0},
{30, 109, 0},
{0, 121, 0},
{0, 117, 0},
{0, 98, 78},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{221, 222, 173},
{65, 142, 217},
{112, 110, 254},
{164, 84, 255},
{208, 72, 204},
{231, 76, 122},
{229, 95, 29},
{200, 125, 0},
{154, 157, 0},
{102, 182, 0},
{58, 195, 0},
{34, 191, 47},
{37, 171, 140},
{79, 79, 79},
{0, 0, 0},
{0, 0, 0},
{221, 222, 173},
{158, 189, 191},
{177, 176, 208},
{198, 166, 206},
{216, 161, 185},
{225, 163, 152},
{224, 171, 114},
{213, 183, 83},
{194, 195, 66},
{173, 206, 68},
{155, 211, 88},
{145, 209, 122},
{146, 201, 159},
{184, 184, 184},
{0, 0, 0},
{0, 0, 0},
{87, 87, 133},
{0, 26, 167},
{5, 2, 198},
{44, 0, 195},
{77, 0, 157},
{95, 0, 94},
{93, 0, 25},
{71, 14, 0},
{36, 38, 0},
{0, 57, 0},
{0, 66, 0},
{0, 63, 38},
{0, 49, 108},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{153, 153, 216},
{0, 74, 254},
{46, 43, 254},
{97, 17, 254},
{140, 5, 247},
{164, 9, 165},
{161, 28, 74},
{133, 57, 0},
{87, 89, 0},
{36, 114, 0},
{0, 126, 10},
{0, 122, 92},
{0, 103, 183},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{229, 228, 254},
{74, 148, 254},
{120, 116, 254},
{172, 91, 254},
{216, 78, 254},
{239, 82, 254},
{237, 102, 166},
{208, 131, 89},
{162, 163, 46},
{110, 189, 51},
{66, 201, 102},
{42, 197, 184},
{45, 178, 254},
{79, 79, 79},
{0, 0, 0},
{0, 0, 0},
{229, 228, 254},
{166, 196, 254},
{185, 183, 254},
{206, 172, 254},
{224, 167, 254},
{233, 169, 254},
{232, 177, 252},
{221, 189, 220},
{202, 202, 203},
{181, 212, 205},
{163, 217, 226},
{153, 216, 254},
{154, 208, 254},
{184, 184, 184},
{0, 0, 0},
{0, 0, 0},
{90, 71, 97},
{0, 11, 130},
{8, 0, 162},
{47, 0, 158},
{80, 0, 120},
{98, 0, 58},
{96, 0, 0},
{74, 0, 0},
{39, 22, 0},
{0, 42, 0},
{0, 51, 0},
{0, 48, 2},
{0, 33, 72},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{158, 132, 166},
{4, 53, 210},
{50, 22, 252},
{101, 0, 247},
{144, 0, 197},
{168, 0, 116},
{165, 7, 25},
{137, 36, 0},
{91, 68, 0},
{40, 93, 0},
{0, 105, 0},
{0, 101, 42},
{0, 82, 134},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{234, 201, 246},
{79, 121, 254},
{125, 89, 254},
{177, 63, 254},
{221, 51, 254},
{245, 55, 195},
{242, 74, 102},
{214, 104, 24},
{167, 136, 0},
{115, 161, 0},
{71, 174, 37},
{48, 170, 120},
{50, 150, 213},
{79, 79, 79},
{0, 0, 0},
{0, 0, 0},
{234, 201, 246},
{171, 168, 254},
{190, 155, 254},
{211, 145, 254},
{229, 140, 254},
{239, 142, 225},
{237, 150, 187},
{226, 162, 156},
{207, 174, 139},
{186, 185, 141},
{168, 190, 161},
{159, 188, 195},
{160, 180, 232},
{184, 184, 184},
{0, 0, 0},
{0, 0, 0},
{66, 85, 88},
{0, 25, 121},
{0, 1, 153},
{23, 0, 149},
{56, 0, 111},
{74, 0, 49},
{72, 0, 0},
{51, 12, 0},
{16, 36, 0},
{0, 55, 0},
{0, 65, 0},
{0, 62, 0},
{0, 47, 63},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{125, 151, 154},
{0, 72, 198},
{17, 40, 240},
{69, 15, 235},
{112, 3, 185},
{135, 7, 104},
{132, 26, 12},
{104, 55, 0},
{59, 87, 0},
{7, 112, 0},
{0, 124, 0},
{0, 120, 30},
{0, 101, 121},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{192, 225, 230},
{37, 145, 254},
{83, 114, 254},
{135, 88, 254},
{179, 76, 254},
{202, 80, 179},
{200, 99, 86},
{171, 129, 8},
{125, 160, 0},
{73, 186, 0},
{29, 198, 21},
{5, 194, 104},
{8, 175, 197},
{79, 79, 79},
{0, 0, 0},
{0, 0, 0},
{192, 225, 230},
{129, 193, 248},
{148, 180, 254},
{169, 170, 254},
{187, 165, 242},
{196, 166, 209},
{195, 174, 171},
{184, 186, 140},
{165, 199, 123},
{144, 209, 125},
{126, 214, 145},
{116, 213, 179},
{118, 205, 216},
{184, 184, 184},
{0, 0, 0},
{0, 0, 0},
{69, 69, 69},
{0, 16, 110},
{0, 0, 142},
{33, 0, 138},
{66, 0, 100},
{84, 0, 38},
{82, 0, 0},
{60, 3, 0},
{25, 27, 0},
{0, 46, 0},
{0, 56, 0},
{0, 53, 0},
{0, 38, 51},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{134, 134, 134},
{0, 64, 187},
{35, 32, 228},
{86, 7, 223},
{129, 0, 174},
{153, 0, 92},
{150, 18, 1},
{122, 47, 0},
{76, 79, 0},
{25, 104, 0},
{0, 116, 0},
{0, 112, 19},
{0, 93, 110},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{207, 207, 207},
{60, 136, 254},
{107, 104, 254},
{159, 79, 254},
{203, 66, 248},
{226, 70, 165},
{224, 90, 72},
{195, 119, 0},
{149, 151, 0},
{97, 177, 0},
{53, 189, 8},
{29, 185, 91},
{32, 166, 183},
{79, 79, 79},
{0, 0, 0},
{0, 0, 0},
{207, 207, 207},
{148, 178, 229},
{166, 165, 246},
{188, 155, 244},
{205, 150, 224},
{215, 152, 190},
{214, 159, 152},
{202, 171, 121},
{183, 184, 104},
{162, 195, 106},
{145, 200, 126},
{135, 198, 160},
{136, 190, 197},
{184, 184, 184},
{0, 0, 0},
{0, 0, 0}};
void Emu::SaveAudioBufferState()
{
@ -457,4 +839,4 @@ void Emu::RestoreAudioBufferState()
sound_buf->RestoreAudioBufferState();
}
} // namespace quickNES
} // namespace quickerNES

View File

@ -4,9 +4,9 @@
// Emu 0.7.0
#include "apu/multiBuffer.hpp"
#include "cart.hpp"
#include "core.hpp"
#include "apu/multiBuffer.hpp"
namespace quickerNES
{
@ -50,18 +50,21 @@ class Emu
// Save emulator state variants
void serializeState(jaffarCommon::serializer::Base &serializer) const { emu.serializeState(serializer); }
void deserializeState(jaffarCommon::deserializer::Base &deserializer) { emu.deserializeState(deserializer); }
void setNTABBlockSize(const size_t size) { emu.setNTABBlockSize(size); }
void enableStateBlock(const std::string &block) { emu.enableStateBlock(block); };
void disableStateBlock(const std::string &block) { emu.disableStateBlock(block); };
void setControllerType(Core::controllerType_t type) { emu.setControllerType(type); }
// Basic emulation
// Emulate one video frame using joypad1 and joypad2 as input. Afterwards, image
// and sound are available for output using the accessors below.
virtual const char *emulate_frame(uint32_t joypad1, uint32_t joypad2 = 0);
virtual const char *emulate_frame(uint32_t joypad1, uint32_t joypad2, uint32_t arkanoid_latch, uint8_t arkanoid_fire);
// Emulate one video frame using joypad1 and joypad2 as input, but skips drawing.
// Afterwards, audio is available for output using the accessors below.
virtual const char *emulate_skip_frame(uint32_t joypad1, uint32_t joypad2 = 0);
virtual const char *emulate_skip_frame(uint32_t joypad1, uint32_t joypad2, uint32_t arkanoid_latch, uint8_t arkanoid_fire);
// Maximum size of palette that can be generated
static const uint16_t max_palette_size = 256;
@ -293,14 +296,12 @@ class Emu
void SaveAudioBufferState();
void RestoreAudioBufferState();
inline void *get_pixels_base_ptr()
{
return pixels_base_ptr;
}
};
inline void Emu::set_pixels(void *p, long n)
{
pixels_base_ptr = p;
@ -318,4 +319,4 @@ inline long Emu::chr_size() const
return cart()->chr_size() ? cart()->chr_size() : emu.ppu.chr_addr_size;
}
} // namespace quickNES
} // namespace quickerNES

View File

@ -291,4 +291,4 @@ Mapper *Mapper::getMapperFromCode(const int mapperCode)
return mapper;
}
} // namespace quickNES
} // namespace quickerNES

View File

@ -3,9 +3,9 @@
// NES mapper interface
// Emu 0.7.0
#include <climits>
#include "../cart.hpp"
#include "../cpu.hpp"
#include <climits>
namespace quickerNES
{
@ -209,4 +209,4 @@ inline bool Mapper::write_intercepted(nes_time_t, nes_addr_t, int) { return fals
inline int Mapper::read(nes_time_t, nes_addr_t) { return -1; } // signal to caller
} // namespace quickNES
} // namespace quickerNES

View File

@ -35,4 +35,4 @@ class Mapper000 : public Mapper
}
};
} // namespace quickNES
} // namespace quickerNES

View File

@ -126,4 +126,4 @@ class Mapper001 : public Mapper, mmc1_state_t
}
};
} // namespace quickNES
} // namespace quickerNES

View File

@ -45,4 +45,4 @@ class Mapper002 : public Mapper
}
};
} // namespace quickNES
} // namespace quickerNES

View File

@ -44,4 +44,4 @@ class Mapper003 : public Mapper
}
};
} // namespace quickNES
} // namespace quickerNES

View File

@ -255,4 +255,4 @@ class Mapper004 : public Mapper, mmc3_state_t
int counter_just_clocked; // used only for debugging
};
} // namespace quickNES
} // namespace quickerNES

View File

@ -149,4 +149,4 @@ class Mapper005 : public Mapper, mmc5_state_t
nes_time_t irq_time;
};
} // namespace quickNES
} // namespace quickerNES

View File

@ -52,4 +52,4 @@ class Mapper007 : public Mapper
}
};
} // namespace quickNES
} // namespace quickerNES

View File

@ -78,4 +78,4 @@ class Mapper009 : public Mapper
}
};
} // namespace quickNES
} // namespace quickerNES

View File

@ -76,4 +76,4 @@ class Mapper010 : public Mapper
}
};
} // namespace quickNES
} // namespace quickerNES

View File

@ -52,4 +52,4 @@ class Mapper011 : public Mapper
}
};
} // namespace quickNES
} // namespace quickerNES

View File

@ -94,4 +94,4 @@ class Mapper015 : public Mapper, Mapper015_state_t
unsigned long int i;
};
} // namespace quickNES
} // namespace quickerNES

View File

@ -199,4 +199,4 @@ class Mapper019 : public Mapper, namco106_state_t
nes_time_t last_time;
};
} // namespace quickNES
} // namespace quickerNES

View File

@ -256,4 +256,4 @@ void Mapper_VRC2_4<type_a, type_b>::write_irq(nes_time_t time,
typedef Mapper_VRC2_4<true, true> Mapper021;
} // namespace quickNES
} // namespace quickerNES

View File

@ -34,4 +34,4 @@ namespace quickerNES
typedef Mapper_VRC2_4<false, true> Mapper022;
} // namespace quickNES
} // namespace quickerNES

View File

@ -33,4 +33,4 @@ namespace quickerNES
typedef Mapper_VRC2_4<false, false> Mapper023;
} // namespace quickNES
} // namespace quickerNES

View File

@ -233,4 +233,4 @@ class Mapper_Vrc6 : public Mapper, vrc6_state_t
typedef Mapper_Vrc6<0> Mapper024;
} // namespace quickNES
} // namespace quickerNES

View File

@ -33,4 +33,4 @@ namespace quickerNES
typedef Mapper_VRC2_4<true, false> Mapper025;
} // namespace quickNES
} // namespace quickerNES

View File

@ -11,4 +11,4 @@ namespace quickerNES
typedef Mapper_Vrc6<3> Mapper026;
} // namespace quickNES
} // namespace quickerNES

View File

@ -53,4 +53,4 @@ class Mapper030 : public Mapper
}
};
} // namespace quickNES
} // namespace quickerNES

View File

@ -126,4 +126,4 @@ class Mapper032 : public Mapper, mapper32_state_t
}
};
} // namespace quickNES
} // namespace quickerNES

View File

@ -103,4 +103,4 @@ class Mapper033 : public Mapper, tc0190_state_t
}
};
} // namespace quickNES
} // namespace quickerNES

View File

@ -44,4 +44,4 @@ class Mapper034 : public Mapper
}
};
} // namespace quickNES
} // namespace quickerNES

View File

@ -53,4 +53,4 @@ class Mapper060 : public Mapper
uint8_t game_sel, last_game;
};
} // namespace quickNES
} // namespace quickerNES

View File

@ -52,4 +52,4 @@ class Mapper066 : public Mapper
}
};
} // namespace quickNES
} // namespace quickerNES

View File

@ -190,4 +190,4 @@ class Mapper069 : public Mapper, fme7_state_t
Fme7_Apu sound;
};
} // namespace quickNES
} // namespace quickerNES

View File

@ -84,4 +84,4 @@ class Mapper_74x161x162x32 : public Mapper
typedef Mapper_74x161x162x32<70> Mapper070;
} // namespace quickNES
} // namespace quickerNES

View File

@ -54,4 +54,4 @@ class Mapper071 : public Mapper
}
};
} // namespace quickNES
} // namespace quickerNES

View File

@ -134,4 +134,4 @@ class Mapper073 : public Mapper, vrc3_state_t
}
};
} // namespace quickNES
} // namespace quickerNES

View File

@ -110,4 +110,4 @@ class Mapper075 : public Mapper, vrc1_state_t
}
};
} // namespace quickNES
} // namespace quickerNES

View File

@ -77,4 +77,4 @@ class Mapper078 : public Mapper
}
};
} // namespace quickNES
} // namespace quickerNES

View File

@ -95,4 +95,4 @@ void Mapper_AveNina<multicart>::write_regs()
typedef Mapper_AveNina<false> Mapper079;
} // namespace quickNES
} // namespace quickerNES

View File

@ -225,4 +225,4 @@ class Mapper085 : public Mapper, vrc7_state_t
};
};
} // namespace quickNES
} // namespace quickerNES

View File

@ -26,4 +26,4 @@ namespace quickerNES
typedef Mapper_74x161x162x32<86> Mapper086;
} // namespace quickNES
} // namespace quickerNES

View File

@ -50,4 +50,4 @@ class Mapper087 : public Mapper
void write(nes_time_t, nes_addr_t, int) {}
};
} // namespace quickNES
} // namespace quickerNES

View File

@ -111,5 +111,4 @@ class Mapper_Namco_34x3 : public Mapper, namco_34x3_state_t
typedef Mapper_Namco_34x3<false> Mapper088;
} // namespace quickNES
} // namespace quickerNES

View File

@ -59,4 +59,4 @@ class Mapper089 : public Mapper
uint8_t regs;
};
} // namespace quickNES
} // namespace quickerNES

View File

@ -58,4 +58,4 @@ class Mapper093 : public Mapper
uint8_t regs;
};
} // namespace quickNES
} // namespace quickerNES

View File

@ -57,4 +57,4 @@ class Mapper094 : public Mapper
uint8_t bank;
};
} // namespace quickNES
} // namespace quickerNES

View File

@ -66,4 +66,4 @@ class Mapper097 : public Mapper
uint8_t bank;
};
} // namespace quickNES
} // namespace quickerNES

View File

@ -30,4 +30,4 @@ namespace quickerNES
typedef Mapper_AveNina<true> Mapper113;
} // namespace quickNES
} // namespace quickerNES

View File

@ -66,4 +66,4 @@ class Mapper140 : public Mapper
uint8_t regs;
};
} // namespace quickNES
} // namespace quickerNES

View File

@ -26,4 +26,4 @@ namespace quickerNES
typedef Mapper_74x161x162x32<152> Mapper152;
} // namespace quickNES
} // namespace quickerNES

View File

@ -30,4 +30,4 @@ namespace quickerNES
typedef Mapper_Namco_34x3<true> Mapper154;
} // namespace quickNES
} // namespace quickerNES

View File

@ -62,4 +62,4 @@ class Mapper156 : public Mapper, m156_state_t
}
};
} // namespace quickNES
} // namespace quickerNES

View File

@ -57,4 +57,4 @@ class Mapper180 : public Mapper
uint8_t bank;
};
} // namespace quickNES
} // namespace quickerNES

View File

@ -67,4 +67,4 @@ class Mapper184 : public Mapper
uint8_t regs;
};
} // namespace quickNES
} // namespace quickerNES

View File

@ -57,4 +57,4 @@ class Mapper190 : public Mapper
}
};
} // namespace quickNES
} // namespace quickerNES

View File

@ -78,4 +78,4 @@ class Mapper193 : public Mapper
uint8_t regs[4];
};
} // namespace quickNES
} // namespace quickerNES

View File

@ -100,4 +100,4 @@ class Mapper206 : public Mapper, namco_34xx_state_t
}
};
} // namespace quickNES
} // namespace quickerNES

View File

@ -93,4 +93,4 @@ class Mapper207 : public Mapper, taito_x1005_state_t
virtual void write(nes_time_t, nes_addr_t addr, int data) {}
};
} // namespace quickNES
} // namespace quickerNES

View File

@ -56,4 +56,4 @@ class Mapper232 : public Mapper
}
};
} // namespace quickNES
} // namespace quickerNES

View File

@ -66,4 +66,4 @@ class Mapper240 : public Mapper
uint8_t regs;
};
} // namespace quickNES
} // namespace quickerNES

View File

@ -55,4 +55,4 @@ class Mapper241 : public Mapper
uint8_t bank;
};
} // namespace quickNES
} // namespace quickerNES

View File

@ -72,4 +72,4 @@ class Mapper244 : public Mapper, mapper244_state_t
}
};
} // namespace quickNES
} // namespace quickerNES

View File

@ -77,4 +77,4 @@ class Mapper246 : public Mapper
uint8_t regs[8];
};
} // namespace quickNES
} // namespace quickerNES

Some files were not shown because too many files have changed in this diff Show More