annotate snes_spc/SPC_CPU.h @ 3:95cdedd01422

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