Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
RishiRecon
GitHub Repository: RishiRecon/exploits
Path: blob/main/misc/emulator/xnes/snes9x/apu/SNES_SPC_misc.cpp
28798 views
1
// SPC emulation support: init, sample buffering, reset, SPC loading
2
3
// snes_spc 0.9.0. http://www.slack.net/~ant/
4
5
#include "SNES_SPC.h"
6
7
#include <string.h>
8
9
/* Copyright (C) 2004-2007 Shay Green. This module is free software; you
10
can redistribute it and/or modify it under the terms of the GNU Lesser
11
General Public License as published by the Free Software Foundation; either
12
version 2.1 of the License, or (at your option) any later version. This
13
module is distributed in the hope that it will be useful, but WITHOUT ANY
14
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
15
FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
16
details. You should have received a copy of the GNU Lesser General Public
17
License along with this module; if not, write to the Free Software Foundation,
18
Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */
19
20
#include "blargg_source.h"
21
22
#define RAM (m.ram.ram)
23
#define REGS (m.smp_regs [0])
24
#define REGS_IN (m.smp_regs [1])
25
26
// (n ? n : 256)
27
#define IF_0_THEN_256( n ) ((uint8_t) ((n) - 1) + 1)
28
29
30
//// Init
31
32
blargg_err_t SNES_SPC::init()
33
{
34
memset( &m, 0, sizeof m );
35
dsp.init( RAM );
36
37
m.tempo = tempo_unit;
38
39
// Most SPC music doesn't need ROM, and almost all the rest only rely
40
// on these two bytes
41
m.rom [0x3E] = 0xFF;
42
m.rom [0x3F] = 0xC0;
43
44
static unsigned char const cycle_table [128] =
45
{// 01 23 45 67 89 AB CD EF
46
0x28,0x47,0x34,0x36,0x26,0x54,0x54,0x68, // 0
47
0x48,0x47,0x45,0x56,0x55,0x65,0x22,0x46, // 1
48
0x28,0x47,0x34,0x36,0x26,0x54,0x54,0x74, // 2
49
0x48,0x47,0x45,0x56,0x55,0x65,0x22,0x38, // 3
50
0x28,0x47,0x34,0x36,0x26,0x44,0x54,0x66, // 4
51
0x48,0x47,0x45,0x56,0x55,0x45,0x22,0x43, // 5
52
0x28,0x47,0x34,0x36,0x26,0x44,0x54,0x75, // 6
53
0x48,0x47,0x45,0x56,0x55,0x55,0x22,0x36, // 7
54
0x28,0x47,0x34,0x36,0x26,0x54,0x52,0x45, // 8
55
0x48,0x47,0x45,0x56,0x55,0x55,0x22,0xC5, // 9
56
0x38,0x47,0x34,0x36,0x26,0x44,0x52,0x44, // A
57
0x48,0x47,0x45,0x56,0x55,0x55,0x22,0x34, // B
58
0x38,0x47,0x45,0x47,0x25,0x64,0x52,0x49, // C
59
0x48,0x47,0x56,0x67,0x45,0x55,0x22,0x83, // D
60
0x28,0x47,0x34,0x36,0x24,0x53,0x43,0x40, // E
61
0x48,0x47,0x45,0x56,0x34,0x54,0x22,0x60, // F
62
};
63
64
// unpack cycle table
65
for ( int i = 0; i < 128; i++ )
66
{
67
int n = cycle_table [i];
68
m.cycle_table [i * 2 + 0] = n >> 4;
69
m.cycle_table [i * 2 + 1] = n & 0x0F;
70
}
71
72
allow_time_overflow = false;
73
74
dsp.rom = m.rom;
75
dsp.hi_ram = m.hi_ram;
76
77
#ifdef DEBUGGER
78
apu_trace = NULL;
79
debug_trace = false;
80
#endif
81
82
#if SPC_LESS_ACCURATE
83
memcpy( reg_times, reg_times_, sizeof reg_times );
84
#endif
85
86
reset();
87
return 0;
88
}
89
90
void SNES_SPC::init_rom( uint8_t const in [rom_size] )
91
{
92
memcpy( m.rom, in, sizeof m.rom );
93
}
94
95
void SNES_SPC::set_tempo( int t )
96
{
97
m.tempo = t;
98
int const timer2_shift = 4; // 64 kHz
99
int const other_shift = 3; // 8 kHz
100
101
#if SPC_DISABLE_TEMPO
102
m.timers [2].prescaler = timer2_shift;
103
m.timers [1].prescaler = timer2_shift + other_shift;
104
m.timers [0].prescaler = timer2_shift + other_shift;
105
#else
106
if ( !t )
107
t = 1;
108
int const timer2_rate = 1 << timer2_shift;
109
int rate = (timer2_rate * tempo_unit + (t >> 1)) / t;
110
if ( rate < timer2_rate / 4 )
111
rate = timer2_rate / 4; // max 4x tempo
112
m.timers [2].prescaler = rate;
113
m.timers [1].prescaler = rate << other_shift;
114
m.timers [0].prescaler = rate << other_shift;
115
#endif
116
}
117
118
// Timer registers have been loaded. Applies these to the timers. Does not
119
// reset timer prescalers or dividers.
120
void SNES_SPC::timers_loaded()
121
{
122
int i;
123
for ( i = 0; i < timer_count; i++ )
124
{
125
Timer* t = &m.timers [i];
126
t->period = IF_0_THEN_256( REGS [r_t0target + i] );
127
t->enabled = REGS [r_control] >> i & 1;
128
t->counter = REGS_IN [r_t0out + i] & 0x0F;
129
}
130
131
set_tempo( m.tempo );
132
}
133
134
// Loads registers from unified 16-byte format
135
void SNES_SPC::load_regs( uint8_t const in [reg_count] )
136
{
137
memcpy( REGS, in, reg_count );
138
memcpy( REGS_IN, REGS, reg_count );
139
140
// These always read back as 0
141
REGS_IN [r_test ] = 0;
142
REGS_IN [r_control ] = 0;
143
REGS_IN [r_t0target] = 0;
144
REGS_IN [r_t1target] = 0;
145
REGS_IN [r_t2target] = 0;
146
}
147
148
// RAM was just loaded from SPC, with $F0-$FF containing SMP registers
149
// and timer counts. Copies these to proper registers.
150
void SNES_SPC::ram_loaded()
151
{
152
m.rom_enabled = dsp.rom_enabled = 0;
153
load_regs( &RAM [0xF0] );
154
155
// Put STOP instruction around memory to catch PC underflow/overflow
156
memset( m.ram.padding1, cpu_pad_fill, sizeof m.ram.padding1 );
157
memset( m.ram.padding2, cpu_pad_fill, sizeof m.ram.padding2 );
158
}
159
160
// Registers were just loaded. Applies these new values.
161
void SNES_SPC::regs_loaded()
162
{
163
enable_rom( REGS [r_control] & 0x80 );
164
timers_loaded();
165
}
166
167
void SNES_SPC::reset_time_regs()
168
{
169
m.cpu_error = 0;
170
m.echo_accessed = 0;
171
m.spc_time = 0;
172
m.dsp_time = 0;
173
#if SPC_LESS_ACCURATE
174
m.dsp_time = clocks_per_sample + 1;
175
#endif
176
177
for ( int i = 0; i < timer_count; i++ )
178
{
179
Timer* t = &m.timers [i];
180
t->next_time = 1;
181
t->divider = 0;
182
}
183
184
regs_loaded();
185
186
m.extra_clocks = 0;
187
reset_buf();
188
}
189
190
void SNES_SPC::reset_common( int timer_counter_init )
191
{
192
int i;
193
for ( i = 0; i < timer_count; i++ )
194
REGS_IN [r_t0out + i] = timer_counter_init;
195
196
// Run IPL ROM
197
memset( &m.cpu_regs, 0, sizeof m.cpu_regs );
198
m.cpu_regs.pc = rom_addr;
199
200
REGS [r_test ] = 0x0A;
201
REGS [r_control] = 0xB0; // ROM enabled, clear ports
202
for ( i = 0; i < port_count; i++ )
203
REGS_IN [r_cpuio0 + i] = 0;
204
205
reset_time_regs();
206
}
207
208
void SNES_SPC::soft_reset()
209
{
210
reset_common( 0 );
211
dsp.soft_reset();
212
}
213
214
void SNES_SPC::reset()
215
{
216
m.cpu_regs.pc = 0xFFC0;
217
m.cpu_regs.a = 0x00;
218
m.cpu_regs.x = 0x00;
219
m.cpu_regs.y = 0x00;
220
m.cpu_regs.psw = 0x02;
221
m.cpu_regs.sp = 0xEF;
222
memset( RAM, 0x00, 0x10000 );
223
ram_loaded();
224
reset_common( 0x0F );
225
dsp.reset();
226
}
227
228
char const SNES_SPC::signature [signature_size + 1] =
229
"SNES-SPC700 Sound File Data v0.30\x1A\x1A";
230
231
blargg_err_t SNES_SPC::load_spc( void const* data, long size )
232
{
233
spc_file_t const* const spc = (spc_file_t const*) data;
234
235
// be sure compiler didn't insert any padding into fle_t
236
assert( sizeof (spc_file_t) == spc_min_file_size + 0x80 );
237
238
// Check signature and file size
239
if ( size < signature_size || memcmp( spc, signature, 27 ) )
240
return "Not an SPC file";
241
242
if ( size < spc_min_file_size )
243
return "Corrupt SPC file";
244
245
// CPU registers
246
m.cpu_regs.pc = spc->pch * 0x100 + spc->pcl;
247
m.cpu_regs.a = spc->a;
248
m.cpu_regs.x = spc->x;
249
m.cpu_regs.y = spc->y;
250
m.cpu_regs.psw = spc->psw;
251
m.cpu_regs.sp = spc->sp;
252
253
// RAM and registers
254
memcpy( RAM, spc->ram, 0x10000 );
255
ram_loaded();
256
257
// DSP registers
258
dsp.load( spc->dsp );
259
260
reset_time_regs();
261
262
return 0;
263
}
264
265
void SNES_SPC::clear_echo()
266
{
267
if ( !(dsp.read( SPC_DSP::r_flg ) & 0x20) )
268
{
269
int addr = 0x100 * dsp.read( SPC_DSP::r_esa );
270
int end = addr + 0x800 * (dsp.read( SPC_DSP::r_edl ) & 0x0F);
271
if ( end > 0x10000 )
272
end = 0x10000;
273
memset( &RAM [addr], 0xFF, end - addr );
274
}
275
}
276
277
278
//// Sample output
279
280
void SNES_SPC::reset_buf()
281
{
282
// Start with half extra buffer of silence
283
sample_t* out = m.extra_buf;
284
while ( out < &m.extra_buf [extra_size / 2] )
285
*out++ = 0;
286
287
m.extra_pos = out;
288
m.buf_begin = 0;
289
290
dsp.set_output( 0, 0 );
291
}
292
293
void SNES_SPC::set_output( sample_t* out, int size )
294
{
295
require( (size & 1) == 0 ); // size must be even
296
297
m.extra_clocks &= clocks_per_sample - 1;
298
if ( out )
299
{
300
sample_t const* out_end = out + size;
301
m.buf_begin = out;
302
m.buf_end = out_end;
303
304
// Copy extra to output
305
sample_t const* in = m.extra_buf;
306
while ( in < m.extra_pos && out < out_end )
307
*out++ = *in++;
308
309
// Handle output being full already
310
if ( out >= out_end )
311
{
312
// Have DSP write to remaining extra space
313
out = dsp.extra();
314
out_end = &dsp.extra() [extra_size];
315
316
// Copy any remaining extra samples as if DSP wrote them
317
while ( in < m.extra_pos )
318
*out++ = *in++;
319
assert( out <= out_end );
320
}
321
322
dsp.set_output( out, out_end - out );
323
}
324
else
325
{
326
reset_buf();
327
}
328
}
329
330
void SNES_SPC::save_extra()
331
{
332
// Get end pointers
333
sample_t const* main_end = m.buf_end; // end of data written to buf
334
sample_t const* dsp_end = dsp.out_pos(); // end of data written to dsp.extra()
335
if ( m.buf_begin <= dsp_end && dsp_end <= main_end )
336
{
337
main_end = dsp_end;
338
dsp_end = dsp.extra(); // nothing in DSP's extra
339
}
340
341
// Copy any extra samples at these ends into extra_buf
342
sample_t* out = m.extra_buf;
343
sample_t const* in;
344
for ( in = m.buf_begin + sample_count(); in < main_end; in++ )
345
*out++ = *in;
346
for ( in = dsp.extra(); in < dsp_end ; in++ )
347
*out++ = *in;
348
349
m.extra_pos = out;
350
assert( out <= &m.extra_buf [extra_size] );
351
}
352
353
blargg_err_t SNES_SPC::play( int count, sample_t* out )
354
{
355
require( (count & 1) == 0 ); // must be even
356
if ( count )
357
{
358
set_output( out, count );
359
end_frame( count * (clocks_per_sample / 2) );
360
}
361
362
const char* err = m.cpu_error;
363
m.cpu_error = 0;
364
return err;
365
}
366
367
blargg_err_t SNES_SPC::skip( int count )
368
{
369
#if SPC_LESS_ACCURATE
370
if ( count > 2 * sample_rate * 2 )
371
{
372
set_output( 0, 0 );
373
374
// Skip a multiple of 4 samples
375
time_t end = count;
376
count = (count & 3) + 1 * sample_rate * 2;
377
end = (end - count) * (clocks_per_sample / 2);
378
379
m.skipped_kon = 0;
380
m.skipped_koff = 0;
381
382
// Preserve DSP and timer synchronization
383
// TODO: verify that this really preserves it
384
int old_dsp_time = m.dsp_time + m.spc_time;
385
m.dsp_time = end - m.spc_time + skipping_time;
386
end_frame( end );
387
m.dsp_time = m.dsp_time - skipping_time + old_dsp_time;
388
389
dsp.write( SPC_DSP::r_koff, m.skipped_koff & ~m.skipped_kon );
390
dsp.write( SPC_DSP::r_kon , m.skipped_kon );
391
clear_echo();
392
}
393
#endif
394
395
return play( count, 0 );
396
}
397
398
//// Snes9x Accessor
399
400
void SNES_SPC::dsp_set_spc_snapshot_callback( void (*callback) (void) )
401
{
402
dsp.set_spc_snapshot_callback( callback );
403
}
404
405
void SNES_SPC::dsp_dump_spc_snapshot( void )
406
{
407
dsp.dump_spc_snapshot();
408
}
409
410
void SNES_SPC::dsp_set_stereo_switch( int value )
411
{
412
dsp.set_stereo_switch( value );
413
}
414
415
SNES_SPC::uint8_t SNES_SPC::dsp_reg_value( int ch, int addr )
416
{
417
return dsp.reg_value( ch, addr );
418
}
419
420
int SNES_SPC::dsp_envx_value( int ch )
421
{
422
return dsp.envx_value( ch );
423
}
424
425
//// Snes9x debugger
426
427
#ifdef DEBUGGER
428
429
void SNES_SPC::debug_toggle_trace( void )
430
{
431
debug_trace = !debug_trace;
432
433
if (debug_trace)
434
{
435
printf("APU tracing enabled.\n");
436
ENSURE_TRACE_OPEN(apu_trace, "apu_trace.log", "wb")
437
}
438
else
439
{
440
printf("APU tracing disabled.\n");
441
fclose(apu_trace);
442
apu_trace = NULL;
443
}
444
}
445
446
bool SNES_SPC::debug_is_enabled( void ) { return debug_trace; }
447
448
void SNES_SPC::debug_do_trace( int a, int x, int y, uint8_t const *pc, uint8_t *sp, int psw, int c, int nz, int dp )
449
{
450
char msg[512];
451
452
ENSURE_TRACE_OPEN(apu_trace, "apu_trace.log", "a")
453
454
debug_op_print(msg, a, x, y, pc, sp, psw, c, nz, dp);
455
fprintf(apu_trace, "%s ", msg);
456
debug_io_print(msg);
457
fprintf(apu_trace, "%s ", msg);
458
S9xPrintHVPosition(msg);
459
fprintf(apu_trace, "%s\n", msg);
460
}
461
462
void SNES_SPC::debug_op_print( char *buffer, int a, int x, int y, uint8_t const *pc, uint8_t *sp, int psw, int c, int nz, int dp )
463
{
464
static char mnemonics[256][20] =
465
{
466
"NOP",
467
"TCALL 0",
468
"SET1 $%02X.0",
469
"BBS $%02X.0,$%04X",
470
"OR A,$%02X",
471
"OR A,!$%04X",
472
"OR A,(X)",
473
"OR A,[$%02X+X]",
474
"OR A,#$%02X",
475
"OR $%02X,$%02X",
476
"OR1 C,$%04X.%d",
477
"ASL $%02X",
478
"MOV !$%04X,Y",
479
"PUSH PSW",
480
"TSET1 !$%04X",
481
"BRK",
482
"BPL $%04X",
483
"TCALL 1",
484
"CLR1 $%02X.0",
485
"BBC $%02X.0,$%04X",
486
"OR A,$%02X+X",
487
"OR A,!$%04X+X",
488
"OR A,!$%04X+Y",
489
"OR A,[$%02X]+Y",
490
"OR $%02X,#$%02X",
491
"OR (X),(Y)",
492
"DECW $%02X",
493
"ASL $%02X+X",
494
"ASL A",
495
"DEC X",
496
"CMP X,!$%04X",
497
"JMP [!$%04X+X]",
498
"CLRP",
499
"TCALL 2",
500
"SET1 $%02X.1",
501
"BBS $%02X.1,$%04X",
502
"AND A,$%02X",
503
"AND A,!$%04X",
504
"AND A,(X)",
505
"AND A,[$%02X+X]",
506
"AND A,#$%02X",
507
"AND $%02X,$%02X",
508
"OR1 C,/$%04X.%d",
509
"ROL $%02X",
510
"ROL !$%04X",
511
"PUSH A",
512
"CBNE $%02X,$%04X",
513
"BRA $%04X",
514
"BMI $%04X",
515
"TCALL 3",
516
"CLR1 $%02X.1",
517
"BBC $%02X.1,$%04X",
518
"AND A,$%02X+X",
519
"AND A,!$%04X+X",
520
"AND A,!$%04X+Y",
521
"AND A,[$%02X]+Y",
522
"AND $%02X,#$%02X",
523
"AND (X),(Y)",
524
"INCW $%02X",
525
"ROL $%02X+X",
526
"ROL A",
527
"INC X",
528
"CMP X,$%02X",
529
"CALL !$%04X",
530
"SETP",
531
"TCALL 4",
532
"SET1 $%02X.2",
533
"BBS $%02X.2,$%04X",
534
"EOR A,$%02X",
535
"EOR A,!$%04X",
536
"EOR A,(X)",
537
"EOR A,[$%02X+X]",
538
"EOR A,#$%02X",
539
"EOR $%02X,$%02X",
540
"AND1 C,$%04X.%d",
541
"LSR $%02X",
542
"LSR !$%04X",
543
"PUSH X",
544
"TCLR1 !$%04X",
545
"PCALL $%02X",
546
"BVC $%04X",
547
"TCALL 5",
548
"CLR1 $%02X.2",
549
"BBC $%02X.2,$%04X",
550
"EOR A,$%02X+X",
551
"EOR A,!$%04X+X",
552
"EOR A,!$%04X+Y",
553
"EOR A,[$%02X]+Y",
554
"EOR $%02X,#$%02X",
555
"EOR (X),(Y)",
556
"CMPW YA,$%02X",
557
"LSR $%02X+X",
558
"LSR A",
559
"MOV X,A",
560
"CMP Y,!$%04X",
561
"JMP !$%04X",
562
"CLRC",
563
"TCALL 6",
564
"SET1 $%02X.3",
565
"BBS $%02X.3,$%04X",
566
"CMP A,$%02X",
567
"CMP A,!$%04X",
568
"CMP A,(X)",
569
"CMP A,[$%02X+X]",
570
"CMP A,#$%02X",
571
"CMP $%02X,$%02X",
572
"AND1 C,/$%04X.%d",
573
"ROR $%02X",
574
"ROR !$%04X",
575
"PUSH Y",
576
"DBNZ $%02X,$%04X",
577
"RET",
578
"BVS $%04X",
579
"TCALL 7",
580
"CLR1 $%02X.3",
581
"BBC $%02X.3,$%04X",
582
"CMP A,$%02X+X",
583
"CMP A,!$%04X+X",
584
"CMP A,!$%04X+Y",
585
"CMP A,[$%02X]+Y",
586
"CMP $%02X,#$%02X",
587
"CMP (X),(Y)",
588
"ADDW YA,$%02X",
589
"ROR $%02X+X",
590
"ROR A",
591
"MOV A,X",
592
"CMP Y,$%02X",
593
"RET1",
594
"SETC",
595
"TCALL 8",
596
"SET1 $%02X.4",
597
"BBS $%02X.4,$%04X",
598
"ADC A,$%02X",
599
"ADC A,!$%04X",
600
"ADC A,(X)",
601
"ADC A,[$%02X+X]",
602
"ADC A,#$%02X",
603
"ADC $%02X,$%02X",
604
"EOR1 C,$%04X.%d",
605
"DEC $%02X",
606
"DEC !$%04X",
607
"MOV Y,#$%02X",
608
"POP PSW",
609
"MOV $%02X,#$%02X",
610
"BCC $%04X",
611
"TCALL 9",
612
"CLR1 $%02X.4",
613
"BBC $%02X.4,$%04X",
614
"ADC A,$%02X+X",
615
"ADC A,!$%04X+X",
616
"ADC A,!$%04X+Y",
617
"ADC A,[$%02X]+Y",
618
"ADC $%02X,#$%02X",
619
"ADC (X),(Y)",
620
"SUBW YA,$%02X",
621
"DEC $%02X+X",
622
"DEC A",
623
"MOV X,SP",
624
"DIV YA,X",
625
"XCN A",
626
"EI",
627
"TCALL 10",
628
"SET1 $%02X.5",
629
"BBS $%02X.5,$%04X",
630
"SBC A,$%02X",
631
"SBC A,!$%04X",
632
"SBC A,(X)",
633
"SBC A,[$%02X+X]",
634
"SBC A,#$%02X",
635
"SBC $%02X,$%02X",
636
"MOV1 C,$%04X.%d",
637
"INC $%02X",
638
"INC !$%04X",
639
"CMP Y,#$%02X",
640
"POP A",
641
"MOV (X)+,A",
642
"BCS $%04X",
643
"TCALL 11",
644
"CLR1 $%02X.5",
645
"BBC $%02X.5,$%04X",
646
"SBC A,$%02X+X",
647
"SBC A,!$%04X+X",
648
"SBC A,!$%04X+Y",
649
"SBC A,[$%02X]+Y",
650
"SBC $%02X,#$%02X",
651
"SBC (X),(Y)",
652
"MOVW YA,$%02X",
653
"INC $%02X+X",
654
"INC A",
655
"MOV SP,X",
656
"DAS A",
657
"MOV A,(X)+",
658
"DI",
659
"TCALL 12",
660
"SET1 $%02X.6",
661
"BBS $%02X.6,$%04X",
662
"MOV $%02X,A",
663
"MOV !$%04X,A",
664
"MOV (X),A",
665
"MOV [$%02X+X],A",
666
"CMP X,#$%02X",
667
"MOV !$%04X,X",
668
"MOV1 $%04X.%d,C",
669
"MOV $%02X,Y",
670
"ASL !$%04X",
671
"MOV X,#$%02X",
672
"POP X",
673
"MUL YA",
674
"BNE $%04X",
675
"TCALL 13",
676
"CLR1 $%02X.6",
677
"BBC $%02X.6,$%04X",
678
"MOV $%02X+X,A",
679
"MOV !$%04X+X,A",
680
"MOV !$%04X+Y,A",
681
"MOV [$%02X]+Y,A",
682
"MOV $%02X,X",
683
"MOV $%02X+Y,X",
684
"MOVW $%02X,YA",
685
"MOV $%02X+X,Y",
686
"DEC Y",
687
"MOV A,Y",
688
"CBNE $%02X+X,$%04X",
689
"DAA A",
690
"CLRV",
691
"TCALL 14",
692
"SET1 $%02X.7",
693
"BBS $%02X.7,$%04X",
694
"MOV A,$%02X",
695
"MOV A,!$%04X",
696
"MOV A,(X)",
697
"MOV A,[$%02X+X]",
698
"MOV A,#$%02X",
699
"MOV X,!$%04X",
700
"NOT1 $%04X.%d",
701
"MOV Y,$%02X",
702
"MOV Y,!$%04X",
703
"NOTC",
704
"POP Y",
705
"SLEEP",
706
"BEQ $%04X",
707
"TCALL 15",
708
"CLR1 $%02X.7",
709
"BBC $%02X.7,$%04X",
710
"MOV A,$%02X+X",
711
"MOV A,!$%04X+X",
712
"MOV A,!$%04X+Y",
713
"MOV A,[$%02X]+Y",
714
"MOV X,$%02X",
715
"MOV X,$%02X+Y",
716
"MOV $%02X,$%02X",
717
"MOV Y,$%02X+X",
718
"INC Y",
719
"MOV Y,A",
720
"DBNZ Y,$%04X",
721
"STOP"
722
};
723
724
static int modes[256] =
725
{
726
2, 2, 0, 5, 0, 1, 2, 0, 0, 3, 6, 0, 1, 2, 1, 2,
727
7, 2, 0, 5, 0, 1, 1, 0, 4, 2, 0, 0, 2, 2, 1, 1,
728
2, 2, 0, 5, 0, 1, 2, 0, 0, 3, 6, 0, 1, 2, 5, 7,
729
7, 2, 0, 5, 0, 1, 1, 0, 4, 2, 0, 0, 2, 2, 0, 1,
730
2, 2, 0, 5, 0, 1, 2, 0, 0, 3, 6, 0, 1, 2, 1, 0,
731
7, 2, 0, 5, 0, 1, 1, 0, 4, 2, 0, 0, 2, 2, 1, 1,
732
2, 2, 0, 5, 0, 1, 2, 0, 0, 3, 6, 0, 1, 2, 5, 2,
733
7, 2, 0, 5, 0, 1, 1, 0, 4, 2, 0, 0, 2, 2, 0, 2,
734
2, 2, 0, 5, 0, 1, 2, 0, 0, 3, 6, 0, 1, 0, 2, 4,
735
7, 2, 0, 5, 0, 1, 1, 0, 4, 2, 0, 0, 2, 2, 2, 2,
736
2, 2, 0, 5, 0, 1, 2, 0, 0, 3, 6, 0, 1, 0, 2, 2,
737
7, 2, 0, 5, 0, 1, 1, 0, 4, 2, 0, 0, 2, 2, 2, 2,
738
2, 2, 0, 5, 0, 1, 2, 0, 0, 1, 6, 0, 1, 0, 2, 2,
739
7, 2, 0, 5, 0, 1, 1, 0, 0, 0, 0, 0, 2, 2, 5, 2,
740
2, 2, 0, 5, 0, 1, 2, 0, 0, 1, 6, 0, 1, 2, 2, 2,
741
7, 2, 0, 5, 0, 1, 1, 0, 0, 0, 3, 0, 2, 2, 7, 2
742
};
743
744
static int modesToBytes[] =
745
{
746
2, 3, 1, 3, 3, 3, 3, 2
747
};
748
749
int const n80 = 0x80; // nz
750
int const p20 = 0x20; // dp
751
int const z02 = 0x02; // nz
752
int const c01 = 0x01; // c
753
754
#define GET_PC() (pc - ram)
755
#define GET_SP() (sp - 0x101 - ram)
756
#define GET_PSW( out )\
757
{\
758
out = psw & ~(n80 | p20 | z02 | c01);\
759
out |= c >> 8 & c01;\
760
out |= dp >> 3 & p20;\
761
out |= ((nz >> 4) | nz) & n80;\
762
if ( !(uint8_t) nz ) out |= z02;\
763
}
764
765
uint8_t const *ram = RAM;
766
767
int addr;
768
int tsp, tpsw;
769
uint8_t d0, d1, d2;
770
771
addr = GET_PC();
772
tsp = GET_SP();
773
GET_PSW(tpsw);
774
775
d0 = *pc;
776
d1 = (addr < 0xffff) ? *(pc + 1) : 0;
777
d2 = (addr < 0xfffe) ? *(pc + 2) : 0;
778
779
int mode = modes[d0];
780
int bytes = modesToBytes[mode];
781
char mnem[100];
782
783
switch (bytes)
784
{
785
case 1:
786
sprintf(buffer, "%04X %02X ", addr, d0);
787
break;
788
789
case 2:
790
sprintf(buffer, "%04X %02X %02X ", addr, d0, d1);
791
break;
792
793
case 3:
794
sprintf(buffer, "%04X %02X %02X %02X ", addr, d0, d1, d2);
795
break;
796
}
797
798
switch (mode)
799
{
800
case 0:
801
sprintf(mnem, mnemonics[d0], d1);
802
break;
803
804
case 1:
805
sprintf(mnem, mnemonics[d0], d1 + (d2 << 8));
806
break;
807
808
case 2:
809
strcpy (mnem, mnemonics[d0]);
810
break;
811
812
case 3:
813
sprintf(mnem, mnemonics[d0], d2, d1);
814
break;
815
816
case 4:
817
sprintf(mnem, mnemonics[d0], d2, d1);
818
break;
819
820
case 5:
821
sprintf(mnem, mnemonics[d0], d1, addr + 3 + (int8_t) d2);
822
break;
823
824
case 6:
825
sprintf(mnem, mnemonics[d0], (d1 + (d2 << 8)) & 0x1fff, d2 >> 5);
826
break;
827
828
case 7:
829
sprintf(mnem, mnemonics[d0], addr + 2 + (int8_t) d1);
830
break;
831
}
832
833
sprintf(buffer, "%s %-20s A:%02X X:%02X Y:%02X S:%02X P:%c%c%c%c%c%c%c%c ROM:%d",
834
buffer, mnem, a, x, y, tsp,
835
(tpsw & 0x80) ? 'N' : 'n',
836
(tpsw & 0x40) ? 'V' : 'v',
837
(tpsw & 0x20) ? 'P' : 'p',
838
(tpsw & 0x10) ? 'B' : 'b',
839
(tpsw & 0x08) ? 'H' : 'h',
840
(tpsw & 0x04) ? 'I' : 'i',
841
(tpsw & 0x02) ? 'Z' : 'z',
842
(tpsw & 0x01) ? 'C' : 'c',
843
m.rom_enabled ? 1 : 0);
844
}
845
846
void SNES_SPC::debug_io_print( char *buffer )
847
{
848
sprintf(buffer, "i/o %02X/%02X %02X/%02X %02X/%02X %02X/%02X",
849
m.smp_regs[1][r_cpuio0], m.smp_regs[0][r_cpuio0],
850
m.smp_regs[1][r_cpuio1], m.smp_regs[0][r_cpuio1],
851
m.smp_regs[1][r_cpuio2], m.smp_regs[0][r_cpuio2],
852
m.smp_regs[1][r_cpuio3], m.smp_regs[0][r_cpuio3]);
853
}
854
855
#endif
856
857