mirror of https://github.com/bsnes-emu/bsnes.git
Update to v095r08 release.
byuu says: Changelog: - added preliminary WASAPI driver (it's really terrible, though. Patches most welcome.) - all of processor/ updated to auto fn() -> ret syntax - all of gb/ updated to auto fn() -> ret syntax If you want to test the WASAPI driver, then edit ui-tomoko/GNUmakefile, and replace audio.xaudio2 with audio.wasapi Note that the two drivers are incompatible and cannot co-exist (yet. We can probably make it work in the future.) All that's left for the auto fn() -> ret syntax is the NES core and the balanced/performance SNES components. This is kind of a big deal because this syntax change causes diffs between WIPs to go crazy. So the sooner we get this done and out of the way, the better. It's also nice from a consistency standpoint, of course.
This commit is contained in:
parent
6adfe71836
commit
a219f9c121
|
@ -7,7 +7,7 @@ using namespace nall;
|
|||
|
||||
namespace Emulator {
|
||||
static const string Name = "higan";
|
||||
static const string Version = "095.07";
|
||||
static const string Version = "095.08";
|
||||
static const string Author = "byuu";
|
||||
static const string License = "GPLv3";
|
||||
static const string Website = "http://byuu.org/";
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
#include <gb/gb.hpp>
|
||||
|
||||
#define APU_CPP
|
||||
namespace GameBoy {
|
||||
|
||||
#include "square1/square1.cpp"
|
||||
|
@ -11,11 +10,11 @@ namespace GameBoy {
|
|||
#include "serialization.cpp"
|
||||
APU apu;
|
||||
|
||||
void APU::Main() {
|
||||
auto APU::Main() -> void {
|
||||
apu.main();
|
||||
}
|
||||
|
||||
void APU::main() {
|
||||
auto APU::main() -> void {
|
||||
while(true) {
|
||||
if(scheduler.sync == Scheduler::SynchronizeMode::All) {
|
||||
scheduler.exit(Scheduler::ExitReason::SynchronizeEvent);
|
||||
|
@ -57,14 +56,14 @@ void APU::main() {
|
|||
}
|
||||
}
|
||||
|
||||
void APU::hipass(int16& sample, int64& bias) {
|
||||
auto APU::hipass(int16& sample, int64& bias) -> void {
|
||||
bias += ((((int64)sample << 16) - (bias >> 16)) * 57593) >> 16;
|
||||
sample = sclamp<16>(sample - (bias >> 32));
|
||||
}
|
||||
|
||||
void APU::power() {
|
||||
auto APU::power() -> void {
|
||||
create(Main, 2 * 1024 * 1024);
|
||||
for(unsigned n = 0xff10; n <= 0xff3f; n++) bus.mmio[n] = this;
|
||||
for(uint n = 0xff10; n <= 0xff3f; n++) bus.mmio[n] = this;
|
||||
|
||||
for(auto& n : mmio_data) n = 0x00;
|
||||
sequencer_base = 0;
|
||||
|
@ -77,7 +76,7 @@ void APU::power() {
|
|||
master.power();
|
||||
}
|
||||
|
||||
uint8 APU::mmio_read(uint16 addr) {
|
||||
auto APU::mmio_read(uint16 addr) -> uint8 {
|
||||
static const uint8 table[48] = {
|
||||
0x80, 0x3f, 0x00, 0xff, 0xbf, //square1
|
||||
0xff, 0x3f, 0x00, 0xff, 0xbf, //square2
|
||||
|
@ -102,7 +101,7 @@ uint8 APU::mmio_read(uint16 addr) {
|
|||
return 0xff;
|
||||
}
|
||||
|
||||
void APU::mmio_write(uint16 addr, uint8 data) {
|
||||
auto APU::mmio_write(uint16 addr, uint8 data) -> void {
|
||||
if(addr >= 0xff10 && addr <= 0xff3f) mmio_data[addr - 0xff10] = data;
|
||||
|
||||
if(addr >= 0xff10 && addr <= 0xff14) return square1.write (addr - 0xff10, data);
|
||||
|
|
|
@ -1,4 +1,14 @@
|
|||
struct APU : Thread, MMIO {
|
||||
static auto Main() -> void;
|
||||
auto main() -> void;
|
||||
auto hipass(int16& sample, int64& bias) -> void;
|
||||
auto power() -> void;
|
||||
|
||||
auto mmio_read(uint16 addr) -> uint8;
|
||||
auto mmio_write(uint16 addr, uint8 data) -> void;
|
||||
|
||||
auto serialize(serializer&) -> void;
|
||||
|
||||
#include "square1/square1.hpp"
|
||||
#include "square2/square2.hpp"
|
||||
#include "wave/wave.hpp"
|
||||
|
@ -14,16 +24,6 @@ struct APU : Thread, MMIO {
|
|||
Wave wave;
|
||||
Noise noise;
|
||||
Master master;
|
||||
|
||||
static void Main();
|
||||
void main();
|
||||
void hipass(int16& sample, int64& bias);
|
||||
void power();
|
||||
|
||||
uint8 mmio_read(uint16 addr);
|
||||
void mmio_write(uint16 addr, uint8 data);
|
||||
|
||||
void serialize(serializer&);
|
||||
};
|
||||
|
||||
extern APU apu;
|
||||
|
|
|
@ -1,16 +1,14 @@
|
|||
#ifdef APU_CPP
|
||||
|
||||
void APU::Master::run() {
|
||||
auto APU::Master::run() -> void {
|
||||
if(enable == false) {
|
||||
center = 0;
|
||||
left = 0;
|
||||
right = 0;
|
||||
|
||||
center_bias = left_bias = right_bias = 0;
|
||||
center_bias = left_bias = right_bias = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
signed sample = 0;
|
||||
int sample = 0;
|
||||
sample += apu.square1.output;
|
||||
sample += apu.square2.output;
|
||||
sample += apu.wave.output;
|
||||
|
@ -41,7 +39,7 @@ center_bias = left_bias = right_bias = 0;
|
|||
right >>= 1;
|
||||
}
|
||||
|
||||
void APU::Master::write(unsigned r, uint8 data) {
|
||||
auto APU::Master::write(uint r, uint8 data) -> void {
|
||||
if(r == 0) { //$ff24 NR50
|
||||
left_in_enable = data & 0x80;
|
||||
left_volume = (data >> 4) & 7;
|
||||
|
@ -65,7 +63,7 @@ void APU::Master::write(unsigned r, uint8 data) {
|
|||
}
|
||||
}
|
||||
|
||||
void APU::Master::power() {
|
||||
auto APU::Master::power() -> void {
|
||||
left_in_enable = 0;
|
||||
left_volume = 0;
|
||||
right_in_enable = 0;
|
||||
|
@ -89,7 +87,7 @@ void APU::Master::power() {
|
|||
right_bias = 0;
|
||||
}
|
||||
|
||||
void APU::Master::serialize(serializer& s) {
|
||||
auto APU::Master::serialize(serializer& s) -> void {
|
||||
s.integer(left_in_enable);
|
||||
s.integer(left_volume);
|
||||
s.integer(right_in_enable);
|
||||
|
@ -112,5 +110,3 @@ void APU::Master::serialize(serializer& s) {
|
|||
s.integer(left_bias);
|
||||
s.integer(right_bias);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
@ -1,4 +1,10 @@
|
|||
struct Master {
|
||||
auto run() -> void;
|
||||
auto write(uint r, uint8 data) -> void;
|
||||
auto power() -> void;
|
||||
|
||||
auto serialize(serializer&) -> void;
|
||||
|
||||
bool left_in_enable;
|
||||
uint3 left_volume;
|
||||
bool right_in_enable;
|
||||
|
@ -20,9 +26,4 @@ struct Master {
|
|||
int64 center_bias;
|
||||
int64 left_bias;
|
||||
int64 right_bias;
|
||||
|
||||
void run();
|
||||
void write(unsigned r, uint8 data);
|
||||
void power();
|
||||
void serialize(serializer&);
|
||||
};
|
||||
|
|
|
@ -1,10 +1,8 @@
|
|||
#ifdef APU_CPP
|
||||
|
||||
bool APU::Noise::dac_enable() {
|
||||
auto APU::Noise::dac_enable() const -> bool {
|
||||
return (envelope_volume || envelope_direction);
|
||||
}
|
||||
|
||||
void APU::Noise::run() {
|
||||
auto APU::Noise::run() -> void {
|
||||
if(period && --period == 0) {
|
||||
period = divisor << frequency;
|
||||
if(frequency < 14) {
|
||||
|
@ -19,13 +17,13 @@ void APU::Noise::run() {
|
|||
output = sample;
|
||||
}
|
||||
|
||||
void APU::Noise::clock_length() {
|
||||
auto APU::Noise::clock_length() -> void {
|
||||
if(enable && counter) {
|
||||
if(++length == 0) enable = false;
|
||||
}
|
||||
}
|
||||
|
||||
void APU::Noise::clock_envelope() {
|
||||
auto APU::Noise::clock_envelope() -> void {
|
||||
if(enable && envelope_frequency && --envelope_period == 0) {
|
||||
envelope_period = envelope_frequency;
|
||||
if(envelope_direction == 0 && volume > 0) volume--;
|
||||
|
@ -33,7 +31,7 @@ void APU::Noise::clock_envelope() {
|
|||
}
|
||||
}
|
||||
|
||||
void APU::Noise::write(unsigned r, uint8 data) {
|
||||
auto APU::Noise::write(uint r, uint8 data) -> void {
|
||||
if(r == 1) { //$ff20 NR41
|
||||
length = data & 0x3f;
|
||||
}
|
||||
|
@ -66,7 +64,7 @@ void APU::Noise::write(unsigned r, uint8 data) {
|
|||
}
|
||||
}
|
||||
|
||||
void APU::Noise::power() {
|
||||
auto APU::Noise::power() -> void {
|
||||
enable = 0;
|
||||
|
||||
envelope_volume = 0;
|
||||
|
@ -85,7 +83,7 @@ void APU::Noise::power() {
|
|||
lfsr = 0;
|
||||
}
|
||||
|
||||
void APU::Noise::serialize(serializer& s) {
|
||||
auto APU::Noise::serialize(serializer& s) -> void {
|
||||
s.integer(enable);
|
||||
|
||||
s.integer(envelope_volume);
|
||||
|
@ -103,5 +101,3 @@ void APU::Noise::serialize(serializer& s) {
|
|||
s.integer(period);
|
||||
s.integer(lfsr);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
@ -1,4 +1,14 @@
|
|||
struct Noise {
|
||||
auto dac_enable() const -> bool;
|
||||
|
||||
auto run() -> void;
|
||||
auto clock_length() -> void;
|
||||
auto clock_envelope() -> void;
|
||||
auto write(uint r, uint8 data) -> void;
|
||||
auto power() -> void;
|
||||
|
||||
auto serialize(serializer&) -> void;
|
||||
|
||||
bool enable;
|
||||
|
||||
uint4 envelope_volume;
|
||||
|
@ -6,22 +16,13 @@ struct Noise {
|
|||
uint3 envelope_frequency;
|
||||
uint4 frequency;
|
||||
bool narrow_lfsr;
|
||||
unsigned divisor;
|
||||
uint divisor;
|
||||
bool counter;
|
||||
|
||||
int16 output;
|
||||
uint6 length;
|
||||
uint3 envelope_period;
|
||||
uint4 volume;
|
||||
unsigned period;
|
||||
uint period;
|
||||
uint15 lfsr;
|
||||
|
||||
bool dac_enable();
|
||||
|
||||
void run();
|
||||
void clock_length();
|
||||
void clock_envelope();
|
||||
void write(unsigned r, uint8 data);
|
||||
void power();
|
||||
void serialize(serializer&);
|
||||
};
|
||||
|
|
|
@ -1,6 +1,4 @@
|
|||
#ifdef APU_CPP
|
||||
|
||||
void APU::serialize(serializer& s) {
|
||||
auto APU::serialize(serializer& s) -> void {
|
||||
Thread::serialize(s);
|
||||
|
||||
s.array(mmio_data);
|
||||
|
@ -13,5 +11,3 @@ void APU::serialize(serializer& s) {
|
|||
noise.serialize(s);
|
||||
master.serialize(s);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
@ -1,10 +1,8 @@
|
|||
#ifdef APU_CPP
|
||||
|
||||
bool APU::Square1::dac_enable() {
|
||||
auto APU::Square1::dac_enable() const -> bool {
|
||||
return (envelope_volume || envelope_direction);
|
||||
}
|
||||
|
||||
void APU::Square1::run() {
|
||||
auto APU::Square1::run() -> void {
|
||||
if(period && --period == 0) {
|
||||
period = 2 * (2048 - frequency);
|
||||
phase++;
|
||||
|
@ -22,12 +20,12 @@ void APU::Square1::run() {
|
|||
output = sample;
|
||||
}
|
||||
|
||||
void APU::Square1::sweep(bool update) {
|
||||
auto APU::Square1::sweep(bool update) -> void {
|
||||
if(sweep_enable == false) return;
|
||||
|
||||
sweep_negate = sweep_direction;
|
||||
unsigned delta = frequency_shadow >> sweep_shift;
|
||||
signed freq = frequency_shadow + (sweep_negate ? -delta : delta);
|
||||
uint delta = frequency_shadow >> sweep_shift;
|
||||
int freq = frequency_shadow + (sweep_negate ? -delta : delta);
|
||||
|
||||
if(freq > 2047) {
|
||||
enable = false;
|
||||
|
@ -38,13 +36,13 @@ void APU::Square1::sweep(bool update) {
|
|||
}
|
||||
}
|
||||
|
||||
void APU::Square1::clock_length() {
|
||||
auto APU::Square1::clock_length() -> void {
|
||||
if(counter && enable) {
|
||||
if(++length == 0) enable = false;
|
||||
}
|
||||
}
|
||||
|
||||
void APU::Square1::clock_sweep() {
|
||||
auto APU::Square1::clock_sweep() -> void {
|
||||
if(enable && sweep_frequency && --sweep_period == 0) {
|
||||
sweep_period = sweep_frequency;
|
||||
sweep(1);
|
||||
|
@ -52,7 +50,7 @@ void APU::Square1::clock_sweep() {
|
|||
}
|
||||
}
|
||||
|
||||
void APU::Square1::clock_envelope() {
|
||||
auto APU::Square1::clock_envelope() -> void {
|
||||
if(enable && envelope_frequency && --envelope_period == 0) {
|
||||
envelope_period = envelope_frequency;
|
||||
if(envelope_direction == 0 && volume > 0) volume--;
|
||||
|
@ -60,7 +58,7 @@ void APU::Square1::clock_envelope() {
|
|||
}
|
||||
}
|
||||
|
||||
void APU::Square1::write(unsigned r, uint8 data) {
|
||||
auto APU::Square1::write(uint r, uint8 data) -> void {
|
||||
if(r == 0) { //$ff10 NR10
|
||||
if(sweep_negate && sweep_direction && !(data & 0x08)) enable = false;
|
||||
sweep_frequency = (data >> 4) & 7;
|
||||
|
@ -103,7 +101,7 @@ void APU::Square1::write(unsigned r, uint8 data) {
|
|||
}
|
||||
}
|
||||
|
||||
void APU::Square1::power() {
|
||||
auto APU::Square1::power() -> void {
|
||||
enable = 0;
|
||||
|
||||
sweep_frequency = 0;
|
||||
|
@ -129,7 +127,7 @@ void APU::Square1::power() {
|
|||
volume = 0;
|
||||
}
|
||||
|
||||
void APU::Square1::serialize(serializer& s) {
|
||||
auto APU::Square1::serialize(serializer& s) -> void {
|
||||
s.integer(enable);
|
||||
|
||||
s.integer(sweep_frequency);
|
||||
|
@ -154,5 +152,3 @@ void APU::Square1::serialize(serializer& s) {
|
|||
s.integer(sweep_enable);
|
||||
s.integer(volume);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
@ -1,4 +1,16 @@
|
|||
struct Square1 {
|
||||
auto dac_enable() const -> bool;
|
||||
|
||||
auto run() -> void;
|
||||
auto sweep(bool update) -> void;
|
||||
auto clock_length() -> void;
|
||||
auto clock_sweep() -> void;
|
||||
auto clock_envelope() -> void;
|
||||
auto write(uint r, uint8 data) -> void;
|
||||
auto power() -> void;
|
||||
|
||||
auto serialize(serializer&) -> void;
|
||||
|
||||
bool enable;
|
||||
|
||||
uint3 sweep_frequency;
|
||||
|
@ -16,21 +28,10 @@ struct Square1 {
|
|||
int16 output;
|
||||
bool duty_output;
|
||||
uint3 phase;
|
||||
unsigned period;
|
||||
uint period;
|
||||
uint3 envelope_period;
|
||||
uint3 sweep_period;
|
||||
signed frequency_shadow;
|
||||
int frequency_shadow;
|
||||
bool sweep_enable;
|
||||
uint4 volume;
|
||||
|
||||
bool dac_enable();
|
||||
|
||||
void run();
|
||||
void sweep(bool update);
|
||||
void clock_length();
|
||||
void clock_sweep();
|
||||
void clock_envelope();
|
||||
void write(unsigned r, uint8 data);
|
||||
void power();
|
||||
void serialize(serializer&);
|
||||
};
|
||||
|
|
|
@ -1,10 +1,8 @@
|
|||
#ifdef APU_CPP
|
||||
|
||||
bool APU::Square2::dac_enable() {
|
||||
auto APU::Square2::dac_enable() const -> bool {
|
||||
return (envelope_volume || envelope_direction);
|
||||
}
|
||||
|
||||
void APU::Square2::run() {
|
||||
auto APU::Square2::run() -> void {
|
||||
if(period && --period == 0) {
|
||||
period = 2 * (2048 - frequency);
|
||||
phase++;
|
||||
|
@ -22,13 +20,13 @@ void APU::Square2::run() {
|
|||
output = sample;
|
||||
}
|
||||
|
||||
void APU::Square2::clock_length() {
|
||||
auto APU::Square2::clock_length() -> void {
|
||||
if(counter && enable) {
|
||||
if(++length == 0) enable = false;
|
||||
}
|
||||
}
|
||||
|
||||
void APU::Square2::clock_envelope() {
|
||||
auto APU::Square2::clock_envelope() -> void {
|
||||
if(enable && envelope_frequency && --envelope_period == 0) {
|
||||
envelope_period = envelope_frequency;
|
||||
if(envelope_direction == 0 && volume > 0) volume--;
|
||||
|
@ -36,7 +34,7 @@ void APU::Square2::clock_envelope() {
|
|||
}
|
||||
}
|
||||
|
||||
void APU::Square2::write(unsigned r, uint8 data) {
|
||||
auto APU::Square2::write(uint r, uint8 data) -> void {
|
||||
if(r == 1) { //$ff16 NR21
|
||||
duty = data >> 6;
|
||||
length = (data & 0x3f);
|
||||
|
@ -67,7 +65,7 @@ void APU::Square2::write(unsigned r, uint8 data) {
|
|||
}
|
||||
}
|
||||
|
||||
void APU::Square2::power() {
|
||||
auto APU::Square2::power() -> void {
|
||||
enable = 0;
|
||||
|
||||
duty = 0;
|
||||
|
@ -86,7 +84,7 @@ void APU::Square2::power() {
|
|||
volume = 0;
|
||||
}
|
||||
|
||||
void APU::Square2::serialize(serializer& s) {
|
||||
auto APU::Square2::serialize(serializer& s) -> void {
|
||||
s.integer(enable);
|
||||
|
||||
s.integer(duty);
|
||||
|
@ -104,5 +102,3 @@ void APU::Square2::serialize(serializer& s) {
|
|||
s.integer(envelope_period);
|
||||
s.integer(volume);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
@ -1,4 +1,14 @@
|
|||
struct Square2 {
|
||||
auto dac_enable() const -> bool;
|
||||
|
||||
auto run() -> void;
|
||||
auto clock_length() -> void;
|
||||
auto clock_envelope() -> void;
|
||||
auto write(uint r, uint8 data) -> void;
|
||||
auto power() -> void;
|
||||
|
||||
auto serialize(serializer&) -> void;
|
||||
|
||||
bool enable;
|
||||
|
||||
uint2 duty;
|
||||
|
@ -12,16 +22,7 @@ struct Square2 {
|
|||
int16 output;
|
||||
bool duty_output;
|
||||
uint3 phase;
|
||||
unsigned period;
|
||||
uint period;
|
||||
uint3 envelope_period;
|
||||
uint4 volume;
|
||||
|
||||
bool dac_enable();
|
||||
|
||||
void run();
|
||||
void clock_length();
|
||||
void clock_envelope();
|
||||
void write(unsigned r, uint8 data);
|
||||
void power();
|
||||
void serialize(serializer&);
|
||||
};
|
||||
|
|
|
@ -1,6 +1,4 @@
|
|||
#ifdef APU_CPP
|
||||
|
||||
void APU::Wave::run() {
|
||||
auto APU::Wave::run() -> void {
|
||||
if(period && --period == 0) {
|
||||
period = 1 * (2048 - frequency);
|
||||
pattern_sample = pattern[++pattern_offset];
|
||||
|
@ -12,13 +10,13 @@ void APU::Wave::run() {
|
|||
output = sample;
|
||||
}
|
||||
|
||||
void APU::Wave::clock_length() {
|
||||
auto APU::Wave::clock_length() -> void {
|
||||
if(enable && counter) {
|
||||
if(++length == 0) enable = false;
|
||||
}
|
||||
}
|
||||
|
||||
void APU::Wave::write(unsigned r, uint8 data) {
|
||||
auto APU::Wave::write(uint r, uint8 data) -> void {
|
||||
if(r == 0) { //$ff1a NR30
|
||||
dac_enable = data & 0x80;
|
||||
if(dac_enable == false) enable = false;
|
||||
|
@ -54,13 +52,13 @@ void APU::Wave::write(unsigned r, uint8 data) {
|
|||
}
|
||||
}
|
||||
|
||||
void APU::Wave::write_pattern(unsigned p, uint8 data) {
|
||||
auto APU::Wave::write_pattern(uint p, uint8 data) -> void {
|
||||
p <<= 1;
|
||||
pattern[p + 0] = (data >> 4) & 15;
|
||||
pattern[p + 1] = (data >> 0) & 15;
|
||||
}
|
||||
|
||||
void APU::Wave::power() {
|
||||
auto APU::Wave::power() -> void {
|
||||
enable = 0;
|
||||
|
||||
dac_enable = 0;
|
||||
|
@ -78,7 +76,7 @@ void APU::Wave::power() {
|
|||
pattern_sample = 0;
|
||||
}
|
||||
|
||||
void APU::Wave::serialize(serializer& s) {
|
||||
auto APU::Wave::serialize(serializer& s) -> void {
|
||||
s.integer(enable);
|
||||
|
||||
s.integer(dac_enable);
|
||||
|
@ -93,5 +91,3 @@ void APU::Wave::serialize(serializer& s) {
|
|||
s.integer(pattern_offset);
|
||||
s.integer(pattern_sample);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
@ -1,22 +1,23 @@
|
|||
struct Wave {
|
||||
auto run() -> void;
|
||||
auto clock_length() -> void;
|
||||
auto write(uint r, uint8 data) -> void;
|
||||
auto write_pattern(uint p, uint8 data) -> void;
|
||||
auto power() -> void;
|
||||
|
||||
auto serialize(serializer&) -> void;
|
||||
|
||||
bool enable;
|
||||
|
||||
bool dac_enable;
|
||||
unsigned volume_shift;
|
||||
uint volume_shift;
|
||||
uint11 frequency;
|
||||
bool counter;
|
||||
uint8 pattern[32];
|
||||
|
||||
int16 output;
|
||||
uint8 length;
|
||||
unsigned period;
|
||||
uint period;
|
||||
uint5 pattern_offset;
|
||||
uint4 pattern_sample;
|
||||
|
||||
void run();
|
||||
void clock_length();
|
||||
void write(unsigned r, uint8 data);
|
||||
void write_pattern(unsigned p, uint8 data);
|
||||
void power();
|
||||
void serialize(serializer&);
|
||||
};
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
#include <gb/gb.hpp>
|
||||
|
||||
#define CARTRIDGE_CPP
|
||||
namespace GameBoy {
|
||||
|
||||
#include "mbc0/mbc0.cpp"
|
||||
|
@ -14,12 +13,21 @@ namespace GameBoy {
|
|||
#include "serialization.cpp"
|
||||
Cartridge cartridge;
|
||||
|
||||
string Cartridge::title() {
|
||||
Cartridge::Cartridge() {
|
||||
loaded = false;
|
||||
sha256 = "";
|
||||
}
|
||||
|
||||
Cartridge::~Cartridge() {
|
||||
unload();
|
||||
}
|
||||
|
||||
auto Cartridge::title() -> string {
|
||||
return information.title;
|
||||
}
|
||||
|
||||
//intended for use with Super Game Boy for when no Game Boy cartridge is inserted
|
||||
void Cartridge::load_empty(System::Revision revision) {
|
||||
auto Cartridge::load_empty(System::Revision revision) -> void {
|
||||
unload();
|
||||
romsize = 32768;
|
||||
romdata = allocate<uint8>(romsize, 0xff);
|
||||
|
@ -30,7 +38,7 @@ void Cartridge::load_empty(System::Revision revision) {
|
|||
system.load(revision);
|
||||
}
|
||||
|
||||
void Cartridge::load(System::Revision revision) {
|
||||
auto Cartridge::load(System::Revision revision) -> void {
|
||||
unload();
|
||||
|
||||
system.revision = revision; //needed for ID::Manifest to return correct group ID
|
||||
|
@ -99,35 +107,35 @@ void Cartridge::load(System::Revision revision) {
|
|||
system.load(revision);
|
||||
}
|
||||
|
||||
void Cartridge::unload() {
|
||||
auto Cartridge::unload() -> void {
|
||||
if(romdata) { delete[] romdata; romdata = nullptr; romsize = 0; }
|
||||
if(ramdata) { delete[] ramdata; ramdata = nullptr; ramsize = 0; }
|
||||
loaded = false;
|
||||
}
|
||||
|
||||
uint8 Cartridge::rom_read(unsigned addr) {
|
||||
auto Cartridge::rom_read(uint addr) -> uint8 {
|
||||
if(addr >= romsize) addr %= romsize;
|
||||
return romdata[addr];
|
||||
}
|
||||
|
||||
void Cartridge::rom_write(unsigned addr, uint8 data) {
|
||||
auto Cartridge::rom_write(uint addr, uint8 data) -> void {
|
||||
if(addr >= romsize) addr %= romsize;
|
||||
romdata[addr] = data;
|
||||
}
|
||||
|
||||
uint8 Cartridge::ram_read(unsigned addr) {
|
||||
auto Cartridge::ram_read(uint addr) -> uint8 {
|
||||
if(ramsize == 0) return 0x00;
|
||||
if(addr >= ramsize) addr %= ramsize;
|
||||
return ramdata[addr];
|
||||
}
|
||||
|
||||
void Cartridge::ram_write(unsigned addr, uint8 data) {
|
||||
auto Cartridge::ram_write(uint addr, uint8 data) -> void {
|
||||
if(ramsize == 0) return;
|
||||
if(addr >= ramsize) addr %= ramsize;
|
||||
ramdata[addr] = data;
|
||||
}
|
||||
|
||||
uint8 Cartridge::mmio_read(uint16 addr) {
|
||||
auto Cartridge::mmio_read(uint16 addr) -> uint8 {
|
||||
if(addr == 0xff50) return 0x00;
|
||||
|
||||
if(bootrom_enable) {
|
||||
|
@ -144,7 +152,7 @@ uint8 Cartridge::mmio_read(uint16 addr) {
|
|||
return mapper->mmio_read(addr);
|
||||
}
|
||||
|
||||
void Cartridge::mmio_write(uint16 addr, uint8 data) {
|
||||
auto Cartridge::mmio_write(uint16 addr, uint8 data) -> void {
|
||||
if(bootrom_enable && addr == 0xff50) {
|
||||
bootrom_enable = false;
|
||||
return;
|
||||
|
@ -153,7 +161,7 @@ void Cartridge::mmio_write(uint16 addr, uint8 data) {
|
|||
mapper->mmio_write(addr, data);
|
||||
}
|
||||
|
||||
void Cartridge::power() {
|
||||
auto Cartridge::power() -> void {
|
||||
bootrom_enable = true;
|
||||
|
||||
mbc0.power();
|
||||
|
@ -165,18 +173,9 @@ void Cartridge::power() {
|
|||
huc1.power();
|
||||
huc3.power();
|
||||
|
||||
for(unsigned n = 0x0000; n <= 0x7fff; n++) bus.mmio[n] = this;
|
||||
for(unsigned n = 0xa000; n <= 0xbfff; n++) bus.mmio[n] = this;
|
||||
for(uint n = 0x0000; n <= 0x7fff; n++) bus.mmio[n] = this;
|
||||
for(uint n = 0xa000; n <= 0xbfff; n++) bus.mmio[n] = this;
|
||||
bus.mmio[0xff50] = this;
|
||||
}
|
||||
|
||||
Cartridge::Cartridge() {
|
||||
loaded = false;
|
||||
sha256 = "";
|
||||
}
|
||||
|
||||
Cartridge::~Cartridge() {
|
||||
unload();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1,4 +1,23 @@
|
|||
struct Cartridge : MMIO, property<Cartridge> {
|
||||
Cartridge();
|
||||
~Cartridge();
|
||||
|
||||
auto load_empty(System::Revision revision) -> void;
|
||||
auto load(System::Revision revision) -> void;
|
||||
auto unload() -> void;
|
||||
|
||||
auto rom_read(uint addr) -> uint8;
|
||||
auto rom_write(uint addr, uint8 data) -> void;
|
||||
auto ram_read(uint addr) -> uint8;
|
||||
auto ram_write(uint addr, uint8 data) -> void;
|
||||
|
||||
auto mmio_read(uint16 addr) -> uint8;
|
||||
auto mmio_write(uint16 addr, uint8 data) -> void;
|
||||
|
||||
auto power() -> void;
|
||||
|
||||
auto serialize(serializer&) -> void;
|
||||
|
||||
#include "mbc0/mbc0.hpp"
|
||||
#include "mbc1/mbc1.hpp"
|
||||
#include "mbc2/mbc2.hpp"
|
||||
|
@ -8,7 +27,7 @@ struct Cartridge : MMIO, property<Cartridge> {
|
|||
#include "huc1/huc1.hpp"
|
||||
#include "huc3/huc3.hpp"
|
||||
|
||||
enum Mapper : unsigned {
|
||||
enum Mapper : uint {
|
||||
MBC0,
|
||||
MBC1,
|
||||
MBC2,
|
||||
|
@ -30,14 +49,14 @@ struct Cartridge : MMIO, property<Cartridge> {
|
|||
bool rtc;
|
||||
bool rumble;
|
||||
|
||||
unsigned romsize;
|
||||
unsigned ramsize;
|
||||
uint romsize;
|
||||
uint ramsize;
|
||||
} information;
|
||||
|
||||
string title();
|
||||
|
||||
struct Memory {
|
||||
unsigned id;
|
||||
uint id;
|
||||
string name;
|
||||
};
|
||||
vector<Memory> memory;
|
||||
|
@ -45,32 +64,14 @@ struct Cartridge : MMIO, property<Cartridge> {
|
|||
readonly<bool> loaded;
|
||||
readonly<string> sha256;
|
||||
|
||||
uint8_t* romdata = nullptr;
|
||||
unsigned romsize = 0;
|
||||
uint8* romdata = nullptr;
|
||||
uint romsize = 0;
|
||||
|
||||
uint8_t* ramdata = nullptr;
|
||||
unsigned ramsize = 0;
|
||||
uint8* ramdata = nullptr;
|
||||
uint ramsize = 0;
|
||||
|
||||
MMIO* mapper = nullptr;
|
||||
bool bootrom_enable = true;
|
||||
|
||||
void load_empty(System::Revision revision);
|
||||
void load(System::Revision revision);
|
||||
void unload();
|
||||
|
||||
uint8 rom_read(unsigned addr);
|
||||
void rom_write(unsigned addr, uint8 data);
|
||||
uint8 ram_read(unsigned addr);
|
||||
void ram_write(unsigned addr, uint8 data);
|
||||
|
||||
uint8 mmio_read(uint16 addr);
|
||||
void mmio_write(uint16 addr, uint8 data);
|
||||
|
||||
void power();
|
||||
|
||||
void serialize(serializer&);
|
||||
Cartridge();
|
||||
~Cartridge();
|
||||
};
|
||||
|
||||
extern Cartridge cartridge;
|
||||
|
|
|
@ -1,6 +1,4 @@
|
|||
#ifdef CARTRIDGE_CPP
|
||||
|
||||
uint8 Cartridge::HuC1::mmio_read(uint16 addr) {
|
||||
auto Cartridge::HuC1::mmio_read(uint16 addr) -> uint8 {
|
||||
if((addr & 0xc000) == 0x0000) { //$0000-3fff
|
||||
return cartridge.rom_read(addr);
|
||||
}
|
||||
|
@ -16,7 +14,7 @@ uint8 Cartridge::HuC1::mmio_read(uint16 addr) {
|
|||
return 0x00;
|
||||
}
|
||||
|
||||
void Cartridge::HuC1::mmio_write(uint16 addr, uint8 data) {
|
||||
auto Cartridge::HuC1::mmio_write(uint16 addr, uint8 data) -> void {
|
||||
if((addr & 0xe000) == 0x0000) { //$0000-1fff
|
||||
ram_writable = (data & 0x0f) == 0x0a;
|
||||
return;
|
||||
|
@ -44,11 +42,9 @@ void Cartridge::HuC1::mmio_write(uint16 addr, uint8 data) {
|
|||
}
|
||||
}
|
||||
|
||||
void Cartridge::HuC1::power() {
|
||||
auto Cartridge::HuC1::power() -> void {
|
||||
ram_writable = false;
|
||||
rom_select = 0x01;
|
||||
ram_select = 0x00;
|
||||
model = 0;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
struct HuC1 : MMIO {
|
||||
auto mmio_read(uint16 addr) -> uint8;
|
||||
auto mmio_write(uint16 addr, uint8 data) -> void;
|
||||
auto power() -> void;
|
||||
|
||||
bool ram_writable; //$0000-1fff
|
||||
uint8 rom_select; //$2000-3fff
|
||||
uint8 ram_select; //$4000-5fff
|
||||
bool model; //$6000-7fff
|
||||
|
||||
uint8 mmio_read(uint16 addr);
|
||||
void mmio_write(uint16 addr, uint8 data);
|
||||
void power();
|
||||
} huc1;
|
||||
|
|
|
@ -1,6 +1,4 @@
|
|||
#ifdef CARTRIDGE_CPP
|
||||
|
||||
uint8 Cartridge::HuC3::mmio_read(uint16 addr) {
|
||||
auto Cartridge::HuC3::mmio_read(uint16 addr) -> uint8 {
|
||||
if((addr & 0xc000) == 0x0000) { //$0000-3fff
|
||||
return cartridge.rom_read(addr);
|
||||
}
|
||||
|
@ -17,7 +15,7 @@ uint8 Cartridge::HuC3::mmio_read(uint16 addr) {
|
|||
return 0x00;
|
||||
}
|
||||
|
||||
void Cartridge::HuC3::mmio_write(uint16 addr, uint8 data) {
|
||||
auto Cartridge::HuC3::mmio_write(uint16 addr, uint8 data) -> void {
|
||||
if((addr & 0xe000) == 0x0000) { //$0000-1fff
|
||||
ram_enable = (data & 0x0f) == 0x0a;
|
||||
return;
|
||||
|
@ -44,10 +42,8 @@ void Cartridge::HuC3::mmio_write(uint16 addr, uint8 data) {
|
|||
}
|
||||
}
|
||||
|
||||
void Cartridge::HuC3::power() {
|
||||
auto Cartridge::HuC3::power() -> void {
|
||||
ram_enable = false;
|
||||
rom_select = 0x01;
|
||||
ram_select = 0x00;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
struct HuC3 : MMIO {
|
||||
auto mmio_read(uint16 addr) -> uint8;
|
||||
auto mmio_write(uint16 addr, uint8 data) -> void;
|
||||
auto power() -> void;
|
||||
|
||||
bool ram_enable; //$0000-1fff
|
||||
uint8 rom_select; //$2000-3fff
|
||||
uint8 ram_select; //$4000-5fff
|
||||
|
||||
uint8 mmio_read(uint16 addr);
|
||||
void mmio_write(uint16 addr, uint8 data);
|
||||
void power();
|
||||
} huc3;
|
||||
|
|
|
@ -1,6 +1,4 @@
|
|||
#ifdef CARTRIDGE_CPP
|
||||
|
||||
uint8 Cartridge::MBC0::mmio_read(uint16 addr) {
|
||||
auto Cartridge::MBC0::mmio_read(uint16 addr) -> uint8 {
|
||||
if((addr & 0x8000) == 0x0000) { //$0000-7fff
|
||||
return cartridge.rom_read(addr);
|
||||
}
|
||||
|
@ -12,14 +10,12 @@ uint8 Cartridge::MBC0::mmio_read(uint16 addr) {
|
|||
return 0x00;
|
||||
}
|
||||
|
||||
void Cartridge::MBC0::mmio_write(uint16 addr, uint8 data) {
|
||||
auto Cartridge::MBC0::mmio_write(uint16 addr, uint8 data) -> void {
|
||||
if((addr & 0xe000) == 0xa000) { //$a000-bfff
|
||||
cartridge.ram_write(addr & 0x1fff, data);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
void Cartridge::MBC0::power() {
|
||||
auto Cartridge::MBC0::power() -> void {
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
struct MBC0 : MMIO {
|
||||
uint8 mmio_read(uint16 addr);
|
||||
void mmio_write(uint16 addr, uint8 data);
|
||||
void power();
|
||||
auto mmio_read(uint16 addr) -> uint8;
|
||||
auto mmio_write(uint16 addr, uint8 data) -> void;
|
||||
auto power() -> void;
|
||||
} mbc0;
|
||||
|
|
|
@ -1,6 +1,4 @@
|
|||
#ifdef CARTRIDGE_CPP
|
||||
|
||||
uint8 Cartridge::MBC1::mmio_read(uint16 addr) {
|
||||
auto Cartridge::MBC1::mmio_read(uint16 addr) -> uint8 {
|
||||
if((addr & 0xc000) == 0x0000) { //$0000-3fff
|
||||
return cartridge.rom_read(addr);
|
||||
}
|
||||
|
@ -27,7 +25,7 @@ uint8 Cartridge::MBC1::mmio_read(uint16 addr) {
|
|||
return 0x00;
|
||||
}
|
||||
|
||||
void Cartridge::MBC1::mmio_write(uint16 addr, uint8 data) {
|
||||
auto Cartridge::MBC1::mmio_write(uint16 addr, uint8 data) -> void {
|
||||
if((addr & 0xe000) == 0x0000) { //$0000-1fff
|
||||
ram_enable = (data & 0x0f) == 0x0a;
|
||||
return;
|
||||
|
@ -60,11 +58,9 @@ void Cartridge::MBC1::mmio_write(uint16 addr, uint8 data) {
|
|||
}
|
||||
}
|
||||
|
||||
void Cartridge::MBC1::power() {
|
||||
auto Cartridge::MBC1::power() -> void {
|
||||
ram_enable = false;
|
||||
rom_select = 0x01;
|
||||
ram_select = 0x00;
|
||||
mode_select = 0;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
struct MBC1 : MMIO {
|
||||
auto mmio_read(uint16 addr) -> uint8;
|
||||
auto mmio_write(uint16 addr, uint8 data) -> void;
|
||||
auto power() -> void;
|
||||
|
||||
bool ram_enable; //$0000-1fff
|
||||
uint8 rom_select; //$2000-3fff
|
||||
uint8 ram_select; //$4000-5fff
|
||||
bool mode_select; //$6000-7fff
|
||||
|
||||
uint8 mmio_read(uint16 addr);
|
||||
void mmio_write(uint16 addr, uint8 data);
|
||||
void power();
|
||||
} mbc1;
|
||||
|
|
|
@ -1,6 +1,4 @@
|
|||
#ifdef CARTRIDGE_CPP
|
||||
|
||||
uint8 Cartridge::MBC2::mmio_read(uint16 addr) {
|
||||
auto Cartridge::MBC2::mmio_read(uint16 addr) -> uint8 {
|
||||
if((addr & 0xc000) == 0x0000) { //$0000-3fff
|
||||
return cartridge.rom_read(addr);
|
||||
}
|
||||
|
@ -17,7 +15,7 @@ uint8 Cartridge::MBC2::mmio_read(uint16 addr) {
|
|||
return 0x00;
|
||||
}
|
||||
|
||||
void Cartridge::MBC2::mmio_write(uint16 addr, uint8 data) {
|
||||
auto Cartridge::MBC2::mmio_write(uint16 addr, uint8 data) -> void {
|
||||
if((addr & 0xe000) == 0x0000) { //$0000-1fff
|
||||
if(!(addr & 0x0100)) ram_enable = (data & 0x0f) == 0x0a;
|
||||
return;
|
||||
|
@ -34,9 +32,7 @@ void Cartridge::MBC2::mmio_write(uint16 addr, uint8 data) {
|
|||
}
|
||||
}
|
||||
|
||||
void Cartridge::MBC2::power() {
|
||||
auto Cartridge::MBC2::power() -> void {
|
||||
ram_enable = false;
|
||||
rom_select = 0x01;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
struct MBC2 : MMIO {
|
||||
auto mmio_read(uint16 addr) -> uint8;
|
||||
auto mmio_write(uint16 addr, uint8 data) -> void;
|
||||
auto power() -> void;
|
||||
|
||||
bool ram_enable; //$0000-1fff
|
||||
uint8 rom_select; //$2000-3fff
|
||||
|
||||
uint8 mmio_read(uint16 addr);
|
||||
void mmio_write(uint16 addr, uint8 data);
|
||||
void power();
|
||||
} mbc2;
|
||||
|
|
|
@ -1,6 +1,4 @@
|
|||
#ifdef CARTRIDGE_CPP
|
||||
|
||||
void Cartridge::MBC3::second() {
|
||||
auto Cartridge::MBC3::second() -> void {
|
||||
if(rtc_halt == false) {
|
||||
if(++rtc_second >= 60) {
|
||||
rtc_second = 0;
|
||||
|
@ -18,7 +16,7 @@ void Cartridge::MBC3::second() {
|
|||
}
|
||||
}
|
||||
|
||||
uint8 Cartridge::MBC3::mmio_read(uint16 addr) {
|
||||
auto Cartridge::MBC3::mmio_read(uint16 addr) -> uint8 {
|
||||
if((addr & 0xc000) == 0x0000) { //$0000-3fff
|
||||
return cartridge.rom_read(addr);
|
||||
}
|
||||
|
@ -44,7 +42,7 @@ uint8 Cartridge::MBC3::mmio_read(uint16 addr) {
|
|||
return 0x00;
|
||||
}
|
||||
|
||||
void Cartridge::MBC3::mmio_write(uint16 addr, uint8 data) {
|
||||
auto Cartridge::MBC3::mmio_write(uint16 addr, uint8 data) -> void {
|
||||
if((addr & 0xe000) == 0x0000) { //$0000-1fff
|
||||
ram_enable = (data & 0x0f) == 0x0a;
|
||||
return;
|
||||
|
@ -97,7 +95,7 @@ void Cartridge::MBC3::mmio_write(uint16 addr, uint8 data) {
|
|||
}
|
||||
}
|
||||
|
||||
void Cartridge::MBC3::power() {
|
||||
auto Cartridge::MBC3::power() -> void {
|
||||
ram_enable = false;
|
||||
rom_select = 0x01;
|
||||
ram_select = 0x00;
|
||||
|
@ -116,5 +114,3 @@ void Cartridge::MBC3::power() {
|
|||
rtc_latch_day = 0;
|
||||
rtc_latch_day_carry = false;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
@ -1,24 +1,24 @@
|
|||
struct MBC3 : MMIO {
|
||||
auto second() -> void;
|
||||
auto mmio_read(uint16 addr) -> uint8;
|
||||
auto mmio_write(uint16 addr, uint8 data) -> void;
|
||||
auto power() -> void;
|
||||
|
||||
bool ram_enable; //$0000-1fff
|
||||
uint8 rom_select; //$2000-3fff
|
||||
uint8 ram_select; //$4000-5fff
|
||||
bool rtc_latch; //$6000-7fff
|
||||
|
||||
bool rtc_halt;
|
||||
unsigned rtc_second;
|
||||
unsigned rtc_minute;
|
||||
unsigned rtc_hour;
|
||||
unsigned rtc_day;
|
||||
uint rtc_second;
|
||||
uint rtc_minute;
|
||||
uint rtc_hour;
|
||||
uint rtc_day;
|
||||
bool rtc_day_carry;
|
||||
|
||||
unsigned rtc_latch_second;
|
||||
unsigned rtc_latch_minute;
|
||||
unsigned rtc_latch_hour;
|
||||
unsigned rtc_latch_day;
|
||||
unsigned rtc_latch_day_carry;
|
||||
|
||||
void second();
|
||||
uint8 mmio_read(uint16 addr);
|
||||
void mmio_write(uint16 addr, uint8 data);
|
||||
void power();
|
||||
uint rtc_latch_second;
|
||||
uint rtc_latch_minute;
|
||||
uint rtc_latch_hour;
|
||||
uint rtc_latch_day;
|
||||
uint rtc_latch_day_carry;
|
||||
} mbc3;
|
||||
|
|
|
@ -1,6 +1,4 @@
|
|||
#ifdef CARTRIDGE_CPP
|
||||
|
||||
uint8 Cartridge::MBC5::mmio_read(uint16 addr) {
|
||||
auto Cartridge::MBC5::mmio_read(uint16 addr) -> uint8 {
|
||||
if((addr & 0xc000) == 0x0000) { //$0000-3fff
|
||||
return cartridge.rom_read(addr);
|
||||
}
|
||||
|
@ -17,7 +15,7 @@ uint8 Cartridge::MBC5::mmio_read(uint16 addr) {
|
|||
return 0x00;
|
||||
}
|
||||
|
||||
void Cartridge::MBC5::mmio_write(uint16 addr, uint8 data) {
|
||||
auto Cartridge::MBC5::mmio_write(uint16 addr, uint8 data) -> void {
|
||||
if((addr & 0xe000) == 0x0000) { //$0000-1fff
|
||||
ram_enable = (data & 0x0f) == 0x0a;
|
||||
return;
|
||||
|
@ -44,10 +42,8 @@ void Cartridge::MBC5::mmio_write(uint16 addr, uint8 data) {
|
|||
}
|
||||
}
|
||||
|
||||
void Cartridge::MBC5::power() {
|
||||
auto Cartridge::MBC5::power() -> void {
|
||||
ram_enable = false;
|
||||
rom_select = 0x001;
|
||||
ram_select = 0x00;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
struct MBC5 : MMIO {
|
||||
auto mmio_read(uint16 addr) -> uint8;
|
||||
auto mmio_write(uint16 addr, uint8 data) -> void;
|
||||
auto power() -> void;
|
||||
|
||||
bool ram_enable; //$0000-1fff
|
||||
uint16 rom_select; //$2000-2fff + $3000-3fff
|
||||
uint8 ram_select; //$4000-5fff
|
||||
|
||||
uint8 mmio_read(uint16 addr);
|
||||
void mmio_write(uint16 addr, uint8 data);
|
||||
void power();
|
||||
} mbc5;
|
||||
|
|
|
@ -1,6 +1,4 @@
|
|||
#ifdef CARTRIDGE_CPP
|
||||
|
||||
uint8 Cartridge::MMM01::mmio_read(uint16 addr) {
|
||||
auto Cartridge::MMM01::mmio_read(uint16 addr) -> uint8 {
|
||||
if((addr & 0x8000) == 0x0000) { //$0000-7fff
|
||||
if(rom_mode == 0) return cartridge.rom_read(addr);
|
||||
}
|
||||
|
@ -21,7 +19,7 @@ uint8 Cartridge::MMM01::mmio_read(uint16 addr) {
|
|||
return 0x00;
|
||||
}
|
||||
|
||||
void Cartridge::MMM01::mmio_write(uint16 addr, uint8 data) {
|
||||
auto Cartridge::MMM01::mmio_write(uint16 addr, uint8 data) -> void {
|
||||
if((addr & 0xe000) == 0x0000) { //$0000-1fff
|
||||
if(rom_mode == 0) {
|
||||
rom_mode = 1;
|
||||
|
@ -53,7 +51,7 @@ void Cartridge::MMM01::mmio_write(uint16 addr, uint8 data) {
|
|||
}
|
||||
}
|
||||
|
||||
void Cartridge::MMM01::power() {
|
||||
auto Cartridge::MMM01::power() -> void {
|
||||
rom_mode = 0;
|
||||
rom_base = 0;
|
||||
|
||||
|
@ -61,5 +59,3 @@ void Cartridge::MMM01::power() {
|
|||
rom_select = 0x01;
|
||||
ram_select = 0x00;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
@ -1,12 +1,12 @@
|
|||
struct MMM01 : MMIO {
|
||||
auto mmio_read(uint16 addr) -> uint8;
|
||||
auto mmio_write(uint16 addr, uint8 data) -> void;
|
||||
auto power() -> void;
|
||||
|
||||
bool rom_mode;
|
||||
uint8 rom_base;
|
||||
|
||||
bool ram_enable;
|
||||
uint8 rom_select;
|
||||
uint8 ram_select;
|
||||
|
||||
uint8 mmio_read(uint16 addr);
|
||||
void mmio_write(uint16 addr, uint8 data);
|
||||
void power();
|
||||
} mmm01;
|
||||
|
|
|
@ -1,6 +1,4 @@
|
|||
#ifdef CARTRIDGE_CPP
|
||||
|
||||
void Cartridge::serialize(serializer& s) {
|
||||
auto Cartridge::serialize(serializer& s) -> void {
|
||||
if(information.battery) s.array(ramdata, ramsize);
|
||||
s.integer(bootrom_enable);
|
||||
|
||||
|
@ -50,5 +48,3 @@ void Cartridge::serialize(serializer& s) {
|
|||
s.integer(huc3.rom_select);
|
||||
s.integer(huc3.ram_select);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
@ -4,19 +4,19 @@ namespace GameBoy {
|
|||
|
||||
Cheat cheat;
|
||||
|
||||
void Cheat::reset() {
|
||||
auto Cheat::reset() -> void {
|
||||
codes.reset();
|
||||
}
|
||||
|
||||
void Cheat::append(unsigned addr, unsigned data) {
|
||||
auto Cheat::append(uint addr, uint data) -> void {
|
||||
codes.append({addr, Unused, data});
|
||||
}
|
||||
|
||||
void Cheat::append(unsigned addr, unsigned comp, unsigned data) {
|
||||
auto Cheat::append(uint addr, uint comp, uint data) -> void {
|
||||
codes.append({addr, comp, data});
|
||||
}
|
||||
|
||||
maybe<unsigned> Cheat::find(unsigned addr, unsigned comp) {
|
||||
auto Cheat::find(uint addr, uint comp) -> maybe<uint> {
|
||||
for(auto& code : codes) {
|
||||
if(code.addr == addr && (code.comp == Unused || code.comp == comp)) {
|
||||
return code.data;
|
||||
|
|
|
@ -1,17 +1,18 @@
|
|||
struct Cheat {
|
||||
struct Code {
|
||||
unsigned addr;
|
||||
unsigned comp;
|
||||
unsigned data;
|
||||
uint addr;
|
||||
uint comp;
|
||||
uint data;
|
||||
};
|
||||
vector<Code> codes;
|
||||
enum : unsigned { Unused = ~0u };
|
||||
enum : uint { Unused = ~0u };
|
||||
|
||||
alwaysinline bool enable() const { return codes.size() > 0; }
|
||||
void reset();
|
||||
void append(unsigned addr, unsigned data);
|
||||
void append(unsigned addr, unsigned comp, unsigned data);
|
||||
maybe<unsigned> find(unsigned addr, unsigned comp);
|
||||
alwaysinline auto enable() const -> bool { return codes.size() > 0; }
|
||||
|
||||
auto reset() -> void;
|
||||
auto append(uint addr, uint data) -> void;
|
||||
auto append(uint addr, uint comp, uint data) -> void;
|
||||
auto find(uint addr, uint comp) -> maybe<uint>;
|
||||
};
|
||||
|
||||
extern Cheat cheat;
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
#include <gb/gb.hpp>
|
||||
|
||||
#define CPU_CPP
|
||||
namespace GameBoy {
|
||||
|
||||
#include "mmio.cpp"
|
||||
|
@ -9,11 +8,11 @@ namespace GameBoy {
|
|||
#include "serialization.cpp"
|
||||
CPU cpu;
|
||||
|
||||
void CPU::Main() {
|
||||
auto CPU::Main() -> void {
|
||||
cpu.main();
|
||||
}
|
||||
|
||||
void CPU::main() {
|
||||
auto CPU::main() -> void {
|
||||
while(true) {
|
||||
if(scheduler.sync == Scheduler::SynchronizeMode::CPU) {
|
||||
scheduler.sync = Scheduler::SynchronizeMode::All;
|
||||
|
@ -25,7 +24,7 @@ void CPU::main() {
|
|||
}
|
||||
}
|
||||
|
||||
void CPU::interrupt_raise(CPU::Interrupt id) {
|
||||
auto CPU::interrupt_raise(CPU::Interrupt id) -> void {
|
||||
if(id == Interrupt::Vblank) {
|
||||
status.interrupt_request_vblank = 1;
|
||||
if(status.interrupt_enable_vblank) r.halt = false;
|
||||
|
@ -52,7 +51,7 @@ void CPU::interrupt_raise(CPU::Interrupt id) {
|
|||
}
|
||||
}
|
||||
|
||||
void CPU::interrupt_test() {
|
||||
auto CPU::interrupt_test() -> void {
|
||||
if(r.ime) {
|
||||
if(status.interrupt_request_vblank && status.interrupt_enable_vblank) {
|
||||
status.interrupt_request_vblank = 0;
|
||||
|
@ -81,7 +80,7 @@ void CPU::interrupt_test() {
|
|||
}
|
||||
}
|
||||
|
||||
void CPU::interrupt_exec(uint16 pc) {
|
||||
auto CPU::interrupt_exec(uint16 pc) -> void {
|
||||
r.ime = 0;
|
||||
op_write(--r[SP], r[PC] >> 8);
|
||||
op_write(--r[SP], r[PC] >> 0);
|
||||
|
@ -91,7 +90,7 @@ void CPU::interrupt_exec(uint16 pc) {
|
|||
op_io();
|
||||
}
|
||||
|
||||
bool CPU::stop() {
|
||||
auto CPU::stop() -> bool {
|
||||
if(status.speed_switch) {
|
||||
status.speed_switch = 0;
|
||||
status.speed_double ^= 1;
|
||||
|
@ -102,13 +101,13 @@ bool CPU::stop() {
|
|||
return false;
|
||||
}
|
||||
|
||||
void CPU::power() {
|
||||
auto CPU::power() -> void {
|
||||
create(Main, 4 * 1024 * 1024);
|
||||
LR35902::power();
|
||||
|
||||
for(unsigned n = 0xc000; n <= 0xdfff; n++) bus.mmio[n] = this; //WRAM
|
||||
for(unsigned n = 0xe000; n <= 0xfdff; n++) bus.mmio[n] = this; //WRAM (mirror)
|
||||
for(unsigned n = 0xff80; n <= 0xfffe; n++) bus.mmio[n] = this; //HRAM
|
||||
for(uint n = 0xc000; n <= 0xdfff; n++) bus.mmio[n] = this; //WRAM
|
||||
for(uint n = 0xe000; n <= 0xfdff; n++) bus.mmio[n] = this; //WRAM (mirror)
|
||||
for(uint n = 0xff80; n <= 0xfffe; n++) bus.mmio[n] = this; //HRAM
|
||||
|
||||
bus.mmio[0xff00] = this; //JOYP
|
||||
bus.mmio[0xff01] = this; //SB
|
||||
|
|
|
@ -1,14 +1,42 @@
|
|||
struct CPU : Processor::LR35902, Thread, MMIO {
|
||||
enum class Interrupt : unsigned {
|
||||
Vblank,
|
||||
Stat,
|
||||
Timer,
|
||||
Serial,
|
||||
Joypad,
|
||||
};
|
||||
enum class Interrupt : uint { Vblank, Stat, Timer, Serial, Joypad };
|
||||
|
||||
static auto Main() -> void;
|
||||
auto main() -> void;
|
||||
auto interrupt_raise(Interrupt id) -> void;
|
||||
auto interrupt_test() -> void;
|
||||
auto interrupt_exec(uint16 pc) -> void;
|
||||
auto stop() -> bool;
|
||||
auto power() -> void;
|
||||
|
||||
auto serialize(serializer&) -> void;
|
||||
|
||||
//mmio.cpp
|
||||
auto wram_addr(uint16 addr) const -> uint;
|
||||
auto mmio_joyp_poll() -> void;
|
||||
auto mmio_read(uint16 addr) -> uint8;
|
||||
auto mmio_write(uint16 addr, uint8 data) -> void;
|
||||
|
||||
//memory.cpp
|
||||
auto op_io() -> void;
|
||||
auto op_read(uint16 addr) -> uint8;
|
||||
auto op_write(uint16 addr, uint8 data) -> void;
|
||||
auto cycle_edge() -> void;
|
||||
auto dma_read(uint16 addr) -> uint8;
|
||||
auto dma_write(uint16 addr, uint8 data) -> void;
|
||||
auto debugger_read(uint16 addr) -> uint8;
|
||||
|
||||
//timing.cpp
|
||||
auto add_clocks(uint clocks) -> void;
|
||||
auto timer_262144hz() -> void;
|
||||
auto timer_65536hz() -> void;
|
||||
auto timer_16384hz() -> void;
|
||||
auto timer_8192hz() -> void;
|
||||
auto timer_4096hz() -> void;
|
||||
auto hblank() -> void;
|
||||
|
||||
struct Status {
|
||||
unsigned clock;
|
||||
uint clock;
|
||||
|
||||
//$ff00 JOYP
|
||||
bool p15;
|
||||
|
@ -18,7 +46,7 @@ struct CPU : Processor::LR35902, Thread, MMIO {
|
|||
|
||||
//$ff01 SB
|
||||
uint8 serial_data;
|
||||
unsigned serial_bits;
|
||||
uint serial_bits;
|
||||
|
||||
//$ff02 SC
|
||||
bool serial_transfer;
|
||||
|
@ -35,7 +63,7 @@ struct CPU : Processor::LR35902, Thread, MMIO {
|
|||
|
||||
//$ff07 TAC
|
||||
bool timer_enable;
|
||||
unsigned timer_clock;
|
||||
uint timer_clock;
|
||||
|
||||
//$ff0f IF
|
||||
bool interrupt_request_joypad;
|
||||
|
@ -87,40 +115,6 @@ struct CPU : Processor::LR35902, Thread, MMIO {
|
|||
|
||||
uint8 wram[32768]; //GB=8192, GBC=32768
|
||||
uint8 hram[128];
|
||||
|
||||
static void Main();
|
||||
void main();
|
||||
void interrupt_raise(Interrupt id);
|
||||
void interrupt_test();
|
||||
void interrupt_exec(uint16 pc);
|
||||
bool stop();
|
||||
void power();
|
||||
|
||||
void serialize(serializer&);
|
||||
|
||||
//mmio.cpp
|
||||
unsigned wram_addr(uint16 addr) const;
|
||||
void mmio_joyp_poll();
|
||||
uint8 mmio_read(uint16 addr);
|
||||
void mmio_write(uint16 addr, uint8 data);
|
||||
|
||||
//memory.cpp
|
||||
void op_io();
|
||||
uint8 op_read(uint16 addr);
|
||||
void op_write(uint16 addr, uint8 data);
|
||||
void cycle_edge();
|
||||
uint8 dma_read(uint16 addr);
|
||||
void dma_write(uint16 addr, uint8 data);
|
||||
uint8 debugger_read(uint16 addr);
|
||||
|
||||
//timing.cpp
|
||||
void add_clocks(unsigned clocks);
|
||||
void timer_262144hz();
|
||||
void timer_65536hz();
|
||||
void timer_16384hz();
|
||||
void timer_8192hz();
|
||||
void timer_4096hz();
|
||||
void hblank();
|
||||
};
|
||||
|
||||
extern CPU cpu;
|
||||
|
|
|
@ -1,25 +1,23 @@
|
|||
#ifdef CPU_CPP
|
||||
|
||||
void CPU::op_io() {
|
||||
auto CPU::op_io() -> void {
|
||||
cycle_edge();
|
||||
add_clocks(4);
|
||||
}
|
||||
|
||||
uint8 CPU::op_read(uint16 addr) {
|
||||
auto CPU::op_read(uint16 addr) -> uint8 {
|
||||
cycle_edge();
|
||||
add_clocks(4);
|
||||
if(oamdma.active && (addr < 0xff80 || addr == 0xffff)) return 0x00;
|
||||
return bus.read(addr);
|
||||
}
|
||||
|
||||
void CPU::op_write(uint16 addr, uint8 data) {
|
||||
auto CPU::op_write(uint16 addr, uint8 data) -> void {
|
||||
cycle_edge();
|
||||
add_clocks(4);
|
||||
if(oamdma.active && (addr < 0xff80 || addr == 0xffff)) return;
|
||||
bus.write(addr, data);
|
||||
}
|
||||
|
||||
void CPU::cycle_edge() {
|
||||
auto CPU::cycle_edge() -> void {
|
||||
if(r.ei) {
|
||||
r.ei = false;
|
||||
r.ime = 1;
|
||||
|
@ -27,7 +25,7 @@ void CPU::cycle_edge() {
|
|||
}
|
||||
|
||||
//VRAM DMA source can only be ROM or RAM
|
||||
uint8 CPU::dma_read(uint16 addr) {
|
||||
auto CPU::dma_read(uint16 addr) -> uint8 {
|
||||
if(addr < 0x8000) return bus.read(addr); //0000-7fff
|
||||
if(addr < 0xa000) return 0x00; //8000-9fff
|
||||
if(addr < 0xe000) return bus.read(addr); //a000-dfff
|
||||
|
@ -35,13 +33,11 @@ uint8 CPU::dma_read(uint16 addr) {
|
|||
}
|
||||
|
||||
//VRAM DMA target is always VRAM
|
||||
void CPU::dma_write(uint16 addr, uint8 data) {
|
||||
auto CPU::dma_write(uint16 addr, uint8 data) -> void {
|
||||
addr = 0x8000 | (addr & 0x1fff); //8000-9fff
|
||||
return bus.write(addr, data);
|
||||
}
|
||||
|
||||
uint8 CPU::debugger_read(uint16 addr) {
|
||||
auto CPU::debugger_read(uint16 addr) -> uint8 {
|
||||
return bus.read(addr);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
@ -1,24 +1,22 @@
|
|||
#ifdef CPU_CPP
|
||||
|
||||
unsigned CPU::wram_addr(uint16 addr) const {
|
||||
auto CPU::wram_addr(uint16 addr) const -> uint {
|
||||
addr &= 0x1fff;
|
||||
if(addr < 0x1000) return addr;
|
||||
auto bank = status.wram_bank + (status.wram_bank == 0);
|
||||
return (bank * 0x1000) + (addr & 0x0fff);
|
||||
}
|
||||
|
||||
void CPU::mmio_joyp_poll() {
|
||||
unsigned button = 0, dpad = 0;
|
||||
auto CPU::mmio_joyp_poll() -> void {
|
||||
uint button = 0, dpad = 0;
|
||||
|
||||
button |= interface->inputPoll(0, 0, (unsigned)Input::Start) << 3;
|
||||
button |= interface->inputPoll(0, 0, (unsigned)Input::Select) << 2;
|
||||
button |= interface->inputPoll(0, 0, (unsigned)Input::B) << 1;
|
||||
button |= interface->inputPoll(0, 0, (unsigned)Input::A) << 0;
|
||||
button |= interface->inputPoll(0, 0, (uint)Input::Start) << 3;
|
||||
button |= interface->inputPoll(0, 0, (uint)Input::Select) << 2;
|
||||
button |= interface->inputPoll(0, 0, (uint)Input::B) << 1;
|
||||
button |= interface->inputPoll(0, 0, (uint)Input::A) << 0;
|
||||
|
||||
dpad |= interface->inputPoll(0, 0, (unsigned)Input::Down) << 3;
|
||||
dpad |= interface->inputPoll(0, 0, (unsigned)Input::Up) << 2;
|
||||
dpad |= interface->inputPoll(0, 0, (unsigned)Input::Left) << 1;
|
||||
dpad |= interface->inputPoll(0, 0, (unsigned)Input::Right) << 0;
|
||||
dpad |= interface->inputPoll(0, 0, (uint)Input::Down) << 3;
|
||||
dpad |= interface->inputPoll(0, 0, (uint)Input::Up) << 2;
|
||||
dpad |= interface->inputPoll(0, 0, (uint)Input::Left) << 1;
|
||||
dpad |= interface->inputPoll(0, 0, (uint)Input::Right) << 0;
|
||||
|
||||
if(system.revision != System::Revision::SuperGameBoy) {
|
||||
//D-pad pivot makes it impossible to press opposing directions at the same time
|
||||
|
@ -34,7 +32,7 @@ void CPU::mmio_joyp_poll() {
|
|||
if(status.joyp != 0x0f) interrupt_raise(Interrupt::Joypad);
|
||||
}
|
||||
|
||||
uint8 CPU::mmio_read(uint16 addr) {
|
||||
auto CPU::mmio_read(uint16 addr) -> uint8 {
|
||||
if(addr >= 0xc000 && addr <= 0xfdff) return wram[wram_addr(addr)];
|
||||
if(addr >= 0xff80 && addr <= 0xfffe) return hram[addr & 0x7f];
|
||||
|
||||
|
@ -135,7 +133,7 @@ uint8 CPU::mmio_read(uint16 addr) {
|
|||
return 0x00;
|
||||
}
|
||||
|
||||
void CPU::mmio_write(uint16 addr, uint8 data) {
|
||||
auto CPU::mmio_write(uint16 addr, uint8 data) -> void {
|
||||
if(addr >= 0xc000 && addr <= 0xfdff) { wram[wram_addr(addr)] = data; return; }
|
||||
if(addr >= 0xff80 && addr <= 0xfffe) { hram[addr & 0x7f] = data; return; }
|
||||
|
||||
|
@ -280,5 +278,3 @@ void CPU::mmio_write(uint16 addr, uint8 data) {
|
|||
return;
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
@ -1,6 +1,4 @@
|
|||
#ifdef CPU_CPP
|
||||
|
||||
void CPU::serialize(serializer& s) {
|
||||
auto CPU::serialize(serializer& s) -> void {
|
||||
LR35902::serialize(s);
|
||||
Thread::serialize(s);
|
||||
|
||||
|
@ -60,5 +58,3 @@ void CPU::serialize(serializer& s) {
|
|||
s.integer(oamdma.bank);
|
||||
s.integer(oamdma.offset);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
@ -2,11 +2,9 @@
|
|||
// 456 clocks/scanline
|
||||
// 154 scanlines/frame
|
||||
|
||||
#ifdef CPU_CPP
|
||||
|
||||
void CPU::add_clocks(unsigned clocks) {
|
||||
auto CPU::add_clocks(uint clocks) -> void {
|
||||
if(oamdma.active) {
|
||||
for(unsigned n = 0; n < 4 * clocks; n++) {
|
||||
for(uint n = 0; n < 4 * clocks; n++) {
|
||||
bus.write(0xfe00 + oamdma.offset, bus.read((oamdma.bank << 8) + oamdma.offset));
|
||||
if(++oamdma.offset == 160) {
|
||||
oamdma.active = false;
|
||||
|
@ -38,7 +36,7 @@ void CPU::add_clocks(unsigned clocks) {
|
|||
if(apu.clock < 0) co_switch(scheduler.active_thread = apu.thread);
|
||||
}
|
||||
|
||||
void CPU::timer_262144hz() {
|
||||
auto CPU::timer_262144hz() -> void {
|
||||
if(status.timer_enable && status.timer_clock == 1) {
|
||||
if(++status.tima == 0) {
|
||||
status.tima = status.tma;
|
||||
|
@ -47,7 +45,7 @@ void CPU::timer_262144hz() {
|
|||
}
|
||||
}
|
||||
|
||||
void CPU::timer_65536hz() {
|
||||
auto CPU::timer_65536hz() -> void {
|
||||
if(status.timer_enable && status.timer_clock == 2) {
|
||||
if(++status.tima == 0) {
|
||||
status.tima = status.tma;
|
||||
|
@ -56,7 +54,7 @@ void CPU::timer_65536hz() {
|
|||
}
|
||||
}
|
||||
|
||||
void CPU::timer_16384hz() {
|
||||
auto CPU::timer_16384hz() -> void {
|
||||
if(status.timer_enable && status.timer_clock == 3) {
|
||||
if(++status.tima == 0) {
|
||||
status.tima = status.tma;
|
||||
|
@ -67,7 +65,7 @@ void CPU::timer_16384hz() {
|
|||
status.div++;
|
||||
}
|
||||
|
||||
void CPU::timer_8192hz() {
|
||||
auto CPU::timer_8192hz() -> void {
|
||||
if(status.serial_transfer && status.serial_clock) {
|
||||
if(--status.serial_bits == 0) {
|
||||
status.serial_transfer = 0;
|
||||
|
@ -76,7 +74,7 @@ void CPU::timer_8192hz() {
|
|||
}
|
||||
}
|
||||
|
||||
void CPU::timer_4096hz() {
|
||||
auto CPU::timer_4096hz() -> void {
|
||||
if(status.timer_enable && status.timer_clock == 0) {
|
||||
if(++status.tima == 0) {
|
||||
status.tima = status.tma;
|
||||
|
@ -85,14 +83,12 @@ void CPU::timer_4096hz() {
|
|||
}
|
||||
}
|
||||
|
||||
void CPU::hblank() {
|
||||
auto CPU::hblank() -> void {
|
||||
if(status.dma_mode == 1 && status.dma_length && ppu.status.ly < 144) {
|
||||
for(unsigned n = 0; n < 16; n++) {
|
||||
for(auto n : range(16)) {
|
||||
dma_write(status.dma_target++, dma_read(status.dma_source++));
|
||||
}
|
||||
add_clocks(8 << status.speed_double);
|
||||
status.dma_length -= 16;
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
@ -4,148 +4,6 @@ namespace GameBoy {
|
|||
|
||||
Interface* interface = nullptr;
|
||||
|
||||
void Interface::lcdScanline() {
|
||||
if(hook) hook->lcdScanline();
|
||||
}
|
||||
|
||||
void Interface::lcdOutput(uint2 color) {
|
||||
if(hook) hook->lcdOutput(color);
|
||||
}
|
||||
|
||||
void Interface::joypWrite(bool p15, bool p14) {
|
||||
if(hook) hook->joypWrite(p15, p14);
|
||||
}
|
||||
|
||||
string Interface::title() {
|
||||
return cartridge.title();
|
||||
}
|
||||
|
||||
double Interface::videoFrequency() {
|
||||
return 4194304.0 / (154.0 * 456.0);
|
||||
}
|
||||
|
||||
double Interface::audioFrequency() {
|
||||
return 4194304.0 / 2.0;
|
||||
}
|
||||
|
||||
bool Interface::loaded() {
|
||||
return cartridge.loaded();
|
||||
}
|
||||
|
||||
string Interface::sha256() {
|
||||
return cartridge.sha256();
|
||||
}
|
||||
|
||||
unsigned Interface::group(unsigned id) {
|
||||
switch(id) {
|
||||
case ID::SystemManifest:
|
||||
case ID::GameBoyBootROM:
|
||||
case ID::SuperGameBoyBootROM:
|
||||
case ID::GameBoyColorBootROM:
|
||||
return 0;
|
||||
case ID::Manifest:
|
||||
case ID::ROM:
|
||||
case ID::RAM:
|
||||
switch(system.revision) {
|
||||
case System::Revision::GameBoy: return ID::GameBoy;
|
||||
case System::Revision::SuperGameBoy: return ID::SuperGameBoy;
|
||||
case System::Revision::GameBoyColor: return ID::GameBoyColor;
|
||||
}
|
||||
throw;
|
||||
}
|
||||
throw;
|
||||
}
|
||||
|
||||
void Interface::load(unsigned id) {
|
||||
if(id == ID::GameBoy) cartridge.load(System::Revision::GameBoy);
|
||||
if(id == ID::SuperGameBoy) cartridge.load(System::Revision::SuperGameBoy);
|
||||
if(id == ID::GameBoyColor) cartridge.load(System::Revision::GameBoyColor);
|
||||
}
|
||||
|
||||
void Interface::save() {
|
||||
for(auto& memory : cartridge.memory) {
|
||||
interface->saveRequest(memory.id, memory.name);
|
||||
}
|
||||
}
|
||||
|
||||
void Interface::load(unsigned id, const stream& stream) {
|
||||
if(id == ID::SystemManifest) {
|
||||
system.information.manifest = stream.text();
|
||||
}
|
||||
|
||||
if(id == ID::GameBoyBootROM) {
|
||||
stream.read(system.bootROM.dmg, min( 256u, stream.size()));
|
||||
}
|
||||
|
||||
if(id == ID::SuperGameBoyBootROM) {
|
||||
stream.read(system.bootROM.sgb, min( 256u, stream.size()));
|
||||
}
|
||||
|
||||
if(id == ID::GameBoyColorBootROM) {
|
||||
stream.read(system.bootROM.cgb, min(2048u, stream.size()));
|
||||
}
|
||||
|
||||
if(id == ID::Manifest) {
|
||||
cartridge.information.markup = stream.text();
|
||||
}
|
||||
|
||||
if(id == ID::ROM) {
|
||||
stream.read(cartridge.romdata, min(cartridge.romsize, stream.size()));
|
||||
}
|
||||
|
||||
if(id == ID::RAM) {
|
||||
stream.read(cartridge.ramdata, min(stream.size(), cartridge.ramsize));
|
||||
}
|
||||
}
|
||||
|
||||
void Interface::save(unsigned id, const stream& stream) {
|
||||
if(id == ID::RAM) {
|
||||
stream.write(cartridge.ramdata, cartridge.ramsize);
|
||||
}
|
||||
}
|
||||
|
||||
void Interface::unload() {
|
||||
save();
|
||||
cartridge.unload();
|
||||
}
|
||||
|
||||
void Interface::power() {
|
||||
system.power();
|
||||
}
|
||||
|
||||
void Interface::reset() {
|
||||
system.power();
|
||||
}
|
||||
|
||||
void Interface::run() {
|
||||
system.run();
|
||||
}
|
||||
|
||||
serializer Interface::serialize() {
|
||||
system.runtosave();
|
||||
return system.serialize();
|
||||
}
|
||||
|
||||
bool Interface::unserialize(serializer& s) {
|
||||
return system.unserialize(s);
|
||||
}
|
||||
|
||||
void Interface::cheatSet(const lstring& list) {
|
||||
cheat.reset();
|
||||
for(auto& codeset : list) {
|
||||
lstring codes = codeset.split("+");
|
||||
for(auto& code : codes) {
|
||||
lstring part = code.split("/");
|
||||
if(part.size() == 2) cheat.append(hex(part[0]), hex(part[1]));
|
||||
if(part.size() == 3) cheat.append(hex(part[0]), hex(part[1]), hex(part[2]));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Interface::paletteUpdate(PaletteMode mode) {
|
||||
video.generate_palette(mode);
|
||||
}
|
||||
|
||||
Interface::Interface() {
|
||||
interface = this;
|
||||
hook = nullptr;
|
||||
|
@ -179,4 +37,146 @@ Interface::Interface() {
|
|||
port.append({0, "Device", {device[0]}});
|
||||
}
|
||||
|
||||
auto Interface::title() -> string {
|
||||
return cartridge.title();
|
||||
}
|
||||
|
||||
auto Interface::videoFrequency() -> double {
|
||||
return 4194304.0 / (154.0 * 456.0);
|
||||
}
|
||||
|
||||
auto Interface::audioFrequency() -> double {
|
||||
return 4194304.0 / 2.0;
|
||||
}
|
||||
|
||||
auto Interface::loaded() -> bool {
|
||||
return cartridge.loaded();
|
||||
}
|
||||
|
||||
auto Interface::sha256() -> string {
|
||||
return cartridge.sha256();
|
||||
}
|
||||
|
||||
auto Interface::group(uint id) -> uint {
|
||||
switch(id) {
|
||||
case ID::SystemManifest:
|
||||
case ID::GameBoyBootROM:
|
||||
case ID::SuperGameBoyBootROM:
|
||||
case ID::GameBoyColorBootROM:
|
||||
return 0;
|
||||
case ID::Manifest:
|
||||
case ID::ROM:
|
||||
case ID::RAM:
|
||||
switch(system.revision) {
|
||||
case System::Revision::GameBoy: return ID::GameBoy;
|
||||
case System::Revision::SuperGameBoy: return ID::SuperGameBoy;
|
||||
case System::Revision::GameBoyColor: return ID::GameBoyColor;
|
||||
}
|
||||
throw;
|
||||
}
|
||||
throw;
|
||||
}
|
||||
|
||||
auto Interface::load(uint id) -> void {
|
||||
if(id == ID::GameBoy) cartridge.load(System::Revision::GameBoy);
|
||||
if(id == ID::SuperGameBoy) cartridge.load(System::Revision::SuperGameBoy);
|
||||
if(id == ID::GameBoyColor) cartridge.load(System::Revision::GameBoyColor);
|
||||
}
|
||||
|
||||
auto Interface::save() -> void {
|
||||
for(auto& memory : cartridge.memory) {
|
||||
interface->saveRequest(memory.id, memory.name);
|
||||
}
|
||||
}
|
||||
|
||||
auto Interface::load(uint id, const stream& stream) -> void {
|
||||
if(id == ID::SystemManifest) {
|
||||
system.information.manifest = stream.text();
|
||||
}
|
||||
|
||||
if(id == ID::GameBoyBootROM) {
|
||||
stream.read(system.bootROM.dmg, min( 256u, stream.size()));
|
||||
}
|
||||
|
||||
if(id == ID::SuperGameBoyBootROM) {
|
||||
stream.read(system.bootROM.sgb, min( 256u, stream.size()));
|
||||
}
|
||||
|
||||
if(id == ID::GameBoyColorBootROM) {
|
||||
stream.read(system.bootROM.cgb, min(2048u, stream.size()));
|
||||
}
|
||||
|
||||
if(id == ID::Manifest) {
|
||||
cartridge.information.markup = stream.text();
|
||||
}
|
||||
|
||||
if(id == ID::ROM) {
|
||||
stream.read(cartridge.romdata, min(cartridge.romsize, stream.size()));
|
||||
}
|
||||
|
||||
if(id == ID::RAM) {
|
||||
stream.read(cartridge.ramdata, min(stream.size(), cartridge.ramsize));
|
||||
}
|
||||
}
|
||||
|
||||
auto Interface::save(uint id, const stream& stream) -> void {
|
||||
if(id == ID::RAM) {
|
||||
stream.write(cartridge.ramdata, cartridge.ramsize);
|
||||
}
|
||||
}
|
||||
|
||||
auto Interface::unload() -> void {
|
||||
save();
|
||||
cartridge.unload();
|
||||
}
|
||||
|
||||
auto Interface::power() -> void {
|
||||
system.power();
|
||||
}
|
||||
|
||||
auto Interface::reset() -> void {
|
||||
system.power();
|
||||
}
|
||||
|
||||
auto Interface::run() -> void {
|
||||
system.run();
|
||||
}
|
||||
|
||||
auto Interface::serialize() -> serializer {
|
||||
system.runtosave();
|
||||
return system.serialize();
|
||||
}
|
||||
|
||||
auto Interface::unserialize(serializer& s) -> bool {
|
||||
return system.unserialize(s);
|
||||
}
|
||||
|
||||
auto Interface::cheatSet(const lstring& list) -> void {
|
||||
cheat.reset();
|
||||
for(auto& codeset : list) {
|
||||
lstring codes = codeset.split("+");
|
||||
for(auto& code : codes) {
|
||||
lstring part = code.split("/");
|
||||
if(part.size() == 2) cheat.append(hex(part[0]), hex(part[1]));
|
||||
if(part.size() == 3) cheat.append(hex(part[0]), hex(part[1]), hex(part[2]));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
auto Interface::paletteUpdate(PaletteMode mode) -> void {
|
||||
video.generate_palette(mode);
|
||||
}
|
||||
|
||||
auto Interface::lcdScanline() -> void {
|
||||
if(hook) hook->lcdScanline();
|
||||
}
|
||||
|
||||
auto Interface::lcdOutput(uint2 color) -> void {
|
||||
if(hook) hook->lcdOutput(color);
|
||||
}
|
||||
|
||||
auto Interface::joypWrite(bool p15, bool p14) -> void {
|
||||
if(hook) hook->joypWrite(p15, p14);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -3,14 +3,14 @@ namespace GameBoy {
|
|||
#endif
|
||||
|
||||
struct ID {
|
||||
enum : unsigned {
|
||||
enum : uint {
|
||||
System,
|
||||
GameBoy,
|
||||
SuperGameBoy,
|
||||
GameBoyColor,
|
||||
};
|
||||
|
||||
enum : unsigned {
|
||||
enum : uint {
|
||||
SystemManifest,
|
||||
GameBoyBootROM,
|
||||
SuperGameBoyBootROM,
|
||||
|
@ -21,49 +21,49 @@ struct ID {
|
|||
RAM,
|
||||
};
|
||||
|
||||
enum : unsigned {
|
||||
enum : uint {
|
||||
Device = 1,
|
||||
};
|
||||
};
|
||||
|
||||
struct Interface : Emulator::Interface {
|
||||
Interface();
|
||||
|
||||
auto title() -> string;
|
||||
auto videoFrequency() -> double;
|
||||
auto audioFrequency() -> double;
|
||||
|
||||
auto loaded() -> bool;
|
||||
auto sha256() -> string;
|
||||
auto group(uint id) -> uint;
|
||||
auto load(uint id) -> void;
|
||||
auto save() -> void;
|
||||
auto load(uint id, const stream& stream) -> void;
|
||||
auto save(uint id, const stream& stream) -> void;
|
||||
auto unload() -> void;
|
||||
|
||||
auto power() -> void;
|
||||
auto reset() -> void;
|
||||
auto run() -> void;
|
||||
|
||||
auto serialize() -> serializer;
|
||||
auto unserialize(serializer&) -> bool;
|
||||
|
||||
auto cheatSet(const lstring&) -> void;
|
||||
|
||||
auto paletteUpdate(PaletteMode mode) -> void;
|
||||
|
||||
//Super Game Boy bindings
|
||||
struct Hook {
|
||||
virtual void lcdScanline() {}
|
||||
virtual void lcdOutput(uint2 color) {}
|
||||
virtual void joypWrite(bool p15, bool p14) {}
|
||||
virtual auto lcdScanline() -> void {}
|
||||
virtual auto lcdOutput(uint2 color) -> void {}
|
||||
virtual auto joypWrite(bool p15, bool p14) -> void {}
|
||||
};
|
||||
Hook* hook = nullptr;
|
||||
|
||||
void lcdScanline();
|
||||
void lcdOutput(uint2 color);
|
||||
void joypWrite(bool p15, bool p14);
|
||||
|
||||
string title();
|
||||
double videoFrequency();
|
||||
double audioFrequency();
|
||||
|
||||
bool loaded();
|
||||
string sha256();
|
||||
unsigned group(unsigned id);
|
||||
void load(unsigned id);
|
||||
void save();
|
||||
void load(unsigned id, const stream& stream);
|
||||
void save(unsigned id, const stream& stream);
|
||||
void unload();
|
||||
|
||||
void power();
|
||||
void reset();
|
||||
void run();
|
||||
|
||||
serializer serialize();
|
||||
bool unserialize(serializer&);
|
||||
|
||||
void cheatSet(const lstring&);
|
||||
|
||||
void paletteUpdate(PaletteMode mode);
|
||||
|
||||
Interface();
|
||||
auto lcdScanline() -> void;
|
||||
auto lcdOutput(uint2 color) -> void;
|
||||
auto joypWrite(bool p15, bool p14) -> void;
|
||||
|
||||
private:
|
||||
vector<Device> device;
|
||||
|
|
|
@ -1,47 +1,41 @@
|
|||
#include <gb/gb.hpp>
|
||||
|
||||
#define MEMORY_CPP
|
||||
namespace GameBoy {
|
||||
|
||||
Unmapped unmapped;
|
||||
Bus bus;
|
||||
|
||||
uint8_t& Memory::operator[](unsigned addr) {
|
||||
Memory::~Memory() {
|
||||
free();
|
||||
}
|
||||
|
||||
auto Memory::operator[](uint addr) -> uint8& {
|
||||
return data[addr];
|
||||
}
|
||||
|
||||
void Memory::allocate(unsigned size_) {
|
||||
auto Memory::allocate(uint size_) -> void {
|
||||
free();
|
||||
size = size_;
|
||||
data = new uint8_t[size]();
|
||||
}
|
||||
|
||||
void Memory::copy(const uint8_t* data_, unsigned size_) {
|
||||
auto Memory::copy(const uint8_t* data_, unsigned size_) -> void {
|
||||
free();
|
||||
size = size_;
|
||||
data = new uint8_t[size];
|
||||
memcpy(data, data_, size);
|
||||
}
|
||||
|
||||
void Memory::free() {
|
||||
auto Memory::free() -> void {
|
||||
if(data) {
|
||||
delete[] data;
|
||||
data = 0;
|
||||
data = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
Memory::Memory() {
|
||||
data = 0;
|
||||
size = 0;
|
||||
}
|
||||
|
||||
Memory::~Memory() {
|
||||
free();
|
||||
}
|
||||
|
||||
//
|
||||
|
||||
uint8 Bus::read(uint16 addr) {
|
||||
auto Bus::read(uint16 addr) -> uint8 {
|
||||
uint8 data = mmio[addr]->mmio_read(addr);
|
||||
|
||||
if(cheat.enable()) {
|
||||
|
@ -51,12 +45,12 @@ uint8 Bus::read(uint16 addr) {
|
|||
return data;
|
||||
}
|
||||
|
||||
void Bus::write(uint16 addr, uint8 data) {
|
||||
auto Bus::write(uint16 addr, uint8 data) -> void {
|
||||
mmio[addr]->mmio_write(addr, data);
|
||||
}
|
||||
|
||||
void Bus::power() {
|
||||
for(unsigned n = 0x0000; n <= 0xffff; n++) mmio[n] = &unmapped;
|
||||
auto Bus::power() -> void {
|
||||
for(auto n : range(65536)) mmio[n] = &unmapped;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1,31 +1,31 @@
|
|||
struct Memory {
|
||||
uint8_t* data;
|
||||
unsigned size;
|
||||
|
||||
uint8_t& operator[](unsigned addr);
|
||||
void allocate(unsigned size);
|
||||
void copy(const uint8_t* data, unsigned size);
|
||||
void free();
|
||||
Memory();
|
||||
~Memory();
|
||||
|
||||
auto operator[](uint addr) -> uint8&;
|
||||
auto allocate(uint size) -> void;
|
||||
auto copy(const uint8* data, uint size) -> void;
|
||||
auto free() -> void;
|
||||
|
||||
uint8* data = nullptr;
|
||||
uint size = 0;
|
||||
};
|
||||
|
||||
struct MMIO {
|
||||
virtual uint8 mmio_read(uint16 addr) = 0;
|
||||
virtual void mmio_write(uint16 addr, uint8 data) = 0;
|
||||
virtual auto mmio_read(uint16 addr) -> uint8 = 0;
|
||||
virtual auto mmio_write(uint16 addr, uint8 data) -> void = 0;
|
||||
};
|
||||
|
||||
struct Unmapped : MMIO {
|
||||
uint8 mmio_read(uint16) { return 0x00; }
|
||||
void mmio_write(uint16, uint8) {}
|
||||
auto mmio_read(uint16) -> uint8 { return 0x00; }
|
||||
auto mmio_write(uint16, uint8) -> void {}
|
||||
};
|
||||
|
||||
struct Bus {
|
||||
MMIO* mmio[65536];
|
||||
uint8 read(uint16 addr);
|
||||
void write(uint16 addr, uint8 data);
|
||||
auto read(uint16 addr) -> uint8;
|
||||
auto write(uint16 addr, uint8 data) -> void;
|
||||
auto power() -> void;
|
||||
|
||||
void power();
|
||||
MMIO* mmio[65536];
|
||||
};
|
||||
|
||||
extern Unmapped unmapped;
|
||||
|
|
|
@ -1,5 +1,3 @@
|
|||
#ifdef PPU_CPP
|
||||
|
||||
//BG attributes:
|
||||
//0x80: 0 = OAM priority, 1 = BG priority
|
||||
//0x40: vertical flip
|
||||
|
@ -14,14 +12,14 @@
|
|||
//0x08: VRAM bank#
|
||||
//0x07: palette#
|
||||
|
||||
void PPU::cgb_read_tile(bool select, unsigned x, unsigned y, unsigned& attr, unsigned& data) {
|
||||
unsigned tmaddr = 0x1800 + (select << 10);
|
||||
auto PPU::cgb_read_tile(bool select, uint x, uint y, uint& attr, uint& data) -> void {
|
||||
uint tmaddr = 0x1800 + (select << 10);
|
||||
tmaddr += (((y >> 3) << 5) + (x >> 3)) & 0x03ff;
|
||||
|
||||
unsigned tile = vram[0x0000 + tmaddr];
|
||||
uint tile = vram[0x0000 + tmaddr];
|
||||
attr = vram[0x2000 + tmaddr];
|
||||
|
||||
unsigned tdaddr = attr & 0x08 ? 0x2000 : 0x0000;
|
||||
uint tdaddr = attr & 0x08 ? 0x2000 : 0x0000;
|
||||
if(status.bg_tiledata_select == 0) {
|
||||
tdaddr += 0x1000 + ((int8)tile << 4);
|
||||
} else {
|
||||
|
@ -37,14 +35,14 @@ void PPU::cgb_read_tile(bool select, unsigned x, unsigned y, unsigned& attr, uns
|
|||
if(attr & 0x20) data = hflip(data);
|
||||
}
|
||||
|
||||
void PPU::cgb_scanline() {
|
||||
auto PPU::cgb_scanline() -> void {
|
||||
px = 0;
|
||||
|
||||
const unsigned Height = (status.ob_size == 0 ? 8 : 16);
|
||||
const uint Height = (status.ob_size == 0 ? 8 : 16);
|
||||
sprites = 0;
|
||||
|
||||
//find first ten sprites on this scanline
|
||||
for(unsigned n = 0; n < 40 * 4; n += 4) {
|
||||
for(uint n = 0; n < 40 * 4; n += 4) {
|
||||
Sprite& s = sprite[sprites];
|
||||
s.y = oam[n + 0] - 16;
|
||||
s.x = oam[n + 1] - 8;
|
||||
|
@ -55,7 +53,7 @@ void PPU::cgb_scanline() {
|
|||
if(s.y >= Height) continue;
|
||||
|
||||
if(s.attr & 0x40) s.y ^= (Height - 1);
|
||||
unsigned tdaddr = (s.attr & 0x08 ? 0x2000 : 0x0000) + (s.tile << 4) + (s.y << 1);
|
||||
uint tdaddr = (s.attr & 0x08 ? 0x2000 : 0x0000) + (s.tile << 4) + (s.y << 1);
|
||||
s.data = vram[tdaddr + 0] << 0;
|
||||
s.data |= vram[tdaddr + 1] << 8;
|
||||
if(s.attr & 0x20) s.data = hflip(s.data);
|
||||
|
@ -64,12 +62,12 @@ void PPU::cgb_scanline() {
|
|||
}
|
||||
}
|
||||
|
||||
void PPU::cgb_run() {
|
||||
auto PPU::cgb_run() -> void {
|
||||
ob.color = 0;
|
||||
ob.palette = 0;
|
||||
ob.priority = 0;
|
||||
|
||||
unsigned color = 0x7fff;
|
||||
uint color = 0x7fff;
|
||||
if(status.display_enable) {
|
||||
cgb_run_bg();
|
||||
if(status.window_display_enable) cgb_run_window();
|
||||
|
@ -94,17 +92,17 @@ void PPU::cgb_run() {
|
|||
*output = color;
|
||||
}
|
||||
|
||||
void PPU::cgb_run_bg() {
|
||||
unsigned scrolly = (status.ly + status.scy) & 255;
|
||||
unsigned scrollx = (px + status.scx) & 255;
|
||||
unsigned tx = scrollx & 7;
|
||||
auto PPU::cgb_run_bg() -> void {
|
||||
uint scrolly = (status.ly + status.scy) & 255;
|
||||
uint scrollx = (px + status.scx) & 255;
|
||||
uint tx = scrollx & 7;
|
||||
if(tx == 0 || px == 0) cgb_read_tile(status.bg_tilemap_select, scrollx, scrolly, background.attr, background.data);
|
||||
|
||||
unsigned index = 0;
|
||||
uint index = 0;
|
||||
index |= (background.data & (0x0080 >> tx)) ? 1 : 0;
|
||||
index |= (background.data & (0x8000 >> tx)) ? 2 : 0;
|
||||
unsigned palette = ((background.attr & 0x07) << 2) + index;
|
||||
unsigned color = 0;
|
||||
uint palette = ((background.attr & 0x07) << 2) + index;
|
||||
uint color = 0;
|
||||
color |= bgpd[(palette << 1) + 0] << 0;
|
||||
color |= bgpd[(palette << 1) + 1] << 8;
|
||||
color &= 0x7fff;
|
||||
|
@ -114,19 +112,19 @@ void PPU::cgb_run_bg() {
|
|||
bg.priority = background.attr & 0x80;
|
||||
}
|
||||
|
||||
void PPU::cgb_run_window() {
|
||||
unsigned scrolly = status.ly - status.wy;
|
||||
unsigned scrollx = px + 7 - status.wx;
|
||||
auto PPU::cgb_run_window() -> void {
|
||||
uint scrolly = status.ly - status.wy;
|
||||
uint scrollx = px + 7 - status.wx;
|
||||
if(scrolly >= 144u) return; //also matches underflow (scrolly < 0)
|
||||
if(scrollx >= 160u) return; //also matches underflow (scrollx < 0)
|
||||
unsigned tx = scrollx & 7;
|
||||
uint tx = scrollx & 7;
|
||||
if(tx == 0 || px == 0) cgb_read_tile(status.window_tilemap_select, scrollx, scrolly, window.attr, window.data);
|
||||
|
||||
unsigned index = 0;
|
||||
uint index = 0;
|
||||
index |= (window.data & (0x0080 >> tx)) ? 1 : 0;
|
||||
index |= (window.data & (0x8000 >> tx)) ? 2 : 0;
|
||||
unsigned palette = ((window.attr & 0x07) << 2) + index;
|
||||
unsigned color = 0;
|
||||
uint palette = ((window.attr & 0x07) << 2) + index;
|
||||
uint color = 0;
|
||||
color |= bgpd[(palette << 1) + 0] << 0;
|
||||
color |= bgpd[(palette << 1) + 1] << 8;
|
||||
color &= 0x7fff;
|
||||
|
@ -136,21 +134,21 @@ void PPU::cgb_run_window() {
|
|||
bg.priority = window.attr & 0x80;
|
||||
}
|
||||
|
||||
void PPU::cgb_run_ob() {
|
||||
auto PPU::cgb_run_ob() -> void {
|
||||
//render backwards, so that first sprite has priority
|
||||
for(signed n = sprites - 1; n >= 0; n--) {
|
||||
for(int n = sprites - 1; n >= 0; n--) {
|
||||
Sprite& s = sprite[n];
|
||||
|
||||
signed tx = px - s.x;
|
||||
int tx = px - s.x;
|
||||
if(tx < 0 || tx > 7) continue;
|
||||
|
||||
unsigned index = 0;
|
||||
uint index = 0;
|
||||
index |= (s.data & (0x0080 >> tx)) ? 1 : 0;
|
||||
index |= (s.data & (0x8000 >> tx)) ? 2 : 0;
|
||||
if(index == 0) continue;
|
||||
|
||||
unsigned palette = ((s.attr & 0x07) << 2) + index;
|
||||
unsigned color = 0;
|
||||
uint palette = ((s.attr & 0x07) << 2) + index;
|
||||
uint color = 0;
|
||||
color |= obpd[(palette << 1) + 0] << 0;
|
||||
color |= obpd[(palette << 1) + 1] << 8;
|
||||
color &= 0x7fff;
|
||||
|
@ -160,5 +158,3 @@ void PPU::cgb_run_ob() {
|
|||
ob.priority = !(s.attr & 0x80);
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
@ -1,13 +1,11 @@
|
|||
#ifdef PPU_CPP
|
||||
|
||||
//OB attributes:
|
||||
//0x80: 0 = OBJ above BG, 1 = BG above OBJ
|
||||
//0x40: vertical flip
|
||||
//0x20: horizontal flip
|
||||
//0x10: palette#
|
||||
|
||||
void PPU::dmg_read_tile(bool select, unsigned x, unsigned y, unsigned& data) {
|
||||
unsigned tmaddr = 0x1800 + (select << 10), tdaddr;
|
||||
auto PPU::dmg_read_tile(bool select, uint x, uint y, uint& data) -> void {
|
||||
uint tmaddr = 0x1800 + (select << 10), tdaddr;
|
||||
tmaddr += (((y >> 3) << 5) + (x >> 3)) & 0x03ff;
|
||||
if(status.bg_tiledata_select == 0) {
|
||||
tdaddr = 0x1000 + ((int8)vram[tmaddr] << 4);
|
||||
|
@ -19,14 +17,14 @@ void PPU::dmg_read_tile(bool select, unsigned x, unsigned y, unsigned& data) {
|
|||
data |= vram[tdaddr + 1] << 8;
|
||||
}
|
||||
|
||||
void PPU::dmg_scanline() {
|
||||
auto PPU::dmg_scanline() -> void {
|
||||
px = 0;
|
||||
|
||||
const unsigned Height = (status.ob_size == 0 ? 8 : 16);
|
||||
const uint Height = (status.ob_size == 0 ? 8 : 16);
|
||||
sprites = 0;
|
||||
|
||||
//find first ten sprites on this scanline
|
||||
for(unsigned n = 0; n < 40 * 4; n += 4) {
|
||||
for(uint n = 0; n < 40 * 4; n += 4) {
|
||||
Sprite& s = sprite[sprites];
|
||||
s.y = oam[n + 0] - 16;
|
||||
s.x = oam[n + 1] - 8;
|
||||
|
@ -37,7 +35,7 @@ void PPU::dmg_scanline() {
|
|||
if(s.y >= Height) continue;
|
||||
|
||||
if(s.attr & 0x40) s.y ^= (Height - 1);
|
||||
unsigned tdaddr = (s.tile << 4) + (s.y << 1);
|
||||
uint tdaddr = (s.tile << 4) + (s.y << 1);
|
||||
s.data = vram[tdaddr + 0] << 0;
|
||||
s.data |= vram[tdaddr + 1] << 8;
|
||||
if(s.attr & 0x20) s.data = hflip(s.data);
|
||||
|
@ -46,21 +44,21 @@ void PPU::dmg_scanline() {
|
|||
}
|
||||
|
||||
//sort by X-coordinate
|
||||
for(unsigned lo = 0; lo < sprites; lo++) {
|
||||
for(unsigned hi = lo + 1; hi < sprites; hi++) {
|
||||
if(sprite[hi].x < sprite[lo].x) std::swap(sprite[lo], sprite[hi]);
|
||||
for(uint lo = 0; lo < sprites; lo++) {
|
||||
for(uint hi = lo + 1; hi < sprites; hi++) {
|
||||
if(sprite[hi].x < sprite[lo].x) swap(sprite[lo], sprite[hi]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void PPU::dmg_run() {
|
||||
auto PPU::dmg_run() -> void {
|
||||
bg.color = 0;
|
||||
bg.palette = 0;
|
||||
|
||||
ob.color = 0;
|
||||
ob.palette = 0;
|
||||
|
||||
unsigned color = 0;
|
||||
uint color = 0;
|
||||
if(status.display_enable) {
|
||||
if(status.bg_enable) dmg_run_bg();
|
||||
if(status.window_display_enable) dmg_run_window();
|
||||
|
@ -82,13 +80,13 @@ void PPU::dmg_run() {
|
|||
interface->lcdOutput(color); //Super Game Boy notification
|
||||
}
|
||||
|
||||
void PPU::dmg_run_bg() {
|
||||
unsigned scrolly = (status.ly + status.scy) & 255;
|
||||
unsigned scrollx = (px + status.scx) & 255;
|
||||
unsigned tx = scrollx & 7;
|
||||
auto PPU::dmg_run_bg() -> void {
|
||||
uint scrolly = (status.ly + status.scy) & 255;
|
||||
uint scrollx = (px + status.scx) & 255;
|
||||
uint tx = scrollx & 7;
|
||||
if(tx == 0 || px == 0) dmg_read_tile(status.bg_tilemap_select, scrollx, scrolly, background.data);
|
||||
|
||||
unsigned index = 0;
|
||||
uint index = 0;
|
||||
index |= (background.data & (0x0080 >> tx)) ? 1 : 0;
|
||||
index |= (background.data & (0x8000 >> tx)) ? 2 : 0;
|
||||
|
||||
|
@ -96,15 +94,15 @@ void PPU::dmg_run_bg() {
|
|||
bg.palette = index;
|
||||
}
|
||||
|
||||
void PPU::dmg_run_window() {
|
||||
unsigned scrolly = status.ly - status.wy;
|
||||
unsigned scrollx = px + 7 - status.wx;
|
||||
auto PPU::dmg_run_window() -> void {
|
||||
uint scrolly = status.ly - status.wy;
|
||||
uint scrollx = px + 7 - status.wx;
|
||||
if(scrolly >= 144u) return; //also matches underflow (scrolly < 0)
|
||||
if(scrollx >= 160u) return; //also matches underflow (scrollx < 0)
|
||||
unsigned tx = scrollx & 7;
|
||||
uint tx = scrollx & 7;
|
||||
if(tx == 0 || px == 0) dmg_read_tile(status.window_tilemap_select, scrollx, scrolly, window.data);
|
||||
|
||||
unsigned index = 0;
|
||||
uint index = 0;
|
||||
index |= (window.data & (0x0080 >> tx)) ? 1 : 0;
|
||||
index |= (window.data & (0x8000 >> tx)) ? 2 : 0;
|
||||
|
||||
|
@ -112,15 +110,15 @@ void PPU::dmg_run_window() {
|
|||
bg.palette = index;
|
||||
}
|
||||
|
||||
void PPU::dmg_run_ob() {
|
||||
auto PPU::dmg_run_ob() -> void {
|
||||
//render backwards, so that first sprite has priority
|
||||
for(signed n = sprites - 1; n >= 0; n--) {
|
||||
for(int n = sprites - 1; n >= 0; n--) {
|
||||
Sprite& s = sprite[n];
|
||||
|
||||
signed tx = px - s.x;
|
||||
int tx = px - s.x;
|
||||
if(tx < 0 || tx > 7) continue;
|
||||
|
||||
unsigned index = 0;
|
||||
uint index = 0;
|
||||
index |= (s.data & (0x0080 >> tx)) ? 1 : 0;
|
||||
index |= (s.data & (0x8000 >> tx)) ? 2 : 0;
|
||||
if(index == 0) continue;
|
||||
|
@ -130,5 +128,3 @@ void PPU::dmg_run_ob() {
|
|||
ob.priority = !(s.attr & 0x80);
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
@ -1,10 +1,8 @@
|
|||
#ifdef PPU_CPP
|
||||
|
||||
unsigned PPU::vram_addr(uint16 addr) const {
|
||||
auto PPU::vram_addr(uint16 addr) const -> uint {
|
||||
return (status.vram_bank * 0x2000) + (addr & 0x1fff);
|
||||
}
|
||||
|
||||
uint8 PPU::mmio_read(uint16 addr) {
|
||||
auto PPU::mmio_read(uint16 addr) -> uint8 {
|
||||
if(addr >= 0x8000 && addr <= 0x9fff) return vram[vram_addr(addr)];
|
||||
if(addr >= 0xfe00 && addr <= 0xfe9f) return oam[addr & 0xff];
|
||||
|
||||
|
@ -20,7 +18,7 @@ uint8 PPU::mmio_read(uint16 addr) {
|
|||
}
|
||||
|
||||
if(addr == 0xff41) { //STAT
|
||||
unsigned mode;
|
||||
uint mode;
|
||||
if(status.ly >= 144) mode = 1; //Vblank
|
||||
else if(status.lx < 80) mode = 2; //OAM
|
||||
else if(status.lx < 252) mode = 3; //LCD
|
||||
|
@ -90,7 +88,7 @@ uint8 PPU::mmio_read(uint16 addr) {
|
|||
return 0x00;
|
||||
}
|
||||
|
||||
void PPU::mmio_write(uint16 addr, uint8 data) {
|
||||
auto PPU::mmio_write(uint16 addr, uint8 data) -> void {
|
||||
if(addr >= 0x8000 && addr <= 0x9fff) { vram[vram_addr(addr)] = data; return; }
|
||||
if(addr >= 0xfe00 && addr <= 0xfe9f) { oam[addr & 0xff] = data; return; }
|
||||
|
||||
|
@ -199,5 +197,3 @@ void PPU::mmio_write(uint16 addr, uint8 data) {
|
|||
if(status.obpi_increment) status.obpi++;
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
@ -6,7 +6,6 @@
|
|||
|
||||
//LX = 0-455
|
||||
|
||||
#define PPU_CPP
|
||||
namespace GameBoy {
|
||||
|
||||
#include "mmio.cpp"
|
||||
|
@ -15,11 +14,11 @@ namespace GameBoy {
|
|||
#include "serialization.cpp"
|
||||
PPU ppu;
|
||||
|
||||
void PPU::Main() {
|
||||
auto PPU::Main() -> void {
|
||||
ppu.main();
|
||||
}
|
||||
|
||||
void PPU::main() {
|
||||
auto PPU::main() -> void {
|
||||
while(true) {
|
||||
if(scheduler.sync == Scheduler::SynchronizeMode::All) {
|
||||
scheduler.exit(Scheduler::ExitReason::SynchronizeEvent);
|
||||
|
@ -30,7 +29,7 @@ void PPU::main() {
|
|||
if(status.display_enable && status.ly < 144) {
|
||||
if(status.interrupt_oam) cpu.interrupt_raise(CPU::Interrupt::Stat);
|
||||
add_clocks(92);
|
||||
for(unsigned n = 0; n < 160; n++) {
|
||||
for(auto n : range(160)) {
|
||||
system.cgb() ? cgb_run() : dmg_run();
|
||||
add_clocks(1);
|
||||
}
|
||||
|
@ -45,7 +44,7 @@ void PPU::main() {
|
|||
}
|
||||
}
|
||||
|
||||
void PPU::add_clocks(unsigned clocks) {
|
||||
auto PPU::add_clocks(uint clocks) -> void {
|
||||
status.lx += clocks;
|
||||
clock += clocks * cpu.frequency;
|
||||
if(clock >= 0 && scheduler.sync != Scheduler::SynchronizeMode::All) {
|
||||
|
@ -53,7 +52,7 @@ void PPU::add_clocks(unsigned clocks) {
|
|||
}
|
||||
}
|
||||
|
||||
void PPU::scanline() {
|
||||
auto PPU::scanline() -> void {
|
||||
status.lx = 0;
|
||||
if(++status.ly == 154) frame();
|
||||
|
||||
|
@ -71,23 +70,23 @@ void PPU::scanline() {
|
|||
}
|
||||
}
|
||||
|
||||
void PPU::frame() {
|
||||
auto PPU::frame() -> void {
|
||||
status.ly = 0;
|
||||
scheduler.exit(Scheduler::ExitReason::FrameEvent);
|
||||
}
|
||||
|
||||
unsigned PPU::hflip(unsigned data) const {
|
||||
auto PPU::hflip(uint data) const -> uint {
|
||||
return ((data & 0x8080) >> 7) | ((data & 0x4040) >> 5)
|
||||
| ((data & 0x2020) >> 3) | ((data & 0x1010) >> 1)
|
||||
| ((data & 0x0808) << 1) | ((data & 0x0404) << 3)
|
||||
| ((data & 0x0202) << 5) | ((data & 0x0101) << 7);
|
||||
}
|
||||
|
||||
void PPU::power() {
|
||||
auto PPU::power() -> void {
|
||||
create(Main, 4 * 1024 * 1024);
|
||||
|
||||
for(unsigned n = 0x8000; n <= 0x9fff; n++) bus.mmio[n] = this; //VRAM
|
||||
for(unsigned n = 0xfe00; n <= 0xfe9f; n++) bus.mmio[n] = this; //OAM
|
||||
for(uint n = 0x8000; n <= 0x9fff; n++) bus.mmio[n] = this; //VRAM
|
||||
for(uint n = 0xfe00; n <= 0xfe9f; n++) bus.mmio[n] = this; //OAM
|
||||
|
||||
bus.mmio[0xff40] = this; //LCDC
|
||||
bus.mmio[0xff41] = this; //STAT
|
||||
|
@ -174,7 +173,4 @@ void PPU::power() {
|
|||
window.data = 0;
|
||||
}
|
||||
|
||||
PPU::PPU() {
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1,4 +1,37 @@
|
|||
struct PPU : Thread, MMIO {
|
||||
static auto Main() -> void;
|
||||
auto main() -> void;
|
||||
auto add_clocks(uint clocks) -> void;
|
||||
auto scanline() -> void;
|
||||
auto frame() -> void;
|
||||
|
||||
auto hflip(uint data) const -> uint;
|
||||
|
||||
//mmio.cpp
|
||||
auto vram_addr(uint16 addr) const -> uint;
|
||||
auto mmio_read(uint16 addr) -> uint8;
|
||||
auto mmio_write(uint16 addr, uint8 data) -> void;
|
||||
|
||||
//dmg.cpp
|
||||
auto dmg_read_tile(bool select, uint x, uint y, uint& data) -> void;
|
||||
auto dmg_scanline() -> void;
|
||||
auto dmg_run() -> void;
|
||||
auto dmg_run_bg() -> void;
|
||||
auto dmg_run_window() -> void;
|
||||
auto dmg_run_ob() -> void;
|
||||
|
||||
//cgb.cpp
|
||||
auto cgb_read_tile(bool select, uint x, uint y, uint& attr, uint& data) -> void;
|
||||
auto cgb_scanline() -> void;
|
||||
auto cgb_run() -> void;
|
||||
auto cgb_run_bg() -> void;
|
||||
auto cgb_run_window() -> void;
|
||||
auto cgb_run_ob() -> void;
|
||||
|
||||
auto power() -> void;
|
||||
|
||||
auto serialize(serializer&) -> void;
|
||||
|
||||
uint8 vram[16384]; //GB = 8192, GBC = 16384
|
||||
uint8 oam[160];
|
||||
uint8 bgp[4];
|
||||
|
@ -7,7 +40,7 @@ struct PPU : Thread, MMIO {
|
|||
uint8 obpd[64];
|
||||
|
||||
struct Status {
|
||||
unsigned lx;
|
||||
uint lx;
|
||||
|
||||
//$ff40 LCDC
|
||||
bool display_enable;
|
||||
|
@ -66,57 +99,23 @@ struct PPU : Thread, MMIO {
|
|||
Pixel ob;
|
||||
|
||||
struct Sprite {
|
||||
unsigned x;
|
||||
unsigned y;
|
||||
unsigned tile;
|
||||
unsigned attr;
|
||||
unsigned data;
|
||||
uint x;
|
||||
uint y;
|
||||
uint tile;
|
||||
uint attr;
|
||||
uint data;
|
||||
};
|
||||
Sprite sprite[10];
|
||||
unsigned sprites;
|
||||
uint sprites;
|
||||
|
||||
unsigned px;
|
||||
uint px;
|
||||
|
||||
struct Background {
|
||||
unsigned attr;
|
||||
unsigned data;
|
||||
uint attr;
|
||||
uint data;
|
||||
};
|
||||
Background background;
|
||||
Background window;
|
||||
|
||||
static void Main();
|
||||
void main();
|
||||
void add_clocks(unsigned clocks);
|
||||
void scanline();
|
||||
void frame();
|
||||
|
||||
unsigned hflip(unsigned data) const;
|
||||
|
||||
//mmio.cpp
|
||||
unsigned vram_addr(uint16 addr) const;
|
||||
uint8 mmio_read(uint16 addr);
|
||||
void mmio_write(uint16 addr, uint8 data);
|
||||
|
||||
//dmg.cpp
|
||||
void dmg_read_tile(bool select, unsigned x, unsigned y, unsigned& data);
|
||||
void dmg_scanline();
|
||||
void dmg_run();
|
||||
void dmg_run_bg();
|
||||
void dmg_run_window();
|
||||
void dmg_run_ob();
|
||||
|
||||
//cgb.cpp
|
||||
void cgb_read_tile(bool select, unsigned x, unsigned y, unsigned& attr, unsigned& data);
|
||||
void cgb_scanline();
|
||||
void cgb_run();
|
||||
void cgb_run_bg();
|
||||
void cgb_run_window();
|
||||
void cgb_run_ob();
|
||||
|
||||
void power();
|
||||
|
||||
void serialize(serializer&);
|
||||
PPU();
|
||||
};
|
||||
|
||||
extern PPU ppu;
|
||||
|
|
|
@ -1,6 +1,4 @@
|
|||
#ifdef PPU_CPP
|
||||
|
||||
void PPU::serialize(serializer& s) {
|
||||
auto PPU::serialize(serializer& s) -> void {
|
||||
Thread::serialize(s);
|
||||
|
||||
s.array(vram);
|
||||
|
@ -68,5 +66,3 @@ void PPU::serialize(serializer& s) {
|
|||
s.integer(window.attr);
|
||||
s.integer(window.data);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
@ -1,30 +1,23 @@
|
|||
#include <gb/gb.hpp>
|
||||
|
||||
#define SCHEDULER_CPP
|
||||
namespace GameBoy {
|
||||
|
||||
Scheduler scheduler;
|
||||
|
||||
void Scheduler::enter() {
|
||||
auto Scheduler::init() -> void {
|
||||
host_thread = co_active();
|
||||
active_thread = cpu.thread;
|
||||
}
|
||||
|
||||
auto Scheduler::enter() -> void {
|
||||
host_thread = co_active();
|
||||
co_switch(active_thread);
|
||||
}
|
||||
|
||||
void Scheduler::exit(ExitReason reason) {
|
||||
auto Scheduler::exit(ExitReason reason) -> void {
|
||||
exit_reason = reason;
|
||||
active_thread = co_active();
|
||||
co_switch(host_thread);
|
||||
}
|
||||
|
||||
void Scheduler::init() {
|
||||
host_thread = co_active();
|
||||
active_thread = cpu.thread;
|
||||
}
|
||||
|
||||
Scheduler::Scheduler() {
|
||||
exit_reason = ExitReason::UnknownEvent;
|
||||
host_thread = nullptr;
|
||||
active_thread = nullptr;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1,16 +1,14 @@
|
|||
struct Scheduler : property<Scheduler> {
|
||||
enum class SynchronizeMode : unsigned { None, CPU, All } sync;
|
||||
enum class ExitReason : unsigned { UnknownEvent, StepEvent, FrameEvent, SynchronizeEvent };
|
||||
readonly<ExitReason> exit_reason;
|
||||
struct Scheduler {
|
||||
enum class SynchronizeMode : uint { None, CPU, All } sync;
|
||||
enum class ExitReason : uint { UnknownEvent, StepEvent, FrameEvent, SynchronizeEvent };
|
||||
|
||||
cothread_t host_thread;
|
||||
cothread_t active_thread;
|
||||
auto init() -> void;
|
||||
auto enter() -> void;
|
||||
auto exit(ExitReason) -> void;
|
||||
|
||||
void enter();
|
||||
void exit(ExitReason);
|
||||
|
||||
void init();
|
||||
Scheduler();
|
||||
cothread_t host_thread = nullptr;
|
||||
cothread_t active_thread = nullptr;
|
||||
ExitReason exit_reason = ExitReason::UnknownEvent;
|
||||
};
|
||||
|
||||
extern Scheduler scheduler;
|
||||
|
|
|
@ -1,9 +1,7 @@
|
|||
#ifdef SYSTEM_CPP
|
||||
|
||||
serializer System::serialize() {
|
||||
auto System::serialize() -> serializer {
|
||||
serializer s(serialize_size);
|
||||
|
||||
unsigned signature = 0x31545342, version = Info::SerializerVersion;
|
||||
uint signature = 0x31545342, version = Info::SerializerVersion;
|
||||
char hash[64], description[512];
|
||||
memcpy(&hash, (const char*)cartridge.sha256(), 64);
|
||||
memset(&description, 0, sizeof description);
|
||||
|
@ -17,8 +15,8 @@ serializer System::serialize() {
|
|||
return s;
|
||||
}
|
||||
|
||||
bool System::unserialize(serializer& s) {
|
||||
unsigned signature, version;
|
||||
auto System::unserialize(serializer& s) -> bool {
|
||||
uint signature, version;
|
||||
char hash[64], description[512];
|
||||
|
||||
s.integer(signature);
|
||||
|
@ -34,11 +32,11 @@ bool System::unserialize(serializer& s) {
|
|||
return true;
|
||||
}
|
||||
|
||||
void System::serialize(serializer& s) {
|
||||
auto System::serialize(serializer& s) -> void {
|
||||
s.integer(clocks_executed);
|
||||
}
|
||||
|
||||
void System::serialize_all(serializer& s) {
|
||||
auto System::serialize_all(serializer& s) -> void {
|
||||
cartridge.serialize(s);
|
||||
system.serialize(s);
|
||||
cpu.serialize(s);
|
||||
|
@ -46,10 +44,10 @@ void System::serialize_all(serializer& s) {
|
|||
apu.serialize(s);
|
||||
}
|
||||
|
||||
void System::serialize_init() {
|
||||
auto System::serialize_init() -> void {
|
||||
serializer s;
|
||||
|
||||
unsigned signature = 0, version = 0, crc32 = 0;
|
||||
uint signature = 0, version = 0, crc32 = 0;
|
||||
char hash[64], description[512];
|
||||
|
||||
s.integer(signature);
|
||||
|
@ -60,5 +58,3 @@ void System::serialize_init() {
|
|||
serialize_all(s);
|
||||
serialize_size = s.size();
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
@ -1,21 +1,26 @@
|
|||
#include <gb/gb.hpp>
|
||||
|
||||
#define SYSTEM_CPP
|
||||
namespace GameBoy {
|
||||
|
||||
#include "serialization.cpp"
|
||||
System system;
|
||||
|
||||
void System::run() {
|
||||
System::System() {
|
||||
for(auto& byte : bootROM.dmg) byte = 0;
|
||||
for(auto& byte : bootROM.sgb) byte = 0;
|
||||
for(auto& byte : bootROM.cgb) byte = 0;
|
||||
}
|
||||
|
||||
auto System::run() -> void {
|
||||
scheduler.sync = Scheduler::SynchronizeMode::None;
|
||||
|
||||
scheduler.enter();
|
||||
if(scheduler.exit_reason() == Scheduler::ExitReason::FrameEvent) {
|
||||
if(scheduler.exit_reason == Scheduler::ExitReason::FrameEvent) {
|
||||
interface->videoRefresh(video.palette, ppu.screen, 4 * 160, 160, 144);
|
||||
}
|
||||
}
|
||||
|
||||
void System::runtosave() {
|
||||
auto System::runtosave() -> void {
|
||||
scheduler.sync = Scheduler::SynchronizeMode::CPU;
|
||||
runthreadtosave();
|
||||
|
||||
|
@ -30,21 +35,21 @@ void System::runtosave() {
|
|||
scheduler.sync = Scheduler::SynchronizeMode::None;
|
||||
}
|
||||
|
||||
void System::runthreadtosave() {
|
||||
auto System::runthreadtosave() -> void {
|
||||
while(true) {
|
||||
scheduler.enter();
|
||||
if(scheduler.exit_reason() == Scheduler::ExitReason::SynchronizeEvent) break;
|
||||
if(scheduler.exit_reason() == Scheduler::ExitReason::FrameEvent) {
|
||||
if(scheduler.exit_reason == Scheduler::ExitReason::SynchronizeEvent) break;
|
||||
if(scheduler.exit_reason == Scheduler::ExitReason::FrameEvent) {
|
||||
interface->videoRefresh(video.palette, ppu.screen, 4 * 160, 160, 144);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void System::init() {
|
||||
auto System::init() -> void {
|
||||
assert(interface != nullptr);
|
||||
}
|
||||
|
||||
void System::load(Revision revision) {
|
||||
auto System::load(Revision revision) -> void {
|
||||
this->revision = revision;
|
||||
serialize_init();
|
||||
if(revision == Revision::SuperGameBoy) return; //Super Famicom core loads boot ROM for SGB
|
||||
|
@ -60,7 +65,7 @@ void System::load(Revision revision) {
|
|||
}
|
||||
}
|
||||
|
||||
void System::power() {
|
||||
auto System::power() -> void {
|
||||
bus.power();
|
||||
cartridge.power();
|
||||
cpu.power();
|
||||
|
@ -71,10 +76,4 @@ void System::power() {
|
|||
clocks_executed = 0;
|
||||
}
|
||||
|
||||
System::System() {
|
||||
for(auto& byte : bootROM.dmg) byte = 0;
|
||||
for(auto& byte : bootROM.sgb) byte = 0;
|
||||
for(auto& byte : bootROM.cgb) byte = 0;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1,19 +1,37 @@
|
|||
class Interface;
|
||||
|
||||
enum class Input : unsigned {
|
||||
enum class Input : uint {
|
||||
Up, Down, Left, Right, B, A, Select, Start,
|
||||
};
|
||||
|
||||
struct System {
|
||||
enum class Revision : unsigned {
|
||||
enum class Revision : uint {
|
||||
GameBoy,
|
||||
SuperGameBoy,
|
||||
GameBoyColor,
|
||||
} revision;
|
||||
|
||||
inline bool dmg() const { return revision == Revision::GameBoy; }
|
||||
inline bool sgb() const { return revision == Revision::SuperGameBoy; }
|
||||
inline bool cgb() const { return revision == Revision::GameBoyColor; }
|
||||
System();
|
||||
|
||||
inline auto dmg() const { return revision == Revision::GameBoy; }
|
||||
inline auto sgb() const { return revision == Revision::SuperGameBoy; }
|
||||
inline auto cgb() const { return revision == Revision::GameBoyColor; }
|
||||
|
||||
auto run() -> void;
|
||||
auto runtosave() -> void;
|
||||
auto runthreadtosave() -> void;
|
||||
|
||||
auto init() -> void;
|
||||
auto load(Revision) -> void;
|
||||
auto power() -> void;
|
||||
|
||||
//serialization.cpp
|
||||
auto serialize() -> serializer;
|
||||
auto unserialize(serializer&) -> bool;
|
||||
|
||||
auto serialize(serializer&) -> void;
|
||||
auto serialize_all(serializer&) -> void;
|
||||
auto serialize_init() -> void;
|
||||
|
||||
struct BootROM {
|
||||
uint8 dmg[ 256];
|
||||
|
@ -21,31 +39,12 @@ struct System {
|
|||
uint8 cgb[2048];
|
||||
} bootROM;
|
||||
|
||||
void run();
|
||||
void runtosave();
|
||||
void runthreadtosave();
|
||||
|
||||
void init();
|
||||
void load(Revision);
|
||||
void power();
|
||||
|
||||
unsigned clocks_executed;
|
||||
|
||||
//serialization.cpp
|
||||
unsigned serialize_size;
|
||||
|
||||
serializer serialize();
|
||||
bool unserialize(serializer&);
|
||||
|
||||
void serialize(serializer&);
|
||||
void serialize_all(serializer&);
|
||||
void serialize_init();
|
||||
|
||||
System();
|
||||
|
||||
struct Information {
|
||||
string manifest;
|
||||
} information;
|
||||
|
||||
uint clocks_executed = 0;
|
||||
uint serialize_size = 0;
|
||||
};
|
||||
|
||||
#include <gb/interface/interface.hpp>
|
||||
|
|
|
@ -1,17 +1,9 @@
|
|||
#include <gb/gb.hpp>
|
||||
|
||||
#define VIDEO_CPP
|
||||
namespace GameBoy {
|
||||
|
||||
Video video;
|
||||
|
||||
void Video::generate_palette(Emulator::Interface::PaletteMode mode) {
|
||||
this->mode = mode;
|
||||
if(system.dmg()) for(unsigned n = 0; n < 4; n++) palette[n] = palette_dmg(n);
|
||||
if(system.sgb()) for(unsigned n = 0; n < 4; n++) palette[n] = palette_sgb(n);
|
||||
if(system.cgb()) for(unsigned n = 0; n < (1 << 15); n++) palette[n] = palette_cgb(n);
|
||||
}
|
||||
|
||||
Video::Video() {
|
||||
palette = new uint32_t[1 << 15]();
|
||||
}
|
||||
|
@ -20,43 +12,50 @@ Video::~Video() {
|
|||
delete[] palette;
|
||||
}
|
||||
|
||||
unsigned Video::palette_dmg(unsigned color) const {
|
||||
auto Video::generate_palette(Emulator::Interface::PaletteMode mode) -> void {
|
||||
this->mode = mode;
|
||||
if(system.dmg()) for(auto n : range(4)) palette[n] = paletteDMG(n);
|
||||
if(system.sgb()) for(auto n : range(4)) palette[n] = paletteSGB(n);
|
||||
if(system.cgb()) for(auto n : range(1 << 15)) palette[n] = paletteCGB(n);
|
||||
}
|
||||
|
||||
auto Video::paletteDMG(uint color) const -> uint {
|
||||
if(mode == Emulator::Interface::PaletteMode::Literal) {
|
||||
return color;
|
||||
}
|
||||
|
||||
if(mode == Emulator::Interface::PaletteMode::Channel) {
|
||||
unsigned L = image::normalize(color, 2, 16);
|
||||
uint L = image::normalize(color, 2, 16);
|
||||
return interface->videoColor(color, 0, 0, 0, L);
|
||||
}
|
||||
|
||||
if(mode == Emulator::Interface::PaletteMode::Standard) {
|
||||
unsigned L = image::normalize(3 - color, 2, 16);
|
||||
uint L = image::normalize(3 - color, 2, 16);
|
||||
return interface->videoColor(color, 0, L, L, L);
|
||||
}
|
||||
|
||||
if(mode == Emulator::Interface::PaletteMode::Emulation) {
|
||||
unsigned R = monochrome[color][0];
|
||||
unsigned G = monochrome[color][1];
|
||||
unsigned B = monochrome[color][2];
|
||||
uint R = monochrome[color][0];
|
||||
uint G = monochrome[color][1];
|
||||
uint B = monochrome[color][2];
|
||||
return interface->videoColor(color, 0, R, G, B);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
unsigned Video::palette_sgb(unsigned color) const {
|
||||
auto Video::paletteSGB(uint color) const -> uint {
|
||||
return color;
|
||||
}
|
||||
|
||||
unsigned Video::palette_cgb(unsigned color) const {
|
||||
auto Video::paletteCGB(uint color) const -> uint {
|
||||
if(mode == Emulator::Interface::PaletteMode::Literal) {
|
||||
return color;
|
||||
}
|
||||
|
||||
unsigned r = (color >> 0) & 31;
|
||||
unsigned g = (color >> 5) & 31;
|
||||
unsigned b = (color >> 10) & 31;
|
||||
uint r = (color >> 0) & 31;
|
||||
uint g = (color >> 5) & 31;
|
||||
uint b = (color >> 10) & 31;
|
||||
|
||||
if(mode == Emulator::Interface::PaletteMode::Channel) {
|
||||
r = image::normalize(r, 5, 16);
|
||||
|
@ -73,9 +72,9 @@ unsigned Video::palette_cgb(unsigned color) const {
|
|||
}
|
||||
|
||||
if(mode == Emulator::Interface::PaletteMode::Emulation) {
|
||||
unsigned R = (r * 26 + g * 4 + b * 2);
|
||||
unsigned G = ( g * 24 + b * 8);
|
||||
unsigned B = (r * 6 + g * 4 + b * 22);
|
||||
uint R = (r * 26 + g * 4 + b * 2);
|
||||
uint G = ( g * 24 + b * 8);
|
||||
uint B = (r * 6 + g * 4 + b * 22);
|
||||
|
||||
R = min(960, R);
|
||||
G = min(960, G);
|
||||
|
|
|
@ -1,16 +1,17 @@
|
|||
struct Video {
|
||||
uint32_t* palette = nullptr;
|
||||
void generate_palette(Emulator::Interface::PaletteMode mode);
|
||||
|
||||
Video();
|
||||
~Video();
|
||||
|
||||
auto generate_palette(Emulator::Interface::PaletteMode mode) -> void;
|
||||
|
||||
uint32* palette = nullptr;
|
||||
|
||||
private:
|
||||
Emulator::Interface::PaletteMode mode;
|
||||
static const uint16 monochrome[4][3];
|
||||
uint32_t palette_dmg(unsigned color) const;
|
||||
uint32_t palette_sgb(unsigned color) const;
|
||||
uint32_t palette_cgb(unsigned color) const;
|
||||
auto paletteDMG(uint color) const -> uint;
|
||||
auto paletteSGB(uint color) const -> uint;
|
||||
auto paletteCGB(uint color) const -> uint;
|
||||
};
|
||||
|
||||
extern Video video;
|
||||
|
|
|
@ -1,14 +1,16 @@
|
|||
#ifdef NALL_DSP_INTERNAL_HPP
|
||||
|
||||
struct Buffer {
|
||||
double** sample = nullptr;
|
||||
uint16_t rdoffset = 0;
|
||||
uint16_t wroffset = 0;
|
||||
unsigned channels = 0;
|
||||
Buffer() {
|
||||
}
|
||||
|
||||
void setChannels(unsigned channels) {
|
||||
~Buffer() {
|
||||
setChannels(0);
|
||||
}
|
||||
|
||||
auto setChannels(uint channels) -> void {
|
||||
if(sample) {
|
||||
for(unsigned c = 0; c < this->channels; c++) {
|
||||
for(auto c : range(this->channels)) {
|
||||
if(sample[c]) delete[] sample[c];
|
||||
}
|
||||
delete[] sample;
|
||||
|
@ -18,22 +20,22 @@ struct Buffer {
|
|||
if(channels == 0) return;
|
||||
|
||||
sample = new double*[channels];
|
||||
for(unsigned c = 0; c < channels; c++) {
|
||||
for(auto c : range(channels)) {
|
||||
sample[c] = new double[65536]();
|
||||
}
|
||||
}
|
||||
|
||||
inline double& read(unsigned channel, signed offset = 0) {
|
||||
return sample[channel][(uint16_t)(rdoffset + offset)];
|
||||
inline auto read(uint channel, int offset = 0) -> double& {
|
||||
return sample[channel][(uint16)(rdoffset + offset)];
|
||||
}
|
||||
|
||||
inline double& write(unsigned channel, signed offset = 0) {
|
||||
return sample[channel][(uint16_t)(wroffset + offset)];
|
||||
inline auto write(uint channel, int offset = 0) -> double& {
|
||||
return sample[channel][(uint16)(wroffset + offset)];
|
||||
}
|
||||
|
||||
inline void clear() {
|
||||
for(unsigned c = 0; c < channels; c++) {
|
||||
for(unsigned n = 0; n < 65536; n++) {
|
||||
inline auto clear() -> void {
|
||||
for(auto c : range(channels)) {
|
||||
for(auto n : range(65536)) {
|
||||
sample[c][n] = 0;
|
||||
}
|
||||
}
|
||||
|
@ -41,12 +43,10 @@ struct Buffer {
|
|||
wroffset = 0;
|
||||
}
|
||||
|
||||
Buffer() {
|
||||
}
|
||||
|
||||
~Buffer() {
|
||||
setChannels(0);
|
||||
}
|
||||
double** sample = nullptr;
|
||||
uint16 rdoffset = 0;
|
||||
uint16 wroffset = 0;
|
||||
uint channels = 0;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
@ -6,24 +6,22 @@
|
|||
|
||||
namespace nall {
|
||||
|
||||
//precision: can be float, double or long double
|
||||
#define real float
|
||||
|
||||
struct DSP;
|
||||
|
||||
struct Resampler {
|
||||
DSP& dsp;
|
||||
real frequency;
|
||||
|
||||
virtual void setFrequency() = 0;
|
||||
virtual void clear() = 0;
|
||||
virtual void sample() = 0;
|
||||
Resampler(DSP& dsp) : dsp(dsp) {}
|
||||
virtual ~Resampler() {}
|
||||
|
||||
virtual auto setFrequency() -> void = 0;
|
||||
virtual auto clear() -> void = 0;
|
||||
virtual auto sample() -> void = 0;
|
||||
|
||||
DSP& dsp;
|
||||
double frequency = 44100.0;
|
||||
};
|
||||
|
||||
struct DSP {
|
||||
enum class ResampleEngine : unsigned {
|
||||
enum class ResampleEngine : uint {
|
||||
Nearest,
|
||||
Linear,
|
||||
Cosine,
|
||||
|
@ -33,24 +31,48 @@ struct DSP {
|
|||
Sinc,
|
||||
};
|
||||
|
||||
inline void setChannels(unsigned channels);
|
||||
inline void setPrecision(unsigned precision);
|
||||
inline void setFrequency(real frequency); //inputFrequency
|
||||
inline void setVolume(real volume);
|
||||
inline void setBalance(real balance);
|
||||
|
||||
inline void setResampler(ResampleEngine resamplingEngine);
|
||||
inline void setResamplerFrequency(real frequency); //outputFrequency
|
||||
|
||||
inline void sample(signed channel[]);
|
||||
inline bool pending();
|
||||
inline void read(signed channel[]);
|
||||
|
||||
inline void clear();
|
||||
inline DSP();
|
||||
inline ~DSP();
|
||||
|
||||
inline auto setChannels(uint channels) -> void;
|
||||
inline auto setPrecision(uint precision) -> void;
|
||||
inline auto setFrequency(double frequency) -> void; //inputFrequency
|
||||
inline auto setVolume(double volume) -> void;
|
||||
inline auto setBalance(double balance) -> void;
|
||||
|
||||
inline auto setResampler(ResampleEngine resamplingEngine) -> void;
|
||||
inline auto setResamplerFrequency(double frequency) -> void; //outputFrequency
|
||||
|
||||
inline auto sample(int channel[]) -> void;
|
||||
inline auto pending() const -> bool;
|
||||
inline auto read(int channel[]) -> void;
|
||||
|
||||
inline auto clear() -> void;
|
||||
|
||||
protected:
|
||||
inline auto write(double channel[]) -> void;
|
||||
inline auto adjustVolume() -> void;
|
||||
inline auto adjustBalance() -> void;
|
||||
inline auto clamp(const uint bits, const int input) -> int;
|
||||
|
||||
struct Settings {
|
||||
uint channels;
|
||||
uint precision;
|
||||
double frequency;
|
||||
double volume;
|
||||
double balance;
|
||||
|
||||
//internal
|
||||
double intensity;
|
||||
double intensityInverse;
|
||||
} settings;
|
||||
|
||||
Resampler* resampler = nullptr;
|
||||
|
||||
#include "buffer.hpp"
|
||||
Buffer buffer;
|
||||
Buffer output;
|
||||
|
||||
friend class ResampleNearest;
|
||||
friend class ResampleLinear;
|
||||
friend class ResampleCosine;
|
||||
|
@ -58,29 +80,6 @@ protected:
|
|||
friend class ResampleAverage;
|
||||
friend class ResampleHermite;
|
||||
friend class ResampleSinc;
|
||||
|
||||
struct Settings {
|
||||
unsigned channels;
|
||||
unsigned precision;
|
||||
real frequency;
|
||||
real volume;
|
||||
real balance;
|
||||
|
||||
//internal
|
||||
real intensity;
|
||||
real intensityInverse;
|
||||
} settings;
|
||||
|
||||
Resampler* resampler = nullptr;
|
||||
inline void write(real channel[]);
|
||||
|
||||
#include "buffer.hpp"
|
||||
Buffer buffer;
|
||||
Buffer output;
|
||||
|
||||
inline void adjustVolume();
|
||||
inline void adjustBalance();
|
||||
inline signed clamp(const unsigned bits, const signed x);
|
||||
};
|
||||
|
||||
#include "resample/nearest.hpp"
|
||||
|
@ -92,59 +91,6 @@ protected:
|
|||
#include "resample/sinc.hpp"
|
||||
#include "settings.hpp"
|
||||
|
||||
void DSP::sample(signed channel[]) {
|
||||
for(unsigned c = 0; c < settings.channels; c++) {
|
||||
buffer.write(c) = (real)channel[c] * settings.intensityInverse;
|
||||
}
|
||||
buffer.wroffset++;
|
||||
resampler->sample();
|
||||
}
|
||||
|
||||
bool DSP::pending() {
|
||||
return output.rdoffset != output.wroffset;
|
||||
}
|
||||
|
||||
void DSP::read(signed channel[]) {
|
||||
adjustVolume();
|
||||
adjustBalance();
|
||||
|
||||
for(unsigned c = 0; c < settings.channels; c++) {
|
||||
channel[c] = clamp(settings.precision, output.read(c) * settings.intensity);
|
||||
}
|
||||
output.rdoffset++;
|
||||
}
|
||||
|
||||
void DSP::write(real channel[]) {
|
||||
for(unsigned c = 0; c < settings.channels; c++) {
|
||||
output.write(c) = channel[c];
|
||||
}
|
||||
output.wroffset++;
|
||||
}
|
||||
|
||||
void DSP::adjustVolume() {
|
||||
for(unsigned c = 0; c < settings.channels; c++) {
|
||||
output.read(c) *= settings.volume;
|
||||
}
|
||||
}
|
||||
|
||||
void DSP::adjustBalance() {
|
||||
if(settings.channels != 2) return; //TODO: support > 2 channels
|
||||
if(settings.balance < 0.0) output.read(1) *= 1.0 + settings.balance;
|
||||
if(settings.balance > 0.0) output.read(0) *= 1.0 - settings.balance;
|
||||
}
|
||||
|
||||
signed DSP::clamp(const unsigned bits, const signed x) {
|
||||
const signed b = 1U << (bits - 1);
|
||||
const signed m = (1U << (bits - 1)) - 1;
|
||||
return (x > m) ? m : (x < -b) ? -b : x;
|
||||
}
|
||||
|
||||
void DSP::clear() {
|
||||
buffer.clear();
|
||||
output.clear();
|
||||
resampler->clear();
|
||||
}
|
||||
|
||||
DSP::DSP() {
|
||||
setResampler(ResampleEngine::Hermite);
|
||||
setResamplerFrequency(44100.0);
|
||||
|
@ -162,7 +108,58 @@ DSP::~DSP() {
|
|||
if(resampler) delete resampler;
|
||||
}
|
||||
|
||||
#undef real
|
||||
auto DSP::sample(int channel[]) -> void {
|
||||
for(auto c : range(settings.channels)) {
|
||||
buffer.write(c) = (double)channel[c] * settings.intensityInverse;
|
||||
}
|
||||
buffer.wroffset++;
|
||||
resampler->sample();
|
||||
}
|
||||
|
||||
auto DSP::pending() const -> bool {
|
||||
return output.rdoffset != output.wroffset;
|
||||
}
|
||||
|
||||
auto DSP::read(int channel[]) -> void {
|
||||
adjustVolume();
|
||||
adjustBalance();
|
||||
|
||||
for(auto c : range(settings.channels)) {
|
||||
channel[c] = clamp(settings.precision, output.read(c) * settings.intensity);
|
||||
}
|
||||
output.rdoffset++;
|
||||
}
|
||||
|
||||
auto DSP::write(double channel[]) -> void {
|
||||
for(auto c : range(settings.channels)) {
|
||||
output.write(c) = channel[c];
|
||||
}
|
||||
output.wroffset++;
|
||||
}
|
||||
|
||||
auto DSP::adjustVolume() -> void {
|
||||
for(auto c : range(settings.channels)) {
|
||||
output.read(c) *= settings.volume;
|
||||
}
|
||||
}
|
||||
|
||||
auto DSP::adjustBalance() -> void {
|
||||
if(settings.channels != 2) return; //TODO: support > 2 channels
|
||||
if(settings.balance < 0.0) output.read(1) *= 1.0 + settings.balance;
|
||||
if(settings.balance > 0.0) output.read(0) *= 1.0 - settings.balance;
|
||||
}
|
||||
|
||||
auto DSP::clamp(const uint bits, const int x) -> int {
|
||||
const int b = 1U << (bits - 1);
|
||||
const int m = (1U << (bits - 1)) - 1;
|
||||
return (x > m) ? m : (x < -b) ? -b : x;
|
||||
}
|
||||
|
||||
auto DSP::clear() -> void {
|
||||
buffer.clear();
|
||||
output.clear();
|
||||
resampler->clear();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
|
|
@ -1,46 +1,48 @@
|
|||
#ifdef NALL_DSP_INTERNAL_HPP
|
||||
|
||||
struct ResampleAverage : Resampler {
|
||||
inline void setFrequency();
|
||||
inline void clear();
|
||||
inline void sample();
|
||||
inline void sampleLinear();
|
||||
ResampleAverage(DSP& dsp) : Resampler(dsp) {}
|
||||
|
||||
real fraction;
|
||||
real step;
|
||||
inline auto setFrequency() -> void;
|
||||
inline auto clear() -> void;
|
||||
inline auto sample() -> void;
|
||||
inline auto sampleLinear() -> void;
|
||||
|
||||
private:
|
||||
double fraction;
|
||||
double step;
|
||||
};
|
||||
|
||||
void ResampleAverage::setFrequency() {
|
||||
auto ResampleAverage::setFrequency() -> void {
|
||||
fraction = 0.0;
|
||||
step = dsp.settings.frequency / frequency;
|
||||
}
|
||||
|
||||
void ResampleAverage::clear() {
|
||||
auto ResampleAverage::clear() -> void {
|
||||
fraction = 0.0;
|
||||
}
|
||||
|
||||
void ResampleAverage::sample() {
|
||||
auto ResampleAverage::sample() -> void {
|
||||
//can only average if input frequency >= output frequency
|
||||
if(step < 1.0) return sampleLinear();
|
||||
|
||||
fraction += 1.0;
|
||||
|
||||
real scalar = 1.0;
|
||||
double scalar = 1.0;
|
||||
if(fraction > step) scalar = 1.0 - (fraction - step);
|
||||
|
||||
for(unsigned c = 0; c < dsp.settings.channels; c++) {
|
||||
for(auto c : range(dsp.settings.channels)) {
|
||||
dsp.output.write(c) += dsp.buffer.read(c) * scalar;
|
||||
}
|
||||
|
||||
if(fraction >= step) {
|
||||
for(unsigned c = 0; c < dsp.settings.channels; c++) {
|
||||
for(auto c : range(dsp.settings.channels)) {
|
||||
dsp.output.write(c) /= step;
|
||||
}
|
||||
dsp.output.wroffset++;
|
||||
|
||||
fraction -= step;
|
||||
for(unsigned c = 0; c < dsp.settings.channels; c++) {
|
||||
for(auto c : range(dsp.settings.channels)) {
|
||||
dsp.output.write(c) = dsp.buffer.read(c) * fraction;
|
||||
}
|
||||
}
|
||||
|
@ -48,15 +50,15 @@ void ResampleAverage::sample() {
|
|||
dsp.buffer.rdoffset++;
|
||||
}
|
||||
|
||||
void ResampleAverage::sampleLinear() {
|
||||
auto ResampleAverage::sampleLinear() -> void {
|
||||
while(fraction <= 1.0) {
|
||||
real channel[dsp.settings.channels];
|
||||
double channel[dsp.settings.channels];
|
||||
|
||||
for(unsigned n = 0; n < dsp.settings.channels; n++) {
|
||||
real a = dsp.buffer.read(n, -1);
|
||||
real b = dsp.buffer.read(n, -0);
|
||||
for(auto n : range(dsp.settings.channels)) {
|
||||
double a = dsp.buffer.read(n, -1);
|
||||
double b = dsp.buffer.read(n, -0);
|
||||
|
||||
real mu = fraction;
|
||||
double mu = fraction;
|
||||
|
||||
channel[n] = a * (1.0 - mu) + b * mu;
|
||||
}
|
||||
|
|
|
@ -1,33 +1,35 @@
|
|||
#ifdef NALL_DSP_INTERNAL_HPP
|
||||
|
||||
struct ResampleCosine : Resampler {
|
||||
inline void setFrequency();
|
||||
inline void clear();
|
||||
inline void sample();
|
||||
ResampleCosine(DSP& dsp) : Resampler(dsp) {}
|
||||
|
||||
real fraction;
|
||||
real step;
|
||||
inline auto setFrequency() -> void;
|
||||
inline auto clear() -> void;
|
||||
inline auto sample() -> void;
|
||||
|
||||
private:
|
||||
double fraction;
|
||||
double step;
|
||||
};
|
||||
|
||||
void ResampleCosine::setFrequency() {
|
||||
auto ResampleCosine::setFrequency() -> void {
|
||||
fraction = 0.0;
|
||||
step = dsp.settings.frequency / frequency;
|
||||
}
|
||||
|
||||
void ResampleCosine::clear() {
|
||||
auto ResampleCosine::clear() -> void {
|
||||
fraction = 0.0;
|
||||
}
|
||||
|
||||
void ResampleCosine::sample() {
|
||||
auto ResampleCosine::sample() -> void {
|
||||
while(fraction <= 1.0) {
|
||||
real channel[dsp.settings.channels];
|
||||
double channel[dsp.settings.channels];
|
||||
|
||||
for(unsigned n = 0; n < dsp.settings.channels; n++) {
|
||||
real a = dsp.buffer.read(n, -1);
|
||||
real b = dsp.buffer.read(n, -0);
|
||||
for(auto n : range(dsp.settings.channels)) {
|
||||
double a = dsp.buffer.read(n, -1);
|
||||
double b = dsp.buffer.read(n, -0);
|
||||
|
||||
real mu = fraction;
|
||||
double mu = fraction;
|
||||
mu = (1.0 - cos(mu * 3.14159265)) / 2.0;
|
||||
|
||||
channel[n] = a * (1.0 - mu) + b * mu;
|
||||
|
|
|
@ -1,40 +1,42 @@
|
|||
#ifdef NALL_DSP_INTERNAL_HPP
|
||||
|
||||
struct ResampleCubic : Resampler {
|
||||
inline void setFrequency();
|
||||
inline void clear();
|
||||
inline void sample();
|
||||
ResampleCubic(DSP& dsp) : Resampler(dsp) {}
|
||||
|
||||
real fraction;
|
||||
real step;
|
||||
inline auto setFrequency() -> void;
|
||||
inline auto clear() -> void;
|
||||
inline auto sample() -> void;
|
||||
|
||||
private:
|
||||
double fraction;
|
||||
double step;
|
||||
};
|
||||
|
||||
void ResampleCubic::setFrequency() {
|
||||
auto ResampleCubic::setFrequency() -> void {
|
||||
fraction = 0.0;
|
||||
step = dsp.settings.frequency / frequency;
|
||||
}
|
||||
|
||||
void ResampleCubic::clear() {
|
||||
auto ResampleCubic::clear() -> void {
|
||||
fraction = 0.0;
|
||||
}
|
||||
|
||||
void ResampleCubic::sample() {
|
||||
auto ResampleCubic::sample() -> void {
|
||||
while(fraction <= 1.0) {
|
||||
real channel[dsp.settings.channels];
|
||||
double channel[dsp.settings.channels];
|
||||
|
||||
for(unsigned n = 0; n < dsp.settings.channels; n++) {
|
||||
real a = dsp.buffer.read(n, -3);
|
||||
real b = dsp.buffer.read(n, -2);
|
||||
real c = dsp.buffer.read(n, -1);
|
||||
real d = dsp.buffer.read(n, -0);
|
||||
for(auto n : range(dsp.settings.channels)) {
|
||||
double a = dsp.buffer.read(n, -3);
|
||||
double b = dsp.buffer.read(n, -2);
|
||||
double c = dsp.buffer.read(n, -1);
|
||||
double d = dsp.buffer.read(n, -0);
|
||||
|
||||
real mu = fraction;
|
||||
double mu = fraction;
|
||||
|
||||
real A = d - c - a + b;
|
||||
real B = a - b - A;
|
||||
real C = c - a;
|
||||
real D = b;
|
||||
double A = d - c - a + b;
|
||||
double B = a - b - A;
|
||||
double C = c - a;
|
||||
double D = b;
|
||||
|
||||
channel[n] = A * (mu * 3) + B * (mu * 2) + C * mu + D;
|
||||
}
|
||||
|
|
|
@ -1,38 +1,40 @@
|
|||
#ifdef NALL_DSP_INTERNAL_HPP
|
||||
|
||||
struct ResampleHermite : Resampler {
|
||||
inline void setFrequency();
|
||||
inline void clear();
|
||||
inline void sample();
|
||||
ResampleHermite(DSP& dsp) : Resampler(dsp) {}
|
||||
|
||||
real fraction;
|
||||
real step;
|
||||
inline auto setFrequency() -> void;
|
||||
inline auto clear() -> void;
|
||||
inline auto sample() -> void;
|
||||
|
||||
private:
|
||||
double fraction;
|
||||
double step;
|
||||
};
|
||||
|
||||
void ResampleHermite::setFrequency() {
|
||||
auto ResampleHermite::setFrequency() -> void {
|
||||
fraction = 0.0;
|
||||
step = dsp.settings.frequency / frequency;
|
||||
}
|
||||
|
||||
void ResampleHermite::clear() {
|
||||
auto ResampleHermite::clear() -> void {
|
||||
fraction = 0.0;
|
||||
}
|
||||
|
||||
void ResampleHermite::sample() {
|
||||
auto ResampleHermite::sample() -> void {
|
||||
while(fraction <= 1.0) {
|
||||
real channel[dsp.settings.channels];
|
||||
double channel[dsp.settings.channels];
|
||||
|
||||
for(unsigned n = 0; n < dsp.settings.channels; n++) {
|
||||
real a = dsp.buffer.read(n, -3);
|
||||
real b = dsp.buffer.read(n, -2);
|
||||
real c = dsp.buffer.read(n, -1);
|
||||
real d = dsp.buffer.read(n, -0);
|
||||
for(auto n : range(dsp.settings.channels)) {
|
||||
double a = dsp.buffer.read(n, -3);
|
||||
double b = dsp.buffer.read(n, -2);
|
||||
double c = dsp.buffer.read(n, -1);
|
||||
double d = dsp.buffer.read(n, -0);
|
||||
|
||||
const real tension = 0.0; //-1 = low, 0 = normal, +1 = high
|
||||
const real bias = 0.0; //-1 = left, 0 = even, +1 = right
|
||||
const double tension = 0.0; //-1 = low, 0 = normal, +1 = high
|
||||
const double bias = 0.0; //-1 = left, 0 = even, +1 = right
|
||||
|
||||
real mu1, mu2, mu3, m0, m1, a0, a1, a2, a3;
|
||||
double mu1, mu2, mu3, m0, m1, a0, a1, a2, a3;
|
||||
|
||||
mu1 = fraction;
|
||||
mu2 = mu1 * mu1;
|
||||
|
|
|
@ -1,33 +1,35 @@
|
|||
#ifdef NALL_DSP_INTERNAL_HPP
|
||||
|
||||
struct ResampleLinear : Resampler {
|
||||
inline void setFrequency();
|
||||
inline void clear();
|
||||
inline void sample();
|
||||
ResampleLinear(DSP& dsp) : Resampler(dsp) {}
|
||||
|
||||
real fraction;
|
||||
real step;
|
||||
inline auto setFrequency() -> void;
|
||||
inline auto clear() -> void;
|
||||
inline auto sample() -> void;
|
||||
|
||||
private:
|
||||
double fraction;
|
||||
double step;
|
||||
};
|
||||
|
||||
void ResampleLinear::setFrequency() {
|
||||
auto ResampleLinear::setFrequency() -> void {
|
||||
fraction = 0.0;
|
||||
step = dsp.settings.frequency / frequency;
|
||||
}
|
||||
|
||||
void ResampleLinear::clear() {
|
||||
auto ResampleLinear::clear() -> void {
|
||||
fraction = 0.0;
|
||||
}
|
||||
|
||||
void ResampleLinear::sample() {
|
||||
auto ResampleLinear::sample() -> void {
|
||||
while(fraction <= 1.0) {
|
||||
real channel[dsp.settings.channels];
|
||||
double channel[dsp.settings.channels];
|
||||
|
||||
for(unsigned n = 0; n < dsp.settings.channels; n++) {
|
||||
real a = dsp.buffer.read(n, -1);
|
||||
real b = dsp.buffer.read(n, -0);
|
||||
for(auto n : range(dsp.settings.channels)) {
|
||||
double a = dsp.buffer.read(n, -1);
|
||||
double b = dsp.buffer.read(n, -0);
|
||||
|
||||
real mu = fraction;
|
||||
double mu = fraction;
|
||||
|
||||
channel[n] = a * (1.0 - mu) + b * mu;
|
||||
}
|
||||
|
|
|
@ -1,33 +1,35 @@
|
|||
#ifdef NALL_DSP_INTERNAL_HPP
|
||||
|
||||
struct ResampleNearest : Resampler {
|
||||
inline void setFrequency();
|
||||
inline void clear();
|
||||
inline void sample();
|
||||
ResampleNearest(DSP& dsp) : Resampler(dsp) {}
|
||||
|
||||
real fraction;
|
||||
real step;
|
||||
inline auto setFrequency() -> void;
|
||||
inline auto clear() -> void;
|
||||
inline auto sample() -> void;
|
||||
|
||||
private:
|
||||
double fraction;
|
||||
double step;
|
||||
};
|
||||
|
||||
void ResampleNearest::setFrequency() {
|
||||
auto ResampleNearest::setFrequency() -> void {
|
||||
fraction = 0.0;
|
||||
step = dsp.settings.frequency / frequency;
|
||||
}
|
||||
|
||||
void ResampleNearest::clear() {
|
||||
auto ResampleNearest::clear() -> void {
|
||||
fraction = 0.0;
|
||||
}
|
||||
|
||||
void ResampleNearest::sample() {
|
||||
auto ResampleNearest::sample() -> void {
|
||||
while(fraction <= 1.0) {
|
||||
real channel[dsp.settings.channels];
|
||||
double channel[dsp.settings.channels];
|
||||
|
||||
for(unsigned n = 0; n < dsp.settings.channels; n++) {
|
||||
real a = dsp.buffer.read(n, -1);
|
||||
real b = dsp.buffer.read(n, -0);
|
||||
for(auto n : range(dsp.settings.channels)) {
|
||||
double a = dsp.buffer.read(n, -1);
|
||||
double b = dsp.buffer.read(n, -0);
|
||||
|
||||
real mu = fraction;
|
||||
double mu = fraction;
|
||||
|
||||
channel[n] = mu < 0.5 ? a : b;
|
||||
}
|
||||
|
|
|
@ -3,51 +3,61 @@
|
|||
#include "lib/sinc.hpp"
|
||||
|
||||
struct ResampleSinc : Resampler {
|
||||
inline void setFrequency();
|
||||
inline void clear();
|
||||
inline void sample();
|
||||
inline ResampleSinc(DSP& dsp);
|
||||
inline ~ResampleSinc();
|
||||
|
||||
inline auto setFrequency() -> void;
|
||||
inline auto clear() -> void;
|
||||
inline auto sample() -> void;
|
||||
|
||||
private:
|
||||
inline void remakeSinc();
|
||||
SincResample* sinc_resampler[8];
|
||||
SincResample* sincResampler[8] = {0};
|
||||
};
|
||||
|
||||
void ResampleSinc::setFrequency() {
|
||||
ResampleSinc::ResampleSinc(DSP& dsp) : Resampler(dsp) {
|
||||
for(auto n : range(8)) {
|
||||
sincResampler[n] = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
ResampleSinc::~ResampleSinc() {
|
||||
for(auto n : range(8)) {
|
||||
if(sincResampler[n]) delete sincResampler[n];
|
||||
}
|
||||
}
|
||||
|
||||
auto ResampleSinc::setFrequency() -> void {
|
||||
remakeSinc();
|
||||
}
|
||||
|
||||
void ResampleSinc::clear() {
|
||||
auto ResampleSinc::clear() -> void {
|
||||
remakeSinc();
|
||||
}
|
||||
|
||||
void ResampleSinc::sample() {
|
||||
for(unsigned c = 0; c < dsp.settings.channels; c++) {
|
||||
sinc_resampler[c]->write(dsp.buffer.read(c));
|
||||
auto ResampleSinc::sample() -> void {
|
||||
for(auto c : range(dsp.settings.channels)) {
|
||||
sincResampler[c]->write(dsp.buffer.read(c));
|
||||
}
|
||||
|
||||
if(sinc_resampler[0]->output_avail()) {
|
||||
if(sincResampler[0]->output_avail()) {
|
||||
do {
|
||||
for(unsigned c = 0; c < dsp.settings.channels; c++) {
|
||||
dsp.output.write(c) = sinc_resampler[c]->read();
|
||||
for(auto c : range(dsp.settings.channels)) {
|
||||
dsp.output.write(c) = sincResampler[c]->read();
|
||||
}
|
||||
dsp.output.wroffset++;
|
||||
} while(sinc_resampler[0]->output_avail());
|
||||
} while(sincResampler[0]->output_avail());
|
||||
}
|
||||
|
||||
dsp.buffer.rdoffset++;
|
||||
}
|
||||
|
||||
ResampleSinc::ResampleSinc(DSP& dsp) : Resampler(dsp) {
|
||||
for(unsigned n = 0; n < 8; n++) sinc_resampler[n] = nullptr;
|
||||
}
|
||||
|
||||
void ResampleSinc::remakeSinc() {
|
||||
auto ResampleSinc::remakeSinc() -> void {
|
||||
assert(dsp.settings.channels < 8);
|
||||
|
||||
for(unsigned c = 0; c < dsp.settings.channels; c++) {
|
||||
if(sinc_resampler[c]) delete sinc_resampler[c];
|
||||
sinc_resampler[c] = new SincResample(dsp.settings.frequency, frequency, 0.85, SincResample::QUALITY_HIGH);
|
||||
for(auto c : range(dsp.settings.channels)) {
|
||||
if(sincResampler[c]) delete sincResampler[c];
|
||||
sincResampler[c] = new SincResample(dsp.settings.frequency, frequency, 0.85, SincResample::QUALITY_HIGH);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,35 +1,35 @@
|
|||
#ifdef NALL_DSP_INTERNAL_HPP
|
||||
|
||||
void DSP::setChannels(unsigned channels) {
|
||||
assert(channels > 0);
|
||||
auto DSP::setChannels(uint channels) -> void {
|
||||
channels = max(1u, channels);
|
||||
buffer.setChannels(channels);
|
||||
output.setChannels(channels);
|
||||
settings.channels = channels;
|
||||
}
|
||||
|
||||
void DSP::setPrecision(unsigned precision) {
|
||||
auto DSP::setPrecision(uint precision) -> void {
|
||||
settings.precision = precision;
|
||||
settings.intensity = 1 << (settings.precision - 1);
|
||||
settings.intensityInverse = 1.0 / settings.intensity;
|
||||
}
|
||||
|
||||
void DSP::setFrequency(real frequency) {
|
||||
auto DSP::setFrequency(double frequency) -> void {
|
||||
settings.frequency = frequency;
|
||||
resampler->setFrequency();
|
||||
}
|
||||
|
||||
void DSP::setVolume(real volume) {
|
||||
auto DSP::setVolume(double volume) -> void {
|
||||
settings.volume = volume;
|
||||
}
|
||||
|
||||
void DSP::setBalance(real balance) {
|
||||
auto DSP::setBalance(double balance) -> void {
|
||||
settings.balance = balance;
|
||||
}
|
||||
|
||||
void DSP::setResampler(ResampleEngine engine) {
|
||||
auto DSP::setResampler(ResampleEngine engine) -> void {
|
||||
if(resampler) delete resampler;
|
||||
|
||||
switch(engine) {
|
||||
switch(engine) { default:
|
||||
case ResampleEngine::Nearest: resampler = new ResampleNearest(*this); return;
|
||||
case ResampleEngine::Linear: resampler = new ResampleLinear (*this); return;
|
||||
case ResampleEngine::Cosine: resampler = new ResampleCosine (*this); return;
|
||||
|
@ -38,11 +38,9 @@ void DSP::setResampler(ResampleEngine engine) {
|
|||
case ResampleEngine::Average: resampler = new ResampleAverage(*this); return;
|
||||
case ResampleEngine::Sinc: resampler = new ResampleSinc (*this); return;
|
||||
}
|
||||
|
||||
throw;
|
||||
}
|
||||
|
||||
void DSP::setResamplerFrequency(real frequency) {
|
||||
auto DSP::setResamplerFrequency(double frequency) -> void {
|
||||
resampler->frequency = frequency;
|
||||
resampler->setFrequency();
|
||||
}
|
||||
|
|
|
@ -7,7 +7,7 @@ namespace Processor {
|
|||
#include "instructions.cpp"
|
||||
#include "serialization.cpp"
|
||||
|
||||
void HG51B::exec(uint24 addr) {
|
||||
auto HG51B::exec(uint24 addr) -> void {
|
||||
if(regs.halt) return;
|
||||
addr = addr + regs.pc * 2;
|
||||
opcode = bus_read(addr++) << 0;
|
||||
|
@ -16,7 +16,7 @@ void HG51B::exec(uint24 addr) {
|
|||
instruction();
|
||||
}
|
||||
|
||||
void HG51B::power() {
|
||||
auto HG51B::power() -> void {
|
||||
regs.halt = true;
|
||||
|
||||
regs.n = 0;
|
||||
|
|
|
@ -1,29 +1,56 @@
|
|||
//Hitachi HG51B169 (HG51BS family/derivative?)
|
||||
|
||||
#ifndef PROCESSOR_HG51B_HPP
|
||||
#define PROCESSOR_HG51B_HPP
|
||||
|
||||
namespace Processor {
|
||||
|
||||
//Hitachi HG51B169 (HG51BS family/derivative?)
|
||||
|
||||
struct HG51B {
|
||||
auto exec(uint24 addr) -> void;
|
||||
virtual auto bus_read(uint24 addr) -> uint8 = 0;
|
||||
virtual auto bus_write(uint24 addr, uint8 data) -> void = 0;
|
||||
|
||||
auto power() -> void;
|
||||
auto serialize(serializer&) -> void;
|
||||
|
||||
//uint16 programROM[2][256];
|
||||
uint24 dataROM[1024];
|
||||
uint8 dataRAM[3072];
|
||||
#include "registers.hpp"
|
||||
void exec(uint24 addr);
|
||||
virtual uint8 bus_read(uint24 addr) = 0;
|
||||
virtual void bus_write(uint24 addr, uint8 data) = 0;
|
||||
|
||||
void power();
|
||||
void serialize(serializer&);
|
||||
|
||||
protected:
|
||||
void push();
|
||||
void pull();
|
||||
unsigned sa();
|
||||
unsigned ri();
|
||||
unsigned np();
|
||||
void instruction();
|
||||
auto push() -> void;
|
||||
auto pull() -> void;
|
||||
auto sa() -> uint;
|
||||
auto ri() -> uint;
|
||||
auto np() -> uint;
|
||||
auto instruction() -> void;
|
||||
|
||||
//registers.cpp
|
||||
auto reg_read(uint8 addr) const -> uint24;
|
||||
auto reg_write(uint8 addr, uint24 data) -> void;
|
||||
|
||||
struct Registers {
|
||||
bool halt;
|
||||
|
||||
uint24 pc;
|
||||
uint16 p;
|
||||
bool n;
|
||||
bool z;
|
||||
bool c;
|
||||
|
||||
uint24 a;
|
||||
uint24 acch;
|
||||
uint24 accl;
|
||||
uint24 busdata;
|
||||
uint24 romdata;
|
||||
uint24 ramdata;
|
||||
uint24 busaddr;
|
||||
uint24 ramaddr;
|
||||
uint24 gpr[16];
|
||||
} regs;
|
||||
|
||||
uint24 stack[8];
|
||||
uint16 opcode;
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
#ifdef PROCESSOR_HG51B_HPP
|
||||
|
||||
void HG51B::push() {
|
||||
auto HG51B::push() -> void {
|
||||
stack[7] = stack[6];
|
||||
stack[6] = stack[5];
|
||||
stack[5] = stack[4];
|
||||
|
@ -11,7 +11,7 @@ void HG51B::push() {
|
|||
stack[0] = regs.pc;
|
||||
}
|
||||
|
||||
void HG51B::pull() {
|
||||
auto HG51B::pull() -> void {
|
||||
regs.pc = stack[0];
|
||||
stack[0] = stack[1];
|
||||
stack[1] = stack[2];
|
||||
|
@ -24,7 +24,7 @@ void HG51B::pull() {
|
|||
}
|
||||
|
||||
//Shift-A: math opcodes can shift A register prior to ALU operation
|
||||
unsigned HG51B::sa() {
|
||||
auto HG51B::sa() -> uint {
|
||||
switch(opcode & 0x0300) { default:
|
||||
case 0x0000: return regs.a << 0;
|
||||
case 0x0100: return regs.a << 1;
|
||||
|
@ -34,18 +34,18 @@ unsigned HG51B::sa() {
|
|||
}
|
||||
|
||||
//Register-or-Immediate: most opcodes can load from a register or immediate
|
||||
unsigned HG51B::ri() {
|
||||
auto HG51B::ri() -> uint {
|
||||
if(opcode & 0x0400) return opcode & 0xff;
|
||||
return reg_read(opcode & 0xff);
|
||||
}
|
||||
|
||||
//New-PC: determine jump target address; opcode.d9 = long jump flag (1 = yes)
|
||||
unsigned HG51B::np() {
|
||||
auto HG51B::np() -> uint {
|
||||
if(opcode & 0x0200) return (regs.p << 8) | (opcode & 0xff);
|
||||
return (regs.pc & 0xffff00) | (opcode & 0xff);
|
||||
}
|
||||
|
||||
void HG51B::instruction() {
|
||||
auto HG51B::instruction() -> void {
|
||||
if((opcode & 0xffff) == 0x0000) {
|
||||
//0000 0000 0000 0000
|
||||
//nop
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
#ifdef PROCESSOR_HG51B_HPP
|
||||
|
||||
uint24 HG51B::reg_read(uint8 addr) const {
|
||||
auto HG51B::reg_read(uint8 addr) const -> uint24 {
|
||||
switch(addr) {
|
||||
case 0x00: return regs.a;
|
||||
case 0x01: return regs.acch;
|
||||
|
@ -46,7 +46,7 @@ uint24 HG51B::reg_read(uint8 addr) const {
|
|||
return 0x000000;
|
||||
}
|
||||
|
||||
void HG51B::reg_write(uint8 addr, uint24 data) {
|
||||
auto HG51B::reg_write(uint8 addr, uint24 data) -> void {
|
||||
switch(addr) {
|
||||
case 0x00: regs.a = data; return;
|
||||
case 0x01: regs.acch = data; return;
|
||||
|
|
|
@ -1,25 +0,0 @@
|
|||
struct Registers {
|
||||
bool halt;
|
||||
|
||||
uint24 pc;
|
||||
uint16 p;
|
||||
bool n;
|
||||
bool z;
|
||||
bool c;
|
||||
|
||||
uint24 a;
|
||||
uint24 acch;
|
||||
uint24 accl;
|
||||
uint24 busdata;
|
||||
uint24 romdata;
|
||||
uint24 ramdata;
|
||||
uint24 busaddr;
|
||||
uint24 ramaddr;
|
||||
uint24 gpr[16];
|
||||
} regs;
|
||||
|
||||
uint24 stack[8];
|
||||
uint16 opcode;
|
||||
|
||||
uint24 reg_read(uint8 addr) const;
|
||||
void reg_write(uint8 addr, uint24 data);
|
|
@ -1,6 +1,6 @@
|
|||
#ifdef PROCESSOR_HG51B_HPP
|
||||
|
||||
void HG51B::serialize(serializer& s) {
|
||||
auto HG51B::serialize(serializer& s) -> void {
|
||||
s.array(dataRAM);
|
||||
for(auto& n : stack) s.integer(n);
|
||||
s.integer(opcode);
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
string LR35902::disassemble(uint16 pc) {
|
||||
auto LR35902::disassemble(uint16 pc) -> string {
|
||||
char output[80];
|
||||
memset(output, ' ', sizeof output);
|
||||
output[79] = 0;
|
||||
|
||||
string opcode = disassemble_opcode(pc);
|
||||
string opcode = disassembleOpcode(pc);
|
||||
string registers = {
|
||||
" AF:", hex(r[AF], 4L),
|
||||
" BC:", hex(r[BC], 4L),
|
||||
|
@ -19,7 +19,7 @@ string LR35902::disassemble(uint16 pc) {
|
|||
return output;
|
||||
}
|
||||
|
||||
string LR35902::disassemble_opcode(uint16 pc) {
|
||||
auto LR35902::disassembleOpcode(uint16 pc) -> string {
|
||||
uint8 opcode = debugger_read(pc);
|
||||
uint8 p0 = debugger_read(pc + 1);
|
||||
uint8 p1 = debugger_read(pc + 2);
|
||||
|
@ -229,7 +229,7 @@ string LR35902::disassemble_opcode(uint16 pc) {
|
|||
case 0xc8: return { "ret z" };
|
||||
case 0xc9: return { "ret" };
|
||||
case 0xca: return { "jp z,$", hex(p1, 2L), hex(p0, 2L) };
|
||||
case 0xcb: return disassemble_opcode_cb(pc + 1);
|
||||
case 0xcb: return disassembleOpcodeCB(pc + 1);
|
||||
case 0xcc: return { "call z,$", hex(p1, 2L), hex(p0, 2L) };
|
||||
case 0xcd: return { "call $", hex(p1, 2L), hex(p0, 2L) };
|
||||
case 0xce: return { "adc a,$", hex(p0, 2L) };
|
||||
|
@ -287,7 +287,7 @@ string LR35902::disassemble_opcode(uint16 pc) {
|
|||
return "";
|
||||
}
|
||||
|
||||
string LR35902::disassemble_opcode_cb(uint16 pc) {
|
||||
auto LR35902::disassembleOpcodeCB(uint16 pc) -> string {
|
||||
uint8 opcode = debugger_read(pc);
|
||||
uint8 p0 = debugger_read(pc + 1);
|
||||
uint8 p1 = debugger_read(pc + 2);
|
||||
|
|
|
@ -1,121 +1,121 @@
|
|||
void LR35902::op_xx() {
|
||||
auto LR35902::op_xx() {
|
||||
}
|
||||
|
||||
void LR35902::op_cb() {
|
||||
exec_cb();
|
||||
auto LR35902::op_cb() {
|
||||
execCB();
|
||||
}
|
||||
|
||||
//8-bit load commands
|
||||
|
||||
template<unsigned x, unsigned y> void LR35902::op_ld_r_r() {
|
||||
template<uint x, uint y> auto LR35902::op_ld_r_r() {
|
||||
r[x] = r[y];
|
||||
}
|
||||
|
||||
template<unsigned x> void LR35902::op_ld_r_n() {
|
||||
template<uint x> auto LR35902::op_ld_r_n() {
|
||||
r[x] = op_read(r[PC]++);
|
||||
}
|
||||
|
||||
template<unsigned x> void LR35902::op_ld_r_hl() {
|
||||
template<uint x> auto LR35902::op_ld_r_hl() {
|
||||
r[x] = op_read(r[HL]);
|
||||
}
|
||||
|
||||
template<unsigned x> void LR35902::op_ld_hl_r() {
|
||||
template<uint x> auto LR35902::op_ld_hl_r() {
|
||||
op_write(r[HL], r[x]);
|
||||
}
|
||||
|
||||
void LR35902::op_ld_hl_n() {
|
||||
auto LR35902::op_ld_hl_n() {
|
||||
op_write(r[HL], op_read(r[PC]++));
|
||||
}
|
||||
|
||||
template<unsigned x> void LR35902::op_ld_a_rr() {
|
||||
template<uint x> auto LR35902::op_ld_a_rr() {
|
||||
r[A] = op_read(r[x]);
|
||||
}
|
||||
|
||||
void LR35902::op_ld_a_nn() {
|
||||
auto LR35902::op_ld_a_nn() {
|
||||
uint8 lo = op_read(r[PC]++);
|
||||
uint8 hi = op_read(r[PC]++);
|
||||
r[A] = op_read((hi << 8) | (lo << 0));
|
||||
}
|
||||
|
||||
template<unsigned x> void LR35902::op_ld_rr_a() {
|
||||
template<uint x> auto LR35902::op_ld_rr_a() {
|
||||
op_write(r[x], r[A]);
|
||||
}
|
||||
|
||||
void LR35902::op_ld_nn_a() {
|
||||
auto LR35902::op_ld_nn_a() {
|
||||
uint8 lo = op_read(r[PC]++);
|
||||
uint8 hi = op_read(r[PC]++);
|
||||
op_write((hi << 8) | (lo << 0), r[A]);
|
||||
}
|
||||
|
||||
void LR35902::op_ld_a_ffn() {
|
||||
auto LR35902::op_ld_a_ffn() {
|
||||
r[A] = op_read(0xff00 + op_read(r[PC]++));
|
||||
}
|
||||
|
||||
void LR35902::op_ld_ffn_a() {
|
||||
auto LR35902::op_ld_ffn_a() {
|
||||
op_write(0xff00 + op_read(r[PC]++), r[A]);
|
||||
}
|
||||
|
||||
void LR35902::op_ld_a_ffc() {
|
||||
auto LR35902::op_ld_a_ffc() {
|
||||
r[A] = op_read(0xff00 + r[C]);
|
||||
}
|
||||
|
||||
void LR35902::op_ld_ffc_a() {
|
||||
auto LR35902::op_ld_ffc_a() {
|
||||
op_write(0xff00 + r[C], r[A]);
|
||||
}
|
||||
|
||||
void LR35902::op_ldi_hl_a() {
|
||||
auto LR35902::op_ldi_hl_a() {
|
||||
op_write(r[HL], r[A]);
|
||||
r[HL]++;
|
||||
}
|
||||
|
||||
void LR35902::op_ldi_a_hl() {
|
||||
auto LR35902::op_ldi_a_hl() {
|
||||
r[A] = op_read(r[HL]);
|
||||
r[HL]++;
|
||||
}
|
||||
|
||||
void LR35902::op_ldd_hl_a() {
|
||||
auto LR35902::op_ldd_hl_a() {
|
||||
op_write(r[HL], r[A]);
|
||||
r[HL]--;
|
||||
}
|
||||
|
||||
void LR35902::op_ldd_a_hl() {
|
||||
auto LR35902::op_ldd_a_hl() {
|
||||
r[A] = op_read(r[HL]);
|
||||
r[HL]--;
|
||||
}
|
||||
|
||||
//16-bit load commands
|
||||
|
||||
template<unsigned x> void LR35902::op_ld_rr_nn() {
|
||||
template<uint x> auto LR35902::op_ld_rr_nn() {
|
||||
r[x] = op_read(r[PC]++) << 0;
|
||||
r[x] |= op_read(r[PC]++) << 8;
|
||||
}
|
||||
|
||||
void LR35902::op_ld_nn_sp() {
|
||||
auto LR35902::op_ld_nn_sp() {
|
||||
uint16 addr = op_read(r[PC]++) << 0;
|
||||
addr |= op_read(r[PC]++) << 8;
|
||||
op_write(addr + 0, r[SP] >> 0);
|
||||
op_write(addr + 1, r[SP] >> 8);
|
||||
}
|
||||
|
||||
void LR35902::op_ld_sp_hl() {
|
||||
auto LR35902::op_ld_sp_hl() {
|
||||
r[SP] = r[HL];
|
||||
op_io();
|
||||
}
|
||||
|
||||
template<unsigned x> void LR35902::op_push_rr() {
|
||||
template<uint x> auto LR35902::op_push_rr() {
|
||||
op_write(--r[SP], r[x] >> 8);
|
||||
op_write(--r[SP], r[x] >> 0);
|
||||
op_io();
|
||||
}
|
||||
|
||||
template<unsigned x> void LR35902::op_pop_rr() {
|
||||
template<uint x> auto LR35902::op_pop_rr() {
|
||||
r[x] = op_read(r[SP]++) << 0;
|
||||
r[x] |= op_read(r[SP]++) << 8;
|
||||
}
|
||||
|
||||
//8-bit arithmetic commands
|
||||
|
||||
void LR35902::opi_add_a(uint8 x) {
|
||||
auto LR35902::opi_add_a(uint8 x) {
|
||||
uint16 rh = r[A] + x;
|
||||
uint16 rl = (r[A] & 0x0f) + (x & 0x0f);
|
||||
r[A] = rh;
|
||||
|
@ -125,11 +125,11 @@ void LR35902::opi_add_a(uint8 x) {
|
|||
r.f.c = rh > 0xff;
|
||||
}
|
||||
|
||||
template<unsigned x> void LR35902::op_add_a_r() { opi_add_a(r[x]); }
|
||||
void LR35902::op_add_a_n() { opi_add_a(op_read(r[PC]++)); }
|
||||
void LR35902::op_add_a_hl() { opi_add_a(op_read(r[HL])); }
|
||||
template<uint x> auto LR35902::op_add_a_r() { opi_add_a(r[x]); }
|
||||
auto LR35902::op_add_a_n() { opi_add_a(op_read(r[PC]++)); }
|
||||
auto LR35902::op_add_a_hl() { opi_add_a(op_read(r[HL])); }
|
||||
|
||||
void LR35902::opi_adc_a(uint8 x) {
|
||||
auto LR35902::opi_adc_a(uint8 x) {
|
||||
uint16 rh = r[A] + x + r.f.c;
|
||||
uint16 rl = (r[A] & 0x0f) + (x & 0x0f) + r.f.c;
|
||||
r[A] = rh;
|
||||
|
@ -139,11 +139,11 @@ void LR35902::opi_adc_a(uint8 x) {
|
|||
r.f.c = rh > 0xff;
|
||||
}
|
||||
|
||||
template<unsigned x> void LR35902::op_adc_a_r() { opi_adc_a(r[x]); }
|
||||
void LR35902::op_adc_a_n() { opi_adc_a(op_read(r[PC]++)); }
|
||||
void LR35902::op_adc_a_hl() { opi_adc_a(op_read(r[HL])); }
|
||||
template<uint x> auto LR35902::op_adc_a_r() { opi_adc_a(r[x]); }
|
||||
auto LR35902::op_adc_a_n() { opi_adc_a(op_read(r[PC]++)); }
|
||||
auto LR35902::op_adc_a_hl() { opi_adc_a(op_read(r[HL])); }
|
||||
|
||||
void LR35902::opi_sub_a(uint8 x) {
|
||||
auto LR35902::opi_sub_a(uint8 x) {
|
||||
uint16 rh = r[A] - x;
|
||||
uint16 rl = (r[A] & 0x0f) - (x & 0x0f);
|
||||
r[A] = rh;
|
||||
|
@ -153,11 +153,11 @@ void LR35902::opi_sub_a(uint8 x) {
|
|||
r.f.c = rh > 0xff;
|
||||
}
|
||||
|
||||
template<unsigned x> void LR35902::op_sub_a_r() { opi_sub_a(r[x]); }
|
||||
void LR35902::op_sub_a_n() { opi_sub_a(op_read(r[PC]++)); }
|
||||
void LR35902::op_sub_a_hl() { opi_sub_a(op_read(r[HL])); }
|
||||
template<uint x> auto LR35902::op_sub_a_r() { opi_sub_a(r[x]); }
|
||||
auto LR35902::op_sub_a_n() { opi_sub_a(op_read(r[PC]++)); }
|
||||
auto LR35902::op_sub_a_hl() { opi_sub_a(op_read(r[HL])); }
|
||||
|
||||
void LR35902::opi_sbc_a(uint8 x) {
|
||||
auto LR35902::opi_sbc_a(uint8 x) {
|
||||
uint16 rh = r[A] - x - r.f.c;
|
||||
uint16 rl = (r[A] & 0x0f) - (x & 0x0f) - r.f.c;
|
||||
r[A] = rh;
|
||||
|
@ -167,11 +167,11 @@ void LR35902::opi_sbc_a(uint8 x) {
|
|||
r.f.c = rh > 0xff;
|
||||
}
|
||||
|
||||
template<unsigned x> void LR35902::op_sbc_a_r() { opi_sbc_a(r[x]); }
|
||||
void LR35902::op_sbc_a_n() { opi_sbc_a(op_read(r[PC]++)); }
|
||||
void LR35902::op_sbc_a_hl() { opi_sbc_a(op_read(r[HL])); }
|
||||
template<uint x> auto LR35902::op_sbc_a_r() { opi_sbc_a(r[x]); }
|
||||
auto LR35902::op_sbc_a_n() { opi_sbc_a(op_read(r[PC]++)); }
|
||||
auto LR35902::op_sbc_a_hl() { opi_sbc_a(op_read(r[HL])); }
|
||||
|
||||
void LR35902::opi_and_a(uint8 x) {
|
||||
auto LR35902::opi_and_a(uint8 x) {
|
||||
r[A] &= x;
|
||||
r.f.z = r[A] == 0;
|
||||
r.f.n = 0;
|
||||
|
@ -179,11 +179,11 @@ void LR35902::opi_and_a(uint8 x) {
|
|||
r.f.c = 0;
|
||||
}
|
||||
|
||||
template<unsigned x> void LR35902::op_and_a_r() { opi_and_a(r[x]); }
|
||||
void LR35902::op_and_a_n() { opi_and_a(op_read(r[PC]++)); }
|
||||
void LR35902::op_and_a_hl() { opi_and_a(op_read(r[HL])); }
|
||||
template<uint x> auto LR35902::op_and_a_r() { opi_and_a(r[x]); }
|
||||
auto LR35902::op_and_a_n() { opi_and_a(op_read(r[PC]++)); }
|
||||
auto LR35902::op_and_a_hl() { opi_and_a(op_read(r[HL])); }
|
||||
|
||||
void LR35902::opi_xor_a(uint8 x) {
|
||||
auto LR35902::opi_xor_a(uint8 x) {
|
||||
r[A] ^= x;
|
||||
r.f.z = r[A] == 0;
|
||||
r.f.n = 0;
|
||||
|
@ -191,11 +191,11 @@ void LR35902::opi_xor_a(uint8 x) {
|
|||
r.f.c = 0;
|
||||
}
|
||||
|
||||
template<unsigned x> void LR35902::op_xor_a_r() { opi_xor_a(r[x]); }
|
||||
void LR35902::op_xor_a_n() { opi_xor_a(op_read(r[PC]++)); }
|
||||
void LR35902::op_xor_a_hl() { opi_xor_a(op_read(r[HL])); }
|
||||
template<uint x> auto LR35902::op_xor_a_r() { opi_xor_a(r[x]); }
|
||||
auto LR35902::op_xor_a_n() { opi_xor_a(op_read(r[PC]++)); }
|
||||
auto LR35902::op_xor_a_hl() { opi_xor_a(op_read(r[HL])); }
|
||||
|
||||
void LR35902::opi_or_a(uint8 x) {
|
||||
auto LR35902::opi_or_a(uint8 x) {
|
||||
r[A] |= x;
|
||||
r.f.z = r[A] == 0;
|
||||
r.f.n = 0;
|
||||
|
@ -203,11 +203,11 @@ void LR35902::opi_or_a(uint8 x) {
|
|||
r.f.c = 0;
|
||||
}
|
||||
|
||||
template<unsigned x> void LR35902::op_or_a_r() { opi_or_a(r[x]); }
|
||||
void LR35902::op_or_a_n() { opi_or_a(op_read(r[PC]++)); }
|
||||
void LR35902::op_or_a_hl() { opi_or_a(op_read(r[HL])); }
|
||||
template<uint x> auto LR35902::op_or_a_r() { opi_or_a(r[x]); }
|
||||
auto LR35902::op_or_a_n() { opi_or_a(op_read(r[PC]++)); }
|
||||
auto LR35902::op_or_a_hl() { opi_or_a(op_read(r[HL])); }
|
||||
|
||||
void LR35902::opi_cp_a(uint8 x) {
|
||||
auto LR35902::opi_cp_a(uint8 x) {
|
||||
uint16 rh = r[A] - x;
|
||||
uint16 rl = (r[A] & 0x0f) - (x & 0x0f);
|
||||
r.f.z = (uint8)rh == 0;
|
||||
|
@ -216,18 +216,18 @@ void LR35902::opi_cp_a(uint8 x) {
|
|||
r.f.c = rh > 0xff;
|
||||
}
|
||||
|
||||
template<unsigned x> void LR35902::op_cp_a_r() { opi_cp_a(r[x]); }
|
||||
void LR35902::op_cp_a_n() { opi_cp_a(op_read(r[PC]++)); }
|
||||
void LR35902::op_cp_a_hl() { opi_cp_a(op_read(r[HL])); }
|
||||
template<uint x> auto LR35902::op_cp_a_r() { opi_cp_a(r[x]); }
|
||||
auto LR35902::op_cp_a_n() { opi_cp_a(op_read(r[PC]++)); }
|
||||
auto LR35902::op_cp_a_hl() { opi_cp_a(op_read(r[HL])); }
|
||||
|
||||
template<unsigned x> void LR35902::op_inc_r() {
|
||||
template<uint x> auto LR35902::op_inc_r() {
|
||||
r[x]++;
|
||||
r.f.z = r[x] == 0;
|
||||
r.f.n = 0;
|
||||
r.f.h = (r[x] & 0x0f) == 0x00;
|
||||
}
|
||||
|
||||
void LR35902::op_inc_hl() {
|
||||
auto LR35902::op_inc_hl() {
|
||||
uint8 n = op_read(r[HL]);
|
||||
op_write(r[HL], ++n);
|
||||
r.f.z = n == 0;
|
||||
|
@ -235,14 +235,14 @@ void LR35902::op_inc_hl() {
|
|||
r.f.h = (n & 0x0f) == 0x00;
|
||||
}
|
||||
|
||||
template<unsigned x> void LR35902::op_dec_r() {
|
||||
template<uint x> auto LR35902::op_dec_r() {
|
||||
r[x]--;
|
||||
r.f.z = r[x] == 0;
|
||||
r.f.n = 1;
|
||||
r.f.h = (r[x] & 0x0f) == 0x0f;
|
||||
}
|
||||
|
||||
void LR35902::op_dec_hl() {
|
||||
auto LR35902::op_dec_hl() {
|
||||
uint8 n = op_read(r[HL]);
|
||||
op_write(r[HL], --n);
|
||||
r.f.z = n == 0;
|
||||
|
@ -250,7 +250,7 @@ void LR35902::op_dec_hl() {
|
|||
r.f.h = (n & 0x0f) == 0x0f;
|
||||
}
|
||||
|
||||
void LR35902::op_daa() {
|
||||
auto LR35902::op_daa() {
|
||||
uint16 a = r[A];
|
||||
if(r.f.n == 0) {
|
||||
if(r.f.h || (a & 0x0f) > 0x09) a += 0x06;
|
||||
|
@ -268,7 +268,7 @@ void LR35902::op_daa() {
|
|||
r.f.c |= a & 0x100;
|
||||
}
|
||||
|
||||
void LR35902::op_cpl() {
|
||||
auto LR35902::op_cpl() {
|
||||
r[A] ^= 0xff;
|
||||
r.f.n = 1;
|
||||
r.f.h = 1;
|
||||
|
@ -276,7 +276,7 @@ void LR35902::op_cpl() {
|
|||
|
||||
//16-bit arithmetic commands
|
||||
|
||||
template<unsigned x> void LR35902::op_add_hl_rr() {
|
||||
template<uint x> auto LR35902::op_add_hl_rr() {
|
||||
op_io();
|
||||
uint32 rb = (r[HL] + r[x]);
|
||||
uint32 rn = (r[HL] & 0xfff) + (r[x] & 0xfff);
|
||||
|
@ -286,20 +286,20 @@ template<unsigned x> void LR35902::op_add_hl_rr() {
|
|||
r.f.c = rb > 0xffff;
|
||||
}
|
||||
|
||||
template<unsigned x> void LR35902::op_inc_rr() {
|
||||
template<uint x> auto LR35902::op_inc_rr() {
|
||||
op_io();
|
||||
r[x]++;
|
||||
}
|
||||
|
||||
template<unsigned x> void LR35902::op_dec_rr() {
|
||||
template<uint x> auto LR35902::op_dec_rr() {
|
||||
op_io();
|
||||
r[x]--;
|
||||
}
|
||||
|
||||
void LR35902::op_add_sp_n() {
|
||||
auto LR35902::op_add_sp_n() {
|
||||
op_io();
|
||||
op_io();
|
||||
signed n = (int8)op_read(r[PC]++);
|
||||
int n = (int8)op_read(r[PC]++);
|
||||
r.f.z = 0;
|
||||
r.f.n = 0;
|
||||
r.f.h = ((r[SP] & 0x0f) + (n & 0x0f)) > 0x0f;
|
||||
|
@ -307,9 +307,9 @@ void LR35902::op_add_sp_n() {
|
|||
r[SP] += n;
|
||||
}
|
||||
|
||||
void LR35902::op_ld_hl_sp_n() {
|
||||
auto LR35902::op_ld_hl_sp_n() {
|
||||
op_io();
|
||||
signed n = (int8)op_read(r[PC]++);
|
||||
int n = (int8)op_read(r[PC]++);
|
||||
r.f.z = 0;
|
||||
r.f.n = 0;
|
||||
r.f.h = ((r[SP] & 0x0f) + (n & 0x0f)) > 0x0f;
|
||||
|
@ -319,7 +319,7 @@ void LR35902::op_ld_hl_sp_n() {
|
|||
|
||||
//rotate/shift commands
|
||||
|
||||
void LR35902::op_rlca() {
|
||||
auto LR35902::op_rlca() {
|
||||
r[A] = (r[A] << 1) | (r[A] >> 7);
|
||||
r.f.z = 0;
|
||||
r.f.n = 0;
|
||||
|
@ -327,7 +327,7 @@ void LR35902::op_rlca() {
|
|||
r.f.c = r[A] & 0x01;
|
||||
}
|
||||
|
||||
void LR35902::op_rla() {
|
||||
auto LR35902::op_rla() {
|
||||
bool c = r[A] & 0x80;
|
||||
r[A] = (r[A] << 1) | (r.f.c << 0);
|
||||
r.f.z = 0;
|
||||
|
@ -336,7 +336,7 @@ void LR35902::op_rla() {
|
|||
r.f.c = c;
|
||||
}
|
||||
|
||||
void LR35902::op_rrca() {
|
||||
auto LR35902::op_rrca() {
|
||||
r[A] = (r[A] >> 1) | (r[A] << 7);
|
||||
r.f.z = 0;
|
||||
r.f.n = 0;
|
||||
|
@ -344,7 +344,7 @@ void LR35902::op_rrca() {
|
|||
r.f.c = r[A] & 0x80;
|
||||
}
|
||||
|
||||
void LR35902::op_rra() {
|
||||
auto LR35902::op_rra() {
|
||||
bool c = r[A] & 0x01;
|
||||
r[A] = (r[A] >> 1) | (r.f.c << 7);
|
||||
r.f.z = 0;
|
||||
|
@ -353,7 +353,7 @@ void LR35902::op_rra() {
|
|||
r.f.c = c;
|
||||
}
|
||||
|
||||
template<unsigned x> void LR35902::op_rlc_r() {
|
||||
template<uint x> auto LR35902::op_rlc_r() {
|
||||
r[x] = (r[x] << 1) | (r[x] >> 7);
|
||||
r.f.z = r[x] == 0;
|
||||
r.f.n = 0;
|
||||
|
@ -361,7 +361,7 @@ template<unsigned x> void LR35902::op_rlc_r() {
|
|||
r.f.c = r[x] & 0x01;
|
||||
}
|
||||
|
||||
void LR35902::op_rlc_hl() {
|
||||
auto LR35902::op_rlc_hl() {
|
||||
uint8 n = op_read(r[HL]);
|
||||
n = (n << 1) | (n >> 7);
|
||||
op_write(r[HL], n);
|
||||
|
@ -371,7 +371,7 @@ void LR35902::op_rlc_hl() {
|
|||
r.f.c = n & 0x01;
|
||||
}
|
||||
|
||||
template<unsigned x> void LR35902::op_rl_r() {
|
||||
template<uint x> auto LR35902::op_rl_r() {
|
||||
bool c = r[x] & 0x80;
|
||||
r[x] = (r[x] << 1) | (r.f.c << 0);
|
||||
r.f.z = r[x] == 0;
|
||||
|
@ -380,7 +380,7 @@ template<unsigned x> void LR35902::op_rl_r() {
|
|||
r.f.c = c;
|
||||
}
|
||||
|
||||
void LR35902::op_rl_hl() {
|
||||
auto LR35902::op_rl_hl() {
|
||||
uint8 n = op_read(r[HL]);
|
||||
bool c = n & 0x80;
|
||||
n = (n << 1) | (r.f.c << 0);
|
||||
|
@ -391,7 +391,7 @@ void LR35902::op_rl_hl() {
|
|||
r.f.c = c;
|
||||
}
|
||||
|
||||
template<unsigned x> void LR35902::op_rrc_r() {
|
||||
template<uint x> auto LR35902::op_rrc_r() {
|
||||
r[x] = (r[x] >> 1) | (r[x] << 7);
|
||||
r.f.z = r[x] == 0;
|
||||
r.f.n = 0;
|
||||
|
@ -399,7 +399,7 @@ template<unsigned x> void LR35902::op_rrc_r() {
|
|||
r.f.c = r[x] & 0x80;
|
||||
}
|
||||
|
||||
void LR35902::op_rrc_hl() {
|
||||
auto LR35902::op_rrc_hl() {
|
||||
uint8 n = op_read(r[HL]);
|
||||
n = (n >> 1) | (n << 7);
|
||||
op_write(r[HL], n);
|
||||
|
@ -409,7 +409,7 @@ void LR35902::op_rrc_hl() {
|
|||
r.f.c = n & 0x80;
|
||||
}
|
||||
|
||||
template<unsigned x> void LR35902::op_rr_r() {
|
||||
template<uint x> auto LR35902::op_rr_r() {
|
||||
bool c = r[x] & 0x01;
|
||||
r[x] = (r[x] >> 1) | (r.f.c << 7);
|
||||
r.f.z = r[x] == 0;
|
||||
|
@ -418,7 +418,7 @@ template<unsigned x> void LR35902::op_rr_r() {
|
|||
r.f.c = c;
|
||||
}
|
||||
|
||||
void LR35902::op_rr_hl() {
|
||||
auto LR35902::op_rr_hl() {
|
||||
uint8 n = op_read(r[HL]);
|
||||
bool c = n & 0x01;
|
||||
n = (n >> 1) | (r.f.c << 7);
|
||||
|
@ -429,7 +429,7 @@ void LR35902::op_rr_hl() {
|
|||
r.f.c = c;
|
||||
}
|
||||
|
||||
template<unsigned x> void LR35902::op_sla_r() {
|
||||
template<uint x> auto LR35902::op_sla_r() {
|
||||
bool c = r[x] & 0x80;
|
||||
r[x] <<= 1;
|
||||
r.f.z = r[x] == 0;
|
||||
|
@ -438,7 +438,7 @@ template<unsigned x> void LR35902::op_sla_r() {
|
|||
r.f.c = c;
|
||||
}
|
||||
|
||||
void LR35902::op_sla_hl() {
|
||||
auto LR35902::op_sla_hl() {
|
||||
uint8 n = op_read(r[HL]);
|
||||
bool c = n & 0x80;
|
||||
n <<= 1;
|
||||
|
@ -449,7 +449,7 @@ void LR35902::op_sla_hl() {
|
|||
r.f.c = c;
|
||||
}
|
||||
|
||||
template<unsigned x> void LR35902::op_swap_r() {
|
||||
template<uint x> auto LR35902::op_swap_r() {
|
||||
r[x] = (r[x] << 4) | (r[x] >> 4);
|
||||
r.f.z = r[x] == 0;
|
||||
r.f.n = 0;
|
||||
|
@ -457,7 +457,7 @@ template<unsigned x> void LR35902::op_swap_r() {
|
|||
r.f.c = 0;
|
||||
}
|
||||
|
||||
void LR35902::op_swap_hl() {
|
||||
auto LR35902::op_swap_hl() {
|
||||
uint8 n = op_read(r[HL]);
|
||||
n = (n << 4) | (n >> 4);
|
||||
op_write(r[HL], n);
|
||||
|
@ -467,7 +467,7 @@ void LR35902::op_swap_hl() {
|
|||
r.f.c = 0;
|
||||
}
|
||||
|
||||
template<unsigned x> void LR35902::op_sra_r() {
|
||||
template<uint x> auto LR35902::op_sra_r() {
|
||||
bool c = r[x] & 0x01;
|
||||
r[x] = (int8)r[x] >> 1;
|
||||
r.f.z = r[x] == 0;
|
||||
|
@ -476,7 +476,7 @@ template<unsigned x> void LR35902::op_sra_r() {
|
|||
r.f.c = c;
|
||||
}
|
||||
|
||||
void LR35902::op_sra_hl() {
|
||||
auto LR35902::op_sra_hl() {
|
||||
uint8 n = op_read(r[HL]);
|
||||
bool c = n & 0x01;
|
||||
n = (int8)n >> 1;
|
||||
|
@ -487,7 +487,7 @@ void LR35902::op_sra_hl() {
|
|||
r.f.c = c;
|
||||
}
|
||||
|
||||
template<unsigned x> void LR35902::op_srl_r() {
|
||||
template<uint x> auto LR35902::op_srl_r() {
|
||||
bool c = r[x] & 0x01;
|
||||
r[x] >>= 1;
|
||||
r.f.z = r[x] == 0;
|
||||
|
@ -496,7 +496,7 @@ template<unsigned x> void LR35902::op_srl_r() {
|
|||
r.f.c = c;
|
||||
}
|
||||
|
||||
void LR35902::op_srl_hl() {
|
||||
auto LR35902::op_srl_hl() {
|
||||
uint8 n = op_read(r[HL]);
|
||||
bool c = n & 0x01;
|
||||
n >>= 1;
|
||||
|
@ -509,34 +509,34 @@ void LR35902::op_srl_hl() {
|
|||
|
||||
//single-bit commands
|
||||
|
||||
template<unsigned b, unsigned x> void LR35902::op_bit_n_r() {
|
||||
template<uint b, uint x> auto LR35902::op_bit_n_r() {
|
||||
r.f.z = (r[x] & (1 << b)) == 0;
|
||||
r.f.n = 0;
|
||||
r.f.h = 1;
|
||||
}
|
||||
|
||||
template<unsigned b> void LR35902::op_bit_n_hl() {
|
||||
template<uint b> auto LR35902::op_bit_n_hl() {
|
||||
uint8 n = op_read(r[HL]);
|
||||
r.f.z = (n & (1 << b)) == 0;
|
||||
r.f.n = 0;
|
||||
r.f.h = 1;
|
||||
}
|
||||
|
||||
template<unsigned b, unsigned x> void LR35902::op_set_n_r() {
|
||||
template<uint b, uint x> auto LR35902::op_set_n_r() {
|
||||
r[x] |= 1 << b;
|
||||
}
|
||||
|
||||
template<unsigned b> void LR35902::op_set_n_hl() {
|
||||
template<uint b> auto LR35902::op_set_n_hl() {
|
||||
uint8 n = op_read(r[HL]);
|
||||
n |= 1 << b;
|
||||
op_write(r[HL], n);
|
||||
}
|
||||
|
||||
template<unsigned b, unsigned x> void LR35902::op_res_n_r() {
|
||||
template<uint b, uint x> auto LR35902::op_res_n_r() {
|
||||
r[x] &= ~(1 << b);
|
||||
}
|
||||
|
||||
template<unsigned b> void LR35902::op_res_n_hl() {
|
||||
template<uint b> auto LR35902::op_res_n_hl() {
|
||||
uint8 n = op_read(r[HL]);
|
||||
n &= ~(1 << b);
|
||||
op_write(r[HL], n);
|
||||
|
@ -544,55 +544,55 @@ template<unsigned b> void LR35902::op_res_n_hl() {
|
|||
|
||||
//control commands
|
||||
|
||||
void LR35902::op_ccf() {
|
||||
auto LR35902::op_ccf() {
|
||||
r.f.n = 0;
|
||||
r.f.h = 0;
|
||||
r.f.c = !r.f.c;
|
||||
}
|
||||
|
||||
void LR35902::op_scf() {
|
||||
auto LR35902::op_scf() {
|
||||
r.f.n = 0;
|
||||
r.f.h = 0;
|
||||
r.f.c = 1;
|
||||
}
|
||||
|
||||
void LR35902::op_nop() {
|
||||
auto LR35902::op_nop() {
|
||||
}
|
||||
|
||||
void LR35902::op_halt() {
|
||||
auto LR35902::op_halt() {
|
||||
r.halt = true;
|
||||
while(r.halt == true) op_io();
|
||||
}
|
||||
|
||||
void LR35902::op_stop() {
|
||||
auto LR35902::op_stop() {
|
||||
if(stop()) return;
|
||||
r.stop = true;
|
||||
while(r.stop == true) op_io();
|
||||
}
|
||||
|
||||
void LR35902::op_di() {
|
||||
auto LR35902::op_di() {
|
||||
r.ime = 0;
|
||||
}
|
||||
|
||||
void LR35902::op_ei() {
|
||||
auto LR35902::op_ei() {
|
||||
r.ei = true;
|
||||
//r.ime = 1;
|
||||
}
|
||||
|
||||
//jump commands
|
||||
|
||||
void LR35902::op_jp_nn() {
|
||||
auto LR35902::op_jp_nn() {
|
||||
uint8 lo = op_read(r[PC]++);
|
||||
uint8 hi = op_read(r[PC]++);
|
||||
r[PC] = (hi << 8) | (lo << 0);
|
||||
op_io();
|
||||
}
|
||||
|
||||
void LR35902::op_jp_hl() {
|
||||
auto LR35902::op_jp_hl() {
|
||||
r[PC] = r[HL];
|
||||
}
|
||||
|
||||
template<unsigned x, bool y> void LR35902::op_jp_f_nn() {
|
||||
template<uint x, bool y> auto LR35902::op_jp_f_nn() {
|
||||
uint8 lo = op_read(r[PC]++);
|
||||
uint8 hi = op_read(r[PC]++);
|
||||
if(r.f[x] == y) {
|
||||
|
@ -601,13 +601,13 @@ template<unsigned x, bool y> void LR35902::op_jp_f_nn() {
|
|||
}
|
||||
}
|
||||
|
||||
void LR35902::op_jr_n() {
|
||||
auto LR35902::op_jr_n() {
|
||||
int8 n = op_read(r[PC]++);
|
||||
r[PC] += n;
|
||||
op_io();
|
||||
}
|
||||
|
||||
template<unsigned x, bool y> void LR35902::op_jr_f_n() {
|
||||
template<uint x, bool y> auto LR35902::op_jr_f_n() {
|
||||
int8 n = op_read(r[PC]++);
|
||||
if(r.f[x] == y) {
|
||||
r[PC] += n;
|
||||
|
@ -615,7 +615,7 @@ template<unsigned x, bool y> void LR35902::op_jr_f_n() {
|
|||
}
|
||||
}
|
||||
|
||||
void LR35902::op_call_nn() {
|
||||
auto LR35902::op_call_nn() {
|
||||
uint8 lo = op_read(r[PC]++);
|
||||
uint8 hi = op_read(r[PC]++);
|
||||
op_write(--r[SP], r[PC] >> 8);
|
||||
|
@ -624,7 +624,7 @@ void LR35902::op_call_nn() {
|
|||
op_io();
|
||||
}
|
||||
|
||||
template<unsigned x, bool y> void LR35902::op_call_f_nn() {
|
||||
template<uint x, bool y> auto LR35902::op_call_f_nn() {
|
||||
uint8 lo = op_read(r[PC]++);
|
||||
uint8 hi = op_read(r[PC]++);
|
||||
if(r.f[x] == y) {
|
||||
|
@ -635,14 +635,14 @@ template<unsigned x, bool y> void LR35902::op_call_f_nn() {
|
|||
}
|
||||
}
|
||||
|
||||
void LR35902::op_ret() {
|
||||
auto LR35902::op_ret() {
|
||||
uint8 lo = op_read(r[SP]++);
|
||||
uint8 hi = op_read(r[SP]++);
|
||||
r[PC] = (hi << 8) | (lo << 0);
|
||||
op_io();
|
||||
}
|
||||
|
||||
template<unsigned x, bool y> void LR35902::op_ret_f() {
|
||||
template<uint x, bool y> auto LR35902::op_ret_f() {
|
||||
op_io();
|
||||
if(r.f[x] == y) {
|
||||
uint8 lo = op_read(r[SP]++);
|
||||
|
@ -652,7 +652,7 @@ template<unsigned x, bool y> void LR35902::op_ret_f() {
|
|||
}
|
||||
}
|
||||
|
||||
void LR35902::op_reti() {
|
||||
auto LR35902::op_reti() {
|
||||
uint8 lo = op_read(r[SP]++);
|
||||
uint8 hi = op_read(r[SP]++);
|
||||
r[PC] = (hi << 8) | (lo << 0);
|
||||
|
@ -660,7 +660,7 @@ void LR35902::op_reti() {
|
|||
r.ime = 1;
|
||||
}
|
||||
|
||||
template<unsigned n> void LR35902::op_rst_n() {
|
||||
template<uint n> auto LR35902::op_rst_n() {
|
||||
op_write(--r[SP], r[PC] >> 8);
|
||||
op_write(--r[SP], r[PC] >> 0);
|
||||
r[PC] = n;
|
||||
|
|
|
@ -7,14 +7,14 @@ namespace Processor {
|
|||
#include "disassembler.cpp"
|
||||
#include "serialization.cpp"
|
||||
|
||||
void LR35902::power() {
|
||||
auto LR35902::power() -> void {
|
||||
r.halt = false;
|
||||
r.stop = false;
|
||||
r.ei = false;
|
||||
r.ime = false;
|
||||
}
|
||||
|
||||
void LR35902::exec() {
|
||||
auto LR35902::exec() -> void {
|
||||
uint8 opcode = op_read(r[PC]++);
|
||||
switch(opcode) {
|
||||
case 0x00: return op_nop();
|
||||
|
@ -276,7 +276,7 @@ void LR35902::exec() {
|
|||
}
|
||||
}
|
||||
|
||||
void LR35902::exec_cb() {
|
||||
auto LR35902::execCB() -> void {
|
||||
uint8 opcode = op_read(r[PC]++);
|
||||
switch(opcode) {
|
||||
case 0x00: return op_rlc_r<B>();
|
||||
|
|
|
@ -1,165 +1,166 @@
|
|||
//Sharp LR35902 (Game Boy Z80-derivative)
|
||||
|
||||
#ifndef PROCESSOR_LR35902_HPP
|
||||
#define PROCESSOR_LR35902_HPP
|
||||
|
||||
namespace Processor {
|
||||
|
||||
//Sharp LR35902 (Game Boy Z80-derivative)
|
||||
|
||||
struct LR35902 {
|
||||
virtual auto op_io() -> void = 0;
|
||||
virtual auto op_read(uint16 addr) -> uint8 = 0;
|
||||
virtual auto op_write(uint16 addr, uint8 data) -> void = 0;
|
||||
virtual auto stop() -> bool = 0;
|
||||
virtual auto debugger_read(uint16 addr) -> uint8 { return 0u; }
|
||||
|
||||
auto power() -> void;
|
||||
auto exec() -> void;
|
||||
auto execCB() -> void;
|
||||
|
||||
auto serialize(serializer&) -> void;
|
||||
|
||||
#include "registers.hpp"
|
||||
|
||||
virtual void op_io() = 0;
|
||||
virtual uint8 op_read(uint16 addr) = 0;
|
||||
virtual void op_write(uint16 addr, uint8 data) = 0;
|
||||
virtual bool stop() = 0;
|
||||
virtual uint8 debugger_read(uint16 addr) { return 0u; }
|
||||
|
||||
void power();
|
||||
void exec();
|
||||
void exec_cb();
|
||||
void serialize(serializer&);
|
||||
|
||||
privileged:
|
||||
void op_xx();
|
||||
void op_cb();
|
||||
auto op_xx();
|
||||
auto op_cb();
|
||||
|
||||
//8-bit load commands
|
||||
template<unsigned x, unsigned y> void op_ld_r_r();
|
||||
template<unsigned x> void op_ld_r_n();
|
||||
template<unsigned x> void op_ld_r_hl();
|
||||
template<unsigned x> void op_ld_hl_r();
|
||||
void op_ld_hl_n();
|
||||
template<unsigned x> void op_ld_a_rr();
|
||||
void op_ld_a_nn();
|
||||
template<unsigned x> void op_ld_rr_a();
|
||||
void op_ld_nn_a();
|
||||
void op_ld_a_ffn();
|
||||
void op_ld_ffn_a();
|
||||
void op_ld_a_ffc();
|
||||
void op_ld_ffc_a();
|
||||
void op_ldi_hl_a();
|
||||
void op_ldi_a_hl();
|
||||
void op_ldd_hl_a();
|
||||
void op_ldd_a_hl();
|
||||
template<uint x, uint y> auto op_ld_r_r();
|
||||
template<uint x> auto op_ld_r_n();
|
||||
template<uint x> auto op_ld_r_hl();
|
||||
template<uint x> auto op_ld_hl_r();
|
||||
auto op_ld_hl_n();
|
||||
template<uint x> auto op_ld_a_rr();
|
||||
auto op_ld_a_nn();
|
||||
template<uint x> auto op_ld_rr_a();
|
||||
auto op_ld_nn_a();
|
||||
auto op_ld_a_ffn();
|
||||
auto op_ld_ffn_a();
|
||||
auto op_ld_a_ffc();
|
||||
auto op_ld_ffc_a();
|
||||
auto op_ldi_hl_a();
|
||||
auto op_ldi_a_hl();
|
||||
auto op_ldd_hl_a();
|
||||
auto op_ldd_a_hl();
|
||||
|
||||
//16-bit load commands
|
||||
template<unsigned x> void op_ld_rr_nn();
|
||||
void op_ld_nn_sp();
|
||||
void op_ld_sp_hl();
|
||||
template<unsigned x> void op_push_rr();
|
||||
template<unsigned x> void op_pop_rr();
|
||||
template<uint x> auto op_ld_rr_nn();
|
||||
auto op_ld_nn_sp();
|
||||
auto op_ld_sp_hl();
|
||||
template<uint x> auto op_push_rr();
|
||||
template<uint x> auto op_pop_rr();
|
||||
|
||||
//8-bit arithmetic commands
|
||||
void opi_add_a(uint8 x);
|
||||
template<unsigned x> void op_add_a_r();
|
||||
void op_add_a_n();
|
||||
void op_add_a_hl();
|
||||
auto opi_add_a(uint8 x);
|
||||
template<uint x> auto op_add_a_r();
|
||||
auto op_add_a_n();
|
||||
auto op_add_a_hl();
|
||||
|
||||
void opi_adc_a(uint8 x);
|
||||
template<unsigned x> void op_adc_a_r();
|
||||
void op_adc_a_n();
|
||||
void op_adc_a_hl();
|
||||
auto opi_adc_a(uint8 x);
|
||||
template<uint x> auto op_adc_a_r();
|
||||
auto op_adc_a_n();
|
||||
auto op_adc_a_hl();
|
||||
|
||||
void opi_sub_a(uint8 x);
|
||||
template<unsigned x> void op_sub_a_r();
|
||||
void op_sub_a_n();
|
||||
void op_sub_a_hl();
|
||||
auto opi_sub_a(uint8 x);
|
||||
template<uint x> auto op_sub_a_r();
|
||||
auto op_sub_a_n();
|
||||
auto op_sub_a_hl();
|
||||
|
||||
void opi_sbc_a(uint8 x);
|
||||
template<unsigned x> void op_sbc_a_r();
|
||||
void op_sbc_a_n();
|
||||
void op_sbc_a_hl();
|
||||
auto opi_sbc_a(uint8 x);
|
||||
template<uint x> auto op_sbc_a_r();
|
||||
auto op_sbc_a_n();
|
||||
auto op_sbc_a_hl();
|
||||
|
||||
void opi_and_a(uint8 x);
|
||||
template<unsigned x> void op_and_a_r();
|
||||
void op_and_a_n();
|
||||
void op_and_a_hl();
|
||||
auto opi_and_a(uint8 x);
|
||||
template<uint x> auto op_and_a_r();
|
||||
auto op_and_a_n();
|
||||
auto op_and_a_hl();
|
||||
|
||||
void opi_xor_a(uint8 x);
|
||||
template<unsigned x> void op_xor_a_r();
|
||||
void op_xor_a_n();
|
||||
void op_xor_a_hl();
|
||||
auto opi_xor_a(uint8 x);
|
||||
template<uint x> auto op_xor_a_r();
|
||||
auto op_xor_a_n();
|
||||
auto op_xor_a_hl();
|
||||
|
||||
void opi_or_a(uint8 x);
|
||||
template<unsigned x> void op_or_a_r();
|
||||
void op_or_a_n();
|
||||
void op_or_a_hl();
|
||||
auto opi_or_a(uint8 x);
|
||||
template<uint x> auto op_or_a_r();
|
||||
auto op_or_a_n();
|
||||
auto op_or_a_hl();
|
||||
|
||||
void opi_cp_a(uint8 x);
|
||||
template<unsigned x> void op_cp_a_r();
|
||||
void op_cp_a_n();
|
||||
void op_cp_a_hl();
|
||||
auto opi_cp_a(uint8 x);
|
||||
template<uint x> auto op_cp_a_r();
|
||||
auto op_cp_a_n();
|
||||
auto op_cp_a_hl();
|
||||
|
||||
template<unsigned x> void op_inc_r();
|
||||
void op_inc_hl();
|
||||
template<unsigned x> void op_dec_r();
|
||||
void op_dec_hl();
|
||||
void op_daa();
|
||||
void op_cpl();
|
||||
template<uint x> auto op_inc_r();
|
||||
auto op_inc_hl();
|
||||
template<uint x> auto op_dec_r();
|
||||
auto op_dec_hl();
|
||||
auto op_daa();
|
||||
auto op_cpl();
|
||||
|
||||
//16-bit arithmetic commands
|
||||
template<unsigned x> void op_add_hl_rr();
|
||||
template<unsigned x> void op_inc_rr();
|
||||
template<unsigned x> void op_dec_rr();
|
||||
void op_add_sp_n();
|
||||
void op_ld_hl_sp_n();
|
||||
template<uint x> auto op_add_hl_rr();
|
||||
template<uint x> auto op_inc_rr();
|
||||
template<uint x> auto op_dec_rr();
|
||||
auto op_add_sp_n();
|
||||
auto op_ld_hl_sp_n();
|
||||
|
||||
//rotate/shift commands
|
||||
void op_rlca();
|
||||
void op_rla();
|
||||
void op_rrca();
|
||||
void op_rra();
|
||||
template<unsigned x> void op_rlc_r();
|
||||
void op_rlc_hl();
|
||||
template<unsigned x> void op_rl_r();
|
||||
void op_rl_hl();
|
||||
template<unsigned x> void op_rrc_r();
|
||||
void op_rrc_hl();
|
||||
template<unsigned x> void op_rr_r();
|
||||
void op_rr_hl();
|
||||
template<unsigned x> void op_sla_r();
|
||||
void op_sla_hl();
|
||||
template<unsigned x> void op_swap_r();
|
||||
void op_swap_hl();
|
||||
template<unsigned x> void op_sra_r();
|
||||
void op_sra_hl();
|
||||
template<unsigned x> void op_srl_r();
|
||||
void op_srl_hl();
|
||||
auto op_rlca();
|
||||
auto op_rla();
|
||||
auto op_rrca();
|
||||
auto op_rra();
|
||||
template<uint x> auto op_rlc_r();
|
||||
auto op_rlc_hl();
|
||||
template<uint x> auto op_rl_r();
|
||||
auto op_rl_hl();
|
||||
template<uint x> auto op_rrc_r();
|
||||
auto op_rrc_hl();
|
||||
template<uint x> auto op_rr_r();
|
||||
auto op_rr_hl();
|
||||
template<uint x> auto op_sla_r();
|
||||
auto op_sla_hl();
|
||||
template<uint x> auto op_swap_r();
|
||||
auto op_swap_hl();
|
||||
template<uint x> auto op_sra_r();
|
||||
auto op_sra_hl();
|
||||
template<uint x> auto op_srl_r();
|
||||
auto op_srl_hl();
|
||||
|
||||
//single-bit commands
|
||||
template<unsigned b, unsigned x> void op_bit_n_r();
|
||||
template<unsigned b> void op_bit_n_hl();
|
||||
template<unsigned b, unsigned x> void op_set_n_r();
|
||||
template<unsigned b> void op_set_n_hl();
|
||||
template<unsigned b, unsigned x> void op_res_n_r();
|
||||
template<unsigned b> void op_res_n_hl();
|
||||
template<uint b, uint x> auto op_bit_n_r();
|
||||
template<uint b> auto op_bit_n_hl();
|
||||
template<uint b, uint x> auto op_set_n_r();
|
||||
template<uint b> auto op_set_n_hl();
|
||||
template<uint b, uint x> auto op_res_n_r();
|
||||
template<uint b> auto op_res_n_hl();
|
||||
|
||||
//control commands
|
||||
void op_ccf();
|
||||
void op_scf();
|
||||
void op_nop();
|
||||
void op_halt();
|
||||
void op_stop();
|
||||
void op_di();
|
||||
void op_ei();
|
||||
auto op_ccf();
|
||||
auto op_scf();
|
||||
auto op_nop();
|
||||
auto op_halt();
|
||||
auto op_stop();
|
||||
auto op_di();
|
||||
auto op_ei();
|
||||
|
||||
//jump commands
|
||||
void op_jp_nn();
|
||||
void op_jp_hl();
|
||||
template<unsigned x, bool y> void op_jp_f_nn();
|
||||
void op_jr_n();
|
||||
template<unsigned x, bool y> void op_jr_f_n();
|
||||
void op_call_nn();
|
||||
template<unsigned x, bool y> void op_call_f_nn();
|
||||
void op_ret();
|
||||
template<unsigned x, bool y> void op_ret_f();
|
||||
void op_reti();
|
||||
template<unsigned n> void op_rst_n();
|
||||
auto op_jp_nn();
|
||||
auto op_jp_hl();
|
||||
template<uint x, bool y> auto op_jp_f_nn();
|
||||
auto op_jr_n();
|
||||
template<uint x, bool y> auto op_jr_f_n();
|
||||
auto op_call_nn();
|
||||
template<uint x, bool y> auto op_call_f_nn();
|
||||
auto op_ret();
|
||||
template<uint x, bool y> auto op_ret_f();
|
||||
auto op_reti();
|
||||
template<uint n> auto op_rst_n();
|
||||
|
||||
//disassembler.cpp
|
||||
string disassemble(uint16 pc);
|
||||
string disassemble_opcode(uint16 pc);
|
||||
string disassemble_opcode_cb(uint16 pc);
|
||||
auto disassemble(uint16 pc) -> string;
|
||||
auto disassembleOpcode(uint16 pc) -> string;
|
||||
auto disassembleOpcodeCB(uint16 pc) -> string;
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
void LR35902::serialize(serializer& s) {
|
||||
auto LR35902::serialize(serializer& s) -> void {
|
||||
s.integer(r.a.data);
|
||||
s.integer(r.f.z);
|
||||
s.integer(r.f.n);
|
||||
|
|
|
@ -1,18 +1,18 @@
|
|||
string R6502::disassemble() {
|
||||
string output = { hex(regs.pc, 4L), " " };
|
||||
auto R6502::disassemble() -> string {
|
||||
string output = {hex(regs.pc, 4L), " "};
|
||||
|
||||
auto abs = [&]() -> string { return { "$", hex(debugger_read(regs.pc + 2), 2L), hex(debugger_read(regs.pc + 1), 2L) }; };
|
||||
auto abx = [&]() -> string { return { "$", hex(debugger_read(regs.pc + 2), 2L), hex(debugger_read(regs.pc + 1), 2L), ",x" }; };
|
||||
auto aby = [&]() -> string { return { "$", hex(debugger_read(regs.pc + 2), 2L), hex(debugger_read(regs.pc + 1), 2L), ",y" }; };
|
||||
auto iab = [&]() -> string { return { "($", hex(debugger_read(regs.pc + 2), 2L), hex(debugger_read(regs.pc + 1), 2L), ")" }; };
|
||||
auto imm = [&]() -> string { return { "#$", hex(debugger_read(regs.pc + 1), 2L) }; };
|
||||
auto imp = [&]() -> string { return ""; };
|
||||
auto izx = [&]() -> string { return { "($", hex(debugger_read(regs.pc + 1), 2L), ",x)" }; };
|
||||
auto izy = [&]() -> string { return { "($", hex(debugger_read(regs.pc + 1), 2L), "),y" }; };
|
||||
auto rel = [&]() -> string { return { "$", hex((regs.pc + 2) + (int8)debugger_read(regs.pc + 1), 4L) }; };
|
||||
auto zpg = [&]() -> string { return { "$", hex(debugger_read(regs.pc + 1), 2L) }; };
|
||||
auto zpx = [&]() -> string { return { "$", hex(debugger_read(regs.pc + 1), 2L), ",x" }; };
|
||||
auto zpy = [&]() -> string { return { "$", hex(debugger_read(regs.pc + 1), 2L), ",y" }; };
|
||||
auto abs = [&]() -> string { return {"$", hex(debugger_read(regs.pc + 2), 2L), hex(debugger_read(regs.pc + 1), 2L)}; };
|
||||
auto abx = [&]() -> string { return {"$", hex(debugger_read(regs.pc + 2), 2L), hex(debugger_read(regs.pc + 1), 2L), ",x"}; };
|
||||
auto aby = [&]() -> string { return {"$", hex(debugger_read(regs.pc + 2), 2L), hex(debugger_read(regs.pc + 1), 2L), ",y"}; };
|
||||
auto iab = [&]() -> string { return {"($", hex(debugger_read(regs.pc + 2), 2L), hex(debugger_read(regs.pc + 1), 2L), ")"}; };
|
||||
auto imm = [&]() -> string { return {"#$", hex(debugger_read(regs.pc + 1), 2L)}; };
|
||||
auto imp = [&]() -> string { return {""}; };
|
||||
auto izx = [&]() -> string { return {"($", hex(debugger_read(regs.pc + 1), 2L), ",x)"}; };
|
||||
auto izy = [&]() -> string { return {"($", hex(debugger_read(regs.pc + 1), 2L), "),y"}; };
|
||||
auto rel = [&]() -> string { return {"$", hex((regs.pc + 2) + (int8)debugger_read(regs.pc + 1), 4L)}; };
|
||||
auto zpg = [&]() -> string { return {"$", hex(debugger_read(regs.pc + 1), 2L)}; };
|
||||
auto zpx = [&]() -> string { return {"$", hex(debugger_read(regs.pc + 1), 2L), ",x"}; };
|
||||
auto zpy = [&]() -> string { return {"$", hex(debugger_read(regs.pc + 1), 2L), ",y"}; };
|
||||
|
||||
#define op(byte, prefix, mode) \
|
||||
case byte: output.append(#prefix, " ", mode()); \
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
//opcode functions
|
||||
//================
|
||||
|
||||
void R6502::opf_adc() {
|
||||
signed result = regs.a + rd + regs.p.c;
|
||||
auto R6502::opf_adc() {
|
||||
int result = regs.a + rd + regs.p.c;
|
||||
regs.p.v = ~(regs.a ^ rd) & (regs.a ^ result) & 0x80;
|
||||
regs.p.c = (result > 0xff);
|
||||
regs.p.n = (result & 0x80);
|
||||
|
@ -10,140 +10,140 @@ void R6502::opf_adc() {
|
|||
regs.a = result;
|
||||
}
|
||||
|
||||
void R6502::opf_and() {
|
||||
auto R6502::opf_and() {
|
||||
regs.a &= rd;
|
||||
regs.p.n = (regs.a & 0x80);
|
||||
regs.p.z = (regs.a == 0);
|
||||
}
|
||||
|
||||
void R6502::opf_asl() {
|
||||
auto R6502::opf_asl() {
|
||||
regs.p.c = rd & 0x80;
|
||||
rd <<= 1;
|
||||
regs.p.n = (rd & 0x80);
|
||||
regs.p.z = (rd == 0);
|
||||
}
|
||||
|
||||
void R6502::opf_bit() {
|
||||
auto R6502::opf_bit() {
|
||||
regs.p.n = (rd & 0x80);
|
||||
regs.p.v = (rd & 0x40);
|
||||
regs.p.z = ((rd & regs.a) == 0);
|
||||
}
|
||||
|
||||
void R6502::opf_cmp() {
|
||||
signed r = regs.a - rd;
|
||||
auto R6502::opf_cmp() {
|
||||
int r = regs.a - rd;
|
||||
regs.p.n = (r & 0x80);
|
||||
regs.p.z = (uint8)(r == 0);
|
||||
regs.p.c = (r >= 0);
|
||||
}
|
||||
|
||||
void R6502::opf_cpx() {
|
||||
signed r = regs.x - rd;
|
||||
auto R6502::opf_cpx() {
|
||||
int r = regs.x - rd;
|
||||
regs.p.n = (r & 0x80);
|
||||
regs.p.z = (uint8)(r == 0);
|
||||
regs.p.c = (r >= 0);
|
||||
}
|
||||
|
||||
void R6502::opf_cpy() {
|
||||
signed r = regs.y - rd;
|
||||
auto R6502::opf_cpy() {
|
||||
int r = regs.y - rd;
|
||||
regs.p.n = (r & 0x80);
|
||||
regs.p.z = (uint8)(r == 0);
|
||||
regs.p.c = (r >= 0);
|
||||
}
|
||||
|
||||
void R6502::opf_dec() {
|
||||
auto R6502::opf_dec() {
|
||||
rd--;
|
||||
regs.p.n = (rd & 0x80);
|
||||
regs.p.z = (rd == 0);
|
||||
}
|
||||
|
||||
void R6502::opf_eor() {
|
||||
auto R6502::opf_eor() {
|
||||
regs.a ^= rd;
|
||||
regs.p.n = (regs.a & 0x80);
|
||||
regs.p.z = (regs.a == 0);
|
||||
}
|
||||
|
||||
void R6502::opf_inc() {
|
||||
auto R6502::opf_inc() {
|
||||
rd++;
|
||||
regs.p.n = (rd & 0x80);
|
||||
regs.p.z = (rd == 0);
|
||||
}
|
||||
|
||||
void R6502::opf_lda() {
|
||||
auto R6502::opf_lda() {
|
||||
regs.a = rd;
|
||||
regs.p.n = (regs.a & 0x80);
|
||||
regs.p.z = (regs.a == 0);
|
||||
}
|
||||
|
||||
void R6502::opf_ldx() {
|
||||
auto R6502::opf_ldx() {
|
||||
regs.x = rd;
|
||||
regs.p.n = (regs.x & 0x80);
|
||||
regs.p.z = (regs.x == 0);
|
||||
}
|
||||
|
||||
void R6502::opf_ldy() {
|
||||
auto R6502::opf_ldy() {
|
||||
regs.y = rd;
|
||||
regs.p.n = (regs.y & 0x80);
|
||||
regs.p.z = (regs.y == 0);
|
||||
}
|
||||
|
||||
void R6502::opf_lsr() {
|
||||
auto R6502::opf_lsr() {
|
||||
regs.p.c = rd & 0x01;
|
||||
rd >>= 1;
|
||||
regs.p.n = (rd & 0x80);
|
||||
regs.p.z = (rd == 0);
|
||||
}
|
||||
|
||||
void R6502::opf_ora() {
|
||||
auto R6502::opf_ora() {
|
||||
regs.a |= rd;
|
||||
regs.p.n = (regs.a & 0x80);
|
||||
regs.p.z = (regs.a == 0);
|
||||
}
|
||||
|
||||
void R6502::opf_rla() {
|
||||
unsigned carry = (unsigned)regs.p.c;
|
||||
auto R6502::opf_rla() {
|
||||
uint carry = (uint)regs.p.c;
|
||||
regs.p.c = regs.a & 0x80;
|
||||
regs.a = (regs.a << 1) | carry;
|
||||
regs.p.n = (regs.a & 0x80);
|
||||
regs.p.z = (regs.a == 0);
|
||||
}
|
||||
|
||||
void R6502::opf_rol() {
|
||||
unsigned carry = (unsigned)regs.p.c;
|
||||
auto R6502::opf_rol() {
|
||||
uint carry = (uint)regs.p.c;
|
||||
regs.p.c = rd & 0x80;
|
||||
rd = (rd << 1) | carry;
|
||||
regs.p.n = (rd & 0x80);
|
||||
regs.p.z = (rd == 0);
|
||||
}
|
||||
|
||||
void R6502::opf_ror() {
|
||||
unsigned carry = (unsigned)regs.p.c << 7;
|
||||
auto R6502::opf_ror() {
|
||||
uint carry = (uint)regs.p.c << 7;
|
||||
regs.p.c = rd & 0x01;
|
||||
rd = carry | (rd >> 1);
|
||||
regs.p.n = (rd & 0x80);
|
||||
regs.p.z = (rd == 0);
|
||||
}
|
||||
|
||||
void R6502::opf_rra() {
|
||||
unsigned carry = (unsigned)regs.p.c << 7;
|
||||
auto R6502::opf_rra() {
|
||||
uint carry = (uint)regs.p.c << 7;
|
||||
regs.p.c = regs.a & 0x01;
|
||||
regs.a = carry | (regs.a >> 1);
|
||||
regs.p.n = (regs.a & 0x80);
|
||||
regs.p.z = (regs.a == 0);
|
||||
}
|
||||
|
||||
void R6502::opf_sbc() {
|
||||
auto R6502::opf_sbc() {
|
||||
rd ^= 0xff;
|
||||
return opf_adc();
|
||||
}
|
||||
|
||||
void R6502::opf_sla() {
|
||||
auto R6502::opf_sla() {
|
||||
regs.p.c = regs.a & 0x80;
|
||||
regs.a <<= 1;
|
||||
regs.p.n = (regs.a & 0x80);
|
||||
regs.p.z = (regs.a == 0);
|
||||
}
|
||||
|
||||
void R6502::opf_sra() {
|
||||
auto R6502::opf_sra() {
|
||||
regs.p.c = regs.a & 0x01;
|
||||
regs.a >>= 1;
|
||||
regs.p.n = (regs.a & 0x80);
|
||||
|
@ -153,7 +153,7 @@ void R6502::opf_sra() {
|
|||
//opcode implementations
|
||||
//======================
|
||||
|
||||
void R6502::opi_branch(bool condition) {
|
||||
auto R6502::opi_branch(bool condition) {
|
||||
if(condition == false) {
|
||||
L rd = op_readpci();
|
||||
} else {
|
||||
|
@ -165,26 +165,26 @@ L op_readpc();
|
|||
}
|
||||
}
|
||||
|
||||
void R6502::opi_clear_flag(bool& flag) {
|
||||
auto R6502::opi_clear_flag(bool& flag) {
|
||||
L op_readpc();
|
||||
flag = 0;
|
||||
}
|
||||
|
||||
void R6502::opi_decrement(uint8& r) {
|
||||
auto R6502::opi_decrement(uint8& r) {
|
||||
L op_readpc();
|
||||
r--;
|
||||
regs.p.n = (r & 0x80);
|
||||
regs.p.z = (r == 0);
|
||||
}
|
||||
|
||||
void R6502::opi_increment(uint8& r) {
|
||||
auto R6502::opi_increment(uint8& r) {
|
||||
L op_readpc();
|
||||
r++;
|
||||
regs.p.n = (r & 0x80);
|
||||
regs.p.z = (r == 0);
|
||||
}
|
||||
|
||||
void R6502::opi_pull(uint8& r) {
|
||||
auto R6502::opi_pull(uint8& r) {
|
||||
op_readpc();
|
||||
op_readpc();
|
||||
L r = op_readsp();
|
||||
|
@ -192,21 +192,21 @@ L r = op_readsp();
|
|||
regs.p.z = (r == 0);
|
||||
}
|
||||
|
||||
void R6502::opi_push(uint8& r) {
|
||||
auto R6502::opi_push(uint8& r) {
|
||||
op_readpc();
|
||||
L op_writesp(r);
|
||||
}
|
||||
|
||||
template<void (R6502::*op)()>
|
||||
void R6502::opi_read_absolute() {
|
||||
template<auto (R6502::*op)() -> void>
|
||||
auto R6502::opi_read_absolute() {
|
||||
abs.l = op_readpci();
|
||||
abs.h = op_readpci();
|
||||
L rd = op_read(abs.w);
|
||||
call(op);
|
||||
}
|
||||
|
||||
template<void (R6502::*op)()>
|
||||
void R6502::opi_read_absolute_x() {
|
||||
template<auto (R6502::*op)() -> void>
|
||||
auto R6502::opi_read_absolute_x() {
|
||||
abs.l = op_readpci();
|
||||
abs.h = op_readpci();
|
||||
op_page(abs.w, abs.w + regs.x);
|
||||
|
@ -214,8 +214,8 @@ L rd = op_read(abs.w + regs.x);
|
|||
call(op);
|
||||
}
|
||||
|
||||
template<void (R6502::*op)()>
|
||||
void R6502::opi_read_absolute_y() {
|
||||
template<auto (R6502::*op)() -> void>
|
||||
auto R6502::opi_read_absolute_y() {
|
||||
abs.l = op_readpci();
|
||||
abs.h = op_readpci();
|
||||
op_page(abs.w, abs.w + regs.y);
|
||||
|
@ -223,14 +223,14 @@ L rd = op_read(abs.w + regs.y);
|
|||
call(op);
|
||||
}
|
||||
|
||||
template<void (R6502::*op)()>
|
||||
void R6502::opi_read_immediate() {
|
||||
template<auto (R6502::*op)() -> void>
|
||||
auto R6502::opi_read_immediate() {
|
||||
L rd = op_readpci();
|
||||
call(op);
|
||||
}
|
||||
|
||||
template<void (R6502::*op)()>
|
||||
void R6502::opi_read_indirect_zero_page_x() {
|
||||
template<auto (R6502::*op)() -> void>
|
||||
auto R6502::opi_read_indirect_zero_page_x() {
|
||||
zp = op_readpci();
|
||||
op_readzp(zp);
|
||||
abs.l = op_readzp(zp++ + regs.x);
|
||||
|
@ -239,8 +239,8 @@ L rd = op_read(abs.w);
|
|||
call(op);
|
||||
}
|
||||
|
||||
template<void (R6502::*op)()>
|
||||
void R6502::opi_read_indirect_zero_page_y() {
|
||||
template<auto (R6502::*op)() -> void>
|
||||
auto R6502::opi_read_indirect_zero_page_y() {
|
||||
rd = op_readpci();
|
||||
abs.l = op_readzp(rd++);
|
||||
abs.h = op_readzp(rd++);
|
||||
|
@ -249,31 +249,31 @@ L rd = op_read(abs.w + regs.y);
|
|||
call(op);
|
||||
}
|
||||
|
||||
template<void (R6502::*op)()>
|
||||
void R6502::opi_read_zero_page() {
|
||||
template<auto (R6502::*op)() -> void>
|
||||
auto R6502::opi_read_zero_page() {
|
||||
zp = op_readpci();
|
||||
L rd = op_readzp(zp);
|
||||
call(op);
|
||||
}
|
||||
|
||||
template<void (R6502::*op)()>
|
||||
void R6502::opi_read_zero_page_x() {
|
||||
template<auto (R6502::*op)() -> void>
|
||||
auto R6502::opi_read_zero_page_x() {
|
||||
zp = op_readpci();
|
||||
op_readzp(zp);
|
||||
L rd = op_readzp(zp + regs.x);
|
||||
call(op);
|
||||
}
|
||||
|
||||
template<void (R6502::*op)()>
|
||||
void R6502::opi_read_zero_page_y() {
|
||||
template<auto (R6502::*op)() -> void>
|
||||
auto R6502::opi_read_zero_page_y() {
|
||||
zp = op_readpci();
|
||||
op_readzp(zp);
|
||||
L rd = op_readzp(zp + regs.y);
|
||||
call(op);
|
||||
}
|
||||
|
||||
template<void (R6502::*op)()>
|
||||
void R6502::opi_rmw_absolute() {
|
||||
template<auto (R6502::*op)() -> void>
|
||||
auto R6502::opi_rmw_absolute() {
|
||||
abs.l = op_readpci();
|
||||
abs.h = op_readpci();
|
||||
rd = op_read(abs.w);
|
||||
|
@ -282,8 +282,8 @@ void R6502::opi_rmw_absolute() {
|
|||
L op_write(abs.w, rd);
|
||||
}
|
||||
|
||||
template<void (R6502::*op)()>
|
||||
void R6502::opi_rmw_absolute_x() {
|
||||
template<auto (R6502::*op)() -> void>
|
||||
auto R6502::opi_rmw_absolute_x() {
|
||||
abs.l = op_readpci();
|
||||
abs.h = op_readpci();
|
||||
op_page_always(abs.w, abs.w + regs.x);
|
||||
|
@ -293,8 +293,8 @@ void R6502::opi_rmw_absolute_x() {
|
|||
L op_write(abs.w + regs.x, rd);
|
||||
}
|
||||
|
||||
template<void (R6502::*op)()>
|
||||
void R6502::opi_rmw_zero_page() {
|
||||
template<auto (R6502::*op)() -> void>
|
||||
auto R6502::opi_rmw_zero_page() {
|
||||
zp = op_readpci();
|
||||
rd = op_readzp(zp);
|
||||
op_writezp(zp, rd);
|
||||
|
@ -302,8 +302,8 @@ void R6502::opi_rmw_zero_page() {
|
|||
L op_writezp(zp, rd);
|
||||
}
|
||||
|
||||
template<void (R6502::*op)()>
|
||||
void R6502::opi_rmw_zero_page_x() {
|
||||
template<auto (R6502::*op)() -> void>
|
||||
auto R6502::opi_rmw_zero_page_x() {
|
||||
zp = op_readpci();
|
||||
op_readzp(zp);
|
||||
rd = op_readzp(zp + regs.x);
|
||||
|
@ -312,38 +312,38 @@ void R6502::opi_rmw_zero_page_x() {
|
|||
L op_writezp(zp + regs.x, rd);
|
||||
}
|
||||
|
||||
void R6502::opi_set_flag(bool& flag) {
|
||||
auto R6502::opi_set_flag(bool& flag) {
|
||||
L op_readpc();
|
||||
flag = 1;
|
||||
}
|
||||
|
||||
template<void (R6502::*op)()>
|
||||
void R6502::opi_shift() {
|
||||
template<auto (R6502::*op)() -> void>
|
||||
auto R6502::opi_shift() {
|
||||
L op_readpc();
|
||||
call(op);
|
||||
}
|
||||
|
||||
void R6502::opi_store_absolute(uint8& r) {
|
||||
auto R6502::opi_store_absolute(uint8& r) {
|
||||
abs.l = op_readpci();
|
||||
abs.h = op_readpci();
|
||||
L op_write(abs.w, r);
|
||||
}
|
||||
|
||||
void R6502::opi_store_absolute_x(uint8& r) {
|
||||
auto R6502::opi_store_absolute_x(uint8& r) {
|
||||
abs.l = op_readpci();
|
||||
abs.h = op_readpci();
|
||||
op_page_always(abs.w, abs.w + regs.x);
|
||||
L op_write(abs.w + regs.x, r);
|
||||
}
|
||||
|
||||
void R6502::opi_store_absolute_y(uint8& r) {
|
||||
auto R6502::opi_store_absolute_y(uint8& r) {
|
||||
abs.l = op_readpci();
|
||||
abs.h = op_readpci();
|
||||
op_page_always(abs.w, abs.w + regs.y);
|
||||
L op_write(abs.w + regs.y, r);
|
||||
}
|
||||
|
||||
void R6502::opi_store_indirect_zero_page_x(uint8& r) {
|
||||
auto R6502::opi_store_indirect_zero_page_x(uint8& r) {
|
||||
zp = op_readpci();
|
||||
op_readzp(zp);
|
||||
abs.l = op_readzp(zp++ + regs.x);
|
||||
|
@ -351,7 +351,7 @@ void R6502::opi_store_indirect_zero_page_x(uint8& r) {
|
|||
L op_write(abs.w, r);
|
||||
}
|
||||
|
||||
void R6502::opi_store_indirect_zero_page_y(uint8& r) {
|
||||
auto R6502::opi_store_indirect_zero_page_y(uint8& r) {
|
||||
rd = op_readpci();
|
||||
abs.l = op_readzp(rd++);
|
||||
abs.h = op_readzp(rd++);
|
||||
|
@ -359,24 +359,24 @@ void R6502::opi_store_indirect_zero_page_y(uint8& r) {
|
|||
L op_write(abs.w + regs.y, r);
|
||||
}
|
||||
|
||||
void R6502::opi_store_zero_page(uint8& r) {
|
||||
auto R6502::opi_store_zero_page(uint8& r) {
|
||||
zp = op_readpci();
|
||||
L op_writezp(zp, r);
|
||||
}
|
||||
|
||||
void R6502::opi_store_zero_page_x(uint8& r) {
|
||||
auto R6502::opi_store_zero_page_x(uint8& r) {
|
||||
zp = op_readpci();
|
||||
op_readzp(zp);
|
||||
L op_writezp(zp + regs.x, r);
|
||||
}
|
||||
|
||||
void R6502::opi_store_zero_page_y(uint8& r) {
|
||||
auto R6502::opi_store_zero_page_y(uint8& r) {
|
||||
zp = op_readpci();
|
||||
op_readzp(zp);
|
||||
L op_writezp(zp + regs.y, r);
|
||||
}
|
||||
|
||||
void R6502::opi_transfer(uint8& s, uint8& d, bool flag) {
|
||||
auto R6502::opi_transfer(uint8& s, uint8& d, bool flag) {
|
||||
L op_readpc();
|
||||
d = s;
|
||||
if(flag == false) return;
|
||||
|
@ -387,7 +387,7 @@ L op_readpc();
|
|||
//opcodes
|
||||
//=======
|
||||
|
||||
void R6502::op_brk() {
|
||||
auto R6502::op_brk() {
|
||||
op_readpci();
|
||||
op_writesp(regs.pc >> 8);
|
||||
op_writesp(regs.pc >> 0);
|
||||
|
@ -399,13 +399,13 @@ L abs.h = op_read(0xffff);
|
|||
regs.pc = abs.w;
|
||||
}
|
||||
|
||||
void R6502::op_jmp_absolute() {
|
||||
auto R6502::op_jmp_absolute() {
|
||||
abs.l = op_readpci();
|
||||
L abs.h = op_readpci();
|
||||
regs.pc = abs.w;
|
||||
}
|
||||
|
||||
void R6502::op_jmp_indirect_absolute() {
|
||||
auto R6502::op_jmp_indirect_absolute() {
|
||||
abs.l = op_readpci();
|
||||
abs.h = op_readpci();
|
||||
iabs.l = op_read(abs.w); abs.l++;
|
||||
|
@ -413,7 +413,7 @@ L iabs.h = op_read(abs.w); abs.l++;
|
|||
regs.pc = iabs.w;
|
||||
}
|
||||
|
||||
void R6502::op_jsr_absolute() {
|
||||
auto R6502::op_jsr_absolute() {
|
||||
abs.l = op_readpci();
|
||||
abs.h = op_readpci();
|
||||
op_readpc();
|
||||
|
@ -423,22 +423,22 @@ L op_writesp(regs.pc >> 0);
|
|||
regs.pc = abs.w;
|
||||
}
|
||||
|
||||
void R6502::op_nop() {
|
||||
auto R6502::op_nop() {
|
||||
L op_readpc();
|
||||
}
|
||||
|
||||
void R6502::op_php() {
|
||||
auto R6502::op_php() {
|
||||
op_readpc();
|
||||
L op_writesp(regs.p | 0x30);
|
||||
}
|
||||
|
||||
void R6502::op_plp() {
|
||||
auto R6502::op_plp() {
|
||||
op_readpc();
|
||||
op_readpc();
|
||||
L regs.p = op_readsp();
|
||||
}
|
||||
|
||||
void R6502::op_rti() {
|
||||
auto R6502::op_rti() {
|
||||
op_readpc();
|
||||
op_readpc();
|
||||
regs.p = op_readsp();
|
||||
|
@ -447,7 +447,7 @@ L abs.h = op_readsp();
|
|||
regs.pc = abs.w;
|
||||
}
|
||||
|
||||
void R6502::op_rts() {
|
||||
auto R6502::op_rts() {
|
||||
op_readpc();
|
||||
op_readpc();
|
||||
abs.l = op_readsp();
|
||||
|
@ -459,7 +459,7 @@ L op_readpc();
|
|||
//illegal opcodes
|
||||
//===============
|
||||
|
||||
void R6502::opill_arr_immediate() {
|
||||
auto R6502::opill_arr_immediate() {
|
||||
L rd = op_readpci();
|
||||
regs.a &= rd;
|
||||
regs.a = (regs.p.c << 7) | (regs.a >> 1);
|
||||
|
@ -469,33 +469,33 @@ L rd = op_readpci();
|
|||
regs.p.v = regs.p.c ^ ((regs.a >> 5) & 1);
|
||||
}
|
||||
|
||||
void R6502::opill_nop_absolute() {
|
||||
auto R6502::opill_nop_absolute() {
|
||||
abs.l = op_readpci();
|
||||
abs.h = op_readpci();
|
||||
L op_readpc();
|
||||
}
|
||||
|
||||
void R6502::opill_nop_absolute_x() {
|
||||
auto R6502::opill_nop_absolute_x() {
|
||||
abs.l = op_readpci();
|
||||
abs.h = op_readpci();
|
||||
op_page(abs.w, abs.w + regs.x);
|
||||
L op_readpc();
|
||||
}
|
||||
|
||||
void R6502::opill_nop_immediate() {
|
||||
auto R6502::opill_nop_immediate() {
|
||||
L rd = op_readpc();
|
||||
}
|
||||
|
||||
void R6502::opill_nop_implied() {
|
||||
auto R6502::opill_nop_implied() {
|
||||
L op_readpc();
|
||||
}
|
||||
|
||||
void R6502::opill_nop_zero_page() {
|
||||
auto R6502::opill_nop_zero_page() {
|
||||
zp = op_readpci();
|
||||
L op_readzp(zp);
|
||||
}
|
||||
|
||||
void R6502::opill_nop_zero_page_x() {
|
||||
auto R6502::opill_nop_zero_page_x() {
|
||||
zp = op_readpci();
|
||||
op_readzp(zp);
|
||||
L op_readzp(zp + regs.x);
|
||||
|
|
|
@ -1,35 +1,35 @@
|
|||
uint8 R6502::op_readpc() {
|
||||
auto R6502::op_readpc() -> uint8 {
|
||||
return op_read(regs.pc);
|
||||
}
|
||||
|
||||
uint8 R6502::op_readpci() {
|
||||
auto R6502::op_readpci() -> uint8 {
|
||||
return op_read(regs.pc++);
|
||||
}
|
||||
|
||||
uint8 R6502::op_readsp() {
|
||||
auto R6502::op_readsp() -> uint8 {
|
||||
return op_read(0x0100 | ++regs.s);
|
||||
}
|
||||
|
||||
uint8 R6502::op_readzp(uint8 addr) {
|
||||
auto R6502::op_readzp(uint8 addr) -> uint8 {
|
||||
return op_read(addr);
|
||||
}
|
||||
|
||||
//
|
||||
|
||||
void R6502::op_writesp(uint8 data) {
|
||||
auto R6502::op_writesp(uint8 data) -> void {
|
||||
op_write(0x0100 | regs.s--, data);
|
||||
}
|
||||
|
||||
void R6502::op_writezp(uint8 addr, uint8 data) {
|
||||
auto R6502::op_writezp(uint8 addr, uint8 data) -> void {
|
||||
op_write(addr, data);
|
||||
}
|
||||
|
||||
//
|
||||
|
||||
void R6502::op_page(uint16 x, uint16 y) {
|
||||
auto R6502::op_page(uint16 x, uint16 y) -> void {
|
||||
if((x & 0xff00) != (y & 0xff00)) op_read((x & 0xff00) | (y & 0x00ff));
|
||||
}
|
||||
|
||||
void R6502::op_page_always(uint16 x, uint16 y) {
|
||||
auto R6502::op_page_always(uint16 x, uint16 y) -> void {
|
||||
op_read((x & 0xff00) | (y & 0x00ff));
|
||||
}
|
||||
|
|
|
@ -12,11 +12,11 @@ namespace Processor {
|
|||
#include "disassembler.cpp"
|
||||
#include "serialization.cpp"
|
||||
|
||||
uint8 R6502::mdr() const {
|
||||
auto R6502::mdr() const -> uint8 {
|
||||
return regs.mdr;
|
||||
}
|
||||
|
||||
void R6502::power() {
|
||||
auto R6502::power() -> void {
|
||||
regs.a = 0x00;
|
||||
regs.x = 0x00;
|
||||
regs.y = 0x00;
|
||||
|
@ -24,13 +24,13 @@ void R6502::power() {
|
|||
regs.p = 0x04;
|
||||
}
|
||||
|
||||
void R6502::reset() {
|
||||
auto R6502::reset() -> void {
|
||||
regs.mdr = 0x00;
|
||||
regs.s -= 3;
|
||||
regs.p.i = 1;
|
||||
}
|
||||
|
||||
void R6502::interrupt() {
|
||||
auto R6502::interrupt() -> void {
|
||||
op_readpc();
|
||||
op_readpc();
|
||||
op_writesp(regs.pc >> 8);
|
||||
|
@ -45,7 +45,7 @@ L abs.h = op_read(vector++);
|
|||
regs.pc = abs.w;
|
||||
}
|
||||
|
||||
void R6502::exec() {
|
||||
auto R6502::exec() -> void {
|
||||
uint8 opcode = op_readpci();
|
||||
switch(opcode) {
|
||||
case 0x00: return op_brk();
|
||||
|
|
|
@ -1,116 +1,116 @@
|
|||
//Ricoh 6502
|
||||
//* Ricoh 2A03
|
||||
//* Ricoh 2A07
|
||||
|
||||
#ifndef PROCESSOR_R6502_HPP
|
||||
#define PROCESSOR_R6502_HPP
|
||||
|
||||
namespace Processor {
|
||||
|
||||
//Ricoh 6502
|
||||
//* Ricoh 2A03
|
||||
//* Ricoh 2A07
|
||||
|
||||
struct R6502 {
|
||||
#include "registers.hpp"
|
||||
virtual auto op_read(uint16 addr) -> uint8 = 0;
|
||||
virtual auto op_write(uint16 addr, uint8 data) -> void = 0;
|
||||
virtual auto last_cycle() -> void = 0;
|
||||
virtual auto nmi(uint16& vector) -> void = 0;
|
||||
virtual auto debugger_read(uint16 addr) -> uint8 { return 0u; }
|
||||
|
||||
virtual uint8 op_read(uint16 addr) = 0;
|
||||
virtual void op_write(uint16 addr, uint8 data) = 0;
|
||||
virtual void last_cycle() = 0;
|
||||
virtual void nmi(uint16& vector) = 0;
|
||||
virtual uint8 debugger_read(uint16 addr) { return 0u; }
|
||||
auto mdr() const -> uint8;
|
||||
auto power() -> void;
|
||||
auto reset() -> void;
|
||||
auto interrupt() -> void;
|
||||
auto exec() -> void;
|
||||
|
||||
uint8 mdr() const;
|
||||
void power();
|
||||
void reset();
|
||||
void interrupt();
|
||||
void exec();
|
||||
|
||||
void serialize(serializer&);
|
||||
auto serialize(serializer&) -> void;
|
||||
|
||||
//memory.cpp
|
||||
uint8 op_readpc();
|
||||
uint8 op_readpci();
|
||||
uint8 op_readsp();
|
||||
uint8 op_readzp(uint8 addr);
|
||||
auto op_readpc() -> uint8;
|
||||
auto op_readpci() -> uint8;
|
||||
auto op_readsp() -> uint8;
|
||||
auto op_readzp(uint8 addr) -> uint8;
|
||||
|
||||
void op_writesp(uint8 data);
|
||||
void op_writezp(uint8 addr, uint8 data);
|
||||
auto op_writesp(uint8 data) -> void;
|
||||
auto op_writezp(uint8 addr, uint8 data) -> void;
|
||||
|
||||
void op_page(uint16 x, uint16 y);
|
||||
void op_page_always(uint16 x, uint16 y);
|
||||
auto op_page(uint16 x, uint16 y) -> void;
|
||||
auto op_page_always(uint16 x, uint16 y) -> void;
|
||||
|
||||
//instructions.cpp
|
||||
void opf_asl();
|
||||
void opf_adc();
|
||||
void opf_and();
|
||||
void opf_bit();
|
||||
void opf_cmp();
|
||||
void opf_cpx();
|
||||
void opf_cpy();
|
||||
void opf_dec();
|
||||
void opf_eor();
|
||||
void opf_inc();
|
||||
void opf_lda();
|
||||
void opf_ldx();
|
||||
void opf_ldy();
|
||||
void opf_lsr();
|
||||
void opf_ora();
|
||||
void opf_rla();
|
||||
void opf_rol();
|
||||
void opf_ror();
|
||||
void opf_rra();
|
||||
void opf_sbc();
|
||||
void opf_sla();
|
||||
void opf_sra();
|
||||
auto opf_asl();
|
||||
auto opf_adc();
|
||||
auto opf_and();
|
||||
auto opf_bit();
|
||||
auto opf_cmp();
|
||||
auto opf_cpx();
|
||||
auto opf_cpy();
|
||||
auto opf_dec();
|
||||
auto opf_eor();
|
||||
auto opf_inc();
|
||||
auto opf_lda();
|
||||
auto opf_ldx();
|
||||
auto opf_ldy();
|
||||
auto opf_lsr();
|
||||
auto opf_ora();
|
||||
auto opf_rla();
|
||||
auto opf_rol();
|
||||
auto opf_ror();
|
||||
auto opf_rra();
|
||||
auto opf_sbc();
|
||||
auto opf_sla();
|
||||
auto opf_sra();
|
||||
|
||||
void opi_branch(bool condition);
|
||||
void opi_clear_flag(bool& flag);
|
||||
void opi_decrement(uint8& r);
|
||||
void opi_increment(uint8& r);
|
||||
void opi_pull(uint8& r);
|
||||
void opi_push(uint8& r);
|
||||
template<void (R6502::*op)()> void opi_read_absolute();
|
||||
template<void (R6502::*op)()> void opi_read_absolute_x();
|
||||
template<void (R6502::*op)()> void opi_read_absolute_y();
|
||||
template<void (R6502::*op)()> void opi_read_immediate();
|
||||
template<void (R6502::*op)()> void opi_read_indirect_zero_page_x();
|
||||
template<void (R6502::*op)()> void opi_read_indirect_zero_page_y();
|
||||
template<void (R6502::*op)()> void opi_read_zero_page();
|
||||
template<void (R6502::*op)()> void opi_read_zero_page_x();
|
||||
template<void (R6502::*op)()> void opi_read_zero_page_y();
|
||||
template<void (R6502::*op)()> void opi_rmw_absolute();
|
||||
template<void (R6502::*op)()> void opi_rmw_absolute_x();
|
||||
template<void (R6502::*op)()> void opi_rmw_zero_page();
|
||||
template<void (R6502::*op)()> void opi_rmw_zero_page_x();
|
||||
void opi_set_flag(bool& flag);
|
||||
template<void (R6502::*op)()> void opi_shift();
|
||||
void opi_store_absolute(uint8& r);
|
||||
void opi_store_absolute_x(uint8& r);
|
||||
void opi_store_absolute_y(uint8& r);
|
||||
void opi_store_indirect_zero_page_x(uint8& r);
|
||||
void opi_store_indirect_zero_page_y(uint8& r);
|
||||
void opi_store_zero_page(uint8& r);
|
||||
void opi_store_zero_page_x(uint8& r);
|
||||
void opi_store_zero_page_y(uint8& r);
|
||||
void opi_transfer(uint8& s, uint8& d, bool flag);
|
||||
auto opi_branch(bool condition);
|
||||
auto opi_clear_flag(bool& flag);
|
||||
auto opi_decrement(uint8& r);
|
||||
auto opi_increment(uint8& r);
|
||||
auto opi_pull(uint8& r);
|
||||
auto opi_push(uint8& r);
|
||||
template<auto (R6502::*op)() -> void> auto opi_read_absolute();
|
||||
template<auto (R6502::*op)() -> void> auto opi_read_absolute_x();
|
||||
template<auto (R6502::*op)() -> void> auto opi_read_absolute_y();
|
||||
template<auto (R6502::*op)() -> void> auto opi_read_immediate();
|
||||
template<auto (R6502::*op)() -> void> auto opi_read_indirect_zero_page_x();
|
||||
template<auto (R6502::*op)() -> void> auto opi_read_indirect_zero_page_y();
|
||||
template<auto (R6502::*op)() -> void> auto opi_read_zero_page();
|
||||
template<auto (R6502::*op)() -> void> auto opi_read_zero_page_x();
|
||||
template<auto (R6502::*op)() -> void> auto opi_read_zero_page_y();
|
||||
template<auto (R6502::*op)() -> void> auto opi_rmw_absolute();
|
||||
template<auto (R6502::*op)() -> void> auto opi_rmw_absolute_x();
|
||||
template<auto (R6502::*op)() -> void> auto opi_rmw_zero_page();
|
||||
template<auto (R6502::*op)() -> void> auto opi_rmw_zero_page_x();
|
||||
auto opi_set_flag(bool& flag);
|
||||
template<auto (R6502::*op)() -> void> auto opi_shift();
|
||||
auto opi_store_absolute(uint8& r);
|
||||
auto opi_store_absolute_x(uint8& r);
|
||||
auto opi_store_absolute_y(uint8& r);
|
||||
auto opi_store_indirect_zero_page_x(uint8& r);
|
||||
auto opi_store_indirect_zero_page_y(uint8& r);
|
||||
auto opi_store_zero_page(uint8& r);
|
||||
auto opi_store_zero_page_x(uint8& r);
|
||||
auto opi_store_zero_page_y(uint8& r);
|
||||
auto opi_transfer(uint8& s, uint8& d, bool flag);
|
||||
|
||||
void op_brk();
|
||||
void op_jmp_absolute();
|
||||
void op_jmp_indirect_absolute();
|
||||
void op_jsr_absolute();
|
||||
void op_nop();
|
||||
void op_php();
|
||||
void op_plp();
|
||||
void op_rti();
|
||||
void op_rts();
|
||||
auto op_brk();
|
||||
auto op_jmp_absolute();
|
||||
auto op_jmp_indirect_absolute();
|
||||
auto op_jsr_absolute();
|
||||
auto op_nop();
|
||||
auto op_php();
|
||||
auto op_plp();
|
||||
auto op_rti();
|
||||
auto op_rts();
|
||||
|
||||
void opill_arr_immediate();
|
||||
void opill_nop_absolute();
|
||||
void opill_nop_absolute_x();
|
||||
void opill_nop_immediate();
|
||||
void opill_nop_implied();
|
||||
void opill_nop_zero_page();
|
||||
void opill_nop_zero_page_x();
|
||||
auto opill_arr_immediate();
|
||||
auto opill_nop_absolute();
|
||||
auto opill_nop_absolute_x();
|
||||
auto opill_nop_immediate();
|
||||
auto opill_nop_implied();
|
||||
auto opill_nop_zero_page();
|
||||
auto opill_nop_zero_page_x();
|
||||
|
||||
//disassembler.cpp
|
||||
string disassemble();
|
||||
auto disassemble() -> string;
|
||||
|
||||
#include "registers.hpp"
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -1,15 +1,15 @@
|
|||
struct Flags {
|
||||
bool n, v, d, i, z, c;
|
||||
|
||||
inline operator unsigned() {
|
||||
inline operator uint() {
|
||||
return (n << 7) | (v << 6) | (d << 3) | (i << 2) | (z << 1) | (c << 0);
|
||||
}
|
||||
|
||||
inline Flags& operator=(uint8 data) {
|
||||
inline auto operator=(uint8 data) -> Flags& {
|
||||
n = data & 0x80; v = data & 0x40;
|
||||
d = data & 0x08; i = data & 0x04; z = data & 0x02; c = data & 0x01;
|
||||
return *this;
|
||||
}
|
||||
|
||||
bool n, v, d, i, z, c;
|
||||
};
|
||||
|
||||
struct Registers {
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
void R6502::serialize(serializer& s) {
|
||||
auto R6502::serialize(serializer& s) -> void {
|
||||
s.integer(regs.mdr);
|
||||
s.integer(regs.pc);
|
||||
s.integer(regs.a);
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
uint8 SPC700::op_adc(uint8 x, uint8 y) {
|
||||
auto SPC700::op_adc(uint8 x, uint8 y) -> uint8 {
|
||||
int r = x + y + regs.p.c;
|
||||
regs.p.n = r & 0x80;
|
||||
regs.p.v = ~(x ^ y) & (x ^ r) & 0x80;
|
||||
|
@ -8,14 +8,14 @@ uint8 SPC700::op_adc(uint8 x, uint8 y) {
|
|||
return r;
|
||||
}
|
||||
|
||||
uint8 SPC700::op_and(uint8 x, uint8 y) {
|
||||
auto SPC700::op_and(uint8 x, uint8 y) -> uint8 {
|
||||
x &= y;
|
||||
regs.p.n = x & 0x80;
|
||||
regs.p.z = x == 0;
|
||||
return x;
|
||||
}
|
||||
|
||||
uint8 SPC700::op_asl(uint8 x) {
|
||||
auto SPC700::op_asl(uint8 x) -> uint8 {
|
||||
regs.p.c = x & 0x80;
|
||||
x <<= 1;
|
||||
regs.p.n = x & 0x80;
|
||||
|
@ -23,7 +23,7 @@ uint8 SPC700::op_asl(uint8 x) {
|
|||
return x;
|
||||
}
|
||||
|
||||
uint8 SPC700::op_cmp(uint8 x, uint8 y) {
|
||||
auto SPC700::op_cmp(uint8 x, uint8 y) -> uint8 {
|
||||
int r = x - y;
|
||||
regs.p.n = r & 0x80;
|
||||
regs.p.z = (uint8)r == 0;
|
||||
|
@ -31,34 +31,34 @@ uint8 SPC700::op_cmp(uint8 x, uint8 y) {
|
|||
return x;
|
||||
}
|
||||
|
||||
uint8 SPC700::op_dec(uint8 x) {
|
||||
auto SPC700::op_dec(uint8 x) -> uint8 {
|
||||
x--;
|
||||
regs.p.n = x & 0x80;
|
||||
regs.p.z = x == 0;
|
||||
return x;
|
||||
}
|
||||
|
||||
uint8 SPC700::op_eor(uint8 x, uint8 y) {
|
||||
auto SPC700::op_eor(uint8 x, uint8 y) -> uint8 {
|
||||
x ^= y;
|
||||
regs.p.n = x & 0x80;
|
||||
regs.p.z = x == 0;
|
||||
return x;
|
||||
}
|
||||
|
||||
uint8 SPC700::op_inc(uint8 x) {
|
||||
auto SPC700::op_inc(uint8 x) -> uint8 {
|
||||
x++;
|
||||
regs.p.n = x & 0x80;
|
||||
regs.p.z = x == 0;
|
||||
return x;
|
||||
}
|
||||
|
||||
uint8 SPC700::op_ld(uint8 x, uint8 y) {
|
||||
auto SPC700::op_ld(uint8 x, uint8 y) -> uint8 {
|
||||
regs.p.n = y & 0x80;
|
||||
regs.p.z = y == 0;
|
||||
return y;
|
||||
}
|
||||
|
||||
uint8 SPC700::op_lsr(uint8 x) {
|
||||
auto SPC700::op_lsr(uint8 x) -> uint8 {
|
||||
regs.p.c = x & 0x01;
|
||||
x >>= 1;
|
||||
regs.p.n = x & 0x80;
|
||||
|
@ -66,15 +66,15 @@ uint8 SPC700::op_lsr(uint8 x) {
|
|||
return x;
|
||||
}
|
||||
|
||||
uint8 SPC700::op_or(uint8 x, uint8 y) {
|
||||
auto SPC700::op_or(uint8 x, uint8 y) -> uint8 {
|
||||
x |= y;
|
||||
regs.p.n = x & 0x80;
|
||||
regs.p.z = x == 0;
|
||||
return x;
|
||||
}
|
||||
|
||||
uint8 SPC700::op_rol(uint8 x) {
|
||||
unsigned carry = regs.p.c << 0;
|
||||
auto SPC700::op_rol(uint8 x) -> uint8 {
|
||||
uint carry = regs.p.c << 0;
|
||||
regs.p.c = x & 0x80;
|
||||
x = (x << 1) | carry;
|
||||
regs.p.n = x & 0x80;
|
||||
|
@ -82,8 +82,8 @@ uint8 SPC700::op_rol(uint8 x) {
|
|||
return x;
|
||||
}
|
||||
|
||||
uint8 SPC700::op_ror(uint8 x) {
|
||||
unsigned carry = regs.p.c << 7;
|
||||
auto SPC700::op_ror(uint8 x) -> uint8 {
|
||||
uint carry = regs.p.c << 7;
|
||||
regs.p.c = x & 0x01;
|
||||
x = carry | (x >> 1);
|
||||
regs.p.n = x & 0x80;
|
||||
|
@ -91,17 +91,17 @@ uint8 SPC700::op_ror(uint8 x) {
|
|||
return x;
|
||||
}
|
||||
|
||||
uint8 SPC700::op_sbc(uint8 x, uint8 y) {
|
||||
auto SPC700::op_sbc(uint8 x, uint8 y) -> uint8 {
|
||||
return op_adc(x, ~y);
|
||||
}
|
||||
|
||||
uint8 SPC700::op_st(uint8 x, uint8 y) {
|
||||
auto SPC700::op_st(uint8 x, uint8 y) -> uint8 {
|
||||
return y;
|
||||
}
|
||||
|
||||
//
|
||||
|
||||
uint16 SPC700::op_adw(uint16 x, uint16 y) {
|
||||
auto SPC700::op_adw(uint16 x, uint16 y) -> uint16 {
|
||||
uint16 r;
|
||||
regs.p.c = 0;
|
||||
r = op_adc(x, y);
|
||||
|
@ -110,7 +110,7 @@ uint16 SPC700::op_adw(uint16 x, uint16 y) {
|
|||
return r;
|
||||
}
|
||||
|
||||
uint16 SPC700::op_cpw(uint16 x, uint16 y) {
|
||||
auto SPC700::op_cpw(uint16 x, uint16 y) -> uint16 {
|
||||
int r = x - y;
|
||||
regs.p.n = r & 0x8000;
|
||||
regs.p.z = (uint16)r == 0;
|
||||
|
@ -118,13 +118,13 @@ uint16 SPC700::op_cpw(uint16 x, uint16 y) {
|
|||
return x;
|
||||
}
|
||||
|
||||
uint16 SPC700::op_ldw(uint16 x, uint16 y) {
|
||||
auto SPC700::op_ldw(uint16 x, uint16 y) -> uint16 {
|
||||
regs.p.n = y & 0x8000;
|
||||
regs.p.z = y == 0;
|
||||
return y;
|
||||
}
|
||||
|
||||
uint16 SPC700::op_sbw(uint16 x, uint16 y) {
|
||||
auto SPC700::op_sbw(uint16 x, uint16 y) -> uint16 {
|
||||
uint16 r;
|
||||
regs.p.c = 1;
|
||||
r = op_sbc(x, y);
|
||||
|
|
|
@ -1,20 +1,20 @@
|
|||
string SPC700::disassemble_opcode(uint16 addr, bool p) {
|
||||
auto SPC700::disassemble(uint16 addr, bool p) -> string {
|
||||
auto read = [&](uint16 addr) -> uint8 {
|
||||
return disassembler_read(addr);
|
||||
};
|
||||
|
||||
auto relative = [&](unsigned length, int8 offset) -> uint16 {
|
||||
auto relative = [&](uint length, int8 offset) -> uint16 {
|
||||
uint16 pc = addr + length;
|
||||
return pc + offset;
|
||||
};
|
||||
|
||||
auto a = [&] { return hex((read(addr + 1) << 0) + (read(addr + 2) << 8), 4L); };
|
||||
auto b = [&](unsigned n) { return hex(read(addr + 1 + n), 2L); };
|
||||
auto r = [&](unsigned r, unsigned n = 0) { return hex(addr + r + (int8)read(addr + 1 + n), 4L); };
|
||||
auto dp = [&](unsigned n) { return hex((p << 8) + read(addr + 1 + n), 3L); };
|
||||
auto b = [&](uint n) { return hex(read(addr + 1 + n), 2L); };
|
||||
auto r = [&](uint r, uint n = 0) { return hex(addr + r + (int8)read(addr + 1 + n), 4L); };
|
||||
auto dp = [&](uint n) { return hex((p << 8) + read(addr + 1 + n), 3L); };
|
||||
auto ab = [&] {
|
||||
unsigned n = (read(addr + 1) << 0) + (read(addr + 2) << 8);
|
||||
return string{ hex(n & 0x1fff, 4L), ":", hex(n >> 13, 1L) };
|
||||
uint n = (read(addr + 1) << 0) + (read(addr + 2) << 8);
|
||||
return string{hex(n & 0x1fff, 4L), ":", hex(n >> 13, 1L)};
|
||||
};
|
||||
|
||||
auto mnemonic = [&]() -> string {
|
||||
|
@ -279,9 +279,9 @@ string SPC700::disassemble_opcode(uint16 addr, bool p) {
|
|||
throw;
|
||||
};
|
||||
|
||||
string output = { "..", hex(addr, 4L), " ", mnemonic() };
|
||||
string output = {"..", hex(addr, 4L), " ", mnemonic()};
|
||||
|
||||
unsigned length = output.length();
|
||||
uint length = output.length();
|
||||
while(length++ < 30) output.append(" ");
|
||||
|
||||
output.append(
|
||||
|
|
|
@ -1,13 +1,13 @@
|
|||
#define call (this->*op)
|
||||
|
||||
template<uint8 (SPC700::*op)(uint8)>
|
||||
void SPC700::op_adjust(uint8& r) {
|
||||
template<auto (SPC700::*op)(uint8) -> uint8>
|
||||
auto SPC700::op_adjust(uint8& r) -> void {
|
||||
op_io();
|
||||
r = call(r);
|
||||
}
|
||||
|
||||
template<uint8 (SPC700::*op)(uint8)>
|
||||
void SPC700::op_adjust_addr() {
|
||||
template<auto (SPC700::*op)(uint8) -> uint8>
|
||||
auto SPC700::op_adjust_addr() -> void {
|
||||
dp.l = op_readpc();
|
||||
dp.h = op_readpc();
|
||||
rd = op_read(dp);
|
||||
|
@ -15,15 +15,15 @@ void SPC700::op_adjust_addr() {
|
|||
op_write(dp, rd);
|
||||
}
|
||||
|
||||
template<uint8 (SPC700::*op)(uint8)>
|
||||
void SPC700::op_adjust_dp() {
|
||||
template<auto (SPC700::*op)(uint8) -> uint8>
|
||||
auto SPC700::op_adjust_dp() -> void {
|
||||
dp = op_readpc();
|
||||
rd = op_readdp(dp);
|
||||
rd = call(rd);
|
||||
op_writedp(dp, rd);
|
||||
}
|
||||
|
||||
void SPC700::op_adjust_dpw(signed n) {
|
||||
auto SPC700::op_adjust_dpw(int n) -> void {
|
||||
dp = op_readpc();
|
||||
rd.w = op_readdp(dp) + n;
|
||||
op_writedp(dp++, rd.l);
|
||||
|
@ -33,8 +33,8 @@ void SPC700::op_adjust_dpw(signed n) {
|
|||
regs.p.z = rd == 0;
|
||||
}
|
||||
|
||||
template<uint8 (SPC700::*op)(uint8)>
|
||||
void SPC700::op_adjust_dpx() {
|
||||
template<auto (SPC700::*op)(uint8) -> uint8>
|
||||
auto SPC700::op_adjust_dpx() -> void {
|
||||
dp = op_readpc();
|
||||
op_io();
|
||||
rd = op_readdp(dp + regs.x);
|
||||
|
@ -42,7 +42,7 @@ void SPC700::op_adjust_dpx() {
|
|||
op_writedp(dp + regs.x, rd);
|
||||
}
|
||||
|
||||
void SPC700::op_branch(bool condition) {
|
||||
auto SPC700::op_branch(bool condition) -> void {
|
||||
rd = op_readpc();
|
||||
if(condition == false) return;
|
||||
op_io();
|
||||
|
@ -50,7 +50,7 @@ void SPC700::op_branch(bool condition) {
|
|||
regs.pc += (int8)rd;
|
||||
}
|
||||
|
||||
void SPC700::op_branch_bit() {
|
||||
auto SPC700::op_branch_bit() -> void {
|
||||
dp = op_readpc();
|
||||
sp = op_readdp(dp);
|
||||
rd = op_readpc();
|
||||
|
@ -61,28 +61,28 @@ void SPC700::op_branch_bit() {
|
|||
regs.pc += (int8)rd;
|
||||
}
|
||||
|
||||
void SPC700::op_pull(uint8& r) {
|
||||
auto SPC700::op_pull(uint8& r) -> void {
|
||||
op_io();
|
||||
op_io();
|
||||
r = op_readsp();
|
||||
}
|
||||
|
||||
void SPC700::op_push(uint8 r) {
|
||||
auto SPC700::op_push(uint8 r) -> void {
|
||||
op_io();
|
||||
op_io();
|
||||
op_writesp(r);
|
||||
}
|
||||
|
||||
template<uint8 (SPC700::*op)(uint8, uint8)>
|
||||
void SPC700::op_read_addr(uint8& r) {
|
||||
template<auto (SPC700::*op)(uint8, uint8) -> uint8>
|
||||
auto SPC700::op_read_addr(uint8& r) -> void {
|
||||
dp.l = op_readpc();
|
||||
dp.h = op_readpc();
|
||||
rd = op_read(dp);
|
||||
r = call(r, rd);
|
||||
}
|
||||
|
||||
template<uint8 (SPC700::*op)(uint8, uint8)>
|
||||
void SPC700::op_read_addri(uint8& r) {
|
||||
template<auto (SPC700::*op)(uint8, uint8) -> uint8>
|
||||
auto SPC700::op_read_addri(uint8& r) -> void {
|
||||
dp.l = op_readpc();
|
||||
dp.h = op_readpc();
|
||||
op_io();
|
||||
|
@ -90,29 +90,29 @@ void SPC700::op_read_addri(uint8& r) {
|
|||
regs.a = call(regs.a, rd);
|
||||
}
|
||||
|
||||
template<uint8 (SPC700::*op)(uint8, uint8)>
|
||||
void SPC700::op_read_const(uint8& r) {
|
||||
template<auto (SPC700::*op)(uint8, uint8) -> uint8>
|
||||
auto SPC700::op_read_const(uint8& r) -> void {
|
||||
rd = op_readpc();
|
||||
r = call(r, rd);
|
||||
}
|
||||
|
||||
template<uint8 (SPC700::*op)(uint8, uint8)>
|
||||
void SPC700::op_read_dp(uint8& r) {
|
||||
template<auto (SPC700::*op)(uint8, uint8) -> uint8>
|
||||
auto SPC700::op_read_dp(uint8& r) -> void {
|
||||
dp = op_readpc();
|
||||
rd = op_readdp(dp);
|
||||
r = call(r, rd);
|
||||
}
|
||||
|
||||
template<uint8 (SPC700::*op)(uint8, uint8)>
|
||||
void SPC700::op_read_dpi(uint8& r, uint8& i) {
|
||||
template<auto (SPC700::*op)(uint8, uint8) -> uint8>
|
||||
auto SPC700::op_read_dpi(uint8& r, uint8& i) -> void {
|
||||
dp = op_readpc();
|
||||
op_io();
|
||||
rd = op_readdp(dp + i);
|
||||
r = call(r, rd);
|
||||
}
|
||||
|
||||
template<uint16 (SPC700::*op)(uint16, uint16)>
|
||||
void SPC700::op_read_dpw() {
|
||||
template<auto (SPC700::*op)(uint16, uint16) -> uint16>
|
||||
auto SPC700::op_read_dpw() -> void {
|
||||
dp = op_readpc();
|
||||
rd.l = op_readdp(dp++);
|
||||
if(op != &SPC700::op_cpw) op_io();
|
||||
|
@ -120,8 +120,8 @@ void SPC700::op_read_dpw() {
|
|||
regs.ya = call(regs.ya, rd);
|
||||
}
|
||||
|
||||
template<uint8 (SPC700::*op)(uint8, uint8)>
|
||||
void SPC700::op_read_idpx() {
|
||||
template<auto (SPC700::*op)(uint8, uint8) -> uint8>
|
||||
auto SPC700::op_read_idpx() -> void {
|
||||
dp = op_readpc() + regs.x;
|
||||
op_io();
|
||||
sp.l = op_readdp(dp++);
|
||||
|
@ -130,8 +130,8 @@ void SPC700::op_read_idpx() {
|
|||
regs.a = call(regs.a, rd);
|
||||
}
|
||||
|
||||
template<uint8 (SPC700::*op)(uint8, uint8)>
|
||||
void SPC700::op_read_idpy() {
|
||||
template<auto (SPC700::*op)(uint8, uint8) -> uint8>
|
||||
auto SPC700::op_read_idpy() -> void {
|
||||
dp = op_readpc();
|
||||
op_io();
|
||||
sp.l = op_readdp(dp++);
|
||||
|
@ -140,14 +140,14 @@ void SPC700::op_read_idpy() {
|
|||
regs.a = call(regs.a, rd);
|
||||
}
|
||||
|
||||
template<uint8 (SPC700::*op)(uint8, uint8)>
|
||||
void SPC700::op_read_ix() {
|
||||
template<auto (SPC700::*op)(uint8, uint8) -> uint8>
|
||||
auto SPC700::op_read_ix() -> void {
|
||||
op_io();
|
||||
rd = op_readdp(regs.x);
|
||||
regs.a = call(regs.a, rd);
|
||||
}
|
||||
|
||||
void SPC700::op_set_addr_bit() {
|
||||
auto SPC700::op_set_addr_bit() -> void {
|
||||
dp.l = op_readpc();
|
||||
dp.h = op_readpc();
|
||||
bit = dp >> 13;
|
||||
|
@ -182,19 +182,19 @@ void SPC700::op_set_addr_bit() {
|
|||
}
|
||||
}
|
||||
|
||||
void SPC700::op_set_bit() {
|
||||
auto SPC700::op_set_bit() -> void {
|
||||
dp = op_readpc();
|
||||
rd = op_readdp(dp) & ~(1 << (opcode >> 5));
|
||||
op_writedp(dp, rd | (!(opcode & 0x10) << (opcode >> 5)));
|
||||
}
|
||||
|
||||
void SPC700::op_set_flag(bool& flag, bool data) {
|
||||
auto SPC700::op_set_flag(bool& flag, bool data) -> void {
|
||||
op_io();
|
||||
if(&flag == ®s.p.i) op_io();
|
||||
flag = data;
|
||||
}
|
||||
|
||||
void SPC700::op_test_addr(bool set) {
|
||||
auto SPC700::op_test_addr(bool set) -> void {
|
||||
dp.l = op_readpc();
|
||||
dp.h = op_readpc();
|
||||
rd = op_read(dp);
|
||||
|
@ -204,7 +204,7 @@ void SPC700::op_test_addr(bool set) {
|
|||
op_write(dp, set ? rd | regs.a : rd & ~regs.a);
|
||||
}
|
||||
|
||||
void SPC700::op_transfer(uint8& from, uint8& to) {
|
||||
auto SPC700::op_transfer(uint8& from, uint8& to) -> void {
|
||||
op_io();
|
||||
to = from;
|
||||
if(&to == ®s.s) return;
|
||||
|
@ -212,14 +212,14 @@ void SPC700::op_transfer(uint8& from, uint8& to) {
|
|||
regs.p.z = (to == 0);
|
||||
}
|
||||
|
||||
void SPC700::op_write_addr(uint8& r) {
|
||||
auto SPC700::op_write_addr(uint8& r) -> void {
|
||||
dp.l = op_readpc();
|
||||
dp.h = op_readpc();
|
||||
op_read(dp);
|
||||
op_write(dp, r);
|
||||
}
|
||||
|
||||
void SPC700::op_write_addri(uint8& i) {
|
||||
auto SPC700::op_write_addri(uint8& i) -> void {
|
||||
dp.l = op_readpc();
|
||||
dp.h = op_readpc();
|
||||
op_io();
|
||||
|
@ -228,21 +228,21 @@ void SPC700::op_write_addri(uint8& i) {
|
|||
op_write(dp, regs.a);
|
||||
}
|
||||
|
||||
void SPC700::op_write_dp(uint8& r) {
|
||||
auto SPC700::op_write_dp(uint8& r) -> void {
|
||||
dp = op_readpc();
|
||||
op_readdp(dp);
|
||||
op_writedp(dp, r);
|
||||
}
|
||||
|
||||
void SPC700::op_write_dpi(uint8& r, uint8& i) {
|
||||
auto SPC700::op_write_dpi(uint8& r, uint8& i) -> void {
|
||||
dp = op_readpc() + i;
|
||||
op_io();
|
||||
op_readdp(dp);
|
||||
op_writedp(dp, r);
|
||||
}
|
||||
|
||||
template<uint8 (SPC700::*op)(uint8, uint8)>
|
||||
void SPC700::op_write_dp_const() {
|
||||
template<auto (SPC700::*op)(uint8, uint8) -> uint8>
|
||||
auto SPC700::op_write_dp_const() -> void {
|
||||
rd = op_readpc();
|
||||
dp = op_readpc();
|
||||
wr = op_readdp(dp);
|
||||
|
@ -250,8 +250,8 @@ void SPC700::op_write_dp_const() {
|
|||
op != &SPC700::op_cmp ? op_writedp(dp, wr) : op_io();
|
||||
}
|
||||
|
||||
template<uint8 (SPC700::*op)(uint8, uint8)>
|
||||
void SPC700::op_write_dp_dp() {
|
||||
template<auto (SPC700::*op)(uint8, uint8) -> uint8>
|
||||
auto SPC700::op_write_dp_dp() -> void {
|
||||
sp = op_readpc();
|
||||
rd = op_readdp(sp);
|
||||
dp = op_readpc();
|
||||
|
@ -260,8 +260,8 @@ void SPC700::op_write_dp_dp() {
|
|||
op != &SPC700::op_cmp ? op_writedp(dp, wr) : op_io();
|
||||
}
|
||||
|
||||
template<uint8 (SPC700::*op)(uint8, uint8)>
|
||||
void SPC700::op_write_ix_iy() {
|
||||
template<auto (SPC700::*op)(uint8, uint8) -> uint8>
|
||||
auto SPC700::op_write_ix_iy() -> void {
|
||||
op_io();
|
||||
rd = op_readdp(regs.y);
|
||||
wr = op_readdp(regs.x);
|
||||
|
@ -271,7 +271,7 @@ void SPC700::op_write_ix_iy() {
|
|||
|
||||
//
|
||||
|
||||
void SPC700::op_bne_dp() {
|
||||
auto SPC700::op_bne_dp() -> void {
|
||||
dp = op_readpc();
|
||||
sp = op_readdp(dp);
|
||||
rd = op_readpc();
|
||||
|
@ -282,7 +282,7 @@ void SPC700::op_bne_dp() {
|
|||
regs.pc += (int8)rd;
|
||||
}
|
||||
|
||||
void SPC700::op_bne_dpdec() {
|
||||
auto SPC700::op_bne_dpdec() -> void {
|
||||
dp = op_readpc();
|
||||
wr = op_readdp(dp);
|
||||
op_writedp(dp, --wr);
|
||||
|
@ -293,7 +293,7 @@ void SPC700::op_bne_dpdec() {
|
|||
regs.pc += (int8)rd;
|
||||
}
|
||||
|
||||
void SPC700::op_bne_dpx() {
|
||||
auto SPC700::op_bne_dpx() -> void {
|
||||
dp = op_readpc();
|
||||
op_io();
|
||||
sp = op_readdp(dp + regs.x);
|
||||
|
@ -305,7 +305,7 @@ void SPC700::op_bne_dpx() {
|
|||
regs.pc += (int8)rd;
|
||||
}
|
||||
|
||||
void SPC700::op_bne_ydec() {
|
||||
auto SPC700::op_bne_ydec() -> void {
|
||||
rd = op_readpc();
|
||||
op_io();
|
||||
op_io();
|
||||
|
@ -315,7 +315,7 @@ void SPC700::op_bne_ydec() {
|
|||
regs.pc += (int8)rd;
|
||||
}
|
||||
|
||||
void SPC700::op_brk() {
|
||||
auto SPC700::op_brk() -> void {
|
||||
rd.l = op_read(0xffde);
|
||||
rd.h = op_read(0xffdf);
|
||||
op_io();
|
||||
|
@ -328,19 +328,19 @@ void SPC700::op_brk() {
|
|||
regs.p.i = 0;
|
||||
}
|
||||
|
||||
void SPC700::op_clv() {
|
||||
auto SPC700::op_clv() -> void {
|
||||
op_io();
|
||||
regs.p.v = 0;
|
||||
regs.p.h = 0;
|
||||
}
|
||||
|
||||
void SPC700::op_cmc() {
|
||||
auto SPC700::op_cmc() -> void {
|
||||
op_io();
|
||||
op_io();
|
||||
regs.p.c = !regs.p.c;
|
||||
}
|
||||
|
||||
void SPC700::op_daa() {
|
||||
auto SPC700::op_daa() -> void {
|
||||
op_io();
|
||||
op_io();
|
||||
if(regs.p.c || (regs.a) > 0x99) {
|
||||
|
@ -354,7 +354,7 @@ void SPC700::op_daa() {
|
|||
regs.p.z = (regs.a == 0);
|
||||
}
|
||||
|
||||
void SPC700::op_das() {
|
||||
auto SPC700::op_das() -> void {
|
||||
op_io();
|
||||
op_io();
|
||||
if(!regs.p.c || (regs.a) > 0x99) {
|
||||
|
@ -368,7 +368,7 @@ void SPC700::op_das() {
|
|||
regs.p.z = (regs.a == 0);
|
||||
}
|
||||
|
||||
void SPC700::op_div_ya_x() {
|
||||
auto SPC700::op_div_ya_x() -> void {
|
||||
op_io();
|
||||
op_io();
|
||||
op_io();
|
||||
|
@ -399,13 +399,13 @@ void SPC700::op_div_ya_x() {
|
|||
regs.p.z = (regs.a == 0);
|
||||
}
|
||||
|
||||
void SPC700::op_jmp_addr() {
|
||||
auto SPC700::op_jmp_addr() -> void {
|
||||
rd.l = op_readpc();
|
||||
rd.h = op_readpc();
|
||||
regs.pc = rd;
|
||||
}
|
||||
|
||||
void SPC700::op_jmp_iaddrx() {
|
||||
auto SPC700::op_jmp_iaddrx() -> void {
|
||||
dp.l = op_readpc();
|
||||
dp.h = op_readpc();
|
||||
op_io();
|
||||
|
@ -415,7 +415,7 @@ void SPC700::op_jmp_iaddrx() {
|
|||
regs.pc = rd;
|
||||
}
|
||||
|
||||
void SPC700::op_jsp_dp() {
|
||||
auto SPC700::op_jsp_dp() -> void {
|
||||
rd = op_readpc();
|
||||
op_io();
|
||||
op_io();
|
||||
|
@ -424,7 +424,7 @@ void SPC700::op_jsp_dp() {
|
|||
regs.pc = 0xff00 | rd;
|
||||
}
|
||||
|
||||
void SPC700::op_jsr_addr() {
|
||||
auto SPC700::op_jsr_addr() -> void {
|
||||
rd.l = op_readpc();
|
||||
rd.h = op_readpc();
|
||||
op_io();
|
||||
|
@ -435,7 +435,7 @@ void SPC700::op_jsr_addr() {
|
|||
regs.pc = rd;
|
||||
}
|
||||
|
||||
void SPC700::op_jst() {
|
||||
auto SPC700::op_jst() -> void {
|
||||
dp = 0xffde - ((opcode >> 4) << 1);
|
||||
rd.l = op_read(dp++);
|
||||
rd.h = op_read(dp++);
|
||||
|
@ -447,7 +447,7 @@ void SPC700::op_jst() {
|
|||
regs.pc = rd;
|
||||
}
|
||||
|
||||
void SPC700::op_lda_ixinc() {
|
||||
auto SPC700::op_lda_ixinc() -> void {
|
||||
op_io();
|
||||
regs.a = op_readdp(regs.x++);
|
||||
op_io();
|
||||
|
@ -455,7 +455,7 @@ void SPC700::op_lda_ixinc() {
|
|||
regs.p.z = regs.a == 0;
|
||||
}
|
||||
|
||||
void SPC700::op_mul_ya() {
|
||||
auto SPC700::op_mul_ya() -> void {
|
||||
op_io();
|
||||
op_io();
|
||||
op_io();
|
||||
|
@ -472,17 +472,17 @@ void SPC700::op_mul_ya() {
|
|||
regs.p.z = (regs.y == 0);
|
||||
}
|
||||
|
||||
void SPC700::op_nop() {
|
||||
auto SPC700::op_nop() -> void {
|
||||
op_io();
|
||||
}
|
||||
|
||||
void SPC700::op_plp() {
|
||||
auto SPC700::op_plp() -> void {
|
||||
op_io();
|
||||
op_io();
|
||||
regs.p = op_readsp();
|
||||
}
|
||||
|
||||
void SPC700::op_rti() {
|
||||
auto SPC700::op_rti() -> void {
|
||||
regs.p = op_readsp();
|
||||
rd.l = op_readsp();
|
||||
rd.h = op_readsp();
|
||||
|
@ -491,7 +491,7 @@ void SPC700::op_rti() {
|
|||
regs.pc = rd;
|
||||
}
|
||||
|
||||
void SPC700::op_rts() {
|
||||
auto SPC700::op_rts() -> void {
|
||||
rd.l = op_readsp();
|
||||
rd.h = op_readsp();
|
||||
op_io();
|
||||
|
@ -499,7 +499,7 @@ void SPC700::op_rts() {
|
|||
regs.pc = rd;
|
||||
}
|
||||
|
||||
void SPC700::op_sta_idpx() {
|
||||
auto SPC700::op_sta_idpx() -> void {
|
||||
sp = op_readpc() + regs.x;
|
||||
op_io();
|
||||
dp.l = op_readdp(sp++);
|
||||
|
@ -508,7 +508,7 @@ void SPC700::op_sta_idpx() {
|
|||
op_write(dp, regs.a);
|
||||
}
|
||||
|
||||
void SPC700::op_sta_idpy() {
|
||||
auto SPC700::op_sta_idpy() -> void {
|
||||
sp = op_readpc();
|
||||
dp.l = op_readdp(sp++);
|
||||
dp.h = op_readdp(sp++);
|
||||
|
@ -518,33 +518,33 @@ void SPC700::op_sta_idpy() {
|
|||
op_write(dp, regs.a);
|
||||
}
|
||||
|
||||
void SPC700::op_sta_ix() {
|
||||
auto SPC700::op_sta_ix() -> void {
|
||||
op_io();
|
||||
op_readdp(regs.x);
|
||||
op_writedp(regs.x, regs.a);
|
||||
}
|
||||
|
||||
void SPC700::op_sta_ixinc() {
|
||||
auto SPC700::op_sta_ixinc() -> void {
|
||||
op_io();
|
||||
op_io();
|
||||
op_writedp(regs.x++, regs.a);
|
||||
}
|
||||
|
||||
void SPC700::op_stw_dp() {
|
||||
auto SPC700::op_stw_dp() -> void {
|
||||
dp = op_readpc();
|
||||
op_readdp(dp);
|
||||
op_writedp(dp++, regs.a);
|
||||
op_writedp(dp++, regs.y);
|
||||
}
|
||||
|
||||
void SPC700::op_wait() {
|
||||
auto SPC700::op_wait() -> void {
|
||||
while(true) {
|
||||
op_io();
|
||||
op_io();
|
||||
}
|
||||
}
|
||||
|
||||
void SPC700::op_xcn() {
|
||||
auto SPC700::op_xcn() -> void {
|
||||
op_io();
|
||||
op_io();
|
||||
op_io();
|
||||
|
|
|
@ -1,19 +1,19 @@
|
|||
alwaysinline uint8 op_readpc() {
|
||||
alwaysinline auto op_readpc() -> uint8 {
|
||||
return op_read(regs.pc++);
|
||||
}
|
||||
|
||||
alwaysinline uint8 op_readsp() {
|
||||
alwaysinline auto op_readsp() -> uint8 {
|
||||
return op_read(0x0100 | ++regs.s);
|
||||
}
|
||||
|
||||
alwaysinline void op_writesp(uint8 data) {
|
||||
alwaysinline auto op_writesp(uint8 data) -> void {
|
||||
return op_write(0x0100 | regs.s--, data);
|
||||
}
|
||||
|
||||
alwaysinline uint8 op_readdp(uint8 addr) {
|
||||
alwaysinline auto op_readdp(uint8 addr) -> uint8 {
|
||||
return op_read((regs.p.p << 8) + addr);
|
||||
}
|
||||
|
||||
alwaysinline void op_writedp(uint8 addr, uint8 data) {
|
||||
alwaysinline auto op_writedp(uint8 addr, uint8 data) -> void {
|
||||
return op_write((regs.p.p << 8) + addr, data);
|
||||
}
|
||||
|
|
|
@ -1,51 +1,51 @@
|
|||
struct flag_t {
|
||||
bool n, v, p, b, h, i, z, c;
|
||||
|
||||
inline operator unsigned() const {
|
||||
struct Flag {
|
||||
inline operator uint() const {
|
||||
return (n << 7) | (v << 6) | (p << 5) | (b << 4)
|
||||
| (h << 3) | (i << 2) | (z << 1) | (c << 0);
|
||||
}
|
||||
|
||||
inline unsigned operator=(uint8 data) {
|
||||
inline auto operator=(uint8 data) -> uint {
|
||||
n = data & 0x80; v = data & 0x40; p = data & 0x20; b = data & 0x10;
|
||||
h = data & 0x08; i = data & 0x04; z = data & 0x02; c = data & 0x01;
|
||||
return data;
|
||||
}
|
||||
|
||||
inline unsigned operator|=(uint8 data) { return operator=(operator unsigned() | data); }
|
||||
inline unsigned operator^=(uint8 data) { return operator=(operator unsigned() ^ data); }
|
||||
inline unsigned operator&=(uint8 data) { return operator=(operator unsigned() & data); }
|
||||
inline auto operator|=(uint8 data) -> uint { return operator=(operator uint() | data); }
|
||||
inline auto operator^=(uint8 data) -> uint { return operator=(operator uint() ^ data); }
|
||||
inline auto operator&=(uint8 data) -> uint { return operator=(operator uint() & data); }
|
||||
|
||||
bool n, v, p, b, h, i, z, c;
|
||||
};
|
||||
|
||||
struct word_t {
|
||||
struct Word {
|
||||
inline operator uint() const { return w; }
|
||||
inline auto operator=(uint data) -> uint { return w = data; }
|
||||
|
||||
inline auto operator++() -> uint { return ++w; }
|
||||
inline auto operator--() -> uint { return --w; }
|
||||
|
||||
inline auto operator++(int) -> uint { unsigned data = w++; return data; }
|
||||
inline auto operator--(int) -> uint { unsigned data = w--; return data; }
|
||||
|
||||
inline auto operator+=(uint data) -> uint { return w += data;; }
|
||||
inline auto operator-=(uint data) -> uint { return w -= data;; }
|
||||
|
||||
inline auto operator|=(uint data) -> uint { return w |= data; }
|
||||
inline auto operator^=(uint data) -> uint { return w ^= data; }
|
||||
inline auto operator&=(uint data) -> uint { return w &= data; }
|
||||
|
||||
union {
|
||||
uint16 w;
|
||||
struct { uint8 order_lsb2(l, h); };
|
||||
};
|
||||
|
||||
inline operator unsigned() const { return w; }
|
||||
inline unsigned operator=(unsigned data) { return w = data; }
|
||||
|
||||
inline unsigned operator++() { return ++w; }
|
||||
inline unsigned operator--() { return --w; }
|
||||
|
||||
inline unsigned operator++(int) { unsigned data = w++; return data; }
|
||||
inline unsigned operator--(int) { unsigned data = w--; return data; }
|
||||
|
||||
inline unsigned operator+=(unsigned data) { return w += data;; }
|
||||
inline unsigned operator-=(unsigned data) { return w -= data;; }
|
||||
|
||||
inline unsigned operator|=(unsigned data) { return w |= data; }
|
||||
inline unsigned operator^=(unsigned data) { return w ^= data; }
|
||||
inline unsigned operator&=(unsigned data) { return w &= data; }
|
||||
};
|
||||
|
||||
struct regs_t {
|
||||
word_t pc;
|
||||
struct Regs {
|
||||
Word pc;
|
||||
union {
|
||||
uint16 ya;
|
||||
struct { uint8 order_lsb2(a, y); };
|
||||
};
|
||||
uint8 x, s;
|
||||
flag_t p;
|
||||
Flag p;
|
||||
};
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
void SPC700::serialize(serializer& s) {
|
||||
auto SPC700::serialize(serializer& s) -> void {
|
||||
s.integer(regs.pc);
|
||||
s.integer(regs.a);
|
||||
s.integer(regs.x);
|
||||
|
|
|
@ -8,7 +8,7 @@ namespace Processor {
|
|||
#include "disassembler.cpp"
|
||||
#include "serialization.cpp"
|
||||
|
||||
void SPC700::op_step() {
|
||||
auto SPC700::op_step() -> void {
|
||||
switch(opcode = op_readpc()) {
|
||||
case 0x00: return op_nop();
|
||||
case 0x01: return op_jst();
|
||||
|
|
|
@ -4,102 +4,103 @@
|
|||
namespace Processor {
|
||||
|
||||
struct SPC700 {
|
||||
virtual void op_io() = 0;
|
||||
virtual uint8 op_read(uint16 addr) = 0;
|
||||
virtual void op_write(uint16 addr, uint8 data) = 0;
|
||||
void op_step();
|
||||
virtual auto op_io() -> void = 0;
|
||||
virtual auto op_read(uint16 addr) -> uint8 = 0;
|
||||
virtual auto op_write(uint16 addr, uint8 data) -> void = 0;
|
||||
virtual auto disassembler_read(uint16 addr) -> uint8 = 0;
|
||||
|
||||
virtual uint8 disassembler_read(uint16 addr) = 0;
|
||||
auto op_step() -> void;
|
||||
|
||||
auto serialize(serializer&) -> void;
|
||||
|
||||
auto disassemble(uint16 addr, bool p) -> string;
|
||||
|
||||
#include "registers.hpp"
|
||||
#include "memory.hpp"
|
||||
|
||||
regs_t regs;
|
||||
word_t dp, sp, rd, wr, bit, ya;
|
||||
Regs regs;
|
||||
Word dp, sp, rd, wr, bit, ya;
|
||||
uint8 opcode;
|
||||
|
||||
void serialize(serializer&);
|
||||
string disassemble_opcode(uint16 addr, bool p);
|
||||
|
||||
protected:
|
||||
uint8 op_adc(uint8, uint8);
|
||||
uint8 op_and(uint8, uint8);
|
||||
uint8 op_asl(uint8);
|
||||
uint8 op_cmp(uint8, uint8);
|
||||
uint8 op_dec(uint8);
|
||||
uint8 op_eor(uint8, uint8);
|
||||
uint8 op_inc(uint8);
|
||||
uint8 op_ld (uint8, uint8);
|
||||
uint8 op_lsr(uint8);
|
||||
uint8 op_or (uint8, uint8);
|
||||
uint8 op_rol(uint8);
|
||||
uint8 op_ror(uint8);
|
||||
uint8 op_sbc(uint8, uint8);
|
||||
uint8 op_st (uint8, uint8);
|
||||
uint16 op_adw(uint16, uint16);
|
||||
uint16 op_cpw(uint16, uint16);
|
||||
uint16 op_ldw(uint16, uint16);
|
||||
uint16 op_sbw(uint16, uint16);
|
||||
auto op_adc(uint8, uint8) -> uint8;
|
||||
auto op_and(uint8, uint8) -> uint8;
|
||||
auto op_asl(uint8) -> uint8;
|
||||
auto op_cmp(uint8, uint8) -> uint8;
|
||||
auto op_dec(uint8) -> uint8;
|
||||
auto op_eor(uint8, uint8) -> uint8;
|
||||
auto op_inc(uint8) -> uint8;
|
||||
auto op_ld (uint8, uint8) -> uint8;
|
||||
auto op_lsr(uint8) -> uint8;
|
||||
auto op_or (uint8, uint8) -> uint8;
|
||||
auto op_rol(uint8) -> uint8;
|
||||
auto op_ror(uint8) -> uint8;
|
||||
auto op_sbc(uint8, uint8) -> uint8;
|
||||
auto op_st (uint8, uint8) -> uint8;
|
||||
auto op_adw(uint16, uint16) -> uint16;
|
||||
auto op_cpw(uint16, uint16) -> uint16;
|
||||
auto op_ldw(uint16, uint16) -> uint16;
|
||||
auto op_sbw(uint16, uint16) -> uint16;
|
||||
|
||||
template<uint8 (SPC700::*op)(uint8)> void op_adjust(uint8&);
|
||||
template<uint8 (SPC700::*op)(uint8)> void op_adjust_addr();
|
||||
template<uint8 (SPC700::*op)(uint8)> void op_adjust_dp();
|
||||
void op_adjust_dpw(signed);
|
||||
template<uint8 (SPC700::*op)(uint8)> void op_adjust_dpx();
|
||||
void op_branch(bool);
|
||||
void op_branch_bit();
|
||||
void op_pull(uint8&);
|
||||
void op_push(uint8);
|
||||
template<uint8 (SPC700::*op)(uint8, uint8)> void op_read_addr(uint8&);
|
||||
template<uint8 (SPC700::*op)(uint8, uint8)> void op_read_addri(uint8&);
|
||||
template<uint8 (SPC700::*op)(uint8, uint8)> void op_read_const(uint8&);
|
||||
template<uint8 (SPC700::*op)(uint8, uint8)> void op_read_dp(uint8&);
|
||||
template<uint8 (SPC700::*op)(uint8, uint8)> void op_read_dpi(uint8&, uint8&);
|
||||
template<uint16 (SPC700::*op)(uint16, uint16)> void op_read_dpw();
|
||||
template<uint8 (SPC700::*op)(uint8, uint8)> void op_read_idpx();
|
||||
template<uint8 (SPC700::*op)(uint8, uint8)> void op_read_idpy();
|
||||
template<uint8 (SPC700::*op)(uint8, uint8)> void op_read_ix();
|
||||
void op_set_addr_bit();
|
||||
void op_set_bit();
|
||||
void op_set_flag(bool&, bool);
|
||||
void op_test_addr(bool);
|
||||
void op_transfer(uint8&, uint8&);
|
||||
void op_write_addr(uint8&);
|
||||
void op_write_addri(uint8&);
|
||||
void op_write_dp(uint8&);
|
||||
void op_write_dpi(uint8&, uint8&);
|
||||
template<uint8 (SPC700::*op)(uint8, uint8)> void op_write_dp_const();
|
||||
template<uint8 (SPC700::*op)(uint8, uint8)> void op_write_dp_dp();
|
||||
template<uint8 (SPC700::*op)(uint8, uint8)> void op_write_ix_iy();
|
||||
template<auto (SPC700::*op)(uint8) -> uint8> auto op_adjust(uint8&) -> void;
|
||||
template<auto (SPC700::*op)(uint8) -> uint8> auto op_adjust_addr() -> void;
|
||||
template<auto (SPC700::*op)(uint8) -> uint8> auto op_adjust_dp() -> void;
|
||||
auto op_adjust_dpw(int) -> void;
|
||||
template<auto (SPC700::*op)(uint8) -> uint8> auto op_adjust_dpx() -> void;
|
||||
auto op_branch(bool) -> void;
|
||||
auto op_branch_bit() -> void;
|
||||
auto op_pull(uint8&) -> void;
|
||||
auto op_push(uint8) -> void;
|
||||
template<auto (SPC700::*op)(uint8, uint8) -> uint8> auto op_read_addr(uint8&) -> void;
|
||||
template<auto (SPC700::*op)(uint8, uint8) -> uint8> auto op_read_addri(uint8&) -> void;
|
||||
template<auto (SPC700::*op)(uint8, uint8) -> uint8> auto op_read_const(uint8&) -> void;
|
||||
template<auto (SPC700::*op)(uint8, uint8) -> uint8> auto op_read_dp(uint8&) -> void;
|
||||
template<auto (SPC700::*op)(uint8, uint8) -> uint8> auto op_read_dpi(uint8&, uint8&) -> void;
|
||||
template<auto (SPC700::*op)(uint16, uint16) -> uint16> auto op_read_dpw() -> void;
|
||||
template<auto (SPC700::*op)(uint8, uint8) -> uint8> auto op_read_idpx() -> void;
|
||||
template<auto (SPC700::*op)(uint8, uint8) -> uint8> auto op_read_idpy() -> void;
|
||||
template<auto (SPC700::*op)(uint8, uint8) -> uint8> auto op_read_ix() -> void;
|
||||
auto op_set_addr_bit() -> void;
|
||||
auto op_set_bit() -> void;
|
||||
auto op_set_flag(bool&, bool) -> void;
|
||||
auto op_test_addr(bool) -> void;
|
||||
auto op_transfer(uint8&, uint8&) -> void;
|
||||
auto op_write_addr(uint8&) -> void;
|
||||
auto op_write_addri(uint8&) -> void;
|
||||
auto op_write_dp(uint8&) -> void;
|
||||
auto op_write_dpi(uint8&, uint8&) -> void;
|
||||
template<auto (SPC700::*op)(uint8, uint8) -> uint8> auto op_write_dp_const() -> void;
|
||||
template<auto (SPC700::*op)(uint8, uint8) -> uint8> auto op_write_dp_dp() -> void;
|
||||
template<auto (SPC700::*op)(uint8, uint8) -> uint8> auto op_write_ix_iy() -> void;
|
||||
|
||||
void op_bne_dp();
|
||||
void op_bne_dpdec();
|
||||
void op_bne_dpx();
|
||||
void op_bne_ydec();
|
||||
void op_brk();
|
||||
void op_clv();
|
||||
void op_cmc();
|
||||
void op_daa();
|
||||
void op_das();
|
||||
void op_div_ya_x();
|
||||
void op_jmp_addr();
|
||||
void op_jmp_iaddrx();
|
||||
void op_jsp_dp();
|
||||
void op_jsr_addr();
|
||||
void op_jst();
|
||||
void op_lda_ixinc();
|
||||
void op_mul_ya();
|
||||
void op_nop();
|
||||
void op_plp();
|
||||
void op_rti();
|
||||
void op_rts();
|
||||
void op_sta_idpx();
|
||||
void op_sta_idpy();
|
||||
void op_sta_ix();
|
||||
void op_sta_ixinc();
|
||||
void op_stw_dp();
|
||||
void op_wait();
|
||||
void op_xcn();
|
||||
auto op_bne_dp() -> void;
|
||||
auto op_bne_dpdec() -> void;
|
||||
auto op_bne_dpx() -> void;
|
||||
auto op_bne_ydec() -> void;
|
||||
auto op_brk() -> void;
|
||||
auto op_clv() -> void;
|
||||
auto op_cmc() -> void;
|
||||
auto op_daa() -> void;
|
||||
auto op_das() -> void;
|
||||
auto op_div_ya_x() -> void;
|
||||
auto op_jmp_addr() -> void;
|
||||
auto op_jmp_iaddrx() -> void;
|
||||
auto op_jsp_dp() -> void;
|
||||
auto op_jsr_addr() -> void;
|
||||
auto op_jst() -> void;
|
||||
auto op_lda_ixinc() -> void;
|
||||
auto op_mul_ya() -> void;
|
||||
auto op_nop() -> void;
|
||||
auto op_plp() -> void;
|
||||
auto op_rti() -> void;
|
||||
auto op_rts() -> void;
|
||||
auto op_sta_idpx() -> void;
|
||||
auto op_sta_idpy() -> void;
|
||||
auto op_sta_ix() -> void;
|
||||
auto op_sta_ixinc() -> void;
|
||||
auto op_stw_dp() -> void;
|
||||
auto op_wait() -> void;
|
||||
auto op_xcn() -> void;
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -1,7 +1,5 @@
|
|||
#ifdef NECDSP_CPP
|
||||
|
||||
string NECDSP::disassemble(uint14 ip) {
|
||||
string output = { hex<4>(ip), " " };
|
||||
auto uPD96050::disassemble(uint14 ip) -> string {
|
||||
string output = {hex(ip, 4L), " "};
|
||||
uint24 opcode = programROM[ip];
|
||||
uint2 type = opcode >> 22;
|
||||
|
||||
|
@ -98,7 +96,7 @@ string NECDSP::disassemble(uint14 ip) {
|
|||
}
|
||||
|
||||
if(dphm) {
|
||||
output.append("\n m", hex<1>(dphm));
|
||||
output.append("\n m", hex(dphm, 1L));
|
||||
}
|
||||
|
||||
if(rpdcr == 1) {
|
||||
|
@ -160,7 +158,7 @@ string NECDSP::disassemble(uint14 ip) {
|
|||
default: output.append("?????? "); break;
|
||||
}
|
||||
|
||||
output.append("$", hex<4>(jp));
|
||||
output.append("$", hex(jp, 4L));
|
||||
}
|
||||
|
||||
if(type == 3) { //LD
|
||||
|
@ -168,7 +166,7 @@ string NECDSP::disassemble(uint14 ip) {
|
|||
uint16 id = opcode >> 6;
|
||||
uint4 dst = opcode >> 0;
|
||||
|
||||
output.append("$", hex<4>(id), ",");
|
||||
output.append("$", hex(id, 4L), ",");
|
||||
|
||||
switch(dst) {
|
||||
case 0: output.append("non"); break;
|
||||
|
@ -192,5 +190,3 @@ string NECDSP::disassemble(uint14 ip) {
|
|||
|
||||
return output;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
void uPD96050::exec() {
|
||||
auto uPD96050::exec() -> void {
|
||||
uint24 opcode = programROM[regs.pc++];
|
||||
switch(opcode >> 22) {
|
||||
case 0: exec_op(opcode); break;
|
||||
case 1: exec_rt(opcode); break;
|
||||
case 2: exec_jp(opcode); break;
|
||||
case 3: exec_ld(opcode); break;
|
||||
case 0: execOP(opcode); break;
|
||||
case 1: execRT(opcode); break;
|
||||
case 2: execJP(opcode); break;
|
||||
case 3: execLD(opcode); break;
|
||||
}
|
||||
|
||||
int32 result = (int32)regs.k * regs.l; //sign + 30-bit result
|
||||
|
@ -12,7 +12,7 @@ void uPD96050::exec() {
|
|||
regs.n = result << 1; //store low 15-bits + zero
|
||||
}
|
||||
|
||||
void uPD96050::exec_op(uint24 opcode) {
|
||||
auto uPD96050::execOP(uint24 opcode) -> void {
|
||||
uint2 pselect = opcode >> 20; //P select
|
||||
uint4 alu = opcode >> 16; //ALU operation mode
|
||||
uint1 asl = opcode >> 15; //accumulator select
|
||||
|
@ -123,7 +123,7 @@ void uPD96050::exec_op(uint24 opcode) {
|
|||
}
|
||||
}
|
||||
|
||||
exec_ld((idb << 6) + dst);
|
||||
execLD((idb << 6) + dst);
|
||||
|
||||
switch(dpl) {
|
||||
case 1: regs.dp = (regs.dp & 0xf0) + ((regs.dp + 1) & 0x0f); break; //DPINC
|
||||
|
@ -136,12 +136,12 @@ void uPD96050::exec_op(uint24 opcode) {
|
|||
if(rpdcr) regs.rp--;
|
||||
}
|
||||
|
||||
void uPD96050::exec_rt(uint24 opcode) {
|
||||
exec_op(opcode);
|
||||
auto uPD96050::execRT(uint24 opcode) -> void {
|
||||
execOP(opcode);
|
||||
regs.pc = regs.stack[--regs.sp];
|
||||
}
|
||||
|
||||
void uPD96050::exec_jp(uint24 opcode) {
|
||||
auto uPD96050::execJP(uint24 opcode) -> void {
|
||||
uint9 brch = opcode >> 13; //branch
|
||||
uint11 na = opcode >> 2; //next address
|
||||
uint2 bank = opcode >> 0; //bank address
|
||||
|
@ -197,7 +197,7 @@ void uPD96050::exec_jp(uint24 opcode) {
|
|||
}
|
||||
}
|
||||
|
||||
void uPD96050::exec_ld(uint24 opcode) {
|
||||
auto uPD96050::execLD(uint24 opcode) -> void {
|
||||
uint16 id = opcode >> 6; //immediate data
|
||||
uint4 dst = opcode >> 0; //destination
|
||||
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
uint8 uPD96050::sr_read() {
|
||||
auto uPD96050::readSR() -> uint8 {
|
||||
return regs.sr >> 8;
|
||||
}
|
||||
|
||||
void uPD96050::sr_write(uint8 data) {
|
||||
auto uPD96050::writeSR(uint8 data) -> void {
|
||||
}
|
||||
|
||||
uint8 uPD96050::dr_read() {
|
||||
auto uPD96050::readDR() -> uint8 {
|
||||
if(regs.sr.drc == 0) {
|
||||
//16-bit
|
||||
if(regs.sr.drs == 0) {
|
||||
|
@ -23,7 +23,7 @@ uint8 uPD96050::dr_read() {
|
|||
}
|
||||
}
|
||||
|
||||
void uPD96050::dr_write(uint8 data) {
|
||||
auto uPD96050::writeDR(uint8 data) -> void {
|
||||
if(regs.sr.drc == 0) {
|
||||
//16-bit
|
||||
if(regs.sr.drs == 0) {
|
||||
|
@ -41,7 +41,7 @@ void uPD96050::dr_write(uint8 data) {
|
|||
}
|
||||
}
|
||||
|
||||
uint8 uPD96050::dp_read(uint12 addr) {
|
||||
auto uPD96050::readDP(uint12 addr) -> uint8 {
|
||||
bool hi = addr & 1;
|
||||
addr = (addr >> 1) & 2047;
|
||||
|
||||
|
@ -52,7 +52,7 @@ uint8 uPD96050::dp_read(uint12 addr) {
|
|||
}
|
||||
}
|
||||
|
||||
void uPD96050::dp_write(uint12 addr, uint8 data) {
|
||||
auto uPD96050::writeDP(uint12 addr, uint8 data) -> void {
|
||||
bool hi = addr & 1;
|
||||
addr = (addr >> 1) & 2047;
|
||||
|
||||
|
|
|
@ -0,0 +1,21 @@
|
|||
uPD96050::Flag::operator uint() const {
|
||||
return (s1 << 5) + (s0 << 4) + (c << 3) + (z << 2) + (ov1 << 1) + (ov0 << 0);
|
||||
}
|
||||
|
||||
auto uPD96050::Flag::operator=(uint d) -> uint {
|
||||
s1 = d & 0x20; s0 = d & 0x10; c = d & 0x08; z = d & 0x04; ov1 = d & 0x02; ov0 = d & 0x01;
|
||||
return d;
|
||||
}
|
||||
|
||||
uPD96050::Status::operator uint() const {
|
||||
return (rqm << 15) + (usf1 << 14) + (usf0 << 13) + (drs << 12)
|
||||
+ (dma << 11) + (drc << 10) + (soc << 9) + (sic << 8)
|
||||
+ (ei << 7) + (p1 << 1) + (p0 << 0);
|
||||
}
|
||||
|
||||
auto uPD96050::Status::operator=(uint d) -> uint {
|
||||
rqm = d & 0x8000; usf1 = d & 0x4000; usf0 = d & 0x2000; drs = d & 0x1000;
|
||||
dma = d & 0x0800; drc = d & 0x0400; soc = d & 0x0200; sic = d & 0x0100;
|
||||
ei = d & 0x0080; p1 = d & 0x0002; p0 = d & 0x0001;
|
||||
return d;
|
||||
}
|
|
@ -1,51 +0,0 @@
|
|||
struct Flag {
|
||||
bool s1, s0, c, z, ov1, ov0;
|
||||
|
||||
inline operator unsigned() const {
|
||||
return (s1 << 5) + (s0 << 4) + (c << 3) + (z << 2) + (ov1 << 1) + (ov0 << 0);
|
||||
}
|
||||
|
||||
inline unsigned operator=(unsigned d) {
|
||||
s1 = d & 0x20; s0 = d & 0x10; c = d & 0x08; z = d & 0x04; ov1 = d & 0x02; ov0 = d & 0x01;
|
||||
return d;
|
||||
}
|
||||
};
|
||||
|
||||
struct Status {
|
||||
bool rqm, usf1, usf0, drs, dma, drc, soc, sic, ei, p1, p0;
|
||||
|
||||
inline operator unsigned() const {
|
||||
return (rqm << 15) + (usf1 << 14) + (usf0 << 13) + (drs << 12)
|
||||
+ (dma << 11) + (drc << 10) + (soc << 9) + (sic << 8)
|
||||
+ (ei << 7) + (p1 << 1) + (p0 << 0);
|
||||
}
|
||||
|
||||
inline unsigned operator=(unsigned d) {
|
||||
rqm = d & 0x8000; usf1 = d & 0x4000; usf0 = d & 0x2000; drs = d & 0x1000;
|
||||
dma = d & 0x0800; drc = d & 0x0400; soc = d & 0x0200; sic = d & 0x0100;
|
||||
ei = d & 0x0080; p1 = d & 0x0002; p0 = d & 0x0001;
|
||||
return d;
|
||||
}
|
||||
};
|
||||
|
||||
struct Regs {
|
||||
uint16 stack[16]; //LIFO
|
||||
varuint pc; //program counter
|
||||
varuint rp; //ROM pointer
|
||||
varuint dp; //data pointer
|
||||
uint4 sp; //stack pointer
|
||||
int16 k;
|
||||
int16 l;
|
||||
int16 m;
|
||||
int16 n;
|
||||
int16 a; //accumulator
|
||||
int16 b; //accumulator
|
||||
Flag flaga;
|
||||
Flag flagb;
|
||||
uint16 tr; //temporary register
|
||||
uint16 trb; //temporary register
|
||||
Status sr; //status register
|
||||
uint16 dr; //data register
|
||||
uint16 si;
|
||||
uint16 so;
|
||||
} regs;
|
|
@ -1,4 +1,4 @@
|
|||
void uPD96050::serialize(serializer& s) {
|
||||
auto uPD96050::serialize(serializer& s) -> void {
|
||||
s.array(dataRAM);
|
||||
|
||||
s.array(regs.stack);
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue