Mercurial > audlegacy-plugins
comparison src/console/Nes_Cpu.cxx @ 341:986f098da058 trunk
[svn] - merge in blargg's changes
author | nenolod |
---|---|
date | Thu, 07 Dec 2006 15:20:41 -0800 |
parents | fb513e10174e |
children |
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 "Nes_Cpu.h" | 3 #include "Nes_Cpu.h" |
4 | 4 |
5 #include "blargg_endian.h" | 5 #include "blargg_endian.h" |
6 #include <limits.h> | 6 #include <limits.h> |
20 | 20 |
21 #ifdef BLARGG_ENABLE_OPTIMIZER | 21 #ifdef BLARGG_ENABLE_OPTIMIZER |
22 #include BLARGG_ENABLE_OPTIMIZER | 22 #include BLARGG_ENABLE_OPTIMIZER |
23 #endif | 23 #endif |
24 | 24 |
25 #define SYNC_TIME() (void) (s.time = s_time) | 25 #define FLUSH_TIME() (void) (s.time = s_time) |
26 #define RELOAD_TIME() (void) (s_time = s.time) | 26 #define CACHE_TIME() (void) (s_time = s.time) |
27 | 27 |
28 #include "nes_cpu_io.h" | 28 #include "nes_cpu_io.h" |
29 | 29 |
30 #include "blargg_source.h" | 30 #include "blargg_source.h" |
31 | 31 |
34 #endif | 34 #endif |
35 | 35 |
36 #ifndef CPU_READ_PPU | 36 #ifndef CPU_READ_PPU |
37 #define CPU_READ_PPU( cpu, addr, out, time )\ | 37 #define CPU_READ_PPU( cpu, addr, out, time )\ |
38 {\ | 38 {\ |
39 SYNC_TIME();\ | 39 FLUSH_TIME();\ |
40 out = CPU_READ( cpu, addr, time );\ | 40 out = CPU_READ( cpu, addr, time );\ |
41 RELOAD_TIME();\ | 41 CACHE_TIME();\ |
42 } | 42 } |
43 #endif | 43 #endif |
44 | 44 |
45 #if BLARGG_NONPORTABLE | 45 #if BLARGG_NONPORTABLE |
46 #define PAGE_OFFSET( addr ) (addr) | 46 #define PAGE_OFFSET( addr ) (addr) |
136 SET_SP( r.sp ); | 136 SET_SP( r.sp ); |
137 | 137 |
138 // status flags | 138 // status flags |
139 #define IS_NEG (nz & 0x8080) | 139 #define IS_NEG (nz & 0x8080) |
140 | 140 |
141 #define CALC_STATUS( out ) do { \ | 141 #define CALC_STATUS( out ) do {\ |
142 out = status & (st_v | st_d | st_i); \ | 142 out = status & (st_v | st_d | st_i);\ |
143 out |= ((nz >> 8) | nz) & st_n; \ | 143 out |= ((nz >> 8) | nz) & st_n;\ |
144 out |= c >> 8 & st_c; \ | 144 out |= c >> 8 & st_c;\ |
145 if ( !(nz & 0xFF) ) out |= st_z; \ | 145 if ( !(nz & 0xFF) ) out |= st_z;\ |
146 } while ( 0 ) | 146 } while ( 0 ) |
147 | 147 |
148 #define SET_STATUS( in ) do { \ | 148 #define SET_STATUS( in ) do {\ |
149 status = in & (st_v | st_d | st_i); \ | 149 status = in & (st_v | st_d | st_i);\ |
150 nz = in << 8; \ | 150 nz = in << 8;\ |
151 c = nz; \ | 151 c = nz;\ |
152 nz |= ~in & st_z; \ | 152 nz |= ~in & st_z;\ |
153 } while ( 0 ) | 153 } while ( 0 ) |
154 | 154 |
155 fuint8 status; | 155 fuint8 status; |
156 fuint16 c; // carry set if (c & 0x100) != 0 | 156 fuint16 c; // carry set if (c & 0x100) != 0 |
157 fuint16 nz; // Z set if (nz & 0xFF) == 0, N set if (nz & 0x8080) != 0 | 157 fuint16 nz; // Z set if (nz & 0xFF) == 0, N set if (nz & 0x8080) != 0 |
164 dec_clock_loop: | 164 dec_clock_loop: |
165 s_time--; | 165 s_time--; |
166 loop: | 166 loop: |
167 | 167 |
168 check( (unsigned) GET_SP() < 0x100 ); | 168 check( (unsigned) GET_SP() < 0x100 ); |
169 check( (unsigned) pc < 0x10000 ); | |
169 check( (unsigned) a < 0x100 ); | 170 check( (unsigned) a < 0x100 ); |
170 check( (unsigned) x < 0x100 ); | 171 check( (unsigned) x < 0x100 ); |
171 check( (unsigned) y < 0x100 ); | 172 check( (unsigned) y < 0x100 ); |
172 check( -32768 <= s_time && s_time < 32767 ); | 173 check( -32768 <= s_time && s_time < 32767 ); |
173 | 174 |
235 #endif | 236 #endif |
236 | 237 |
237 // Macros | 238 // Macros |
238 | 239 |
239 #define GET_MSB() (instr [1]) | 240 #define GET_MSB() (instr [1]) |
240 #define ADD_PAGE (pc++, data += 0x100 * GET_MSB()); | 241 #define ADD_PAGE() (pc++, data += 0x100 * GET_MSB()) |
241 #define GET_ADDR() GET_LE16( instr ) | 242 #define GET_ADDR() GET_LE16( instr ) |
242 | 243 |
243 #define NO_PAGE_CROSSING( lsb ) | 244 #define NO_PAGE_CROSSING( lsb ) |
244 #define HANDLE_PAGE_CROSSING( lsb ) s_time += (lsb) >> 8; | 245 #define HANDLE_PAGE_CROSSING( lsb ) s_time += (lsb) >> 8; |
245 | 246 |
246 #define INC_DEC_XY( reg, n ) reg = uint8_t (nz = reg + n); goto loop; | 247 #define INC_DEC_XY( reg, n ) reg = uint8_t (nz = reg + n); goto loop; |
247 | 248 |
248 #define IND_Y( cross, out ) { \ | 249 #define IND_Y( cross, out ) {\ |
249 fuint16 temp = READ_LOW( data ) + y; \ | 250 fuint16 temp = READ_LOW( data ) + y;\ |
250 out = temp + 0x100 * READ_LOW( uint8_t (data + 1) ); \ | 251 out = temp + 0x100 * READ_LOW( uint8_t (data + 1) );\ |
251 cross( temp ); \ | 252 cross( temp );\ |
252 } | 253 } |
253 | 254 |
254 #define IND_X( out ) { \ | 255 #define IND_X( out ) {\ |
255 fuint16 temp = data + x; \ | 256 fuint16 temp = data + x;\ |
256 out = 0x100 * READ_LOW( uint8_t (temp + 1) ) + READ_LOW( uint8_t (temp) ); \ | 257 out = 0x100 * READ_LOW( uint8_t (temp + 1) ) + READ_LOW( uint8_t (temp) );\ |
257 } | 258 } |
258 | 259 |
259 #define ARITH_ADDR_MODES( op ) \ | 260 #define ARITH_ADDR_MODES( op )\ |
260 case op - 0x04: /* (ind,x) */ \ | 261 case op - 0x04: /* (ind,x) */\ |
261 IND_X( data ) \ | 262 IND_X( data )\ |
262 goto ptr##op; \ | 263 goto ptr##op;\ |
263 case op + 0x0C: /* (ind),y */ \ | 264 case op + 0x0C: /* (ind),y */\ |
264 IND_Y( HANDLE_PAGE_CROSSING, data ) \ | 265 IND_Y( HANDLE_PAGE_CROSSING, data )\ |
265 goto ptr##op; \ | 266 goto ptr##op;\ |
266 case op + 0x10: /* zp,X */ \ | 267 case op + 0x10: /* zp,X */\ |
267 data = uint8_t (data + x); \ | 268 data = uint8_t (data + x);\ |
268 case op + 0x00: /* zp */ \ | 269 case op + 0x00: /* zp */\ |
269 data = READ_LOW( data ); \ | 270 data = READ_LOW( data );\ |
270 goto imm##op; \ | 271 goto imm##op;\ |
271 case op + 0x14: /* abs,Y */ \ | 272 case op + 0x14: /* abs,Y */\ |
272 data += y; \ | 273 data += y;\ |
273 goto ind##op; \ | 274 goto ind##op;\ |
274 case op + 0x18: /* abs,X */ \ | 275 case op + 0x18: /* abs,X */\ |
275 data += x; \ | 276 data += x;\ |
276 ind##op: \ | 277 ind##op:\ |
277 HANDLE_PAGE_CROSSING( data ); \ | 278 HANDLE_PAGE_CROSSING( data );\ |
278 case op + 0x08: /* abs */ \ | 279 case op + 0x08: /* abs */\ |
279 ADD_PAGE \ | 280 ADD_PAGE();\ |
280 ptr##op: \ | 281 ptr##op:\ |
281 SYNC_TIME(); \ | 282 FLUSH_TIME();\ |
282 data = READ( data ); \ | 283 data = READ( data );\ |
283 RELOAD_TIME(); \ | 284 CACHE_TIME();\ |
284 case op + 0x04: /* imm */ \ | 285 case op + 0x04: /* imm */\ |
285 imm##op: \ | 286 imm##op: |
286 | 287 |
287 #define BRANCH( cond ) \ | 288 // TODO: more efficient way to handle negative branch that wraps PC around |
288 { \ | 289 #define BRANCH( cond )\ |
289 fint16 offset = (BOOST::int8_t) data; \ | 290 {\ |
291 fint16 offset = (BOOST::int8_t) data;\ | |
290 fuint16 extra_clock = (++pc & 0xFF) + offset;\ | 292 fuint16 extra_clock = (++pc & 0xFF) + offset;\ |
291 if ( !(cond) ) goto dec_clock_loop; \ | 293 if ( !(cond) ) goto dec_clock_loop;\ |
292 pc += offset; \ | 294 pc = BOOST::uint16_t (pc + offset);\ |
293 s_time += extra_clock >> 8 & 1; \ | 295 s_time += extra_clock >> 8 & 1;\ |
294 goto loop; \ | 296 goto loop;\ |
295 } | 297 } |
296 | 298 |
297 // Often-Used | 299 // Often-Used |
298 | 300 |
299 case 0xB5: // LDA zp,x | 301 case 0xB5: // LDA zp,x |
405 { | 407 { |
406 WRITE_LOW( addr, a ); | 408 WRITE_LOW( addr, a ); |
407 goto loop; | 409 goto loop; |
408 } | 410 } |
409 sta_ptr: | 411 sta_ptr: |
410 SYNC_TIME(); | 412 FLUSH_TIME(); |
411 WRITE( addr, a ); | 413 WRITE( addr, a ); |
412 RELOAD_TIME(); | 414 CACHE_TIME(); |
413 goto loop; | 415 goto loop; |
414 | 416 |
415 case 0x91: // STA (ind),Y | 417 case 0x91: // STA (ind),Y |
416 IND_Y( NO_PAGE_CROSSING, addr ) | 418 IND_Y( NO_PAGE_CROSSING, addr ) |
417 pc++; | 419 pc++; |
464 pc += 2; | 466 pc += 2; |
465 a = nz = READ_PROG( addr ); | 467 a = nz = READ_PROG( addr ); |
466 if ( (addr ^ 0x8000) <= 0x9FFF ) | 468 if ( (addr ^ 0x8000) <= 0x9FFF ) |
467 goto loop; | 469 goto loop; |
468 a_nz_read_addr: | 470 a_nz_read_addr: |
469 SYNC_TIME(); | 471 FLUSH_TIME(); |
470 a = nz = READ( addr ); | 472 a = nz = READ( addr ); |
471 RELOAD_TIME(); | 473 CACHE_TIME(); |
472 goto loop; | 474 goto loop; |
473 | 475 |
474 } | 476 } |
475 | 477 |
476 // Branch | 478 // Branch |
527 data += x; | 529 data += x; |
528 HANDLE_PAGE_CROSSING( data ); | 530 HANDLE_PAGE_CROSSING( data ); |
529 case 0xAC:{// LDY abs | 531 case 0xAC:{// LDY abs |
530 unsigned addr = data + 0x100 * GET_MSB(); | 532 unsigned addr = data + 0x100 * GET_MSB(); |
531 pc += 2; | 533 pc += 2; |
532 SYNC_TIME(); | 534 FLUSH_TIME(); |
533 y = nz = READ( addr ); | 535 y = nz = READ( addr ); |
534 RELOAD_TIME(); | 536 CACHE_TIME(); |
535 goto loop; | 537 goto loop; |
536 } | 538 } |
537 | 539 |
538 case 0xBE: // LDX abs,y | 540 case 0xBE: // LDX abs,y |
539 data += y; | 541 data += y; |
540 HANDLE_PAGE_CROSSING( data ); | 542 HANDLE_PAGE_CROSSING( data ); |
541 case 0xAE:{// LDX abs | 543 case 0xAE:{// LDX abs |
542 unsigned addr = data + 0x100 * GET_MSB(); | 544 unsigned addr = data + 0x100 * GET_MSB(); |
543 pc += 2; | 545 pc += 2; |
544 SYNC_TIME(); | 546 FLUSH_TIME(); |
545 x = nz = READ( addr ); | 547 x = nz = READ( addr ); |
546 RELOAD_TIME(); | 548 CACHE_TIME(); |
547 goto loop; | 549 goto loop; |
548 } | 550 } |
549 | 551 |
550 { | 552 { |
551 fuint8 temp; | 553 fuint8 temp; |
561 if ( addr <= 0x7FF ) | 563 if ( addr <= 0x7FF ) |
562 { | 564 { |
563 WRITE_LOW( addr, temp ); | 565 WRITE_LOW( addr, temp ); |
564 goto loop; | 566 goto loop; |
565 } | 567 } |
566 SYNC_TIME(); | 568 FLUSH_TIME(); |
567 WRITE( addr, temp ); | 569 WRITE( addr, temp ); |
568 RELOAD_TIME(); | 570 CACHE_TIME(); |
569 goto loop; | 571 goto loop; |
570 } | 572 } |
571 | 573 |
572 // Compare | 574 // Compare |
573 | 575 |
574 case 0xEC:{// CPX abs | 576 case 0xEC:{// CPX abs |
575 unsigned addr = GET_ADDR(); | 577 unsigned addr = GET_ADDR(); |
576 pc++; | 578 pc++; |
577 SYNC_TIME(); | 579 FLUSH_TIME(); |
578 data = READ( addr ); | 580 data = READ( addr ); |
579 RELOAD_TIME(); | 581 CACHE_TIME(); |
580 goto cpx_data; | 582 goto cpx_data; |
581 } | 583 } |
582 | 584 |
583 case 0xE4: // CPX zp | 585 case 0xE4: // CPX zp |
584 data = READ_LOW( data ); | 586 data = READ_LOW( data ); |
591 goto loop; | 593 goto loop; |
592 | 594 |
593 case 0xCC:{// CPY abs | 595 case 0xCC:{// CPY abs |
594 unsigned addr = GET_ADDR(); | 596 unsigned addr = GET_ADDR(); |
595 pc++; | 597 pc++; |
596 SYNC_TIME(); | 598 FLUSH_TIME(); |
597 data = READ( addr ); | 599 data = READ( addr ); |
598 RELOAD_TIME(); | 600 CACHE_TIME(); |
599 goto cpy_data; | 601 goto cpy_data; |
600 } | 602 } |
601 | 603 |
602 case 0xC4: // CPY zp | 604 case 0xC4: // CPY zp |
603 data = READ_LOW( data ); | 605 data = READ_LOW( data ); |
697 data += x; | 699 data += x; |
698 case 0x4E: // LSR abs | 700 case 0x4E: // LSR abs |
699 c = 0; | 701 c = 0; |
700 case 0x6E: // ROR abs | 702 case 0x6E: // ROR abs |
701 ror_abs: { | 703 ror_abs: { |
702 ADD_PAGE | 704 ADD_PAGE(); |
703 SYNC_TIME(); | 705 FLUSH_TIME(); |
704 int temp = READ( data ); | 706 int temp = READ( data ); |
705 nz = (c >> 1 & 0x80) | (temp >> 1); | 707 nz = (c >> 1 & 0x80) | (temp >> 1); |
706 c = temp << 8; | 708 c = temp << 8; |
707 goto rotate_common; | 709 goto rotate_common; |
708 } | 710 } |
715 data += x; | 717 data += x; |
716 case 0x0E: // ASL abs | 718 case 0x0E: // ASL abs |
717 c = 0; | 719 c = 0; |
718 case 0x2E: // ROL abs | 720 case 0x2E: // ROL abs |
719 rol_abs: | 721 rol_abs: |
720 ADD_PAGE | 722 ADD_PAGE(); |
721 nz = c >> 8 & 1; | 723 nz = c >> 8 & 1; |
722 SYNC_TIME(); | 724 FLUSH_TIME(); |
723 nz |= (c = READ( data ) << 1); | 725 nz |= (c = READ( data ) << 1); |
724 rotate_common: | 726 rotate_common: |
725 pc++; | 727 pc++; |
726 WRITE( data, (uint8_t) nz ); | 728 WRITE( data, (uint8_t) nz ); |
727 RELOAD_TIME(); | 729 CACHE_TIME(); |
728 goto loop; | 730 goto loop; |
729 | 731 |
730 case 0x7E: // ROR abs,X | 732 case 0x7E: // ROR abs,X |
731 data += x; | 733 data += x; |
732 goto ror_abs; | 734 goto ror_abs; |
803 case 0xCE: // DEC abs | 805 case 0xCE: // DEC abs |
804 data = GET_ADDR(); | 806 data = GET_ADDR(); |
805 dec_ptr: | 807 dec_ptr: |
806 nz = (unsigned) -1; | 808 nz = (unsigned) -1; |
807 inc_common: | 809 inc_common: |
808 SYNC_TIME(); | 810 FLUSH_TIME(); |
809 nz += READ( data ); | 811 nz += READ( data ); |
810 pc += 2; | 812 pc += 2; |
811 WRITE( data, (uint8_t) nz ); | 813 WRITE( data, (uint8_t) nz ); |
812 RELOAD_TIME(); | 814 CACHE_TIME(); |
813 goto loop; | 815 goto loop; |
814 | 816 |
815 // Transfer | 817 // Transfer |
816 | 818 |
817 case 0xAA: // TAX | 819 case 0xAA: // TAX |
1048 goto loop; | 1050 goto loop; |
1049 } | 1051 } |
1050 | 1052 |
1051 out_of_time: | 1053 out_of_time: |
1052 pc--; | 1054 pc--; |
1053 SYNC_TIME(); | 1055 FLUSH_TIME(); |
1054 CPU_DONE( this, TIME, result_ ); | 1056 CPU_DONE( this, TIME, result_ ); |
1055 RELOAD_TIME(); | 1057 CACHE_TIME(); |
1056 if ( result_ >= 0 ) | 1058 if ( result_ >= 0 ) |
1057 goto interrupt; | 1059 goto interrupt; |
1058 if ( s_time < 0 ) | 1060 if ( s_time < 0 ) |
1059 goto loop; | 1061 goto loop; |
1060 | 1062 |