summaryrefslogtreecommitdiff
path: root/lib/rbcodec/codecs/libspc/spc_cpu.c
diff options
context:
space:
mode:
Diffstat (limited to 'lib/rbcodec/codecs/libspc/spc_cpu.c')
-rw-r--r--lib/rbcodec/codecs/libspc/spc_cpu.c1049
1 files changed, 1049 insertions, 0 deletions
diff --git a/lib/rbcodec/codecs/libspc/spc_cpu.c b/lib/rbcodec/codecs/libspc/spc_cpu.c
new file mode 100644
index 0000000000..23dcc257de
--- /dev/null
+++ b/lib/rbcodec/codecs/libspc/spc_cpu.c
@@ -0,0 +1,1049 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * Copyright (C) 2006-2007 Adam Gashlin (hcs)
11 * Copyright (C) 2004-2007 Shay Green (blargg)
12 * Copyright (C) 2002 Brad Martin
13 *
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.
18 *
19 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
20 * KIND, either express or implied.
21 *
22 ****************************************************************************/
23
24/* The CPU portion (shock!) */
25#include "codeclib.h"
26#include "spc_codec.h"
27#include "spc_profiler.h"
28
29#undef check
30#define check assert
31
32#define READ( addr ) (SPC_read( this, addr, spc_time_ ))
33#define WRITE( addr, value ) (SPC_write( this, addr, value, spc_time_ ))
34
35#define READ_DP( addr ) READ( (addr) + dp )
36#define WRITE_DP( addr, value ) WRITE( (addr) + dp, value )
37
38#define READ_PROG16( addr ) GET_LE16( RAM + (addr) )
39
40#define READ_PC( pc ) (*(pc))
41#define READ_PC16( pc ) GET_LE16( pc )
42
43#define SET_PC( n ) (pc = RAM + (n))
44#define GET_PC() (pc - RAM)
45
46static 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 */
63};
64
65#define MEM_BIT() CPU_mem_bit( this, pc, spc_time_ )
66
67static unsigned CPU_mem_bit( THIS, uint8_t const* pc, long const spc_time_ )
68 ICODE_ATTR_SPC;
69
70static unsigned CPU_mem_bit( THIS, uint8_t const* pc, long const spc_time_ )
71{
72 unsigned addr = READ_PC16( pc );
73 unsigned t = READ( addr & 0x1FFF ) >> (addr >> 13);
74 return (t << 8) & 0x100;
75}
76
77/* status flags */
78enum { st_n = 0x80 };
79enum { st_v = 0x40 };
80enum { st_p = 0x20 };
81enum { st_b = 0x10 };
82enum { st_h = 0x08 };
83enum { st_i = 0x04 };
84enum { st_z = 0x02 };
85enum { st_c = 0x01 };
86
87#define IS_NEG (nz & 0x880)
88
89#define CALC_STATUS( out )\
90{\
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;\
96}
97
98#define SET_STATUS( in )\
99{\
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;\
104}
105
106
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)
113
114long CPU_run( THIS, long start_time )
115{
116#if 0
117 ENTER_TIMER(cpu);
118#endif
119
120 register long spc_time_ = start_time;
121
122#ifdef CPU_ARM
123 uint8_t* const ram_ = ram.ram;
124 #undef RAM
125 #define RAM ram_
126#endif
127
128 int a = this->r.a;
129 int x = this->r.x;
130 int y = this->r.y;
131
132 uint8_t const* pc;
133 SET_PC( this->r.pc );
134
135 uint8_t* sp;
136 SET_SP( this->r.sp );
137
138 int status;
139 int c;
140 int nz;
141 unsigned dp;
142 {
143 int temp = this->r.status;
144 SET_STATUS( temp );
145 }
146
147 goto loop;
148
149 /* main loop */
150cbranch_taken_loop:
151 pc += *(int8_t const*) pc;
152 spc_time_ += 2;
153inc_pc_loop:
154 pc++;
155loop:
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 );
161
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 )
168 {
169
170/* Common instructions */
171
172#define BRANCH( cond )\
173{\
174 pc++;\
175 int offset = (int8_t) data;\
176 if ( cond ) {\
177 pc += offset;\
178 spc_time_ += 2;\
179 }\
180 goto loop;\
181}
182
183 case 0xF0: /* BEQ (most common) */
184 BRANCH( !(uint8_t) nz )
185
186 case 0xD0: /* BNE */
187 BRANCH( (uint8_t) nz )
188
189 case 0x3F: /* CALL */
190 PUSH16( GET_PC() + 2 );
191 SET_PC( READ_PC16( pc ) );
192 goto loop;
193
194 case 0x6F: /* RET */
195 SET_PC( POP() );
196 pc += POP() * 0x100;
197 goto loop;
198
199#define CASE( n ) case n:
200
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:
228
229/* 1. 8-bit Data Transmission Commands. Group I */
230
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;
241
242 case 0xE8: /* MOV A,imm */
243 a = data;
244 nz = data;
245 goto inc_pc_loop;
246
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;
261
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;
276
277/* 2. 8-BIT DATA TRANSMISSION COMMANDS, GROUP 2 */
278
279 ADDR_MODES( 0xC8 ) /* MOV addr,A */
280 WRITE( data, a );
281 goto inc_pc_loop;
282
283 {
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;
294 }
295
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;
301
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;
307
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;
313
314/* 3. 8-BIT DATA TRANSMISSIN COMMANDS, GROUP 3. */
315
316 case 0x7D: /* MOV A,X */
317 a = x;
318 nz = x;
319 goto loop;
320
321 case 0xDD: /* MOV A,Y */
322 a = y;
323 nz = y;
324 goto loop;
325
326 case 0x5D: /* MOV X,A */
327 x = a;
328 nz = a;
329 goto loop;
330
331 case 0xFD: /* MOV Y,A */
332 y = a;
333 nz = a;
334 goto loop;
335
336 case 0x9D: /* MOV X,SP */
337 x = nz = GET_SP();
338 goto loop;
339
340 case 0xBD: /* MOV SP,X */
341 SET_SP( x );
342 goto loop;
343
344 /*case 0xC6:*/ /* MOV (X),A (handled by MOV addr,A in group 2) */
345
346 case 0xAF: /* MOV (X)+,A */
347 WRITE_DP( x, a );
348 x++;
349 goto loop;
350
351/* 5. 8-BIT LOGIC OPERATION COMMANDS */
352
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;\
373 }
374
375 LOGICAL_OP( 0x28, & ); /* AND */
376
377 LOGICAL_OP( 0x08, | ); /* OR */
378
379 LOGICAL_OP( 0x48, ^ ); /* EOR */
380
381/* 4. 8-BIT ARITHMETIC OPERATION COMMANDS */
382
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;
390
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;
397
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;
405
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;
419
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;
433
434 {
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;
451
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;
474 }
475 WRITE( addr, (uint8_t) nz );
476 goto inc_pc_loop;
477 }
478
479 }
480
481/* 6. ADDITION & SUBTRACTION COMMANDS */
482
483#define INC_DEC_REG( reg, n )\
484 nz = reg + n;\
485 reg = (uint8_t) nz;\
486 goto loop;
487
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 */
491
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 */
495
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;
512
513/* 7. SHIFT, ROTATION COMMANDS */
514
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;
522 }
523
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;
532 }
533
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;
555
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;
578 }
579
580 case 0x9F: /* XCN */
581 nz = a = (a >> 4) | (uint8_t) (a << 4);
582 goto loop;
583
584/* 8. 16-BIT TRANSMISION COMMANDS */
585
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;
592
593 case 0xDA: /* MOVW dp,YA */
594 WRITE_DP( data, a );
595 WRITE_DP( (uint8_t) (data + 1), y );
596 goto inc_pc_loop;
597
598/* 9. 16-BIT OPERATION COMMANDS */
599
600 case 0x3A: /* INCW dp */
601 case 0x1A:{/* DECW dp */
602 data += dp;
603
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 );
609
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 );
616
617 goto inc_pc_loop;
618 }
619
620 case 0x9A: /* SUBW YA,dp */
621 case 0x7A: /* ADDW YA,dp */
622 {
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);
628
629 /* to do: fix half-carry for SUBW (it's probably wrong) */
630
631 /* for SUBW, negate and truncate to 16 bits */
632 if ( opcode & 0x80 ) {
633 temp = (temp ^ 0xFFFF) + 1;
634 sign = temp >> 8;
635 }
636
637 /* add low byte (A) */
638 temp += a;
639 a = (uint8_t) temp;
640 nz = (temp | (temp >> 1)) & 0x7F;
641
642 /* add high byte (Y) */
643 temp >>= 8;
644 c = y + temp;
645 nz = (nz | c) & 0xFF;
646
647 /* half-carry (temporary avoids CodeWarrior optimizer bug) */
648 unsigned hc = (c & 15) - (y & 15);
649 status |= (hc >> 4) & st_h;
650
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;
654
655 y = (uint8_t) c;
656
657 goto inc_pc_loop;
658 }
659
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;
669 }
670
671/* 10. MULTIPLICATION & DIVISON COMMANDS */
672
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;
680 }
681
682 case 0x9E: /* DIV YA,X */
683 {
684 /* behavior based on SPC CPU tests */
685
686 status &= ~(st_h | st_v);
687
688 if ( (y & 15) >= (x & 15) )
689 status |= st_h;
690
691 if ( y >= x )
692 status |= st_v;
693
694 unsigned ya = y * 0x100 + a;
695 if ( y < x * 2 )
696 {
697 a = ya / x;
698 y = ya - a * x;
699 }
700 else
701 {
702 a = 255 - (ya - x * 0x200) / (256 - x);
703 y = x + (ya - x * 0x200) % (256 - x);
704 }
705
706 nz = (uint8_t) a;
707 a = (uint8_t) a;
708
709 goto loop;
710 }
711
712/* 11. DECIMAL COMPENSATION COMMANDS */
713
714 /* seem unused */
715 /* case 0xDF: */ /* DAA */
716 /* case 0xBE: */ /* DAS */
717
718/* 12. BRANCHING COMMANDS */
719
720 case 0x2F: /* BRA rel */
721 pc += (int8_t) data;
722 goto inc_pc_loop;
723
724 case 0x30: /* BMI */
725 BRANCH( IS_NEG )
726
727 case 0x10: /* BPL */
728 BRANCH( !IS_NEG )
729
730 case 0xB0: /* BCS */
731 BRANCH( c & 0x100 )
732
733 case 0x90: /* BCC */
734 BRANCH( !(c & 0x100) )
735
736 case 0x70: /* BVS */
737 BRANCH( status & st_v )
738
739 case 0x50: /* BVC */
740 BRANCH( !(status & st_v) )
741
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;
754
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;
767
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;
776
777 case 0xFE: /* DBNZ Y,rel */
778 y = (uint8_t) (y - 1);
779 BRANCH( y )
780
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;
788 }
789
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;
796
797/* 13. SUB-ROUTINE CALL RETURN COMMANDS */
798
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;
808 }
809
810 case 0x4F: /* PCALL offset */
811 PUSH16( GET_PC() + 1 );
812 SET_PC( 0xFF00 + data );
813 goto loop;
814
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;
834
835/* 14. STACK OPERATION COMMANDS */
836
837 {
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;
849 }
850
851 case 0x0D: { /* PUSH PSW */
852 int temp;
853 CALC_STATUS( temp );
854 PUSH( temp );
855 goto loop;
856 }
857
858 case 0x2D: /* PUSH A */
859 PUSH( a );
860 goto loop;
861
862 case 0x4D: /* PUSH X */
863 PUSH( x );
864 goto loop;
865
866 case 0x6D: /* PUSH Y */
867 PUSH( y );
868 goto loop;
869
870 case 0xAE: /* POP A */
871 a = POP();
872 goto loop;
873
874 case 0xCE: /* POP X */
875 x = POP();
876 goto loop;
877
878 case 0xEE: /* POP Y */
879 y = POP();
880 goto loop;
881
882/* 15. BIT OPERATION COMMANDS */
883
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;
907 }
908
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;
920 }
921
922 case 0x4A: /* AND1 C,mem.bit */
923 c &= MEM_BIT();
924 pc += 2;
925 goto loop;
926
927 case 0x6A: /* AND1 C,/mem.bit */
928 check( 0 ); /* untested */
929 c &= ~MEM_BIT();
930 pc += 2;
931 goto loop;
932
933 case 0x0A: /* OR1 C,mem.bit */
934 check( 0 ); /* untested */
935 c |= MEM_BIT();
936 pc += 2;
937 goto loop;
938
939 case 0x2A: /* OR1 C,/mem.bit */
940 check( 0 ); /* untested */
941 c |= ~MEM_BIT();
942 pc += 2;
943 goto loop;
944
945 case 0x8A: /* EOR1 C,mem.bit */
946 c ^= MEM_BIT();
947 pc += 2;
948 goto loop;
949
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;
957 }
958
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;
967 }
968
969 case 0xAA: /* MOV1 C,mem.bit */
970 c = MEM_BIT();
971 pc += 2;
972 goto loop;
973
974/* 16. PROGRAM STATUS FLAG OPERATION COMMANDS */
975
976 case 0x60: /* CLRC */
977 c = 0;
978 goto loop;
979
980 case 0x80: /* SETC */
981 c = ~0;
982 goto loop;
983
984 case 0xED: /* NOTC */
985 c ^= 0x100;
986 goto loop;
987
988 case 0xE0: /* CLRV */
989 status &= ~(st_v | st_h);
990 goto loop;
991
992 case 0x20: /* CLRP */
993 dp = 0;
994 goto loop;
995
996 case 0x40: /* SETP */
997 dp = 0x100;
998 goto loop;
999
1000 case 0xA0: /* EI */
1001 check( 0 ); /* untested */
1002 status |= st_i;
1003 goto loop;
1004
1005 case 0xC0: /* DI */
1006 check( 0 ); /* untested */
1007 status &= ~st_i;
1008 goto loop;
1009
1010/* 17. OTHER COMMANDS */
1011
1012 case 0x00: /* NOP */
1013 goto loop;
1014
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 */
1021
1022 /* unhandled instructions fall out of switch so emulator can catch them */
1023
1024out_of_time:
1025 /* undo partial execution of opcode */
1026 spc_time_ -= this->cycle_table [*--pc];
1027 {
1028 int temp;
1029 CALC_STATUS( temp );
1030 this->r.status = (uint8_t) temp;
1031 }
1032
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;
1038
1039#if 0
1040 EXIT_TIMER(cpu);
1041#endif
1042 return spc_time_;
1043}
1044
1045void CPU_Init( THIS )
1046{
1047 ci->memcpy( this->cycle_table, cycle_table, sizeof cycle_table );
1048}
1049