Coverage Report

Created: 2026-07-12 08:57

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