comparison src/console/Sap_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 "Sap_Cpu.h" 3 #include "Sap_Cpu.h"
4 4
5 #include <limits.h> 5 #include <limits.h>
6 #include "blargg_endian.h" 6 #include "blargg_endian.h"
16 FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more 16 FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
17 details. You should have received a copy of the GNU Lesser General Public 17 details. You should have received a copy of the GNU Lesser General Public
18 License along with this module; if not, write to the Free Software Foundation, 18 License along with this module; if not, write to the Free Software Foundation,
19 Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ 19 Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */
20 20
21 #define SYNC_TIME() (void) (s.time = s_time) 21 #define FLUSH_TIME() (void) (s.time = s_time)
22 #define RELOAD_TIME() (void) (s_time = s.time) 22 #define CACHE_TIME() (void) (s_time = s.time)
23 23
24 #include "sap_cpu_io.h" 24 #include "sap_cpu_io.h"
25 25
26 #ifndef CPU_DONE 26 #ifndef CPU_DONE
27 #define CPU_DONE( cpu, time, result_out ) { result_out = -1; } 27 #define CPU_DONE( cpu, time, result_out ) { result_out = -1; }
92 SET_SP( r.sp ); 92 SET_SP( r.sp );
93 93
94 // status flags 94 // status flags
95 #define IS_NEG (nz & 0x8080) 95 #define IS_NEG (nz & 0x8080)
96 96
97 #define CALC_STATUS( out ) do { \ 97 #define CALC_STATUS( out ) do {\
98 out = status & (st_v | st_d | st_i); \ 98 out = status & (st_v | st_d | st_i);\
99 out |= ((nz >> 8) | nz) & st_n; \ 99 out |= ((nz >> 8) | nz) & st_n;\
100 out |= c >> 8 & st_c; \ 100 out |= c >> 8 & st_c;\
101 if ( !(nz & 0xFF) ) out |= st_z; \ 101 if ( !(nz & 0xFF) ) out |= st_z;\
102 } while ( 0 ) 102 } while ( 0 )
103 103
104 #define SET_STATUS( in ) do { \ 104 #define SET_STATUS( in ) do {\
105 status = in & (st_v | st_d | st_i); \ 105 status = in & (st_v | st_d | st_i);\
106 nz = in << 8; \ 106 nz = in << 8;\
107 c = nz; \ 107 c = nz;\
108 nz |= ~in & st_z; \ 108 nz |= ~in & st_z;\
109 } while ( 0 ) 109 } while ( 0 )
110 110
111 fuint8 status; 111 fuint8 status;
112 fuint16 c; // carry set if (c & 0x100) != 0 112 fuint16 c; // carry set if (c & 0x100) != 0
113 fuint16 nz; // Z set if (nz & 0xFF) == 0, N set if (nz & 0x8080) != 0 113 fuint16 nz; // Z set if (nz & 0xFF) == 0, N set if (nz & 0x8080) != 0
180 goto out_of_time; 180 goto out_of_time;
181 181
182 // Macros 182 // Macros
183 183
184 #define GET_MSB() (instr [1]) 184 #define GET_MSB() (instr [1])
185 #define ADD_PAGE (pc++, data += 0x100 * GET_MSB()); 185 #define ADD_PAGE() (pc++, data += 0x100 * GET_MSB())
186 #define GET_ADDR() GET_LE16( instr ) 186 #define GET_ADDR() GET_LE16( instr )
187 187
188 #define NO_PAGE_CROSSING( lsb ) 188 #define NO_PAGE_CROSSING( lsb )
189 #define HANDLE_PAGE_CROSSING( lsb ) s_time += (lsb) >> 8; 189 #define HANDLE_PAGE_CROSSING( lsb ) s_time += (lsb) >> 8;
190 190
191 #define INC_DEC_XY( reg, n ) reg = uint8_t (nz = reg + n); goto loop; 191 #define INC_DEC_XY( reg, n ) reg = uint8_t (nz = reg + n); goto loop;
192 192
193 #define IND_Y( cross, out ) { \ 193 #define IND_Y( cross, out ) {\
194 fuint16 temp = READ_LOW( data ) + y; \ 194 fuint16 temp = READ_LOW( data ) + y;\
195 out = temp + 0x100 * READ_LOW( uint8_t (data + 1) ); \ 195 out = temp + 0x100 * READ_LOW( uint8_t (data + 1) );\
196 cross( temp ); \ 196 cross( temp );\
197 } 197 }
198 198
199 #define IND_X( out ) { \ 199 #define IND_X( out ) {\
200 fuint16 temp = data + x; \ 200 fuint16 temp = data + x;\
201 out = 0x100 * READ_LOW( uint8_t (temp + 1) ) + READ_LOW( uint8_t (temp) ); \ 201 out = 0x100 * READ_LOW( uint8_t (temp + 1) ) + READ_LOW( uint8_t (temp) );\
202 } 202 }
203 203
204 #define ARITH_ADDR_MODES( op ) \ 204 #define ARITH_ADDR_MODES( op )\
205 case op - 0x04: /* (ind,x) */ \ 205 case op - 0x04: /* (ind,x) */\
206 IND_X( data ) \ 206 IND_X( data )\
207 goto ptr##op; \ 207 goto ptr##op;\
208 case op + 0x0C: /* (ind),y */ \ 208 case op + 0x0C: /* (ind),y */\
209 IND_Y( HANDLE_PAGE_CROSSING, data ) \ 209 IND_Y( HANDLE_PAGE_CROSSING, data )\
210 goto ptr##op; \ 210 goto ptr##op;\
211 case op + 0x10: /* zp,X */ \ 211 case op + 0x10: /* zp,X */\
212 data = uint8_t (data + x); \ 212 data = uint8_t (data + x);\
213 case op + 0x00: /* zp */ \ 213 case op + 0x00: /* zp */\
214 data = READ_LOW( data ); \ 214 data = READ_LOW( data );\
215 goto imm##op; \ 215 goto imm##op;\
216 case op + 0x14: /* abs,Y */ \ 216 case op + 0x14: /* abs,Y */\
217 data += y; \ 217 data += y;\
218 goto ind##op; \ 218 goto ind##op;\
219 case op + 0x18: /* abs,X */ \ 219 case op + 0x18: /* abs,X */\
220 data += x; \ 220 data += x;\
221 ind##op: \ 221 ind##op:\
222 HANDLE_PAGE_CROSSING( data ); \ 222 HANDLE_PAGE_CROSSING( data );\
223 case op + 0x08: /* abs */ \ 223 case op + 0x08: /* abs */\
224 ADD_PAGE \ 224 ADD_PAGE();\
225 ptr##op: \ 225 ptr##op:\
226 SYNC_TIME(); \ 226 FLUSH_TIME();\
227 data = READ( data ); \ 227 data = READ( data );\
228 RELOAD_TIME(); \ 228 CACHE_TIME();\
229 case op + 0x04: /* imm */ \ 229 case op + 0x04: /* imm */\
230 imm##op: \ 230 imm##op:
231 231
232 #define BRANCH( cond ) \ 232 // TODO: more efficient way to handle negative branch that wraps PC around
233 { \ 233 #define BRANCH( cond )\
234 fint16 offset = (BOOST::int8_t) data; \ 234 {\
235 fint16 offset = (BOOST::int8_t) data;\
235 fuint16 extra_clock = (++pc & 0xFF) + offset;\ 236 fuint16 extra_clock = (++pc & 0xFF) + offset;\
236 if ( !(cond) ) goto dec_clock_loop; \ 237 if ( !(cond) ) goto dec_clock_loop;\
237 pc += offset; \ 238 pc += offset;\
238 s_time += extra_clock >> 8 & 1; \ 239 s_time += extra_clock >> 8 & 1;\
239 goto loop; \ 240 goto loop;\
240 } 241 }
241 242
242 // Often-Used 243 // Often-Used
243 244
244 case 0xB5: // LDA zp,x 245 case 0xB5: // LDA zp,x
350 { 351 {
351 WRITE_LOW( addr, a ); 352 WRITE_LOW( addr, a );
352 goto loop; 353 goto loop;
353 } 354 }
354 sta_ptr: 355 sta_ptr:
355 SYNC_TIME(); 356 FLUSH_TIME();
356 WRITE( addr, a ); 357 WRITE( addr, a );
357 RELOAD_TIME(); 358 CACHE_TIME();
358 goto loop; 359 goto loop;
359 360
360 case 0x91: // STA (ind),Y 361 case 0x91: // STA (ind),Y
361 IND_Y( NO_PAGE_CROSSING, addr ) 362 IND_Y( NO_PAGE_CROSSING, addr )
362 pc++; 363 pc++;
409 pc += 2; 410 pc += 2;
410 a = nz = READ_PROG( addr ); 411 a = nz = READ_PROG( addr );
411 if ( (addr ^ 0x8000) <= 0x9FFF ) 412 if ( (addr ^ 0x8000) <= 0x9FFF )
412 goto loop; 413 goto loop;
413 a_nz_read_addr: 414 a_nz_read_addr:
414 SYNC_TIME(); 415 FLUSH_TIME();
415 a = nz = READ( addr ); 416 a = nz = READ( addr );
416 RELOAD_TIME(); 417 CACHE_TIME();
417 goto loop; 418 goto loop;
418 419
419 } 420 }
420 421
421 // Branch 422 // Branch
472 data += x; 473 data += x;
473 HANDLE_PAGE_CROSSING( data ); 474 HANDLE_PAGE_CROSSING( data );
474 case 0xAC:{// LDY abs 475 case 0xAC:{// LDY abs
475 unsigned addr = data + 0x100 * GET_MSB(); 476 unsigned addr = data + 0x100 * GET_MSB();
476 pc += 2; 477 pc += 2;
477 SYNC_TIME(); 478 FLUSH_TIME();
478 y = nz = READ( addr ); 479 y = nz = READ( addr );
479 RELOAD_TIME(); 480 CACHE_TIME();
480 goto loop; 481 goto loop;
481 } 482 }
482 483
483 case 0xBE: // LDX abs,y 484 case 0xBE: // LDX abs,y
484 data += y; 485 data += y;
485 HANDLE_PAGE_CROSSING( data ); 486 HANDLE_PAGE_CROSSING( data );
486 case 0xAE:{// LDX abs 487 case 0xAE:{// LDX abs
487 unsigned addr = data + 0x100 * GET_MSB(); 488 unsigned addr = data + 0x100 * GET_MSB();
488 pc += 2; 489 pc += 2;
489 SYNC_TIME(); 490 FLUSH_TIME();
490 x = nz = READ( addr ); 491 x = nz = READ( addr );
491 RELOAD_TIME(); 492 CACHE_TIME();
492 goto loop; 493 goto loop;
493 } 494 }
494 495
495 { 496 {
496 fuint8 temp; 497 fuint8 temp;
506 if ( addr <= 0x7FF ) 507 if ( addr <= 0x7FF )
507 { 508 {
508 WRITE_LOW( addr, temp ); 509 WRITE_LOW( addr, temp );
509 goto loop; 510 goto loop;
510 } 511 }
511 SYNC_TIME(); 512 FLUSH_TIME();
512 WRITE( addr, temp ); 513 WRITE( addr, temp );
513 RELOAD_TIME(); 514 CACHE_TIME();
514 goto loop; 515 goto loop;
515 } 516 }
516 517
517 // Compare 518 // Compare
518 519
519 case 0xEC:{// CPX abs 520 case 0xEC:{// CPX abs
520 unsigned addr = GET_ADDR(); 521 unsigned addr = GET_ADDR();
521 pc++; 522 pc++;
522 SYNC_TIME(); 523 FLUSH_TIME();
523 data = READ( addr ); 524 data = READ( addr );
524 RELOAD_TIME(); 525 CACHE_TIME();
525 goto cpx_data; 526 goto cpx_data;
526 } 527 }
527 528
528 case 0xE4: // CPX zp 529 case 0xE4: // CPX zp
529 data = READ_LOW( data ); 530 data = READ_LOW( data );
536 goto loop; 537 goto loop;
537 538
538 case 0xCC:{// CPY abs 539 case 0xCC:{// CPY abs
539 unsigned addr = GET_ADDR(); 540 unsigned addr = GET_ADDR();
540 pc++; 541 pc++;
541 SYNC_TIME(); 542 FLUSH_TIME();
542 data = READ( addr ); 543 data = READ( addr );
543 RELOAD_TIME(); 544 CACHE_TIME();
544 goto cpy_data; 545 goto cpy_data;
545 } 546 }
546 547
547 case 0xC4: // CPY zp 548 case 0xC4: // CPY zp
548 data = READ_LOW( data ); 549 data = READ_LOW( data );
643 data += x; 644 data += x;
644 case 0x4E: // LSR abs 645 case 0x4E: // LSR abs
645 c = 0; 646 c = 0;
646 case 0x6E: // ROR abs 647 case 0x6E: // ROR abs
647 ror_abs: { 648 ror_abs: {
648 ADD_PAGE 649 ADD_PAGE();
649 SYNC_TIME(); 650 FLUSH_TIME();
650 int temp = READ( data ); 651 int temp = READ( data );
651 nz = (c >> 1 & 0x80) | (temp >> 1); 652 nz = (c >> 1 & 0x80) | (temp >> 1);
652 c = temp << 8; 653 c = temp << 8;
653 goto rotate_common; 654 goto rotate_common;
654 } 655 }
661 data += x; 662 data += x;
662 case 0x0E: // ASL abs 663 case 0x0E: // ASL abs
663 c = 0; 664 c = 0;
664 case 0x2E: // ROL abs 665 case 0x2E: // ROL abs
665 rol_abs: 666 rol_abs:
666 ADD_PAGE 667 ADD_PAGE();
667 nz = c >> 8 & 1; 668 nz = c >> 8 & 1;
668 SYNC_TIME(); 669 FLUSH_TIME();
669 nz |= (c = READ( data ) << 1); 670 nz |= (c = READ( data ) << 1);
670 rotate_common: 671 rotate_common:
671 pc++; 672 pc++;
672 WRITE( data, (uint8_t) nz ); 673 WRITE( data, (uint8_t) nz );
673 RELOAD_TIME(); 674 CACHE_TIME();
674 goto loop; 675 goto loop;
675 676
676 case 0x7E: // ROR abs,X 677 case 0x7E: // ROR abs,X
677 data += x; 678 data += x;
678 goto ror_abs; 679 goto ror_abs;
749 case 0xCE: // DEC abs 750 case 0xCE: // DEC abs
750 data = GET_ADDR(); 751 data = GET_ADDR();
751 dec_ptr: 752 dec_ptr:
752 nz = (unsigned) -1; 753 nz = (unsigned) -1;
753 inc_common: 754 inc_common:
754 SYNC_TIME(); 755 FLUSH_TIME();
755 nz += READ( data ); 756 nz += READ( data );
756 pc += 2; 757 pc += 2;
757 WRITE( data, (uint8_t) nz ); 758 WRITE( data, (uint8_t) nz );
758 RELOAD_TIME(); 759 CACHE_TIME();
759 goto loop; 760 goto loop;
760 761
761 // Transfer 762 // Transfer
762 763
763 case 0xAA: // TAX 764 case 0xAA: // TAX
938 } 939 }
939 assert( false ); 940 assert( false );
940 941
941 int result_; 942 int result_;
942 handle_brk: 943 handle_brk:
943 if ( pc >= idle_addr + 1 ) 944 if ( (pc - 1) >= idle_addr )
944 goto idle_done; 945 goto idle_done;
945 pc++; 946 pc++;
946 result_ = 4; 947 result_ = 4;
947 dprintf( "BRK executed\n" ); 948 dprintf( "BRK executed\n" );
948 949
976 //s_time = 0; 977 //s_time = 0;
977 pc--; 978 pc--;
978 goto stop; 979 goto stop;
979 out_of_time: 980 out_of_time:
980 pc--; 981 pc--;
981 SYNC_TIME(); 982 FLUSH_TIME();
982 CPU_DONE( this, TIME, result_ ); 983 CPU_DONE( this, TIME, result_ );
983 RELOAD_TIME(); 984 CACHE_TIME();
984 if ( result_ >= 0 ) 985 if ( result_ >= 0 )
985 goto interrupt; 986 goto interrupt;
986 if ( s_time < 0 ) 987 if ( s_time < 0 )
987 goto loop; 988 goto loop;
988 989