comparison src/console/Snes_Spc.cxx @ 341:986f098da058 trunk

[svn] - merge in blargg's changes
author nenolod
date Thu, 07 Dec 2006 15:20:41 -0800
parents fb513e10174e
children c31e94fefd2a
comparison
equal deleted inserted replaced
340:9e5a7158fa80 341:986f098da058
1 // Game_Music_Emu 0.5.1. http://www.slack.net/~ant/ 1 // Game_Music_Emu 0.5.2. http://www.slack.net/~ant/
2 2
3 #include "Snes_Spc.h" 3 #include "Snes_Spc.h"
4 4
5 #include <string.h> 5 #include <string.h>
6 6
18 #include "blargg_source.h" 18 #include "blargg_source.h"
19 19
20 // always in the future (CPU time can go over 0, but not by this much) 20 // always in the future (CPU time can go over 0, but not by this much)
21 int const timer_disabled_time = 127; 21 int const timer_disabled_time = 127;
22 22
23 Snes_Spc::Snes_Spc() : dsp( ram ), cpu( this, ram ) 23 Snes_Spc::Snes_Spc() : dsp( mem.ram ), cpu( this, mem.ram )
24 { 24 {
25 set_tempo( 1.0 ); 25 set_tempo( 1.0 );
26 26
27 // Put STOP instruction past end of memory to catch PC overflow. 27 // Put STOP instruction around memory to catch PC underflow/overflow.
28 memset( ram + ram_size, 0xFF, (sizeof ram) - ram_size ); 28 memset( mem.padding1, 0xFF, sizeof mem.padding1 );
29 memset( mem.padding2, 0xFF, sizeof mem.padding2 );
29 30
30 // A few tracks read from the last four bytes of IPL ROM 31 // A few tracks read from the last four bytes of IPL ROM
31 boot_rom [sizeof boot_rom - 2] = 0xC0; 32 boot_rom [sizeof boot_rom - 2] = 0xC0;
32 boot_rom [sizeof boot_rom - 1] = 0xFF; 33 boot_rom [sizeof boot_rom - 1] = 0xFF;
33 memset( boot_rom, 0, sizeof boot_rom - 2 ); 34 memset( boot_rom, 0, sizeof boot_rom - 2 );
63 char unused2 [212]; 64 char unused2 [212];
64 uint8_t ram [0x10000]; 65 uint8_t ram [0x10000];
65 uint8_t dsp [128]; 66 uint8_t dsp [128];
66 uint8_t ipl_rom [128]; 67 uint8_t ipl_rom [128];
67 }; 68 };
68 BOOST_STATIC_ASSERT( sizeof (spc_file_t) == spc_file_size + 128 ); 69 assert( offsetof (spc_file_t,ipl_rom) == spc_file_size );
69 70
70 const spc_file_t* spc = (spc_file_t const*) data; 71 const spc_file_t* spc = (spc_file_t const*) data;
71 72
72 if ( size < spc_file_size ) 73 if ( size < spc_file_size )
73 return "Not an SPC file"; 74 return "Not an SPC file";
96 void Snes_Spc::clear_echo() 97 void Snes_Spc::clear_echo()
97 { 98 {
98 if ( !(dsp.read( 0x6C ) & 0x20) ) 99 if ( !(dsp.read( 0x6C ) & 0x20) )
99 { 100 {
100 unsigned addr = 0x100 * dsp.read( 0x6D ); 101 unsigned addr = 0x100 * dsp.read( 0x6D );
101 unsigned size = 0x800 * dsp.read( 0x7D ); 102 size_t size = 0x800 * dsp.read( 0x7D );
102 memset( ram + addr, 0xFF, min( size, ram_size - addr ) ); 103 memset( mem.ram + addr, 0xFF, min( size, sizeof mem.ram - addr ) );
103 } 104 }
104 } 105 }
105 106
106 // Handle other file formats (emulator save states) in user code, not here. 107 // Handle other file formats (emulator save states) in user code, not here.
107 108
117 // since the SPC player adds a few extra cycles delay after restoring 118 // since the SPC player adds a few extra cycles delay after restoring
118 // KON from the DSP registers at the end of an SPC file). 119 // KON from the DSP registers at the end of an SPC file).
119 extra_cycles = 32; 120 extra_cycles = 32;
120 121
121 // ram 122 // ram
122 memcpy( ram, new_ram, ram_size ); 123 memcpy( mem.ram, new_ram, sizeof mem.ram );
123 memcpy( extra_ram, ram + rom_addr, sizeof extra_ram ); 124 memcpy( extra_ram, mem.ram + rom_addr, sizeof extra_ram );
124 125
125 // boot rom (have to force enable_rom() to update it) 126 // boot rom (have to force enable_rom() to update it)
126 rom_enabled = !(ram [0xF1] & 0x80); 127 rom_enabled = !(mem.ram [0xF1] & 0x80);
127 enable_rom( !rom_enabled ); 128 enable_rom( !rom_enabled );
128 129
129 // dsp 130 // dsp
130 dsp.reset(); 131 dsp.reset();
131 int i; 132 int i;
136 for ( i = 0; i < timer_count; i++ ) 137 for ( i = 0; i < timer_count; i++ )
137 { 138 {
138 Timer& t = timer [i]; 139 Timer& t = timer [i];
139 140
140 t.next_tick = 0; 141 t.next_tick = 0;
141 t.enabled = (ram [0xF1] >> i) & 1; 142 t.enabled = (mem.ram [0xF1] >> i) & 1;
142 if ( !t.enabled ) 143 if ( !t.enabled )
143 t.next_tick = timer_disabled_time; 144 t.next_tick = timer_disabled_time;
144 t.count = 0; 145 t.count = 0;
145 t.counter = ram [0xFD + i] & 15; 146 t.counter = mem.ram [0xFD + i] & 15;
146 147
147 int p = ram [0xFA + i]; 148 int p = mem.ram [0xFA + i];
148 t.period = p ? p : 0x100; 149 t.period = p ? p : 0x100;
149 } 150 }
150 151
151 // Handle registers which already give 0 when read by setting RAM and not changing it. 152 // Handle registers which already give 0 when read by setting RAM and not changing it.
152 // Put STOP instruction in registers which can be read, to catch attempted CPU execution. 153 // Put STOP instruction in registers which can be read, to catch attempted CPU execution.
153 ram [0xF0] = 0; 154 mem.ram [0xF0] = 0;
154 ram [0xF1] = 0; 155 mem.ram [0xF1] = 0;
155 ram [0xF3] = 0xFF; 156 mem.ram [0xF3] = 0xFF;
156 ram [0xFA] = 0; 157 mem.ram [0xFA] = 0;
157 ram [0xFB] = 0; 158 mem.ram [0xFB] = 0;
158 ram [0xFC] = 0; 159 mem.ram [0xFC] = 0;
159 ram [0xFD] = 0xFF; 160 mem.ram [0xFD] = 0xFF;
160 ram [0xFE] = 0xFF; 161 mem.ram [0xFE] = 0xFF;
161 ram [0xFF] = 0xFF; 162 mem.ram [0xFF] = 0xFF;
162 163
163 return 0; // success 164 return 0; // success
164 } 165 }
165 166
166 // Hardware 167 // Hardware
236 237
237 // Read 238 // Read
238 239
239 int Snes_Spc::read( spc_addr_t addr ) 240 int Snes_Spc::read( spc_addr_t addr )
240 { 241 {
241 int result = ram [addr]; 242 int result = mem.ram [addr];
242 243
243 if ( (rom_addr <= addr && addr < 0xFFFC || addr >= 0xFFFE) && rom_enabled ) 244 if ( (rom_addr <= addr && addr < 0xFFFC || addr >= 0xFFFE) && rom_enabled )
244 dprintf( "Read from ROM: %04X -> %02X\n", addr, result ); 245 dprintf( "Read from ROM: %04X -> %02X\n", addr, result );
245 246
246 if ( unsigned (addr - 0xF0) < 0x10 ) 247 if ( unsigned (addr - 0xF0) < 0x10 )
251 int i = addr - 0xFD; 252 int i = addr - 0xFD;
252 if ( i >= 0 ) 253 if ( i >= 0 )
253 { 254 {
254 Timer& t = timer [i]; 255 Timer& t = timer [i];
255 t.run_until( time() ); 256 t.run_until( time() );
256 int result = t.counter; 257 int old = t.counter;
257 t.counter = 0; 258 t.counter = 0;
258 return result; 259 return old;
259 } 260 }
260 261
261 // dsp 262 // dsp
262 if ( addr == 0xF3 ) 263 if ( addr == 0xF3 )
263 { 264 {
264 run_dsp( time() ); 265 run_dsp( time() );
265 if ( ram [0xF2] >= Spc_Dsp::register_count ) 266 if ( mem.ram [0xF2] >= Spc_Dsp::register_count )
266 dprintf( "DSP read from $%02X\n", (int) ram [0xF2] ); 267 dprintf( "DSP read from $%02X\n", (int) mem.ram [0xF2] );
267 return dsp.read( ram [0xF2] & 0x7F ); 268 return dsp.read( mem.ram [0xF2] & 0x7F );
268 } 269 }
269 270
270 if ( addr == 0xF0 || addr == 0xF1 || addr == 0xF8 || 271 if ( addr == 0xF0 || addr == 0xF1 || addr == 0xF8 ||
271 addr == 0xF9 || addr == 0xFA ) 272 addr == 0xF9 || addr == 0xFA )
272 dprintf( "Read from register $%02X\n", (int) addr ); 273 dprintf( "Read from register $%02X\n", (int) addr );
273 274
274 // Registers which always read as 0 are handled by setting ram [reg] to 0 275 // Registers which always read as 0 are handled by setting mem.ram [reg] to 0
275 // at startup then never changing that value. 276 // at startup then never changing that value.
276 277
277 check(( check_for_echo_access( addr ), true )); 278 check(( check_for_echo_access( addr ), true ));
278 } 279 }
279 280
286 void Snes_Spc::enable_rom( bool enable ) 287 void Snes_Spc::enable_rom( bool enable )
287 { 288 {
288 if ( rom_enabled != enable ) 289 if ( rom_enabled != enable )
289 { 290 {
290 rom_enabled = enable; 291 rom_enabled = enable;
291 memcpy( ram + rom_addr, (enable ? boot_rom : extra_ram), rom_size ); 292 memcpy( mem.ram + rom_addr, (enable ? boot_rom : extra_ram), rom_size );
292 // TODO: ROM can still get overwritten when DSP writes to echo buffer 293 // TODO: ROM can still get overwritten when DSP writes to echo buffer
293 } 294 }
294 } 295 }
295 296
296 void Snes_Spc::write( spc_addr_t addr, int data ) 297 void Snes_Spc::write( spc_addr_t addr, int data )
297 { 298 {
298 // first page is very common 299 // first page is very common
299 if ( addr < 0xF0 ) { 300 if ( addr < 0xF0 ) {
300 ram [addr] = (uint8_t) data; 301 mem.ram [addr] = (uint8_t) data;
301 } 302 }
302 else switch ( addr ) 303 else switch ( addr )
303 { 304 {
304 // RAM 305 // RAM
305 default: 306 default:
306 check(( check_for_echo_access( addr ), true )); 307 check(( check_for_echo_access( addr ), true ));
307 if ( addr < rom_addr ) { 308 if ( addr < rom_addr ) {
308 ram [addr] = (uint8_t) data; 309 mem.ram [addr] = (uint8_t) data;
309 } 310 }
310 else { 311 else {
311 extra_ram [addr - rom_addr] = (uint8_t) data; 312 extra_ram [addr - rom_addr] = (uint8_t) data;
312 if ( !rom_enabled ) 313 if ( !rom_enabled )
313 ram [addr] = (uint8_t) data; 314 mem.ram [addr] = (uint8_t) data;
314 } 315 }
315 break; 316 break;
316 317
317 // DSP 318 // DSP
318 //case 0xF2: // mapped to RAM 319 //case 0xF2: // mapped to RAM
319 case 0xF3: { 320 case 0xF3: {
320 run_dsp( time() ); 321 run_dsp( time() );
321 int reg = ram [0xF2]; 322 int reg = mem.ram [0xF2];
322 if ( next_dsp > 0 ) { 323 if ( next_dsp > 0 ) {
323 // skip mode 324 // skip mode
324 325
325 // key press 326 // key press
326 if ( reg == 0x4C ) 327 if ( reg == 0x4C )
365 } 366 }
366 } 367 }
367 368
368 // port clears 369 // port clears
369 if ( data & 0x10 ) { 370 if ( data & 0x10 ) {
370 ram [0xF4] = 0; 371 mem.ram [0xF4] = 0;
371 ram [0xF5] = 0; 372 mem.ram [0xF5] = 0;
372 } 373 }
373 if ( data & 0x20 ) { 374 if ( data & 0x20 ) {
374 ram [0xF6] = 0; 375 mem.ram [0xF6] = 0;
375 ram [0xF7] = 0; 376 mem.ram [0xF7] = 0;
376 } 377 }
377 378
378 enable_rom( data & 0x80 ); 379 enable_rom( data & 0x80 );
379 380
380 break; 381 break;