mirror of
https://github.com/bsnes-emu/bsnes.git
synced 2025-07-31 09:10:23 +02:00
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:
@@ -12,7 +12,7 @@ using namespace nall;
|
|||||||
|
|
||||||
namespace Emulator {
|
namespace Emulator {
|
||||||
static const string Name = "higan";
|
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 Author = "byuu";
|
||||||
static const string License = "GPLv3";
|
static const string License = "GPLv3";
|
||||||
static const string Website = "http://byuu.org/";
|
static const string Website = "http://byuu.org/";
|
||||||
|
@@ -7,6 +7,7 @@ CPU cpu;
|
|||||||
#include "io.cpp"
|
#include "io.cpp"
|
||||||
#include "irq.cpp"
|
#include "irq.cpp"
|
||||||
#include "timer.cpp"
|
#include "timer.cpp"
|
||||||
|
#include "serialization.cpp"
|
||||||
|
|
||||||
auto CPU::Enter() -> void {
|
auto CPU::Enter() -> void {
|
||||||
while(true) scheduler.synchronize(), cpu.main();
|
while(true) scheduler.synchronize(), cpu.main();
|
||||||
|
@@ -19,8 +19,15 @@ struct CPU : Processor::HuC6280, Thread {
|
|||||||
//timer.cpp
|
//timer.cpp
|
||||||
auto timerStep(uint clocks) -> void;
|
auto timerStep(uint clocks) -> void;
|
||||||
|
|
||||||
|
//serialization.cpp
|
||||||
|
auto serialize(serializer&) -> void;
|
||||||
|
|
||||||
vector<Thread*> peripherals;
|
vector<Thread*> peripherals;
|
||||||
|
|
||||||
|
private:
|
||||||
|
uint8 ram[0x8000]; //PC Engine = 8KB, SuperGrafx = 32KB
|
||||||
|
uint8 bram[0x800]; //PC Engine CD-ROM Backup RAM = 2KB
|
||||||
|
|
||||||
struct IRQ {
|
struct IRQ {
|
||||||
//irq.cpp
|
//irq.cpp
|
||||||
auto pending() const -> bool;
|
auto pending() const -> bool;
|
||||||
@@ -59,10 +66,6 @@ struct CPU : Processor::HuC6280, Thread {
|
|||||||
struct IO {
|
struct IO {
|
||||||
uint8 mdr;
|
uint8 mdr;
|
||||||
} io;
|
} io;
|
||||||
|
|
||||||
private:
|
|
||||||
uint8 ram[0x8000]; //PC Engine = 8KB, SuperGrafx = 32KB
|
|
||||||
uint8 bram[0x800]; //PC Engine CD-ROM Backup RAM = 2KB
|
|
||||||
};
|
};
|
||||||
|
|
||||||
extern CPU cpu;
|
extern CPU cpu;
|
||||||
|
21
higan/pce/cpu/serialization.cpp
Normal file
21
higan/pce/cpu/serialization.cpp
Normal file
@@ -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() {
|
Interface::Interface() {
|
||||||
information.overscan = true;
|
information.overscan = true;
|
||||||
|
|
||||||
information.capability.states = false;
|
information.capability.states = true;
|
||||||
information.capability.cheats = false;
|
information.capability.cheats = false;
|
||||||
|
|
||||||
Port controllerPort{ID::Port::Controller, "Controller Port"};
|
Port controllerPort{ID::Port::Controller, "Controller Port"};
|
||||||
@@ -108,11 +108,12 @@ auto Interface::run() -> void {
|
|||||||
}
|
}
|
||||||
|
|
||||||
auto Interface::serialize() -> serializer {
|
auto Interface::serialize() -> serializer {
|
||||||
return {};
|
system.runToSave();
|
||||||
|
return system.serialize();
|
||||||
}
|
}
|
||||||
|
|
||||||
auto Interface::unserialize(serializer& s) -> bool {
|
auto Interface::unserialize(serializer& s) -> bool {
|
||||||
return false;
|
return system.unserialize(s);
|
||||||
}
|
}
|
||||||
|
|
||||||
auto Interface::cap(const string& name) -> bool {
|
auto Interface::cap(const string& name) -> bool {
|
||||||
|
@@ -1,7 +1,6 @@
|
|||||||
auto PSG::Channel::power(uint id) -> void {
|
auto PSG::Channel::power(uint id) -> void {
|
||||||
this->id = id;
|
this->id = id;
|
||||||
memory::fill(&io, sizeof(IO));
|
memory::fill(&io, sizeof(IO));
|
||||||
memory::fill(&output, sizeof(Output));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
auto PSG::Channel::run() -> void {
|
auto PSG::Channel::run() -> void {
|
||||||
@@ -19,22 +18,12 @@ auto PSG::Channel::run() -> void {
|
|||||||
|
|
||||||
if(--io.noisePeriod == 0) {
|
if(--io.noisePeriod == 0) {
|
||||||
io.noisePeriod = ~io.noiseFrequency << 7;
|
io.noisePeriod = ~io.noiseFrequency << 7;
|
||||||
//todo: this should be a square wave; PRNG algorithm is also unknown
|
io.noiseSample = nall::random() & 1 ? ~0 : 0;
|
||||||
io.noiseSample = nall::random();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return sample(io.noiseSample);
|
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 {
|
auto PSG::Channel::sample(uint5 sample) -> void {
|
||||||
output.left = sample << 8; //<< io.volume << io.volumeLeft;
|
io.output = sample;
|
||||||
output.right = sample << 8; //<< io.volume << io.volumeRight;
|
|
||||||
}
|
}
|
||||||
|
@@ -49,7 +49,7 @@ auto PSG::Channel::write(uint4 addr, uint8 data) -> void {
|
|||||||
io.waveOffset++;
|
io.waveOffset++;
|
||||||
io.waveSample = io.waveBuffer[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.direct = data.bit(6);
|
||||||
io.enable = data.bit(7);
|
io.enable = data.bit(7);
|
||||||
}
|
}
|
||||||
|
@@ -5,25 +5,43 @@ namespace PCEngine {
|
|||||||
PSG psg;
|
PSG psg;
|
||||||
#include "io.cpp"
|
#include "io.cpp"
|
||||||
#include "channel.cpp"
|
#include "channel.cpp"
|
||||||
|
#include "serialization.cpp"
|
||||||
|
|
||||||
auto PSG::Enter() -> void {
|
auto PSG::Enter() -> void {
|
||||||
while(true) scheduler.synchronize(), psg.main();
|
while(true) scheduler.synchronize(), psg.main();
|
||||||
}
|
}
|
||||||
|
|
||||||
auto PSG::main() -> void {
|
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)) {
|
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();
|
channel[C].run();
|
||||||
if(C == 1 && io.lfoEnable) {
|
if(C == 1 && io.lfoEnable) {
|
||||||
//todo: frequency modulation of channel 0 using channel 1's output
|
//todo: frequency modulation of channel 0 using channel 1's output
|
||||||
} else {
|
} else {
|
||||||
left += channel[C].output.left;
|
outputLeft += channel[C].io.output * volumeScalar[volumeLeft];
|
||||||
right += channel[C].output.right;
|
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);
|
step(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -38,6 +56,14 @@ auto PSG::power() -> void {
|
|||||||
|
|
||||||
memory::fill(&io, sizeof(IO));
|
memory::fill(&io, sizeof(IO));
|
||||||
for(auto C : range(6)) channel[C].power(C);
|
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
|
//io.cpp
|
||||||
auto write(uint4 addr, uint8 data) -> void;
|
auto write(uint4 addr, uint8 data) -> void;
|
||||||
|
|
||||||
|
//serialization.cpp
|
||||||
|
auto serialize(serializer&) -> void;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
struct IO {
|
struct IO {
|
||||||
uint3 channel;
|
uint3 channel;
|
||||||
@@ -26,8 +29,6 @@ private:
|
|||||||
//channel.cpp
|
//channel.cpp
|
||||||
auto power(uint id) -> void;
|
auto power(uint id) -> void;
|
||||||
auto run() -> void;
|
auto run() -> void;
|
||||||
auto loadWavePeriod() -> void;
|
|
||||||
auto loadWaveSample() -> void;
|
|
||||||
auto sample(uint5 sample) -> void;
|
auto sample(uint5 sample) -> void;
|
||||||
|
|
||||||
//io.cpp
|
//io.cpp
|
||||||
@@ -35,7 +36,7 @@ private:
|
|||||||
|
|
||||||
struct IO {
|
struct IO {
|
||||||
uint12 waveFrequency;
|
uint12 waveFrequency;
|
||||||
uint4 volume;
|
uint5 volume;
|
||||||
uint1 direct;
|
uint1 direct;
|
||||||
uint1 enable;
|
uint1 enable;
|
||||||
uint4 volumeLeft;
|
uint4 volumeLeft;
|
||||||
@@ -49,15 +50,14 @@ private:
|
|||||||
uint5 waveOffset;
|
uint5 waveOffset;
|
||||||
uint12 noisePeriod;
|
uint12 noisePeriod;
|
||||||
uint5 noiseSample;
|
uint5 noiseSample;
|
||||||
} io;
|
|
||||||
|
|
||||||
struct Output {
|
uint5 output;
|
||||||
uint left;
|
} io;
|
||||||
uint right;
|
|
||||||
} output;
|
|
||||||
|
|
||||||
uint id;
|
uint id;
|
||||||
} channel[6];
|
} channel[6];
|
||||||
|
|
||||||
|
double volumeScalar[32];
|
||||||
};
|
};
|
||||||
|
|
||||||
extern PSG psg;
|
extern PSG psg;
|
||||||
|
28
higan/pce/psg/serialization.cpp
Normal file
28
higan/pce/psg/serialization.cpp
Normal file
@@ -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);
|
||||||
|
}
|
||||||
|
}
|
67
higan/pce/system/serialization.cpp
Normal file
67
higan/pce/system/serialization.cpp
Normal file
@@ -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;
|
System system;
|
||||||
Scheduler scheduler;
|
Scheduler scheduler;
|
||||||
#include "peripherals.cpp"
|
#include "peripherals.cpp"
|
||||||
|
#include "serialization.cpp"
|
||||||
|
|
||||||
auto System::run() -> void {
|
auto System::run() -> void {
|
||||||
if(scheduler.enter() == Scheduler::Event::Frame) vce.refresh();
|
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 {
|
auto System::load(Emulator::Interface* interface, Model model) -> bool {
|
||||||
information = {};
|
information = {};
|
||||||
information.model = model;
|
information.model = model;
|
||||||
@@ -22,6 +31,7 @@ auto System::load(Emulator::Interface* interface, Model model) -> bool {
|
|||||||
if(!cartridge.load()) return false;
|
if(!cartridge.load()) return false;
|
||||||
|
|
||||||
cpu.load();
|
cpu.load();
|
||||||
|
serializeInit();
|
||||||
this->interface = interface;
|
this->interface = interface;
|
||||||
information.colorburst = Emulator::Constants::Colorburst::NTSC;
|
information.colorburst = Emulator::Constants::Colorburst::NTSC;
|
||||||
return information.loaded = true;
|
return information.loaded = true;
|
||||||
|
@@ -6,6 +6,7 @@ struct System {
|
|||||||
inline auto colorburst() const -> double { return information.colorburst; }
|
inline auto colorburst() const -> double { return information.colorburst; }
|
||||||
|
|
||||||
auto run() -> void;
|
auto run() -> void;
|
||||||
|
auto runToSave() -> void;
|
||||||
|
|
||||||
auto load(Emulator::Interface*, Model) -> bool;
|
auto load(Emulator::Interface*, Model) -> bool;
|
||||||
auto save() -> void;
|
auto save() -> void;
|
||||||
@@ -13,6 +14,13 @@ struct System {
|
|||||||
|
|
||||||
auto power() -> void;
|
auto power() -> void;
|
||||||
|
|
||||||
|
//serialization.cpp
|
||||||
|
auto serializeInit() -> void;
|
||||||
|
auto serialize() -> serializer;
|
||||||
|
auto unserialize(serializer&) -> bool;
|
||||||
|
auto serializeAll(serializer&) -> void;
|
||||||
|
auto serialize(serializer&) -> void;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Emulator::Interface* interface = nullptr;
|
Emulator::Interface* interface = nullptr;
|
||||||
|
|
||||||
@@ -21,6 +29,7 @@ private:
|
|||||||
Model model = Model::PCEngine;
|
Model model = Model::PCEngine;
|
||||||
string manifest;
|
string manifest;
|
||||||
double colorburst = 0.0;
|
double colorburst = 0.0;
|
||||||
|
uint serializeSize = 0;
|
||||||
} information;
|
} information;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
13
higan/pce/vce/serialization.cpp
Normal file
13
higan/pce/vce/serialization.cpp
Normal file
@@ -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;
|
VCE vce;
|
||||||
#include "memory.cpp"
|
#include "memory.cpp"
|
||||||
#include "io.cpp"
|
#include "io.cpp"
|
||||||
|
#include "serialization.cpp"
|
||||||
|
|
||||||
auto VCE::Enter() -> void {
|
auto VCE::Enter() -> void {
|
||||||
while(true) scheduler.synchronize(), vce.main();
|
while(true) scheduler.synchronize(), vce.main();
|
||||||
|
@@ -13,6 +13,9 @@ struct VCE : Thread {
|
|||||||
auto read(uint3 addr) -> uint8;
|
auto read(uint3 addr) -> uint8;
|
||||||
auto write(uint3 addr, uint8 data) -> void;
|
auto write(uint3 addr, uint8 data) -> void;
|
||||||
|
|
||||||
|
//serialization.cpp
|
||||||
|
auto serialize(serializer&) -> void;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
uint32 buffer[1365 * 263];
|
uint32 buffer[1365 * 263];
|
||||||
|
|
||||||
@@ -21,10 +24,8 @@ private:
|
|||||||
auto read(uint9 addr) -> uint9;
|
auto read(uint9 addr) -> uint9;
|
||||||
auto write(uint9 addr, bool a0, uint8 data) -> void;
|
auto write(uint9 addr, bool a0, uint8 data) -> void;
|
||||||
|
|
||||||
uint9 address;
|
|
||||||
|
|
||||||
private:
|
|
||||||
uint9 data[0x200];
|
uint9 data[0x200];
|
||||||
|
uint9 address;
|
||||||
} cram;
|
} cram;
|
||||||
|
|
||||||
struct Timing {
|
struct Timing {
|
||||||
|
83
higan/pce/vdc/serialization.cpp
Normal file
83
higan/pce/vdc/serialization.cpp
Normal file
@@ -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 "dma.cpp"
|
||||||
#include "background.cpp"
|
#include "background.cpp"
|
||||||
#include "sprite.cpp"
|
#include "sprite.cpp"
|
||||||
|
#include "serialization.cpp"
|
||||||
|
|
||||||
auto VDC::Enter() -> void {
|
auto VDC::Enter() -> void {
|
||||||
while(true) {
|
while(true) {
|
||||||
|
@@ -16,6 +16,9 @@ struct VDC : Thread {
|
|||||||
auto read(uint2 addr) -> uint8;
|
auto read(uint2 addr) -> uint8;
|
||||||
auto write(uint2 addr, uint8 data) -> void;
|
auto write(uint2 addr, uint8 data) -> void;
|
||||||
|
|
||||||
|
//serialization.cpp
|
||||||
|
auto serialize(serializer&) -> void;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
uint9 data;
|
uint9 data;
|
||||||
|
|
||||||
@@ -24,15 +27,14 @@ private:
|
|||||||
auto read(uint16 addr) -> uint16;
|
auto read(uint16 addr) -> uint16;
|
||||||
auto write(uint16 addr, uint16 data) -> void;
|
auto write(uint16 addr, uint16 data) -> void;
|
||||||
|
|
||||||
|
uint16 data[0x8000];
|
||||||
|
|
||||||
uint16 addressRead;
|
uint16 addressRead;
|
||||||
uint16 addressWrite;
|
uint16 addressWrite;
|
||||||
uint16 addressIncrement;
|
uint16 addressIncrement;
|
||||||
|
|
||||||
uint16 dataRead;
|
uint16 dataRead;
|
||||||
uint16 dataWrite;
|
uint16 dataWrite;
|
||||||
|
|
||||||
private:
|
|
||||||
uint16 data[0x8000];
|
|
||||||
} vram;
|
} vram;
|
||||||
|
|
||||||
struct SATB {
|
struct SATB {
|
||||||
@@ -40,7 +42,6 @@ private:
|
|||||||
auto read(uint8 addr) -> uint16;
|
auto read(uint8 addr) -> uint16;
|
||||||
auto write(uint8 addr, uint16 data) -> void;
|
auto write(uint8 addr, uint16 data) -> void;
|
||||||
|
|
||||||
private:
|
|
||||||
uint16 data[0x100];
|
uint16 data[0x100];
|
||||||
} satb;
|
} satb;
|
||||||
|
|
||||||
@@ -191,10 +192,6 @@ private:
|
|||||||
uint2 vramAccess;
|
uint2 vramAccess;
|
||||||
uint2 spriteAccess;
|
uint2 spriteAccess;
|
||||||
bool cgMode;
|
bool cgMode;
|
||||||
|
|
||||||
//$0400 CR
|
|
||||||
bool colorBlur;
|
|
||||||
bool grayscale;
|
|
||||||
} io;
|
} io;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
9
higan/pce/vpc/serialization.cpp
Normal file
9
higan/pce/vpc/serialization.cpp
Normal file
@@ -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 {
|
namespace PCEngine {
|
||||||
|
|
||||||
VPC vpc;
|
VPC vpc;
|
||||||
|
#include "serialization.cpp"
|
||||||
|
|
||||||
auto VPC::bus(uint hclock) -> uint9 {
|
auto VPC::bus(uint hclock) -> uint9 {
|
||||||
//bus values are direct CRAM entry indexes:
|
//bus values are direct CRAM entry indexes:
|
||||||
|
@@ -8,6 +8,9 @@ struct VPC {
|
|||||||
auto write(uint5 addr, uint8 data) -> void;
|
auto write(uint5 addr, uint8 data) -> void;
|
||||||
auto store(uint2 addr, uint8 data) -> void;
|
auto store(uint2 addr, uint8 data) -> void;
|
||||||
|
|
||||||
|
//serialization.cpp
|
||||||
|
auto serialize(serializer&) -> void;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
struct Settings {
|
struct Settings {
|
||||||
bool enableVDC0;
|
bool enableVDC0;
|
||||||
|
@@ -26,6 +26,7 @@ namespace Processor {
|
|||||||
#include "instruction.cpp"
|
#include "instruction.cpp"
|
||||||
#include "instructions.cpp"
|
#include "instructions.cpp"
|
||||||
#include "disassembler.cpp"
|
#include "disassembler.cpp"
|
||||||
|
#include "serialization.cpp"
|
||||||
#undef A
|
#undef A
|
||||||
#undef X
|
#undef X
|
||||||
#undef Y
|
#undef Y
|
||||||
|
@@ -106,6 +106,9 @@ struct HuC6280 {
|
|||||||
//disassembler.cpp
|
//disassembler.cpp
|
||||||
auto disassemble(uint16 pc) -> string;
|
auto disassemble(uint16 pc) -> string;
|
||||||
|
|
||||||
|
//serialization.cpp
|
||||||
|
auto serialize(serializer&) -> void;
|
||||||
|
|
||||||
struct Flags {
|
struct Flags {
|
||||||
bool c; //carry
|
bool c; //carry
|
||||||
bool z; //zero
|
bool z; //zero
|
||||||
|
18
higan/processor/huc6280/serialization.cpp
Normal file
18
higan/processor/huc6280/serialization.cpp
Normal file
@@ -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);
|
||||||
|
}
|
Reference in New Issue
Block a user