mirror of https://github.com/bsnes-emu/bsnes.git
Update to v102r07 release.
byuu says: Changelog: - PCE: emulated PSG volume controls (vastly enhances audio quality) - PCE: emulated PSG noise as a square wave (somewhat enhances audio quality) - PCE: added save state support (currently broken and deadlocks the emulator though) Thankfully, MAME had some rather easy to read code on how the volume adjustment works, which they apparently ripped out of expired patents. Hooray! The two remaining sound issues are: 1. the random number generator for the noise channel is definitely not hardware accurate. But it won't affect the sound quality at all. You'd only be able to tell the difference by looking at hex bytes of a stream rip. 2. I have no clue how to emulate the LFO (frequency modulation). A comment in MAME's code (they also don't emulate it) advises that they aren't aware of any games that even use it. But I'm there has to be at least one? Given LFO not being used, and the RNG not really mattering all that much ... the sound's pretty close to perfect now.
This commit is contained in:
parent
fa6cbac251
commit
7c9b78b7bb
|
@ -12,7 +12,7 @@ using namespace nall;
|
|||
|
||||
namespace Emulator {
|
||||
static const string Name = "higan";
|
||||
static const string Version = "102.06";
|
||||
static const string Version = "102.07";
|
||||
static const string Author = "byuu";
|
||||
static const string License = "GPLv3";
|
||||
static const string Website = "http://byuu.org/";
|
||||
|
|
|
@ -7,6 +7,7 @@ CPU cpu;
|
|||
#include "io.cpp"
|
||||
#include "irq.cpp"
|
||||
#include "timer.cpp"
|
||||
#include "serialization.cpp"
|
||||
|
||||
auto CPU::Enter() -> void {
|
||||
while(true) scheduler.synchronize(), cpu.main();
|
||||
|
|
|
@ -19,8 +19,15 @@ struct CPU : Processor::HuC6280, Thread {
|
|||
//timer.cpp
|
||||
auto timerStep(uint clocks) -> void;
|
||||
|
||||
//serialization.cpp
|
||||
auto serialize(serializer&) -> void;
|
||||
|
||||
vector<Thread*> peripherals;
|
||||
|
||||
private:
|
||||
uint8 ram[0x8000]; //PC Engine = 8KB, SuperGrafx = 32KB
|
||||
uint8 bram[0x800]; //PC Engine CD-ROM Backup RAM = 2KB
|
||||
|
||||
struct IRQ {
|
||||
//irq.cpp
|
||||
auto pending() const -> bool;
|
||||
|
@ -59,10 +66,6 @@ struct CPU : Processor::HuC6280, Thread {
|
|||
struct IO {
|
||||
uint8 mdr;
|
||||
} io;
|
||||
|
||||
private:
|
||||
uint8 ram[0x8000]; //PC Engine = 8KB, SuperGrafx = 32KB
|
||||
uint8 bram[0x800]; //PC Engine CD-ROM Backup RAM = 2KB
|
||||
};
|
||||
|
||||
extern CPU cpu;
|
||||
|
|
|
@ -0,0 +1,21 @@
|
|||
auto CPU::serialize(serializer& s) -> void {
|
||||
HuC6280::serialize(s);
|
||||
Thread::serialize(s);
|
||||
|
||||
s.array(ram, Model::PCEngine() ? 0x2000 : 0x8000);
|
||||
s.array(bram);
|
||||
|
||||
s.integer(irq.disableExternal);
|
||||
s.integer(irq.disableVDC);
|
||||
s.integer(irq.disableTimer);
|
||||
s.integer(irq.pendingIRQ);
|
||||
s.integer(irq.pendingVector);
|
||||
|
||||
s.integer(timer.enable);
|
||||
s.integer(timer.latch);
|
||||
s.integer(timer.value);
|
||||
s.integer(timer.clock);
|
||||
s.integer(timer.line);
|
||||
|
||||
s.integer(io.mdr);
|
||||
}
|
|
@ -10,7 +10,7 @@ Settings settings;
|
|||
Interface::Interface() {
|
||||
information.overscan = true;
|
||||
|
||||
information.capability.states = false;
|
||||
information.capability.states = true;
|
||||
information.capability.cheats = false;
|
||||
|
||||
Port controllerPort{ID::Port::Controller, "Controller Port"};
|
||||
|
@ -108,11 +108,12 @@ auto Interface::run() -> void {
|
|||
}
|
||||
|
||||
auto Interface::serialize() -> serializer {
|
||||
return {};
|
||||
system.runToSave();
|
||||
return system.serialize();
|
||||
}
|
||||
|
||||
auto Interface::unserialize(serializer& s) -> bool {
|
||||
return false;
|
||||
return system.unserialize(s);
|
||||
}
|
||||
|
||||
auto Interface::cap(const string& name) -> bool {
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
auto PSG::Channel::power(uint id) -> void {
|
||||
this->id = id;
|
||||
memory::fill(&io, sizeof(IO));
|
||||
memory::fill(&output, sizeof(Output));
|
||||
}
|
||||
|
||||
auto PSG::Channel::run() -> void {
|
||||
|
@ -19,22 +18,12 @@ auto PSG::Channel::run() -> void {
|
|||
|
||||
if(--io.noisePeriod == 0) {
|
||||
io.noisePeriod = ~io.noiseFrequency << 7;
|
||||
//todo: this should be a square wave; PRNG algorithm is also unknown
|
||||
io.noiseSample = nall::random();
|
||||
io.noiseSample = nall::random() & 1 ? ~0 : 0;
|
||||
}
|
||||
|
||||
return sample(io.noiseSample);
|
||||
}
|
||||
|
||||
auto PSG::Channel::loadWavePeriod() -> void {
|
||||
io.wavePeriod = io.waveFrequency;
|
||||
}
|
||||
|
||||
auto PSG::Channel::loadWaveSample() -> void {
|
||||
io.waveSample = io.waveBuffer[io.waveOffset];
|
||||
}
|
||||
|
||||
auto PSG::Channel::sample(uint5 sample) -> void {
|
||||
output.left = sample << 8; //<< io.volume << io.volumeLeft;
|
||||
output.right = sample << 8; //<< io.volume << io.volumeRight;
|
||||
io.output = sample;
|
||||
}
|
||||
|
|
|
@ -49,7 +49,7 @@ auto PSG::Channel::write(uint4 addr, uint8 data) -> void {
|
|||
io.waveOffset++;
|
||||
io.waveSample = io.waveBuffer[io.waveOffset];
|
||||
}
|
||||
io.volume = data.bits(0,3);
|
||||
io.volume = data.bits(0,4);
|
||||
io.direct = data.bit(6);
|
||||
io.enable = data.bit(7);
|
||||
}
|
||||
|
|
|
@ -5,25 +5,43 @@ namespace PCEngine {
|
|||
PSG psg;
|
||||
#include "io.cpp"
|
||||
#include "channel.cpp"
|
||||
#include "serialization.cpp"
|
||||
|
||||
auto PSG::Enter() -> void {
|
||||
while(true) scheduler.synchronize(), psg.main();
|
||||
}
|
||||
|
||||
auto PSG::main() -> void {
|
||||
uint left = 0, right = 0;
|
||||
static const uint5 volumeScale[16] = {
|
||||
0x00, 0x03, 0x05, 0x07, 0x09, 0x0b, 0x0d, 0x0f,
|
||||
0x10, 0x13, 0x15, 0x17, 0x19, 0x1b, 0x1d, 0x1f,
|
||||
};
|
||||
|
||||
uint5 lmal = volumeScale[io.volumeLeft];
|
||||
uint5 rmal = volumeScale[io.volumeRight];
|
||||
|
||||
double outputLeft = 0.0;
|
||||
double outputRight = 0.0;
|
||||
|
||||
for(auto C : range(6)) {
|
||||
uint5 al = channel[C].io.volume;
|
||||
uint5 lal = volumeScale[channel[C].io.volumeLeft];
|
||||
uint5 ral = volumeScale[channel[C].io.volumeRight];
|
||||
|
||||
uint5 volumeLeft = min(0x1f, (0x1f - lmal) + (0x1f - lal) + (0x1f - al));
|
||||
uint5 volumeRight = min(0x1f, (0x1f - rmal) + (0x1f - ral) + (0x1f - al));
|
||||
|
||||
channel[C].run();
|
||||
if(C == 1 && io.lfoEnable) {
|
||||
//todo: frequency modulation of channel 0 using channel 1's output
|
||||
} else {
|
||||
left += channel[C].output.left;
|
||||
right += channel[C].output.right;
|
||||
outputLeft += channel[C].io.output * volumeScalar[volumeLeft];
|
||||
outputRight += channel[C].io.output * volumeScalar[volumeRight];
|
||||
}
|
||||
}
|
||||
|
||||
stream->sample(left / 32768.0, right / 32768.0);
|
||||
//normalize 0.0 to 65536.0 => -1.0 to +1.0
|
||||
stream->sample(outputLeft / 32768.0 - 1.0, outputRight / 32768.0 - 1.0);
|
||||
step(1);
|
||||
}
|
||||
|
||||
|
@ -38,6 +56,14 @@ auto PSG::power() -> void {
|
|||
|
||||
memory::fill(&io, sizeof(IO));
|
||||
for(auto C : range(6)) channel[C].power(C);
|
||||
|
||||
double level = 65536.0 / 6.0 / 32.0; //max volume / channels / steps
|
||||
double step = 48.0 / 32.0; //48dB volume range spread over 32 steps
|
||||
for(uint n : range(31)) {
|
||||
volumeScalar[n] = level;
|
||||
level /= pow(10.0, step / 20.0);
|
||||
}
|
||||
volumeScalar[31] = 0.0;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -12,6 +12,9 @@ struct PSG : Thread {
|
|||
//io.cpp
|
||||
auto write(uint4 addr, uint8 data) -> void;
|
||||
|
||||
//serialization.cpp
|
||||
auto serialize(serializer&) -> void;
|
||||
|
||||
private:
|
||||
struct IO {
|
||||
uint3 channel;
|
||||
|
@ -26,8 +29,6 @@ private:
|
|||
//channel.cpp
|
||||
auto power(uint id) -> void;
|
||||
auto run() -> void;
|
||||
auto loadWavePeriod() -> void;
|
||||
auto loadWaveSample() -> void;
|
||||
auto sample(uint5 sample) -> void;
|
||||
|
||||
//io.cpp
|
||||
|
@ -35,7 +36,7 @@ private:
|
|||
|
||||
struct IO {
|
||||
uint12 waveFrequency;
|
||||
uint4 volume;
|
||||
uint5 volume;
|
||||
uint1 direct;
|
||||
uint1 enable;
|
||||
uint4 volumeLeft;
|
||||
|
@ -49,15 +50,14 @@ private:
|
|||
uint5 waveOffset;
|
||||
uint12 noisePeriod;
|
||||
uint5 noiseSample;
|
||||
} io;
|
||||
|
||||
struct Output {
|
||||
uint left;
|
||||
uint right;
|
||||
} output;
|
||||
uint5 output;
|
||||
} io;
|
||||
|
||||
uint id;
|
||||
} channel[6];
|
||||
|
||||
double volumeScalar[32];
|
||||
};
|
||||
|
||||
extern PSG psg;
|
||||
|
|
|
@ -0,0 +1,28 @@
|
|||
auto PSG::serialize(serializer& s) -> void {
|
||||
Thread::serialize(s);
|
||||
|
||||
s.integer(io.channel);
|
||||
s.integer(io.volumeLeft);
|
||||
s.integer(io.volumeRight);
|
||||
s.integer(io.lfoFrequency);
|
||||
s.integer(io.lfoControl);
|
||||
s.integer(io.lfoEnable);
|
||||
|
||||
for(auto C : range(6)) {
|
||||
s.integer(channel[C].io.waveFrequency);
|
||||
s.integer(channel[C].io.volume);
|
||||
s.integer(channel[C].io.direct);
|
||||
s.integer(channel[C].io.enable);
|
||||
s.integer(channel[C].io.volumeLeft);
|
||||
s.integer(channel[C].io.volumeRight);
|
||||
s.array(channel[C].io.waveBuffer);
|
||||
s.integer(channel[C].io.noiseFrequency);
|
||||
s.integer(channel[C].io.noiseEnable);
|
||||
s.integer(channel[C].io.wavePeriod);
|
||||
s.integer(channel[C].io.waveSample);
|
||||
s.integer(channel[C].io.waveOffset);
|
||||
s.integer(channel[C].io.noisePeriod);
|
||||
s.integer(channel[C].io.noiseSample);
|
||||
s.integer(channel[C].io.output);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,67 @@
|
|||
auto System::serializeInit() -> void {
|
||||
serializer s;
|
||||
|
||||
uint signature = 0;
|
||||
char version[16] = {0};
|
||||
char hash[64] = {0};
|
||||
char description[512] = {0};
|
||||
|
||||
s.integer(signature);
|
||||
s.array(version);
|
||||
s.array(hash);
|
||||
s.array(description);
|
||||
|
||||
serializeAll(s);
|
||||
information.serializeSize = s.size();
|
||||
}
|
||||
|
||||
auto System::serialize() -> serializer {
|
||||
serializer s{information.serializeSize};
|
||||
|
||||
uint signature = 0x31545342;
|
||||
char version[16] = {0};
|
||||
char hash[64] = {0};
|
||||
char description[512] = {0};
|
||||
memory::copy(&version, (const char*)Emulator::SerializerVersion, Emulator::SerializerVersion.size());
|
||||
memory::copy(&hash, (const char*)cartridge.sha256(), 64);
|
||||
|
||||
s.integer(signature);
|
||||
s.array(version);
|
||||
s.array(hash);
|
||||
s.array(description);
|
||||
|
||||
serializeAll(s);
|
||||
return s;
|
||||
}
|
||||
|
||||
auto System::unserialize(serializer& s) -> bool {
|
||||
uint signature = 0;
|
||||
char version[16] = {0};
|
||||
char hash[64] = {0};
|
||||
char description[512] = {0};
|
||||
|
||||
s.integer(signature);
|
||||
s.array(version);
|
||||
s.array(hash);
|
||||
s.array(description);
|
||||
|
||||
if(signature != 0x31545342) return false;
|
||||
if(string{version} != Emulator::SerializerVersion) return false;
|
||||
|
||||
power();
|
||||
serializeAll(s);
|
||||
return true;
|
||||
}
|
||||
|
||||
auto System::serializeAll(serializer& s) -> void {
|
||||
system.serialize(s);
|
||||
cpu.serialize(s);
|
||||
vce.serialize(s);
|
||||
vpc.serialize(s);
|
||||
vdc0.serialize(s);
|
||||
vdc1.serialize(s);
|
||||
psg.serialize(s);
|
||||
}
|
||||
|
||||
auto System::serialize(serializer& s) -> void {
|
||||
}
|
|
@ -5,11 +5,20 @@ namespace PCEngine {
|
|||
System system;
|
||||
Scheduler scheduler;
|
||||
#include "peripherals.cpp"
|
||||
#include "serialization.cpp"
|
||||
|
||||
auto System::run() -> void {
|
||||
if(scheduler.enter() == Scheduler::Event::Frame) vce.refresh();
|
||||
}
|
||||
|
||||
auto System::runToSave() -> void {
|
||||
scheduler.synchronize(cpu);
|
||||
scheduler.synchronize(vce);
|
||||
scheduler.synchronize(vdc0);
|
||||
scheduler.synchronize(vdc1);
|
||||
scheduler.synchronize(psg);
|
||||
}
|
||||
|
||||
auto System::load(Emulator::Interface* interface, Model model) -> bool {
|
||||
information = {};
|
||||
information.model = model;
|
||||
|
@ -22,6 +31,7 @@ auto System::load(Emulator::Interface* interface, Model model) -> bool {
|
|||
if(!cartridge.load()) return false;
|
||||
|
||||
cpu.load();
|
||||
serializeInit();
|
||||
this->interface = interface;
|
||||
information.colorburst = Emulator::Constants::Colorburst::NTSC;
|
||||
return information.loaded = true;
|
||||
|
|
|
@ -6,6 +6,7 @@ struct System {
|
|||
inline auto colorburst() const -> double { return information.colorburst; }
|
||||
|
||||
auto run() -> void;
|
||||
auto runToSave() -> void;
|
||||
|
||||
auto load(Emulator::Interface*, Model) -> bool;
|
||||
auto save() -> void;
|
||||
|
@ -13,6 +14,13 @@ struct System {
|
|||
|
||||
auto power() -> void;
|
||||
|
||||
//serialization.cpp
|
||||
auto serializeInit() -> void;
|
||||
auto serialize() -> serializer;
|
||||
auto unserialize(serializer&) -> bool;
|
||||
auto serializeAll(serializer&) -> void;
|
||||
auto serialize(serializer&) -> void;
|
||||
|
||||
private:
|
||||
Emulator::Interface* interface = nullptr;
|
||||
|
||||
|
@ -21,6 +29,7 @@ private:
|
|||
Model model = Model::PCEngine;
|
||||
string manifest;
|
||||
double colorburst = 0.0;
|
||||
uint serializeSize = 0;
|
||||
} information;
|
||||
};
|
||||
|
||||
|
|
|
@ -0,0 +1,13 @@
|
|||
auto VCE::serialize(serializer& s) -> void {
|
||||
Thread::serialize(s);
|
||||
|
||||
s.array(cram.data);
|
||||
s.integer(cram.address);
|
||||
|
||||
s.integer(timing.hclock);
|
||||
s.integer(timing.vclock);
|
||||
|
||||
s.integer(io.clock);
|
||||
s.integer(io.extraLine);
|
||||
s.integer(io.grayscale);
|
||||
}
|
|
@ -5,6 +5,7 @@ namespace PCEngine {
|
|||
VCE vce;
|
||||
#include "memory.cpp"
|
||||
#include "io.cpp"
|
||||
#include "serialization.cpp"
|
||||
|
||||
auto VCE::Enter() -> void {
|
||||
while(true) scheduler.synchronize(), vce.main();
|
||||
|
|
|
@ -13,6 +13,9 @@ struct VCE : Thread {
|
|||
auto read(uint3 addr) -> uint8;
|
||||
auto write(uint3 addr, uint8 data) -> void;
|
||||
|
||||
//serialization.cpp
|
||||
auto serialize(serializer&) -> void;
|
||||
|
||||
private:
|
||||
uint32 buffer[1365 * 263];
|
||||
|
||||
|
@ -21,10 +24,8 @@ private:
|
|||
auto read(uint9 addr) -> uint9;
|
||||
auto write(uint9 addr, bool a0, uint8 data) -> void;
|
||||
|
||||
uint9 address;
|
||||
|
||||
private:
|
||||
uint9 data[0x200];
|
||||
uint9 address;
|
||||
} cram;
|
||||
|
||||
struct Timing {
|
||||
|
|
|
@ -0,0 +1,83 @@
|
|||
auto VDC::serialize(serializer& s) -> void {
|
||||
Thread::serialize(s);
|
||||
|
||||
s.array(vram.data);
|
||||
s.integer(vram.addressRead);
|
||||
s.integer(vram.addressWrite);
|
||||
s.integer(vram.addressIncrement);
|
||||
s.integer(vram.dataRead);
|
||||
s.integer(vram.dataWrite);
|
||||
|
||||
s.array(satb.data);
|
||||
|
||||
s.integer(timing.horizontalSyncWidth);
|
||||
s.integer(timing.horizontalDisplayStart);
|
||||
s.integer(timing.horizontalDisplayLength);
|
||||
s.integer(timing.horizontalDisplayEnd);
|
||||
s.integer(timing.verticalSyncWidth);
|
||||
s.integer(timing.verticalDisplayStart);
|
||||
s.integer(timing.verticalDisplayLength);
|
||||
s.integer(timing.verticalDisplayEnd);
|
||||
s.integer(timing.vpulse);
|
||||
s.integer(timing.hpulse);
|
||||
s.integer(timing.hclock);
|
||||
s.integer(timing.vclock);
|
||||
s.integer(timing.hoffset);
|
||||
s.integer(timing.voffset);
|
||||
s.integer(timing.hstart);
|
||||
s.integer(timing.vstart);
|
||||
s.integer(timing.hlength);
|
||||
s.integer(timing.vlength);
|
||||
|
||||
s.integer(irq.enableCollision);
|
||||
s.integer(irq.enableOverflow);
|
||||
s.integer(irq.enableLineCoincidence);
|
||||
s.integer(irq.enableVblank);
|
||||
s.integer(irq.enableTransferVRAM);
|
||||
s.integer(irq.enableTransferSATB);
|
||||
s.integer(irq.pendingCollision);
|
||||
s.integer(irq.pendingOverflow);
|
||||
s.integer(irq.pendingLineCoincidence);
|
||||
s.integer(irq.pendingVblank);
|
||||
s.integer(irq.pendingTransferVRAM);
|
||||
s.integer(irq.pendingTransferSATB);
|
||||
s.integer(irq.line);
|
||||
|
||||
s.integer(dma.sourceIncrementMode);
|
||||
s.integer(dma.targetIncrementMode);
|
||||
s.integer(dma.satbRepeat);
|
||||
s.integer(dma.source);
|
||||
s.integer(dma.target);
|
||||
s.integer(dma.length);
|
||||
s.integer(dma.satbSource);
|
||||
s.integer(dma.vramActive);
|
||||
s.integer(dma.satbActive);
|
||||
s.integer(dma.satbPending);
|
||||
s.integer(dma.satbOffset);
|
||||
|
||||
s.integer(background.enable);
|
||||
s.integer(background.hscroll);
|
||||
s.integer(background.vscroll);
|
||||
s.integer(background.vcounter);
|
||||
s.integer(background.width);
|
||||
s.integer(background.height);
|
||||
s.integer(background.hoffset);
|
||||
s.integer(background.voffset);
|
||||
s.integer(background.color);
|
||||
s.integer(background.palette);
|
||||
|
||||
s.integer(sprite.enable);
|
||||
s.integer(sprite.color);
|
||||
s.integer(sprite.palette);
|
||||
s.integer(sprite.priority);
|
||||
//todo: serialize array<sprite.objects>
|
||||
|
||||
s.integer(io.address);
|
||||
s.integer(io.externalSync);
|
||||
s.integer(io.displayOutput);
|
||||
s.integer(io.dramRefresh);
|
||||
s.integer(io.lineCoincidence);
|
||||
s.integer(io.vramAccess);
|
||||
s.integer(io.spriteAccess);
|
||||
s.integer(io.cgMode);
|
||||
}
|
|
@ -10,6 +10,7 @@ VDC vdc1;
|
|||
#include "dma.cpp"
|
||||
#include "background.cpp"
|
||||
#include "sprite.cpp"
|
||||
#include "serialization.cpp"
|
||||
|
||||
auto VDC::Enter() -> void {
|
||||
while(true) {
|
||||
|
|
|
@ -16,6 +16,9 @@ struct VDC : Thread {
|
|||
auto read(uint2 addr) -> uint8;
|
||||
auto write(uint2 addr, uint8 data) -> void;
|
||||
|
||||
//serialization.cpp
|
||||
auto serialize(serializer&) -> void;
|
||||
|
||||
private:
|
||||
uint9 data;
|
||||
|
||||
|
@ -24,15 +27,14 @@ private:
|
|||
auto read(uint16 addr) -> uint16;
|
||||
auto write(uint16 addr, uint16 data) -> void;
|
||||
|
||||
uint16 data[0x8000];
|
||||
|
||||
uint16 addressRead;
|
||||
uint16 addressWrite;
|
||||
uint16 addressIncrement;
|
||||
|
||||
uint16 dataRead;
|
||||
uint16 dataWrite;
|
||||
|
||||
private:
|
||||
uint16 data[0x8000];
|
||||
} vram;
|
||||
|
||||
struct SATB {
|
||||
|
@ -40,7 +42,6 @@ private:
|
|||
auto read(uint8 addr) -> uint16;
|
||||
auto write(uint8 addr, uint16 data) -> void;
|
||||
|
||||
private:
|
||||
uint16 data[0x100];
|
||||
} satb;
|
||||
|
||||
|
@ -191,10 +192,6 @@ private:
|
|||
uint2 vramAccess;
|
||||
uint2 spriteAccess;
|
||||
bool cgMode;
|
||||
|
||||
//$0400 CR
|
||||
bool colorBlur;
|
||||
bool grayscale;
|
||||
} io;
|
||||
};
|
||||
|
||||
|
|
|
@ -0,0 +1,9 @@
|
|||
auto VPC::serialize(serializer& s) -> void {
|
||||
for(auto n : range(4)) {
|
||||
s.integer(settings[n].enableVDC0);
|
||||
s.integer(settings[n].enableVDC1);
|
||||
s.integer(settings[n].priority);
|
||||
}
|
||||
s.array(window);
|
||||
s.integer(select);
|
||||
}
|
|
@ -3,6 +3,7 @@
|
|||
namespace PCEngine {
|
||||
|
||||
VPC vpc;
|
||||
#include "serialization.cpp"
|
||||
|
||||
auto VPC::bus(uint hclock) -> uint9 {
|
||||
//bus values are direct CRAM entry indexes:
|
||||
|
|
|
@ -8,6 +8,9 @@ struct VPC {
|
|||
auto write(uint5 addr, uint8 data) -> void;
|
||||
auto store(uint2 addr, uint8 data) -> void;
|
||||
|
||||
//serialization.cpp
|
||||
auto serialize(serializer&) -> void;
|
||||
|
||||
private:
|
||||
struct Settings {
|
||||
bool enableVDC0;
|
||||
|
|
|
@ -26,6 +26,7 @@ namespace Processor {
|
|||
#include "instruction.cpp"
|
||||
#include "instructions.cpp"
|
||||
#include "disassembler.cpp"
|
||||
#include "serialization.cpp"
|
||||
#undef A
|
||||
#undef X
|
||||
#undef Y
|
||||
|
|
|
@ -106,6 +106,9 @@ struct HuC6280 {
|
|||
//disassembler.cpp
|
||||
auto disassemble(uint16 pc) -> string;
|
||||
|
||||
//serialization.cpp
|
||||
auto serialize(serializer&) -> void;
|
||||
|
||||
struct Flags {
|
||||
bool c; //carry
|
||||
bool z; //zero
|
||||
|
|
|
@ -0,0 +1,18 @@
|
|||
auto HuC6280::serialize(serializer& s) -> void {
|
||||
s.integer(r.a);
|
||||
s.integer(r.x);
|
||||
s.integer(r.y);
|
||||
s.integer(r.s);
|
||||
s.integer(r.pc);
|
||||
s.array(r.mpr);
|
||||
s.integer(r.mdr);
|
||||
s.integer(r.p.c);
|
||||
s.integer(r.p.z);
|
||||
s.integer(r.p.i);
|
||||
s.integer(r.p.d);
|
||||
s.integer(r.p.b);
|
||||
s.integer(r.p.t);
|
||||
s.integer(r.p.v);
|
||||
s.integer(r.p.n);
|
||||
s.integer(r.cs);
|
||||
}
|
Loading…
Reference in New Issue