Mercurial > audlegacy-plugins
comparison src/console/Spc_Cpu.cxx @ 316:fb513e10174e trunk
[svn] - merge libconsole-blargg into mainline libconsole:
+ obsoletes plugins-ugly:sapplug
author | nenolod |
---|---|
date | Thu, 30 Nov 2006 19:54:33 -0800 |
parents | 3da1b8942b8b |
children | 986f098da058 |
comparison
equal
deleted
inserted
replaced
315:2294f3a6f136 | 316:fb513e10174e |
---|---|
1 | 1 // Game_Music_Emu 0.5.1. http://www.slack.net/~ant/ |
2 // Game_Music_Emu 0.3.0. http://www.slack.net/~ant/ | |
3 | 2 |
4 #include "Spc_Cpu.h" | 3 #include "Spc_Cpu.h" |
5 | |
6 #include <limits.h> | |
7 | 4 |
8 #include "blargg_endian.h" | 5 #include "blargg_endian.h" |
9 #include "Snes_Spc.h" | 6 #include "Snes_Spc.h" |
10 | 7 |
11 /* Copyright (C) 2004-2006 Shay Green. This module is free software; you | 8 /* Copyright (C) 2004-2006 Shay Green. This module is free software; you |
12 can redistribute it and/or modify it under the terms of the GNU Lesser | 9 can redistribute it and/or modify it under the terms of the GNU Lesser |
13 General Public License as published by the Free Software Foundation; either | 10 General Public License as published by the Free Software Foundation; either |
14 version 2.1 of the License, or (at your option) any later version. This | 11 version 2.1 of the License, or (at your option) any later version. This |
15 module is distributed in the hope that it will be useful, but WITHOUT ANY | 12 module is distributed in the hope that it will be useful, but WITHOUT ANY |
16 WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS | 13 WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS |
17 FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for | 14 FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more |
18 more details. You should have received a copy of the GNU Lesser General | 15 details. You should have received a copy of the GNU Lesser General Public |
19 Public License along with this module; if not, write to the Free Software | 16 License along with this module; if not, write to the Free Software Foundation, |
20 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ | 17 Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ |
21 | 18 |
22 #include BLARGG_SOURCE_BEGIN | 19 #include "blargg_source.h" |
23 | 20 |
24 // Several instructions are commented out (or not even implemented). These aren't | 21 // Several instructions are commented out (or not even implemented). These aren't |
25 // used by the SPC files tested. | 22 // used by the SPC files tested. |
26 | 23 |
27 // Optimize performance for the most common instructions, and size for the rest: | 24 // Optimize performance for the most common instructions, and size for the rest: |
41 | 38 |
42 Spc_Cpu::Spc_Cpu( Snes_Spc* e, uint8_t* ram_in ) : ram( ram_in ), emu( *e ) | 39 Spc_Cpu::Spc_Cpu( Snes_Spc* e, uint8_t* ram_in ) : ram( ram_in ), emu( *e ) |
43 { | 40 { |
44 remain_ = 0; | 41 remain_ = 0; |
45 BOOST_STATIC_ASSERT( sizeof (int) >= 4 ); | 42 BOOST_STATIC_ASSERT( sizeof (int) >= 4 ); |
43 blargg_verify_byte_order(); | |
46 } | 44 } |
47 | 45 |
48 #define READ( addr ) (emu.read( addr )) | 46 #define READ( addr ) (emu.read( addr )) |
49 #define WRITE( addr, value ) (emu.write( addr, value )) | 47 #define WRITE( addr, value ) (emu.write( addr, value )) |
50 | 48 |
63 { | 61 { |
64 WRITE( addr, data ); | 62 WRITE( addr, data ); |
65 } | 63 } |
66 | 64 |
67 // Cycle table derived from text copy of SPC-700 manual (using regular expressions) | 65 // Cycle table derived from text copy of SPC-700 manual (using regular expressions) |
68 static const unsigned char cycle_table [0x100] = { | 66 static unsigned char const cycle_table [0x100] = { |
69 // 0 1 2 3 4 5 6 7 8 9 A B C D E F | 67 // 0 1 2 3 4 5 6 7 8 9 A B C D E F |
70 2,8,4,5,3,4,3,6,2,6,5,4,5,4,6,8, // 0 | 68 2,8,4,5,3,4,3,6,2,6,5,4,5,4,6,8, // 0 |
71 2,8,4,5,4,5,5,6,5,5,6,5,2,2,4,6, // 1 | 69 2,8,4,5,4,5,5,6,5,5,6,5,2,2,4,6, // 1 |
72 2,8,4,5,3,4,3,6,2,6,5,4,5,4,5,4, // 2 | 70 2,8,4,5,3,4,3,6,2,6,5,4,5,4,5,4, // 2 |
73 2,8,4,5,4,5,5,6,5,5,6,5,2,2,3,8, // 3 | 71 2,8,4,5,4,5,5,6,5,5,6,5,2,2,3,8, // 3 |
88 // The C,mem instructions are hardly used, so a non-inline function is used for | 86 // The C,mem instructions are hardly used, so a non-inline function is used for |
89 // the common access code. | 87 // the common access code. |
90 unsigned Spc_Cpu::mem_bit( spc_addr_t pc ) | 88 unsigned Spc_Cpu::mem_bit( spc_addr_t pc ) |
91 { | 89 { |
92 unsigned addr = READ_PROG16( pc ); | 90 unsigned addr = READ_PROG16( pc ); |
93 unsigned t = READ( addr & 0x1fff ) >> (addr >> 13); | 91 unsigned t = READ( addr & 0x1FFF ) >> (addr >> 13); |
94 return (t << 8) & 0x100; | 92 return (t << 8) & 0x100; |
95 } | 93 } |
96 | |
97 #include BLARGG_ENABLE_OPTIMIZER | |
98 | 94 |
99 spc_time_t Spc_Cpu::run( spc_time_t cycle_count ) | 95 spc_time_t Spc_Cpu::run( spc_time_t cycle_count ) |
100 { | 96 { |
101 remain_ = cycle_count; | 97 remain_ = cycle_count; |
102 | 98 |
103 uint8_t* const ram = this->ram; // cache | 99 uint8_t* const ram = this->ram; // cache |
104 | 100 |
105 // Stack pointer is kept one greater than usual SPC stack pointer to allow | 101 // Stack pointer is kept one greater than usual SPC stack pointer to allow |
106 // common pre-decrement and post-increment memory instructions that some | 102 // common pre-decrement and post-increment memory instructions that some |
107 // processors have. Address wrap-around isn't supported. | 103 // processors have. Address wrap-around isn't supported. |
108 #define PUSH( v ) (*--sp = (v)) | 104 #define PUSH( v ) (*--sp = uint8_t (v)) |
109 #define PUSH16( v ) (sp -= 2, SET_LE16( sp, v )) | 105 #define PUSH16( v ) (sp -= 2, SET_LE16( sp, v )) |
110 #define POP() (*sp++) | 106 #define POP() (*sp++) |
111 #define SET_SP( v ) (sp = ram + 0x101 + (v)) | 107 #define SET_SP( v ) (sp = ram + 0x101 + (v)) |
112 #define GET_SP() (sp - 0x101 - ram) | 108 #define GET_SP() (sp - 0x101 - ram) |
113 | 109 |
114 uint8_t* sp; | 110 uint8_t* sp; |
115 SET_SP( r.sp ); | 111 SET_SP( r.sp ); |
116 | 112 |
117 // registers | 113 // registers |
118 unsigned pc = r.pc; | 114 unsigned pc = (unsigned) r.pc; |
119 int a = r.a; | 115 int a = r.a; |
120 int x = r.x; | 116 int x = r.x; |
121 int y = r.y; | 117 int y = r.y; |
122 | 118 |
123 // status flags | 119 // status flags |
147 nz = (in << 4) & 0x800; \ | 143 nz = (in << 4) & 0x800; \ |
148 nz |= ~in & st_z; \ | 144 nz |= ~in & st_z; \ |
149 dp = (in << 3) & 0x100; \ | 145 dp = (in << 3) & 0x100; \ |
150 } while ( 0 ) | 146 } while ( 0 ) |
151 | 147 |
152 uint8_t status; | 148 int status; |
153 int c; // store C as 'c' & 0x100. | 149 int c; // store C as 'c' & 0x100. |
154 int nz; // Z set if (nz & 0xff) == 0, N set if (nz & 0x880) != 0 | 150 int nz; // Z set if (nz & 0xFF) == 0, N set if (nz & 0x880) != 0 |
155 unsigned dp; // direct page base | 151 unsigned dp; // direct page base |
156 { | 152 { |
157 int temp = r.status; | 153 int temp = r.status; |
158 SET_STATUS( temp ); | 154 SET_STATUS( temp ); |
159 } | 155 } |
171 loop: | 167 loop: |
172 | 168 |
173 check( (unsigned) pc < 0x10000 ); | 169 check( (unsigned) pc < 0x10000 ); |
174 check( (unsigned) GET_SP() < 0x100 ); | 170 check( (unsigned) GET_SP() < 0x100 ); |
175 | 171 |
176 assert( (unsigned) a < 0x100 ); | 172 check( (unsigned) a < 0x100 ); |
177 assert( (unsigned) x < 0x100 ); | 173 check( (unsigned) x < 0x100 ); |
178 assert( (unsigned) y < 0x100 ); | 174 check( (unsigned) y < 0x100 ); |
179 | 175 |
180 unsigned opcode = READ_PROG( pc ); | 176 unsigned opcode = READ_PROG( pc ); |
181 pc++; | 177 pc++; |
182 // to do: if pc is at end of memory, this will get wrong byte | 178 // to do: if pc is at end of memory, this will get wrong byte |
183 data = READ_PROG( pc ); | 179 data = READ_PROG( pc ); |
410 ADDR_MODES( 0x68 ) // CMP addr | 406 ADDR_MODES( 0x68 ) // CMP addr |
411 data = READ( data ); | 407 data = READ( data ); |
412 case 0x68: // CMP imm | 408 case 0x68: // CMP imm |
413 nz = a - data; | 409 nz = a - data; |
414 c = ~nz; | 410 c = ~nz; |
415 nz &= 0xff; | 411 nz &= 0xFF; |
416 goto inc_pc_loop; | 412 goto inc_pc_loop; |
417 | 413 |
418 case 0x79: // CMP (X),(Y) | 414 case 0x79: // CMP (X),(Y) |
419 data = READ_DP( x ); | 415 data = READ_DP( x ); |
420 nz = data - READ_DP( y ); | 416 nz = data - READ_DP( y ); |
421 c = ~nz; | 417 c = ~nz; |
422 nz &= 0xff; | 418 nz &= 0xFF; |
423 goto loop; | 419 goto loop; |
424 | 420 |
425 case 0x69: // CMP (dp),(dp) | 421 case 0x69: // CMP (dp),(dp) |
426 data = READ_DP( data ); | 422 data = READ_DP( data ); |
427 case 0x78: // CMP dp,imm | 423 case 0x78: // CMP dp,imm |
428 pc++; | 424 pc++; |
429 nz = READ_DP( READ_PROG( pc ) ) - data; | 425 nz = READ_DP( READ_PROG( pc ) ) - data; |
430 c = ~nz; | 426 c = ~nz; |
431 nz &= 0xff; | 427 nz &= 0xFF; |
432 goto inc_pc_loop; | 428 goto inc_pc_loop; |
433 | 429 |
434 case 0x3E: // CMP X,dp | 430 case 0x3E: // CMP X,dp |
435 data += dp; | 431 data += dp; |
436 goto cmp_x_addr; | 432 goto cmp_x_addr; |
440 cmp_x_addr: | 436 cmp_x_addr: |
441 data = READ( data ); | 437 data = READ( data ); |
442 case 0xC8: // CMP X,imm | 438 case 0xC8: // CMP X,imm |
443 nz = x - data; | 439 nz = x - data; |
444 c = ~nz; | 440 c = ~nz; |
445 nz &= 0xff; | 441 nz &= 0xFF; |
446 goto inc_pc_loop; | 442 goto inc_pc_loop; |
447 | 443 |
448 case 0x7E: // CMP Y,dp | 444 case 0x7E: // CMP Y,dp |
449 data += dp; | 445 data += dp; |
450 goto cmp_y_addr; | 446 goto cmp_y_addr; |
454 cmp_y_addr: | 450 cmp_y_addr: |
455 data = READ( data ); | 451 data = READ( data ); |
456 case 0xAD: // CMP Y,imm | 452 case 0xAD: // CMP Y,imm |
457 nz = y - data; | 453 nz = y - data; |
458 c = ~nz; | 454 c = ~nz; |
459 nz &= 0xff; | 455 nz &= 0xFF; |
460 goto inc_pc_loop; | 456 goto inc_pc_loop; |
461 | 457 |
462 { | 458 { |
463 int addr; | 459 int addr; |
464 case 0xB9: // SBC (x),(y) | 460 case 0xB9: // SBC (x),(y) |
487 case 0x88: // ADC imm | 483 case 0x88: // ADC imm |
488 addr = -1; // A | 484 addr = -1; // A |
489 nz = a; | 485 nz = a; |
490 adc_data: { | 486 adc_data: { |
491 if ( opcode & 0x20 ) | 487 if ( opcode & 0x20 ) |
492 data ^= 0xff; // SBC | 488 data ^= 0xFF; // SBC |
493 int carry = (c >> 8) & 1; | 489 int carry = (c >> 8) & 1; |
494 int ov = (nz ^ 0x80) + carry + (BOOST::int8_t) data; // sign-extend | 490 int ov = (nz ^ 0x80) + carry + (BOOST::int8_t) data; // sign-extend |
495 int hc = (nz & 15) + carry; | 491 int hc = (nz & 15) + carry; |
496 c = nz += data + carry; | 492 c = nz += data + carry; |
497 hc = (nz & 15) - hc; | 493 hc = (nz & 15) - hc; |
611 | 607 |
612 // 8. 16-BIT TRANSMISION COMMANDS | 608 // 8. 16-BIT TRANSMISION COMMANDS |
613 | 609 |
614 case 0xBA: // MOVW YA,dp | 610 case 0xBA: // MOVW YA,dp |
615 a = READ_DP( data ); | 611 a = READ_DP( data ); |
616 nz = (a & 0x7f) | (a >> 1); | 612 nz = (a & 0x7F) | (a >> 1); |
617 y = READ_DP( uint8_t (data + 1) ); | 613 y = READ_DP( uint8_t (data + 1) ); |
618 nz |= y; | 614 nz |= y; |
619 goto inc_pc_loop; | 615 goto inc_pc_loop; |
620 | 616 |
621 case 0xDA: // MOVW dp,YA | 617 case 0xDA: // MOVW dp,YA |
630 data += dp; | 626 data += dp; |
631 | 627 |
632 // low byte | 628 // low byte |
633 int temp = READ( data ); | 629 int temp = READ( data ); |
634 temp += ((opcode >> 4) & 2) - 1; // +1 for INCW, -1 for DECW | 630 temp += ((opcode >> 4) & 2) - 1; // +1 for INCW, -1 for DECW |
635 nz = ((temp >> 1) | temp) & 0x7f; | 631 nz = ((temp >> 1) | temp) & 0x7F; |
636 WRITE( data, (uint8_t) temp ); | 632 WRITE( data, (uint8_t) temp ); |
637 | 633 |
638 // high byte | 634 // high byte |
639 data = uint8_t (data + 1) + dp; | 635 data = uint8_t (data + 1) + dp; |
640 temp >>= 8; | 636 temp >>= 8; |
663 } | 659 } |
664 | 660 |
665 // add low byte (A) | 661 // add low byte (A) |
666 temp += a; | 662 temp += a; |
667 a = (uint8_t) temp; | 663 a = (uint8_t) temp; |
668 nz = (temp | (temp >> 1)) & 0x7f; | 664 nz = (temp | (temp >> 1)) & 0x7F; |
669 | 665 |
670 // add high byte (Y) | 666 // add high byte (Y) |
671 temp >>= 8; | 667 temp >>= 8; |
672 c = y + temp; | 668 c = y + temp; |
673 nz = (nz | c) & 0xff; | 669 nz = (nz | c) & 0xFF; |
674 | 670 |
675 // half-carry (temporary avoids CodeWarrior optimizer bug) | 671 // half-carry (temporary avoids CodeWarrior optimizer bug) |
676 unsigned hc = (c & 15) - (y & 15); | 672 unsigned hc = (c & 15) - (y & 15); |
677 status |= (hc >> 4) & st_h; | 673 status |= (hc >> 4) & st_h; |
678 | 674 |
684 goto inc_pc_loop; | 680 goto inc_pc_loop; |
685 } | 681 } |
686 | 682 |
687 case 0x5A: { // CMPW YA,dp | 683 case 0x5A: { // CMPW YA,dp |
688 int temp = a - READ_DP( data ); | 684 int temp = a - READ_DP( data ); |
689 nz = ((temp >> 1) | temp) & 0x7f; | 685 nz = ((temp >> 1) | temp) & 0x7F; |
690 temp = y + (temp >> 8); | 686 temp = y + (temp >> 8); |
691 temp -= READ_DP( uint8_t (data + 1) ); | 687 temp -= READ_DP( uint8_t (data + 1) ); |
692 nz |= temp; | 688 nz |= temp; |
693 c = ~temp; | 689 c = ~temp; |
694 nz &= 0xff; | 690 nz &= 0xFF; |
695 goto inc_pc_loop; | 691 goto inc_pc_loop; |
696 } | 692 } |
697 | 693 |
698 // 10. MULTIPLICATION & DIVISON COMMANDS | 694 // 10. MULTIPLICATION & DIVISON COMMANDS |
699 | 695 |
700 case 0xCF: { // MUL YA | 696 case 0xCF: { // MUL YA |
701 unsigned temp = y * a; | 697 unsigned temp = y * a; |
702 a = (uint8_t) temp; | 698 a = (uint8_t) temp; |
703 nz = ((temp >> 1) | temp) & 0x7f; | 699 nz = ((temp >> 1) | temp) & 0x7F; |
704 y = temp >> 8; | 700 y = temp >> 8; |
705 nz |= y; | 701 nz |= y; |
706 goto loop; | 702 goto loop; |
707 } | 703 } |
708 | 704 |
824 // 13. SUB-ROUTINE CALL RETURN COMMANDS | 820 // 13. SUB-ROUTINE CALL RETURN COMMANDS |
825 | 821 |
826 case 0x0F: // BRK | 822 case 0x0F: // BRK |
827 check( false ); // untested | 823 check( false ); // untested |
828 PUSH16( pc + 1 ); | 824 PUSH16( pc + 1 ); |
829 pc = READ_PROG16( 0xffde ); // vector address verified | 825 pc = READ_PROG16( 0xFFDE ); // vector address verified |
830 int temp; | 826 int temp; |
831 CALC_STATUS( temp ); | 827 CALC_STATUS( temp ); |
832 PUSH( temp ); | 828 PUSH( temp ); |
833 status = (status | st_b) & ~st_i; | 829 status = (status | st_b) & ~st_i; |
834 goto loop; | 830 goto loop; |
835 | 831 |
836 case 0x4F: // PCALL offset | 832 case 0x4F: // PCALL offset |
837 pc++; | 833 pc++; |
838 PUSH16( pc ); | 834 PUSH16( pc ); |
839 pc = 0xff00 + data; | 835 pc = 0xFF00 + data; |
840 goto loop; | 836 goto loop; |
841 | 837 |
842 case 0x01: // TCALL n | 838 case 0x01: // TCALL n |
843 case 0x11: | 839 case 0x11: |
844 case 0x21: | 840 case 0x21: |
854 case 0xC1: | 850 case 0xC1: |
855 case 0xD1: | 851 case 0xD1: |
856 case 0xE1: | 852 case 0xE1: |
857 case 0xF1: | 853 case 0xF1: |
858 PUSH16( pc ); | 854 PUSH16( pc ); |
859 pc = READ_PROG16( 0xffde - (opcode >> 3) ); | 855 pc = READ_PROG16( 0xFFDE - (opcode >> 3) ); |
860 goto loop; | 856 goto loop; |
861 | 857 |
862 // 14. STACK OPERATION COMMANDS | 858 // 14. STACK OPERATION COMMANDS |
863 | 859 |
864 { | 860 { |
975 goto loop; | 971 goto loop; |
976 | 972 |
977 case 0xEA: { // NOT1 mem.bit | 973 case 0xEA: { // NOT1 mem.bit |
978 data = READ_PROG16( pc ); | 974 data = READ_PROG16( pc ); |
979 pc += 2; | 975 pc += 2; |
980 unsigned temp = READ( data & 0x1fff ); | 976 unsigned temp = READ( data & 0x1FFF ); |
981 temp ^= 1 << (data >> 13); | 977 temp ^= 1 << (data >> 13); |
982 WRITE( data & 0x1fff, temp ); | 978 WRITE( data & 0x1FFF, temp ); |
983 goto loop; | 979 goto loop; |
984 } | 980 } |
985 | 981 |
986 case 0xCA: { // MOV1 mem.bit,C | 982 case 0xCA: { // MOV1 mem.bit,C |
987 data = READ_PROG16( pc ); | 983 data = READ_PROG16( pc ); |
988 pc += 2; | 984 pc += 2; |
989 unsigned temp = READ( data & 0x1fff ); | 985 unsigned temp = READ( data & 0x1FFF ); |
990 unsigned bit = data >> 13; | 986 unsigned bit = data >> 13; |
991 temp = (temp & ~(1 << bit)) | (((c >> 8) & 1) << bit); | 987 temp = (temp & ~(1 << bit)) | (((c >> 8) & 1) << bit); |
992 WRITE( data & 0x1fff, temp ); | 988 WRITE( data & 0x1FFF, temp ); |
993 goto loop; | 989 goto loop; |
994 } | 990 } |
995 | 991 |
996 case 0xAA: // MOV1 C,mem.bit | 992 case 0xAA: // MOV1 C,mem.bit |
997 c = mem_bit( pc ); | 993 c = mem_bit( pc ); |
1050 pc--; | 1046 pc--; |
1051 | 1047 |
1052 { | 1048 { |
1053 int temp; | 1049 int temp; |
1054 CALC_STATUS( temp ); | 1050 CALC_STATUS( temp ); |
1055 r.status = temp; | 1051 r.status = (uint8_t) temp; |
1056 } | 1052 } |
1057 | 1053 |
1058 r.pc = pc; | 1054 r.pc = pc; |
1059 r.sp = GET_SP(); | 1055 r.sp = (uint8_t) GET_SP(); |
1060 r.a = a; | 1056 r.a = (uint8_t) a; |
1061 r.x = x; | 1057 r.x = (uint8_t) x; |
1062 r.y = y; | 1058 r.y = (uint8_t) y; |
1063 | 1059 |
1064 return remain_; | 1060 return remain_; |
1065 } | 1061 } |
1066 |