summaryrefslogtreecommitdiff
path: root/lib/rbcodec/codecs/libgme/z80_cpu_run.h
diff options
context:
space:
mode:
Diffstat (limited to 'lib/rbcodec/codecs/libgme/z80_cpu_run.h')
-rw-r--r--lib/rbcodec/codecs/libgme/z80_cpu_run.h1696
1 files changed, 1696 insertions, 0 deletions
diff --git a/lib/rbcodec/codecs/libgme/z80_cpu_run.h b/lib/rbcodec/codecs/libgme/z80_cpu_run.h
new file mode 100644
index 0000000000..a453487bb0
--- /dev/null
+++ b/lib/rbcodec/codecs/libgme/z80_cpu_run.h
@@ -0,0 +1,1696 @@
1// Game_Music_Emu 0.6-pre. 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,
11though they NEVER have side-effects, so multiple evaluation is OK.
12- Output parameters might be a multiple-assignment expression like "a=x",
13so they must NOT be parenthesized.
14- Except where noted, time() and related functions will NOT work
15correctly inside a macro. TIME() is always correct, and between FLUSH_TIME() and
16CACHE_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_MEM( addr_t );
22 void WRITE_MEM( addr_t, int data );
23
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 );
27
28 // Reference to Z80_Cpu object used for emulation
29 #define CPU cpu
30
31// The following can be used within macros:
32
33 // Current time
34 time_t TIME();
35
36 // Allows use of time functions
37 void FLUSH_TIME();
38
39 // Must be used before end of macro if FLUSH_TIME() was used earlier
40 void CACHE_TIME();
41
42// Configuration (optional; commented behavior if defined)
43
44 // Optimizes as if map_mem( 0, 0x10000, FLAT_MEM, FLAT_MEM ) is always in effect
45 #define FLAT_MEM my_mem_array
46
47 // If RST 7 ($FF) is encountered and PC = IDLE_ADDR, stops execution
48 #define IDLE_ADDR 0x1234
49
50 // Expanded just before beginning of code, to help debugger
51 #define CPU_BEGIN void my_run_cpu() {
52
53#endif
54
55/* Copyright (C) 2006-2008 Shay Green. This module is free software; you
56can redistribute it and/or modify it under the terms of the GNU Lesser
57General Public License as published by the Free Software Foundation; either
58version 2.1 of the License, or (at your option) any later version. This
59module is distributed in the hope that it will be useful, but WITHOUT ANY
60WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
61FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
62details. You should have received a copy of the GNU Lesser General Public
63License along with this module; if not, write to the Free Software Foundation,
64Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */
65
66#ifdef CPU_BEGIN
67 CPU_BEGIN
68#endif
69
70#define R cpu->r
71
72// flags, named with hex value for clarity
73int const S80 = 0x80;
74int const Z40 = 0x40;
75int const F20 = 0x20;
76int const H10 = 0x10;
77int const F08 = 0x08;
78int const V04 = 0x04;
79int const P04 = 0x04;
80int const N02 = 0x02;
81int const C01 = 0x01;
82
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 )
87
88#define SET_R( n ) (void) (R.r = n)
89#define GET_R() (R.r)
90
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;}
95
96// Memory
97#define RW_MEM( addr, rw ) RW_PAGE( addr, rw ) [RW_OFFSET( addr )]
98#define READ_CODE( addr ) RW_MEM( addr, read )
99
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
109
110#ifndef READ_MEM
111 #define READ_MEM( addr ) RW_MEM( addr, read )
112#endif
113
114#ifndef WRITE_MEM
115 #define WRITE_MEM( addr, data ) (RW_MEM( addr, write ) = data)
116#endif
117
118#define READ_WORD( addr ) GET_LE16( &RW_MEM( addr, read ) )
119#define WRITE_WORD( addr, data ) SET_LE16( &RW_MEM( addr, write ), data )
120
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 */
125
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
131
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
139
140#define R16( n, shift, offset ) (r.r16_ [((unsigned) (n) >> shift) - (offset >> shift)])
141
142#define EX( x, y ) \
143 {\
144 int temp = x;\
145 x = y;\
146 y = temp;\
147 }
148
149#define EXX( name ) \
150 EX( R.alt.name, r.name )
151
152bool warning = false;
153{
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;
161
162
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;
170
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;
177
178 //goto loop; // confuses optimizer
179 s_time += 7;
180 pc -= 2;
181
182call_not_taken:
183 s_time -= 7;
184jp_not_taken:
185 pc += 2;
186loop:
187
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 );
193
194 byte const* instr = RW_PAGE( pc, read );
195
196 int opcode;
197
198 if ( RW_OFFSET( ~0 ) == ~0 )
199 {
200 opcode = instr [RW_OFFSET( pc )];
201 pc++;
202 instr += RW_OFFSET( pc );
203 }
204 else
205 {
206 instr += RW_OFFSET( pc );
207 opcode = *instr++;
208 pc++;
209 }
210
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
229
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,
248 };
249
250 if ( s_time >= 0 )
251 goto out_of_time;
252 s_time += clock_table [opcode];
253
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
260
261#define GET_ADDR() GET_LE16( &INSTR( 0, pc ) )
262
263 int data;
264 data = INSTR( 0, pc );
265
266 switch ( opcode )
267 {
268// Common
269
270 case 0x00: // NOP
271 CASE7( 40, 49, 52, 5B, 64, 6D, 7F ): // LD B,B etc.
272 goto loop;
273
274 case 0x08:{// EX AF,AF'
275 EXX( b.a );
276 EX( R.alt.b.flags, flags );
277 goto loop;
278 }
279
280 case 0xD3: // OUT (imm),A
281 pc++;
282 OUT_PORT( (data + r.b.a * 0x100), r.b.a );
283 goto loop;
284
285 case 0x2E: // LD L,imm
286 pc++;
287 r.b.l = data;
288 goto loop;
289
290 case 0x3E: // LD A,imm
291 pc++;
292 r.b.a = data;
293 goto loop;
294
295 case 0x3A:{// LD A,(addr)
296 int addr = GET_ADDR();
297 pc += 2;
298 r.b.a = READ_MEM( addr );
299 goto loop;
300 }
301
302// Conditional
303
304#define ZERO (flags & Z40)
305#define CARRY (flags & C01)
306#define EVEN (flags & P04)
307#define MINUS (flags & S80)
308
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;\
319}
320
321#define JR( cond ) JR_( cond, 5 )
322
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
328
329 case 0x10:{// DJNZ disp
330 int temp = r.b.b - 1;
331 r.b.b = temp;
332 JR( temp )
333 }
334
335// JP
336#define JP( cond ) \
337 if ( !(cond) )\
338 goto jp_not_taken;\
339 pc = GET_ADDR();\
340 goto loop;
341
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
350
351 case 0xC3: // JP addr
352 pc = GET_ADDR();
353 goto loop;
354
355 case 0xE9: // JP HL
356 pc = r.w.hl;
357 goto loop;
358
359// RET
360#define RET( cond ) \
361 if ( cond )\
362 goto ret_taken;\
363 s_time -= 6;\
364 goto loop;
365
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
374
375 case 0xC9: // RET
376 ret_taken:
377 pc = READ_WORD( sp );
378 sp = WORD( sp + 2 );
379 goto loop;
380
381// CALL
382#define CALL( cond ) \
383 if ( cond )\
384 goto call_taken;\
385 goto call_not_taken;
386
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
395
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;
403 }
404 }
405
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 )
412 {
413 pc = WORD( pc - 1 );
414 s_time -= 11;
415 goto loop;
416 }
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;
425
426// PUSH/POP
427 case 0xF5: // PUSH AF
428 data = r.b.a * 0x100u + flags;
429 goto push_data;
430
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;
439
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;
445
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;
452
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;
461
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;
469
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;
489 }
490
491// CP
492 case 0xBE: // CP (HL)
493 data = READ_MEM( r.w.hl );
494 goto cp_data;
495
496 case 0xFE: // CP imm
497 pc++;
498 goto cp_data;
499
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;
512 }
513
514// ADD HL,r.w
515
516 case 0x39: // ADD HL,SP
517 data = sp;
518 goto add_hl_data;
519
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;
533 }
534
535 case 0x27:{// DAA
536 int a = r.b.a;
537 if ( a > 0x99 )
538 flags |= C01;
539
540 int adjust = 0x60 * (flags & C01);
541
542 if ( flags & H10 || (a & 0x0F) > 9 )
543 adjust += 0x06;
544
545 if ( flags & N02 )
546 adjust = -adjust;
547 a += adjust;
548
549 flags = (flags & (C01 | N02)) +
550 ((r.b.a ^ a) & H10) +
551 SZ28P( BYTE( a ) );
552 r.b.a = a;
553 goto loop;
554 }
555
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;
561
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;
572
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;
577
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;
588
589 case 0x03: // INC BC
590 case 0x13: // INC DE
591 case 0x23: // INC HL
592 R16( opcode, 4, 0x03 )++;
593 goto loop;
594
595 case 0x33: // INC SP
596 sp = WORD( sp + 1 );
597 goto loop;
598
599 case 0x0B: // DEC BC
600 case 0x1B: // DEC DE
601 case 0x2B: // DEC HL
602 R16( opcode, 4, 0x0B )--;
603 goto loop;
604
605 case 0x3B: // DEC SP
606 sp = WORD( sp - 1 );
607 goto loop;
608
609// AND
610 case 0xA6: // AND (HL)
611 data = READ_MEM( r.w.hl );
612 goto and_data;
613
614 case 0xE6: // AND imm
615 pc++;
616 goto and_data;
617
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;
624
625// OR
626 case 0xB6: // OR (HL)
627 data = READ_MEM( r.w.hl );
628 goto or_data;
629
630 case 0xF6: // OR imm
631 pc++;
632 goto or_data;
633
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;
640
641// XOR
642 case 0xAE: // XOR (HL)
643 data = READ_MEM( r.w.hl );
644 goto xor_data;
645
646 case 0xEE: // XOR imm
647 pc++;
648 goto xor_data;
649
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;
656
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;
661
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;
671
672 CASE5( 06, 0E, 16, 1E, 26 ): // LD r,imm
673 R8( opcode >> 3, 0 ) = data;
674 pc++;
675 goto loop;
676
677 case 0x36: // LD (HL),imm
678 pc++;
679 WRITE_MEM( r.w.hl, data );
680 goto loop;
681
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;
685
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;
692
693 case 0x31: // LD sp,imm
694 sp = GET_ADDR();
695 pc += 2;
696 goto loop;
697
698 case 0x2A:{// LD HL,(addr)
699 int addr = GET_ADDR();
700 pc += 2;
701 r.w.hl = READ_WORD( addr );
702 goto loop;
703 }
704
705 case 0x32:{// LD (addr),A
706 int addr = GET_ADDR();
707 pc += 2;
708 WRITE_MEM( addr, r.b.a );
709 goto loop;
710 }
711
712 case 0x22:{// LD (addr),HL
713 int addr = GET_ADDR();
714 pc += 2;
715 WRITE_WORD( addr, r.w.hl );
716 goto loop;
717 }
718
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;
723
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;
728
729 case 0xF9: // LD SP,HL
730 sp = r.w.hl;
731 goto loop;
732
733// Rotate
734
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;
742 }
743
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;
752 }
753
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;
761 }
762
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;
770 }
771
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;
780 }
781
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;
787 }
788
789 case 0x37: // SCF
790 flags = ((flags & (S80 | Z40 | P04)) | C01) +
791 (r.b.a & (F20 | F08));
792 goto loop;
793
794 case 0xDB: // IN A,(imm)
795 pc++;
796 r.b.a = IN_PORT( (data + r.b.a * 0x100) );
797 goto loop;
798
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;
804 }
805
806 case 0xEB: // EX DE,HL
807 EX( r.w.hl, r.w.de );
808 goto loop;
809
810 case 0xD9: // EXX DE,HL
811 EXX( w.bc );
812 EXX( w.de );
813 EXX( w.hl );
814 goto loop;
815
816 case 0xF3: // DI
817 R.iff1 = 0;
818 R.iff2 = 0;
819 goto loop;
820
821 case 0xFB: // EI
822 R.iff1 = 1;
823 R.iff2 = 1;
824 // TODO: delayed effect
825 goto loop;
826
827 case 0x76: // HALT
828 goto halt;
829
830//////////////////////////////////////// CB prefix
831 {
832 case 0xCB:
833 pc++;
834 switch ( data )
835 {
836
837 // Rotate left
838
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;\
845 }
846
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 ) )
852
853 CASE7( 00, 01, 02, 03, 04, 05, 07 ):{// RLC r
854 byte* reg = &R8( data, 0 );
855 RLC( *reg, *reg = result )
856 }
857
858 #define RL( read, write ) {\
859 int result = (read << 1) + (flags & C01);\
860 flags = SZ28PC( result );\
861 write;\
862 goto loop;\
863 }
864
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 ) )
870
871 CASE7( 10, 11, 12, 13, 14, 15, 17 ):{// RL r
872 byte* reg = &R8( data, 0x10 );
873 RL( *reg, *reg = result )
874 }
875
876 #define SLA( read, low_bit, write ) {\
877 int result = (read << 1) + low_bit;\
878 flags = SZ28PC( result );\
879 write;\
880 goto loop;\
881 }
882
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 ) )
888
889 CASE7( 20, 21, 22, 23, 24, 25, 27 ):{// SLA r
890 byte* reg = &R8( data, 0x20 );
891 SLA( *reg, 0, *reg = result )
892 }
893
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 ) )
899
900 CASE7( 30, 31, 32, 33, 34, 35, 37 ):{// SLL r
901 byte* reg = &R8( data, 0x30 );
902 SLA( *reg, 1, *reg = result )
903 }
904
905 // Rotate right
906
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;\
914 }
915
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 ) )
921
922 CASE7( 08, 09, 0A, 0B, 0C, 0D, 0F ):{// RRC r
923 byte* reg = &R8( data, 0x08 );
924 RRC( *reg, *reg = result )
925 }
926
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;\
934 }
935
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 ) )
941
942 CASE7( 18, 19, 1A, 1B, 1C, 1D, 1F ):{// RR r
943 byte* reg = &R8( data, 0x18 );
944 RR( *reg, *reg = result )
945 }
946
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;\
954 }
955
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 ) )
961
962 CASE7( 28, 29, 2A, 2B, 2C, 2D, 2F ):{// SRA r
963 byte* reg = &R8( data, 0x28 );
964 SRA( *reg, *reg = result )
965 }
966
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;\
974 }
975
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 ) )
981
982 CASE7( 38, 39, 3A, 3B, 3C, 3D, 3F ):{// SRL r
983 byte* reg = &R8( data, 0x38 );
984 SRL( *reg, *reg = result )
985 }
986
987 // BIT
988 {
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;
1010 }
1011
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;
1023 }
1024
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;
1035
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;
1046 }
1047 assert( false );
1048 }
1049
1050#undef GET_ADDR
1051#define GET_ADDR() GET_LE16( &INSTR( 1, pc ) )
1052
1053//////////////////////////////////////// ED prefix
1054 {
1055 case 0xED:
1056 pc++;
1057 s_time += (clock_table + 256) [data] >> 4;
1058 switch ( data )
1059 {
1060 {
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;
1089 }
1090
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;
1096 }
1097
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;
1103
1104 {
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;
1116 }
1117
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;
1124 }
1125
1126 case 0x7B:{// LD SP,(ADDR)
1127 int addr = GET_ADDR();
1128 pc += 2;
1129 sp = READ_WORD( addr );
1130 goto loop;
1131 }
1132
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;
1140 }
1141
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;
1149 }
1150
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;
1157
1158 {
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 );
1170
1171 int result = r.b.a - temp;
1172 flags = (flags & C01) + N02 +
1173 ((((temp ^ r.b.a) & H10) ^ result) & (S80 | H10));
1174
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;
1182
1183 flags += V04;
1184 if ( flags & Z40 || data < 0xB0 )
1185 goto loop;
1186
1187 pc -= 2;
1188 s_time += 5;
1189 goto loop;
1190 }
1191
1192 {
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 );
1204
1205 addr = r.w.de;
1206 r.w.de = addr + inc;
1207 WRITE_MEM( addr, temp );
1208
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;
1214
1215 flags += V04;
1216 if ( data < 0xB0 )
1217 goto loop;
1218
1219 pc -= 2;
1220 s_time += 5;
1221 goto loop;
1222 }
1223
1224 {
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 );
1236
1237 int b = --r.b.b;
1238 flags = (temp >> 6 & N02) + SZ28( b );
1239 if ( b && data >= 0xB0 )
1240 {
1241 pc -= 2;
1242 s_time += 5;
1243 }
1244
1245 OUT_PORT( r.w.bc, temp );
1246 goto loop;
1247 }
1248
1249 {
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;
1258
1259 int addr = r.w.hl;
1260 r.w.hl = addr + inc;
1261
1262 int temp = IN_PORT( r.w.bc );
1263
1264 int b = --r.b.b;
1265 flags = (temp >> 6 & N02) + SZ28( b );
1266 if ( b && data >= 0xB0 )
1267 {
1268 pc -= 2;
1269 s_time += 5;
1270 }
1271
1272 WRITE_MEM( addr, temp );
1273 goto loop;
1274 }
1275
1276 case 0x47: // LD I,A
1277 R.i = r.b.a;
1278 goto loop;
1279
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;
1285
1286 case 0x57: // LD A,I
1287 r.b.a = R.i;
1288 goto ld_ai_common;
1289
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;
1297
1298 CASE8( 45, 4D, 55, 5D, 65, 6D, 75, 7D ): // RETI/RETN
1299 R.iff1 = R.iff2;
1300 goto ret_taken;
1301
1302 case 0x46: case 0x4E: case 0x66: case 0x6E: // IM 0
1303 R.im = 0;
1304 goto loop;
1305
1306 case 0x56: case 0x76: // IM 1
1307 R.im = 1;
1308 goto loop;
1309
1310 case 0x5E: case 0x7E: // IM 2
1311 R.im = 2;
1312 goto loop;
1313
1314 default:
1315 dprintf( "Opcode $ED $%02X not supported\n", data );
1316 warning = true;
1317 goto loop;
1318 }
1319 assert( false );
1320 }
1321
1322//////////////////////////////////////// DD/FD prefix
1323 {
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 )
1335 {
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))
1339
1340 #define SET_IXY( in ) if ( opcode == 0xDD ) ix = in; else iy = in;
1341
1342 // ADD/ADC/SUB/SBC
1343
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;
1353
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;
1362
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;
1371
1372 {
1373 int temp;
1374 case 0x39: // ADD IXY,SP
1375 temp = sp;
1376 goto add_ixy_data;
1377
1378 case 0x29: // ADD IXY,HL
1379 temp = ixy;
1380 goto add_ixy_data;
1381
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;
1394 }
1395 }
1396
1397 // AND
1398 case 0xA6: // AND (IXY+disp)
1399 pc++;
1400 data = READ_MEM( IXY_DISP( ixy, SBYTE( data2 ) ) );
1401 goto and_data;
1402
1403 case 0xA4: // AND HXY
1404 data = ixy >> 8;
1405 goto and_data;
1406
1407 case 0xA5: // AND LXY
1408 data = BYTE( ixy );
1409 goto and_data;
1410
1411 // OR
1412 case 0xB6: // OR (IXY+disp)
1413 pc++;
1414 data = READ_MEM( IXY_DISP( ixy, SBYTE( data2 ) ) );
1415 goto or_data;
1416
1417 case 0xB4: // OR HXY
1418 data = ixy >> 8;
1419 goto or_data;
1420
1421 case 0xB5: // OR LXY
1422 data = BYTE( ixy );
1423 goto or_data;
1424
1425 // XOR
1426 case 0xAE: // XOR (IXY+disp)
1427 pc++;
1428 data = READ_MEM( IXY_DISP( ixy, SBYTE( data2 ) ) );
1429 goto xor_data;
1430
1431 case 0xAC: // XOR HXY
1432 data = ixy >> 8;
1433 goto xor_data;
1434
1435 case 0xAD: // XOR LXY
1436 data = BYTE( ixy );
1437 goto xor_data;
1438
1439 // CP
1440 case 0xBE: // CP (IXY+disp)
1441 pc++;
1442 data = READ_MEM( IXY_DISP( ixy, SBYTE( data2 ) ) );
1443 goto cp_data;
1444
1445 case 0xBC: // CP HXY
1446 data = ixy >> 8;
1447 goto cp_data;
1448
1449 case 0xBD: // CP LXY
1450 data = BYTE( ixy );
1451 goto cp_data;
1452
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;
1462
1463 CASE5( 44, 4C, 54, 5C, 7C ): // LD r,HXY
1464 R8( data >> 3, 8 ) = ixy >> 8;
1465 goto loop;
1466
1467 case 0x64: // LD HXY,HXY
1468 case 0x6D: // LD LXY,LXY
1469 goto loop;
1470
1471 CASE5( 45, 4D, 55, 5D, 7D ): // LD r,LXY
1472 R8( data >> 3, 8 ) = ixy;
1473 goto loop;
1474
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;
1479
1480 case 0x26: // LD HXY,imm
1481 pc++;
1482 goto ld_hxy_data;
1483
1484 case 0x65: // LD HXY,LXY
1485 data2 = BYTE( ixy );
1486 goto ld_hxy_data;
1487
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;
1493
1494 case 0x2E: // LD LXY,imm
1495 pc++;
1496 goto ld_lxy_data;
1497
1498 case 0x6C: // LD LXY,HXY
1499 data2 = ixy >> 8;
1500 goto ld_lxy_data;
1501
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 )
1508 {
1509 ix = ixy;
1510 goto loop;
1511 }
1512 iy = ixy;
1513 goto loop;
1514
1515 case 0xF9: // LD SP,IXY
1516 sp = ixy;
1517 goto loop;
1518
1519 case 0x22:{// LD (ADDR),IXY
1520 int addr = GET_ADDR();
1521 pc += 2;
1522 WRITE_WORD( addr, ixy );
1523 goto loop;
1524 }
1525
1526 case 0x21: // LD IXY,imm
1527 ixy = GET_ADDR();
1528 pc += 2;
1529 goto set_ixy;
1530
1531 case 0x2A:{// LD IXY,(addr)
1532 int addr = GET_ADDR();
1533 ixy = READ_WORD( addr );
1534 pc += 2;
1535 goto set_ixy;
1536 }
1537
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 )
1545 {
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)
1554
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;
1561 }
1562
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;
1572 }
1573
1574 default:
1575 dprintf( "Opcode $%02X $CB $%02X not supported\n", opcode, data2 );
1576 warning = true;
1577 goto loop;
1578 }
1579 assert( false );
1580 }
1581
1582 // INC/DEC
1583 case 0x23: // INC IXY
1584 ixy = WORD( ixy + 1 );
1585 goto set_ixy;
1586
1587 case 0x2B: // DEC IXY
1588 ixy = WORD( ixy - 1 );
1589 goto set_ixy;
1590
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;
1597
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;
1604
1605 case 0x24: // INC HXY
1606 ixy = WORD( ixy + 0x100 );
1607 data = ixy >> 8;
1608 goto inc_xy_common;
1609
1610 case 0x2C: // INC LXY
1611 data = BYTE( ixy + 1 );
1612 ixy = (ixy & 0xFF00) + data;
1613 inc_xy_common:
1614 if ( opcode == 0xDD )
1615 {
1616 ix = ixy;
1617 goto inc_set_flags;
1618 }
1619 iy = ixy;
1620 goto inc_set_flags;
1621
1622 case 0x25: // DEC HXY
1623 ixy = WORD( ixy - 0x100 );
1624 data = ixy >> 8;
1625 goto dec_xy_common;
1626
1627 case 0x2D: // DEC LXY
1628 data = BYTE( ixy - 1 );
1629 ixy = (ixy & 0xFF00) + data;
1630 dec_xy_common:
1631 if ( opcode == 0xDD )
1632 {
1633 ix = ixy;
1634 goto dec_set_flags;
1635 }
1636 iy = ixy;
1637 goto dec_set_flags;
1638
1639 // PUSH/POP
1640 case 0xE5: // PUSH IXY
1641 data = ixy;
1642 goto push_data;
1643
1644 case 0xE1:{// POP IXY
1645 ixy = READ_WORD( sp );
1646 sp = WORD( sp + 2 );
1647 goto set_ixy;
1648 }
1649
1650 // Misc
1651
1652 case 0xE9: // JP (IXY)
1653 pc = ixy;
1654 goto loop;
1655
1656 case 0xE3:{// EX (SP),IXY
1657 int temp = READ_WORD( sp );
1658 WRITE_WORD( sp, ixy );
1659 ixy = temp;
1660 goto set_ixy;
1661 }
1662
1663 default:
1664 dprintf( "Unnecessary DD/FD prefix encountered\n" );
1665 warning = true;
1666 pc--;
1667 goto loop;
1668 }
1669 assert( false );
1670 }
1671
1672 }
1673 dprintf( "Unhandled main opcode: $%02X\n", opcode );
1674 assert( false );
1675
1676#ifdef IDLE_ADDR
1677hit_idle_addr:
1678 s_time -= 11;
1679 goto out_of_time;
1680#endif
1681halt:
1682 s_time &= 3; // increment by multiple of 4
1683out_of_time:
1684 pc--;
1685
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;
1692
1693 cpu->cpu_state_.base = s.base;
1694 cpu->cpu_state_.time = s_time;
1695 cpu->cpu_state = &cpu->cpu_state_;
1696}