1 /***************************************************************************
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
10 * Copyright (C) 2006-2007 Adam Gashlin (hcs)
11 * Copyright (C) 2004-2007 Shay Green (blargg)
12 * Copyright (C) 2002 Brad Martin
14 * This program is free software; you can redistribute it and/or
15 * modify it under the terms of the GNU General Public License
16 * as published by the Free Software Foundation; either version 2
17 * of the License, or (at your option) any later version.
19 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
20 * KIND, either express or implied.
22 ****************************************************************************/
24 /* The CPU portion (shock!) */
26 #include "spc_codec.h"
27 #include "spc_profiler.h"
32 #define READ( addr ) (SPC_read( this, addr, spc_time_ ))
33 #define WRITE( addr, value ) (SPC_write( this, addr, value, spc_time_ ))
35 #define READ_DP( addr ) READ( (addr) + dp )
36 #define WRITE_DP( addr, value ) WRITE( (addr) + dp, value )
38 #define READ_PROG16( addr ) GET_LE16( RAM + (addr) )
40 #define READ_PC( pc ) (*(pc))
41 #define READ_PC16( pc ) GET_LE16( pc )
43 #define SET_PC( n ) (pc = RAM + (n))
44 #define GET_PC() (pc - RAM)
46 static unsigned char const cycle_table
[0x100] = {
47 2,8,4,5,3,4,3,6,2,6,5,4,5,4,6,8, /* 0 */
48 2,8,4,5,4,5,5,6,5,5,6,5,2,2,4,6, /* 1 */
49 2,8,4,5,3,4,3,6,2,6,5,4,5,4,5,4, /* 2 */
50 2,8,4,5,4,5,5,6,5,5,6,5,2,2,3,8, /* 3 */
51 2,8,4,5,3,4,3,6,2,6,4,4,5,4,6,6, /* 4 */
52 2,8,4,5,4,5,5,6,5,5,4,5,2,2,4,3, /* 5 */
53 2,8,4,5,3,4,3,6,2,6,4,4,5,4,5,5, /* 6 */
54 2,8,4,5,4,5,5,6,5,5,5,5,2,2,3,6, /* 7 */
55 2,8,4,5,3,4,3,6,2,6,5,4,5,2,4,5, /* 8 */
56 2,8,4,5,4,5,5,6,5,5,5,5,2,2,12,5,/* 9 */
57 3,8,4,5,3,4,3,6,2,6,4,4,5,2,4,4, /* A */
58 2,8,4,5,4,5,5,6,5,5,5,5,2,2,3,4, /* B */
59 3,8,4,5,4,5,4,7,2,5,6,4,5,2,4,9, /* C */
60 2,8,4,5,5,6,6,7,4,5,4,5,2,2,6,3, /* D */
61 2,8,4,5,3,4,3,6,2,4,5,3,4,3,4,3, /* E */
62 2,8,4,5,4,5,5,6,3,4,5,4,2,2,4,3 /* F */
65 #define MEM_BIT() CPU_mem_bit( this, pc, spc_time_ )
67 static unsigned CPU_mem_bit( THIS
, uint8_t const* pc
, long const spc_time_
)
70 static unsigned CPU_mem_bit( THIS
, uint8_t const* pc
, long const spc_time_
)
72 unsigned addr
= READ_PC16( pc
);
73 unsigned t
= READ( addr
& 0x1FFF ) >> (addr
>> 13);
74 return (t
<< 8) & 0x100;
87 #define IS_NEG (nz & 0x880)
89 #define CALC_STATUS( out )\
91 out = status & ~(st_n | st_z | st_c);\
92 out |= (c >> 8) & st_c;\
93 out |= (dp >> 3) & st_p;\
94 if ( IS_NEG ) out |= st_n;\
95 if ( !(nz & 0xFF) ) out |= st_z;\
98 #define SET_STATUS( in )\
100 status = in & ~(st_n | st_z | st_c | st_p);\
102 nz = ((in << 4) & 0x800) | (~in & st_z);\
103 dp = (in << 3) & 0x100;\
108 #define PUSH( v ) (*--sp = (uint8_t) (v))
109 #define PUSH16( v ) (sp -= 2, SET_LE16( sp, v ))
110 #define POP() (*sp++)
111 #define SET_SP( v ) (sp = RAM + 0x101 + (v))
112 #define GET_SP() (sp - 0x101 - RAM)
114 long CPU_run( THIS
, long start_time
)
120 register long spc_time_
= start_time
;
123 uint8_t* const ram_
= ram
.ram
;
133 SET_PC( this->r
.pc
);
136 SET_SP( this->r
.sp
);
143 int temp
= this->r
.status
;
151 pc
+= *(int8_t const*) pc
;
156 check( (unsigned) GET_PC() < 0x10000 );
157 check( (unsigned) GET_SP() < 0x100 );
158 check( (unsigned) a
< 0x100 );
159 check( (unsigned) x
< 0x100 );
160 check( (unsigned) y
< 0x100 );
162 unsigned opcode
= *pc
;
163 int cycles
= this->cycle_table
[opcode
];
164 unsigned data
= *++pc
;
165 if ( (spc_time_
+= cycles
) > 0 )
170 /* Common instructions */
172 #define BRANCH( cond )\
175 int offset = (int8_t) data;\
183 case 0xF0: /* BEQ (most common) */
184 BRANCH( !(uint8_t) nz
)
187 BRANCH( (uint8_t) nz
)
189 case 0x3F: /* CALL */
190 PUSH16( GET_PC() + 2 );
191 SET_PC( READ_PC16( pc
) );
199 #define CASE( n ) case n:
201 /* Define common address modes based on opcode for immediate mode. Execution
202 ends with data set to the address of the operand. */
203 #define ADDR_MODES( op )\
204 CASE( op - 0x02 ) /* (X) */\
208 CASE( op + 0x0F ) /* (dp)+Y */\
209 data = READ_PROG16( data + dp ) + y;\
211 CASE( op - 0x01 ) /* (dp+X) */\
212 data = READ_PROG16( ((uint8_t) (data + x)) + dp );\
214 CASE( op + 0x0E ) /* abs+Y */\
217 CASE( op + 0x0D ) /* abs+X */\
219 CASE( op - 0x03 ) /* abs */\
221 data += 0x100 * READ_PC( ++pc );\
223 CASE( op + 0x0C ) /* dp+X */\
224 data = (uint8_t) (data + x);\
225 CASE( op - 0x04 ) /* dp */\
229 /* 1. 8-bit Data Transmission Commands. Group I */
231 ADDR_MODES( 0xE8 ) /* MOV A,addr */
232 /*case 0xE4:*/ /* MOV a,dp (most common) */
234 a
= nz
= READ( data
);
236 case 0xBF: /* MOV A,(X)+ */
238 x
= (uint8_t) (x
+ 1);
242 case 0xE8: /* MOV A,imm */
247 case 0xF9: /* MOV X,dp+Y */
248 data
= (uint8_t) (data
+ y
);
249 case 0xF8: /* MOV X,dp */
252 case 0xE9: /* MOV X,abs */
253 data
= READ_PC16( pc
);
257 case 0xCD: /* MOV X,imm */
262 case 0xFB: /* MOV Y,dp+X */
263 data
= (uint8_t) (data
+ x
);
264 case 0xEB: /* MOV Y,dp */
267 case 0xEC: /* MOV Y,abs */
268 data
= READ_PC16( pc
);
272 case 0x8D: /* MOV Y,imm */
277 /* 2. 8-BIT DATA TRANSMISSION COMMANDS, GROUP 2 */
279 ADDR_MODES( 0xC8 ) /* MOV addr,A */
285 case 0xCC: /* MOV abs,Y */
288 case 0xC9: /* MOV abs,X */
291 WRITE( READ_PC16( pc
), temp
);
296 case 0xD9: /* MOV dp+Y,X */
297 data
= (uint8_t) (data
+ y
);
298 case 0xD8: /* MOV dp,X */
299 WRITE( data
+ dp
, x
);
302 case 0xDB: /* MOV dp+X,Y */
303 data
= (uint8_t) (data
+ x
);
304 case 0xCB: /* MOV dp,Y */
305 WRITE( data
+ dp
, y
);
308 case 0xFA: /* MOV dp,dp */
309 data
= READ( data
+ dp
);
310 case 0x8F: /* MOV dp,#imm */
311 WRITE_DP( READ_PC( ++pc
), data
);
314 /* 3. 8-BIT DATA TRANSMISSIN COMMANDS, GROUP 3. */
316 case 0x7D: /* MOV A,X */
321 case 0xDD: /* MOV A,Y */
326 case 0x5D: /* MOV X,A */
331 case 0xFD: /* MOV Y,A */
336 case 0x9D: /* MOV X,SP */
340 case 0xBD: /* MOV SP,X */
344 /*case 0xC6:*/ /* MOV (X),A (handled by MOV addr,A in group 2) */
346 case 0xAF: /* MOV (X)+,A */
351 /* 5. 8-BIT LOGIC OPERATION COMMANDS */
353 #define LOGICAL_OP( op, func )\
354 ADDR_MODES( op ) /* addr */\
355 data = READ( data );\
357 nz = a func##= data;\
360 case op + 0x11: /* X,Y */\
361 data = READ_DP( y );\
365 case op + 0x01: /* dp,dp */\
366 data = READ_DP( data );\
367 case op + 0x10: /*dp,imm*/\
368 addr = READ_PC( ++pc ) + dp;\
370 nz = data func READ( addr );\
375 LOGICAL_OP( 0x28, & ); /* AND */
377 LOGICAL_OP( 0x08, | ); /* OR */
379 LOGICAL_OP( 0x48, ^ ); /* EOR */
381 /* 4. 8-BIT ARITHMETIC OPERATION COMMANDS */
383 ADDR_MODES( 0x68 ) /* CMP addr */
385 case 0x68: /* CMP imm */
391 case 0x79: /* CMP (X),(Y) */
393 nz
= data
- READ_DP( y
);
398 case 0x69: /* CMP (dp),(dp) */
399 data
= READ_DP( data
);
400 case 0x78: /* CMP dp,imm */
401 nz
= READ_DP( READ_PC( ++pc
) ) - data
;
406 case 0x3E: /* CMP X,dp */
409 case 0x1E: /* CMP X,abs */
410 data
= READ_PC16( pc
);
414 case 0xC8: /* CMP X,imm */
420 case 0x7E: /* CMP Y,dp */
423 case 0x5E: /* CMP Y,abs */
424 data
= READ_PC16( pc
);
428 case 0xAD: /* CMP Y,imm */
436 case 0xB9: /* SBC (x),(y) */
437 case 0x99: /* ADC (x),(y) */
438 pc
--; /* compensate for inc later */
442 case 0xA9: /* SBC dp,dp */
443 case 0x89: /* ADC dp,dp */
444 data
= READ_DP( data
);
445 case 0xB8: /* SBC dp,imm */
446 case 0x98: /* ADC dp,imm */
447 addr
= READ_PC( ++pc
) + dp
;
452 /* catch ADC and SBC together, then decode later based on operand */
454 #define CASE( n ) case n: case (n) + 0x20:
455 ADDR_MODES( 0x88 ) /* ADC/SBC addr */
457 case 0xA8: /* SBC imm */
458 case 0x88: /* ADC imm */
463 data
^= 0xFF; /* SBC */
464 int carry
= (c
>> 8) & 1;
465 int ov
= (nz
^ 0x80) + carry
+ (int8_t) data
; /* sign-extend */
466 int hc
= (nz
& 15) + carry
;
467 c
= nz
+= data
+ carry
;
469 status
= (status
& ~(st_v
| st_h
)) | ((ov
>> 2) & st_v
) |
475 WRITE( addr
, (uint8_t) nz
);
481 /* 6. ADDITION & SUBTRACTION COMMANDS */
483 #define INC_DEC_REG( reg, n )\
488 case 0xBC: INC_DEC_REG( a
, 1 ) /* INC A */
489 case 0x3D: INC_DEC_REG( x
, 1 ) /* INC X */
490 case 0xFC: INC_DEC_REG( y
, 1 ) /* INC Y */
492 case 0x9C: INC_DEC_REG( a
, -1 ) /* DEC A */
493 case 0x1D: INC_DEC_REG( x
, -1 ) /* DEC X */
494 case 0xDC: INC_DEC_REG( y
, -1 ) /* DEC Y */
496 case 0x9B: /* DEC dp+X */
497 case 0xBB: /* INC dp+X */
498 data
= (uint8_t) (data
+ x
);
499 case 0x8B: /* DEC dp */
500 case 0xAB: /* INC dp */
503 case 0x8C: /* DEC abs */
504 case 0xAC: /* INC abs */
505 data
= READ_PC16( pc
);
508 nz
= ((opcode
>> 4) & 2) - 1;
510 WRITE( data
, (uint8_t) nz
);
513 /* 7. SHIFT, ROTATION COMMANDS */
515 case 0x5C: /* LSR A */
517 case 0x7C:{/* ROR A */
518 nz
= ((c
>> 1) & 0x80) | (a
>> 1);
524 case 0x1C: /* ASL A */
526 case 0x3C:{/* ROL A */
527 int temp
= (c
>> 8) & 1;
534 case 0x0B: /* ASL dp */
538 case 0x1B: /* ASL dp+X */
540 case 0x3B: /* ROL dp+X */
541 data
= (uint8_t) (data
+ x
);
542 case 0x2B: /* ROL dp */
545 case 0x0C: /* ASL abs */
547 case 0x2C: /* ROL abs */
548 data
= READ_PC16( pc
);
552 nz
|= (c
= READ( data
) << 1);
553 WRITE( data
, (uint8_t) nz
);
556 case 0x4B: /* LSR dp */
560 case 0x5B: /* LSR dp+X */
562 case 0x7B: /* ROR dp+X */
563 data
= (uint8_t) (data
+ x
);
564 case 0x6B: /* ROR dp */
567 case 0x4C: /* LSR abs */
569 case 0x6C: /* ROR abs */
570 data
= READ_PC16( pc
);
573 int temp
= READ( data
);
574 nz
= ((c
>> 1) & 0x80) | (temp
>> 1);
581 nz
= a
= (a
>> 4) | (uint8_t) (a
<< 4);
584 /* 8. 16-BIT TRANSMISION COMMANDS */
586 case 0xBA: /* MOVW YA,dp */
588 nz
= (a
& 0x7F) | (a
>> 1);
589 y
= READ_DP( (uint8_t) (data
+ 1) );
593 case 0xDA: /* MOVW dp,YA */
595 WRITE_DP( (uint8_t) (data
+ 1), y
);
598 /* 9. 16-BIT OPERATION COMMANDS */
600 case 0x3A: /* INCW dp */
601 case 0x1A:{/* DECW dp */
605 int temp
= READ( data
);
606 temp
+= ((opcode
>> 4) & 2) - 1; /* +1 for INCW, -1 for DECW */
607 nz
= ((temp
>> 1) | temp
) & 0x7F;
608 WRITE( data
, (uint8_t) temp
);
611 data
= ((uint8_t) (data
+ 1)) + dp
;
613 temp
= (uint8_t) (temp
+ READ( data
));
620 case 0x9A: /* SUBW YA,dp */
621 case 0x7A: /* ADDW YA,dp */
623 /* read 16-bit addend */
624 int temp
= READ_DP( data
);
625 int sign
= READ_DP( (uint8_t) (data
+ 1) );
626 temp
+= 0x100 * sign
;
627 status
&= ~(st_v
| st_h
);
629 /* to do: fix half-carry for SUBW (it's probably wrong) */
631 /* for SUBW, negate and truncate to 16 bits */
632 if ( opcode
& 0x80 ) {
633 temp
= (temp
^ 0xFFFF) + 1;
637 /* add low byte (A) */
640 nz
= (temp
| (temp
>> 1)) & 0x7F;
642 /* add high byte (Y) */
645 nz
= (nz
| c
) & 0xFF;
647 /* half-carry (temporary avoids CodeWarrior optimizer bug) */
648 unsigned hc
= (c
& 15) - (y
& 15);
649 status
|= (hc
>> 4) & st_h
;
651 /* overflow if sign of YA changed when previous sign
652 and addend sign were same */
653 status
|= (((c
^ y
) & ~(y
^ sign
)) >> 1) & st_v
;
660 case 0x5A: { /* CMPW YA,dp */
661 int temp
= a
- READ_DP( data
);
662 nz
= ((temp
>> 1) | temp
) & 0x7F;
663 temp
= y
+ (temp
>> 8);
664 temp
-= READ_DP( (uint8_t) (data
+ 1) );
671 /* 10. MULTIPLICATION & DIVISON COMMANDS */
673 case 0xCF: { /* MUL YA */
674 unsigned temp
= y
* a
;
676 nz
= ((temp
>> 1) | temp
) & 0x7F;
682 case 0x9E: /* DIV YA,X */
684 /* behavior based on SPC CPU tests */
686 status
&= ~(st_h
| st_v
);
688 if ( (y
& 15) >= (x
& 15) )
694 unsigned ya
= y
* 0x100 + a
;
702 a
= 255 - (ya
- x
* 0x200) / (256 - x
);
703 y
= x
+ (ya
- x
* 0x200) % (256 - x
);
712 /* 11. DECIMAL COMPENSATION COMMANDS */
715 /* case 0xDF: */ /* DAA */
716 /* case 0xBE: */ /* DAS */
718 /* 12. BRANCHING COMMANDS */
720 case 0x2F: /* BRA rel */
734 BRANCH( !(c
& 0x100) )
737 BRANCH( status
& st_v
)
740 BRANCH( !(status
& st_v
) )
742 case 0x03: /* BBS dp.bit,rel */
751 if ( (READ_DP( data
) >> (opcode
>> 5)) & 1 )
752 goto cbranch_taken_loop
;
755 case 0x13: /* BBC dp.bit,rel */
764 if ( !((READ_DP( data
) >> (opcode
>> 5)) & 1) )
765 goto cbranch_taken_loop
;
768 case 0xDE: /* CBNE dp+X,rel */
769 data
= (uint8_t) (data
+ x
);
771 case 0x2E: /* CBNE dp,rel */
773 if ( READ_DP( data
) != a
)
774 goto cbranch_taken_loop
;
777 case 0xFE: /* DBNZ Y,rel */
778 y
= (uint8_t) (y
- 1);
781 case 0x6E: { /* DBNZ dp,rel */
783 unsigned temp
= READ_DP( data
) - 1;
784 WRITE_DP( (uint8_t) data
, (uint8_t) temp
);
786 goto cbranch_taken_loop
;
790 case 0x1F: /* JMP (abs+X) */
791 SET_PC( READ_PC16( pc
) + x
);
793 case 0x5F: /* JMP abs */
794 SET_PC( READ_PC16( pc
) );
797 /* 13. SUB-ROUTINE CALL RETURN COMMANDS */
800 check( 0 ); /* untested */
801 PUSH16( GET_PC() + 1 );
802 SET_PC( READ_PROG16( 0xFFDE ) ); /* vector address verified */
806 status
= (status
| st_b
) & ~st_i
;
810 case 0x4F: /* PCALL offset */
811 PUSH16( GET_PC() + 1 );
812 SET_PC( 0xFF00 + data
);
815 case 0x01: /* TCALL n */
832 SET_PC( READ_PROG16( 0xFFDE - (opcode
>> 3) ) );
835 /* 14. STACK OPERATION COMMANDS */
839 case 0x7F: /* RET1 */
844 case 0x8E: /* POP PSW */
851 case 0x0D: { /* PUSH PSW */
858 case 0x2D: /* PUSH A */
862 case 0x4D: /* PUSH X */
866 case 0x6D: /* PUSH Y */
870 case 0xAE: /* POP A */
874 case 0xCE: /* POP X */
878 case 0xEE: /* POP Y */
882 /* 15. BIT OPERATION COMMANDS */
884 case 0x02: /* SET1 */
892 case 0x12: /* CLR1 */
901 int bit
= 1 << (opcode
>> 5);
905 WRITE( data
, (READ( data
) & mask
) | bit
);
909 case 0x0E: /* TSET1 abs */
910 case 0x4E:{/* TCLR1 abs */
911 data
= READ_PC16( pc
);
913 unsigned temp
= READ( data
);
916 if ( !(opcode
& 0x40) )
922 case 0x4A: /* AND1 C,mem.bit */
927 case 0x6A: /* AND1 C,/mem.bit */
928 check( 0 ); /* untested */
933 case 0x0A: /* OR1 C,mem.bit */
934 check( 0 ); /* untested */
939 case 0x2A: /* OR1 C,/mem.bit */
940 check( 0 ); /* untested */
945 case 0x8A: /* EOR1 C,mem.bit */
950 case 0xEA: { /* NOT1 mem.bit */
951 data
= READ_PC16( pc
);
953 unsigned temp
= READ( data
& 0x1FFF );
954 temp
^= 1 << (data
>> 13);
955 WRITE( data
& 0x1FFF, temp
);
959 case 0xCA: { /* MOV1 mem.bit,C */
960 data
= READ_PC16( pc
);
962 unsigned temp
= READ( data
& 0x1FFF );
963 unsigned bit
= data
>> 13;
964 temp
= (temp
& ~(1 << bit
)) | (((c
>> 8) & 1) << bit
);
965 WRITE( data
& 0x1FFF, temp
);
969 case 0xAA: /* MOV1 C,mem.bit */
974 /* 16. PROGRAM STATUS FLAG OPERATION COMMANDS */
976 case 0x60: /* CLRC */
980 case 0x80: /* SETC */
984 case 0xED: /* NOTC */
988 case 0xE0: /* CLRV */
989 status
&= ~(st_v
| st_h
);
992 case 0x20: /* CLRP */
996 case 0x40: /* SETP */
1001 check( 0 ); /* untested */
1006 check( 0 ); /* untested */
1010 /* 17. OTHER COMMANDS */
1012 case 0x00: /* NOP */
1015 /*case 0xEF:*/ /* SLEEP */
1016 /*case 0xFF:*/ /* STOP */
1018 c
|= 1; /* force switch table to have 256 entries,
1019 hopefully helping optimizer */
1022 /* unhandled instructions fall out of switch so emulator can catch them */
1025 /* undo partial execution of opcode */
1026 spc_time_
-= this->cycle_table
[*--pc
];
1029 CALC_STATUS( temp
);
1030 this->r
.status
= (uint8_t) temp
;
1033 this->r
.pc
= GET_PC();
1034 this->r
.sp
= (uint8_t) GET_SP();
1035 this->r
.a
= (uint8_t) a
;
1036 this->r
.x
= (uint8_t) x
;
1037 this->r
.y
= (uint8_t) y
;
1045 void CPU_Init( THIS
)
1047 ci
->memcpy( this->cycle_table
, cycle_table
, sizeof cycle_table
);