mirror of
https://github.com/bsnes-emu/bsnes.git
synced 2025-02-22 14:12:35 +01:00
byuu says: Changelog: - processor/spc700: restored fetch/load/store/pull/push shorthand functions - processor/spc700: split functions that tested the algorithm used (`op != &SPC700:...`) to separate instructions - mostly for code clarity over code size: it was awkward having cycle counts change based on a function parameter - processor/spc700: implemented Overload's new findings on which cycles are truly internal (no bus reads) - sfc/smp: TEST register emulation has been vastly improved¹ ¹: it turns out that TEST.d4,d5 is the external clock divider (used when accessing RAM through the DSP), and TEST.d6,d7 is the internal clock divider (used when accessing IPLROM, IO registers, or during idle cycles.) The DSP (24576khz) feeds its clock / 12 through to the SMP (2048khz). The clock divider setting further divides the clock by 2, 4, 8, or 16. Since 8 and 16 are not cleanly divislbe by 12, the SMP cycle count glitches out and seems to take 10 and 2 clocks instead of 8 or 16. This can on real hardware either cause the SMP to run very slowly, or more likely, crash the SMP completely until reset. What's even stranger is the timers aren't affected by this. They still clock by 2, 4, 8, or 16. Note that technically I could divide my own clock counters by 24 and reduce these to {1,2,5,10} and {1,2,4,8}, I instead chose to divide by 12 to better illustrate this hardware issue and better model that the SMP clock runs at 2048khz and not 1024khz. Further, note that things aren't 100% perfect yet. This seems to throw off some tests, such as blargg's `test_timer_speed`. I can't tell how far off I am because blargg's test tragically doesn't print out fail values. But you can see the improvements in that higan is now passing all of Revenant's tests that were obviously completely wrong before.
95 lines
1.8 KiB
C++
95 lines
1.8 KiB
C++
//Sony CXP1100Q-1
|
|
|
|
struct SMP : Processor::SPC700, Thread {
|
|
uint8 iplrom[64];
|
|
|
|
//smp.cpp
|
|
auto synchronizing() const -> bool override;
|
|
|
|
auto portRead(uint2 port) const -> uint8;
|
|
auto portWrite(uint2 port, uint8 data) -> void;
|
|
|
|
auto main() -> void;
|
|
auto load(Markup::Node) -> bool;
|
|
auto power() -> void;
|
|
|
|
//serialization.cpp
|
|
auto serialize(serializer&) -> void;
|
|
|
|
private:
|
|
struct IO {
|
|
//timing
|
|
uint clockCounter;
|
|
uint dspCounter;
|
|
|
|
//external
|
|
uint8 apu0;
|
|
uint8 apu1;
|
|
uint8 apu2;
|
|
uint8 apu3;
|
|
|
|
//$00f0
|
|
uint1 timersDisable;
|
|
uint1 ramWritable;
|
|
uint1 ramDisable;
|
|
uint1 timersEnable;
|
|
uint2 externalWaitStates;
|
|
uint2 internalWaitStates;
|
|
|
|
//$00f1
|
|
bool iplromEnable;
|
|
|
|
//$00f2
|
|
uint8 dspAddr;
|
|
|
|
//$00f4-00f7
|
|
uint8 cpu0;
|
|
uint8 cpu1;
|
|
uint8 cpu2;
|
|
uint8 cpu3;
|
|
|
|
//$00f8-00f9
|
|
uint8 aux4;
|
|
uint8 aux5;
|
|
} io;
|
|
|
|
static auto Enter() -> void;
|
|
|
|
//memory.cpp
|
|
auto ramRead(uint16 addr) -> uint8;
|
|
auto ramWrite(uint16 addr, uint8 data) -> void;
|
|
|
|
auto busRead(uint16 addr) -> uint8;
|
|
auto busWrite(uint16 addr, uint8 data) -> void;
|
|
|
|
auto idle() -> void override;
|
|
auto read(uint16 addr) -> uint8 override;
|
|
auto write(uint16 addr, uint8 data) -> void override;
|
|
|
|
auto readDisassembler(uint16 addr) -> uint8 override;
|
|
|
|
//timing.cpp
|
|
template<uint Frequency> struct Timer {
|
|
uint8 stage0;
|
|
uint8 stage1;
|
|
uint8 stage2;
|
|
uint4 stage3;
|
|
bool line;
|
|
bool enable;
|
|
uint8 target;
|
|
|
|
auto step(uint clocks) -> void;
|
|
auto synchronizeStage1() -> void;
|
|
};
|
|
|
|
Timer<128> timer0;
|
|
Timer<128> timer1;
|
|
Timer< 16> timer2;
|
|
|
|
inline auto wait(maybe<uint16> address = nothing) -> void;
|
|
inline auto step(uint clocks) -> void;
|
|
inline auto stepTimers(uint clocks) -> void;
|
|
};
|
|
|
|
extern SMP smp;
|