1 // $package. http://www.slack.net/~ant/ 2 3 // Last validated with zexall 2009.12.05. 4 // Doesn't implement the R register or immediate interrupt after EI. 5 // Address wrap-around isn't completely correct, but is prevented from crashing emulator. 6 // 16-bit memory accesses are made directly to mapped memory, instead of using macro. 7 8 #if 0 9 /* Define these macros in the source file before #including this file. 10 - Parameters might be expressions, so they are best evaluated only once, 11 though they NEVER have side-effects, so multiple evaluation is OK. 12 - Output parameters might be a multiple-assignment expression like "a=x", 13 so they must NOT be parenthesized. 14 - Except where noted, time() and related functions will NOT work 15 correctly inside a macro. TIME() is always correct, and between FLUSH_TIME() and 16 CACHE_TIME() the normal time changing functions can be used. 17 - Macros "returning" void may use a {} statement block. */ 18 19 // 0 <= addr <= 0xFFFF + 0x100 20 // Optional; default uses whatever was set with map_mem() 21 int READ_CODE( addr_t ); 22 23 // 0 <= addr <= 0xFFFF + 0x100 24 // Optional; default uses whatever was set with map_mem() 25 int READ_MEM( addr_t ); 26 void WRITE_MEM( addr_t, int data ); 27 28 // 0 <= port <= 0xFFFF (apparently upper 8 bits are output by hardware) 29 void OUT_PORT( int port, int data ); 30 int IN_PORT int port ); 31 32 // Reference to Z80_Cpu object used for emulation 33 #define CPU cpu 34 35 // The following can be used within macros: 36 37 // Current time 38 time_t TIME(); 39 40 // Allows use of time functions 41 void FLUSH_TIME(); 42 43 // Must be used before end of macro if FLUSH_TIME() was used earlier 44 void CACHE_TIME(); 45 46 // Configuration (optional; commented behavior if defined) 47 48 // Optimizes as if map_mem( 0, 0x10000, FLAT_MEM, FLAT_MEM ) is always in effect 49 #define FLAT_MEM my_mem_array 50 51 // If RST 7 ($FF) is encountered and PC = IDLE_ADDR, stops execution 52 #define IDLE_ADDR 0x1234 53 54 // Expanded just before beginning of code, to help debugger 55 #define CPU_BEGIN void my_run_cpu() { 56 57 #endif 58 59 /* Copyright (C) 2006-2008 Shay Green. This module is free software; you 60 can redistribute it and/or modify it under the terms of the GNU Lesser 61 General Public License as published by the Free Software Foundation; either 62 version 2.1 of the License, or (at your option) any later version. This 63 module is distributed in the hope that it will be useful, but WITHOUT ANY 64 WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 65 FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more 66 details. You should have received a copy of the GNU Lesser General Public 67 License along with this module; if not, write to the Free Software Foundation, 68 Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ 69 70 #ifdef CPU_BEGIN 71 CPU_BEGIN 72 #endif 73 74 #define R CPU.r 75 76 // flags, named with hex value for clarity 77 int const S80 = 0x80; 78 int const Z40 = 0x40; 79 int const F20 = 0x20; 80 int const H10 = 0x10; 81 int const F08 = 0x08; 82 int const V04 = 0x04; 83 int const P04 = 0x04; 84 int const N02 = 0x02; 85 int const C01 = 0x01; 86 87 #define SZ28P( n ) CPU.szpc [n] 88 #define SZ28PC( n ) CPU.szpc [n] 89 #define SZ28C( n ) (CPU.szpc [n] & ~P04) 90 #define SZ28( n ) SZ28C( n ) 91 92 #define SET_R( n ) (void) (R.r = n) 93 #define GET_R() (R.r) 94 95 // Time 96 #define TIME() (s_time + s.base) 97 #define FLUSH_TIME() {s.time = s_time;} 98 #define CACHE_TIME() {s_time = s.time;} 99 100 // Memory 101 #define RW_MEM( addr, rw ) RW_PAGE( addr, rw ) [RW_OFFSET( addr )] 102 #ifndef READ_CODE 103 #define READ_CODE( addr ) RW_MEM( addr, read ) 104 #endif 105 106 #ifdef FLAT_MEM 107 #define RW_PAGE( addr, rw ) FLAT_MEM 108 #define RW_OFFSET( addr ) (addr) 109 #define INSTR( off, addr ) READ_CODE( addr ) 110 #else 111 #define RW_PAGE( addr, rw ) s.rw [(unsigned) (addr) >> Z80_Cpu::page_bits] 112 #define RW_OFFSET( addr ) Z80_CPU_OFFSET( addr ) 113 #define INSTR( off, addr ) instr [off] 114 #endif 115 116 #ifndef READ_MEM 117 #define READ_MEM( addr ) RW_MEM( addr, read ) 118 #endif 119 120 #ifndef WRITE_MEM 121 #define WRITE_MEM( addr, data ) (RW_MEM( addr, write ) = data) 122 #endif 123 124 #define READ_WORD( addr ) GET_LE16( &RW_MEM( addr, read ) ) 125 #define WRITE_WORD( addr, data ) SET_LE16( &RW_MEM( addr, write ), data ) 126 127 // Truncation 128 #define BYTE( n ) ((BOOST::uint8_t ) (n)) /* (unsigned) n & 0xFF */ 129 #define SBYTE( n ) ((BOOST::int8_t ) (n)) /* (BYTE( n ) ^ 0x80) - 0x80 */ 130 #define WORD( n ) ((BOOST::uint16_t) (n)) /* (unsigned) n & 0xFFFF */ 131 132 // Misc 133 #define CASE5( a, b, c, d, e ) case 0x##a:case 0x##b:case 0x##c:case 0x##d:case 0x##e 134 #define CASE6( a, b, c, d, e, f ) CASE5( a, b, c, d, e ): case 0x##f 135 #define CASE7( a, b, c, d, e, f, g ) CASE6( a, b, c, d, e, f ): case 0x##g 136 #define CASE8( a, b, c, d, e, f, g, h ) CASE7( a, b, c, d, e, f, g ): case 0x##h 137 138 #if BLARGG_BIG_ENDIAN 139 #define R8( n, offset ) ((r.r8_ - offset) [n]) 140 #elif BLARGG_LITTLE_ENDIAN 141 #define R8( n, offset ) ((r.r8_ - offset) [(n) ^ 1]) 142 #else 143 #error "Byte order of CPU must be known" 144 #endif 145 146 #define R16( n, shift, offset ) (r.r16_ [((unsigned) (n) >> shift) - (offset >> shift)]) 147 148 #define EX( x, y ) \ 149 {\ 150 int temp = x;\ 151 x = y;\ 152 y = temp;\ 153 } 154 155 #define EXX( name ) \ 156 EX( R.alt.name, r.name ) 157 158 bool warning = false; 159 { 160 Z80_Cpu::cpu_state_t s; 161 #ifdef FLAT_MEM 162 s.base = CPU.cpu_state_.base; 163 #else 164 s = CPU.cpu_state_; 165 #endif 166 CPU.cpu_state = &s; 167 168 169 union r_t { 170 Z80_Cpu::regs_t b; 171 Z80_Cpu::pairs_t w; 172 byte r8_ [8]; // indexed 173 BOOST::uint16_t r16_ [4]; 174 } r; 175 r.b = R.b; 176 177 Z80_Cpu::time_t s_time = CPU.cpu_state_.time; 178 int pc = R.pc; 179 int sp = R.sp; 180 int ix = R.ix; // TODO: keep in memory for direct access? 181 int iy = R.iy; 182 int flags = R.b.flags; 183 184 //goto loop; // confuses optimizer 185 s_time += 7; 186 pc -= 2; 187 188 call_not_taken: 189 s_time -= 7; 190 jp_not_taken: 191 pc += 2; 192 loop: 193 194 check( (unsigned) pc < 0x10000 + 1 ); // +1 so emulator can catch wrap-around 195 check( (unsigned) sp < 0x10000 ); 196 check( (unsigned) flags < 0x100 ); 197 check( (unsigned) ix < 0x10000 ); 198 check( (unsigned) iy < 0x10000 ); 199 200 byte const* instr = RW_PAGE( pc, read ); 201 202 int opcode; 203 204 if ( RW_OFFSET( ~0 ) == ~0 ) 205 { 206 opcode = instr [RW_OFFSET( pc )]; 207 pc++; 208 instr += RW_OFFSET( pc ); 209 } 210 else 211 { 212 instr += RW_OFFSET( pc ); 213 opcode = *instr++; 214 pc++; 215 } 216 217 static byte const clock_table [256 * 2] = { 218 // 0 1 2 3 4 5 6 7 8 9 A B C D E F 219 4,10, 7, 6, 4, 4, 7, 4, 4,11, 7, 6, 4, 4, 7, 4, // 0 220 8,10, 7, 6, 4, 4, 7, 4,12,11, 7, 6, 4, 4, 7, 4, // 1 221 7,10,16, 6, 4, 4, 7, 4, 7,11,16, 6, 4, 4, 7, 4, // 2 222 7,10,13, 6,11,11,10, 4, 7,11,13, 6, 4, 4, 7, 4, // 3 223 4, 4, 4, 4, 4, 4, 7, 4, 4, 4, 4, 4, 4, 4, 7, 4, // 4 224 4, 4, 4, 4, 4, 4, 7, 4, 4, 4, 4, 4, 4, 4, 7, 4, // 5 225 4, 4, 4, 4, 4, 4, 7, 4, 4, 4, 4, 4, 4, 4, 7, 4, // 6 226 7, 7, 7, 7, 7, 7, 4, 7, 4, 4, 4, 4, 4, 4, 7, 4, // 7 227 4, 4, 4, 4, 4, 4, 7, 4, 4, 4, 4, 4, 4, 4, 7, 4, // 8 228 4, 4, 4, 4, 4, 4, 7, 4, 4, 4, 4, 4, 4, 4, 7, 4, // 9 229 4, 4, 4, 4, 4, 4, 7, 4, 4, 4, 4, 4, 4, 4, 7, 4, // A 230 4, 4, 4, 4, 4, 4, 7, 4, 4, 4, 4, 4, 4, 4, 7, 4, // B 231 11,10,10,10,17,11, 7,11,11,10,10, 8,17,17, 7,11, // C 232 11,10,10,11,17,11, 7,11,11, 4,10,11,17, 8, 7,11, // D 233 11,10,10,19,17,11, 7,11,11, 4,10, 4,17, 8, 7,11, // E 234 11,10,10, 4,17,11, 7,11,11, 6,10, 4,17, 8, 7,11, // F 235 236 // high four bits are $ED time - 8, low four bits are $DD/$FD time - 8 237 //0 1 2 3 4 5 6 7 8 9 A B C D E F 238 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x07,0x00,0x00,0x00,0x00,0x00,0x00, 239 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x07,0x00,0x00,0x00,0x00,0x00,0x00, 240 0x00,0x06,0x0C,0x02,0x00,0x00,0x03,0x00,0x00,0x07,0x0C,0x02,0x00,0x00,0x03,0x00, 241 0x00,0x00,0x00,0x00,0x0F,0x0F,0x0B,0x00,0x00,0x07,0x00,0x00,0x00,0x00,0x00,0x00, 242 0x40,0x40,0x70,0xC0,0x00,0x60,0x0B,0x10,0x40,0x40,0x70,0xC0,0x00,0x60,0x0B,0x10, 243 0x40,0x40,0x70,0xC0,0x00,0x60,0x0B,0x10,0x40,0x40,0x70,0xC0,0x00,0x60,0x0B,0x10, 244 0x40,0x40,0x70,0xC0,0x00,0x60,0x0B,0xA0,0x40,0x40,0x70,0xC0,0x00,0x60,0x0B,0xA0, 245 0x4B,0x4B,0x7B,0xCB,0x0B,0x6B,0x00,0x0B,0x40,0x40,0x70,0xC0,0x00,0x60,0x0B,0x00, 246 0x00,0x00,0x00,0x00,0x00,0x00,0x0B,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0B,0x00, 247 0x00,0x00,0x00,0x00,0x00,0x00,0x0B,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0B,0x00, 248 0x80,0x80,0x80,0x80,0x00,0x00,0x0B,0x00,0x80,0x80,0x80,0x80,0x00,0x00,0x0B,0x00, 249 0xD0,0xD0,0xD0,0xD0,0x00,0x00,0x0B,0x00,0xD0,0xD0,0xD0,0xD0,0x00,0x00,0x0B,0x00, 250 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0F,0x00,0x00,0x00,0x00, 251 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 252 0x00,0x06,0x00,0x0F,0x00,0x07,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 253 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x00,0x00,0x00,0x00,0x00,0x00, 254 }; 255 256 if ( s_time >= 0 ) 257 goto out_of_time; 258 s_time += clock_table [opcode]; 259 260 #ifdef Z80_CPU_LOG_H 261 //log_opcode( opcode, READ_CODE( pc ) ); 262 z80_cpu_log( "log.txt", pc - 1, opcode, READ_CODE( pc ), 263 READ_CODE( pc + 1 ), READ_CODE( pc + 2 ) ); 264 z80_log_regs( r.b.a, r.w.bc, r.w.de, r.w.hl, sp, ix, iy ); 265 #endif 266 267 #define GET_ADDR() GET_LE16( &INSTR( 0, pc ) ) 268 269 int data; 270 data = INSTR( 0, pc ); 271 272 switch ( opcode ) 273 { 274 // Common 275 276 case 0x00: // NOP 277 CASE7( 40, 49, 52, 5B, 64, 6D, 7F ): // LD B,B etc. 278 goto loop; 279 280 case 0x08:{// EX AF,AF' 281 EXX( b.a ); 282 EX( R.alt.b.flags, flags ); 283 goto loop; 284 } 285 286 case 0xD3: // OUT (imm),A 287 pc++; 288 OUT_PORT( (data + r.b.a * 0x100), r.b.a ); 289 goto loop; 290 291 case 0x2E: // LD L,imm 292 pc++; 293 r.b.l = data; 294 goto loop; 295 296 case 0x3E: // LD A,imm 297 pc++; 298 r.b.a = data; 299 goto loop; 300 301 case 0x3A:{// LD A,(addr) 302 int addr = GET_ADDR(); 303 pc += 2; 304 r.b.a = READ_MEM( addr ); 305 goto loop; 306 } 307 308 // Conditional 309 310 #define ZERO (flags & Z40) 311 #define CARRY (flags & C01) 312 #define EVEN (flags & P04) 313 #define MINUS (flags & S80) 314 315 // JR 316 // TODO: more efficient way to handle negative branch that wraps PC around 317 #define JR_( cond, clocks ) {\ 318 pc++;\ 319 if ( !(cond) )\ 320 goto loop;\ 321 int offset = SBYTE( data );\ 322 pc = WORD( pc + offset );\ 323 s_time += clocks;\ 324 goto loop;\ 325 } 326 327 #define JR( cond ) JR_( cond, 5 ) 328 329 case 0x20: JR( !ZERO ) // JR NZ,disp 330 case 0x28: JR( ZERO ) // JR Z,disp 331 case 0x30: JR( !CARRY ) // JR NC,disp 332 case 0x38: JR( CARRY ) // JR C,disp 333 case 0x18: JR_( true,0) // JR disp 334 335 case 0x10:{// DJNZ disp 336 int temp = r.b.b - 1; 337 r.b.b = temp; 338 JR( temp ) 339 } 340 341 // JP 342 #define JP( cond ) \ 343 if ( !(cond) )\ 344 goto jp_not_taken;\ 345 pc = GET_ADDR();\ 346 goto loop; 347 348 case 0xC2: JP( !ZERO ) // JP NZ,addr 349 case 0xCA: JP( ZERO ) // JP Z,addr 350 case 0xD2: JP( !CARRY ) // JP NC,addr 351 case 0xDA: JP( CARRY ) // JP C,addr 352 case 0xE2: JP( !EVEN ) // JP PO,addr 353 case 0xEA: JP( EVEN ) // JP PE,addr 354 case 0xF2: JP( !MINUS ) // JP P,addr 355 case 0xFA: JP( MINUS ) // JP M,addr 356 357 case 0xC3: // JP addr 358 pc = GET_ADDR(); 359 goto loop; 360 361 case 0xE9: // JP HL 362 pc = r.w.hl; 363 goto loop; 364 365 // RET 366 #define RET( cond ) \ 367 if ( cond )\ 368 goto ret_taken;\ 369 s_time -= 6;\ 370 goto loop; 371 372 case 0xC0: RET( !ZERO ) // RET NZ 373 case 0xC8: RET( ZERO ) // RET Z 374 case 0xD0: RET( !CARRY ) // RET NC 375 case 0xD8: RET( CARRY ) // RET C 376 case 0xE0: RET( !EVEN ) // RET PO 377 case 0xE8: RET( EVEN ) // RET PE 378 case 0xF0: RET( !MINUS ) // RET P 379 case 0xF8: RET( MINUS ) // RET M 380 381 case 0xC9: // RET 382 ret_taken: 383 pc = READ_WORD( sp ); 384 sp = WORD( sp + 2 ); 385 goto loop; 386 387 // CALL 388 #define CALL( cond ) \ 389 if ( cond )\ 390 goto call_taken;\ 391 goto call_not_taken; 392 393 case 0xC4: CALL( !ZERO ) // CALL NZ,addr 394 case 0xCC: CALL( ZERO ) // CALL Z,addr 395 case 0xD4: CALL( !CARRY ) // CALL NC,addr 396 case 0xDC: CALL( CARRY ) // CALL C,addr 397 case 0xE4: CALL( !EVEN ) // CALL PO,addr 398 case 0xEC: CALL( EVEN ) // CALL PE,addr 399 case 0xF4: CALL( !MINUS ) // CALL P,addr 400 case 0xFC: CALL( MINUS ) // CALL M,addr 401 402 case 0xCD:{// CALL addr 403 call_taken: 404 int addr = pc + 2; 405 pc = GET_ADDR(); 406 sp = WORD( sp - 2 ); 407 WRITE_WORD( sp, addr ); 408 goto loop; 409 } 410 411 case 0xFF: // RST 412 #ifdef IDLE_ADDR 413 if ( pc == IDLE_ADDR + 1 ) 414 goto hit_idle_addr; 415 #else 416 if ( pc > 0x10000 ) 417 { 418 pc = WORD( pc - 1 ); 419 s_time -= 11; 420 goto loop; 421 } 422 #endif 423 CASE7( C7, CF, D7, DF, E7, EF, F7 ): 424 data = pc; 425 pc = opcode & 0x38; 426 #ifdef RST_BASE 427 pc += RST_BASE; 428 #endif 429 goto push_data; 430 431 // PUSH/POP 432 case 0xF5: // PUSH AF 433 data = r.b.a * 0x100u + flags; 434 goto push_data; 435 436 case 0xC5: // PUSH BC 437 case 0xD5: // PUSH DE 438 case 0xE5: // PUSH HL 439 data = R16( opcode, 4, 0xC5 ); 440 push_data: 441 sp = WORD( sp - 2 ); 442 WRITE_WORD( sp, data ); 443 goto loop; 444 445 case 0xF1: // POP AF 446 flags = READ_MEM( sp ); 447 r.b.a = READ_MEM( (sp + 1) ); 448 sp = WORD( sp + 2 ); 449 goto loop; 450 451 case 0xC1: // POP BC 452 case 0xD1: // POP DE 453 case 0xE1: // POP HL 454 R16( opcode, 4, 0xC1 ) = READ_WORD( sp ); 455 sp = WORD( sp + 2 ); 456 goto loop; 457 458 // ADC/ADD/SBC/SUB 459 case 0x96: // SUB (HL) 460 case 0x86: // ADD (HL) 461 flags &= ~C01; 462 case 0x9E: // SBC (HL) 463 case 0x8E: // ADC (HL) 464 data = READ_MEM( r.w.hl ); 465 goto adc_data; 466 467 case 0xD6: // SUB A,imm 468 case 0xC6: // ADD imm 469 flags &= ~C01; 470 case 0xDE: // SBC A,imm 471 case 0xCE: // ADC imm 472 pc++; 473 goto adc_data; 474 475 CASE7( 90, 91, 92, 93, 94, 95, 97 ): // SUB r 476 CASE7( 80, 81, 82, 83, 84, 85, 87 ): // ADD r 477 flags &= ~C01; 478 CASE7( 98, 99, 9A, 9B, 9C, 9D, 9F ): // SBC r 479 CASE7( 88, 89, 8A, 8B, 8C, 8D, 8F ): // ADC r 480 data = R8( opcode & 7, 0 ); 481 adc_data: { 482 int result = data + (flags & C01); 483 data ^= r.b.a; 484 flags = opcode >> 3 & N02; // bit 4 is set in subtract opcodes 485 if ( flags ) 486 result = -result; 487 result += r.b.a; 488 data ^= result; 489 flags +=(data & H10) + 490 ((data + 0x80) >> 6 & V04) + 491 SZ28C( result & 0x1FF ); 492 r.b.a = result; 493 goto loop; 494 } 495 496 // CP 497 case 0xBE: // CP (HL) 498 data = READ_MEM( r.w.hl ); 499 goto cp_data; 500 501 case 0xFE: // CP imm 502 pc++; 503 goto cp_data; 504 505 CASE7( B8, B9, BA, BB, BC, BD, BF ): // CP r 506 data = R8( opcode, 0xB8 ); 507 cp_data: { 508 int result = r.b.a - data; 509 flags = N02 + (data & (F20 | F08)) + (result >> 8 & C01); 510 data ^= r.b.a; 511 flags +=(((result ^ r.b.a) & data) >> 5 & V04) + 512 (((data & H10) ^ result) & (S80 | H10)); 513 if ( BYTE( result ) ) 514 goto loop; 515 flags += Z40; 516 goto loop; 517 } 518 519 // ADD HL,r.w 520 521 case 0x39: // ADD HL,SP 522 data = sp; 523 goto add_hl_data; 524 525 case 0x09: // ADD HL,BC 526 case 0x19: // ADD HL,DE 527 case 0x29: // ADD HL,HL 528 data = R16( opcode, 4, 0x09 ); 529 add_hl_data: { 530 int sum = r.w.hl + data; 531 data ^= r.w.hl; 532 r.w.hl = sum; 533 flags = (flags & (S80 | Z40 | V04)) + 534 (sum >> 16) + 535 (sum >> 8 & (F20 | F08)) + 536 ((data ^ sum) >> 8 & H10); 537 goto loop; 538 } 539 540 case 0x27:{// DAA 541 int a = r.b.a; 542 if ( a > 0x99 ) 543 flags |= C01; 544 545 int adjust = 0x60 * (flags & C01); 546 547 if ( flags & H10 || (a & 0x0F) > 9 ) 548 adjust += 0x06; 549 550 if ( flags & N02 ) 551 adjust = -adjust; 552 a += adjust; 553 554 flags = (flags & (C01 | N02)) + 555 ((r.b.a ^ a) & H10) + 556 SZ28P( BYTE( a ) ); 557 r.b.a = a; 558 goto loop; 559 } 560 561 // INC/DEC 562 case 0x34: // INC (HL) 563 data = READ_MEM( r.w.hl ) + 1; 564 WRITE_MEM( r.w.hl, data ); 565 goto inc_set_flags; 566 567 CASE7( 04, 0C, 14, 1C, 24, 2C, 3C ): // INC r 568 data = ++R8( opcode >> 3, 0 ); 569 inc_set_flags: 570 flags = (flags & C01) + 571 (((data & 0x0F) - 1) & H10) + 572 SZ28( BYTE( data ) ); 573 if ( data != 0x80 ) 574 goto loop; 575 flags += V04; 576 goto loop; 577 578 case 0x35: // DEC (HL) 579 data = READ_MEM( r.w.hl ) - 1; 580 WRITE_MEM( r.w.hl, data ); 581 goto dec_set_flags; 582 583 CASE7( 05, 0D, 15, 1D, 25, 2D, 3D ): // DEC r 584 data = --R8( opcode >> 3, 0 ); 585 dec_set_flags: 586 flags = (flags & C01) + N02 + 587 (((data & 0x0F) + 1) & H10) + 588 SZ28( BYTE( data ) ); 589 if ( data != 0x7F ) 590 goto loop; 591 flags += V04; 592 goto loop; 593 594 case 0x03: // INC BC 595 case 0x13: // INC DE 596 case 0x23: // INC HL 597 R16( opcode, 4, 0x03 )++; 598 goto loop; 599 600 case 0x33: // INC SP 601 sp = WORD( sp + 1 ); 602 goto loop; 603 604 case 0x0B: // DEC BC 605 case 0x1B: // DEC DE 606 case 0x2B: // DEC HL 607 R16( opcode, 4, 0x0B )--; 608 goto loop; 609 610 case 0x3B: // DEC SP 611 sp = WORD( sp - 1 ); 612 goto loop; 613 614 // AND 615 case 0xA6: // AND (HL) 616 data = READ_MEM( r.w.hl ); 617 goto and_data; 618 619 case 0xE6: // AND imm 620 pc++; 621 goto and_data; 622 623 CASE7( A0, A1, A2, A3, A4, A5, A7 ): // AND r 624 data = R8( opcode, 0xA0 ); 625 and_data: 626 r.b.a &= data; 627 flags = SZ28P( r.b.a ) + H10; 628 goto loop; 629 630 // OR 631 case 0xB6: // OR (HL) 632 data = READ_MEM( r.w.hl ); 633 goto or_data; 634 635 case 0xF6: // OR imm 636 pc++; 637 goto or_data; 638 639 CASE7( B0, B1, B2, B3, B4, B5, B7 ): // OR r 640 data = R8( opcode, 0xB0 ); 641 or_data: 642 r.b.a |= data; 643 flags = SZ28P( r.b.a ); 644 goto loop; 645 646 // XOR 647 case 0xAE: // XOR (HL) 648 data = READ_MEM( r.w.hl ); 649 goto xor_data; 650 651 case 0xEE: // XOR imm 652 pc++; 653 goto xor_data; 654 655 CASE7( A8, A9, AA, AB, AC, AD, AF ): // XOR r 656 data = R8( opcode, 0xA8 ); 657 xor_data: 658 r.b.a ^= data; 659 flags = SZ28P( r.b.a ); 660 goto loop; 661 662 // LD 663 CASE7( 70, 71, 72, 73, 74, 75, 77 ): // LD (HL),r 664 WRITE_MEM( r.w.hl, R8( opcode, 0x70 ) ); 665 goto loop; 666 667 CASE6( 41, 42, 43, 44, 45, 47 ): // LD B,r 668 CASE6( 48, 4A, 4B, 4C, 4D, 4F ): // LD C,r 669 CASE6( 50, 51, 53, 54, 55, 57 ): // LD D,r 670 CASE6( 58, 59, 5A, 5C, 5D, 5F ): // LD E,r 671 CASE6( 60, 61, 62, 63, 65, 67 ): // LD H,r 672 CASE6( 68, 69, 6A, 6B, 6C, 6F ): // LD L,r 673 CASE6( 78, 79, 7A, 7B, 7C, 7D ): // LD A,r 674 R8( opcode >> 3 & 7, 0 ) = R8( opcode & 7, 0 ); 675 goto loop; 676 677 CASE5( 06, 0E, 16, 1E, 26 ): // LD r,imm 678 R8( opcode >> 3, 0 ) = data; 679 pc++; 680 goto loop; 681 682 case 0x36: // LD (HL),imm 683 pc++; 684 WRITE_MEM( r.w.hl, data ); 685 goto loop; 686 687 CASE7( 46, 4E, 56, 5E, 66, 6E, 7E ): // LD r,(HL) 688 R8( opcode >> 3, 8 ) = READ_MEM( r.w.hl ); 689 goto loop; 690 691 case 0x01: // LD r.w,imm 692 case 0x11: 693 case 0x21: 694 R16( opcode, 4, 0x01 ) = GET_ADDR(); 695 pc += 2; 696 goto loop; 697 698 case 0x31: // LD sp,imm 699 sp = GET_ADDR(); 700 pc += 2; 701 goto loop; 702 703 case 0x2A:{// LD HL,(addr) 704 int addr = GET_ADDR(); 705 pc += 2; 706 r.w.hl = READ_WORD( addr ); 707 goto loop; 708 } 709 710 case 0x32:{// LD (addr),A 711 int addr = GET_ADDR(); 712 pc += 2; 713 WRITE_MEM( addr, r.b.a ); 714 goto loop; 715 } 716 717 case 0x22:{// LD (addr),HL 718 int addr = GET_ADDR(); 719 pc += 2; 720 WRITE_WORD( addr, r.w.hl ); 721 goto loop; 722 } 723 724 case 0x02: // LD (BC),A 725 case 0x12: // LD (DE),A 726 WRITE_MEM( R16( opcode, 4, 0x02 ), r.b.a ); 727 goto loop; 728 729 case 0x0A: // LD A,(BC) 730 case 0x1A: // LD A,(DE) 731 r.b.a = READ_MEM( R16( opcode, 4, 0x0A ) ); 732 goto loop; 733 734 case 0xF9: // LD SP,HL 735 sp = r.w.hl; 736 goto loop; 737 738 // Rotate 739 740 case 0x07:{// RLCA 741 int temp = r.b.a; 742 temp = (temp << 1) + (temp >> 7); 743 flags = (flags & (S80 | Z40 | P04)) + 744 (temp & (F20 | F08 | C01)); 745 r.b.a = temp; 746 goto loop; 747 } 748 749 case 0x0F:{// RRCA 750 int temp = r.b.a; 751 flags = (flags & (S80 | Z40 | P04)) + 752 (temp & C01); 753 temp = (temp << 7) + (temp >> 1); 754 flags += temp & (F20 | F08); 755 r.b.a = temp; 756 goto loop; 757 } 758 759 case 0x17:{// RLA 760 int temp = (r.b.a << 1) + (flags & C01); 761 flags = (flags & (S80 | Z40 | P04)) + 762 (temp & (F20 | F08)) + 763 (temp >> 8); 764 r.b.a = temp; 765 goto loop; 766 } 767 768 case 0x1F:{// RRA 769 int temp = (flags << 7) + (r.b.a >> 1); 770 flags = (flags & (S80 | Z40 | P04)) + 771 (temp & (F20 | F08)) + 772 (r.b.a & C01); 773 r.b.a = temp; 774 goto loop; 775 } 776 777 // Misc 778 case 0x2F:{// CPL 779 int temp = ~r.b.a; 780 flags = (flags & (S80 | Z40 | P04 | C01)) + 781 (temp & (F20 | F08)) + 782 (H10 | N02); 783 r.b.a = temp; 784 goto loop; 785 } 786 787 case 0x3F:{// CCF 788 flags = ((flags & (S80 | Z40 | P04 | C01)) ^ C01) + 789 (flags << 4 & H10) + 790 (r.b.a & (F20 | F08)); 791 goto loop; 792 } 793 794 case 0x37: // SCF 795 flags = (flags & (S80 | Z40 | P04)) | C01 + 796 (r.b.a & (F20 | F08)); 797 goto loop; 798 799 case 0xDB: // IN A,(imm) 800 pc++; 801 r.b.a = IN_PORT( (data + r.b.a * 0x100) ); 802 goto loop; 803 804 case 0xE3:{// EX (SP),HL 805 int temp = READ_WORD( sp ); 806 WRITE_WORD( sp, r.w.hl ); 807 r.w.hl = temp; 808 goto loop; 809 } 810 811 case 0xEB: // EX DE,HL 812 EX( r.w.hl, r.w.de ); 813 goto loop; 814 815 case 0xD9: // EXX DE,HL 816 EXX( w.bc ); 817 EXX( w.de ); 818 EXX( w.hl ); 819 goto loop; 820 821 case 0xF3: // DI 822 R.iff1 = 0; 823 R.iff2 = 0; 824 goto loop; 825 826 case 0xFB: // EI 827 R.iff1 = 1; 828 R.iff2 = 1; 829 // TODO: delayed effect 830 goto loop; 831 832 case 0x76: // HALT 833 goto halt; 834 835 //////////////////////////////////////// CB prefix 836 { 837 case 0xCB: 838 pc++; 839 switch ( data ) 840 { 841 842 // Rotate left 843 844 #define RLC( read, write ) {\ 845 int result = read;\ 846 result = BYTE( result << 1 ) + (result >> 7);\ 847 flags = SZ28P( result ) + (result & C01);\ 848 write;\ 849 goto loop;\ 850 } 851 852 case 0x06: // RLC (HL) 853 s_time += 7; 854 data = r.w.hl; 855 rlc_data_addr: RLC(READ_MEM (data),WRITE_MEM (data,result))856 RLC( READ_MEM( data ), WRITE_MEM( data, result ) ) 857 858 CASE7( 00, 01, 02, 03, 04, 05, 07 ):{// RLC r 859 byte& reg = R8( data, 0 ); 860 RLC( reg, reg = result ) 861 } 862 863 #define RL( read, write ) {\ 864 int result = (read << 1) + (flags & C01);\ 865 flags = SZ28PC( result );\ 866 write;\ 867 goto loop;\ 868 } 869 870 case 0x16: // RL (HL) 871 s_time += 7; 872 data = r.w.hl; 873 rl_data_addr: RL(READ_MEM (data),WRITE_MEM (data,result))874 RL( READ_MEM( data ), WRITE_MEM( data, result ) ) 875 876 CASE7( 10, 11, 12, 13, 14, 15, 17 ):{// RL r 877 byte& reg = R8( data, 0x10 ); 878 RL( reg, reg = result ) 879 } 880 881 #define SLA( read, low_bit, write ) {\ 882 int result = (read << 1) + low_bit;\ 883 flags = SZ28PC( result );\ 884 write;\ 885 goto loop;\ 886 } 887 888 case 0x26: // SLA (HL) 889 s_time += 7; 890 data = r.w.hl; 891 sla_data_addr: READ_MEM(data)892 SLA( READ_MEM( data ), 0, WRITE_MEM( data, result ) ) 893 894 CASE7( 20, 21, 22, 23, 24, 25, 27 ):{// SLA r 895 byte& reg = R8( data, 0x20 ); 896 SLA( reg, 0, reg = result ) 897 } 898 899 case 0x36: // SLL (HL) 900 s_time += 7; 901 data = r.w.hl; 902 sll_data_addr: READ_MEM(data)903 SLA( READ_MEM( data ), 1, WRITE_MEM( data, result ) ) 904 905 CASE7( 30, 31, 32, 33, 34, 35, 37 ):{// SLL r 906 byte& reg = R8( data, 0x30 ); 907 SLA( reg, 1, reg = result ) 908 } 909 910 // Rotate right 911 912 #define RRC( read, write ) {\ 913 int result = read;\ 914 flags = result & C01;\ 915 result = BYTE( result << 7 ) + (result >> 1);\ 916 flags += SZ28P( result );\ 917 write;\ 918 goto loop;\ 919 } 920 921 case 0x0E: // RRC (HL) 922 s_time += 7; 923 data = r.w.hl; 924 rrc_data_addr: RRC(READ_MEM (data),WRITE_MEM (data,result))925 RRC( READ_MEM( data ), WRITE_MEM( data, result ) ) 926 927 CASE7( 08, 09, 0A, 0B, 0C, 0D, 0F ):{// RRC r 928 byte& reg = R8( data, 0x08 ); 929 RRC( reg, reg = result ) 930 } 931 932 #define RR( read, write ) {\ 933 int result = read;\ 934 int temp = result & C01;\ 935 result = BYTE( flags << 7 ) + (result >> 1);\ 936 flags = SZ28P( result ) + temp;\ 937 write;\ 938 goto loop;\ 939 } 940 941 case 0x1E: // RR (HL) 942 s_time += 7; 943 data = r.w.hl; 944 rr_data_addr: RR(READ_MEM (data),WRITE_MEM (data,result))945 RR( READ_MEM( data ), WRITE_MEM( data, result ) ) 946 947 CASE7( 18, 19, 1A, 1B, 1C, 1D, 1F ):{// RR r 948 byte& reg = R8( data, 0x18 ); 949 RR( reg, reg = result ) 950 } 951 952 #define SRA( read, write ) {\ 953 int result = read;\ 954 flags = result & C01;\ 955 result = (result & 0x80) + (result >> 1);\ 956 flags += SZ28P( result );\ 957 write;\ 958 goto loop;\ 959 } 960 961 case 0x2E: // SRA (HL) 962 data = r.w.hl; 963 s_time += 7; 964 sra_data_addr: SRA(READ_MEM (data),WRITE_MEM (data,result))965 SRA( READ_MEM( data ), WRITE_MEM( data, result ) ) 966 967 CASE7( 28, 29, 2A, 2B, 2C, 2D, 2F ):{// SRA r 968 byte& reg = R8( data, 0x28 ); 969 SRA( reg, reg = result ) 970 } 971 972 #define SRL( read, write ) {\ 973 int result = read;\ 974 flags = result & C01;\ 975 result >>= 1;\ 976 flags += SZ28P( result );\ 977 write;\ 978 goto loop;\ 979 } 980 981 case 0x3E: // SRL (HL) 982 s_time += 7; 983 data = r.w.hl; 984 srl_data_addr: SRL(READ_MEM (data),WRITE_MEM (data,result))985 SRL( READ_MEM( data ), WRITE_MEM( data, result ) ) 986 987 CASE7( 38, 39, 3A, 3B, 3C, 3D, 3F ):{// SRL r 988 byte& reg = R8( data, 0x38 ); 989 SRL( reg, reg = result ) 990 } 991 992 // BIT 993 { 994 int temp; 995 CASE8( 46, 4E, 56, 5E, 66, 6E, 76, 7E ): // BIT b,(HL) 996 s_time += 4; 997 temp = READ_MEM( r.w.hl ); 998 flags &= C01; 999 goto bit_temp; 1000 CASE7( 40, 41, 42, 43, 44, 45, 47 ): // BIT 0,r 1001 CASE7( 48, 49, 4A, 4B, 4C, 4D, 4F ): // BIT 1,r 1002 CASE7( 50, 51, 52, 53, 54, 55, 57 ): // BIT 2,r 1003 CASE7( 58, 59, 5A, 5B, 5C, 5D, 5F ): // BIT 3,r 1004 CASE7( 60, 61, 62, 63, 64, 65, 67 ): // BIT 4,r 1005 CASE7( 68, 69, 6A, 6B, 6C, 6D, 6F ): // BIT 5,r 1006 CASE7( 70, 71, 72, 73, 74, 75, 77 ): // BIT 6,r 1007 CASE7( 78, 79, 7A, 7B, 7C, 7D, 7F ): // BIT 7,r 1008 temp = R8( data & 7, 0 ); 1009 flags = (flags & C01) + (temp & (F20 | F08)); 1010 bit_temp: 1011 temp = temp & (1 << (data >> 3 & 7)); 1012 flags += (temp & S80) + H10; 1013 flags += (unsigned) --temp >> 8 & (Z40 | P04); 1014 goto loop; 1015 } 1016 1017 // SET/RES 1018 CASE8( 86, 8E, 96, 9E, A6, AE, B6, BE ): // RES b,(HL) CASE8(C6,CE,D6,DE,E6,EE,F6,FE)1019 CASE8( C6, CE, D6, DE, E6, EE, F6, FE ):{// SET b,(HL) 1020 s_time += 7; 1021 int temp = READ_MEM( r.w.hl ); 1022 int bit = 1 << (data >> 3 & 7); 1023 temp |= bit; // SET 1024 if ( !(data & 0x40) ) 1025 temp ^= bit; // RES 1026 WRITE_MEM( r.w.hl, temp ); 1027 goto loop; 1028 } 1029 1030 CASE7( C0, C1, C2, C3, C4, C5, C7 ): // SET 0,r 1031 CASE7( C8, C9, CA, CB, CC, CD, CF ): // SET 1,r 1032 CASE7( D0, D1, D2, D3, D4, D5, D7 ): // SET 2,r 1033 CASE7( D8, D9, DA, DB, DC, DD, DF ): // SET 3,r 1034 CASE7( E0, E1, E2, E3, E4, E5, E7 ): // SET 4,r 1035 CASE7( E8, E9, EA, EB, EC, ED, EF ): // SET 5,r 1036 CASE7( F0, F1, F2, F3, F4, F5, F7 ): // SET 6,r 1037 CASE7( F8, F9, FA, FB, FC, FD, FF ): // SET 7,r 1038 R8( data & 7, 0 ) |= 1 << (data >> 3 & 7); 1039 goto loop; 1040 1041 CASE7( 80, 81, 82, 83, 84, 85, 87 ): // RES 0,r 1042 CASE7( 88, 89, 8A, 8B, 8C, 8D, 8F ): // RES 1,r 1043 CASE7( 90, 91, 92, 93, 94, 95, 97 ): // RES 2,r 1044 CASE7( 98, 99, 9A, 9B, 9C, 9D, 9F ): // RES 3,r 1045 CASE7( A0, A1, A2, A3, A4, A5, A7 ): // RES 4,r 1046 CASE7( A8, A9, AA, AB, AC, AD, AF ): // RES 5,r 1047 CASE7( B0, B1, B2, B3, B4, B5, B7 ): // RES 6,r 1048 CASE7( B8, B9, BA, BB, BC, BD, BF ): // RES 7,r 1049 R8( data & 7, 0 ) &= ~(1 << (data >> 3 & 7)); 1050 goto loop; 1051 } 1052 assert( false ); 1053 } 1054 1055 #undef GET_ADDR 1056 #define GET_ADDR() GET_LE16( &INSTR( 1, pc ) ) 1057 1058 //////////////////////////////////////// ED prefix 1059 { 1060 case 0xED: 1061 pc++; 1062 s_time += (clock_table + 256) [data] >> 4; 1063 switch ( data ) 1064 { 1065 { 1066 int temp; 1067 case 0x72: // SBC HL,SP 1068 case 0x7A: // ADC HL,SP 1069 temp = sp; 1070 if ( 0 ) 1071 case 0x42: // SBC HL,BC 1072 case 0x52: // SBC HL,DE 1073 case 0x62: // SBC HL,HL 1074 case 0x4A: // ADC HL,BC 1075 case 0x5A: // ADC HL,DE 1076 case 0x6A: // ADC HL,HL 1077 temp = R16( data >> 3 & 6, 1, 0 ); 1078 int sum = temp + (flags & C01); 1079 flags = ~data >> 2 & N02; 1080 if ( flags ) 1081 sum = -sum; 1082 sum += r.w.hl; 1083 temp ^= r.w.hl; 1084 temp ^= sum; 1085 flags +=(sum >> 16 & C01) + 1086 (temp >> 8 & H10) + 1087 (sum >> 8 & (S80 | F20 | F08)) + 1088 ((temp + 0x8000) >> 14 & V04); 1089 r.w.hl = sum; 1090 if ( WORD( sum ) ) 1091 goto loop; 1092 flags += Z40; 1093 goto loop; 1094 } 1095 1096 CASE8( 40, 48, 50, 58, 60, 68, 70, 78 ):{// IN r,(C) 1097 int temp = IN_PORT( r.w.bc ); 1098 R8( data >> 3, 8 ) = temp; 1099 flags = (flags & C01) + SZ28P( temp ); 1100 goto loop; 1101 } 1102 1103 case 0x71: // OUT (C),0 1104 r.b.flags = 0; 1105 CASE7( 41, 49, 51, 59, 61, 69, 79 ): // OUT (C),r 1106 OUT_PORT( r.w.bc, R8( data >> 3, 8 ) ); 1107 goto loop; 1108 1109 { 1110 int temp; 1111 case 0x73: // LD (ADDR),SP 1112 temp = sp; 1113 if ( 0 ) 1114 case 0x43: // LD (ADDR),BC 1115 case 0x53: // LD (ADDR),DE 1116 temp = R16( data, 4, 0x43 ); 1117 int addr = GET_ADDR(); 1118 pc += 2; 1119 WRITE_WORD( addr, temp ); 1120 goto loop; 1121 } 1122 1123 case 0x4B: // LD BC,(ADDR) 1124 case 0x5B:{// LD DE,(ADDR) 1125 int addr = GET_ADDR(); 1126 pc += 2; 1127 R16( data, 4, 0x4B ) = READ_WORD( addr ); 1128 goto loop; 1129 } 1130 1131 case 0x7B:{// LD SP,(ADDR) 1132 int addr = GET_ADDR(); 1133 pc += 2; 1134 sp = READ_WORD( addr ); 1135 goto loop; 1136 } 1137 1138 case 0x67:{// RRD 1139 int temp = READ_MEM( r.w.hl ); 1140 WRITE_MEM( r.w.hl, ((r.b.a << 4) + (temp >> 4)) ); 1141 temp = (r.b.a & 0xF0) + (temp & 0x0F); 1142 flags = (flags & C01) + SZ28P( temp ); 1143 r.b.a = temp; 1144 goto loop; 1145 } 1146 1147 case 0x6F:{// RLD 1148 int temp = READ_MEM( r.w.hl ); 1149 WRITE_MEM( r.w.hl, ((temp << 4) + (r.b.a & 0x0F)) ); 1150 temp = (r.b.a & 0xF0) + (temp >> 4); 1151 flags = (flags & C01) + SZ28P( temp ); 1152 r.b.a = temp; 1153 goto loop; 1154 } 1155 1156 CASE8( 44, 4C, 54, 5C, 64, 6C, 74, 7C ): // NEG 1157 opcode = 0x10; // flag to do SBC instead of ADC 1158 flags &= ~C01; 1159 data = r.b.a; 1160 r.b.a = 0; 1161 goto adc_data; 1162 1163 { 1164 int inc; 1165 case 0xA9: // CPD 1166 case 0xB9: // CPDR 1167 inc = -1; 1168 if ( 0 ) 1169 case 0xA1: // CPI 1170 case 0xB1: // CPIR 1171 inc = +1; 1172 int addr = r.w.hl; 1173 r.w.hl = addr + inc; 1174 int temp = READ_MEM( addr ); 1175 1176 int result = r.b.a - temp; 1177 flags = (flags & C01) + N02 + 1178 ((((temp ^ r.b.a) & H10) ^ result) & (S80 | H10)); 1179 1180 if ( !BYTE( result ) ) 1181 flags += Z40; 1182 result -= (flags & H10) >> 4; 1183 flags += result & F08; 1184 flags += result << 4 & F20; 1185 if ( !--r.w.bc ) 1186 goto loop; 1187 1188 flags += V04; 1189 if ( flags & Z40 || data < 0xB0 ) 1190 goto loop; 1191 1192 pc -= 2; 1193 s_time += 5; 1194 goto loop; 1195 } 1196 1197 { 1198 int inc; 1199 case 0xA8: // LDD 1200 case 0xB8: // LDDR 1201 inc = -1; 1202 if ( 0 ) 1203 case 0xA0: // LDI 1204 case 0xB0: // LDIR 1205 inc = +1; 1206 int addr = r.w.hl; 1207 r.w.hl = addr + inc; 1208 int temp = READ_MEM( addr ); 1209 1210 addr = r.w.de; 1211 r.w.de = addr + inc; 1212 WRITE_MEM( addr, temp ); 1213 1214 temp += r.b.a; 1215 flags = (flags & (S80 | Z40 | C01)) + 1216 (temp & F08) + (temp << 4 & F20); 1217 if ( !--r.w.bc ) 1218 goto loop; 1219 1220 flags += V04; 1221 if ( data < 0xB0 ) 1222 goto loop; 1223 1224 pc -= 2; 1225 s_time += 5; 1226 goto loop; 1227 } 1228 1229 { 1230 int inc; 1231 case 0xAB: // OUTD 1232 case 0xBB: // OTDR 1233 inc = -1; 1234 if ( 0 ) 1235 case 0xA3: // OUTI 1236 case 0xB3: // OTIR 1237 inc = +1; 1238 int addr = r.w.hl; 1239 r.w.hl = addr + inc; 1240 int temp = READ_MEM( addr ); 1241 1242 int b = --r.b.b; 1243 flags = (temp >> 6 & N02) + SZ28( b ); 1244 if ( b && data >= 0xB0 ) 1245 { 1246 pc -= 2; 1247 s_time += 5; 1248 } 1249 1250 OUT_PORT( r.w.bc, temp ); 1251 goto loop; 1252 } 1253 1254 { 1255 int inc; 1256 case 0xAA: // IND 1257 case 0xBA: // INDR 1258 inc = -1; 1259 if ( 0 ) 1260 case 0xA2: // INI 1261 case 0xB2: // INIR 1262 inc = +1; 1263 1264 int addr = r.w.hl; 1265 r.w.hl = addr + inc; 1266 1267 int temp = IN_PORT( r.w.bc ); 1268 1269 int b = --r.b.b; 1270 flags = (temp >> 6 & N02) + SZ28( b ); 1271 if ( b && data >= 0xB0 ) 1272 { 1273 pc -= 2; 1274 s_time += 5; 1275 } 1276 1277 WRITE_MEM( addr, temp ); 1278 goto loop; 1279 } 1280 1281 case 0x47: // LD I,A 1282 R.i = r.b.a; 1283 goto loop; 1284 1285 case 0x4F: // LD R,A 1286 SET_R( r.b.a ); 1287 dprintf( "LD R,A not supported\n" ); 1288 warning = true; 1289 goto loop; 1290 1291 case 0x57: // LD A,I 1292 r.b.a = R.i; 1293 goto ld_ai_common; 1294 1295 case 0x5F: // LD A,R 1296 r.b.a = GET_R(); 1297 dprintf( "LD A,R not supported\n" ); 1298 warning = true; 1299 ld_ai_common: 1300 flags = (flags & C01) + SZ28( r.b.a ) + (R.iff2 << 2 & V04); 1301 goto loop; 1302 1303 CASE8( 45, 4D, 55, 5D, 65, 6D, 75, 7D ): // RETI/RETN 1304 R.iff1 = R.iff2; 1305 goto ret_taken; 1306 1307 case 0x46: case 0x4E: case 0x66: case 0x6E: // IM 0 1308 R.im = 0; 1309 goto loop; 1310 1311 case 0x56: case 0x76: // IM 1 1312 R.im = 1; 1313 goto loop; 1314 1315 case 0x5E: case 0x7E: // IM 2 1316 R.im = 2; 1317 goto loop; 1318 1319 default: 1320 dprintf( "Opcode $ED $%02X not supported\n", data ); 1321 warning = true; 1322 goto loop; 1323 } 1324 assert( false ); 1325 } 1326 1327 //////////////////////////////////////// DD/FD prefix 1328 { 1329 int ixy; 1330 case 0xDD: 1331 ixy = ix; 1332 goto ix_prefix; 1333 case 0xFD: 1334 ixy = iy; 1335 ix_prefix: 1336 pc++; 1337 int data2 = READ_CODE( pc ); 1338 s_time += (clock_table + 256) [data] & 0x0F; 1339 switch ( data ) 1340 { 1341 // TODO: more efficient way of avoid negative address 1342 // TODO: avoid using this as argument to READ_MEM() since it is evaluated twice 1343 #define IXY_DISP( ixy, disp ) WORD( (ixy ) + (disp)) 1344 1345 #define SET_IXY( in ) if ( opcode == 0xDD ) ix = in; else iy = in; 1346 1347 // ADD/ADC/SUB/SBC 1348 1349 case 0x96: // SUB (IXY+disp) 1350 case 0x86: // ADD (IXY+disp) 1351 flags &= ~C01; 1352 case 0x9E: // SBC (IXY+disp) 1353 case 0x8E: // ADC (IXY+disp) 1354 pc++; 1355 opcode = data; 1356 data = READ_MEM( IXY_DISP( ixy, SBYTE( data2 ) ) ); 1357 goto adc_data; 1358 1359 case 0x94: // SUB HXY 1360 case 0x84: // ADD HXY 1361 flags &= ~C01; 1362 case 0x9C: // SBC HXY 1363 case 0x8C: // ADC HXY 1364 opcode = data; 1365 data = ixy >> 8; 1366 goto adc_data; 1367 1368 case 0x95: // SUB LXY 1369 case 0x85: // ADD LXY 1370 flags &= ~C01; 1371 case 0x9D: // SBC LXY 1372 case 0x8D: // ADC LXY 1373 opcode = data; 1374 data = BYTE( ixy ); 1375 goto adc_data; 1376 1377 { 1378 int temp; 1379 case 0x39: // ADD IXY,SP 1380 temp = sp; 1381 goto add_ixy_data; 1382 1383 case 0x29: // ADD IXY,HL 1384 temp = ixy; 1385 goto add_ixy_data; 1386 1387 case 0x09: // ADD IXY,BC 1388 case 0x19: // ADD IXY,DE 1389 temp = R16( data, 4, 0x09 ); 1390 add_ixy_data: { 1391 int sum = ixy + temp; 1392 temp ^= ixy; 1393 ixy = WORD( sum ); 1394 flags = (flags & (S80 | Z40 | V04)) + 1395 (sum >> 16) + 1396 (sum >> 8 & (F20 | F08)) + 1397 ((temp ^ sum) >> 8 & H10); 1398 goto set_ixy; 1399 } 1400 } 1401 1402 // AND 1403 case 0xA6: // AND (IXY+disp) 1404 pc++; 1405 data = READ_MEM( IXY_DISP( ixy, SBYTE( data2 ) ) ); 1406 goto and_data; 1407 1408 case 0xA4: // AND HXY 1409 data = ixy >> 8; 1410 goto and_data; 1411 1412 case 0xA5: // AND LXY 1413 data = BYTE( ixy ); 1414 goto and_data; 1415 1416 // OR 1417 case 0xB6: // OR (IXY+disp) 1418 pc++; 1419 data = READ_MEM( IXY_DISP( ixy, SBYTE( data2 ) ) ); 1420 goto or_data; 1421 1422 case 0xB4: // OR HXY 1423 data = ixy >> 8; 1424 goto or_data; 1425 1426 case 0xB5: // OR LXY 1427 data = BYTE( ixy ); 1428 goto or_data; 1429 1430 // XOR 1431 case 0xAE: // XOR (IXY+disp) 1432 pc++; 1433 data = READ_MEM( IXY_DISP( ixy, SBYTE( data2 ) ) ); 1434 goto xor_data; 1435 1436 case 0xAC: // XOR HXY 1437 data = ixy >> 8; 1438 goto xor_data; 1439 1440 case 0xAD: // XOR LXY 1441 data = BYTE( ixy ); 1442 goto xor_data; 1443 1444 // CP 1445 case 0xBE: // CP (IXY+disp) 1446 pc++; 1447 data = READ_MEM( IXY_DISP( ixy, SBYTE( data2 ) ) ); 1448 goto cp_data; 1449 1450 case 0xBC: // CP HXY 1451 data = ixy >> 8; 1452 goto cp_data; 1453 1454 case 0xBD: // CP LXY 1455 data = BYTE( ixy ); 1456 goto cp_data; 1457 1458 // LD 1459 CASE7( 70, 71, 72, 73, 74, 75, 77 ): // LD (IXY+disp),r 1460 data = R8( data, 0x70 ); 1461 if ( 0 ) 1462 case 0x36: // LD (IXY+disp),imm 1463 pc++, data = READ_CODE( pc ); 1464 pc++; 1465 WRITE_MEM( IXY_DISP( ixy, SBYTE( data2 ) ), data ); 1466 goto loop; 1467 1468 CASE5( 44, 4C, 54, 5C, 7C ): // LD r,HXY 1469 R8( data >> 3, 8 ) = ixy >> 8; 1470 goto loop; 1471 1472 case 0x64: // LD HXY,HXY 1473 case 0x6D: // LD LXY,LXY 1474 goto loop; 1475 1476 CASE5( 45, 4D, 55, 5D, 7D ): // LD r,LXY 1477 R8( data >> 3, 8 ) = ixy; 1478 goto loop; 1479 1480 CASE7( 46, 4E, 56, 5E, 66, 6E, 7E ): // LD r,(IXY+disp) 1481 pc++; 1482 R8( data >> 3, 8 ) = READ_MEM( IXY_DISP( ixy, SBYTE( data2 ) ) ); 1483 goto loop; 1484 1485 case 0x26: // LD HXY,imm 1486 pc++; 1487 goto ld_hxy_data; 1488 1489 case 0x65: // LD HXY,LXY 1490 data2 = BYTE( ixy ); 1491 goto ld_hxy_data; 1492 1493 CASE5( 60, 61, 62, 63, 67 ): // LD HXY,r 1494 data2 = R8( data, 0x60 ); 1495 ld_hxy_data: 1496 ixy = BYTE( ixy ) + (data2 << 8); 1497 goto set_ixy; 1498 1499 case 0x2E: // LD LXY,imm 1500 pc++; 1501 goto ld_lxy_data; 1502 1503 case 0x6C: // LD LXY,HXY 1504 data2 = ixy >> 8; 1505 goto ld_lxy_data; 1506 1507 CASE5( 68, 69, 6A, 6B, 6F ): // LD LXY,r 1508 data2 = R8( data, 0x68 ); 1509 ld_lxy_data: 1510 ixy = (ixy & 0xFF00) + data2; 1511 set_ixy: 1512 if ( opcode == 0xDD ) 1513 { 1514 ix = ixy; 1515 goto loop; 1516 } 1517 iy = ixy; 1518 goto loop; 1519 1520 case 0xF9: // LD SP,IXY 1521 sp = ixy; 1522 goto loop; 1523 1524 case 0x22:{// LD (ADDR),IXY 1525 int addr = GET_ADDR(); 1526 pc += 2; 1527 WRITE_WORD( addr, ixy ); 1528 goto loop; 1529 } 1530 1531 case 0x21: // LD IXY,imm 1532 ixy = GET_ADDR(); 1533 pc += 2; 1534 goto set_ixy; 1535 1536 case 0x2A:{// LD IXY,(addr) 1537 int addr = GET_ADDR(); 1538 ixy = READ_WORD( addr ); 1539 pc += 2; 1540 goto set_ixy; 1541 } 1542 1543 // DD/FD CB prefix 1544 case 0xCB: { 1545 data = IXY_DISP( ixy, SBYTE( data2 ) ); 1546 pc++; 1547 data2 = READ_CODE( pc ); 1548 pc++; 1549 switch ( data2 ) 1550 { 1551 case 0x06: goto rlc_data_addr; // RLC (IXY) 1552 case 0x16: goto rl_data_addr; // RL (IXY) 1553 case 0x26: goto sla_data_addr; // SLA (IXY) 1554 case 0x36: goto sll_data_addr; // SLL (IXY) 1555 case 0x0E: goto rrc_data_addr; // RRC (IXY) 1556 case 0x1E: goto rr_data_addr; // RR (IXY) 1557 case 0x2E: goto sra_data_addr; // SRA (IXY) 1558 case 0x3E: goto srl_data_addr; // SRL (IXY) 1559 1560 CASE8( 46, 4E, 56, 5E, 66, 6E, 76, 7E ):{// BIT b,(IXY+disp) 1561 int temp = READ_MEM( data ); 1562 temp = temp & (1 << (data2 >> 3 & 7)); 1563 flags = (flags & C01) + H10 + (temp & S80); 1564 flags += (unsigned) --temp >> 8 & (Z40 | P04); 1565 goto loop; 1566 } 1567 1568 CASE8( 86, 8E, 96, 9E, A6, AE, B6, BE ): // RES b,(IXY+disp) CASE8(C6,CE,D6,DE,E6,EE,F6,FE)1569 CASE8( C6, CE, D6, DE, E6, EE, F6, FE ):{// SET b,(IXY+disp) 1570 int temp = READ_MEM( data ); 1571 int bit = 1 << (data2 >> 3 & 7); 1572 temp |= bit; // SET 1573 if ( !(data2 & 0x40) ) 1574 temp ^= bit; // RES 1575 WRITE_MEM( data, temp ); 1576 goto loop; 1577 } 1578 1579 default: 1580 dprintf( "Opcode $%02X $CB $%02X not supported\n", opcode, data2 ); 1581 warning = true; 1582 goto loop; 1583 } 1584 assert( false ); 1585 } 1586 1587 // INC/DEC 1588 case 0x23: // INC IXY 1589 ixy = WORD( ixy + 1 ); 1590 goto set_ixy; 1591 1592 case 0x2B: // DEC IXY 1593 ixy = WORD( ixy - 1 ); 1594 goto set_ixy; 1595 1596 case 0x34: // INC (IXY+disp) 1597 ixy = IXY_DISP( ixy, SBYTE( data2 ) ); 1598 pc++; 1599 data = READ_MEM( ixy ) + 1; 1600 WRITE_MEM( ixy, data ); 1601 goto inc_set_flags; 1602 1603 case 0x35: // DEC (IXY+disp) 1604 ixy = IXY_DISP( ixy, SBYTE( data2 ) ); 1605 pc++; 1606 data = READ_MEM( ixy ) - 1; 1607 WRITE_MEM( ixy, data ); 1608 goto dec_set_flags; 1609 1610 case 0x24: // INC HXY 1611 ixy = WORD( ixy + 0x100 ); 1612 data = ixy >> 8; 1613 goto inc_xy_common; 1614 1615 case 0x2C: // INC LXY 1616 data = BYTE( ixy + 1 ); 1617 ixy = (ixy & 0xFF00) + data; 1618 inc_xy_common: 1619 if ( opcode == 0xDD ) 1620 { 1621 ix = ixy; 1622 goto inc_set_flags; 1623 } 1624 iy = ixy; 1625 goto inc_set_flags; 1626 1627 case 0x25: // DEC HXY 1628 ixy = WORD( ixy - 0x100 ); 1629 data = ixy >> 8; 1630 goto dec_xy_common; 1631 1632 case 0x2D: // DEC LXY 1633 data = BYTE( ixy - 1 ); 1634 ixy = (ixy & 0xFF00) + data; 1635 dec_xy_common: 1636 if ( opcode == 0xDD ) 1637 { 1638 ix = ixy; 1639 goto dec_set_flags; 1640 } 1641 iy = ixy; 1642 goto dec_set_flags; 1643 1644 // PUSH/POP 1645 case 0xE5: // PUSH IXY 1646 data = ixy; 1647 goto push_data; 1648 1649 case 0xE1:{// POP IXY 1650 ixy = READ_WORD( sp ); 1651 sp = WORD( sp + 2 ); 1652 goto set_ixy; 1653 } 1654 1655 // Misc 1656 1657 case 0xE9: // JP (IXY) 1658 pc = ixy; 1659 goto loop; 1660 1661 case 0xE3:{// EX (SP),IXY 1662 int temp = READ_WORD( sp ); 1663 WRITE_WORD( sp, ixy ); 1664 ixy = temp; 1665 goto set_ixy; 1666 } 1667 1668 default: 1669 dprintf( "Unnecessary DD/FD prefix encountered\n" ); 1670 warning = true; 1671 pc--; 1672 goto loop; 1673 } 1674 assert( false ); 1675 } 1676 1677 } 1678 dprintf( "Unhandled main opcode: $%02X\n", opcode ); 1679 assert( false ); 1680 1681 #ifdef IDLE_ADDR 1682 hit_idle_addr: 1683 s_time -= 11; 1684 goto out_of_time; 1685 #endif 1686 halt: 1687 s_time &= 3; // increment by multiple of 4 1688 out_of_time: 1689 pc--; 1690 1691 r.b.flags = flags; 1692 R.ix = ix; 1693 R.iy = iy; 1694 R.sp = sp; 1695 R.pc = pc; 1696 R.b = r.b; 1697 1698 CPU.cpu_state_.base = s.base; 1699 CPU.cpu_state_.time = s_time; 1700 CPU.cpu_state = &CPU.cpu_state_; 1701 } 1702