diff snes_spc/SPC_CPU.h @ 0:e38dacceb958

initial import
author Robert McIntyre <rlm@mit.edu>
date Fri, 21 Oct 2011 05:53:11 -0700
parents
children
line wrap: on
line diff
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/snes_spc/SPC_CPU.h	Fri Oct 21 05:53:11 2011 -0700
     1.3 @@ -0,0 +1,1220 @@
     1.4 +// snes_spc 0.9.0. http://www.slack.net/~ant/
     1.5 +
     1.6 +/* Copyright (C) 2004-2007 Shay Green. This module is free software; you
     1.7 +can redistribute it and/or modify it under the terms of the GNU Lesser
     1.8 +General Public License as published by the Free Software Foundation; either
     1.9 +version 2.1 of the License, or (at your option) any later version. This
    1.10 +module is distributed in the hope that it will be useful, but WITHOUT ANY
    1.11 +WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
    1.12 +FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
    1.13 +details. You should have received a copy of the GNU Lesser General Public
    1.14 +License along with this module; if not, write to the Free Software Foundation,
    1.15 +Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */
    1.16 +
    1.17 +//// Memory access
    1.18 +
    1.19 +#if SPC_MORE_ACCURACY
    1.20 +	#define SUSPICIOUS_OPCODE( name ) ((void) 0)
    1.21 +#else
    1.22 +	#define SUSPICIOUS_OPCODE( name ) dprintf( "SPC: suspicious opcode: " name "\n" )
    1.23 +#endif
    1.24 +
    1.25 +#define CPU_READ( time, offset, addr )\
    1.26 +	cpu_read( addr, time + offset )
    1.27 +
    1.28 +#define CPU_WRITE( time, offset, addr, data )\
    1.29 +	cpu_write( data, addr, time + offset )
    1.30 +
    1.31 +#if SPC_MORE_ACCURACY
    1.32 +	#define CPU_READ_TIMER( time, offset, addr, out )\
    1.33 +		{ out = CPU_READ( time, offset, addr ); }
    1.34 +
    1.35 +#else
    1.36 +	// timers are by far the most common thing read from dp
    1.37 +	#define CPU_READ_TIMER( time, offset, addr_, out )\
    1.38 +	{\
    1.39 +		rel_time_t adj_time = time + offset;\
    1.40 +		int dp_addr = addr_;\
    1.41 +		int ti = dp_addr - (r_t0out + 0xF0);\
    1.42 +		if ( (unsigned) ti < timer_count )\
    1.43 +		{\
    1.44 +			Timer* t = &m.timers [ti];\
    1.45 +			if ( adj_time >= t->next_time )\
    1.46 +				t = run_timer_( t, adj_time );\
    1.47 +			out = t->counter;\
    1.48 +			t->counter = 0;\
    1.49 +		}\
    1.50 +		else\
    1.51 +		{\
    1.52 +			out = ram [dp_addr];\
    1.53 +			int i = dp_addr - 0xF0;\
    1.54 +			if ( (unsigned) i < 0x10 )\
    1.55 +				out = cpu_read_smp_reg( i, adj_time );\
    1.56 +		}\
    1.57 +	}
    1.58 +#endif
    1.59 +
    1.60 +#define TIME_ADJ( n )   (n)
    1.61 +
    1.62 +#define READ_TIMER( time, addr, out )       CPU_READ_TIMER( rel_time, TIME_ADJ(time), (addr), out )
    1.63 +#define READ(  time, addr )                 CPU_READ ( rel_time, TIME_ADJ(time), (addr) )
    1.64 +#define WRITE( time, addr, data )           CPU_WRITE( rel_time, TIME_ADJ(time), (addr), (data) )
    1.65 +
    1.66 +#define DP_ADDR( addr )                     (dp + (addr))
    1.67 +
    1.68 +#define READ_DP_TIMER(  time, addr, out )   CPU_READ_TIMER( rel_time, TIME_ADJ(time), DP_ADDR( addr ), out )
    1.69 +#define READ_DP(  time, addr )              READ ( time, DP_ADDR( addr ) )
    1.70 +#define WRITE_DP( time, addr, data )        WRITE( time, DP_ADDR( addr ), data )
    1.71 +
    1.72 +#define READ_PROG16( addr )                 GET_LE16( ram + (addr) )
    1.73 +
    1.74 +#define SET_PC( n )     (pc = ram + (n))
    1.75 +#define GET_PC()        (pc - ram)
    1.76 +#define READ_PC( pc )   (*(pc))
    1.77 +#define READ_PC16( pc ) GET_LE16( pc )
    1.78 +
    1.79 +// TODO: remove non-wrapping versions?
    1.80 +#define SPC_NO_SP_WRAPAROUND 0
    1.81 +
    1.82 +#define SET_SP( v )     (sp = ram + 0x101 + (v))
    1.83 +#define GET_SP()        (sp - 0x101 - ram)
    1.84 +
    1.85 +#if SPC_NO_SP_WRAPAROUND
    1.86 +#define PUSH16( v )     (sp -= 2, SET_LE16( sp, v ))
    1.87 +#define PUSH( v )       (void) (*--sp = (uint8_t) (v))
    1.88 +#define POP( out )      (void) ((out) = *sp++)
    1.89 +
    1.90 +#else
    1.91 +#define PUSH16( data )\
    1.92 +{\
    1.93 +	int addr = (sp -= 2) - ram;\
    1.94 +	if ( addr > 0x100 )\
    1.95 +	{\
    1.96 +		SET_LE16( sp, data );\
    1.97 +	}\
    1.98 +	else\
    1.99 +	{\
   1.100 +		ram [(uint8_t) addr + 0x100] = (uint8_t) data;\
   1.101 +		sp [1] = (uint8_t) (data >> 8);\
   1.102 +		sp += 0x100;\
   1.103 +	}\
   1.104 +}
   1.105 +
   1.106 +#define PUSH( data )\
   1.107 +{\
   1.108 +	*--sp = (uint8_t) (data);\
   1.109 +	if ( sp - ram == 0x100 )\
   1.110 +		sp += 0x100;\
   1.111 +}
   1.112 +
   1.113 +#define POP( out )\
   1.114 +{\
   1.115 +	out = *sp++;\
   1.116 +	if ( sp - ram == 0x201 )\
   1.117 +	{\
   1.118 +		out = sp [-0x101];\
   1.119 +		sp -= 0x100;\
   1.120 +	}\
   1.121 +}
   1.122 +
   1.123 +#endif
   1.124 +
   1.125 +#define MEM_BIT( rel ) CPU_mem_bit( pc, rel_time + rel )
   1.126 +
   1.127 +unsigned SNES_SPC::CPU_mem_bit( uint8_t const* pc, rel_time_t rel_time )
   1.128 +{
   1.129 +	unsigned addr = READ_PC16( pc );
   1.130 +	unsigned t = READ( 0, addr & 0x1FFF ) >> (addr >> 13);
   1.131 +	return t << 8 & 0x100;
   1.132 +}
   1.133 +
   1.134 +//// Status flag handling
   1.135 +
   1.136 +// Hex value in name to clarify code and bit shifting.
   1.137 +// Flag stored in indicated variable during emulation
   1.138 +int const n80 = 0x80; // nz
   1.139 +int const v40 = 0x40; // psw
   1.140 +int const p20 = 0x20; // dp
   1.141 +int const b10 = 0x10; // psw
   1.142 +int const h08 = 0x08; // psw
   1.143 +int const i04 = 0x04; // psw
   1.144 +int const z02 = 0x02; // nz
   1.145 +int const c01 = 0x01; // c
   1.146 +
   1.147 +int const nz_neg_mask = 0x880; // either bit set indicates N flag set
   1.148 +
   1.149 +#define GET_PSW( out )\
   1.150 +{\
   1.151 +	out = psw & ~(n80 | p20 | z02 | c01);\
   1.152 +	out |= c  >> 8 & c01;\
   1.153 +	out |= dp >> 3 & p20;\
   1.154 +	out |= ((nz >> 4) | nz) & n80;\
   1.155 +	if ( !(uint8_t) nz ) out |= z02;\
   1.156 +}
   1.157 +
   1.158 +#define SET_PSW( in )\
   1.159 +{\
   1.160 +	psw = in;\
   1.161 +	c   = in << 8;\
   1.162 +	dp  = in << 3 & 0x100;\
   1.163 +	nz  = (in << 4 & 0x800) | (~in & z02);\
   1.164 +}
   1.165 +
   1.166 +SPC_CPU_RUN_FUNC
   1.167 +{
   1.168 +	uint8_t* const ram = RAM;
   1.169 +	int a = m.cpu_regs.a;
   1.170 +	int x = m.cpu_regs.x;
   1.171 +	int y = m.cpu_regs.y;
   1.172 +	uint8_t const* pc;
   1.173 +	uint8_t* sp;
   1.174 +	int psw;
   1.175 +	int c;
   1.176 +	int nz;
   1.177 +	int dp;
   1.178 +	
   1.179 +	SET_PC( m.cpu_regs.pc );
   1.180 +	SET_SP( m.cpu_regs.sp );
   1.181 +	SET_PSW( m.cpu_regs.psw );
   1.182 +	
   1.183 +	goto loop;
   1.184 +	
   1.185 +	
   1.186 +	// Main loop
   1.187 +	
   1.188 +cbranch_taken_loop:
   1.189 +	pc += *(BOOST::int8_t const*) pc;
   1.190 +inc_pc_loop:
   1.191 +	pc++;
   1.192 +loop:
   1.193 +{
   1.194 +	unsigned opcode;
   1.195 +	unsigned data;
   1.196 +	
   1.197 +	check( (unsigned) a < 0x100 );
   1.198 +	check( (unsigned) x < 0x100 );
   1.199 +	check( (unsigned) y < 0x100 );
   1.200 +	
   1.201 +	opcode = *pc;
   1.202 +	if ( (rel_time += m.cycle_table [opcode]) > 0 )
   1.203 +		goto out_of_time;
   1.204 +	
   1.205 +	#ifdef SPC_CPU_OPCODE_HOOK
   1.206 +		SPC_CPU_OPCODE_HOOK( GET_PC(), opcode );
   1.207 +	#endif
   1.208 +	/*
   1.209 +	//SUB_CASE_COUNTER( 1 );
   1.210 +	#define PROFILE_TIMER_LOOP( op, addr, len )\
   1.211 +	if ( opcode == op )\
   1.212 +	{\
   1.213 +		int cond = (unsigned) ((addr) - 0xFD) < 3 &&\
   1.214 +				pc [len] == 0xF0 && pc [len+1] == 0xFE - len;\
   1.215 +		SUB_CASE_COUNTER( op && cond );\
   1.216 +	}
   1.217 +	
   1.218 +	PROFILE_TIMER_LOOP( 0xEC, GET_LE16( pc + 1 ), 3 );
   1.219 +	PROFILE_TIMER_LOOP( 0xEB, pc [1], 2 );
   1.220 +	PROFILE_TIMER_LOOP( 0xE4, pc [1], 2 );
   1.221 +	*/
   1.222 +	
   1.223 +	// TODO: if PC is at end of memory, this will get wrong operand (very obscure)
   1.224 +	data = *++pc;
   1.225 +	switch ( opcode )
   1.226 +	{
   1.227 +	
   1.228 +// Common instructions
   1.229 +
   1.230 +#define BRANCH( cond )\
   1.231 +{\
   1.232 +	pc++;\
   1.233 +	pc += (BOOST::int8_t) data;\
   1.234 +	if ( cond )\
   1.235 +		goto loop;\
   1.236 +	pc -= (BOOST::int8_t) data;\
   1.237 +	rel_time -= 2;\
   1.238 +	goto loop;\
   1.239 +}
   1.240 +
   1.241 +	case 0xF0: // BEQ
   1.242 +		BRANCH( !(uint8_t) nz ) // 89% taken
   1.243 +	
   1.244 +	case 0xD0: // BNE
   1.245 +		BRANCH( (uint8_t) nz )
   1.246 +	
   1.247 +	case 0x3F:{// CALL
   1.248 +		int old_addr = GET_PC() + 2;
   1.249 +		SET_PC( READ_PC16( pc ) );
   1.250 +		PUSH16( old_addr );
   1.251 +		goto loop;
   1.252 +	}
   1.253 +	
   1.254 +	case 0x6F:// RET
   1.255 +		#if SPC_NO_SP_WRAPAROUND
   1.256 +		{
   1.257 +			SET_PC( GET_LE16( sp ) );
   1.258 +			sp += 2;
   1.259 +		}
   1.260 +		#else
   1.261 +		{
   1.262 +			int addr = sp - ram;
   1.263 +			SET_PC( GET_LE16( sp ) );
   1.264 +			sp += 2;
   1.265 +			if ( addr < 0x1FF )
   1.266 +				goto loop;
   1.267 +			
   1.268 +			SET_PC( sp [-0x101] * 0x100 + ram [(uint8_t) addr + 0x100] );
   1.269 +			sp -= 0x100;
   1.270 +		}
   1.271 +		#endif
   1.272 +		goto loop;
   1.273 +	
   1.274 +	case 0xE4: // MOV a,dp
   1.275 +		++pc;
   1.276 +		// 80% from timer
   1.277 +		READ_DP_TIMER( 0, data, a = nz );
   1.278 +		goto loop;
   1.279 +	
   1.280 +	case 0xFA:{// MOV dp,dp
   1.281 +		int temp;
   1.282 +		READ_DP_TIMER( -2, data, temp );
   1.283 +		data = temp + no_read_before_write ;
   1.284 +	}
   1.285 +	// fall through
   1.286 +	case 0x8F:{// MOV dp,#imm
   1.287 +		int temp = READ_PC( pc + 1 );
   1.288 +		pc += 2;
   1.289 +		
   1.290 +		#if !SPC_MORE_ACCURACY
   1.291 +		{
   1.292 +			int i = dp + temp;
   1.293 +			ram [i] = (uint8_t) data;
   1.294 +			i -= 0xF0;
   1.295 +			if ( (unsigned) i < 0x10 ) // 76%
   1.296 +			{
   1.297 +				REGS [i] = (uint8_t) data;
   1.298 +				
   1.299 +				// Registers other than $F2 and $F4-$F7
   1.300 +				//if ( i != 2 && i != 4 && i != 5 && i != 6 && i != 7 )
   1.301 +				if ( ((~0x2F00 << (bits_in_int - 16)) << i) < 0 ) // 12%
   1.302 +					cpu_write_smp_reg( data, rel_time, i );
   1.303 +			}
   1.304 +		}
   1.305 +		#else
   1.306 +			WRITE_DP( 0, temp, data );
   1.307 +		#endif
   1.308 +		goto loop;
   1.309 +	}
   1.310 +	
   1.311 +	case 0xC4: // MOV dp,a
   1.312 +		++pc;
   1.313 +		#if !SPC_MORE_ACCURACY
   1.314 +		{
   1.315 +			int i = dp + data;
   1.316 +			ram [i] = (uint8_t) a;
   1.317 +			i -= 0xF0;
   1.318 +			if ( (unsigned) i < 0x10 ) // 39%
   1.319 +			{
   1.320 +				unsigned sel = i - 2;
   1.321 +				REGS [i] = (uint8_t) a;
   1.322 +				
   1.323 +				if ( sel == 1 ) // 51% $F3
   1.324 +					dsp_write( a, rel_time );
   1.325 +				else if ( sel > 1 ) // 1% not $F2 or $F3
   1.326 +					cpu_write_smp_reg_( a, rel_time, i );
   1.327 +			}
   1.328 +		}
   1.329 +		#else
   1.330 +			WRITE_DP( 0, data, a );
   1.331 +		#endif
   1.332 +		goto loop;
   1.333 +	
   1.334 +#define CASE( n )   case n:
   1.335 +
   1.336 +// Define common address modes based on opcode for immediate mode. Execution
   1.337 +// ends with data set to the address of the operand.
   1.338 +#define ADDR_MODES_( op )\
   1.339 +	CASE( op - 0x02 ) /* (X) */\
   1.340 +		data = x + dp;\
   1.341 +		pc--;\
   1.342 +		goto end_##op;\
   1.343 +	CASE( op + 0x0F ) /* (dp)+Y */\
   1.344 +		data = READ_PROG16( data + dp ) + y;\
   1.345 +		goto end_##op;\
   1.346 +	CASE( op - 0x01 ) /* (dp+X) */\
   1.347 +		data = READ_PROG16( ((uint8_t) (data + x)) + dp );\
   1.348 +		goto end_##op;\
   1.349 +	CASE( op + 0x0E ) /* abs+Y */\
   1.350 +		data += y;\
   1.351 +		goto abs_##op;\
   1.352 +	CASE( op + 0x0D ) /* abs+X */\
   1.353 +		data += x;\
   1.354 +	CASE( op - 0x03 ) /* abs */\
   1.355 +	abs_##op:\
   1.356 +		data += 0x100 * READ_PC( ++pc );\
   1.357 +		goto end_##op;\
   1.358 +	CASE( op + 0x0C ) /* dp+X */\
   1.359 +		data = (uint8_t) (data + x);
   1.360 +
   1.361 +#define ADDR_MODES_NO_DP( op )\
   1.362 +	ADDR_MODES_( op )\
   1.363 +		data += dp;\
   1.364 +	end_##op:
   1.365 +
   1.366 +#define ADDR_MODES( op )\
   1.367 +	ADDR_MODES_( op )\
   1.368 +	CASE( op - 0x04 ) /* dp */\
   1.369 +		data += dp;\
   1.370 +	end_##op:
   1.371 +
   1.372 +// 1. 8-bit Data Transmission Commands. Group I
   1.373 +
   1.374 +	ADDR_MODES_NO_DP( 0xE8 ) // MOV A,addr
   1.375 +		a = nz = READ( 0, data );
   1.376 +		goto inc_pc_loop;
   1.377 +	
   1.378 +	case 0xBF:{// MOV A,(X)+
   1.379 +		int temp = x + dp;
   1.380 +		x = (uint8_t) (x + 1);
   1.381 +		a = nz = READ( -1, temp );
   1.382 +		goto loop;
   1.383 +	}
   1.384 +	
   1.385 +	case 0xE8: // MOV A,imm
   1.386 +		a  = data;
   1.387 +		nz = data;
   1.388 +		goto inc_pc_loop;
   1.389 +	
   1.390 +	case 0xF9: // MOV X,dp+Y
   1.391 +		data = (uint8_t) (data + y);
   1.392 +	case 0xF8: // MOV X,dp
   1.393 +		READ_DP_TIMER( 0, data, x = nz );
   1.394 +		goto inc_pc_loop;
   1.395 +	
   1.396 +	case 0xE9: // MOV X,abs
   1.397 +		data = READ_PC16( pc );
   1.398 +		++pc;
   1.399 +		data = READ( 0, data );
   1.400 +	case 0xCD: // MOV X,imm
   1.401 +		x  = data;
   1.402 +		nz = data;
   1.403 +		goto inc_pc_loop;
   1.404 +	
   1.405 +	case 0xFB: // MOV Y,dp+X
   1.406 +		data = (uint8_t) (data + x);
   1.407 +	case 0xEB: // MOV Y,dp
   1.408 +		// 70% from timer
   1.409 +		pc++;
   1.410 +		READ_DP_TIMER( 0, data, y = nz );
   1.411 +		goto loop;
   1.412 +	
   1.413 +	case 0xEC:{// MOV Y,abs
   1.414 +		int temp = READ_PC16( pc );
   1.415 +		pc += 2;
   1.416 +		READ_TIMER( 0, temp, y = nz );
   1.417 +		//y = nz = READ( 0, temp );
   1.418 +		goto loop;
   1.419 +	}
   1.420 +	
   1.421 +	case 0x8D: // MOV Y,imm
   1.422 +		y  = data;
   1.423 +		nz = data;
   1.424 +		goto inc_pc_loop;
   1.425 +	
   1.426 +// 2. 8-BIT DATA TRANSMISSION COMMANDS, GROUP 2
   1.427 +
   1.428 +	ADDR_MODES_NO_DP( 0xC8 ) // MOV addr,A
   1.429 +		WRITE( 0, data, a );
   1.430 +		goto inc_pc_loop;
   1.431 +	
   1.432 +	{
   1.433 +		int temp;
   1.434 +	case 0xCC: // MOV abs,Y
   1.435 +		temp = y;
   1.436 +		goto mov_abs_temp;
   1.437 +	case 0xC9: // MOV abs,X
   1.438 +		temp = x;
   1.439 +	mov_abs_temp:
   1.440 +		WRITE( 0, READ_PC16( pc ), temp );
   1.441 +		pc += 2;
   1.442 +		goto loop;
   1.443 +	}
   1.444 +	
   1.445 +	case 0xD9: // MOV dp+Y,X
   1.446 +		data = (uint8_t) (data + y);
   1.447 +	case 0xD8: // MOV dp,X
   1.448 +		WRITE( 0, data + dp, x );
   1.449 +		goto inc_pc_loop;
   1.450 +	
   1.451 +	case 0xDB: // MOV dp+X,Y
   1.452 +		data = (uint8_t) (data + x);
   1.453 +	case 0xCB: // MOV dp,Y
   1.454 +		WRITE( 0, data + dp, y );
   1.455 +		goto inc_pc_loop;
   1.456 +
   1.457 +// 3. 8-BIT DATA TRANSMISSIN COMMANDS, GROUP 3.
   1.458 +	
   1.459 +	case 0x7D: // MOV A,X
   1.460 +		a  = x;
   1.461 +		nz = x;
   1.462 +		goto loop;
   1.463 +	
   1.464 +	case 0xDD: // MOV A,Y
   1.465 +		a  = y;
   1.466 +		nz = y;
   1.467 +		goto loop;
   1.468 +	
   1.469 +	case 0x5D: // MOV X,A
   1.470 +		x  = a;
   1.471 +		nz = a;
   1.472 +		goto loop;
   1.473 +	
   1.474 +	case 0xFD: // MOV Y,A
   1.475 +		y  = a;
   1.476 +		nz = a;
   1.477 +		goto loop;
   1.478 +	
   1.479 +	case 0x9D: // MOV X,SP
   1.480 +		x = nz = GET_SP();
   1.481 +		goto loop;
   1.482 +	
   1.483 +	case 0xBD: // MOV SP,X
   1.484 +		SET_SP( x );
   1.485 +		goto loop;
   1.486 +	
   1.487 +	//case 0xC6: // MOV (X),A (handled by MOV addr,A in group 2)
   1.488 +	
   1.489 +	case 0xAF: // MOV (X)+,A
   1.490 +		WRITE_DP( 0, x, a + no_read_before_write  );
   1.491 +		x++;
   1.492 +		goto loop;
   1.493 +	
   1.494 +// 5. 8-BIT LOGIC OPERATION COMMANDS
   1.495 +	
   1.496 +#define LOGICAL_OP( op, func )\
   1.497 +	ADDR_MODES( op ) /* addr */\
   1.498 +		data = READ( 0, data );\
   1.499 +	case op: /* imm */\
   1.500 +		nz = a func##= data;\
   1.501 +		goto inc_pc_loop;\
   1.502 +	{   unsigned addr;\
   1.503 +	case op + 0x11: /* X,Y */\
   1.504 +		data = READ_DP( -2, y );\
   1.505 +		addr = x + dp;\
   1.506 +		goto addr_##op;\
   1.507 +	case op + 0x01: /* dp,dp */\
   1.508 +		data = READ_DP( -3, data );\
   1.509 +	case op + 0x10:{/*dp,imm*/\
   1.510 +		uint8_t const* addr2 = pc + 1;\
   1.511 +		pc += 2;\
   1.512 +		addr = READ_PC( addr2 ) + dp;\
   1.513 +	}\
   1.514 +	addr_##op:\
   1.515 +		nz = data func READ( -1, addr );\
   1.516 +		WRITE( 0, addr, nz );\
   1.517 +		goto loop;\
   1.518 +	}
   1.519 +	
   1.520 +	LOGICAL_OP( 0x28, & ); // AND
   1.521 +	
   1.522 +	LOGICAL_OP( 0x08, | ); // OR
   1.523 +	
   1.524 +	LOGICAL_OP( 0x48, ^ ); // EOR
   1.525 +	
   1.526 +// 4. 8-BIT ARITHMETIC OPERATION COMMANDS
   1.527 +
   1.528 +	ADDR_MODES( 0x68 ) // CMP addr
   1.529 +		data = READ( 0, data );
   1.530 +	case 0x68: // CMP imm
   1.531 +		nz = a - data;
   1.532 +		c = ~nz;
   1.533 +		nz &= 0xFF;
   1.534 +		goto inc_pc_loop;
   1.535 +	
   1.536 +	case 0x79: // CMP (X),(Y)
   1.537 +		data = READ_DP( -2, y );
   1.538 +		nz = READ_DP( -1, x ) - data;
   1.539 +		c = ~nz;
   1.540 +		nz &= 0xFF;
   1.541 +		goto loop;
   1.542 +	
   1.543 +	case 0x69: // CMP dp,dp
   1.544 +		data = READ_DP( -3, data );
   1.545 +	case 0x78: // CMP dp,imm
   1.546 +		nz = READ_DP( -1, READ_PC( ++pc ) ) - data;
   1.547 +		c = ~nz;
   1.548 +		nz &= 0xFF;
   1.549 +		goto inc_pc_loop;
   1.550 +	
   1.551 +	case 0x3E: // CMP X,dp
   1.552 +		data += dp;
   1.553 +		goto cmp_x_addr;
   1.554 +	case 0x1E: // CMP X,abs
   1.555 +		data = READ_PC16( pc );
   1.556 +		pc++;
   1.557 +	cmp_x_addr:
   1.558 +		data = READ( 0, data );
   1.559 +	case 0xC8: // CMP X,imm
   1.560 +		nz = x - data;
   1.561 +		c = ~nz;
   1.562 +		nz &= 0xFF;
   1.563 +		goto inc_pc_loop;
   1.564 +	
   1.565 +	case 0x7E: // CMP Y,dp
   1.566 +		data += dp;
   1.567 +		goto cmp_y_addr;
   1.568 +	case 0x5E: // CMP Y,abs
   1.569 +		data = READ_PC16( pc );
   1.570 +		pc++;
   1.571 +	cmp_y_addr:
   1.572 +		data = READ( 0, data );
   1.573 +	case 0xAD: // CMP Y,imm
   1.574 +		nz = y - data;
   1.575 +		c = ~nz;
   1.576 +		nz &= 0xFF;
   1.577 +		goto inc_pc_loop;
   1.578 +	
   1.579 +	{
   1.580 +		int addr;
   1.581 +	case 0xB9: // SBC (x),(y)
   1.582 +	case 0x99: // ADC (x),(y)
   1.583 +		pc--; // compensate for inc later
   1.584 +		data = READ_DP( -2, y );
   1.585 +		addr = x + dp;
   1.586 +		goto adc_addr;
   1.587 +	case 0xA9: // SBC dp,dp
   1.588 +	case 0x89: // ADC dp,dp
   1.589 +		data = READ_DP( -3, data );
   1.590 +	case 0xB8: // SBC dp,imm
   1.591 +	case 0x98: // ADC dp,imm
   1.592 +		addr = READ_PC( ++pc ) + dp;
   1.593 +	adc_addr:
   1.594 +		nz = READ( -1, addr );
   1.595 +		goto adc_data;
   1.596 +		
   1.597 +// catch ADC and SBC together, then decode later based on operand
   1.598 +#undef CASE
   1.599 +#define CASE( n ) case n: case (n) + 0x20:
   1.600 +	ADDR_MODES( 0x88 ) // ADC/SBC addr
   1.601 +		data = READ( 0, data );
   1.602 +	case 0xA8: // SBC imm
   1.603 +	case 0x88: // ADC imm
   1.604 +		addr = -1; // A
   1.605 +		nz = a;
   1.606 +	adc_data: {
   1.607 +		int flags;
   1.608 +		if ( opcode >= 0xA0 ) // SBC
   1.609 +			data ^= 0xFF;
   1.610 +		
   1.611 +		flags = data ^ nz;
   1.612 +		nz += data + (c >> 8 & 1);
   1.613 +		flags ^= nz;
   1.614 +		
   1.615 +		psw = (psw & ~(v40 | h08)) |
   1.616 +				(flags >> 1 & h08) |
   1.617 +				((flags + 0x80) >> 2 & v40);
   1.618 +		c = nz;
   1.619 +		if ( addr < 0 )
   1.620 +		{
   1.621 +			a = (uint8_t) nz;
   1.622 +			goto inc_pc_loop;
   1.623 +		}
   1.624 +		WRITE( 0, addr, /*(uint8_t)*/ nz );
   1.625 +		goto inc_pc_loop;
   1.626 +	}
   1.627 +	
   1.628 +	}
   1.629 +	
   1.630 +// 6. ADDITION & SUBTRACTION COMMANDS
   1.631 +
   1.632 +#define INC_DEC_REG( reg, op )\
   1.633 +		nz  = reg op;\
   1.634 +		reg = (uint8_t) nz;\
   1.635 +		goto loop;
   1.636 +
   1.637 +	case 0xBC: INC_DEC_REG( a, + 1 ) // INC A
   1.638 +	case 0x3D: INC_DEC_REG( x, + 1 ) // INC X
   1.639 +	case 0xFC: INC_DEC_REG( y, + 1 ) // INC Y
   1.640 +	
   1.641 +	case 0x9C: INC_DEC_REG( a, - 1 ) // DEC A
   1.642 +	case 0x1D: INC_DEC_REG( x, - 1 ) // DEC X
   1.643 +	case 0xDC: INC_DEC_REG( y, - 1 ) // DEC Y
   1.644 +
   1.645 +	case 0x9B: // DEC dp+X
   1.646 +	case 0xBB: // INC dp+X
   1.647 +		data = (uint8_t) (data + x);
   1.648 +	case 0x8B: // DEC dp
   1.649 +	case 0xAB: // INC dp
   1.650 +		data += dp;
   1.651 +		goto inc_abs;
   1.652 +	case 0x8C: // DEC abs
   1.653 +	case 0xAC: // INC abs
   1.654 +		data = READ_PC16( pc );
   1.655 +		pc++;
   1.656 +	inc_abs:
   1.657 +		nz = (opcode >> 4 & 2) - 1;
   1.658 +		nz += READ( -1, data );
   1.659 +		WRITE( 0, data, /*(uint8_t)*/ nz );
   1.660 +		goto inc_pc_loop;
   1.661 +	
   1.662 +// 7. SHIFT, ROTATION COMMANDS
   1.663 +
   1.664 +	case 0x5C: // LSR A
   1.665 +		c = 0;
   1.666 +	case 0x7C:{// ROR A
   1.667 +		nz = (c >> 1 & 0x80) | (a >> 1);
   1.668 +		c = a << 8;
   1.669 +		a = nz;
   1.670 +		goto loop;
   1.671 +	}
   1.672 +	
   1.673 +	case 0x1C: // ASL A
   1.674 +		c = 0;
   1.675 +	case 0x3C:{// ROL A
   1.676 +		int temp = c >> 8 & 1;
   1.677 +		c = a << 1;
   1.678 +		nz = c | temp;
   1.679 +		a = (uint8_t) nz;
   1.680 +		goto loop;
   1.681 +	}
   1.682 +	
   1.683 +	case 0x0B: // ASL dp
   1.684 +		c = 0;
   1.685 +		data += dp;
   1.686 +		goto rol_mem;
   1.687 +	case 0x1B: // ASL dp+X
   1.688 +		c = 0;
   1.689 +	case 0x3B: // ROL dp+X
   1.690 +		data = (uint8_t) (data + x);
   1.691 +	case 0x2B: // ROL dp
   1.692 +		data += dp;
   1.693 +		goto rol_mem;
   1.694 +	case 0x0C: // ASL abs
   1.695 +		c = 0;
   1.696 +	case 0x2C: // ROL abs
   1.697 +		data = READ_PC16( pc );
   1.698 +		pc++;
   1.699 +	rol_mem:
   1.700 +		nz = c >> 8 & 1;
   1.701 +		nz |= (c = READ( -1, data ) << 1);
   1.702 +		WRITE( 0, data, /*(uint8_t)*/ nz );
   1.703 +		goto inc_pc_loop;
   1.704 +	
   1.705 +	case 0x4B: // LSR dp
   1.706 +		c = 0;
   1.707 +		data += dp;
   1.708 +		goto ror_mem;
   1.709 +	case 0x5B: // LSR dp+X
   1.710 +		c = 0;
   1.711 +	case 0x7B: // ROR dp+X
   1.712 +		data = (uint8_t) (data + x);
   1.713 +	case 0x6B: // ROR dp
   1.714 +		data += dp;
   1.715 +		goto ror_mem;
   1.716 +	case 0x4C: // LSR abs
   1.717 +		c = 0;
   1.718 +	case 0x6C: // ROR abs
   1.719 +		data = READ_PC16( pc );
   1.720 +		pc++;
   1.721 +	ror_mem: {
   1.722 +		int temp = READ( -1, data );
   1.723 +		nz = (c >> 1 & 0x80) | (temp >> 1);
   1.724 +		c = temp << 8;
   1.725 +		WRITE( 0, data, nz );
   1.726 +		goto inc_pc_loop;
   1.727 +	}
   1.728 +
   1.729 +	case 0x9F: // XCN
   1.730 +		nz = a = (a >> 4) | (uint8_t) (a << 4);
   1.731 +		goto loop;
   1.732 +
   1.733 +// 8. 16-BIT TRANSMISION COMMANDS
   1.734 +
   1.735 +	case 0xBA: // MOVW YA,dp
   1.736 +		a = READ_DP( -2, data );
   1.737 +		nz = (a & 0x7F) | (a >> 1);
   1.738 +		y = READ_DP( 0, (uint8_t) (data + 1) );
   1.739 +		nz |= y;
   1.740 +		goto inc_pc_loop;
   1.741 +	
   1.742 +	case 0xDA: // MOVW dp,YA
   1.743 +		WRITE_DP( -1, data, a );
   1.744 +		WRITE_DP( 0, (uint8_t) (data + 1), y + no_read_before_write  );
   1.745 +		goto inc_pc_loop;
   1.746 +	
   1.747 +// 9. 16-BIT OPERATION COMMANDS
   1.748 +
   1.749 +	case 0x3A: // INCW dp
   1.750 +	case 0x1A:{// DECW dp
   1.751 +		int temp;
   1.752 +		// low byte
   1.753 +		data += dp;
   1.754 +		temp = READ( -3, data );
   1.755 +		temp += (opcode >> 4 & 2) - 1; // +1 for INCW, -1 for DECW
   1.756 +		nz = ((temp >> 1) | temp) & 0x7F;
   1.757 +		WRITE( -2, data, /*(uint8_t)*/ temp );
   1.758 +		
   1.759 +		// high byte
   1.760 +		data = (uint8_t) (data + 1) + dp;
   1.761 +		temp = (uint8_t) ((temp >> 8) + READ( -1, data ));
   1.762 +		nz |= temp;
   1.763 +		WRITE( 0, data, temp );
   1.764 +		
   1.765 +		goto inc_pc_loop;
   1.766 +	}
   1.767 +		
   1.768 +	case 0x7A: // ADDW YA,dp
   1.769 +	case 0x9A:{// SUBW YA,dp
   1.770 +		int lo = READ_DP( -2, data );
   1.771 +		int hi = READ_DP( 0, (uint8_t) (data + 1) );
   1.772 +		int result;
   1.773 +		int flags;
   1.774 +		
   1.775 +		if ( opcode == 0x9A ) // SUBW
   1.776 +		{
   1.777 +			lo = (lo ^ 0xFF) + 1;
   1.778 +			hi ^= 0xFF;
   1.779 +		}
   1.780 +		
   1.781 +		lo += a;
   1.782 +		result = y + hi + (lo >> 8);
   1.783 +		flags = hi ^ y ^ result;
   1.784 +		
   1.785 +		psw = (psw & ~(v40 | h08)) |
   1.786 +				(flags >> 1 & h08) |
   1.787 +				((flags + 0x80) >> 2 & v40);
   1.788 +		c = result;
   1.789 +		a = (uint8_t) lo;
   1.790 +		result = (uint8_t) result;
   1.791 +		y = result;
   1.792 +		nz = (((lo >> 1) | lo) & 0x7F) | result;
   1.793 +		
   1.794 +		goto inc_pc_loop;
   1.795 +	}
   1.796 +	
   1.797 +	case 0x5A: { // CMPW YA,dp
   1.798 +		int temp = a - READ_DP( -1, data );
   1.799 +		nz = ((temp >> 1) | temp) & 0x7F;
   1.800 +		temp = y + (temp >> 8);
   1.801 +		temp -= READ_DP( 0, (uint8_t) (data + 1) );
   1.802 +		nz |= temp;
   1.803 +		c  = ~temp;
   1.804 +		nz &= 0xFF;
   1.805 +		goto inc_pc_loop;
   1.806 +	}
   1.807 +	
   1.808 +// 10. MULTIPLICATION & DIVISON COMMANDS
   1.809 +
   1.810 +	case 0xCF: { // MUL YA
   1.811 +		unsigned temp = y * a;
   1.812 +		a = (uint8_t) temp;
   1.813 +		nz = ((temp >> 1) | temp) & 0x7F;
   1.814 +		y = temp >> 8;
   1.815 +		nz |= y;
   1.816 +		goto loop;
   1.817 +	}
   1.818 +	
   1.819 +	case 0x9E: // DIV YA,X
   1.820 +	{
   1.821 +		unsigned ya = y * 0x100 + a;
   1.822 +		
   1.823 +		psw &= ~(h08 | v40);
   1.824 +		
   1.825 +		if ( y >= x )
   1.826 +			psw |= v40;
   1.827 +		
   1.828 +		if ( (y & 15) >= (x & 15) )
   1.829 +			psw |= h08;
   1.830 +		
   1.831 +		if ( y < x * 2 )
   1.832 +		{
   1.833 +			a = ya / x;
   1.834 +			y = ya - a * x;
   1.835 +		}
   1.836 +		else
   1.837 +		{
   1.838 +			a = 255 - (ya - x * 0x200) / (256 - x);
   1.839 +			y = x   + (ya - x * 0x200) % (256 - x);
   1.840 +		}
   1.841 +		
   1.842 +		nz = (uint8_t) a;
   1.843 +		a = (uint8_t) a;
   1.844 +		
   1.845 +		goto loop;
   1.846 +	}
   1.847 +	
   1.848 +// 11. DECIMAL COMPENSATION COMMANDS
   1.849 +	
   1.850 +	case 0xDF: // DAA
   1.851 +		SUSPICIOUS_OPCODE( "DAA" );
   1.852 +		if ( a > 0x99 || c & 0x100 )
   1.853 +		{
   1.854 +			a += 0x60;
   1.855 +			c = 0x100;
   1.856 +		}
   1.857 +		
   1.858 +		if ( (a & 0x0F) > 9 || psw & h08 )
   1.859 +			a += 0x06;
   1.860 +		
   1.861 +		nz = a;
   1.862 +		a = (uint8_t) a;
   1.863 +		goto loop;
   1.864 +	
   1.865 +	case 0xBE: // DAS
   1.866 +		SUSPICIOUS_OPCODE( "DAS" );
   1.867 +		if ( a > 0x99 || !(c & 0x100) )
   1.868 +		{
   1.869 +			a -= 0x60;
   1.870 +			c = 0;
   1.871 +		}
   1.872 +		
   1.873 +		if ( (a & 0x0F) > 9 || !(psw & h08) )
   1.874 +			a -= 0x06;
   1.875 +		
   1.876 +		nz = a;
   1.877 +		a = (uint8_t) a;
   1.878 +		goto loop;
   1.879 +	
   1.880 +// 12. BRANCHING COMMANDS
   1.881 +
   1.882 +	case 0x2F: // BRA rel
   1.883 +		pc += (BOOST::int8_t) data;
   1.884 +		goto inc_pc_loop;
   1.885 +	
   1.886 +	case 0x30: // BMI
   1.887 +		BRANCH( (nz & nz_neg_mask) )
   1.888 +	
   1.889 +	case 0x10: // BPL
   1.890 +		BRANCH( !(nz & nz_neg_mask) )
   1.891 +	
   1.892 +	case 0xB0: // BCS
   1.893 +		BRANCH( c & 0x100 )
   1.894 +	
   1.895 +	case 0x90: // BCC
   1.896 +		BRANCH( !(c & 0x100) )
   1.897 +	
   1.898 +	case 0x70: // BVS
   1.899 +		BRANCH( psw & v40 )
   1.900 +	
   1.901 +	case 0x50: // BVC
   1.902 +		BRANCH( !(psw & v40) )
   1.903 +	
   1.904 +	#define CBRANCH( cond )\
   1.905 +	{\
   1.906 +		pc++;\
   1.907 +		if ( cond )\
   1.908 +			goto cbranch_taken_loop;\
   1.909 +		rel_time -= 2;\
   1.910 +		goto inc_pc_loop;\
   1.911 +	}
   1.912 +	
   1.913 +	case 0x03: // BBS dp.bit,rel
   1.914 +	case 0x23:
   1.915 +	case 0x43:
   1.916 +	case 0x63:
   1.917 +	case 0x83:
   1.918 +	case 0xA3:
   1.919 +	case 0xC3:
   1.920 +	case 0xE3:
   1.921 +		CBRANCH( READ_DP( -4, data ) >> (opcode >> 5) & 1 )
   1.922 +	
   1.923 +	case 0x13: // BBC dp.bit,rel
   1.924 +	case 0x33:
   1.925 +	case 0x53:
   1.926 +	case 0x73:
   1.927 +	case 0x93:
   1.928 +	case 0xB3:
   1.929 +	case 0xD3:
   1.930 +	case 0xF3:
   1.931 +		CBRANCH( !(READ_DP( -4, data ) >> (opcode >> 5) & 1) )
   1.932 +	
   1.933 +	case 0xDE: // CBNE dp+X,rel
   1.934 +		data = (uint8_t) (data + x);
   1.935 +		// fall through
   1.936 +	case 0x2E:{// CBNE dp,rel
   1.937 +		int temp;
   1.938 +		// 61% from timer
   1.939 +		READ_DP_TIMER( -4, data, temp );
   1.940 +		CBRANCH( temp != a )
   1.941 +	}
   1.942 +	
   1.943 +	case 0x6E: { // DBNZ dp,rel
   1.944 +		unsigned temp = READ_DP( -4, data ) - 1;
   1.945 +		WRITE_DP( -3, (uint8_t) data, /*(uint8_t)*/ temp + no_read_before_write  );
   1.946 +		CBRANCH( temp )
   1.947 +	}
   1.948 +	
   1.949 +	case 0xFE: // DBNZ Y,rel
   1.950 +		y = (uint8_t) (y - 1);
   1.951 +		BRANCH( y )
   1.952 +	
   1.953 +	case 0x1F: // JMP [abs+X]
   1.954 +		SET_PC( READ_PC16( pc ) + x );
   1.955 +		// fall through
   1.956 +	case 0x5F: // JMP abs
   1.957 +		SET_PC( READ_PC16( pc ) );
   1.958 +		goto loop;
   1.959 +	
   1.960 +// 13. SUB-ROUTINE CALL RETURN COMMANDS
   1.961 +	
   1.962 +	case 0x0F:{// BRK
   1.963 +		int temp;
   1.964 +		int ret_addr = GET_PC();
   1.965 +		SUSPICIOUS_OPCODE( "BRK" );
   1.966 +		SET_PC( READ_PROG16( 0xFFDE ) ); // vector address verified
   1.967 +		PUSH16( ret_addr );
   1.968 +		GET_PSW( temp );
   1.969 +		psw = (psw | b10) & ~i04;
   1.970 +		PUSH( temp );
   1.971 +		goto loop;
   1.972 +	}
   1.973 +	
   1.974 +	case 0x4F:{// PCALL offset
   1.975 +		int ret_addr = GET_PC() + 1;
   1.976 +		SET_PC( 0xFF00 | data );
   1.977 +		PUSH16( ret_addr );
   1.978 +		goto loop;
   1.979 +	}
   1.980 +	
   1.981 +	case 0x01: // TCALL n
   1.982 +	case 0x11:
   1.983 +	case 0x21:
   1.984 +	case 0x31:
   1.985 +	case 0x41:
   1.986 +	case 0x51:
   1.987 +	case 0x61:
   1.988 +	case 0x71:
   1.989 +	case 0x81:
   1.990 +	case 0x91:
   1.991 +	case 0xA1:
   1.992 +	case 0xB1:
   1.993 +	case 0xC1:
   1.994 +	case 0xD1:
   1.995 +	case 0xE1:
   1.996 +	case 0xF1: {
   1.997 +		int ret_addr = GET_PC();
   1.998 +		SET_PC( READ_PROG16( 0xFFDE - (opcode >> 3) ) );
   1.999 +		PUSH16( ret_addr );
  1.1000 +		goto loop;
  1.1001 +	}
  1.1002 +	
  1.1003 +// 14. STACK OPERATION COMMANDS
  1.1004 +
  1.1005 +	{
  1.1006 +		int temp;
  1.1007 +	case 0x7F: // RET1
  1.1008 +		temp = *sp;
  1.1009 +		SET_PC( GET_LE16( sp + 1 ) );
  1.1010 +		sp += 3;
  1.1011 +		goto set_psw;
  1.1012 +	case 0x8E: // POP PSW
  1.1013 +		POP( temp );
  1.1014 +	set_psw:
  1.1015 +		SET_PSW( temp );
  1.1016 +		goto loop;
  1.1017 +	}
  1.1018 +	
  1.1019 +	case 0x0D: { // PUSH PSW
  1.1020 +		int temp;
  1.1021 +		GET_PSW( temp );
  1.1022 +		PUSH( temp );
  1.1023 +		goto loop;
  1.1024 +	}
  1.1025 +
  1.1026 +	case 0x2D: // PUSH A
  1.1027 +		PUSH( a );
  1.1028 +		goto loop;
  1.1029 +	
  1.1030 +	case 0x4D: // PUSH X
  1.1031 +		PUSH( x );
  1.1032 +		goto loop;
  1.1033 +	
  1.1034 +	case 0x6D: // PUSH Y
  1.1035 +		PUSH( y );
  1.1036 +		goto loop;
  1.1037 +	
  1.1038 +	case 0xAE: // POP A
  1.1039 +		POP( a );
  1.1040 +		goto loop;
  1.1041 +	
  1.1042 +	case 0xCE: // POP X
  1.1043 +		POP( x );
  1.1044 +		goto loop;
  1.1045 +	
  1.1046 +	case 0xEE: // POP Y
  1.1047 +		POP( y );
  1.1048 +		goto loop;
  1.1049 +	
  1.1050 +// 15. BIT OPERATION COMMANDS
  1.1051 +
  1.1052 +	case 0x02: // SET1
  1.1053 +	case 0x22:
  1.1054 +	case 0x42:
  1.1055 +	case 0x62:
  1.1056 +	case 0x82:
  1.1057 +	case 0xA2:
  1.1058 +	case 0xC2:
  1.1059 +	case 0xE2:
  1.1060 +	case 0x12: // CLR1
  1.1061 +	case 0x32:
  1.1062 +	case 0x52:
  1.1063 +	case 0x72:
  1.1064 +	case 0x92:
  1.1065 +	case 0xB2:
  1.1066 +	case 0xD2:
  1.1067 +	case 0xF2: {
  1.1068 +		int bit = 1 << (opcode >> 5);
  1.1069 +		int mask = ~bit;
  1.1070 +		if ( opcode & 0x10 )
  1.1071 +			bit = 0;
  1.1072 +		data += dp;
  1.1073 +		WRITE( 0, data, (READ( -1, data ) & mask) | bit );
  1.1074 +		goto inc_pc_loop;
  1.1075 +	}
  1.1076 +		
  1.1077 +	case 0x0E: // TSET1 abs
  1.1078 +	case 0x4E: // TCLR1 abs
  1.1079 +		data = READ_PC16( pc );
  1.1080 +		pc += 2;
  1.1081 +		{
  1.1082 +			unsigned temp = READ( -2, data );
  1.1083 +			nz = (uint8_t) (a - temp);
  1.1084 +			temp &= ~a;
  1.1085 +			if ( opcode == 0x0E )
  1.1086 +				temp |= a;
  1.1087 +			WRITE( 0, data, temp );
  1.1088 +		}
  1.1089 +		goto loop;
  1.1090 +	
  1.1091 +	case 0x4A: // AND1 C,mem.bit
  1.1092 +		c &= MEM_BIT( 0 );
  1.1093 +		pc += 2;
  1.1094 +		goto loop;
  1.1095 +	
  1.1096 +	case 0x6A: // AND1 C,/mem.bit
  1.1097 +		c &= ~MEM_BIT( 0 );
  1.1098 +		pc += 2;
  1.1099 +		goto loop;
  1.1100 +	
  1.1101 +	case 0x0A: // OR1 C,mem.bit
  1.1102 +		c |= MEM_BIT( -1 );
  1.1103 +		pc += 2;
  1.1104 +		goto loop;
  1.1105 +	
  1.1106 +	case 0x2A: // OR1 C,/mem.bit
  1.1107 +		c |= ~MEM_BIT( -1 );
  1.1108 +		pc += 2;
  1.1109 +		goto loop;
  1.1110 +	
  1.1111 +	case 0x8A: // EOR1 C,mem.bit
  1.1112 +		c ^= MEM_BIT( -1 );
  1.1113 +		pc += 2;
  1.1114 +		goto loop;
  1.1115 +	
  1.1116 +	case 0xEA: // NOT1 mem.bit
  1.1117 +		data = READ_PC16( pc );
  1.1118 +		pc += 2;
  1.1119 +		{
  1.1120 +			unsigned temp = READ( -1, data & 0x1FFF );
  1.1121 +			temp ^= 1 << (data >> 13);
  1.1122 +			WRITE( 0, data & 0x1FFF, temp );
  1.1123 +		}
  1.1124 +		goto loop;
  1.1125 +	
  1.1126 +	case 0xCA: // MOV1 mem.bit,C
  1.1127 +		data = READ_PC16( pc );
  1.1128 +		pc += 2;
  1.1129 +		{
  1.1130 +			unsigned temp = READ( -2, data & 0x1FFF );
  1.1131 +			unsigned bit = data >> 13;
  1.1132 +			temp = (temp & ~(1 << bit)) | ((c >> 8 & 1) << bit);
  1.1133 +			WRITE( 0, data & 0x1FFF, temp + no_read_before_write  );
  1.1134 +		}
  1.1135 +		goto loop;
  1.1136 +	
  1.1137 +	case 0xAA: // MOV1 C,mem.bit
  1.1138 +		c = MEM_BIT( 0 );
  1.1139 +		pc += 2;
  1.1140 +		goto loop;
  1.1141 +	
  1.1142 +// 16. PROGRAM PSW FLAG OPERATION COMMANDS
  1.1143 +
  1.1144 +	case 0x60: // CLRC
  1.1145 +		c = 0;
  1.1146 +		goto loop;
  1.1147 +		
  1.1148 +	case 0x80: // SETC
  1.1149 +		c = ~0;
  1.1150 +		goto loop;
  1.1151 +	
  1.1152 +	case 0xED: // NOTC
  1.1153 +		c ^= 0x100;
  1.1154 +		goto loop;
  1.1155 +		
  1.1156 +	case 0xE0: // CLRV
  1.1157 +		psw &= ~(v40 | h08);
  1.1158 +		goto loop;
  1.1159 +	
  1.1160 +	case 0x20: // CLRP
  1.1161 +		dp = 0;
  1.1162 +		goto loop;
  1.1163 +	
  1.1164 +	case 0x40: // SETP
  1.1165 +		dp = 0x100;
  1.1166 +		goto loop;
  1.1167 +	
  1.1168 +	case 0xA0: // EI
  1.1169 +		SUSPICIOUS_OPCODE( "EI" );
  1.1170 +		psw |= i04;
  1.1171 +		goto loop;
  1.1172 +	
  1.1173 +	case 0xC0: // DI
  1.1174 +		SUSPICIOUS_OPCODE( "DI" );
  1.1175 +		psw &= ~i04;
  1.1176 +		goto loop;
  1.1177 +	
  1.1178 +// 17. OTHER COMMANDS
  1.1179 +
  1.1180 +	case 0x00: // NOP
  1.1181 +		goto loop;
  1.1182 +	
  1.1183 +	case 0xFF:{// STOP
  1.1184 +		// handle PC wrap-around
  1.1185 +		unsigned addr = GET_PC() - 1;
  1.1186 +		if ( addr >= 0x10000 )
  1.1187 +		{
  1.1188 +			addr &= 0xFFFF;
  1.1189 +			SET_PC( addr );
  1.1190 +			dprintf( "SPC: PC wrapped around\n" );
  1.1191 +			goto loop;
  1.1192 +		}
  1.1193 +	}
  1.1194 +	// fall through
  1.1195 +	case 0xEF: // SLEEP
  1.1196 +		SUSPICIOUS_OPCODE( "STOP/SLEEP" );
  1.1197 +		--pc;
  1.1198 +		rel_time = 0;
  1.1199 +		m.cpu_error = "SPC emulation error";
  1.1200 +		goto stop;
  1.1201 +	} // switch
  1.1202 +	
  1.1203 +	assert( 0 ); // catch any unhandled instructions
  1.1204 +}   
  1.1205 +out_of_time:
  1.1206 +	rel_time -= m.cycle_table [*pc]; // undo partial execution of opcode
  1.1207 +stop:
  1.1208 +	
  1.1209 +	// Uncache registers
  1.1210 +	if ( GET_PC() >= 0x10000 )
  1.1211 +		dprintf( "SPC: PC wrapped around\n" );
  1.1212 +	m.cpu_regs.pc = (uint16_t) GET_PC();
  1.1213 +	m.cpu_regs.sp = ( uint8_t) GET_SP();
  1.1214 +	m.cpu_regs.a  = ( uint8_t) a;
  1.1215 +	m.cpu_regs.x  = ( uint8_t) x;
  1.1216 +	m.cpu_regs.y  = ( uint8_t) y;
  1.1217 +	{
  1.1218 +		int temp;
  1.1219 +		GET_PSW( temp );
  1.1220 +		m.cpu_regs.psw = (uint8_t) temp;
  1.1221 +	}
  1.1222 +}
  1.1223 +SPC_CPU_RUN_FUNC_END