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