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