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.
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
31 // The following can be used within macros:
36 // Allows use of time functions
39 // Must be used before end of macro if FLUSH_TIME() was used earlier
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() {
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 */
72 // flags, named with hex value for clarity
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)
92 #define TIME() (s_time + s.base)
93 #define FLUSH_TIME() {s.time = s_time;}
94 #define CACHE_TIME() {s_time = s.time;}
97 #define RW_MEM( addr, rw ) RW_PAGE( addr, rw ) [RW_OFFSET( addr )]
98 #define READ_CODE( addr ) RW_MEM( addr, read )
101 #define RW_PAGE( addr, rw ) FLAT_MEM
102 #define RW_OFFSET( addr ) (addr)
103 #define INSTR( off, addr ) READ_CODE( addr )
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]
111 #define READ_MEM( addr ) RW_MEM( addr, read )
115 #define WRITE_MEM( addr, data ) (RW_MEM( addr, write ) = data)
118 #define READ_WORD( addr ) GET_LE16( &RW_MEM( addr, read ) )
119 #define WRITE_WORD( addr, data ) SET_LE16( &RW_MEM( addr, write ), data )
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 */
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])
137 #error "Byte order of CPU must be known"
140 #define R16( n, shift, offset ) (r.r16_ [((unsigned) (n) >> shift) - (offset >> shift)])
149 #define EXX( name ) \
150 EX( R.alt.name, r.name )
152 bool warning
= false;
154 struct cpu_state_t s
;
156 s
.base
= cpu
->cpu_state_
.base
;
166 byte r8_
[8]; // indexed
171 cpu_time_t s_time
= cpu
->cpu_state_
.time
;
174 int ix
= R
.ix
; // TODO: keep in memory for direct access?
176 int flags
= R
.b
.flags
;
178 //goto loop; // confuses optimizer
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
);
198 if ( RW_OFFSET( ~0 ) == ~0 )
200 opcode
= instr
[RW_OFFSET( pc
)];
202 instr
+= RW_OFFSET( pc
);
206 instr
+= RW_OFFSET( 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,
252 s_time
+= clock_table
[opcode
];
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
);
261 #define GET_ADDR() GET_LE16( &INSTR( 0, pc ) )
264 data
= INSTR( 0, pc
);
271 CASE7( 40, 49, 52, 5B
, 64, 6D
, 7F
): // LD B,B etc.
274 case 0x08:{// EX AF,AF'
276 EX( R
.alt
.b
.flags
, flags
);
280 case 0xD3: // OUT (imm),A
282 OUT_PORT( (data
+ r
.b
.a
* 0x100), r
.b
.a
);
285 case 0x2E: // LD L,imm
290 case 0x3E: // LD A,imm
295 case 0x3A:{// LD A,(addr)
296 int addr
= GET_ADDR();
298 r
.b
.a
= READ_MEM( addr
);
304 #define ZERO (flags & Z40)
305 #define CARRY (flags & C01)
306 #define EVEN (flags & P04)
307 #define MINUS (flags & S80)
310 // TODO: more efficient way to handle negative branch that wraps PC around
311 #define JR_( cond, clocks ) {\
315 int offset = SBYTE( data );\
316 pc = WORD( pc + offset );\
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;
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
360 #define RET( cond ) \
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
377 pc
= READ_WORD( sp
);
382 #define CALL( cond ) \
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
401 WRITE_WORD( sp
, addr
);
408 if ( pc
== IDLE_ADDR
+ 1 )
418 CASE7( C7
, CF
, D7
, DF
, E7
, EF
, F7
):
427 case 0xF5: // PUSH AF
428 data
= r
.b
.a
* 0x100u
+ flags
;
431 case 0xC5: // PUSH BC
432 case 0xD5: // PUSH DE
433 case 0xE5: // PUSH HL
434 data
= R16( opcode
, 4, 0xC5 );
437 WRITE_WORD( sp
, data
);
441 flags
= READ_MEM( sp
);
442 r
.b
.a
= READ_MEM( (sp
+ 1) );
449 R16( opcode
, 4, 0xC1 ) = READ_WORD( sp
);
454 case 0x96: // SUB (HL)
455 case 0x86: // ADD (HL)
457 case 0x9E: // SBC (HL)
458 case 0x8E: // ADC (HL)
459 data
= READ_MEM( r
.w
.hl
);
462 case 0xD6: // SUB A,imm
463 case 0xC6: // ADD imm
465 case 0xDE: // SBC A,imm
466 case 0xCE: // ADC imm
470 CASE7( 90, 91, 92, 93, 94, 95, 97 ): // SUB r
471 CASE7( 80, 81, 82, 83, 84, 85, 87 ): // ADD r
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 );
477 int result
= data
+ (flags
& C01
);
479 flags
= opcode
>> 3 & N02
; // bit 4 is set in subtract opcodes
484 flags
+=(data
& H10
) +
485 ((data
+ 0x80) >> 6 & V04
) +
486 SZ28C( result
& 0x1FF );
492 case 0xBE: // CP (HL)
493 data
= READ_MEM( r
.w
.hl
);
500 CASE7( B8
, B9
, BA
, BB
, BC
, BD
, BF
): // CP r
501 data
= R8( opcode
, 0xB8 );
503 int result
= r
.b
.a
- data
;
504 flags
= N02
+ (data
& (F20
| F08
)) + (result
>> 8 & C01
);
506 flags
+=(((result
^ r
.b
.a
) & data
) >> 5 & V04
) +
507 (((data
& H10
) ^ result
) & (S80
| H10
));
508 if ( BYTE( result
) )
516 case 0x39: // ADD HL,SP
520 case 0x09: // ADD HL,BC
521 case 0x19: // ADD HL,DE
522 case 0x29: // ADD HL,HL
523 data
= R16( opcode
, 4, 0x09 );
525 int sum
= r
.w
.hl
+ data
;
528 flags
= (flags
& (S80
| Z40
| V04
)) +
530 (sum
>> 8 & (F20
| F08
)) +
531 ((data
^ sum
) >> 8 & H10
);
540 int adjust
= 0x60 * (flags
& C01
);
542 if ( flags
& H10
|| (a
& 0x0F) > 9 )
549 flags
= (flags
& (C01
| N02
)) +
550 ((r
.b
.a
^ a
) & H10
) +
557 case 0x34: // INC (HL)
558 data
= READ_MEM( r
.w
.hl
) + 1;
559 WRITE_MEM( r
.w
.hl
, data
);
562 CASE7( 04, 0C
, 14, 1C
, 24, 2C
, 3C
): // INC r
563 data
= ++R8( opcode
>> 3, 0 );
565 flags
= (flags
& C01
) +
566 (((data
& 0x0F) - 1) & H10
) +
567 SZ28( BYTE( data
) );
573 case 0x35: // DEC (HL)
574 data
= READ_MEM( r
.w
.hl
) - 1;
575 WRITE_MEM( r
.w
.hl
, data
);
578 CASE7( 05, 0D
, 15, 1D
, 25, 2D
, 3D
): // DEC r
579 data
= --R8( opcode
>> 3, 0 );
581 flags
= (flags
& C01
) + N02
+
582 (((data
& 0x0F) + 1) & H10
) +
583 SZ28( BYTE( data
) );
592 R16( opcode
, 4, 0x03 )++;
602 R16( opcode
, 4, 0x0B )--;
610 case 0xA6: // AND (HL)
611 data
= READ_MEM( r
.w
.hl
);
614 case 0xE6: // AND imm
618 CASE7( A0
, A1
, A2
, A3
, A4
, A5
, A7
): // AND r
619 data
= R8( opcode
, 0xA0 );
622 flags
= SZ28P( r
.b
.a
) + H10
;
626 case 0xB6: // OR (HL)
627 data
= READ_MEM( r
.w
.hl
);
634 CASE7( B0
, B1
, B2
, B3
, B4
, B5
, B7
): // OR r
635 data
= R8( opcode
, 0xB0 );
638 flags
= SZ28P( r
.b
.a
);
642 case 0xAE: // XOR (HL)
643 data
= READ_MEM( r
.w
.hl
);
646 case 0xEE: // XOR imm
650 CASE7( A8
, A9
, AA
, AB
, AC
, AD
, AF
): // XOR r
651 data
= R8( opcode
, 0xA8 );
654 flags
= SZ28P( r
.b
.a
);
658 CASE7( 70, 71, 72, 73, 74, 75, 77 ): // LD (HL),r
659 WRITE_MEM( r
.w
.hl
, R8( opcode
, 0x70 ) );
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 );
672 CASE5( 06, 0E
, 16, 1E
, 26 ): // LD r,imm
673 R8( opcode
>> 3, 0 ) = data
;
677 case 0x36: // LD (HL),imm
679 WRITE_MEM( r
.w
.hl
, data
);
682 CASE7( 46, 4E
, 56, 5E
, 66, 6E
, 7E
): // LD r,(HL)
683 R8( opcode
>> 3, 8 ) = READ_MEM( r
.w
.hl
);
686 case 0x01: // LD r.w,imm
689 R16( opcode
, 4, 0x01 ) = GET_ADDR();
693 case 0x31: // LD sp,imm
698 case 0x2A:{// LD HL,(addr)
699 int addr
= GET_ADDR();
701 r
.w
.hl
= READ_WORD( addr
);
705 case 0x32:{// LD (addr),A
706 int addr
= GET_ADDR();
708 WRITE_MEM( addr
, r
.b
.a
);
712 case 0x22:{// LD (addr),HL
713 int addr
= GET_ADDR();
715 WRITE_WORD( addr
, r
.w
.hl
);
719 case 0x02: // LD (BC),A
720 case 0x12: // LD (DE),A
721 WRITE_MEM( R16( opcode
, 4, 0x02 ), r
.b
.a
);
724 case 0x0A: // LD A,(BC)
725 case 0x1A: // LD A,(DE)
726 r
.b
.a
= READ_MEM( R16( opcode
, 4, 0x0A ) );
729 case 0xF9: // LD SP,HL
737 temp
= (temp
<< 1) + (temp
>> 7);
738 flags
= (flags
& (S80
| Z40
| P04
)) +
739 (temp
& (F20
| F08
| C01
));
746 flags
= (flags
& (S80
| Z40
| P04
)) +
748 temp
= (temp
<< 7) + (temp
>> 1);
749 flags
+= temp
& (F20
| F08
);
755 int temp
= (r
.b
.a
<< 1) + (flags
& C01
);
756 flags
= (flags
& (S80
| Z40
| P04
)) +
757 (temp
& (F20
| F08
)) +
764 int temp
= (flags
<< 7) + (r
.b
.a
>> 1);
765 flags
= (flags
& (S80
| Z40
| P04
)) +
766 (temp
& (F20
| F08
)) +
775 flags
= (flags
& (S80
| Z40
| P04
| C01
)) +
776 (temp
& (F20
| F08
)) +
783 flags
= ((flags
& (S80
| Z40
| P04
| C01
)) ^ C01
) +
785 (r
.b
.a
& (F20
| F08
));
790 flags
= ((flags
& (S80
| Z40
| P04
)) | C01
) +
791 (r
.b
.a
& (F20
| F08
));
794 case 0xDB: // IN A,(imm)
796 r
.b
.a
= IN_PORT( (data
+ r
.b
.a
* 0x100) );
799 case 0xE3:{// EX (SP),HL
800 int temp
= READ_WORD( sp
);
801 WRITE_WORD( sp
, r
.w
.hl
);
806 case 0xEB: // EX DE,HL
807 EX( r
.w
.hl
, r
.w
.de
);
810 case 0xD9: // EXX DE,HL
824 // TODO: delayed effect
830 //////////////////////////////////////// CB prefix
839 #define RLC( read, write ) {\
841 result = BYTE( result << 1 ) + (result >> 7);\
842 flags = SZ28P( result ) + (result & C01);\
847 case 0x06: // RLC (HL)
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 );\
865 case 0x16: // RL (HL)
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 );\
883 case 0x26: // SLA (HL)
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)
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
)
907 #define RRC( read, write ) {\
909 flags = result & C01;\
910 result = BYTE( result << 7 ) + (result >> 1);\
911 flags += SZ28P( result );\
916 case 0x0E: // RRC (HL)
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 ) {\
929 int temp = result & C01;\
930 result = BYTE( flags << 7 ) + (result >> 1);\
931 flags = SZ28P( result ) + temp;\
936 case 0x1E: // RR (HL)
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 ) {\
949 flags = result & C01;\
950 result = (result & 0x80) + (result >> 1);\
951 flags += SZ28P( result );\
956 case 0x2E: // SRA (HL)
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 ) {\
969 flags = result & C01;\
971 flags += SZ28P( result );\
976 case 0x3E: // SRL (HL)
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
)
990 CASE8( 46, 4E
, 56, 5E
, 66, 6E
, 76, 7E
): // BIT b,(HL)
992 temp
= READ_MEM( r
.w
.hl
);
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
));
1006 temp
= temp
& (1 << (data
>> 3 & 7));
1007 flags
+= (temp
& S80
) + H10
;
1008 flags
+= (unsigned) --temp
>> 8 & (Z40
| P04
);
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)
1016 int temp
= READ_MEM( r
.w
.hl
);
1017 int bit
= 1 << (data
>> 3 & 7);
1019 if ( !(data
& 0x40) )
1021 WRITE_MEM( r
.w
.hl
, temp
);
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);
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));
1051 #define GET_ADDR() GET_LE16( &INSTR( 1, pc ) )
1053 //////////////////////////////////////// ED prefix
1057 s_time
+= (clock_table
+ 256) [data
] >> 4;
1062 case 0x72: // SBC HL,SP
1063 case 0x7A: // ADC HL,SP
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
;
1080 flags
+=(sum
>> 16 & C01
) +
1082 (sum
>> 8 & (S80
| F20
| F08
)) +
1083 ((temp
+ 0x8000) >> 14 & V04
);
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
);
1098 case 0x71: // OUT (C),0
1100 CASE7( 41, 49, 51, 59, 61, 69, 79 ): // OUT (C),r
1101 OUT_PORT( r
.w
.bc
, R8( data
>> 3, 8 ) );
1106 case 0x73: // LD (ADDR),SP
1109 case 0x43: // LD (ADDR),BC
1110 case 0x53: // LD (ADDR),DE
1111 temp
= R16( data
, 4, 0x43 );
1112 int addr
= GET_ADDR();
1114 WRITE_WORD( addr
, temp
);
1118 case 0x4B: // LD BC,(ADDR)
1119 case 0x5B:{// LD DE,(ADDR)
1120 int addr
= GET_ADDR();
1122 R16( data
, 4, 0x4B ) = READ_WORD( addr
);
1126 case 0x7B:{// LD SP,(ADDR)
1127 int addr
= GET_ADDR();
1129 sp
= READ_WORD( addr
);
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
);
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
);
1151 CASE8( 44, 4C
, 54, 5C
, 64, 6C
, 74, 7C
): // NEG
1152 opcode
= 0x10; // flag to do SBC instead of ADC
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
) )
1177 result
-= (flags
& H10
) >> 4;
1178 flags
+= result
& F08
;
1179 flags
+= result
<< 4 & F20
;
1184 if ( flags
& Z40
|| data
< 0xB0 )
1202 r
.w
.hl
= addr
+ inc
;
1203 int temp
= READ_MEM( addr
);
1206 r
.w
.de
= addr
+ inc
;
1207 WRITE_MEM( addr
, temp
);
1210 flags
= (flags
& (S80
| Z40
| C01
)) +
1211 (temp
& F08
) + (temp
<< 4 & F20
);
1234 r
.w
.hl
= addr
+ inc
;
1235 int temp
= READ_MEM( addr
);
1238 flags
= (temp
>> 6 & N02
) + SZ28( b
);
1239 if ( b
&& data
>= 0xB0 )
1245 OUT_PORT( r
.w
.bc
, temp
);
1260 r
.w
.hl
= addr
+ inc
;
1262 int temp
= IN_PORT( r
.w
.bc
);
1265 flags
= (temp
>> 6 & N02
) + SZ28( b
);
1266 if ( b
&& data
>= 0xB0 )
1272 WRITE_MEM( addr
, temp
);
1276 case 0x47: // LD I,A
1280 case 0x4F: // LD R,A
1282 dprintf( "LD R,A not supported\n" );
1286 case 0x57: // LD A,I
1290 case 0x5F: // LD A,R
1292 dprintf( "LD A,R not supported\n" );
1295 flags
= (flags
& C01
) + SZ28( r
.b
.a
) + (R
.iff2
<< 2 & V04
);
1298 CASE8( 45, 4D
, 55, 5D
, 65, 6D
, 75, 7D
): // RETI/RETN
1302 case 0x46: case 0x4E: case 0x66: case 0x6E: // IM 0
1306 case 0x56: case 0x76: // IM 1
1310 case 0x5E: case 0x7E: // IM 2
1315 dprintf( "Opcode $ED $%02X not supported\n", data
);
1322 //////////////////////////////////////// DD/FD prefix
1332 int data2
= READ_CODE( pc
);
1333 s_time
+= (clock_table
+ 256) [data
] & 0x0F;
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;
1344 case 0x96: // SUB (IXY+disp)
1345 case 0x86: // ADD (IXY+disp)
1347 case 0x9E: // SBC (IXY+disp)
1348 case 0x8E: // ADC (IXY+disp)
1351 data
= READ_MEM( IXY_DISP( ixy
, SBYTE( data2
) ) );
1354 case 0x94: // SUB HXY
1355 case 0x84: // ADD HXY
1357 case 0x9C: // SBC HXY
1358 case 0x8C: // ADC HXY
1363 case 0x95: // SUB LXY
1364 case 0x85: // ADD LXY
1366 case 0x9D: // SBC LXY
1367 case 0x8D: // ADC LXY
1374 case 0x39: // ADD IXY,SP
1378 case 0x29: // ADD IXY,HL
1382 case 0x09: // ADD IXY,BC
1383 case 0x19: // ADD IXY,DE
1384 temp
= R16( data
, 4, 0x09 );
1386 int sum
= ixy
+ temp
;
1389 flags
= (flags
& (S80
| Z40
| V04
)) +
1391 (sum
>> 8 & (F20
| F08
)) +
1392 ((temp
^ sum
) >> 8 & H10
);
1398 case 0xA6: // AND (IXY+disp)
1400 data
= READ_MEM( IXY_DISP( ixy
, SBYTE( data2
) ) );
1403 case 0xA4: // AND HXY
1407 case 0xA5: // AND LXY
1412 case 0xB6: // OR (IXY+disp)
1414 data
= READ_MEM( IXY_DISP( ixy
, SBYTE( data2
) ) );
1417 case 0xB4: // OR HXY
1421 case 0xB5: // OR LXY
1426 case 0xAE: // XOR (IXY+disp)
1428 data
= READ_MEM( IXY_DISP( ixy
, SBYTE( data2
) ) );
1431 case 0xAC: // XOR HXY
1435 case 0xAD: // XOR LXY
1440 case 0xBE: // CP (IXY+disp)
1442 data
= READ_MEM( IXY_DISP( ixy
, SBYTE( data2
) ) );
1445 case 0xBC: // CP HXY
1449 case 0xBD: // CP LXY
1454 CASE7( 70, 71, 72, 73, 74, 75, 77 ): // LD (IXY+disp),r
1455 data
= R8( data
, 0x70 );
1457 case 0x36: // LD (IXY+disp),imm
1458 pc
++, data
= READ_CODE( pc
);
1460 WRITE_MEM( IXY_DISP( ixy
, SBYTE( data2
) ), data
);
1463 CASE5( 44, 4C
, 54, 5C
, 7C
): // LD r,HXY
1464 R8( data
>> 3, 8 ) = ixy
>> 8;
1467 case 0x64: // LD HXY,HXY
1468 case 0x6D: // LD LXY,LXY
1471 CASE5( 45, 4D
, 55, 5D
, 7D
): // LD r,LXY
1472 R8( data
>> 3, 8 ) = ixy
;
1475 CASE7( 46, 4E
, 56, 5E
, 66, 6E
, 7E
): // LD r,(IXY+disp)
1477 R8( data
>> 3, 8 ) = READ_MEM( IXY_DISP( ixy
, SBYTE( data2
) ) );
1480 case 0x26: // LD HXY,imm
1484 case 0x65: // LD HXY,LXY
1485 data2
= BYTE( ixy
);
1488 CASE5( 60, 61, 62, 63, 67 ): // LD HXY,r
1489 data2
= R8( data
, 0x60 );
1491 ixy
= BYTE( ixy
) + (data2
<< 8);
1494 case 0x2E: // LD LXY,imm
1498 case 0x6C: // LD LXY,HXY
1502 CASE5( 68, 69, 6A
, 6B
, 6F
): // LD LXY,r
1503 data2
= R8( data
, 0x68 );
1505 ixy
= (ixy
& 0xFF00) + data2
;
1507 if ( opcode
== 0xDD )
1515 case 0xF9: // LD SP,IXY
1519 case 0x22:{// LD (ADDR),IXY
1520 int addr
= GET_ADDR();
1522 WRITE_WORD( addr
, ixy
);
1526 case 0x21: // LD IXY,imm
1531 case 0x2A:{// LD IXY,(addr)
1532 int addr
= GET_ADDR();
1533 ixy
= READ_WORD( addr
);
1540 data
= IXY_DISP( ixy
, SBYTE( data2
) );
1542 data2
= READ_CODE( pc
);
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
);
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);
1568 if ( !(data2
& 0x40) )
1570 WRITE_MEM( data
, temp
);
1575 dprintf( "Opcode $%02X $CB $%02X not supported\n", opcode
, data2
);
1583 case 0x23: // INC IXY
1584 ixy
= WORD( ixy
+ 1 );
1587 case 0x2B: // DEC IXY
1588 ixy
= WORD( ixy
- 1 );
1591 case 0x34: // INC (IXY+disp)
1592 ixy
= IXY_DISP( ixy
, SBYTE( data2
) );
1594 data
= READ_MEM( ixy
) + 1;
1595 WRITE_MEM( ixy
, data
);
1598 case 0x35: // DEC (IXY+disp)
1599 ixy
= IXY_DISP( ixy
, SBYTE( data2
) );
1601 data
= READ_MEM( ixy
) - 1;
1602 WRITE_MEM( ixy
, data
);
1605 case 0x24: // INC HXY
1606 ixy
= WORD( ixy
+ 0x100 );
1610 case 0x2C: // INC LXY
1611 data
= BYTE( ixy
+ 1 );
1612 ixy
= (ixy
& 0xFF00) + data
;
1614 if ( opcode
== 0xDD )
1622 case 0x25: // DEC HXY
1623 ixy
= WORD( ixy
- 0x100 );
1627 case 0x2D: // DEC LXY
1628 data
= BYTE( ixy
- 1 );
1629 ixy
= (ixy
& 0xFF00) + data
;
1631 if ( opcode
== 0xDD )
1640 case 0xE5: // PUSH IXY
1644 case 0xE1:{// POP IXY
1645 ixy
= READ_WORD( sp
);
1646 sp
= WORD( sp
+ 2 );
1652 case 0xE9: // JP (IXY)
1656 case 0xE3:{// EX (SP),IXY
1657 int temp
= READ_WORD( sp
);
1658 WRITE_WORD( sp
, ixy
);
1664 dprintf( "Unnecessary DD/FD prefix encountered\n" );
1673 dprintf( "Unhandled main opcode: $%02X\n", opcode
);
1682 s_time
&= 3; // increment by multiple of 4
1693 cpu
->cpu_state_
.base
= s
.base
;
1694 cpu
->cpu_state_
.time
= s_time
;
1695 cpu
->cpu_state
= &cpu
->cpu_state_
;