PageRenderTime 62ms CodeModel.GetById 13ms app.highlight 40ms RepoModel.GetById 1ms app.codeStats 0ms

/gme/Spc_Cpu.h

http://game-music-emu.googlecode.com/
C++ Header | 1220 lines | 965 code | 186 blank | 69 comment | 42 complexity | 60ca033f253a9be094d43befa17253c0 MD5 | raw file
   1// Game_Music_Emu 0.5.5. http://www.slack.net/~ant/
   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
  14//// Memory access
  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 )                 GET_LE16( ram + (addr) )
  70
  71#define SET_PC( n )     (pc = ram + (n))
  72#define GET_PC()        (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()        (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 = (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
 124unsigned 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
 135int const n80 = 0x80; // nz
 136int const v40 = 0x40; // psw
 137int const p20 = 0x20; // dp
 138int const b10 = 0x10; // psw
 139int const h08 = 0x08; // psw
 140int const i04 = 0x04; // psw
 141int const z02 = 0x02; // nz
 142int const c01 = 0x01; // c
 143
 144int 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
 163SPC_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	
 185cbranch_taken_loop:
 186	pc += *(BOOST::int8_t const*) pc;
 187inc_pc_loop:
 188	pc++;
 189loop:
 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 = 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 ( ((~0x2F00 << (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			debug_printf( "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}   
1202out_of_time:
1203	rel_time -= m.cycle_table [*pc]; // undo partial execution of opcode
1204stop:
1205	
1206	// Uncache registers
1207	if ( GET_PC() >= 0x10000 )
1208		debug_printf( "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}
1220SPC_CPU_RUN_FUNC_END