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