libsnes: implement "stateful" smp that can restore its state at more points, theoretically eliminating incorrectness from smp misbehavior. no real speed loss. doesn't fix anything at the moment; i might back out the change if it turns out to never fix anything. breaks savestates.
This commit is contained in:
parent
5f854466ab
commit
5e3d6555b0
Binary file not shown.
|
@ -4,10 +4,13 @@
|
|||
namespace SNES {
|
||||
|
||||
#include "algorithms.cpp"
|
||||
#include "opcodes.cpp"
|
||||
//#include "opcodes.cpp"
|
||||
#include "disassembler.cpp"
|
||||
#include "serialization.cpp"
|
||||
|
||||
|
||||
#include "uop.cpp"
|
||||
|
||||
/*
|
||||
void SMPcore::op_step() {
|
||||
switch(opcode = op_readpc()) {
|
||||
case 0x00: return op_nop();
|
||||
|
@ -268,5 +271,5 @@ void SMPcore::op_step() {
|
|||
case 0xff: return op_wait();
|
||||
}
|
||||
}
|
||||
|
||||
*/
|
||||
}
|
||||
|
|
|
@ -9,7 +9,9 @@ struct SMPcore {
|
|||
|
||||
regs_t regs;
|
||||
word_t dp, sp, rd, wr, bit, ya;
|
||||
uint8 opcode;
|
||||
uint8 opcode;
|
||||
|
||||
int uindex;
|
||||
|
||||
void core_serialize(serializer&);
|
||||
string disassemble_opcode(uint16 addr);
|
||||
|
|
|
@ -16,4 +16,10 @@ alwaysinline uint8 op_readdp(uint8 addr) {
|
|||
|
||||
alwaysinline void op_writedp(uint8 addr, uint8 data) {
|
||||
return op_write((regs.p.p << 8) + addr, data);
|
||||
}
|
||||
}
|
||||
|
||||
alwaysinline void op_next() {
|
||||
opcode = op_readpc();
|
||||
uindex = -1;
|
||||
}
|
||||
|
||||
|
|
|
@ -21,7 +21,9 @@ void SMPcore::core_serialize(serializer &s) {
|
|||
s.integer(rd.w);
|
||||
s.integer(wr.w);
|
||||
s.integer(bit.w);
|
||||
s.integer(ya.w);
|
||||
s.integer(ya.w);
|
||||
|
||||
s.integer(uindex);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -40,7 +40,7 @@ uint8 SMP::op_busread(uint16 addr) {
|
|||
case 0xf5: //CPUIO1
|
||||
case 0xf6: //CPUIO2
|
||||
case 0xf7: //CPUIO3
|
||||
synchronize_cpu();
|
||||
synchronize_cpu_force();
|
||||
return cpu.port_read(addr);
|
||||
|
||||
case 0xf8: //RAM0
|
||||
|
@ -98,7 +98,7 @@ void SMP::op_buswrite(uint16 addr, uint8 data) {
|
|||
if(data & 0x30) {
|
||||
//one-time clearing of APU port read registers,
|
||||
//emulated by simulating CPU writes of 0x00
|
||||
synchronize_cpu();
|
||||
synchronize_cpu_force();
|
||||
if(data & 0x20) {
|
||||
cpu.port_write(2, 0x00);
|
||||
cpu.port_write(3, 0x00);
|
||||
|
@ -142,7 +142,7 @@ void SMP::op_buswrite(uint16 addr, uint8 data) {
|
|||
case 0xf5: //CPUIO1
|
||||
case 0xf6: //CPUIO2
|
||||
case 0xf7: //CPUIO3
|
||||
synchronize_cpu();
|
||||
synchronize_cpu_force();
|
||||
port_write(addr, data);
|
||||
break;
|
||||
|
||||
|
|
|
@ -16,12 +16,23 @@ void SMP::step(unsigned clocks) {
|
|||
}
|
||||
|
||||
void SMP::synchronize_cpu() {
|
||||
if(CPU::Threaded == true) {
|
||||
if(CPU::Threaded == true) {
|
||||
if(clock >= 0 && scheduler.sync != Scheduler::SynchronizeMode::All) co_switch(cpu.thread);
|
||||
} else {
|
||||
while(clock >= 0) cpu.enter();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void SMP::synchronize_cpu_force() {
|
||||
if(CPU::Threaded == true) {
|
||||
if(clock >= 0 && scheduler.sync != Scheduler::SynchronizeMode::All)
|
||||
co_switch(cpu.thread);
|
||||
else if(clock >= 0 && scheduler.sync == Scheduler::SynchronizeMode::All)
|
||||
interface->message("SMP had to advance nondeterministically!");
|
||||
} else {
|
||||
while(clock >= 0) cpu.enter();
|
||||
}
|
||||
}
|
||||
|
||||
void SMP::synchronize_dsp() {
|
||||
if(DSP::Threaded == true) {
|
||||
|
@ -34,10 +45,13 @@ void SMP::synchronize_dsp() {
|
|||
void SMP::Enter() { smp.enter(); }
|
||||
|
||||
void SMP::enter() {
|
||||
while(true) {
|
||||
while(true) {
|
||||
// see comment in timing.cpp
|
||||
if(clock > +(768 * 24 * (int64)24000000)) synchronize_cpu();
|
||||
|
||||
if(scheduler.sync == Scheduler::SynchronizeMode::All) {
|
||||
scheduler.exit(Scheduler::ExitReason::SynchronizeEvent);
|
||||
}
|
||||
}
|
||||
|
||||
debugger.op_exec(regs.pc);
|
||||
op_step();
|
||||
|
@ -58,7 +72,11 @@ void SMP::power() {
|
|||
void SMP::reset() {
|
||||
create(Enter, system.apu_frequency());
|
||||
|
||||
regs.pc = 0xffc0;
|
||||
regs.pc = 0xffc0;
|
||||
// exact value doesn't matter much, so long as "fetch" is next
|
||||
opcode = 0; // NOP
|
||||
uindex = 1; // fetch phase
|
||||
|
||||
regs.a = 0x00;
|
||||
regs.x = 0x00;
|
||||
regs.y = 0x00;
|
||||
|
|
|
@ -4,7 +4,8 @@ struct SMP : public Processor, public SMPcore {
|
|||
|
||||
enum : bool { Threaded = true };
|
||||
alwaysinline void step(unsigned clocks);
|
||||
alwaysinline void synchronize_cpu();
|
||||
alwaysinline void synchronize_cpu();
|
||||
alwaysinline void synchronize_cpu_force();
|
||||
alwaysinline void synchronize_dsp();
|
||||
|
||||
uint8 port_read(uint2 port) const;
|
||||
|
|
|
@ -4,12 +4,22 @@ void SMP::add_clocks(unsigned clocks) {
|
|||
step(clocks);
|
||||
synchronize_dsp();
|
||||
|
||||
#if defined(DEBUGGER)
|
||||
#if defined(DEBUGGER)
|
||||
#error -DDEBUGGER SMP runtosave() correctness not checked
|
||||
synchronize_cpu();
|
||||
#else
|
||||
//forcefully sync S-SMP to S-CPU in case chips are not communicating
|
||||
//sync if S-SMP is more than 24 samples ahead of S-CPU
|
||||
if(clock > +(768 * 24 * (int64)24000000)) synchronize_cpu();
|
||||
//sync if S-SMP is more than 24 samples ahead of S-CPU
|
||||
/*
|
||||
our new smp design guarantees that there is at most one required synchronize_cpu() per uop,
|
||||
inside an op_busread() or op_buswrite(). this extra synchronize can cause problems if we
|
||||
swap out of the SMP at the beginning of a uop with an add_clocks() call when there is an
|
||||
important op_busread() / op_buswrite() later on. the SMP will need to finish that uop in
|
||||
order to reach a savable state, but it might never get to do so until it's too late (ie,
|
||||
scheduler.sync == Scheduler.SynchronizeMode::All). so we remove this call and instead
|
||||
do catchup sync in the main Enter() loop.
|
||||
*/
|
||||
//if(clock > +(768 * 24 * (int64)24000000)) synchronize_cpu();
|
||||
#endif
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue