summaryrefslogtreecommitdiff
path: root/apps/codecs/spc/Spc_Cpu.h
diff options
context:
space:
mode:
Diffstat (limited to 'apps/codecs/spc/Spc_Cpu.h')
-rw-r--r--apps/codecs/spc/Spc_Cpu.h1037
1 files changed, 1037 insertions, 0 deletions
diff --git a/apps/codecs/spc/Spc_Cpu.h b/apps/codecs/spc/Spc_Cpu.h
new file mode 100644
index 0000000000..b931ca2a3b
--- /dev/null
+++ b/apps/codecs/spc/Spc_Cpu.h
@@ -0,0 +1,1037 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 *
9 * Copyright (C) 2006-2007 Adam Gashlin (hcs)
10 * Copyright (C) 2004-2007 Shay Green (blargg)
11 * Copyright (C) 2002 Brad Martin
12 *
13 * All files in this archive are subject to the GNU General Public License.
14 * See the file COPYING in the source tree root for full license agreement.
15 *
16 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
17 * KIND, either express or implied.
18 *
19 ****************************************************************************/
20
21
22/* The CPU portion (shock!) */
23
24#define READ( addr ) (SPC_read( this, addr, spc_time_ ))
25#define WRITE( addr, value ) (SPC_write( this, addr, value, spc_time_ ))
26
27#define READ_DP( addr ) READ( (addr) + dp )
28#define WRITE_DP( addr, value ) WRITE( (addr) + dp, value )
29
30#define READ_PROG16( addr ) GET_LE16( RAM + (addr) )
31
32#define READ_PC( pc ) (*(pc))
33#define READ_PC16( pc ) GET_LE16( pc )
34
35#define SET_PC( n ) (pc = RAM + (n))
36#define GET_PC() (pc - RAM)
37
38static unsigned char const cycle_table [0x100] = {
39 2,8,4,5,3,4,3,6,2,6,5,4,5,4,6,8, /* 0 */
40 2,8,4,5,4,5,5,6,5,5,6,5,2,2,4,6, /* 1 */
41 2,8,4,5,3,4,3,6,2,6,5,4,5,4,5,4, /* 2 */
42 2,8,4,5,4,5,5,6,5,5,6,5,2,2,3,8, /* 3 */
43 2,8,4,5,3,4,3,6,2,6,4,4,5,4,6,6, /* 4 */
44 2,8,4,5,4,5,5,6,5,5,4,5,2,2,4,3, /* 5 */
45 2,8,4,5,3,4,3,6,2,6,4,4,5,4,5,5, /* 6 */
46 2,8,4,5,4,5,5,6,5,5,5,5,2,2,3,6, /* 7 */
47 2,8,4,5,3,4,3,6,2,6,5,4,5,2,4,5, /* 8 */
48 2,8,4,5,4,5,5,6,5,5,5,5,2,2,12,5,/* 9 */
49 3,8,4,5,3,4,3,6,2,6,4,4,5,2,4,4, /* A */
50 2,8,4,5,4,5,5,6,5,5,5,5,2,2,3,4, /* B */
51 3,8,4,5,4,5,4,7,2,5,6,4,5,2,4,9, /* C */
52 2,8,4,5,5,6,6,7,4,5,4,5,2,2,6,3, /* D */
53 2,8,4,5,3,4,3,6,2,4,5,3,4,3,4,3, /* E */
54 2,8,4,5,4,5,5,6,3,4,5,4,2,2,4,3 /* F */
55};
56
57#define MEM_BIT() CPU_mem_bit( this, pc, spc_time_ )
58
59static unsigned CPU_mem_bit( THIS, uint8_t const* pc, long const spc_time_ )
60 ICODE_ATTR;
61
62static unsigned CPU_mem_bit( THIS, uint8_t const* pc, long const spc_time_ )
63{
64 unsigned addr = READ_PC16( pc );
65 unsigned t = READ( addr & 0x1FFF ) >> (addr >> 13);
66 return (t << 8) & 0x100;
67}
68
69/* status flags */
70enum { st_n = 0x80 };
71enum { st_v = 0x40 };
72enum { st_p = 0x20 };
73enum { st_b = 0x10 };
74enum { st_h = 0x08 };
75enum { st_i = 0x04 };
76enum { st_z = 0x02 };
77enum { st_c = 0x01 };
78
79#define IS_NEG (nz & 0x880)
80
81#define CALC_STATUS( out )\
82{\
83 out = status & ~(st_n | st_z | st_c);\
84 out |= (c >> 8) & st_c;\
85 out |= (dp >> 3) & st_p;\
86 if ( IS_NEG ) out |= st_n;\
87 if ( !(nz & 0xFF) ) out |= st_z;\
88}
89
90#define SET_STATUS( in )\
91{\
92 status = in & ~(st_n | st_z | st_c | st_p);\
93 c = in << 8;\
94 nz = ((in << 4) & 0x800) | (~in & st_z);\
95 dp = (in << 3) & 0x100;\
96}
97
98
99/* stack */
100#define PUSH( v ) (*--sp = (uint8_t) (v))
101#define PUSH16( v ) (sp -= 2, SET_LE16( sp, v ))
102#define POP() (*sp++)
103#define SET_SP( v ) (sp = RAM + 0x101 + (v))
104#define GET_SP() (sp - 0x101 - RAM)
105
106static long CPU_run( THIS, long start_time ) ICODE_ATTR;
107
108static long CPU_run( THIS, long start_time )
109{
110#if 0
111 ENTER_TIMER(cpu);
112#endif
113
114 register long spc_time_ = start_time;
115
116#ifdef CPU_ARM
117 uint8_t* const ram_ = ram.ram;
118 #undef RAM
119 #define RAM ram_
120#endif
121
122 int a = this->r.a;
123 int x = this->r.x;
124 int y = this->r.y;
125
126 uint8_t const* pc;
127 SET_PC( this->r.pc );
128
129 uint8_t* sp;
130 SET_SP( this->r.sp );
131
132 int status;
133 int c;
134 int nz;
135 unsigned dp;
136 {
137 int temp = this->r.status;
138 SET_STATUS( temp );
139 }
140
141 goto loop;
142
143 /* main loop */
144cbranch_taken_loop:
145 pc += *(int8_t const*) pc;
146 spc_time_ += 2;
147inc_pc_loop:
148 pc++;
149loop:
150 check( (unsigned) GET_PC() < 0x10000 );
151 check( (unsigned) GET_SP() < 0x100 );
152 check( (unsigned) a < 0x100 );
153 check( (unsigned) x < 0x100 );
154 check( (unsigned) y < 0x100 );
155
156 unsigned opcode = *pc;
157 int cycles = this->cycle_table [opcode];
158 unsigned data = *++pc;
159 if ( (spc_time_ += cycles) > 0 )
160 goto out_of_time;
161 switch ( opcode )
162 {
163
164/* Common instructions */
165
166#define BRANCH( cond )\
167{\
168 pc++;\
169 int offset = (int8_t) data;\
170 if ( cond ) {\
171 pc += offset;\
172 spc_time_ += 2;\
173 }\
174 goto loop;\
175}
176
177 case 0xF0: /* BEQ (most common) */
178 BRANCH( !(uint8_t) nz )
179
180 case 0xD0: /* BNE */
181 BRANCH( (uint8_t) nz )
182
183 case 0x3F: /* CALL */
184 PUSH16( GET_PC() + 2 );
185 SET_PC( READ_PC16( pc ) );
186 goto loop;
187
188 case 0x6F: /* RET */
189 SET_PC( POP() );
190 pc += POP() * 0x100;
191 goto loop;
192
193#define CASE( n ) case n:
194
195/* Define common address modes based on opcode for immediate mode. Execution
196 ends with data set to the address of the operand. */
197#define ADDR_MODES( op )\
198 CASE( op - 0x02 ) /* (X) */\
199 data = x + dp;\
200 pc--;\
201 goto end_##op;\
202 CASE( op + 0x0F ) /* (dp)+Y */\
203 data = READ_PROG16( data + dp ) + y;\
204 goto end_##op;\
205 CASE( op - 0x01 ) /* (dp+X) */\
206 data = READ_PROG16( ((uint8_t) (data + x)) + dp );\
207 goto end_##op;\
208 CASE( op + 0x0E ) /* abs+Y */\
209 data += y;\
210 goto abs_##op;\
211 CASE( op + 0x0D ) /* abs+X */\
212 data += x;\
213 CASE( op - 0x03 ) /* abs */\
214 abs_##op:\
215 data += 0x100 * READ_PC( ++pc );\
216 goto end_##op;\
217 CASE( op + 0x0C ) /* dp+X */\
218 data = (uint8_t) (data + x);\
219 CASE( op - 0x04 ) /* dp */\
220 data += dp;\
221 end_##op:
222
223/* 1. 8-bit Data Transmission Commands. Group I */
224
225 ADDR_MODES( 0xE8 ) /* MOV A,addr */
226 /*case 0xE4:*/ /* MOV a,dp (most common) */
227 mov_a_addr:
228 a = nz = READ( data );
229 goto inc_pc_loop;
230 case 0xBF: /* MOV A,(X)+ */
231 data = x + dp;
232 x = (uint8_t) (x + 1);
233 pc--;
234 goto mov_a_addr;
235
236 case 0xE8: /* MOV A,imm */
237 a = data;
238 nz = data;
239 goto inc_pc_loop;
240
241 case 0xF9: /* MOV X,dp+Y */
242 data = (uint8_t) (data + y);
243 case 0xF8: /* MOV X,dp */
244 data += dp;
245 goto mov_x_addr;
246 case 0xE9: /* MOV X,abs */
247 data = READ_PC16( pc );
248 pc++;
249 mov_x_addr:
250 data = READ( data );
251 case 0xCD: /* MOV X,imm */
252 x = data;
253 nz = data;
254 goto inc_pc_loop;
255
256 case 0xFB: /* MOV Y,dp+X */
257 data = (uint8_t) (data + x);
258 case 0xEB: /* MOV Y,dp */
259 data += dp;
260 goto mov_y_addr;
261 case 0xEC: /* MOV Y,abs */
262 data = READ_PC16( pc );
263 pc++;
264 mov_y_addr:
265 data = READ( data );
266 case 0x8D: /* MOV Y,imm */
267 y = data;
268 nz = data;
269 goto inc_pc_loop;
270
271/* 2. 8-BIT DATA TRANSMISSION COMMANDS, GROUP 2 */
272
273 ADDR_MODES( 0xC8 ) /* MOV addr,A */
274 WRITE( data, a );
275 goto inc_pc_loop;
276
277 {
278 int temp;
279 case 0xCC: /* MOV abs,Y */
280 temp = y;
281 goto mov_abs_temp;
282 case 0xC9: /* MOV abs,X */
283 temp = x;
284 mov_abs_temp:
285 WRITE( READ_PC16( pc ), temp );
286 pc += 2;
287 goto loop;
288 }
289
290 case 0xD9: /* MOV dp+Y,X */
291 data = (uint8_t) (data + y);
292 case 0xD8: /* MOV dp,X */
293 WRITE( data + dp, x );
294 goto inc_pc_loop;
295
296 case 0xDB: /* MOV dp+X,Y */
297 data = (uint8_t) (data + x);
298 case 0xCB: /* MOV dp,Y */
299 WRITE( data + dp, y );
300 goto inc_pc_loop;
301
302 case 0xFA: /* MOV dp,dp */
303 data = READ( data + dp );
304 case 0x8F: /* MOV dp,#imm */
305 WRITE_DP( READ_PC( ++pc ), data );
306 goto inc_pc_loop;
307
308/* 3. 8-BIT DATA TRANSMISSIN COMMANDS, GROUP 3. */
309
310 case 0x7D: /* MOV A,X */
311 a = x;
312 nz = x;
313 goto loop;
314
315 case 0xDD: /* MOV A,Y */
316 a = y;
317 nz = y;
318 goto loop;
319
320 case 0x5D: /* MOV X,A */
321 x = a;
322 nz = a;
323 goto loop;
324
325 case 0xFD: /* MOV Y,A */
326 y = a;
327 nz = a;
328 goto loop;
329
330 case 0x9D: /* MOV X,SP */
331 x = nz = GET_SP();
332 goto loop;
333
334 case 0xBD: /* MOV SP,X */
335 SET_SP( x );
336 goto loop;
337
338 /*case 0xC6:*/ /* MOV (X),A (handled by MOV addr,A in group 2) */
339
340 case 0xAF: /* MOV (X)+,A */
341 WRITE_DP( x, a );
342 x++;
343 goto loop;
344
345/* 5. 8-BIT LOGIC OPERATION COMMANDS */
346
347#define LOGICAL_OP( op, func )\
348 ADDR_MODES( op ) /* addr */\
349 data = READ( data );\
350 case op: /* imm */\
351 nz = a func##= data;\
352 goto inc_pc_loop;\
353 { unsigned addr;\
354 case op + 0x11: /* X,Y */\
355 data = READ_DP( y );\
356 addr = x + dp;\
357 pc--;\
358 goto addr_##op;\
359 case op + 0x01: /* dp,dp */\
360 data = READ_DP( data );\
361 case op + 0x10: /*dp,imm*/\
362 addr = READ_PC( ++pc ) + dp;\
363 addr_##op:\
364 nz = data func READ( addr );\
365 WRITE( addr, nz );\
366 goto inc_pc_loop;\
367 }
368
369 LOGICAL_OP( 0x28, & ); /* AND */
370
371 LOGICAL_OP( 0x08, | ); /* OR */
372
373 LOGICAL_OP( 0x48, ^ ); /* EOR */
374
375/* 4. 8-BIT ARITHMETIC OPERATION COMMANDS */
376
377 ADDR_MODES( 0x68 ) /* CMP addr */
378 data = READ( data );
379 case 0x68: /* CMP imm */
380 nz = a - data;
381 c = ~nz;
382 nz &= 0xFF;
383 goto inc_pc_loop;
384
385 case 0x79: /* CMP (X),(Y) */
386 data = READ_DP( x );
387 nz = data - READ_DP( y );
388 c = ~nz;
389 nz &= 0xFF;
390 goto loop;
391
392 case 0x69: /* CMP (dp),(dp) */
393 data = READ_DP( data );
394 case 0x78: /* CMP dp,imm */
395 nz = READ_DP( READ_PC( ++pc ) ) - data;
396 c = ~nz;
397 nz &= 0xFF;
398 goto inc_pc_loop;
399
400 case 0x3E: /* CMP X,dp */
401 data += dp;
402 goto cmp_x_addr;
403 case 0x1E: /* CMP X,abs */
404 data = READ_PC16( pc );
405 pc++;
406 cmp_x_addr:
407 data = READ( data );
408 case 0xC8: /* CMP X,imm */
409 nz = x - data;
410 c = ~nz;
411 nz &= 0xFF;
412 goto inc_pc_loop;
413
414 case 0x7E: /* CMP Y,dp */
415 data += dp;
416 goto cmp_y_addr;
417 case 0x5E: /* CMP Y,abs */
418 data = READ_PC16( pc );
419 pc++;
420 cmp_y_addr:
421 data = READ( data );
422 case 0xAD: /* CMP Y,imm */
423 nz = y - data;
424 c = ~nz;
425 nz &= 0xFF;
426 goto inc_pc_loop;
427
428 {
429 int addr;
430 case 0xB9: /* SBC (x),(y) */
431 case 0x99: /* ADC (x),(y) */
432 pc--; /* compensate for inc later */
433 data = READ_DP( x );
434 addr = y + dp;
435 goto adc_addr;
436 case 0xA9: /* SBC dp,dp */
437 case 0x89: /* ADC dp,dp */
438 data = READ_DP( data );
439 case 0xB8: /* SBC dp,imm */
440 case 0x98: /* ADC dp,imm */
441 addr = READ_PC( ++pc ) + dp;
442 adc_addr:
443 nz = READ( addr );
444 goto adc_data;
445
446/* catch ADC and SBC together, then decode later based on operand */
447#undef CASE
448#define CASE( n ) case n: case (n) + 0x20:
449 ADDR_MODES( 0x88 ) /* ADC/SBC addr */
450 data = READ( data );
451 case 0xA8: /* SBC imm */
452 case 0x88: /* ADC imm */
453 addr = -1; /* A */
454 nz = a;
455 adc_data: {
456 if ( opcode & 0x20 )
457 data ^= 0xFF; /* SBC */
458 int carry = (c >> 8) & 1;
459 int ov = (nz ^ 0x80) + carry + (int8_t) data; /* sign-extend */
460 int hc = (nz & 15) + carry;
461 c = nz += data + carry;
462 hc = (nz & 15) - hc;
463 status = (status & ~(st_v | st_h)) | ((ov >> 2) & st_v) |
464 ((hc >> 1) & st_h);
465 if ( addr < 0 ) {
466 a = (uint8_t) nz;
467 goto inc_pc_loop;
468 }
469 WRITE( addr, (uint8_t) nz );
470 goto inc_pc_loop;
471 }
472
473 }
474
475/* 6. ADDITION & SUBTRACTION COMMANDS */
476
477#define INC_DEC_REG( reg, n )\
478 nz = reg + n;\
479 reg = (uint8_t) nz;\
480 goto loop;
481
482 case 0xBC: INC_DEC_REG( a, 1 ) /* INC A */
483 case 0x3D: INC_DEC_REG( x, 1 ) /* INC X */
484 case 0xFC: INC_DEC_REG( y, 1 ) /* INC Y */
485
486 case 0x9C: INC_DEC_REG( a, -1 ) /* DEC A */
487 case 0x1D: INC_DEC_REG( x, -1 ) /* DEC X */
488 case 0xDC: INC_DEC_REG( y, -1 ) /* DEC Y */
489
490 case 0x9B: /* DEC dp+X */
491 case 0xBB: /* INC dp+X */
492 data = (uint8_t) (data + x);
493 case 0x8B: /* DEC dp */
494 case 0xAB: /* INC dp */
495 data += dp;
496 goto inc_abs;
497 case 0x8C: /* DEC abs */
498 case 0xAC: /* INC abs */
499 data = READ_PC16( pc );
500 pc++;
501 inc_abs:
502 nz = ((opcode >> 4) & 2) - 1;
503 nz += READ( data );
504 WRITE( data, (uint8_t) nz );
505 goto inc_pc_loop;
506
507/* 7. SHIFT, ROTATION COMMANDS */
508
509 case 0x5C: /* LSR A */
510 c = 0;
511 case 0x7C:{/* ROR A */
512 nz = ((c >> 1) & 0x80) | (a >> 1);
513 c = a << 8;
514 a = nz;
515 goto loop;
516 }
517
518 case 0x1C: /* ASL A */
519 c = 0;
520 case 0x3C:{/* ROL A */
521 int temp = (c >> 8) & 1;
522 c = a << 1;
523 nz = c | temp;
524 a = (uint8_t) nz;
525 goto loop;
526 }
527
528 case 0x0B: /* ASL dp */
529 c = 0;
530 data += dp;
531 goto rol_mem;
532 case 0x1B: /* ASL dp+X */
533 c = 0;
534 case 0x3B: /* ROL dp+X */
535 data = (uint8_t) (data + x);
536 case 0x2B: /* ROL dp */
537 data += dp;
538 goto rol_mem;
539 case 0x0C: /* ASL abs */
540 c = 0;
541 case 0x2C: /* ROL abs */
542 data = READ_PC16( pc );
543 pc++;
544 rol_mem:
545 nz = (c >> 8) & 1;
546 nz |= (c = READ( data ) << 1);
547 WRITE( data, (uint8_t) nz );
548 goto inc_pc_loop;
549
550 case 0x4B: /* LSR dp */
551 c = 0;
552 data += dp;
553 goto ror_mem;
554 case 0x5B: /* LSR dp+X */
555 c = 0;
556 case 0x7B: /* ROR dp+X */
557 data = (uint8_t) (data + x);
558 case 0x6B: /* ROR dp */
559 data += dp;
560 goto ror_mem;
561 case 0x4C: /* LSR abs */
562 c = 0;
563 case 0x6C: /* ROR abs */
564 data = READ_PC16( pc );
565 pc++;
566 ror_mem: {
567 int temp = READ( data );
568 nz = ((c >> 1) & 0x80) | (temp >> 1);
569 c = temp << 8;
570 WRITE( data, nz );
571 goto inc_pc_loop;
572 }
573
574 case 0x9F: /* XCN */
575 nz = a = (a >> 4) | (uint8_t) (a << 4);
576 goto loop;
577
578/* 8. 16-BIT TRANSMISION COMMANDS */
579
580 case 0xBA: /* MOVW YA,dp */
581 a = READ_DP( data );
582 nz = (a & 0x7F) | (a >> 1);
583 y = READ_DP( (uint8_t) (data + 1) );
584 nz |= y;
585 goto inc_pc_loop;
586
587 case 0xDA: /* MOVW dp,YA */
588 WRITE_DP( data, a );
589 WRITE_DP( (uint8_t) (data + 1), y );
590 goto inc_pc_loop;
591
592/* 9. 16-BIT OPERATION COMMANDS */
593
594 case 0x3A: /* INCW dp */
595 case 0x1A:{/* DECW dp */
596 data += dp;
597
598 /* low byte */
599 int temp = READ( data );
600 temp += ((opcode >> 4) & 2) - 1; /* +1 for INCW, -1 for DECW */
601 nz = ((temp >> 1) | temp) & 0x7F;
602 WRITE( data, (uint8_t) temp );
603
604 /* high byte */
605 data = ((uint8_t) (data + 1)) + dp;
606 temp >>= 8;
607 temp = (uint8_t) (temp + READ( data ));
608 nz |= temp;
609 WRITE( data, temp );
610
611 goto inc_pc_loop;
612 }
613
614 case 0x9A: /* SUBW YA,dp */
615 case 0x7A: /* ADDW YA,dp */
616 {
617 /* read 16-bit addend */
618 int temp = READ_DP( data );
619 int sign = READ_DP( (uint8_t) (data + 1) );
620 temp += 0x100 * sign;
621 status &= ~(st_v | st_h);
622
623 /* to do: fix half-carry for SUBW (it's probably wrong) */
624
625 /* for SUBW, negate and truncate to 16 bits */
626 if ( opcode & 0x80 ) {
627 temp = (temp ^ 0xFFFF) + 1;
628 sign = temp >> 8;
629 }
630
631 /* add low byte (A) */
632 temp += a;
633 a = (uint8_t) temp;
634 nz = (temp | (temp >> 1)) & 0x7F;
635
636 /* add high byte (Y) */
637 temp >>= 8;
638 c = y + temp;
639 nz = (nz | c) & 0xFF;
640
641 /* half-carry (temporary avoids CodeWarrior optimizer bug) */
642 unsigned hc = (c & 15) - (y & 15);
643 status |= (hc >> 4) & st_h;
644
645 /* overflow if sign of YA changed when previous sign
646 and addend sign were same */
647 status |= (((c ^ y) & ~(y ^ sign)) >> 1) & st_v;
648
649 y = (uint8_t) c;
650
651 goto inc_pc_loop;
652 }
653
654 case 0x5A: { /* CMPW YA,dp */
655 int temp = a - READ_DP( data );
656 nz = ((temp >> 1) | temp) & 0x7F;
657 temp = y + (temp >> 8);
658 temp -= READ_DP( (uint8_t) (data + 1) );
659 nz |= temp;
660 c = ~temp;
661 nz &= 0xFF;
662 goto inc_pc_loop;
663 }
664
665/* 10. MULTIPLICATION & DIVISON COMMANDS */
666
667 case 0xCF: { /* MUL YA */
668 unsigned temp = y * a;
669 a = (uint8_t) temp;
670 nz = ((temp >> 1) | temp) & 0x7F;
671 y = temp >> 8;
672 nz |= y;
673 goto loop;
674 }
675
676 case 0x9E: /* DIV YA,X */
677 {
678 /* behavior based on SPC CPU tests */
679
680 status &= ~(st_h | st_v);
681
682 if ( (y & 15) >= (x & 15) )
683 status |= st_h;
684
685 if ( y >= x )
686 status |= st_v;
687
688 unsigned ya = y * 0x100 + a;
689 if ( y < x * 2 )
690 {
691 a = ya / x;
692 y = ya - a * x;
693 }
694 else
695 {
696 a = 255 - (ya - x * 0x200) / (256 - x);
697 y = x + (ya - x * 0x200) % (256 - x);
698 }
699
700 nz = (uint8_t) a;
701 a = (uint8_t) a;
702
703 goto loop;
704 }
705
706/* 11. DECIMAL COMPENSATION COMMANDS */
707
708 /* seem unused */
709 /* case 0xDF: */ /* DAA */
710 /* case 0xBE: */ /* DAS */
711
712/* 12. BRANCHING COMMANDS */
713
714 case 0x2F: /* BRA rel */
715 pc += (int8_t) data;
716 goto inc_pc_loop;
717
718 case 0x30: /* BMI */
719 BRANCH( IS_NEG )
720
721 case 0x10: /* BPL */
722 BRANCH( !IS_NEG )
723
724 case 0xB0: /* BCS */
725 BRANCH( c & 0x100 )
726
727 case 0x90: /* BCC */
728 BRANCH( !(c & 0x100) )
729
730 case 0x70: /* BVS */
731 BRANCH( status & st_v )
732
733 case 0x50: /* BVC */
734 BRANCH( !(status & st_v) )
735
736 case 0x03: /* BBS dp.bit,rel */
737 case 0x23:
738 case 0x43:
739 case 0x63:
740 case 0x83:
741 case 0xA3:
742 case 0xC3:
743 case 0xE3:
744 pc++;
745 if ( (READ_DP( data ) >> (opcode >> 5)) & 1 )
746 goto cbranch_taken_loop;
747 goto inc_pc_loop;
748
749 case 0x13: /* BBC dp.bit,rel */
750 case 0x33:
751 case 0x53:
752 case 0x73:
753 case 0x93:
754 case 0xB3:
755 case 0xD3:
756 case 0xF3:
757 pc++;
758 if ( !((READ_DP( data ) >> (opcode >> 5)) & 1) )
759 goto cbranch_taken_loop;
760 goto inc_pc_loop;
761
762 case 0xDE: /* CBNE dp+X,rel */
763 data = (uint8_t) (data + x);
764 /* fall through */
765 case 0x2E: /* CBNE dp,rel */
766 pc++;
767 if ( READ_DP( data ) != a )
768 goto cbranch_taken_loop;
769 goto inc_pc_loop;
770
771 case 0xFE: /* DBNZ Y,rel */
772 y = (uint8_t) (y - 1);
773 BRANCH( y )
774
775 case 0x6E: { /* DBNZ dp,rel */
776 pc++;
777 unsigned temp = READ_DP( data ) - 1;
778 WRITE_DP( (uint8_t) data, (uint8_t) temp );
779 if ( temp )
780 goto cbranch_taken_loop;
781 goto inc_pc_loop;
782 }
783
784 case 0x1F: /* JMP (abs+X) */
785 SET_PC( READ_PC16( pc ) + x );
786 /* fall through */
787 case 0x5F: /* JMP abs */
788 SET_PC( READ_PC16( pc ) );
789 goto loop;
790
791/* 13. SUB-ROUTINE CALL RETURN COMMANDS */
792
793 case 0x0F:{/* BRK */
794 check( 0 ); /* untested */
795 PUSH16( GET_PC() + 1 );
796 SET_PC( READ_PROG16( 0xFFDE ) ); /* vector address verified */
797 int temp;
798 CALC_STATUS( temp );
799 PUSH( temp );
800 status = (status | st_b) & ~st_i;
801 goto loop;
802 }
803
804 case 0x4F: /* PCALL offset */
805 PUSH16( GET_PC() + 1 );
806 SET_PC( 0xFF00 + data );
807 goto loop;
808
809 case 0x01: /* TCALL n */
810 case 0x11:
811 case 0x21:
812 case 0x31:
813 case 0x41:
814 case 0x51:
815 case 0x61:
816 case 0x71:
817 case 0x81:
818 case 0x91:
819 case 0xA1:
820 case 0xB1:
821 case 0xC1:
822 case 0xD1:
823 case 0xE1:
824 case 0xF1:
825 PUSH16( GET_PC() );
826 SET_PC( READ_PROG16( 0xFFDE - (opcode >> 3) ) );
827 goto loop;
828
829/* 14. STACK OPERATION COMMANDS */
830
831 {
832 int temp;
833 case 0x7F: /* RET1 */
834 temp = POP();
835 SET_PC( POP() );
836 pc += POP() << 8;
837 goto set_status;
838 case 0x8E: /* POP PSW */
839 temp = POP();
840 set_status:
841 SET_STATUS( temp );
842 goto loop;
843 }
844
845 case 0x0D: { /* PUSH PSW */
846 int temp;
847 CALC_STATUS( temp );
848 PUSH( temp );
849 goto loop;
850 }
851
852 case 0x2D: /* PUSH A */
853 PUSH( a );
854 goto loop;
855
856 case 0x4D: /* PUSH X */
857 PUSH( x );
858 goto loop;
859
860 case 0x6D: /* PUSH Y */
861 PUSH( y );
862 goto loop;
863
864 case 0xAE: /* POP A */
865 a = POP();
866 goto loop;
867
868 case 0xCE: /* POP X */
869 x = POP();
870 goto loop;
871
872 case 0xEE: /* POP Y */
873 y = POP();
874 goto loop;
875
876/* 15. BIT OPERATION COMMANDS */
877
878 case 0x02: /* SET1 */
879 case 0x22:
880 case 0x42:
881 case 0x62:
882 case 0x82:
883 case 0xA2:
884 case 0xC2:
885 case 0xE2:
886 case 0x12: /* CLR1 */
887 case 0x32:
888 case 0x52:
889 case 0x72:
890 case 0x92:
891 case 0xB2:
892 case 0xD2:
893 case 0xF2: {
894 data += dp;
895 int bit = 1 << (opcode >> 5);
896 int mask = ~bit;
897 if ( opcode & 0x10 )
898 bit = 0;
899 WRITE( data, (READ( data ) & mask) | bit );
900 goto inc_pc_loop;
901 }
902
903 case 0x0E: /* TSET1 abs */
904 case 0x4E:{/* TCLR1 abs */
905 data = READ_PC16( pc );
906 pc += 2;
907 unsigned temp = READ( data );
908 nz = temp & a;
909 temp &= ~a;
910 if ( !(opcode & 0x40) )
911 temp |= a;
912 WRITE( data, temp );
913 goto loop;
914 }
915
916 case 0x4A: /* AND1 C,mem.bit */
917 c &= MEM_BIT();
918 pc += 2;
919 goto loop;
920
921 case 0x6A: /* AND1 C,/mem.bit */
922 check( 0 ); /* untested */
923 c &= ~MEM_BIT();
924 pc += 2;
925 goto loop;
926
927 case 0x0A: /* OR1 C,mem.bit */
928 check( 0 ); /* untested */
929 c |= MEM_BIT();
930 pc += 2;
931 goto loop;
932
933 case 0x2A: /* OR1 C,/mem.bit */
934 check( 0 ); /* untested */
935 c |= ~MEM_BIT();
936 pc += 2;
937 goto loop;
938
939 case 0x8A: /* EOR1 C,mem.bit */
940 c ^= MEM_BIT();
941 pc += 2;
942 goto loop;
943
944 case 0xEA: { /* NOT1 mem.bit */
945 data = READ_PC16( pc );
946 pc += 2;
947 unsigned temp = READ( data & 0x1FFF );
948 temp ^= 1 << (data >> 13);
949 WRITE( data & 0x1FFF, temp );
950 goto loop;
951 }
952
953 case 0xCA: { /* MOV1 mem.bit,C */
954 data = READ_PC16( pc );
955 pc += 2;
956 unsigned temp = READ( data & 0x1FFF );
957 unsigned bit = data >> 13;
958 temp = (temp & ~(1 << bit)) | (((c >> 8) & 1) << bit);
959 WRITE( data & 0x1FFF, temp );
960 goto loop;
961 }
962
963 case 0xAA: /* MOV1 C,mem.bit */
964 c = MEM_BIT();
965 pc += 2;
966 goto loop;
967
968/* 16. PROGRAM STATUS FLAG OPERATION COMMANDS */
969
970 case 0x60: /* CLRC */
971 c = 0;
972 goto loop;
973
974 case 0x80: /* SETC */
975 c = ~0;
976 goto loop;
977
978 case 0xED: /* NOTC */
979 c ^= 0x100;
980 goto loop;
981
982 case 0xE0: /* CLRV */
983 status &= ~(st_v | st_h);
984 goto loop;
985
986 case 0x20: /* CLRP */
987 dp = 0;
988 goto loop;
989
990 case 0x40: /* SETP */
991 dp = 0x100;
992 goto loop;
993
994 case 0xA0: /* EI */
995 check( 0 ); /* untested */
996 status |= st_i;
997 goto loop;
998
999 case 0xC0: /* DI */
1000 check( 0 ); /* untested */
1001 status &= ~st_i;
1002 goto loop;
1003
1004/* 17. OTHER COMMANDS */
1005
1006 case 0x00: /* NOP */
1007 goto loop;
1008
1009 /*case 0xEF:*/ /* SLEEP */
1010 /*case 0xFF:*/ /* STOP */
1011 case 0xFF:
1012 c |= 1; /* force switch table to have 256 entries,
1013 hopefully helping optimizer */
1014 } /* switch */
1015
1016 /* unhandled instructions fall out of switch so emulator can catch them */
1017
1018out_of_time:
1019 /* undo partial execution of opcode */
1020 spc_time_ -= this->cycle_table [*--pc];
1021 {
1022 int temp;
1023 CALC_STATUS( temp );
1024 this->r.status = (uint8_t) temp;
1025 }
1026
1027 this->r.pc = GET_PC();
1028 this->r.sp = (uint8_t) GET_SP();
1029 this->r.a = (uint8_t) a;
1030 this->r.x = (uint8_t) x;
1031 this->r.y = (uint8_t) y;
1032
1033#if 0
1034 EXIT_TIMER(cpu);
1035#endif
1036 return spc_time_;
1037}