Mercurial > audlegacy-plugins
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; |