Notable differences from upstream:
* Did not use the same #include setup for the new byuu apu and instead chose to do things more traditionally, as the latter is also much easier to deal with in Visual Studio than just including .cpp files into other .cpp files...
* MSU1 support not included (I see no need for this in a plugin meant to be used for original SNES music).
* The dynamic rate control on the APU not included (I also see no need for it in this plugin).
* The extra resamplers I added in were removed as the original hermite resampler was folded into a single non-inhertiable resampler.
* Bits of cleanup.
| 1 | 1 |
deleted file mode 100644 |
| ... | ... |
@@ -1,236 +0,0 @@ |
| 1 |
-// SNES SPC-700 APU emulator |
|
| 2 |
- |
|
| 3 |
-// snes_spc 0.9.0 |
|
| 4 |
-#pragma once |
|
| 5 |
- |
|
| 6 |
-#include "SPC_DSP.h" |
|
| 7 |
-#include "blargg_endian.h" |
|
| 8 |
- |
|
| 9 |
-// (n ? n : 256) |
|
| 10 |
-template<typename T> inline T IF_0_THEN_256(const T &n) { return static_cast<uint8_t>(n - 1) + 1; }
|
|
| 11 |
- |
|
| 12 |
-struct SNES_SPC |
|
| 13 |
-{
|
|
| 14 |
-public: |
|
| 15 |
- // Must be called once before using |
|
| 16 |
- void init(); |
|
| 17 |
- |
|
| 18 |
- // Sample pairs generated per second |
|
| 19 |
- enum { sample_rate = 32000 };
|
|
| 20 |
- |
|
| 21 |
- // Emulator use |
|
| 22 |
- |
|
| 23 |
- // Sets IPL ROM data. Library does not include ROM data. Most SPC music files |
|
| 24 |
- // don't need ROM, but a full emulator must provide this. |
|
| 25 |
- enum { rom_size = 0x40 };
|
|
| 26 |
- void init_rom(const uint8_t rom[rom_size]); |
|
| 27 |
- |
|
| 28 |
- // Sets destination for output samples |
|
| 29 |
- typedef short sample_t; |
|
| 30 |
- void set_output(sample_t *out, int out_size); |
|
| 31 |
- |
|
| 32 |
- // Number of samples written to output since last set |
|
| 33 |
- int sample_count() const; |
|
| 34 |
- |
|
| 35 |
- // Resets SPC to power-on state. This resets your output buffer, so you must |
|
| 36 |
- // call set_output() after this. |
|
| 37 |
- void reset(); |
|
| 38 |
- |
|
| 39 |
- // Emulates pressing reset switch on SNES. This resets your output buffer, so |
|
| 40 |
- // you must call set_output() after this. |
|
| 41 |
- void soft_reset(); |
|
| 42 |
- |
|
| 43 |
- // 1024000 SPC clocks per second, sample pair every 32 clocks |
|
| 44 |
- typedef int time_t; |
|
| 45 |
- enum { clock_rate = 1024000 };
|
|
| 46 |
- enum { clocks_per_sample = 32 };
|
|
| 47 |
- |
|
| 48 |
- // Emulated port read/write at specified time |
|
| 49 |
- enum { port_count = 4 };
|
|
| 50 |
- int read_port(time_t, int port); |
|
| 51 |
- void write_port(time_t, int port, int data); |
|
| 52 |
- |
|
| 53 |
- // Runs SPC to end_time and starts a new time frame at 0 |
|
| 54 |
- void end_frame(time_t end_time); |
|
| 55 |
- |
|
| 56 |
- // Sound control |
|
| 57 |
- |
|
| 58 |
- // Mutes voices corresponding to non-zero bits in mask (issues repeated KOFF events). |
|
| 59 |
- // Reduces emulation accuracy. |
|
| 60 |
- enum { voice_count = 8 };
|
|
| 61 |
- void mute_voices(int mask); |
|
| 62 |
- |
|
| 63 |
- // If true, prevents channels and global volumes from being phase-negated. |
|
| 64 |
- // Only supported by fast DSP. |
|
| 65 |
- void disable_surround(bool disable = true ); |
|
| 66 |
- |
|
| 67 |
- // Sets tempo, where tempo_unit = normal, tempo_unit / 2 = half speed, etc. |
|
| 68 |
- enum { tempo_unit = 0x100 };
|
|
| 69 |
- void set_tempo(int); |
|
| 70 |
- |
|
| 71 |
- // SPC music files |
|
| 72 |
- |
|
| 73 |
- // Clears echo region. Useful after loading an SPC as many have garbage in echo. |
|
| 74 |
- void clear_echo(); |
|
| 75 |
- |
|
| 76 |
- // Plays for count samples and write samples to out. Discards samples if out |
|
| 77 |
- // is NULL. Count must be a multiple of 2 since output is stereo. |
|
| 78 |
- void play(int count, sample_t *out); |
|
| 79 |
- |
|
| 80 |
- // Skips count samples. Several times faster than play() when using fast DSP. |
|
| 81 |
- void skip(int count); |
|
| 82 |
- |
|
| 83 |
- //// Snes9x Accessor |
|
| 84 |
- |
|
| 85 |
- void spc_allow_time_overflow(bool); |
|
| 86 |
- |
|
| 87 |
- void dsp_set_stereo_switch(int); |
|
| 88 |
- uint8_t dsp_reg_value(int, int); |
|
| 89 |
- int dsp_envx_value(int); |
|
| 90 |
- |
|
| 91 |
-public: |
|
| 92 |
- // Time relative to m_spc_time. Speeds up code a bit by eliminating need to |
|
| 93 |
- // constantly add m_spc_time to time from CPU. CPU uses time that ends at |
|
| 94 |
- // 0 to eliminate reloading end time every instruction. It pays off. |
|
| 95 |
- typedef int rel_time_t; |
|
| 96 |
- |
|
| 97 |
- struct Timer |
|
| 98 |
- {
|
|
| 99 |
- rel_time_t next_time; // time of next event |
|
| 100 |
- int prescaler; |
|
| 101 |
- int period; |
|
| 102 |
- int divider; |
|
| 103 |
- bool enabled; |
|
| 104 |
- int counter; |
|
| 105 |
- }; |
|
| 106 |
- enum { reg_count = 0x10 };
|
|
| 107 |
- enum { timer_count = 3 };
|
|
| 108 |
- enum { extra_size = SPC_DSP::extra_size };
|
|
| 109 |
- |
|
| 110 |
-private: |
|
| 111 |
- SPC_DSP dsp; |
|
| 112 |
- |
|
| 113 |
- struct state_t |
|
| 114 |
- {
|
|
| 115 |
- Timer timers[timer_count]; |
|
| 116 |
- |
|
| 117 |
- uint8_t smp_regs[2][reg_count]; |
|
| 118 |
- |
|
| 119 |
- struct |
|
| 120 |
- {
|
|
| 121 |
- int pc; |
|
| 122 |
- int a; |
|
| 123 |
- int x; |
|
| 124 |
- int y; |
|
| 125 |
- int psw; |
|
| 126 |
- int sp; |
|
| 127 |
- } cpu_regs; |
|
| 128 |
- |
|
| 129 |
- rel_time_t dsp_time; |
|
| 130 |
- time_t spc_time; |
|
| 131 |
- |
|
| 132 |
- int tempo; |
|
| 133 |
- |
|
| 134 |
- int extra_clocks; |
|
| 135 |
- sample_t *buf_begin; |
|
| 136 |
- const sample_t *buf_end; |
|
| 137 |
- sample_t *extra_pos; |
|
| 138 |
- sample_t extra_buf[extra_size]; |
|
| 139 |
- |
|
| 140 |
- bool rom_enabled; |
|
| 141 |
- uint8_t rom[rom_size]; |
|
| 142 |
- uint8_t hi_ram[rom_size]; |
|
| 143 |
- |
|
| 144 |
- unsigned char cycle_table[256]; |
|
| 145 |
- |
|
| 146 |
- struct |
|
| 147 |
- {
|
|
| 148 |
- // padding to neutralize address overflow |
|
| 149 |
- union |
|
| 150 |
- {
|
|
| 151 |
- uint8_t padding1[0x100]; |
|
| 152 |
- uint16_t align; // makes compiler align data for 16-bit access |
|
| 153 |
- } padding1[1]; |
|
| 154 |
- uint8_t ram[0x10000]; |
|
| 155 |
- uint8_t padding2[0x100]; |
|
| 156 |
- } ram; |
|
| 157 |
- }; |
|
| 158 |
- state_t m; |
|
| 159 |
- |
|
| 160 |
- enum { rom_addr = 0xFFC0 };
|
|
| 161 |
- |
|
| 162 |
- enum { skipping_time = 127 };
|
|
| 163 |
- |
|
| 164 |
- // Value that padding should be filled with |
|
| 165 |
- enum { cpu_pad_fill = 0xFF };
|
|
| 166 |
- |
|
| 167 |
- enum |
|
| 168 |
- {
|
|
| 169 |
- r_test = 0x0, |
|
| 170 |
- r_control = 0x1, |
|
| 171 |
- r_dspaddr = 0x2, |
|
| 172 |
- r_dspdata = 0x3, |
|
| 173 |
- r_cpuio0 = 0x4, |
|
| 174 |
- r_cpuio1 = 0x5, |
|
| 175 |
- r_cpuio2 = 0x6, |
|
| 176 |
- r_cpuio3 = 0x7, |
|
| 177 |
- r_f8 = 0x8, |
|
| 178 |
- r_f9 = 0x9, |
|
| 179 |
- r_t0target = 0xA, |
|
| 180 |
- r_t1target = 0xB, |
|
| 181 |
- r_t2target = 0xC, |
|
| 182 |
- r_t0out = 0xD, |
|
| 183 |
- r_t1out = 0xE, |
|
| 184 |
- r_t2out = 0xF |
|
| 185 |
- }; |
|
| 186 |
- |
|
| 187 |
- void timers_loaded(); |
|
| 188 |
- void enable_rom(bool enable); |
|
| 189 |
- void reset_buf(); |
|
| 190 |
- void save_extra(); |
|
| 191 |
- void load_regs(const uint8_t in[reg_count]); |
|
| 192 |
- void ram_loaded(); |
|
| 193 |
- void regs_loaded(); |
|
| 194 |
- void reset_time_regs(); |
|
| 195 |
- void reset_common(int timer_counter_init); |
|
| 196 |
- |
|
| 197 |
- Timer *run_timer_(Timer *t, rel_time_t); |
|
| 198 |
- Timer *run_timer(Timer *t, rel_time_t); |
|
| 199 |
- void RUN_DSP(rel_time_t); |
|
| 200 |
- int dsp_read(rel_time_t); |
|
| 201 |
- void dsp_write(int data, rel_time_t); |
|
| 202 |
- void cpu_write_smp_reg_(int data, rel_time_t, int addr); |
|
| 203 |
- void cpu_write_smp_reg(int data, rel_time_t, int addr); |
|
| 204 |
- void cpu_write_high(int data, int i, rel_time_t); |
|
| 205 |
- void cpu_write(int data, int addr, rel_time_t); |
|
| 206 |
- int cpu_read_smp_reg(int i, rel_time_t); |
|
| 207 |
- int cpu_read(int addr, rel_time_t); |
|
| 208 |
- unsigned CPU_mem_bit(const uint8_t *pc, rel_time_t); |
|
| 209 |
- |
|
| 210 |
- bool check_echo_access(int addr); |
|
| 211 |
- uint8_t *run_until_(time_t end_time); |
|
| 212 |
- |
|
| 213 |
- // Snes9x timing hack |
|
| 214 |
- bool allow_time_overflow; |
|
| 215 |
-}; |
|
| 216 |
- |
|
| 217 |
-inline int SNES_SPC::sample_count() const { return (this->m.extra_clocks >> 5) * 2; }
|
|
| 218 |
- |
|
| 219 |
-inline int SNES_SPC::read_port(time_t t, int port) |
|
| 220 |
-{
|
|
| 221 |
- assert(static_cast<unsigned>(port) < port_count); |
|
| 222 |
- return this->run_until_(t)[port]; |
|
| 223 |
-} |
|
| 224 |
- |
|
| 225 |
-inline void SNES_SPC::write_port(time_t t, int port, int data) |
|
| 226 |
-{
|
|
| 227 |
- assert(static_cast<unsigned>(port) < port_count); |
|
| 228 |
- this->run_until_(t)[0x10 + port] = data; |
|
| 229 |
- this->m.ram.ram[0xF4 + port] = data; |
|
| 230 |
-} |
|
| 231 |
- |
|
| 232 |
-inline void SNES_SPC::mute_voices(int mask) { this->dsp.mute_voices(mask); }
|
|
| 233 |
- |
|
| 234 |
-inline void SNES_SPC::disable_surround(bool disable) { this->dsp.disable_surround(disable); }
|
|
| 235 |
- |
|
| 236 |
-inline void SNES_SPC::spc_allow_time_overflow(bool allow) { this->allow_time_overflow = allow; }
|
* [2SF] Used more up-to-date asmjit, despite the ugly looking code.
| ... | ... |
@@ -230,7 +230,7 @@ inline void SNES_SPC::write_port(time_t t, int port, int data) |
| 230 | 230 |
} |
| 231 | 231 |
|
| 232 | 232 |
inline void SNES_SPC::mute_voices(int mask) { this->dsp.mute_voices(mask); }
|
| 233 |
- |
|
| 233 |
+ |
|
| 234 | 234 |
inline void SNES_SPC::disable_surround(bool disable) { this->dsp.disable_surround(disable); }
|
| 235 | 235 |
|
| 236 | 236 |
inline void SNES_SPC::spc_allow_time_overflow(bool allow) { this->allow_time_overflow = allow; }
|
| ... | ... |
@@ -1,8 +1,7 @@ |
| 1 | 1 |
// SNES SPC-700 APU emulator |
| 2 | 2 |
|
| 3 | 3 |
// snes_spc 0.9.0 |
| 4 |
-#ifndef SNES_SPC_H |
|
| 5 |
-#define SNES_SPC_H |
|
| 4 |
+#pragma once |
|
| 6 | 5 |
|
| 7 | 6 |
#include "SPC_DSP.h" |
| 8 | 7 |
#include "blargg_endian.h" |
| ... | ... |
@@ -235,5 +234,3 @@ inline void SNES_SPC::mute_voices(int mask) { this->dsp.mute_voices(mask); }
|
| 235 | 234 |
inline void SNES_SPC::disable_surround(bool disable) { this->dsp.disable_surround(disable); }
|
| 236 | 235 |
|
| 237 | 236 |
inline void SNES_SPC::spc_allow_time_overflow(bool allow) { this->allow_time_overflow = allow; }
|
| 238 |
- |
|
| 239 |
-#endif |
| ... | ... |
@@ -7,32 +7,28 @@ |
| 7 | 7 |
#include "SPC_DSP.h" |
| 8 | 8 |
#include "blargg_endian.h" |
| 9 | 9 |
|
| 10 |
-#ifdef DEBUGGER |
|
| 11 |
-#include "snes9x.h" |
|
| 12 |
-#include "display.h" |
|
| 13 |
-#include "debug.h" |
|
| 14 |
-#endif |
|
| 10 |
+// (n ? n : 256) |
|
| 11 |
+template<typename T> inline T IF_0_THEN_256(const T &n) { return static_cast<uint8_t>(n - 1) + 1; }
|
|
| 15 | 12 |
|
| 16 |
-struct SNES_SPC {
|
|
| 13 |
+struct SNES_SPC |
|
| 14 |
+{
|
|
| 17 | 15 |
public: |
| 18 |
- typedef BOOST::uint8_t uint8_t; |
|
| 19 |
- |
|
| 20 | 16 |
// Must be called once before using |
| 21 |
- blargg_err_t init(); |
|
| 22 |
- |
|
| 17 |
+ void init(); |
|
| 18 |
+ |
|
| 23 | 19 |
// Sample pairs generated per second |
| 24 | 20 |
enum { sample_rate = 32000 };
|
| 25 |
- |
|
| 26 |
-// Emulator use |
|
| 27 |
- |
|
| 21 |
+ |
|
| 22 |
+ // Emulator use |
|
| 23 |
+ |
|
| 28 | 24 |
// Sets IPL ROM data. Library does not include ROM data. Most SPC music files |
| 29 | 25 |
// don't need ROM, but a full emulator must provide this. |
| 30 | 26 |
enum { rom_size = 0x40 };
|
| 31 |
- void init_rom( uint8_t const rom [rom_size] ); |
|
| 27 |
+ void init_rom(const uint8_t rom[rom_size]); |
|
| 32 | 28 |
|
| 33 | 29 |
// Sets destination for output samples |
| 34 | 30 |
typedef short sample_t; |
| 35 |
- void set_output( sample_t* out, int out_size ); |
|
| 31 |
+ void set_output(sample_t *out, int out_size); |
|
| 36 | 32 |
|
| 37 | 33 |
// Number of samples written to output since last set |
| 38 | 34 |
int sample_count() const; |
| ... | ... |
@@ -49,126 +45,78 @@ public: |
| 49 | 45 |
typedef int time_t; |
| 50 | 46 |
enum { clock_rate = 1024000 };
|
| 51 | 47 |
enum { clocks_per_sample = 32 };
|
| 52 |
- |
|
| 48 |
+ |
|
| 53 | 49 |
// Emulated port read/write at specified time |
| 54 | 50 |
enum { port_count = 4 };
|
| 55 |
- int read_port ( time_t, int port ); |
|
| 56 |
- void write_port( time_t, int port, int data ); |
|
| 51 |
+ int read_port(time_t, int port); |
|
| 52 |
+ void write_port(time_t, int port, int data); |
|
| 57 | 53 |
|
| 58 | 54 |
// Runs SPC to end_time and starts a new time frame at 0 |
| 59 |
- void end_frame( time_t end_time ); |
|
| 60 |
- |
|
| 61 |
-// Sound control |
|
| 62 |
- |
|
| 55 |
+ void end_frame(time_t end_time); |
|
| 56 |
+ |
|
| 57 |
+ // Sound control |
|
| 58 |
+ |
|
| 63 | 59 |
// Mutes voices corresponding to non-zero bits in mask (issues repeated KOFF events). |
| 64 | 60 |
// Reduces emulation accuracy. |
| 65 | 61 |
enum { voice_count = 8 };
|
| 66 |
- void mute_voices( int mask ); |
|
| 67 |
- |
|
| 62 |
+ void mute_voices(int mask); |
|
| 63 |
+ |
|
| 68 | 64 |
// If true, prevents channels and global volumes from being phase-negated. |
| 69 | 65 |
// Only supported by fast DSP. |
| 70 |
- void disable_surround( bool disable = true ); |
|
| 71 |
- |
|
| 66 |
+ void disable_surround(bool disable = true ); |
|
| 67 |
+ |
|
| 72 | 68 |
// Sets tempo, where tempo_unit = normal, tempo_unit / 2 = half speed, etc. |
| 73 | 69 |
enum { tempo_unit = 0x100 };
|
| 74 |
- void set_tempo( int ); |
|
| 70 |
+ void set_tempo(int); |
|
| 75 | 71 |
|
| 76 |
-// SPC music files |
|
| 72 |
+ // SPC music files |
|
| 77 | 73 |
|
| 78 |
- // Loads SPC data into emulator |
|
| 79 |
- enum { spc_min_file_size = 0x10180 };
|
|
| 80 |
- enum { spc_file_size = 0x10200 };
|
|
| 81 |
- blargg_err_t load_spc( void const* in, long size ); |
|
| 82 |
- |
|
| 83 | 74 |
// Clears echo region. Useful after loading an SPC as many have garbage in echo. |
| 84 | 75 |
void clear_echo(); |
| 85 | 76 |
|
| 86 | 77 |
// Plays for count samples and write samples to out. Discards samples if out |
| 87 | 78 |
// is NULL. Count must be a multiple of 2 since output is stereo. |
| 88 |
- blargg_err_t play( int count, sample_t* out ); |
|
| 89 |
- |
|
| 90 |
- // Skips count samples. Several times faster than play() when using fast DSP. |
|
| 91 |
- blargg_err_t skip( int count ); |
|
| 92 |
- |
|
| 93 |
-// State save/load (only available with accurate DSP) |
|
| 94 |
- |
|
| 95 |
-#if !SPC_NO_COPY_STATE_FUNCS |
|
| 96 |
- // Saves/loads state |
|
| 97 |
- enum { state_size = 68 * 1024L }; // maximum space needed when saving
|
|
| 98 |
- typedef SPC_DSP::copy_func_t copy_func_t; |
|
| 99 |
- void copy_state( unsigned char** io, copy_func_t ); |
|
| 100 |
- |
|
| 101 |
- // Writes minimal header to spc_out |
|
| 102 |
- static void init_header( void* spc_out ); |
|
| 103 |
- |
|
| 104 |
- // Saves emulator state as SPC file data. Writes spc_file_size bytes to spc_out. |
|
| 105 |
- // Does not set up SPC header; use init_header() for that. |
|
| 106 |
- void save_spc( void* spc_out ); |
|
| 107 |
- |
|
| 108 |
- // Returns true if new key-on events occurred since last check. Useful for |
|
| 109 |
- // trimming silence while saving an SPC. |
|
| 110 |
- bool check_kon(); |
|
| 111 |
-#endif |
|
| 79 |
+ void play(int count, sample_t *out); |
|
| 112 | 80 |
|
| 113 |
-//// Snes9x Accessor |
|
| 81 |
+ // Skips count samples. Several times faster than play() when using fast DSP. |
|
| 82 |
+ void skip(int count); |
|
| 114 | 83 |
|
| 115 |
- void spc_allow_time_overflow( bool ); |
|
| 84 |
+ //// Snes9x Accessor |
|
| 116 | 85 |
|
| 117 |
- void dsp_set_spc_snapshot_callback(void (*callback)()); |
|
| 118 |
- void dsp_dump_spc_snapshot(); |
|
| 119 |
- void dsp_set_stereo_switch( int ); |
|
| 120 |
- uint8_t dsp_reg_value( int, int ); |
|
| 121 |
- int dsp_envx_value( int ); |
|
| 86 |
+ void spc_allow_time_overflow(bool); |
|
| 122 | 87 |
|
| 123 |
-//// Snes9x Debugger |
|
| 124 |
- |
|
| 125 |
-#ifdef DEBUGGER |
|
| 126 |
- void debug_toggle_trace(); |
|
| 127 |
- bool debug_is_enabled(); |
|
| 128 |
- void debug_do_trace( int, int, int, uint8_t const *, uint8_t *, int, int, int, int ); |
|
| 129 |
- void debug_op_print( char *, int, int, int, uint8_t const *, uint8_t *, int, int, int, int ); |
|
| 130 |
- void debug_io_print( char * ); |
|
| 131 |
-#endif |
|
| 88 |
+ void dsp_set_stereo_switch(int); |
|
| 89 |
+ uint8_t dsp_reg_value(int, int); |
|
| 90 |
+ int dsp_envx_value(int); |
|
| 132 | 91 |
|
| 133 | 92 |
public: |
| 134 |
- BLARGG_DISABLE_NOTHROW |
|
| 135 |
- |
|
| 136 |
- typedef BOOST::uint16_t uint16_t; |
|
| 137 |
- |
|
| 138 | 93 |
// Time relative to m_spc_time. Speeds up code a bit by eliminating need to |
| 139 | 94 |
// constantly add m_spc_time to time from CPU. CPU uses time that ends at |
| 140 | 95 |
// 0 to eliminate reloading end time every instruction. It pays off. |
| 141 | 96 |
typedef int rel_time_t; |
| 142 |
- |
|
| 97 |
+ |
|
| 143 | 98 |
struct Timer |
| 144 | 99 |
{
|
| 145 | 100 |
rel_time_t next_time; // time of next event |
| 146 | 101 |
int prescaler; |
| 147 | 102 |
int period; |
| 148 | 103 |
int divider; |
| 149 |
- int enabled; |
|
| 104 |
+ bool enabled; |
|
| 150 | 105 |
int counter; |
| 151 | 106 |
}; |
| 152 | 107 |
enum { reg_count = 0x10 };
|
| 153 | 108 |
enum { timer_count = 3 };
|
| 154 | 109 |
enum { extra_size = SPC_DSP::extra_size };
|
| 155 |
- |
|
| 156 |
- enum { signature_size = 35 };
|
|
| 157 |
- |
|
| 110 |
+ |
|
| 158 | 111 |
private: |
| 159 | 112 |
SPC_DSP dsp; |
| 160 |
- |
|
| 161 |
- #if SPC_LESS_ACCURATE |
|
| 162 |
- static signed char const reg_times_ [256]; |
|
| 163 |
- signed char reg_times [256]; |
|
| 164 |
- #endif |
|
| 165 |
- |
|
| 113 |
+ |
|
| 166 | 114 |
struct state_t |
| 167 | 115 |
{
|
| 168 |
- Timer timers [timer_count]; |
|
| 169 |
- |
|
| 170 |
- uint8_t smp_regs [2] [reg_count]; |
|
| 171 |
- |
|
| 116 |
+ Timer timers[timer_count]; |
|
| 117 |
+ |
|
| 118 |
+ uint8_t smp_regs[2][reg_count]; |
|
| 119 |
+ |
|
| 172 | 120 |
struct |
| 173 | 121 |
{
|
| 174 | 122 |
int pc; |
| ... | ... |
@@ -178,139 +126,114 @@ private: |
| 178 | 126 |
int psw; |
| 179 | 127 |
int sp; |
| 180 | 128 |
} cpu_regs; |
| 181 |
- |
|
| 182 |
- rel_time_t dsp_time; |
|
| 183 |
- time_t spc_time; |
|
| 184 |
- bool echo_accessed; |
|
| 185 |
- |
|
| 186 |
- int tempo; |
|
| 187 |
- int skipped_kon; |
|
| 188 |
- int skipped_koff; |
|
| 189 |
- const char* cpu_error; |
|
| 190 |
- |
|
| 191 |
- int extra_clocks; |
|
| 192 |
- sample_t* buf_begin; |
|
| 193 |
- sample_t const* buf_end; |
|
| 194 |
- sample_t* extra_pos; |
|
| 195 |
- sample_t extra_buf [extra_size]; |
|
| 196 |
- |
|
| 197 |
- int rom_enabled; |
|
| 198 |
- uint8_t rom [rom_size]; |
|
| 199 |
- uint8_t hi_ram [rom_size]; |
|
| 200 |
- |
|
| 201 |
- unsigned char cycle_table [256]; |
|
| 202 |
- |
|
| 129 |
+ |
|
| 130 |
+ rel_time_t dsp_time; |
|
| 131 |
+ time_t spc_time; |
|
| 132 |
+ |
|
| 133 |
+ int tempo; |
|
| 134 |
+ |
|
| 135 |
+ int extra_clocks; |
|
| 136 |
+ sample_t *buf_begin; |
|
| 137 |
+ const sample_t *buf_end; |
|
| 138 |
+ sample_t *extra_pos; |
|
| 139 |
+ sample_t extra_buf[extra_size]; |
|
| 140 |
+ |
|
| 141 |
+ bool rom_enabled; |
|
| 142 |
+ uint8_t rom[rom_size]; |
|
| 143 |
+ uint8_t hi_ram[rom_size]; |
|
| 144 |
+ |
|
| 145 |
+ unsigned char cycle_table[256]; |
|
| 146 |
+ |
|
| 203 | 147 |
struct |
| 204 | 148 |
{
|
| 205 | 149 |
// padding to neutralize address overflow |
| 206 |
- union {
|
|
| 207 |
- uint8_t padding1 [0x100]; |
|
| 150 |
+ union |
|
| 151 |
+ {
|
|
| 152 |
+ uint8_t padding1[0x100]; |
|
| 208 | 153 |
uint16_t align; // makes compiler align data for 16-bit access |
| 209 |
- } padding1 [1]; |
|
| 210 |
- uint8_t ram [0x10000]; |
|
| 211 |
- uint8_t padding2 [0x100]; |
|
| 154 |
+ } padding1[1]; |
|
| 155 |
+ uint8_t ram[0x10000]; |
|
| 156 |
+ uint8_t padding2[0x100]; |
|
| 212 | 157 |
} ram; |
| 213 | 158 |
}; |
| 214 | 159 |
state_t m; |
| 215 |
- |
|
| 160 |
+ |
|
| 216 | 161 |
enum { rom_addr = 0xFFC0 };
|
| 217 |
- |
|
| 162 |
+ |
|
| 218 | 163 |
enum { skipping_time = 127 };
|
| 219 |
- |
|
| 164 |
+ |
|
| 220 | 165 |
// Value that padding should be filled with |
| 221 | 166 |
enum { cpu_pad_fill = 0xFF };
|
| 222 |
- |
|
| 223 |
- enum {
|
|
| 224 |
- r_test = 0x0, r_control = 0x1, |
|
| 225 |
- r_dspaddr = 0x2, r_dspdata = 0x3, |
|
| 226 |
- r_cpuio0 = 0x4, r_cpuio1 = 0x5, |
|
| 227 |
- r_cpuio2 = 0x6, r_cpuio3 = 0x7, |
|
| 228 |
- r_f8 = 0x8, r_f9 = 0x9, |
|
| 229 |
- r_t0target = 0xA, r_t1target = 0xB, r_t2target = 0xC, |
|
| 230 |
- r_t0out = 0xD, r_t1out = 0xE, r_t2out = 0xF |
|
| 167 |
+ |
|
| 168 |
+ enum |
|
| 169 |
+ {
|
|
| 170 |
+ r_test = 0x0, |
|
| 171 |
+ r_control = 0x1, |
|
| 172 |
+ r_dspaddr = 0x2, |
|
| 173 |
+ r_dspdata = 0x3, |
|
| 174 |
+ r_cpuio0 = 0x4, |
|
| 175 |
+ r_cpuio1 = 0x5, |
|
| 176 |
+ r_cpuio2 = 0x6, |
|
| 177 |
+ r_cpuio3 = 0x7, |
|
| 178 |
+ r_f8 = 0x8, |
|
| 179 |
+ r_f9 = 0x9, |
|
| 180 |
+ r_t0target = 0xA, |
|
| 181 |
+ r_t1target = 0xB, |
|
| 182 |
+ r_t2target = 0xC, |
|
| 183 |
+ r_t0out = 0xD, |
|
| 184 |
+ r_t1out = 0xE, |
|
| 185 |
+ r_t2out = 0xF |
|
| 231 | 186 |
}; |
| 232 |
- |
|
| 187 |
+ |
|
| 233 | 188 |
void timers_loaded(); |
| 234 |
- void enable_rom( int enable ); |
|
| 189 |
+ void enable_rom(bool enable); |
|
| 235 | 190 |
void reset_buf(); |
| 236 | 191 |
void save_extra(); |
| 237 |
- void load_regs( uint8_t const in [reg_count] ); |
|
| 192 |
+ void load_regs(const uint8_t in[reg_count]); |
|
| 238 | 193 |
void ram_loaded(); |
| 239 | 194 |
void regs_loaded(); |
| 240 | 195 |
void reset_time_regs(); |
| 241 |
- void reset_common( int timer_counter_init ); |
|
| 242 |
- |
|
| 243 |
- Timer* run_timer_ ( Timer* t, rel_time_t ); |
|
| 244 |
- Timer* run_timer ( Timer* t, rel_time_t ); |
|
| 245 |
- int dsp_read ( rel_time_t ); |
|
| 246 |
- void dsp_write ( int data, rel_time_t ); |
|
| 247 |
- void cpu_write_smp_reg_( int data, rel_time_t, int addr ); |
|
| 248 |
- void cpu_write_smp_reg ( int data, rel_time_t, int addr ); |
|
| 249 |
- void cpu_write_high ( int data, int i, rel_time_t ); |
|
| 250 |
- void cpu_write ( int data, int addr, rel_time_t ); |
|
| 251 |
- int cpu_read_smp_reg ( int i, rel_time_t ); |
|
| 252 |
- int cpu_read ( int addr, rel_time_t ); |
|
| 253 |
- unsigned CPU_mem_bit ( uint8_t const* pc, rel_time_t ); |
|
| 254 |
- |
|
| 255 |
- bool check_echo_access ( int addr ); |
|
| 256 |
- uint8_t* run_until_( time_t end_time ); |
|
| 257 |
- |
|
| 258 |
- struct spc_file_t |
|
| 259 |
- {
|
|
| 260 |
- char signature [signature_size]; |
|
| 261 |
- uint8_t has_id666; |
|
| 262 |
- uint8_t version; |
|
| 263 |
- uint8_t pcl, pch; |
|
| 264 |
- uint8_t a; |
|
| 265 |
- uint8_t x; |
|
| 266 |
- uint8_t y; |
|
| 267 |
- uint8_t psw; |
|
| 268 |
- uint8_t sp; |
|
| 269 |
- char text [212]; |
|
| 270 |
- uint8_t ram [0x10000]; |
|
| 271 |
- uint8_t dsp [128]; |
|
| 272 |
- uint8_t unused [0x40]; |
|
| 273 |
- uint8_t ipl_rom [0x40]; |
|
| 274 |
- }; |
|
| 275 |
- |
|
| 276 |
- static char const signature [signature_size + 1]; |
|
| 277 |
- |
|
| 278 |
- void save_regs( uint8_t out [reg_count] ); |
|
| 279 |
- |
|
| 280 |
-// Snes9x timing hack |
|
| 196 |
+ void reset_common(int timer_counter_init); |
|
| 197 |
+ |
|
| 198 |
+ Timer *run_timer_(Timer *t, rel_time_t); |
|
| 199 |
+ Timer *run_timer(Timer *t, rel_time_t); |
|
| 200 |
+ void RUN_DSP(rel_time_t); |
|
| 201 |
+ int dsp_read(rel_time_t); |
|
| 202 |
+ void dsp_write(int data, rel_time_t); |
|
| 203 |
+ void cpu_write_smp_reg_(int data, rel_time_t, int addr); |
|
| 204 |
+ void cpu_write_smp_reg(int data, rel_time_t, int addr); |
|
| 205 |
+ void cpu_write_high(int data, int i, rel_time_t); |
|
| 206 |
+ void cpu_write(int data, int addr, rel_time_t); |
|
| 207 |
+ int cpu_read_smp_reg(int i, rel_time_t); |
|
| 208 |
+ int cpu_read(int addr, rel_time_t); |
|
| 209 |
+ unsigned CPU_mem_bit(const uint8_t *pc, rel_time_t); |
|
| 210 |
+ |
|
| 211 |
+ bool check_echo_access(int addr); |
|
| 212 |
+ uint8_t *run_until_(time_t end_time); |
|
| 213 |
+ |
|
| 214 |
+ // Snes9x timing hack |
|
| 281 | 215 |
bool allow_time_overflow; |
| 282 |
-// Snes9x debugger |
|
| 283 |
-#ifdef DEBUGGER |
|
| 284 |
- FILE *apu_trace; |
|
| 285 |
- bool debug_trace; |
|
| 286 |
-#endif |
|
| 287 | 216 |
}; |
| 288 | 217 |
|
| 289 |
-#include <assert.h> |
|
| 290 |
- |
|
| 291 |
-inline int SNES_SPC::sample_count() const { return (m.extra_clocks >> 5) * 2; }
|
|
| 218 |
+inline int SNES_SPC::sample_count() const { return (this->m.extra_clocks >> 5) * 2; }
|
|
| 292 | 219 |
|
| 293 |
-inline int SNES_SPC::read_port( time_t t, int port ) |
|
| 220 |
+inline int SNES_SPC::read_port(time_t t, int port) |
|
| 294 | 221 |
{
|
| 295 |
- assert( (unsigned) port < port_count ); |
|
| 296 |
- return run_until_( t ) [port]; |
|
| 222 |
+ assert(static_cast<unsigned>(port) < port_count); |
|
| 223 |
+ return this->run_until_(t)[port]; |
|
| 297 | 224 |
} |
| 298 | 225 |
|
| 299 |
-inline void SNES_SPC::write_port( time_t t, int port, int data ) |
|
| 226 |
+inline void SNES_SPC::write_port(time_t t, int port, int data) |
|
| 300 | 227 |
{
|
| 301 |
- assert( (unsigned) port < port_count ); |
|
| 302 |
- run_until_( t ) [0x10 + port] = data; |
|
| 303 |
- m.ram.ram [0xF4 + port] = data; |
|
| 228 |
+ assert(static_cast<unsigned>(port) < port_count); |
|
| 229 |
+ this->run_until_(t)[0x10 + port] = data; |
|
| 230 |
+ this->m.ram.ram[0xF4 + port] = data; |
|
| 304 | 231 |
} |
| 305 | 232 |
|
| 306 |
-inline void SNES_SPC::mute_voices( int mask ) { dsp.mute_voices( mask ); }
|
|
| 233 |
+inline void SNES_SPC::mute_voices(int mask) { this->dsp.mute_voices(mask); }
|
|
| 307 | 234 |
|
| 308 |
-inline void SNES_SPC::disable_surround( bool disable ) { dsp.disable_surround( disable ); }
|
|
| 309 |
- |
|
| 310 |
-#if !SPC_NO_COPY_STATE_FUNCS |
|
| 311 |
-inline bool SNES_SPC::check_kon() { return dsp.check_kon(); }
|
|
| 312 |
-#endif |
|
| 235 |
+inline void SNES_SPC::disable_surround(bool disable) { this->dsp.disable_surround(disable); }
|
|
| 313 | 236 |
|
| 314 |
-inline void SNES_SPC::spc_allow_time_overflow( bool allow ) { allow_time_overflow = allow; }
|
|
| 237 |
+inline void SNES_SPC::spc_allow_time_overflow(bool allow) { this->allow_time_overflow = allow; }
|
|
| 315 | 238 |
|
| 316 | 239 |
#endif |
| 1 | 1 |
new file mode 100644 |
| ... | ... |
@@ -0,0 +1,316 @@ |
| 1 |
+// SNES SPC-700 APU emulator |
|
| 2 |
+ |
|
| 3 |
+// snes_spc 0.9.0 |
|
| 4 |
+#ifndef SNES_SPC_H |
|
| 5 |
+#define SNES_SPC_H |
|
| 6 |
+ |
|
| 7 |
+#include "SPC_DSP.h" |
|
| 8 |
+#include "blargg_endian.h" |
|
| 9 |
+ |
|
| 10 |
+#ifdef DEBUGGER |
|
| 11 |
+#include "snes9x.h" |
|
| 12 |
+#include "display.h" |
|
| 13 |
+#include "debug.h" |
|
| 14 |
+#endif |
|
| 15 |
+ |
|
| 16 |
+struct SNES_SPC {
|
|
| 17 |
+public: |
|
| 18 |
+ typedef BOOST::uint8_t uint8_t; |
|
| 19 |
+ |
|
| 20 |
+ // Must be called once before using |
|
| 21 |
+ blargg_err_t init(); |
|
| 22 |
+ |
|
| 23 |
+ // Sample pairs generated per second |
|
| 24 |
+ enum { sample_rate = 32000 };
|
|
| 25 |
+ |
|
| 26 |
+// Emulator use |
|
| 27 |
+ |
|
| 28 |
+ // Sets IPL ROM data. Library does not include ROM data. Most SPC music files |
|
| 29 |
+ // don't need ROM, but a full emulator must provide this. |
|
| 30 |
+ enum { rom_size = 0x40 };
|
|
| 31 |
+ void init_rom( uint8_t const rom [rom_size] ); |
|
| 32 |
+ |
|
| 33 |
+ // Sets destination for output samples |
|
| 34 |
+ typedef short sample_t; |
|
| 35 |
+ void set_output( sample_t* out, int out_size ); |
|
| 36 |
+ |
|
| 37 |
+ // Number of samples written to output since last set |
|
| 38 |
+ int sample_count() const; |
|
| 39 |
+ |
|
| 40 |
+ // Resets SPC to power-on state. This resets your output buffer, so you must |
|
| 41 |
+ // call set_output() after this. |
|
| 42 |
+ void reset(); |
|
| 43 |
+ |
|
| 44 |
+ // Emulates pressing reset switch on SNES. This resets your output buffer, so |
|
| 45 |
+ // you must call set_output() after this. |
|
| 46 |
+ void soft_reset(); |
|
| 47 |
+ |
|
| 48 |
+ // 1024000 SPC clocks per second, sample pair every 32 clocks |
|
| 49 |
+ typedef int time_t; |
|
| 50 |
+ enum { clock_rate = 1024000 };
|
|
| 51 |
+ enum { clocks_per_sample = 32 };
|
|
| 52 |
+ |
|
| 53 |
+ // Emulated port read/write at specified time |
|
| 54 |
+ enum { port_count = 4 };
|
|
| 55 |
+ int read_port ( time_t, int port ); |
|
| 56 |
+ void write_port( time_t, int port, int data ); |
|
| 57 |
+ |
|
| 58 |
+ // Runs SPC to end_time and starts a new time frame at 0 |
|
| 59 |
+ void end_frame( time_t end_time ); |
|
| 60 |
+ |
|
| 61 |
+// Sound control |
|
| 62 |
+ |
|
| 63 |
+ // Mutes voices corresponding to non-zero bits in mask (issues repeated KOFF events). |
|
| 64 |
+ // Reduces emulation accuracy. |
|
| 65 |
+ enum { voice_count = 8 };
|
|
| 66 |
+ void mute_voices( int mask ); |
|
| 67 |
+ |
|
| 68 |
+ // If true, prevents channels and global volumes from being phase-negated. |
|
| 69 |
+ // Only supported by fast DSP. |
|
| 70 |
+ void disable_surround( bool disable = true ); |
|
| 71 |
+ |
|
| 72 |
+ // Sets tempo, where tempo_unit = normal, tempo_unit / 2 = half speed, etc. |
|
| 73 |
+ enum { tempo_unit = 0x100 };
|
|
| 74 |
+ void set_tempo( int ); |
|
| 75 |
+ |
|
| 76 |
+// SPC music files |
|
| 77 |
+ |
|
| 78 |
+ // Loads SPC data into emulator |
|
| 79 |
+ enum { spc_min_file_size = 0x10180 };
|
|
| 80 |
+ enum { spc_file_size = 0x10200 };
|
|
| 81 |
+ blargg_err_t load_spc( void const* in, long size ); |
|
| 82 |
+ |
|
| 83 |
+ // Clears echo region. Useful after loading an SPC as many have garbage in echo. |
|
| 84 |
+ void clear_echo(); |
|
| 85 |
+ |
|
| 86 |
+ // Plays for count samples and write samples to out. Discards samples if out |
|
| 87 |
+ // is NULL. Count must be a multiple of 2 since output is stereo. |
|
| 88 |
+ blargg_err_t play( int count, sample_t* out ); |
|
| 89 |
+ |
|
| 90 |
+ // Skips count samples. Several times faster than play() when using fast DSP. |
|
| 91 |
+ blargg_err_t skip( int count ); |
|
| 92 |
+ |
|
| 93 |
+// State save/load (only available with accurate DSP) |
|
| 94 |
+ |
|
| 95 |
+#if !SPC_NO_COPY_STATE_FUNCS |
|
| 96 |
+ // Saves/loads state |
|
| 97 |
+ enum { state_size = 68 * 1024L }; // maximum space needed when saving
|
|
| 98 |
+ typedef SPC_DSP::copy_func_t copy_func_t; |
|
| 99 |
+ void copy_state( unsigned char** io, copy_func_t ); |
|
| 100 |
+ |
|
| 101 |
+ // Writes minimal header to spc_out |
|
| 102 |
+ static void init_header( void* spc_out ); |
|
| 103 |
+ |
|
| 104 |
+ // Saves emulator state as SPC file data. Writes spc_file_size bytes to spc_out. |
|
| 105 |
+ // Does not set up SPC header; use init_header() for that. |
|
| 106 |
+ void save_spc( void* spc_out ); |
|
| 107 |
+ |
|
| 108 |
+ // Returns true if new key-on events occurred since last check. Useful for |
|
| 109 |
+ // trimming silence while saving an SPC. |
|
| 110 |
+ bool check_kon(); |
|
| 111 |
+#endif |
|
| 112 |
+ |
|
| 113 |
+//// Snes9x Accessor |
|
| 114 |
+ |
|
| 115 |
+ void spc_allow_time_overflow( bool ); |
|
| 116 |
+ |
|
| 117 |
+ void dsp_set_spc_snapshot_callback(void (*callback)()); |
|
| 118 |
+ void dsp_dump_spc_snapshot(); |
|
| 119 |
+ void dsp_set_stereo_switch( int ); |
|
| 120 |
+ uint8_t dsp_reg_value( int, int ); |
|
| 121 |
+ int dsp_envx_value( int ); |
|
| 122 |
+ |
|
| 123 |
+//// Snes9x Debugger |
|
| 124 |
+ |
|
| 125 |
+#ifdef DEBUGGER |
|
| 126 |
+ void debug_toggle_trace(); |
|
| 127 |
+ bool debug_is_enabled(); |
|
| 128 |
+ void debug_do_trace( int, int, int, uint8_t const *, uint8_t *, int, int, int, int ); |
|
| 129 |
+ void debug_op_print( char *, int, int, int, uint8_t const *, uint8_t *, int, int, int, int ); |
|
| 130 |
+ void debug_io_print( char * ); |
|
| 131 |
+#endif |
|
| 132 |
+ |
|
| 133 |
+public: |
|
| 134 |
+ BLARGG_DISABLE_NOTHROW |
|
| 135 |
+ |
|
| 136 |
+ typedef BOOST::uint16_t uint16_t; |
|
| 137 |
+ |
|
| 138 |
+ // Time relative to m_spc_time. Speeds up code a bit by eliminating need to |
|
| 139 |
+ // constantly add m_spc_time to time from CPU. CPU uses time that ends at |
|
| 140 |
+ // 0 to eliminate reloading end time every instruction. It pays off. |
|
| 141 |
+ typedef int rel_time_t; |
|
| 142 |
+ |
|
| 143 |
+ struct Timer |
|
| 144 |
+ {
|
|
| 145 |
+ rel_time_t next_time; // time of next event |
|
| 146 |
+ int prescaler; |
|
| 147 |
+ int period; |
|
| 148 |
+ int divider; |
|
| 149 |
+ int enabled; |
|
| 150 |
+ int counter; |
|
| 151 |
+ }; |
|
| 152 |
+ enum { reg_count = 0x10 };
|
|
| 153 |
+ enum { timer_count = 3 };
|
|
| 154 |
+ enum { extra_size = SPC_DSP::extra_size };
|
|
| 155 |
+ |
|
| 156 |
+ enum { signature_size = 35 };
|
|
| 157 |
+ |
|
| 158 |
+private: |
|
| 159 |
+ SPC_DSP dsp; |
|
| 160 |
+ |
|
| 161 |
+ #if SPC_LESS_ACCURATE |
|
| 162 |
+ static signed char const reg_times_ [256]; |
|
| 163 |
+ signed char reg_times [256]; |
|
| 164 |
+ #endif |
|
| 165 |
+ |
|
| 166 |
+ struct state_t |
|
| 167 |
+ {
|
|
| 168 |
+ Timer timers [timer_count]; |
|
| 169 |
+ |
|
| 170 |
+ uint8_t smp_regs [2] [reg_count]; |
|
| 171 |
+ |
|
| 172 |
+ struct |
|
| 173 |
+ {
|
|
| 174 |
+ int pc; |
|
| 175 |
+ int a; |
|
| 176 |
+ int x; |
|
| 177 |
+ int y; |
|
| 178 |
+ int psw; |
|
| 179 |
+ int sp; |
|
| 180 |
+ } cpu_regs; |
|
| 181 |
+ |
|
| 182 |
+ rel_time_t dsp_time; |
|
| 183 |
+ time_t spc_time; |
|
| 184 |
+ bool echo_accessed; |
|
| 185 |
+ |
|
| 186 |
+ int tempo; |
|
| 187 |
+ int skipped_kon; |
|
| 188 |
+ int skipped_koff; |
|
| 189 |
+ const char* cpu_error; |
|
| 190 |
+ |
|
| 191 |
+ int extra_clocks; |
|
| 192 |
+ sample_t* buf_begin; |
|
| 193 |
+ sample_t const* buf_end; |
|
| 194 |
+ sample_t* extra_pos; |
|
| 195 |
+ sample_t extra_buf [extra_size]; |
|
| 196 |
+ |
|
| 197 |
+ int rom_enabled; |
|
| 198 |
+ uint8_t rom [rom_size]; |
|
| 199 |
+ uint8_t hi_ram [rom_size]; |
|
| 200 |
+ |
|
| 201 |
+ unsigned char cycle_table [256]; |
|
| 202 |
+ |
|
| 203 |
+ struct |
|
| 204 |
+ {
|
|
| 205 |
+ // padding to neutralize address overflow |
|
| 206 |
+ union {
|
|
| 207 |
+ uint8_t padding1 [0x100]; |
|
| 208 |
+ uint16_t align; // makes compiler align data for 16-bit access |
|
| 209 |
+ } padding1 [1]; |
|
| 210 |
+ uint8_t ram [0x10000]; |
|
| 211 |
+ uint8_t padding2 [0x100]; |
|
| 212 |
+ } ram; |
|
| 213 |
+ }; |
|
| 214 |
+ state_t m; |
|
| 215 |
+ |
|
| 216 |
+ enum { rom_addr = 0xFFC0 };
|
|
| 217 |
+ |
|
| 218 |
+ enum { skipping_time = 127 };
|
|
| 219 |
+ |
|
| 220 |
+ // Value that padding should be filled with |
|
| 221 |
+ enum { cpu_pad_fill = 0xFF };
|
|
| 222 |
+ |
|
| 223 |
+ enum {
|
|
| 224 |
+ r_test = 0x0, r_control = 0x1, |
|
| 225 |
+ r_dspaddr = 0x2, r_dspdata = 0x3, |
|
| 226 |
+ r_cpuio0 = 0x4, r_cpuio1 = 0x5, |
|
| 227 |
+ r_cpuio2 = 0x6, r_cpuio3 = 0x7, |
|
| 228 |
+ r_f8 = 0x8, r_f9 = 0x9, |
|
| 229 |
+ r_t0target = 0xA, r_t1target = 0xB, r_t2target = 0xC, |
|
| 230 |
+ r_t0out = 0xD, r_t1out = 0xE, r_t2out = 0xF |
|
| 231 |
+ }; |
|
| 232 |
+ |
|
| 233 |
+ void timers_loaded(); |
|
| 234 |
+ void enable_rom( int enable ); |
|
| 235 |
+ void reset_buf(); |
|
| 236 |
+ void save_extra(); |
|
| 237 |
+ void load_regs( uint8_t const in [reg_count] ); |
|
| 238 |
+ void ram_loaded(); |
|
| 239 |
+ void regs_loaded(); |
|
| 240 |
+ void reset_time_regs(); |
|
| 241 |
+ void reset_common( int timer_counter_init ); |
|
| 242 |
+ |
|
| 243 |
+ Timer* run_timer_ ( Timer* t, rel_time_t ); |
|
| 244 |
+ Timer* run_timer ( Timer* t, rel_time_t ); |
|
| 245 |
+ int dsp_read ( rel_time_t ); |
|
| 246 |
+ void dsp_write ( int data, rel_time_t ); |
|
| 247 |
+ void cpu_write_smp_reg_( int data, rel_time_t, int addr ); |
|
| 248 |
+ void cpu_write_smp_reg ( int data, rel_time_t, int addr ); |
|
| 249 |
+ void cpu_write_high ( int data, int i, rel_time_t ); |
|
| 250 |
+ void cpu_write ( int data, int addr, rel_time_t ); |
|
| 251 |
+ int cpu_read_smp_reg ( int i, rel_time_t ); |
|
| 252 |
+ int cpu_read ( int addr, rel_time_t ); |
|
| 253 |
+ unsigned CPU_mem_bit ( uint8_t const* pc, rel_time_t ); |
|
| 254 |
+ |
|
| 255 |
+ bool check_echo_access ( int addr ); |
|
| 256 |
+ uint8_t* run_until_( time_t end_time ); |
|
| 257 |
+ |
|
| 258 |
+ struct spc_file_t |
|
| 259 |
+ {
|
|
| 260 |
+ char signature [signature_size]; |
|
| 261 |
+ uint8_t has_id666; |
|
| 262 |
+ uint8_t version; |
|
| 263 |
+ uint8_t pcl, pch; |
|
| 264 |
+ uint8_t a; |
|
| 265 |
+ uint8_t x; |
|
| 266 |
+ uint8_t y; |
|
| 267 |
+ uint8_t psw; |
|
| 268 |
+ uint8_t sp; |
|
| 269 |
+ char text [212]; |
|
| 270 |
+ uint8_t ram [0x10000]; |
|
| 271 |
+ uint8_t dsp [128]; |
|
| 272 |
+ uint8_t unused [0x40]; |
|
| 273 |
+ uint8_t ipl_rom [0x40]; |
|
| 274 |
+ }; |
|
| 275 |
+ |
|
| 276 |
+ static char const signature [signature_size + 1]; |
|
| 277 |
+ |
|
| 278 |
+ void save_regs( uint8_t out [reg_count] ); |
|
| 279 |
+ |
|
| 280 |
+// Snes9x timing hack |
|
| 281 |
+ bool allow_time_overflow; |
|
| 282 |
+// Snes9x debugger |
|
| 283 |
+#ifdef DEBUGGER |
|
| 284 |
+ FILE *apu_trace; |
|
| 285 |
+ bool debug_trace; |
|
| 286 |
+#endif |
|
| 287 |
+}; |
|
| 288 |
+ |
|
| 289 |
+#include <assert.h> |
|
| 290 |
+ |
|
| 291 |
+inline int SNES_SPC::sample_count() const { return (m.extra_clocks >> 5) * 2; }
|
|
| 292 |
+ |
|
| 293 |
+inline int SNES_SPC::read_port( time_t t, int port ) |
|
| 294 |
+{
|
|
| 295 |
+ assert( (unsigned) port < port_count ); |
|
| 296 |
+ return run_until_( t ) [port]; |
|
| 297 |
+} |
|
| 298 |
+ |
|
| 299 |
+inline void SNES_SPC::write_port( time_t t, int port, int data ) |
|
| 300 |
+{
|
|
| 301 |
+ assert( (unsigned) port < port_count ); |
|
| 302 |
+ run_until_( t ) [0x10 + port] = data; |
|
| 303 |
+ m.ram.ram [0xF4 + port] = data; |
|
| 304 |
+} |
|
| 305 |
+ |
|
| 306 |
+inline void SNES_SPC::mute_voices( int mask ) { dsp.mute_voices( mask ); }
|
|
| 307 |
+ |
|
| 308 |
+inline void SNES_SPC::disable_surround( bool disable ) { dsp.disable_surround( disable ); }
|
|
| 309 |
+ |
|
| 310 |
+#if !SPC_NO_COPY_STATE_FUNCS |
|
| 311 |
+inline bool SNES_SPC::check_kon() { return dsp.check_kon(); }
|
|
| 312 |
+#endif |
|
| 313 |
+ |
|
| 314 |
+inline void SNES_SPC::spc_allow_time_overflow( bool allow ) { allow_time_overflow = allow; }
|
|
| 315 |
+ |
|
| 316 |
+#endif |