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