LMMS
Loading...
Searching...
No Matches
Spc_Cpu.h
Go to the documentation of this file.
1// Game_Music_Emu https://bitbucket.org/mpyne/game-music-emu/
2
3/* Copyright (C) 2004-2007 Shay Green. This module is free software; you
4can redistribute it and/or modify it under the terms of the GNU Lesser
5General Public License as published by the Free Software Foundation; either
6version 2.1 of the License, or (at your option) any later version. This
7module is distributed in the hope that it will be useful, but WITHOUT ANY
8WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
9FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
10details. You should have received a copy of the GNU Lesser General Public
11License along with this module; if not, write to the Free Software Foundation,
12Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */
13
15
16#if SPC_MORE_ACCURACY
17 #define SUSPICIOUS_OPCODE( name ) ((void) 0)
18#else
19 #define SUSPICIOUS_OPCODE( name ) debug_printf( "SPC: suspicious opcode: " name "\n" )
20#endif
21
22#define CPU_READ( time, offset, addr )\
23 cpu_read( addr, time + offset )
24
25#define CPU_WRITE( time, offset, addr, data )\
26 cpu_write( data, addr, time + offset )
27
28#if SPC_MORE_ACCURACY
29 #define CPU_READ_TIMER( time, offset, addr, out )\
30 { out = CPU_READ( time, offset, addr ); }
31
32#else
33 // timers are by far the most common thing read from dp
34 #define CPU_READ_TIMER( time, offset, addr_, out )\
35 {\
36 rel_time_t adj_time = time + offset;\
37 int dp_addr = addr_;\
38 int ti = dp_addr - (r_t0out + 0xF0);\
39 if ( (unsigned) ti < timer_count )\
40 {\
41 Timer* t = &m.timers [ti];\
42 if ( adj_time >= t->next_time )\
43 t = run_timer_( t, adj_time );\
44 out = t->counter;\
45 t->counter = 0;\
46 }\
47 else\
48 {\
49 out = ram [dp_addr];\
50 int i = dp_addr - 0xF0;\
51 if ( (unsigned) i < 0x10 )\
52 out = cpu_read_smp_reg( i, adj_time );\
53 }\
54 }
55#endif
56
57#define TIME_ADJ( n ) (n)
58
59#define READ_TIMER( time, addr, out ) CPU_READ_TIMER( rel_time, TIME_ADJ(time), (addr), out )
60#define READ( time, addr ) CPU_READ ( rel_time, TIME_ADJ(time), (addr) )
61#define WRITE( time, addr, data ) CPU_WRITE( rel_time, TIME_ADJ(time), (addr), (data) )
62
63#define DP_ADDR( addr ) (dp + (addr))
64
65#define READ_DP_TIMER( time, addr, out ) CPU_READ_TIMER( rel_time, TIME_ADJ(time), DP_ADDR( addr ), out )
66#define READ_DP( time, addr ) READ ( time, DP_ADDR( addr ) )
67#define WRITE_DP( time, addr, data ) WRITE( time, DP_ADDR( addr ), data )
68
69#define READ_PROG16( addr ) (RAM [(addr) & 0xffff] | (RAM [((addr) + 1) & 0xffff] << 8))
70
71#define SET_PC( n ) (pc = n)
72#define GET_PC() (pc)
73#define READ_PC( pc ) (ram [pc])
74#define READ_PC16( pc ) READ_PROG16( pc )
75
76#define SET_SP( v ) (sp = v)
77#define GET_SP() ((uint8_t) (sp))
78
79#define PUSH16( data )\
80{\
81 PUSH( (data & 0xff00) >> 8 );\
82 PUSH( data & 0xff );\
83}
84
85#define PUSH( data )\
86{\
87 ram [0x100 + sp] = (uint8_t) (data);\
88 --sp;\
89}
90
91#define POP( out )\
92{\
93 ++sp;\
94 out = ram [0x100 + sp];\
95}
96
97#define MEM_BIT( rel ) CPU_mem_bit( pc, rel_time + rel )
98
100{
101 unsigned addr = READ_PC16( pc );
102 unsigned t = READ( 0, addr & 0x1FFF ) >> (addr >> 13);
103 return t << 8 & 0x100;
104}
105
107
108// Hex value in name to clarify code and bit shifting.
109// Flag stored in indicated variable during emulation
110int const n80 = 0x80; // nz
111int const v40 = 0x40; // psw
112int const p20 = 0x20; // dp
113int const b10 = 0x10; // psw
114int const h08 = 0x08; // psw
115int const i04 = 0x04; // psw
116int const z02 = 0x02; // nz
117int const c01 = 0x01; // c
118
119int const nz_neg_mask = 0x880; // either bit set indicates N flag set
120
121#define GET_PSW( out )\
122{\
123 out = psw & ~(n80 | p20 | z02 | c01);\
124 out |= c >> 8 & c01;\
125 out |= dp >> 3 & p20;\
126 out |= ((nz >> 4) | nz) & n80;\
127 if ( !(uint8_t) nz ) out |= z02;\
128}
129
130#define SET_PSW( in )\
131{\
132 psw = in;\
133 c = in << 8;\
134 dp = in << 3 & 0x100;\
135 nz = (in << 4 & 0x800) | (~in & z02);\
136}
137
139{
140 uint8_t* const ram = RAM;
141 uint8_t a = m.cpu_regs.a;
142 uint8_t x = m.cpu_regs.x;
143 uint8_t y = m.cpu_regs.y;
146 int psw;
147 int c;
148 int nz;
149 int dp;
150
151 SET_PC( m.cpu_regs.pc );
152 SET_SP( m.cpu_regs.sp );
153 SET_PSW( m.cpu_regs.psw );
154
155 goto loop;
156
157
158 // Main loop
159
160cbranch_taken_loop:
161 pc += (int8_t) ram [pc];
162inc_pc_loop:
163 pc++;
165{
166 unsigned opcode;
167 unsigned data;
168
169 check( (unsigned) a < 0x100 );
170 check( (unsigned) x < 0x100 );
171 check( (unsigned) y < 0x100 );
172
173 opcode = ram [pc];
174 if ( (rel_time += m.cycle_table [opcode]) > 0 )
175 goto out_of_time;
176
177 #ifdef SPC_CPU_OPCODE_HOOK
178 SPC_CPU_OPCODE_HOOK( GET_PC(), opcode );
179 #endif
180 /*
181 //SUB_CASE_COUNTER( 1 );
182 #define PROFILE_TIMER_LOOP( op, addr, len )\
183 if ( opcode == op )\
184 {\
185 int cond = (unsigned) ((addr) - 0xFD) < 3 &&\
186 pc [len] == 0xF0 && pc [len+1] == 0xFE - len;\
187 SUB_CASE_COUNTER( op && cond );\
188 }
189
190 PROFILE_TIMER_LOOP( 0xEC, GET_LE16( pc + 1 ), 3 );
191 PROFILE_TIMER_LOOP( 0xEB, pc [1], 2 );
192 PROFILE_TIMER_LOOP( 0xE4, pc [1], 2 );
193 */
194
195 // TODO: if PC is at end of memory, this will get wrong operand (very obscure)
196 pc++;
197 data = ram [pc];
198 switch ( opcode )
199 {
200
201// Common instructions
202
203#define BRANCH( cond )\
204{\
205 pc++;\
206 pc += (int8_t) data;\
207 if ( cond )\
208 goto loop;\
209 pc -= (int8_t) data;\
210 rel_time -= 2;\
211 goto loop;\
212}
213
214 case 0xF0: // BEQ
215 BRANCH( !(uint8_t) nz ) // 89% taken
216
217 case 0xD0: // BNE
218 BRANCH( (uint8_t) nz )
219
220 case 0x3F:{// CALL
221 int old_addr = GET_PC() + 2;
222 SET_PC( READ_PC16( pc ) );
223 PUSH16( old_addr );
224 goto loop;
225 }
226
227 case 0x6F:// RET
228 {
229 uint8_t l, h;
230 POP( l );
231 POP( h );
232 SET_PC( l | (h << 8) );
233 }
234 goto loop;
235
236 case 0xE4: // MOV a,dp
237 ++pc;
238 // 80% from timer
239 READ_DP_TIMER( 0, data, a = nz );
240 goto loop;
241
242 case 0xFA:{// MOV dp,dp
243 int temp;
244 READ_DP_TIMER( -2, data, temp );
245 data = temp + no_read_before_write ;
246 }
247 // fall through
248 case 0x8F:{// MOV dp,#imm
249 int temp = READ_PC( pc + 1 );
250 pc += 2;
251
252 #if !SPC_MORE_ACCURACY
253 {
254 int i = dp + temp;
255 ram [i] = (uint8_t) data;
256 i -= 0xF0;
257 if ( (unsigned) i < 0x10 ) // 76%
258 {
259 REGS [i] = (uint8_t) data;
260
261 // Registers other than $F2 and $F4-$F7
262 if ( i != 2 && (i < 4 || i > 7)) // 12%
263 cpu_write_smp_reg( data, rel_time, i );
264 }
265 }
266 #else
267 WRITE_DP( 0, temp, data );
268 #endif
269 goto loop;
270 }
271
272 case 0xC4: // MOV dp,a
273 ++pc;
274 #if !SPC_MORE_ACCURACY
275 {
276 int i = dp + data;
277 ram [i] = (uint8_t) a;
278 i -= 0xF0;
279 if ( (unsigned) i < 0x10 ) // 39%
280 {
281 unsigned sel = i - 2;
282 REGS [i] = (uint8_t) a;
283
284 if ( sel == 1 ) // 51% $F3
285 dsp_write( a, rel_time );
286 else if ( sel > 1 ) // 1% not $F2 or $F3
287 cpu_write_smp_reg_( a, rel_time, i );
288 }
289 }
290 #else
291 WRITE_DP( 0, data, a );
292 #endif
293 goto loop;
294
295#define CASE( n ) case n:
296
297// Define common address modes based on opcode for immediate mode. Execution
298// ends with data set to the address of the operand.
299#define ADDR_MODES_( op )\
300 CASE( op - 0x02 ) /* (X) */\
301 data = x + dp;\
302 pc--;\
303 goto end_##op;\
304 CASE( op + 0x0F ) /* (dp)+Y */\
305 data = READ_PROG16( data + dp ) + y;\
306 goto end_##op;\
307 CASE( op - 0x01 ) /* (dp+X) */\
308 data = READ_PROG16( ((uint8_t) (data + x)) + dp );\
309 goto end_##op;\
310 CASE( op + 0x0E ) /* abs+Y */\
311 data += y;\
312 goto abs_##op;\
313 CASE( op + 0x0D ) /* abs+X */\
314 data += x;\
315 CASE( op - 0x03 ) /* abs */\
316 abs_##op:\
317 data += 0x100 * READ_PC( ++pc );\
318 goto end_##op;\
319 CASE( op + 0x0C ) /* dp+X */\
320 data = (uint8_t) (data + x);
321
322#define ADDR_MODES_NO_DP( op )\
323 ADDR_MODES_( op )\
324 data += dp;\
325 end_##op:
326
327#define ADDR_MODES( op )\
328 ADDR_MODES_( op )\
329 CASE( op - 0x04 ) /* dp */\
330 data += dp;\
331 end_##op:
332
333// 1. 8-bit Data Transmission Commands. Group I
334
335 ADDR_MODES_NO_DP( 0xE8 ) // MOV A,addr
336 a = nz = READ( 0, data );
337 goto inc_pc_loop;
338
339 case 0xBF:{// MOV A,(X)+
340 int temp = x + dp;
341 x = (uint8_t) (x + 1);
342 a = nz = READ( -1, temp );
343 goto loop;
344 }
345
346 case 0xE8: // MOV A,imm
347 a = data;
348 nz = data;
349 goto inc_pc_loop;
350
351 case 0xF9: // MOV X,dp+Y
352 data = (uint8_t) (data + y);
353 case 0xF8: // MOV X,dp
354 READ_DP_TIMER( 0, data, x = nz );
355 goto inc_pc_loop;
356
357 case 0xE9: // MOV X,abs
358 data = READ_PC16( pc );
359 ++pc;
360 data = READ( 0, data );
361 case 0xCD: // MOV X,imm
362 x = data;
363 nz = data;
364 goto inc_pc_loop;
365
366 case 0xFB: // MOV Y,dp+X
367 data = (uint8_t) (data + x);
368 case 0xEB: // MOV Y,dp
369 // 70% from timer
370 pc++;
371 READ_DP_TIMER( 0, data, y = nz );
372 goto loop;
373
374 case 0xEC:{// MOV Y,abs
375 int temp = READ_PC16( pc );
376 pc += 2;
377 READ_TIMER( 0, temp, y = nz );
378 //y = nz = READ( 0, temp );
379 goto loop;
380 }
381
382 case 0x8D: // MOV Y,imm
383 y = data;
384 nz = data;
385 goto inc_pc_loop;
386
387// 2. 8-BIT DATA TRANSMISSION COMMANDS, GROUP 2
388
389 ADDR_MODES_NO_DP( 0xC8 ) // MOV addr,A
390 WRITE( 0, data, a );
391 goto inc_pc_loop;
392
393 {
394 int temp;
395 case 0xCC: // MOV abs,Y
396 temp = y;
397 goto mov_abs_temp;
398 case 0xC9: // MOV abs,X
399 temp = x;
400 mov_abs_temp:
401 WRITE( 0, READ_PC16( pc ), temp );
402 pc += 2;
403 goto loop;
404 }
405
406 case 0xD9: // MOV dp+Y,X
407 data = (uint8_t) (data + y);
408 case 0xD8: // MOV dp,X
409 WRITE( 0, data + dp, x );
410 goto inc_pc_loop;
411
412 case 0xDB: // MOV dp+X,Y
413 data = (uint8_t) (data + x);
414 case 0xCB: // MOV dp,Y
415 WRITE( 0, data + dp, y );
416 goto inc_pc_loop;
417
418// 3. 8-BIT DATA TRANSMISSIN COMMANDS, GROUP 3.
419
420 case 0x7D: // MOV A,X
421 a = x;
422 nz = x;
423 goto loop;
424
425 case 0xDD: // MOV A,Y
426 a = y;
427 nz = y;
428 goto loop;
429
430 case 0x5D: // MOV X,A
431 x = a;
432 nz = a;
433 goto loop;
434
435 case 0xFD: // MOV Y,A
436 y = a;
437 nz = a;
438 goto loop;
439
440 case 0x9D: // MOV X,SP
441 x = nz = GET_SP();
442 goto loop;
443
444 case 0xBD: // MOV SP,X
445 SET_SP( x );
446 goto loop;
447
448 //case 0xC6: // MOV (X),A (handled by MOV addr,A in group 2)
449
450 case 0xAF: // MOV (X)+,A
452 x = (uint8_t) (x + 1);
453 goto loop;
454
455// 5. 8-BIT LOGIC OPERATION COMMANDS
456
457#define LOGICAL_OP( op, func )\
458 ADDR_MODES( op ) /* addr */\
459 data = READ( 0, data );\
460 case op: /* imm */\
461 nz = a func##= data;\
462 goto inc_pc_loop;\
463 { unsigned addr;\
464 case op + 0x11: /* X,Y */\
465 data = READ_DP( -2, y );\
466 addr = x + dp;\
467 goto addr_##op;\
468 case op + 0x01: /* dp,dp */\
469 data = READ_DP( -3, data );\
470 case op + 0x10:{/*dp,imm*/\
471 uint16_t addr2 = pc + 1;\
472 pc += 2;\
473 addr = READ_PC( addr2 ) + dp;\
474 }\
475 addr_##op:\
476 nz = data func READ( -1, addr );\
477 WRITE( 0, addr, nz );\
478 goto loop;\
479 }
480
481 LOGICAL_OP( 0x28, & ); // AND
482
483 LOGICAL_OP( 0x08, | ); // OR
484
485 LOGICAL_OP( 0x48, ^ ); // EOR
486
487// 4. 8-BIT ARITHMETIC OPERATION COMMANDS
488
489 ADDR_MODES( 0x68 ) // CMP addr
490 data = READ( 0, data );
491 case 0x68: // CMP imm
492 nz = a - data;
493 c = ~nz;
494 nz &= 0xFF;
495 goto inc_pc_loop;
496
497 case 0x79: // CMP (X),(Y)
498 data = READ_DP( -2, y );
499 nz = READ_DP( -1, x ) - data;
500 c = ~nz;
501 nz &= 0xFF;
502 goto loop;
503
504 case 0x69: // CMP dp,dp
505 data = READ_DP( -3, data );
506 case 0x78: // CMP dp,imm
507 nz = READ_DP( -1, READ_PC( ++pc ) ) - data;
508 c = ~nz;
509 nz &= 0xFF;
510 goto inc_pc_loop;
511
512 case 0x3E: // CMP X,dp
513 data += dp;
514 goto cmp_x_addr;
515 case 0x1E: // CMP X,abs
516 data = READ_PC16( pc );
517 pc++;
518 cmp_x_addr:
519 data = READ( 0, data );
520 case 0xC8: // CMP X,imm
521 nz = x - data;
522 c = ~nz;
523 nz &= 0xFF;
524 goto inc_pc_loop;
525
526 case 0x7E: // CMP Y,dp
527 data += dp;
528 goto cmp_y_addr;
529 case 0x5E: // CMP Y,abs
530 data = READ_PC16( pc );
531 pc++;
532 cmp_y_addr:
533 data = READ( 0, data );
534 case 0xAD: // CMP Y,imm
535 nz = y - data;
536 c = ~nz;
537 nz &= 0xFF;
538 goto inc_pc_loop;
539
540 {
541 int addr;
542 case 0xB9: // SBC (x),(y)
543 case 0x99: // ADC (x),(y)
544 pc--; // compensate for inc later
545 data = READ_DP( -2, y );
546 addr = x + dp;
547 goto adc_addr;
548 case 0xA9: // SBC dp,dp
549 case 0x89: // ADC dp,dp
550 data = READ_DP( -3, data );
551 case 0xB8: // SBC dp,imm
552 case 0x98: // ADC dp,imm
553 addr = READ_PC( ++pc ) + dp;
554 adc_addr:
555 nz = READ( -1, addr );
556 goto adc_data;
557
558// catch ADC and SBC together, then decode later based on operand
559#undef CASE
560#define CASE( n ) case n: case (n) + 0x20:
561 ADDR_MODES( 0x88 ) // ADC/SBC addr
562 data = READ( 0, data );
563 case 0xA8: // SBC imm
564 case 0x88: // ADC imm
565 addr = -1; // A
566 nz = a;
567 adc_data: {
568 int flags;
569 if ( opcode >= 0xA0 ) // SBC
570 data ^= 0xFF;
571
572 flags = data ^ nz;
573 nz += data + (c >> 8 & 1);
574 flags ^= nz;
575
576 psw = (psw & ~(v40 | h08)) |
577 (flags >> 1 & h08) |
578 ((flags + 0x80) >> 2 & v40);
579 c = nz;
580 if ( addr < 0 )
581 {
582 a = (uint8_t) nz;
583 goto inc_pc_loop;
584 }
585 WRITE( 0, addr, /*(uint8_t)*/ nz );
586 goto inc_pc_loop;
587 }
588
589 }
590
591// 6. ADDITION & SUBTRACTION COMMANDS
592
593#define INC_DEC_REG( reg, op )\
594 nz = reg op;\
595 reg = (uint8_t) nz;\
596 goto loop;
597
598 case 0xBC: INC_DEC_REG( a, + 1 ) // INC A
599 case 0x3D: INC_DEC_REG( x, + 1 ) // INC X
600 case 0xFC: INC_DEC_REG( y, + 1 ) // INC Y
601
602 case 0x9C: INC_DEC_REG( a, - 1 ) // DEC A
603 case 0x1D: INC_DEC_REG( x, - 1 ) // DEC X
604 case 0xDC: INC_DEC_REG( y, - 1 ) // DEC Y
605
606 case 0x9B: // DEC dp+X
607 case 0xBB: // INC dp+X
608 data = (uint8_t) (data + x);
609 case 0x8B: // DEC dp
610 case 0xAB: // INC dp
611 data += dp;
612 goto inc_abs;
613 case 0x8C: // DEC abs
614 case 0xAC: // INC abs
615 data = READ_PC16( pc );
616 pc++;
617 inc_abs:
618 nz = (opcode >> 4 & 2) - 1;
619 nz += READ( -1, data );
620 WRITE( 0, data, /*(uint8_t)*/ nz );
621 goto inc_pc_loop;
622
623// 7. SHIFT, ROTATION COMMANDS
624
625 case 0x5C: // LSR A
626 c = 0;
627 case 0x7C:{// ROR A
628 nz = (c >> 1 & 0x80) | (a >> 1);
629 c = a << 8;
630 a = nz;
631 goto loop;
632 }
633
634 case 0x1C: // ASL A
635 c = 0;
636 case 0x3C:{// ROL A
637 int temp = c >> 8 & 1;
638 c = a << 1;
639 nz = c | temp;
640 a = (uint8_t) nz;
641 goto loop;
642 }
643
644 case 0x0B: // ASL dp
645 c = 0;
646 data += dp;
647 goto rol_mem;
648 case 0x1B: // ASL dp+X
649 c = 0;
650 case 0x3B: // ROL dp+X
651 data = (uint8_t) (data + x);
652 case 0x2B: // ROL dp
653 data += dp;
654 goto rol_mem;
655 case 0x0C: // ASL abs
656 c = 0;
657 case 0x2C: // ROL abs
658 data = READ_PC16( pc );
659 pc++;
660 rol_mem:
661 nz = c >> 8 & 1;
662 nz |= (c = READ( -1, data ) << 1);
663 WRITE( 0, data, /*(uint8_t)*/ nz );
664 goto inc_pc_loop;
665
666 case 0x4B: // LSR dp
667 c = 0;
668 data += dp;
669 goto ror_mem;
670 case 0x5B: // LSR dp+X
671 c = 0;
672 case 0x7B: // ROR dp+X
673 data = (uint8_t) (data + x);
674 case 0x6B: // ROR dp
675 data += dp;
676 goto ror_mem;
677 case 0x4C: // LSR abs
678 c = 0;
679 case 0x6C: // ROR abs
680 data = READ_PC16( pc );
681 pc++;
682 ror_mem: {
683 int temp = READ( -1, data );
684 nz = (c >> 1 & 0x80) | (temp >> 1);
685 c = temp << 8;
686 WRITE( 0, data, nz );
687 goto inc_pc_loop;
688 }
689
690 case 0x9F: // XCN
691 nz = a = (a >> 4) | (uint8_t) (a << 4);
692 goto loop;
693
694// 8. 16-BIT TRANSMISION COMMANDS
695
696 case 0xBA: // MOVW YA,dp
697 a = READ_DP( -2, data );
698 nz = (a & 0x7F) | (a >> 1);
699 y = READ_DP( 0, (uint8_t) (data + 1) );
700 nz |= y;
701 goto inc_pc_loop;
702
703 case 0xDA: // MOVW dp,YA
704 WRITE_DP( -1, data, a );
705 WRITE_DP( 0, (uint8_t) (data + 1), y + no_read_before_write );
706 goto inc_pc_loop;
707
708// 9. 16-BIT OPERATION COMMANDS
709
710 case 0x3A: // INCW dp
711 case 0x1A:{// DECW dp
712 int temp;
713 // low byte
714 data += dp;
715 temp = READ( -3, data );
716 temp += (opcode >> 4 & 2) - 1; // +1 for INCW, -1 for DECW
717 nz = ((temp >> 1) | temp) & 0x7F;
718 WRITE( -2, data, /*(uint8_t)*/ temp );
719
720 // high byte
721 data = (uint8_t) (data + 1) + dp;
722 temp = (uint8_t) ((temp >> 8) + READ( -1, data ));
723 nz |= temp;
724 WRITE( 0, data, temp );
725
726 goto inc_pc_loop;
727 }
728
729 case 0x7A: // ADDW YA,dp
730 case 0x9A:{// SUBW YA,dp
731 int lo = READ_DP( -2, data );
732 int hi = READ_DP( 0, (uint8_t) (data + 1) );
733 int result;
734 int flags;
735
736 if ( opcode == 0x9A ) // SUBW
737 {
738 lo = (lo ^ 0xFF) + 1;
739 hi ^= 0xFF;
740 }
741
742 lo += a;
743 result = y + hi + (lo >> 8);
744 flags = hi ^ y ^ result;
745
746 psw = (psw & ~(v40 | h08)) |
747 (flags >> 1 & h08) |
748 ((flags + 0x80) >> 2 & v40);
749 c = result;
750 a = (uint8_t) lo;
752 y = result;
753 nz = (((lo >> 1) | lo) & 0x7F) | result;
754
755 goto inc_pc_loop;
756 }
757
758 case 0x5A: { // CMPW YA,dp
759 int temp = a - READ_DP( -1, data );
760 nz = ((temp >> 1) | temp) & 0x7F;
761 temp = y + (temp >> 8);
762 temp -= READ_DP( 0, (uint8_t) (data + 1) );
763 nz |= temp;
764 c = ~temp;
765 nz &= 0xFF;
766 goto inc_pc_loop;
767 }
768
769// 10. MULTIPLICATION & DIVISON COMMANDS
770
771 case 0xCF: { // MUL YA
772 unsigned temp = y * a;
773 a = (uint8_t) temp;
774 nz = ((temp >> 1) | temp) & 0x7F;
775 y = (uint8_t) (temp >> 8);
776 nz |= y;
777 goto loop;
778 }
779
780 case 0x9E: // DIV YA,X
781 {
782 unsigned ya = y * 0x100 + a;
783
784 psw &= ~(h08 | v40);
785
786 if ( y >= x )
787 psw |= v40;
788
789 if ( (y & 15) >= (x & 15) )
790 psw |= h08;
791
792 if ( y < x * 2 )
793 {
794 a = ya / x;
795 y = ya - a * x;
796 }
797 else
798 {
799 a = 255 - (ya - x * 0x200) / (256 - x);
800 y = x + (ya - x * 0x200) % (256 - x);
801 }
802
803 nz = (uint8_t) a;
804 a = (uint8_t) a;
805 y = (uint8_t) y;
806
807 goto loop;
808 }
809
810// 11. DECIMAL COMPENSATION COMMANDS
811
812 case 0xDF: // DAA
813 SUSPICIOUS_OPCODE( "DAA" );
814 if ( a > 0x99 || c & 0x100 )
815 {
816 a += 0x60;
817 c = 0x100;
818 }
819
820 if ( (a & 0x0F) > 9 || psw & h08 )
821 a += 0x06;
822
823 nz = a;
824 a = (uint8_t) a;
825 goto loop;
826
827 case 0xBE: // DAS
828 SUSPICIOUS_OPCODE( "DAS" );
829 if ( a > 0x99 || !(c & 0x100) )
830 {
831 a -= 0x60;
832 c = 0;
833 }
834
835 if ( (a & 0x0F) > 9 || !(psw & h08) )
836 a -= 0x06;
837
838 nz = a;
839 a = (uint8_t) a;
840 goto loop;
841
842// 12. BRANCHING COMMANDS
843
844 case 0x2F: // BRA rel
845 pc += (int8_t) data;
846 goto inc_pc_loop;
847
848 case 0x30: // BMI
849 BRANCH( (nz & nz_neg_mask) )
850
851 case 0x10: // BPL
852 BRANCH( !(nz & nz_neg_mask) )
853
854 case 0xB0: // BCS
855 BRANCH( c & 0x100 )
856
857 case 0x90: // BCC
858 BRANCH( !(c & 0x100) )
859
860 case 0x70: // BVS
861 BRANCH( psw & v40 )
862
863 case 0x50: // BVC
864 BRANCH( !(psw & v40) )
865
866 #define CBRANCH( cond )\
867 {\
868 pc++;\
869 if ( cond )\
870 goto cbranch_taken_loop;\
871 rel_time -= 2;\
872 goto inc_pc_loop;\
873 }
874
875 case 0x03: // BBS dp.bit,rel
876 case 0x23:
877 case 0x43:
878 case 0x63:
879 case 0x83:
880 case 0xA3:
881 case 0xC3:
882 case 0xE3:
883 CBRANCH( READ_DP( -4, data ) >> (opcode >> 5) & 1 )
884
885 case 0x13: // BBC dp.bit,rel
886 case 0x33:
887 case 0x53:
888 case 0x73:
889 case 0x93:
890 case 0xB3:
891 case 0xD3:
892 case 0xF3:
893 CBRANCH( !(READ_DP( -4, data ) >> (opcode >> 5) & 1) )
894
895 case 0xDE: // CBNE dp+X,rel
896 data = (uint8_t) (data + x);
897 // fall through
898 case 0x2E:{// CBNE dp,rel
899 int temp;
900 // 61% from timer
901 READ_DP_TIMER( -4, data, temp );
902 CBRANCH( temp != a )
903 }
904
905 case 0x6E: { // DBNZ dp,rel
906 unsigned temp = READ_DP( -4, data ) - 1;
907 WRITE_DP( -3, (uint8_t) data, /*(uint8_t)*/ temp + no_read_before_write );
908 CBRANCH( temp )
909 }
910
911 case 0xFE: // DBNZ Y,rel
912 y = (uint8_t) (y - 1);
913 BRANCH( y )
914
915 case 0x1F: // JMP [abs+X]
916 SET_PC( READ_PC16( pc ) + x );
917 // fall through
918 case 0x5F: // JMP abs
919 SET_PC( READ_PC16( pc ) );
920 goto loop;
921
922// 13. SUB-ROUTINE CALL RETURN COMMANDS
923
924 case 0x0F:{// BRK
925 int temp;
926 int ret_addr = GET_PC();
927 SUSPICIOUS_OPCODE( "BRK" );
928 SET_PC( READ_PROG16( 0xFFDE ) ); // vector address verified
929 PUSH16( ret_addr );
930 GET_PSW( temp );
931 psw = (psw | b10) & ~i04;
932 PUSH( temp );
933 goto loop;
934 }
935
936 case 0x4F:{// PCALL offset
937 int ret_addr = GET_PC() + 1;
938 SET_PC( 0xFF00 | data );
939 PUSH16( ret_addr );
940 goto loop;
941 }
942
943 case 0x01: // TCALL n
944 case 0x11:
945 case 0x21:
946 case 0x31:
947 case 0x41:
948 case 0x51:
949 case 0x61:
950 case 0x71:
951 case 0x81:
952 case 0x91:
953 case 0xA1:
954 case 0xB1:
955 case 0xC1:
956 case 0xD1:
957 case 0xE1:
958 case 0xF1: {
959 int ret_addr = GET_PC();
960 SET_PC( READ_PROG16( 0xFFDE - (opcode >> 3) ) );
961 PUSH16( ret_addr );
962 goto loop;
963 }
964
965// 14. STACK OPERATION COMMANDS
966
967 {
968 int temp;
969 uint8_t l, h;
970 case 0x7F: // RET1
971 POP (temp);
972 POP (l);
973 POP (h);
974 SET_PC( l | (h << 8) );
975 goto set_psw;
976 case 0x8E: // POP PSW
977 POP( temp );
978 set_psw:
979 SET_PSW( temp );
980 goto loop;
981 }
982
983 case 0x0D: { // PUSH PSW
984 int temp;
985 GET_PSW( temp );
986 PUSH( temp );
987 goto loop;
988 }
989
990 case 0x2D: // PUSH A
991 PUSH( a );
992 goto loop;
993
994 case 0x4D: // PUSH X
995 PUSH( x );
996 goto loop;
997
998 case 0x6D: // PUSH Y
999 PUSH( y );
1000 goto loop;
1001
1002 case 0xAE: // POP A
1003 POP( a );
1004 goto loop;
1005
1006 case 0xCE: // POP X
1007 POP( x );
1008 goto loop;
1009
1010 case 0xEE: // POP Y
1011 POP( y );
1012 goto loop;
1013
1014// 15. BIT OPERATION COMMANDS
1015
1016 case 0x02: // SET1
1017 case 0x22:
1018 case 0x42:
1019 case 0x62:
1020 case 0x82:
1021 case 0xA2:
1022 case 0xC2:
1023 case 0xE2:
1024 case 0x12: // CLR1
1025 case 0x32:
1026 case 0x52:
1027 case 0x72:
1028 case 0x92:
1029 case 0xB2:
1030 case 0xD2:
1031 case 0xF2: {
1032 int bit = 1 << (opcode >> 5);
1033 int mask = ~bit;
1034 if ( opcode & 0x10 )
1035 bit = 0;
1036 data += dp;
1037 WRITE( 0, data, (READ( -1, data ) & mask) | bit );
1038 goto inc_pc_loop;
1039 }
1040
1041 case 0x0E: // TSET1 abs
1042 case 0x4E: // TCLR1 abs
1043 data = READ_PC16( pc );
1044 pc += 2;
1045 {
1046 unsigned temp = READ( -2, data );
1047 nz = (uint8_t) (a - temp);
1048 temp &= ~a;
1049 if ( opcode == 0x0E )
1050 temp |= a;
1051 WRITE( 0, data, temp );
1052 }
1053 goto loop;
1054
1055 case 0x4A: // AND1 C,mem.bit
1056 c &= MEM_BIT( 0 );
1057 pc += 2;
1058 goto loop;
1059
1060 case 0x6A: // AND1 C,/mem.bit
1061 c &= ~MEM_BIT( 0 );
1062 pc += 2;
1063 goto loop;
1064
1065 case 0x0A: // OR1 C,mem.bit
1066 c |= MEM_BIT( -1 );
1067 pc += 2;
1068 goto loop;
1069
1070 case 0x2A: // OR1 C,/mem.bit
1071 c |= ~MEM_BIT( -1 );
1072 pc += 2;
1073 goto loop;
1074
1075 case 0x8A: // EOR1 C,mem.bit
1076 c ^= MEM_BIT( -1 );
1077 pc += 2;
1078 goto loop;
1079
1080 case 0xEA: // NOT1 mem.bit
1081 data = READ_PC16( pc );
1082 pc += 2;
1083 {
1084 unsigned temp = READ( -1, data & 0x1FFF );
1085 temp ^= 1 << (data >> 13);
1086 WRITE( 0, data & 0x1FFF, temp );
1087 }
1088 goto loop;
1089
1090 case 0xCA: // MOV1 mem.bit,C
1091 data = READ_PC16( pc );
1092 pc += 2;
1093 {
1094 unsigned temp = READ( -2, data & 0x1FFF );
1095 unsigned bit = data >> 13;
1096 temp = (temp & ~(1 << bit)) | ((c >> 8 & 1) << bit);
1097 WRITE( 0, data & 0x1FFF, temp + no_read_before_write );
1098 }
1099 goto loop;
1100
1101 case 0xAA: // MOV1 C,mem.bit
1102 c = MEM_BIT( 0 );
1103 pc += 2;
1104 goto loop;
1105
1106// 16. PROGRAM PSW FLAG OPERATION COMMANDS
1107
1108 case 0x60: // CLRC
1109 c = 0;
1110 goto loop;
1111
1112 case 0x80: // SETC
1113 c = ~0;
1114 goto loop;
1115
1116 case 0xED: // NOTC
1117 c ^= 0x100;
1118 goto loop;
1119
1120 case 0xE0: // CLRV
1121 psw &= ~(v40 | h08);
1122 goto loop;
1123
1124 case 0x20: // CLRP
1125 dp = 0;
1126 goto loop;
1127
1128 case 0x40: // SETP
1129 dp = 0x100;
1130 goto loop;
1131
1132 case 0xA0: // EI
1133 SUSPICIOUS_OPCODE( "EI" );
1134 psw |= i04;
1135 goto loop;
1136
1137 case 0xC0: // DI
1138 SUSPICIOUS_OPCODE( "DI" );
1139 psw &= ~i04;
1140 goto loop;
1141
1142// 17. OTHER COMMANDS
1143
1144 case 0x00: // NOP
1145 goto loop;
1146
1147 case 0xFF:{// STOP
1148 // handle PC wrap-around
1149 if ( pc == 0x0000 )
1150 {
1151 debug_printf( "SPC: PC wrapped around\n" );
1152 goto loop;
1153 }
1154 }
1155 // fall through
1156 case 0xEF: // SLEEP
1157 SUSPICIOUS_OPCODE( "STOP/SLEEP" );
1158 --pc;
1159 rel_time = 0;
1160 m.cpu_error = "SPC emulation error";
1161 goto stop;
1162 } // switch
1163
1164 assert( 0 ); // catch any unhandled instructions
1165}
1166out_of_time:
1167 rel_time -= m.cycle_table [ ram [pc] ]; // undo partial execution of opcode
1169
1170 // Uncache registers
1171 m.cpu_regs.pc = (uint16_t) GET_PC();
1172 m.cpu_regs.sp = ( uint8_t) GET_SP();
1173 m.cpu_regs.a = ( uint8_t) a;
1174 m.cpu_regs.x = ( uint8_t) x;
1175 m.cpu_regs.y = ( uint8_t) y;
1176 {
1177 int temp;
1178 GET_PSW( temp );
1179 m.cpu_regs.psw = (uint8_t) temp;
1180 }
1181}
#define READ(addr)
Definition Ay_Cpu.cpp:92
#define RAM
Definition Snes_Spc.cpp:22
#define REGS
Definition Snes_Spc.cpp:23
int const no_read_before_write
Definition Spc_Cpu.cpp:285
#define SPC_CPU_RUN_FUNC_END
Definition Spc_Cpu.cpp:506
#define SPC_CPU_RUN_FUNC
Definition Spc_Cpu.cpp:495
int const b10
Definition Spc_Cpu.h:113
#define READ_PC(pc)
Definition Spc_Cpu.h:73
#define POP(out)
Definition Spc_Cpu.h:91
#define SET_SP(v)
Definition Spc_Cpu.h:76
int const nz_neg_mask
Definition Spc_Cpu.h:119
int const z02
Definition Spc_Cpu.h:116
assert(0)
opcode
Definition Spc_Cpu.h:173
#define BRANCH(cond)
#define READ_DP_TIMER( time, addr, out)
Definition Spc_Cpu.h:65
#define ADDR_MODES_NO_DP(op)
#define WRITE_DP(time, addr, data)
Definition Spc_Cpu.h:67
uint8_t a
Definition Spc_Cpu.h:141
int psw
Definition Spc_Cpu.h:146
#define READ_TIMER(time, addr, out)
Definition Spc_Cpu.h:59
#define GET_PC()
Definition Spc_Cpu.h:72
int dp
Definition Spc_Cpu.h:149
#define CBRANCH(cond)
#define MEM_BIT(rel)
Definition Spc_Cpu.h:97
int const v40
Definition Spc_Cpu.h:111
#define GET_SP()
Definition Spc_Cpu.h:77
int const p20
Definition Spc_Cpu.h:112
#define ADDR_MODES(op)
#define SET_PSW(in)
Definition Spc_Cpu.h:130
#define INC_DEC_REG(reg, op)
#define READ_DP( time, addr)
Definition Spc_Cpu.h:66
#define PUSH(data)
Definition Spc_Cpu.h:85
uint8_t sp
Definition Spc_Cpu.h:145
int const c01
Definition Spc_Cpu.h:117
#define READ_PC16(pc)
Definition Spc_Cpu.h:74
#define GET_PSW(out)
Definition Spc_Cpu.h:121
#define LOGICAL_OP(op, func)
#define SET_PC(n)
Definition Spc_Cpu.h:71
#define SUSPICIOUS_OPCODE(name)
Definition Spc_Cpu.h:19
#define READ( time, addr)
Definition Spc_Cpu.h:60
int nz
Definition Spc_Cpu.h:148
check((unsigned) a< 0x100)
uint16_t pc
Definition Spc_Cpu.h:144
#define READ_PROG16(addr)
Definition Spc_Cpu.h:69
#define WRITE(time, addr, data)
Definition Spc_Cpu.h:61
int const n80
Definition Spc_Cpu.h:110
int const i04
Definition Spc_Cpu.h:115
#define PUSH16(data)
Definition Spc_Cpu.h:79
int const h08
Definition Spc_Cpu.h:114
goto loop
Definition Spc_Cpu.h:155
static const unsigned long mask[]
Definition bitwise.c:31
#define debug_printf
Definition blargg_source.h:26
int * l
Definition inflate.c:1579
unsigned * m
Definition inflate.c:1559
struct huft * t
Definition inflate.c:943
int y
Definition inflate.c:1588
register unsigned i
Definition inflate.c:1575
unsigned x[BMAX+1]
Definition inflate.c:1586
virtual ASIOError stop()=0
JSAMPIMAGE data
Definition jpeglib.h:945
unsigned short uint16_t
Definition mid.cpp:99
unsigned char uint8_t
Definition mid.cpp:98
signed char int8_t
Definition mid.cpp:95
BLARGG_DISABLE_NOTHROW typedef int rel_time_t
Definition Snes_Spc.h:129
unsigned CPU_mem_bit(uint16_t pc, rel_time_t)
Definition Spc_Cpu.h:99
return c
Definition crypt.c:175
uch h[RAND_HEAD_LEN]
Definition crypt.c:459
int result
Definition process.c:1455