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