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