Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
RishiRecon
GitHub Repository: RishiRecon/exploits
Path: blob/main/misc/emulator/xnes/snes9x/apu/SNES_SPC.h
28798 views
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) (void) );
118
void dsp_dump_spc_snapshot( void );
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( void );
127
bool debug_is_enabled( void );
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
317
318