FS#12113: Optimize IRAM configuration for SPC. Performance increases by 5-6% on PP502...
[kugel-rb.git] / apps / codecs / libspc / spc_cpu.c
blob23dcc257dea8b11d4f379d8487f8393f25ad35be
1 /***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
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!) */
25 #include "codeclib.h"
26 #include "spc_codec.h"
27 #include "spc_profiler.h"
29 #undef check
30 #define check assert
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_ )
68 ICODE_ATTR_SPC;
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;
77 /* status flags */
78 enum { st_n = 0x80 };
79 enum { st_v = 0x40 };
80 enum { st_p = 0x20 };
81 enum { st_b = 0x10 };
82 enum { st_h = 0x08 };
83 enum { st_i = 0x04 };
84 enum { st_z = 0x02 };
85 enum { st_c = 0x01 };
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);\
101 c = in << 8;\
102 nz = ((in << 4) & 0x800) | (~in & st_z);\
103 dp = (in << 3) & 0x100;\
107 /* stack */
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 )
116 #if 0
117 ENTER_TIMER(cpu);
118 #endif
120 register long spc_time_ = start_time;
122 #ifdef CPU_ARM
123 uint8_t* const ram_ = ram.ram;
124 #undef RAM
125 #define RAM ram_
126 #endif
128 int a = this->r.a;
129 int x = this->r.x;
130 int y = this->r.y;
132 uint8_t const* pc;
133 SET_PC( this->r.pc );
135 uint8_t* sp;
136 SET_SP( this->r.sp );
138 int status;
139 int c;
140 int nz;
141 unsigned dp;
143 int temp = this->r.status;
144 SET_STATUS( temp );
147 goto loop;
149 /* main loop */
150 cbranch_taken_loop:
151 pc += *(int8_t const*) pc;
152 spc_time_ += 2;
153 inc_pc_loop:
154 pc++;
155 loop:
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 )
166 goto out_of_time;
167 switch ( opcode )
170 /* Common instructions */
172 #define BRANCH( cond )\
174 pc++;\
175 int offset = (int8_t) data;\
176 if ( cond ) {\
177 pc += offset;\
178 spc_time_ += 2;\
180 goto loop;\
183 case 0xF0: /* BEQ (most common) */
184 BRANCH( !(uint8_t) nz )
186 case 0xD0: /* BNE */
187 BRANCH( (uint8_t) nz )
189 case 0x3F: /* CALL */
190 PUSH16( GET_PC() + 2 );
191 SET_PC( READ_PC16( pc ) );
192 goto loop;
194 case 0x6F: /* RET */
195 SET_PC( POP() );
196 pc += POP() * 0x100;
197 goto loop;
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) */\
205 data = x + dp;\
206 pc--;\
207 goto end_##op;\
208 CASE( op + 0x0F ) /* (dp)+Y */\
209 data = READ_PROG16( data + dp ) + y;\
210 goto end_##op;\
211 CASE( op - 0x01 ) /* (dp+X) */\
212 data = READ_PROG16( ((uint8_t) (data + x)) + dp );\
213 goto end_##op;\
214 CASE( op + 0x0E ) /* abs+Y */\
215 data += y;\
216 goto abs_##op;\
217 CASE( op + 0x0D ) /* abs+X */\
218 data += x;\
219 CASE( op - 0x03 ) /* abs */\
220 abs_##op:\
221 data += 0x100 * READ_PC( ++pc );\
222 goto end_##op;\
223 CASE( op + 0x0C ) /* dp+X */\
224 data = (uint8_t) (data + x);\
225 CASE( op - 0x04 ) /* dp */\
226 data += dp;\
227 end_##op:
229 /* 1. 8-bit Data Transmission Commands. Group I */
231 ADDR_MODES( 0xE8 ) /* MOV A,addr */
232 /*case 0xE4:*/ /* MOV a,dp (most common) */
233 mov_a_addr:
234 a = nz = READ( data );
235 goto inc_pc_loop;
236 case 0xBF: /* MOV A,(X)+ */
237 data = x + dp;
238 x = (uint8_t) (x + 1);
239 pc--;
240 goto mov_a_addr;
242 case 0xE8: /* MOV A,imm */
243 a = data;
244 nz = data;
245 goto inc_pc_loop;
247 case 0xF9: /* MOV X,dp+Y */
248 data = (uint8_t) (data + y);
249 case 0xF8: /* MOV X,dp */
250 data += dp;
251 goto mov_x_addr;
252 case 0xE9: /* MOV X,abs */
253 data = READ_PC16( pc );
254 pc++;
255 mov_x_addr:
256 data = READ( data );
257 case 0xCD: /* MOV X,imm */
258 x = data;
259 nz = data;
260 goto inc_pc_loop;
262 case 0xFB: /* MOV Y,dp+X */
263 data = (uint8_t) (data + x);
264 case 0xEB: /* MOV Y,dp */
265 data += dp;
266 goto mov_y_addr;
267 case 0xEC: /* MOV Y,abs */
268 data = READ_PC16( pc );
269 pc++;
270 mov_y_addr:
271 data = READ( data );
272 case 0x8D: /* MOV Y,imm */
273 y = data;
274 nz = data;
275 goto inc_pc_loop;
277 /* 2. 8-BIT DATA TRANSMISSION COMMANDS, GROUP 2 */
279 ADDR_MODES( 0xC8 ) /* MOV addr,A */
280 WRITE( data, a );
281 goto inc_pc_loop;
284 int temp;
285 case 0xCC: /* MOV abs,Y */
286 temp = y;
287 goto mov_abs_temp;
288 case 0xC9: /* MOV abs,X */
289 temp = x;
290 mov_abs_temp:
291 WRITE( READ_PC16( pc ), temp );
292 pc += 2;
293 goto loop;
296 case 0xD9: /* MOV dp+Y,X */
297 data = (uint8_t) (data + y);
298 case 0xD8: /* MOV dp,X */
299 WRITE( data + dp, x );
300 goto inc_pc_loop;
302 case 0xDB: /* MOV dp+X,Y */
303 data = (uint8_t) (data + x);
304 case 0xCB: /* MOV dp,Y */
305 WRITE( data + dp, y );
306 goto inc_pc_loop;
308 case 0xFA: /* MOV dp,dp */
309 data = READ( data + dp );
310 case 0x8F: /* MOV dp,#imm */
311 WRITE_DP( READ_PC( ++pc ), data );
312 goto inc_pc_loop;
314 /* 3. 8-BIT DATA TRANSMISSIN COMMANDS, GROUP 3. */
316 case 0x7D: /* MOV A,X */
317 a = x;
318 nz = x;
319 goto loop;
321 case 0xDD: /* MOV A,Y */
322 a = y;
323 nz = y;
324 goto loop;
326 case 0x5D: /* MOV X,A */
327 x = a;
328 nz = a;
329 goto loop;
331 case 0xFD: /* MOV Y,A */
332 y = a;
333 nz = a;
334 goto loop;
336 case 0x9D: /* MOV X,SP */
337 x = nz = GET_SP();
338 goto loop;
340 case 0xBD: /* MOV SP,X */
341 SET_SP( x );
342 goto loop;
344 /*case 0xC6:*/ /* MOV (X),A (handled by MOV addr,A in group 2) */
346 case 0xAF: /* MOV (X)+,A */
347 WRITE_DP( x, a );
348 x++;
349 goto loop;
351 /* 5. 8-BIT LOGIC OPERATION COMMANDS */
353 #define LOGICAL_OP( op, func )\
354 ADDR_MODES( op ) /* addr */\
355 data = READ( data );\
356 case op: /* imm */\
357 nz = a func##= data;\
358 goto inc_pc_loop;\
359 { unsigned addr;\
360 case op + 0x11: /* X,Y */\
361 data = READ_DP( y );\
362 addr = x + dp;\
363 pc--;\
364 goto addr_##op;\
365 case op + 0x01: /* dp,dp */\
366 data = READ_DP( data );\
367 case op + 0x10: /*dp,imm*/\
368 addr = READ_PC( ++pc ) + dp;\
369 addr_##op:\
370 nz = data func READ( addr );\
371 WRITE( addr, nz );\
372 goto inc_pc_loop;\
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 */
384 data = READ( data );
385 case 0x68: /* CMP imm */
386 nz = a - data;
387 c = ~nz;
388 nz &= 0xFF;
389 goto inc_pc_loop;
391 case 0x79: /* CMP (X),(Y) */
392 data = READ_DP( x );
393 nz = data - READ_DP( y );
394 c = ~nz;
395 nz &= 0xFF;
396 goto loop;
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;
402 c = ~nz;
403 nz &= 0xFF;
404 goto inc_pc_loop;
406 case 0x3E: /* CMP X,dp */
407 data += dp;
408 goto cmp_x_addr;
409 case 0x1E: /* CMP X,abs */
410 data = READ_PC16( pc );
411 pc++;
412 cmp_x_addr:
413 data = READ( data );
414 case 0xC8: /* CMP X,imm */
415 nz = x - data;
416 c = ~nz;
417 nz &= 0xFF;
418 goto inc_pc_loop;
420 case 0x7E: /* CMP Y,dp */
421 data += dp;
422 goto cmp_y_addr;
423 case 0x5E: /* CMP Y,abs */
424 data = READ_PC16( pc );
425 pc++;
426 cmp_y_addr:
427 data = READ( data );
428 case 0xAD: /* CMP Y,imm */
429 nz = y - data;
430 c = ~nz;
431 nz &= 0xFF;
432 goto inc_pc_loop;
435 int addr;
436 case 0xB9: /* SBC (x),(y) */
437 case 0x99: /* ADC (x),(y) */
438 pc--; /* compensate for inc later */
439 data = READ_DP( x );
440 addr = y + dp;
441 goto adc_addr;
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;
448 adc_addr:
449 nz = READ( addr );
450 goto adc_data;
452 /* catch ADC and SBC together, then decode later based on operand */
453 #undef CASE
454 #define CASE( n ) case n: case (n) + 0x20:
455 ADDR_MODES( 0x88 ) /* ADC/SBC addr */
456 data = READ( data );
457 case 0xA8: /* SBC imm */
458 case 0x88: /* ADC imm */
459 addr = -1; /* A */
460 nz = a;
461 adc_data: {
462 if ( opcode & 0x20 )
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;
468 hc = (nz & 15) - hc;
469 status = (status & ~(st_v | st_h)) | ((ov >> 2) & st_v) |
470 ((hc >> 1) & st_h);
471 if ( addr < 0 ) {
472 a = (uint8_t) nz;
473 goto inc_pc_loop;
475 WRITE( addr, (uint8_t) nz );
476 goto inc_pc_loop;
481 /* 6. ADDITION & SUBTRACTION COMMANDS */
483 #define INC_DEC_REG( reg, n )\
484 nz = reg + n;\
485 reg = (uint8_t) nz;\
486 goto loop;
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 */
501 data += dp;
502 goto inc_abs;
503 case 0x8C: /* DEC abs */
504 case 0xAC: /* INC abs */
505 data = READ_PC16( pc );
506 pc++;
507 inc_abs:
508 nz = ((opcode >> 4) & 2) - 1;
509 nz += READ( data );
510 WRITE( data, (uint8_t) nz );
511 goto inc_pc_loop;
513 /* 7. SHIFT, ROTATION COMMANDS */
515 case 0x5C: /* LSR A */
516 c = 0;
517 case 0x7C:{/* ROR A */
518 nz = ((c >> 1) & 0x80) | (a >> 1);
519 c = a << 8;
520 a = nz;
521 goto loop;
524 case 0x1C: /* ASL A */
525 c = 0;
526 case 0x3C:{/* ROL A */
527 int temp = (c >> 8) & 1;
528 c = a << 1;
529 nz = c | temp;
530 a = (uint8_t) nz;
531 goto loop;
534 case 0x0B: /* ASL dp */
535 c = 0;
536 data += dp;
537 goto rol_mem;
538 case 0x1B: /* ASL dp+X */
539 c = 0;
540 case 0x3B: /* ROL dp+X */
541 data = (uint8_t) (data + x);
542 case 0x2B: /* ROL dp */
543 data += dp;
544 goto rol_mem;
545 case 0x0C: /* ASL abs */
546 c = 0;
547 case 0x2C: /* ROL abs */
548 data = READ_PC16( pc );
549 pc++;
550 rol_mem:
551 nz = (c >> 8) & 1;
552 nz |= (c = READ( data ) << 1);
553 WRITE( data, (uint8_t) nz );
554 goto inc_pc_loop;
556 case 0x4B: /* LSR dp */
557 c = 0;
558 data += dp;
559 goto ror_mem;
560 case 0x5B: /* LSR dp+X */
561 c = 0;
562 case 0x7B: /* ROR dp+X */
563 data = (uint8_t) (data + x);
564 case 0x6B: /* ROR dp */
565 data += dp;
566 goto ror_mem;
567 case 0x4C: /* LSR abs */
568 c = 0;
569 case 0x6C: /* ROR abs */
570 data = READ_PC16( pc );
571 pc++;
572 ror_mem: {
573 int temp = READ( data );
574 nz = ((c >> 1) & 0x80) | (temp >> 1);
575 c = temp << 8;
576 WRITE( data, nz );
577 goto inc_pc_loop;
580 case 0x9F: /* XCN */
581 nz = a = (a >> 4) | (uint8_t) (a << 4);
582 goto loop;
584 /* 8. 16-BIT TRANSMISION COMMANDS */
586 case 0xBA: /* MOVW YA,dp */
587 a = READ_DP( data );
588 nz = (a & 0x7F) | (a >> 1);
589 y = READ_DP( (uint8_t) (data + 1) );
590 nz |= y;
591 goto inc_pc_loop;
593 case 0xDA: /* MOVW dp,YA */
594 WRITE_DP( data, a );
595 WRITE_DP( (uint8_t) (data + 1), y );
596 goto inc_pc_loop;
598 /* 9. 16-BIT OPERATION COMMANDS */
600 case 0x3A: /* INCW dp */
601 case 0x1A:{/* DECW dp */
602 data += dp;
604 /* low byte */
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 );
610 /* high byte */
611 data = ((uint8_t) (data + 1)) + dp;
612 temp >>= 8;
613 temp = (uint8_t) (temp + READ( data ));
614 nz |= temp;
615 WRITE( data, temp );
617 goto inc_pc_loop;
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;
634 sign = temp >> 8;
637 /* add low byte (A) */
638 temp += a;
639 a = (uint8_t) temp;
640 nz = (temp | (temp >> 1)) & 0x7F;
642 /* add high byte (Y) */
643 temp >>= 8;
644 c = y + temp;
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;
655 y = (uint8_t) c;
657 goto inc_pc_loop;
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) );
665 nz |= temp;
666 c = ~temp;
667 nz &= 0xFF;
668 goto inc_pc_loop;
671 /* 10. MULTIPLICATION & DIVISON COMMANDS */
673 case 0xCF: { /* MUL YA */
674 unsigned temp = y * a;
675 a = (uint8_t) temp;
676 nz = ((temp >> 1) | temp) & 0x7F;
677 y = temp >> 8;
678 nz |= y;
679 goto loop;
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) )
689 status |= st_h;
691 if ( y >= x )
692 status |= st_v;
694 unsigned ya = y * 0x100 + a;
695 if ( y < x * 2 )
697 a = ya / x;
698 y = ya - a * x;
700 else
702 a = 255 - (ya - x * 0x200) / (256 - x);
703 y = x + (ya - x * 0x200) % (256 - x);
706 nz = (uint8_t) a;
707 a = (uint8_t) a;
709 goto loop;
712 /* 11. DECIMAL COMPENSATION COMMANDS */
714 /* seem unused */
715 /* case 0xDF: */ /* DAA */
716 /* case 0xBE: */ /* DAS */
718 /* 12. BRANCHING COMMANDS */
720 case 0x2F: /* BRA rel */
721 pc += (int8_t) data;
722 goto inc_pc_loop;
724 case 0x30: /* BMI */
725 BRANCH( IS_NEG )
727 case 0x10: /* BPL */
728 BRANCH( !IS_NEG )
730 case 0xB0: /* BCS */
731 BRANCH( c & 0x100 )
733 case 0x90: /* BCC */
734 BRANCH( !(c & 0x100) )
736 case 0x70: /* BVS */
737 BRANCH( status & st_v )
739 case 0x50: /* BVC */
740 BRANCH( !(status & st_v) )
742 case 0x03: /* BBS dp.bit,rel */
743 case 0x23:
744 case 0x43:
745 case 0x63:
746 case 0x83:
747 case 0xA3:
748 case 0xC3:
749 case 0xE3:
750 pc++;
751 if ( (READ_DP( data ) >> (opcode >> 5)) & 1 )
752 goto cbranch_taken_loop;
753 goto inc_pc_loop;
755 case 0x13: /* BBC dp.bit,rel */
756 case 0x33:
757 case 0x53:
758 case 0x73:
759 case 0x93:
760 case 0xB3:
761 case 0xD3:
762 case 0xF3:
763 pc++;
764 if ( !((READ_DP( data ) >> (opcode >> 5)) & 1) )
765 goto cbranch_taken_loop;
766 goto inc_pc_loop;
768 case 0xDE: /* CBNE dp+X,rel */
769 data = (uint8_t) (data + x);
770 /* fall through */
771 case 0x2E: /* CBNE dp,rel */
772 pc++;
773 if ( READ_DP( data ) != a )
774 goto cbranch_taken_loop;
775 goto inc_pc_loop;
777 case 0xFE: /* DBNZ Y,rel */
778 y = (uint8_t) (y - 1);
779 BRANCH( y )
781 case 0x6E: { /* DBNZ dp,rel */
782 pc++;
783 unsigned temp = READ_DP( data ) - 1;
784 WRITE_DP( (uint8_t) data, (uint8_t) temp );
785 if ( temp )
786 goto cbranch_taken_loop;
787 goto inc_pc_loop;
790 case 0x1F: /* JMP (abs+X) */
791 SET_PC( READ_PC16( pc ) + x );
792 /* fall through */
793 case 0x5F: /* JMP abs */
794 SET_PC( READ_PC16( pc ) );
795 goto loop;
797 /* 13. SUB-ROUTINE CALL RETURN COMMANDS */
799 case 0x0F:{/* BRK */
800 check( 0 ); /* untested */
801 PUSH16( GET_PC() + 1 );
802 SET_PC( READ_PROG16( 0xFFDE ) ); /* vector address verified */
803 int temp;
804 CALC_STATUS( temp );
805 PUSH( temp );
806 status = (status | st_b) & ~st_i;
807 goto loop;
810 case 0x4F: /* PCALL offset */
811 PUSH16( GET_PC() + 1 );
812 SET_PC( 0xFF00 + data );
813 goto loop;
815 case 0x01: /* TCALL n */
816 case 0x11:
817 case 0x21:
818 case 0x31:
819 case 0x41:
820 case 0x51:
821 case 0x61:
822 case 0x71:
823 case 0x81:
824 case 0x91:
825 case 0xA1:
826 case 0xB1:
827 case 0xC1:
828 case 0xD1:
829 case 0xE1:
830 case 0xF1:
831 PUSH16( GET_PC() );
832 SET_PC( READ_PROG16( 0xFFDE - (opcode >> 3) ) );
833 goto loop;
835 /* 14. STACK OPERATION COMMANDS */
838 int temp;
839 case 0x7F: /* RET1 */
840 temp = POP();
841 SET_PC( POP() );
842 pc += POP() << 8;
843 goto set_status;
844 case 0x8E: /* POP PSW */
845 temp = POP();
846 set_status:
847 SET_STATUS( temp );
848 goto loop;
851 case 0x0D: { /* PUSH PSW */
852 int temp;
853 CALC_STATUS( temp );
854 PUSH( temp );
855 goto loop;
858 case 0x2D: /* PUSH A */
859 PUSH( a );
860 goto loop;
862 case 0x4D: /* PUSH X */
863 PUSH( x );
864 goto loop;
866 case 0x6D: /* PUSH Y */
867 PUSH( y );
868 goto loop;
870 case 0xAE: /* POP A */
871 a = POP();
872 goto loop;
874 case 0xCE: /* POP X */
875 x = POP();
876 goto loop;
878 case 0xEE: /* POP Y */
879 y = POP();
880 goto loop;
882 /* 15. BIT OPERATION COMMANDS */
884 case 0x02: /* SET1 */
885 case 0x22:
886 case 0x42:
887 case 0x62:
888 case 0x82:
889 case 0xA2:
890 case 0xC2:
891 case 0xE2:
892 case 0x12: /* CLR1 */
893 case 0x32:
894 case 0x52:
895 case 0x72:
896 case 0x92:
897 case 0xB2:
898 case 0xD2:
899 case 0xF2: {
900 data += dp;
901 int bit = 1 << (opcode >> 5);
902 int mask = ~bit;
903 if ( opcode & 0x10 )
904 bit = 0;
905 WRITE( data, (READ( data ) & mask) | bit );
906 goto inc_pc_loop;
909 case 0x0E: /* TSET1 abs */
910 case 0x4E:{/* TCLR1 abs */
911 data = READ_PC16( pc );
912 pc += 2;
913 unsigned temp = READ( data );
914 nz = temp & a;
915 temp &= ~a;
916 if ( !(opcode & 0x40) )
917 temp |= a;
918 WRITE( data, temp );
919 goto loop;
922 case 0x4A: /* AND1 C,mem.bit */
923 c &= MEM_BIT();
924 pc += 2;
925 goto loop;
927 case 0x6A: /* AND1 C,/mem.bit */
928 check( 0 ); /* untested */
929 c &= ~MEM_BIT();
930 pc += 2;
931 goto loop;
933 case 0x0A: /* OR1 C,mem.bit */
934 check( 0 ); /* untested */
935 c |= MEM_BIT();
936 pc += 2;
937 goto loop;
939 case 0x2A: /* OR1 C,/mem.bit */
940 check( 0 ); /* untested */
941 c |= ~MEM_BIT();
942 pc += 2;
943 goto loop;
945 case 0x8A: /* EOR1 C,mem.bit */
946 c ^= MEM_BIT();
947 pc += 2;
948 goto loop;
950 case 0xEA: { /* NOT1 mem.bit */
951 data = READ_PC16( pc );
952 pc += 2;
953 unsigned temp = READ( data & 0x1FFF );
954 temp ^= 1 << (data >> 13);
955 WRITE( data & 0x1FFF, temp );
956 goto loop;
959 case 0xCA: { /* MOV1 mem.bit,C */
960 data = READ_PC16( pc );
961 pc += 2;
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 );
966 goto loop;
969 case 0xAA: /* MOV1 C,mem.bit */
970 c = MEM_BIT();
971 pc += 2;
972 goto loop;
974 /* 16. PROGRAM STATUS FLAG OPERATION COMMANDS */
976 case 0x60: /* CLRC */
977 c = 0;
978 goto loop;
980 case 0x80: /* SETC */
981 c = ~0;
982 goto loop;
984 case 0xED: /* NOTC */
985 c ^= 0x100;
986 goto loop;
988 case 0xE0: /* CLRV */
989 status &= ~(st_v | st_h);
990 goto loop;
992 case 0x20: /* CLRP */
993 dp = 0;
994 goto loop;
996 case 0x40: /* SETP */
997 dp = 0x100;
998 goto loop;
1000 case 0xA0: /* EI */
1001 check( 0 ); /* untested */
1002 status |= st_i;
1003 goto loop;
1005 case 0xC0: /* DI */
1006 check( 0 ); /* untested */
1007 status &= ~st_i;
1008 goto loop;
1010 /* 17. OTHER COMMANDS */
1012 case 0x00: /* NOP */
1013 goto loop;
1015 /*case 0xEF:*/ /* SLEEP */
1016 /*case 0xFF:*/ /* STOP */
1017 case 0xFF:
1018 c |= 1; /* force switch table to have 256 entries,
1019 hopefully helping optimizer */
1020 } /* switch */
1022 /* unhandled instructions fall out of switch so emulator can catch them */
1024 out_of_time:
1025 /* undo partial execution of opcode */
1026 spc_time_ -= this->cycle_table [*--pc];
1028 int temp;
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;
1039 #if 0
1040 EXIT_TIMER(cpu);
1041 #endif
1042 return spc_time_;
1045 void CPU_Init( THIS )
1047 ci->memcpy( this->cycle_table, cycle_table, sizeof cycle_table );