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