/*

  Bug: did I get "ld ($4db3),hl" the wrong way round???

  mem[0x4dc1] = RA;
                                  dumpregs(0x0e62, "// ld     hl,$0101        ; [0e62] 21 01 01 \n");
  HL=0x0101;
                                  dumpregs(0x0e65, "// ld     ($4db1),hl      ; [0e65] 22 B1 4D \n");
  HL = mem[0x4db1];
                                  dumpregs(0x0e68, "// ld     ($4db3),hl      ; [0e68] 22 B3 4D \n");
  HL = mem[0x4db3];
                                  dumpregs(0x0e6b, "// ret                    ; [0e6b] C9 \n");
 */



// to do:  rst 10 => RA = mem[HL+RA]; // table lookup
// rst 8 => save byte in A at *HL++ while --RB
// rst 18 HL = mem[HL=HL + B*2] + mem[DE = HL+1]<<8  // 16bit table lookup

// STATUS: all opcodes are now translated and the code runs a considerable
// way, BUT there are still some obvious bugs to be fixed because of
// a lot of register-pair consolidation and splitting remains to be done.

// remember to edit out the loop in the init code where it waits
// for a test interrupt.  Need a mechanism to do high-level edits
// to the code driven by the disasm.info config file.

//-------------------------------------------------------------------------

// This is a static translator which generates C from Z80 code - the
// C is the same as would have been executed if the code were run in
// an emulator.  For a description of the technique which was used to
// create this, see http://www.gtoal.com/sbt/

// I am not doing all the tricks that are described in that paper
// because the Z80 is a nicer architecture for emulation and there
// is not as much need to optimise flags for example.

// taking some liberties!:  in an accurate emulator, we make sure that
// wraparound in the address space works exactly as the computer,
// even though no good program would do that.  We assume the programs
// this is going to be used on are well behaved.  If they are not,
// you can tweak the output by hand.

// I am taking out all the masking which was done in this code
// and have declared the variables as "register unsigned char"
// or "register unsigned short" and will trust the compiler to
// use the appropriate code - either a byte access, or a word
// access (32 bit) plus a mask operation.  I reckon it can't be
// any worse than an explicit mask, and it may be better if the
// mask is not needed.

// The generated code needs to be run in a harness, and probably
// tweaked a little to remove unnecessary stuff (such as interrupt
// handler initialisation).  Ideally we want to craft it so that
// a call on the encapsulating procedure executes a single frame
// of play and returns to the caller.  Although this is relatively
// general purpose code, I'm writing it specifically to run Ms Pacman
// on my GP32 handheld.  (I own a MS Pacman cabinet, but it's hard
// to carry around with you :-) )

// pending: need to use def/use code to merge byte register pairs
// and split them apart only when needed:

// the default is to keep the master copy of AF/BC/DE in the byte registers
// and consolidate them when a word register is needed; then
// if a word register is written to as a unit, the byte registers
// must be extracted from it; and to keep HL/IX/IY in word registers
// and do the reverse; SP and PC are always word variables.  They
// could even be kept in regular ints, which are 32 bit on this
// system.  (We are however trying to remain byte-sex independant)

// (note: although this makes for more efficient code, in practise it
// is much easier to debug if both copies are kept in sync, so I am
// adding some redundant merge/split instructions for now)

// Once we can remove the redundant labels and calculate some
// basic blocks, the dead code removal should remove some of
// this overhead.  Would be nice if the compiler did this for us
// but we may end up requiring to do this explicitly ourselves.

// when the generated code is encapsulated in a procedure, we will
// be able to use the register attribute as below.  [see emu.c]
// We can still handle multiple register sets by copy-in/copy-out.

// pending: daatable ... have a table for chnflags too. (i|=1024 etc)
// *or* remap the flag bit posns in RF! - hacky... only needs to
// be unmapped on PUSH F/POP F...

/* register */ unsigned char RA, RF, RB, RC, RD, RE;
unsigned short /*AF,*/ BC, DE;
unsigned char RH, RL, RI, RJ, RX, RY;
/* register */ unsigned short HL, IX, IY;
unsigned short SP, PC;

unsigned short AF2, BC2, DE2, HL2;  /* IX -> RI,RX   IY -> RJ,RY */

/*** Z80Em: Portable Z80 emulator *******************************************/
/***                                                                      ***/
/***                                 Z80.c                                ***/
/***                                                                      ***/
/*** This file contains the emulation code                                ***/
/***                                                                      ***/
/*** Copyright (C) Marcel de Kogel 1996,1997                              ***/
/***     You are not allowed to distribute this software commercially     ***/
/***     Please, notify me, if you make any changes to this file          ***/
/****************************************************************************/

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <stdarg.h>

unsigned char mem[0x10000];

char *S(char *format, ...)
{
  static char buffs[256*256];
  char *buff;
  static int nextbuff = 0;
  va_list ap;
  nextbuff = (nextbuff+1)&255;
  buff = &buffs[nextbuff*256];
  va_start(ap, format);
  vsprintf(buff, format, ap);
  va_end(ap);
  return(buff);  
}

char *H2(int i)
{
  static char buffs[16][16];
  char *buff;
  static int nextbuff = 0;
  nextbuff = (nextbuff+1)&15;
  buff = &buffs[nextbuff][0];
  sprintf(buff, "0x%02x", i&255);
  return(buff);  
}

char *H4(int i)
{
  static char buffs[16][16];
  char *buff;
  static int nextbuff = 0;
  nextbuff = (nextbuff+1)&15;
  buff = &buffs[nextbuff][0];
  sprintf(buff, "0x%04x", i&65535);
  return(buff);  
}

void D(char *s, ...)
{
  static char buff[4096];
  va_list ap;
  va_start(ap, s);
  vsprintf(buff, s, ap);
  puts(buff);  // yes, the appended \n is deliberate
  va_end(ap);
}

#include "Z80.h"

int debug = (0!=0);
int counting_cycles = (0!=0);
int counting_r = (0!=0);

//#define M_RDMEM(A)      S("mem[%s]", #A)
#define M_WRMEM(A,V)    D("  i=%s; mem[i]=%s; /* force order */", #A, #V)
#define M_RDOP(A)       Z80_RDOP(A)
#define M_RDOP_ARG(A)   Z80_RDOP_ARG(A)
#define M_RDSTACK(A)    Z80_RDSTACK(A)
#define M_WRSTACK(A,V)  D("  i=%s; mem[i]=%s; /* force order */", #A, #V)

#define DoIn(lo,hi)     Z80_In((lo)+(((unsigned)(hi))<<8))
#define DoOut(lo,hi,v)  Z80_Out((lo)+(((unsigned)(hi))<<8),v)

static void Interrupt(int j);
static void ei(void);

#define S_FLAG          0x80
#define Z_FLAG          0x40
#define H_FLAG          0x10
#define V_FLAG          0x04
#define N_FLAG          0x02
#define C_FLAG          0x01

#define M_SKIP_CALL     "PC+=2"
#define M_SKIP_JP       "PC+=2"
#define M_SKIP_JR       "PC+=1"
#define M_SKIP_RET	""

static Z80_Regs R;
int Z80_Running=1;
int Z80_IPeriod=50000;
int Z80_ICount=50000;

#ifdef TRACE
static unsigned pc_trace[256];
static unsigned pc_count=0;
#endif

static unsigned char PostIncCarry[256];
static unsigned char AddFlags[256][256];
static byte PTable[512];
static byte ZSTable[512];
static byte IncTable[512];
static byte DecTable[512];
static byte ZSPTable[512];
static byte ZSPHTable[512];
#include "Z80DAA.h"

typedef void (*opcode_fn) (void);

#define M_C     "(RF&C_FLAG)"
#define M_NC    "(!(RF&C_FLAG))"
#define M_Z     "(RF&Z_FLAG)"
#define M_NZ    "(!(RF&Z_FLAG))"
#define M_M     "(RF&S_FLAG)"
#define M_P     "(!(RF&S_FLAG))"
#define M_PE    "(RF&P_FLAG)"
#define M_PO    "(!(RF&P_FLAG))"

/* Get next opcode argument and increment program counter */
unsigned M_RDMEM_OPCODE (void)
{
 unsigned retval;
 retval=mem[PC];
 PC++;
 return retval;
}

unsigned M_RDMEM_OPCODE_WORD (void)
{
 int i;
 i=M_RDMEM_OPCODE();
 i+=M_RDMEM_OPCODE()<<8;
 return i;
}

char *signed_char(char *lit) {
  static char tmp[128];
  int ch;
  if ((strlen(lit)==4) && (strncmp(lit, "0x", 2)==0)) {
    ch = lit[2];
    if (('8' <= ch && ch <= '9') || ('A' <= ch && ch <= 'F') || ('a' <= ch && ch <= 'f')) {
      sprintf(tmp, "(signed char)%s", lit);
    } else {
      sprintf(tmp, "%s", lit);
    }
  } else {
    sprintf(tmp, "(signed char)%s", lit);
  }
  return tmp;
}

#define M_XIX     S("(IX+%s)", signed_char(H2(M_RDMEM_OPCODE())))
#define M_XIY     S("(IY+%s)", signed_char(H2(M_RDMEM_OPCODE())))
#define M_RD_XHL  "mem[HL]"
#define M_RD_XIX  S("mem[IX+%s]", signed_char(H2(M_RDMEM_OPCODE())))
#define M_RD_XIY  S("mem[IY+%s]", signed_char(H2(M_RDMEM_OPCODE())))

void M_WR_XIX_S(char * a)
{
D("  mem[%s]=%s;", M_XIX, a); // I had tagged this as a bug but I think it's fixed now
}

void M_WR_XIY_S(char *a)
{
D("  mem[%s]=%s;", M_XIY, a); // I had tagged this as a bug but I think it's fixed now
}

#ifdef X86_ASM
#include "Z80CDx86.h"
#else
#include "Z80Codes.h"
#endif

static void adc_a_xhl(void) { D("  %s;", M_ADC_S("mem[HL]")); }
static void adc_a_xix(void) {
  D("  %s;", M_ADC_S("j"));
}
static void adc_a_xiy(void) {
  D("  j=%s;", M_RD_XIY);
  D("  %s;", M_ADC_S("j"));
}

static void adc_a_a(void) { D("  %s;", M_ADC_S("RA")); }
static void adc_a_b(void) { D("  %s;", M_ADC_S("RB")); }
static void adc_a_c(void) { D("  %s;", M_ADC_S("RC")); }
static void adc_a_d(void) { D("  %s;", M_ADC_S("RD")); }
static void adc_a_e(void) { D("  %s;", M_ADC_S("RE")); }
static void adc_a_h(void) { D("  %s;", M_ADC_S("RH")); }
static void adc_a_l(void) { D("  %s;", M_ADC_S("RL")); }
static void adc_a_ixl(void) { D("  %s;", M_ADC_S("RX")); }
static void adc_a_ixh(void) { D("  %s;", M_ADC_S("RI")); }
static void adc_a_iyl(void) { D("  %s;", M_ADC_S("RY")); }
static void adc_a_iyh(void) { D("  %s;", M_ADC_S("RJ")); }
static void adc_a_byte(void) { D("  %s;", M_ADC_S(S("0x%02x", M_RDMEM_OPCODE()))); }

static void adc_hl_bc(void) { D("  %s;", M_ADCW_S("BC")); }
static void adc_hl_de(void) { D("  %s;", M_ADCW_S("DE")); }
static void adc_hl_hl(void) { D("  %s;", M_ADCW_S("HL")); }
static void adc_hl_sp(void) { D("  %s;", M_ADCW_S("SP")); }

static void add_a_xhl(void) { D("  %s;", M_ADD_S("mem[HL]")); }
static void add_a_xix(void) { D("  %s;", M_ADD_S(M_RD_XIX)); }
static void add_a_xiy(void) { D("  %s;", M_ADD_S(M_RD_XIY)); }
static void add_a_a(void) { D("  %s;",M_ADD_S("RA")); }
static void add_a_b(void) { D("  %s;",M_ADD_S("RB")); }
static void add_a_c(void) { D("  %s;",M_ADD_S("RC")); }
static void add_a_d(void) { D("  %s;",M_ADD_S("RD")); }
static void add_a_e(void) { D("  %s;",M_ADD_S("RE")); }
static void add_a_h(void) { D("  %s;",M_ADD_S("RH")); }
static void add_a_l(void) { D("  %s;",M_ADD_S("RL")); }
static void add_a_ixl(void) { D("  %s;",M_ADD_S("RX")); }
static void add_a_ixh(void) { D("  %s;",M_ADD_S("RI")); }
static void add_a_iyl(void) { D("  %s;",M_ADD_S("RY")); }
static void add_a_iyh(void) { D("  %s;",M_ADD_S("RJ")); }
static void add_a_byte(void) { D("  %s;", M_ADD_S(S("0x%02x", M_RDMEM_OPCODE()))); }

static void add_hl_bc(void) { D("  %s;", M_ADDW_S("HL","BC")); }
static void add_hl_de(void) { D("  %s;", M_ADDW_S("HL","DE")); }
static void add_hl_hl(void) { D("  %s;", M_ADDW_S("HL","HL")); }
static void add_hl_sp(void) { D("  %s;", M_ADDW_S("HL","SP")); }
static void add_ix_bc(void) { D("  %s;", M_ADDW_S("IX","BC")); }
static void add_ix_de(void) { D("  %s;", M_ADDW_S("IX","DE")); }
static void add_ix_ix(void) { D("  %s;", M_ADDW_S("IX","IX")); }
static void add_ix_sp(void) { D("  %s;", M_ADDW_S("IX","SP")); }
static void add_iy_bc(void) { D("  %s;", M_ADDW_S("IY","BC")); }
static void add_iy_de(void) { D("  %s;", M_ADDW_S("IY","DE")); }
static void add_iy_iy(void) { D("  %s;", M_ADDW_S("IY","IY")); }
static void add_iy_sp(void) { D("  %s;", M_ADDW_S("IY","SP")); }

static void and_xhl(void) { D("  %s;", M_AND_S("mem[HL]")); }
static void and_xix(void) { D("  %s;", M_AND_S(M_RD_XIX)); }
static void and_xiy(void) { D("  %s;", M_AND_S(M_RD_XIY)); }
static void and_a(void) { D("  RF=ZSPHTable[RA];"); }
static void and_b(void) { D("  %s;", M_AND_S("RB")); }
static void and_c(void) { D("  %s;", M_AND_S("RC")); }
static void and_d(void) { D("  %s;", M_AND_S("RD")); }
static void and_e(void) { D("  %s;", M_AND_S("RE")); }
static void and_h(void) { D("  %s;", M_AND_S("RH")); }
static void and_l(void) { D("  %s;", M_AND_S("RL")); }
static void and_ixh(void) { D("  %s;", M_AND_S("RI")); }
static void and_ixl(void) { D("  %s;", M_AND_S("RX")); }
static void and_iyh(void) { D("  %s;", M_AND_S("RJ")); }
static void and_iyl(void) { D("  %s;", M_AND_S("RY")); }


static void and_byte(void) { D("  %s;", M_AND_S(S("0x%02x", M_RDMEM_OPCODE()))); }

static void bit_0_xhl(void) { D("  %s;", M_BIT_S("0","mem[HL]")); }
static void bit_0_xix(void) { D("  %s;", M_BIT_S("0", M_RD_XIX)); }
static void bit_0_xiy(void) { D("  %s;", M_BIT_S("0", M_RD_XIY)); }
static void bit_0_a(void) { D("  %s;", M_BIT_S("0","RA")); }
static void bit_0_b(void) { D("  %s;", M_BIT_S("0","RB")); }
static void bit_0_c(void) { D("  %s;", M_BIT_S("0","RC")); }
static void bit_0_d(void) { D("  %s;", M_BIT_S("0","RD")); }
static void bit_0_e(void) { D("  %s;", M_BIT_S("0","RE")); }
static void bit_0_h(void) { D("  %s;", M_BIT_S("0","RH")); }
static void bit_0_l(void) { D("  %s;", M_BIT_S("0","RL")); }

static void bit_1_xhl(void) { D("  %s;", M_BIT_S("1","mem[HL]")); }
static void bit_1_xix(void) { D("  %s;", M_BIT_S("1", M_RD_XIX)); }
static void bit_1_xiy(void) { D("  %s;", M_BIT_S("1", M_RD_XIY)); }
static void bit_1_a(void) { D("  %s;", M_BIT_S("1","RA")); }
static void bit_1_b(void) { D("  %s;", M_BIT_S("1","RB")); }
static void bit_1_c(void) { D("  %s;", M_BIT_S("1","RC")); }
static void bit_1_d(void) { D("  %s;", M_BIT_S("1","RD")); }
static void bit_1_e(void) { D("  %s;", M_BIT_S("1","RE")); }
static void bit_1_h(void) { D("  %s;", M_BIT_S("1","RH")); }
static void bit_1_l(void) { D("  %s;", M_BIT_S("1","RL")); }

static void bit_2_xhl(void) { D("  %s;", M_BIT_S("2","mem[HL]")); }
static void bit_2_xix(void) { D("  %s;", M_BIT_S("2", M_RD_XIX)); }
static void bit_2_xiy(void) { D("  %s;", M_BIT_S("2", M_RD_XIY)); }
static void bit_2_a(void) { D("  %s;", M_BIT_S("2","RA")); }
static void bit_2_b(void) { D("  %s;", M_BIT_S("2","RB")); }
static void bit_2_c(void) { D("  %s;", M_BIT_S("2","RC")); }
static void bit_2_d(void) { D("  %s;", M_BIT_S("2","RD")); }
static void bit_2_e(void) { D("  %s;", M_BIT_S("2","RE")); }
static void bit_2_h(void) { D("  %s;", M_BIT_S("2","RH")); }
static void bit_2_l(void) { D("  %s;", M_BIT_S("2","RL")); }

static void bit_3_xhl(void) { D("  %s;", M_BIT_S("3","mem[HL]")); }
static void bit_3_xix(void) { D("  %s;", M_BIT_S("3", M_RD_XIX)); }
static void bit_3_xiy(void) { D("  %s;", M_BIT_S("3", M_RD_XIY)); }
static void bit_3_a(void) { D("  %s;", M_BIT_S("3","RA")); }
static void bit_3_b(void) { D("  %s;", M_BIT_S("3","RB")); }
static void bit_3_c(void) { D("  %s;", M_BIT_S("3","RC")); }
static void bit_3_d(void) { D("  %s;", M_BIT_S("3","RD")); }
static void bit_3_e(void) { D("  %s;", M_BIT_S("3","RE")); }
static void bit_3_h(void) { D("  %s;", M_BIT_S("3","RH")); }
static void bit_3_l(void) { D("  %s;", M_BIT_S("3","RL")); }

static void bit_4_xhl(void) { D("  %s;", M_BIT_S("4","mem[HL]")); }
static void bit_4_xix(void) { D("  %s;", M_BIT_S("4", M_RD_XIX)); }
static void bit_4_xiy(void) { D("  %s;", M_BIT_S("4", M_RD_XIY)); }
static void bit_4_a(void) { D("  %s;", M_BIT_S("4","RA")); }
static void bit_4_b(void) { D("  %s;", M_BIT_S("4","RB")); }
static void bit_4_c(void) { D("  %s;", M_BIT_S("4","RC")); }
static void bit_4_d(void) { D("  %s;", M_BIT_S("4","RD")); }
static void bit_4_e(void) { D("  %s;", M_BIT_S("4","RE")); }
static void bit_4_h(void) { D("  %s;", M_BIT_S("4","RH")); }
static void bit_4_l(void) { D("  %s;", M_BIT_S("4","RL")); }

static void bit_5_xhl(void) { D("  %s;", M_BIT_S("5","mem[HL]")); }
static void bit_5_xix(void) { D("  %s;", M_BIT_S("5", M_RD_XIX)); }
static void bit_5_xiy(void) { D("  %s;", M_BIT_S("5", M_RD_XIY)); }
static void bit_5_a(void) { D("  %s;", M_BIT_S("5","RA")); }
static void bit_5_b(void) { D("  %s;", M_BIT_S("5","RB")); }
static void bit_5_c(void) { D("  %s;", M_BIT_S("5","RC")); }
static void bit_5_d(void) { D("  %s;", M_BIT_S("5","RD")); }
static void bit_5_e(void) { D("  %s;", M_BIT_S("5","RE")); }
static void bit_5_h(void) { D("  %s;", M_BIT_S("5","RH")); }
static void bit_5_l(void) { D("  %s;", M_BIT_S("5","RL")); }

static void bit_6_xhl(void) { D("  %s;", M_BIT_S("6","mem[HL]")); }
static void bit_6_xix(void) { D("  %s;", M_BIT_S("6", M_RD_XIX)); }
static void bit_6_xiy(void) { D("  %s;", M_BIT_S("6", M_RD_XIY)); }
static void bit_6_a(void) { D("  %s;", M_BIT_S("6","RA")); }
static void bit_6_b(void) { D("  %s;", M_BIT_S("6","RB")); }
static void bit_6_c(void) { D("  %s;", M_BIT_S("6","RC")); }
static void bit_6_d(void) { D("  %s;", M_BIT_S("6","RD")); }
static void bit_6_e(void) { D("  %s;", M_BIT_S("6","RE")); }
static void bit_6_h(void) { D("  %s;", M_BIT_S("6","RH")); }
static void bit_6_l(void) { D("  %s;", M_BIT_S("6","RL")); }

static void bit_7_xhl(void) { D("  %s;", M_BIT_S("7","mem[HL]")); }
static void bit_7_xix(void) { D("  %s;", M_BIT_S("7", M_RD_XIX)); }
static void bit_7_xiy(void) { D("  %s;", M_BIT_S("7", M_RD_XIY)); }
static void bit_7_a(void) { D("  %s;", M_BIT_S("7","RA")); }
static void bit_7_b(void) { D("  %s;", M_BIT_S("7","RB")); }
static void bit_7_c(void) { D("  %s;", M_BIT_S("7","RC")); }
static void bit_7_d(void) { D("  %s;", M_BIT_S("7","RD")); }
static void bit_7_e(void) { D("  %s;", M_BIT_S("7","RE")); }
static void bit_7_h(void) { D("  %s;", M_BIT_S("7","RH")); }
static void bit_7_l(void) { D("  %s;", M_BIT_S("7","RL")); }

static void call_c(void) { D("  if (%s) {%s;}", M_C, M_CALL_S); }
static void call_m(void) { D("  if (%s) {%s;}", M_M, M_CALL_S); }
static void call_nc(void) { D("  if (%s) {%s;}", M_NC, M_CALL_S); }
static void call_nz(void) { D("  if (%s) {%s;}", M_NZ, M_CALL_S); }
static void call_p(void) { D("  if (%s) {%s;}", M_P, M_CALL_S); }
static void call_pe(void) { D("  if (%s) {%s;}", M_PE, M_CALL_S); }
static void call_po(void) { D("  if (%s) {%s;}", M_PO, M_CALL_S); }
static void call_z(void) { D("  if (%s) {%s;}", M_Z, M_CALL_S); }
static void call(void) { D("  %s;", M_CALL_S); }

static void ccf(void) { D("  RF=((RF&0xED)|((RF&1)<<4))^1;"); }

static void cp_xhl(void) { D("  %s;", M_CP_S("mem[HL]")); }
static void cp_xix(void) { D("  %s;", M_CP_S(M_RD_XIX)); }
static void cp_xiy(void) { D("  %s;", M_CP_S(M_RD_XIY)); }
static void cp_a(void) { D("  %s;", M_CP_S("RA")); }
static void cp_b(void) { D("  %s;", M_CP_S("RB")); }
static void cp_c(void) { D("  %s;", M_CP_S("RC")); }
static void cp_d(void) { D("  %s;", M_CP_S("RD")); }
static void cp_e(void) { D("  %s;", M_CP_S("RE")); }
static void cp_h(void) { D("  %s;", M_CP_S("RH")); }
static void cp_l(void) { D("  %s;", M_CP_S("RL")); }
static void cp_ixh(void) { D("  %s;", M_CP_S("RI")); }
static void cp_ixl(void) { D("  %s;", M_CP_S("RX")); }
static void cp_iyh(void) { D("  %s;", M_CP_S("RJ")); }
static void cp_iyl(void) { D("  %s;", M_CP_S("RY")); }
static void cp_byte(void) { D("  %s;", M_CP_S(S("0x%02x", M_RDMEM_OPCODE()))); }

static void cpd(void)
{
D("  i=mem[HL--]; j=RA-i;");
D("  --BC;");
D("  RF=(RF&C_FLAG)|ZSTable[j]|((RA^i^j)&H_FLAG)|( BC ? V_FLAG:0)|N_FLAG;");
}

static void cpdr(void)
{
 D("  {");
 D("    i=mem[HL--]; j=RA-i;");
 D("    --BC;");
 D("    RF=(RF&C_FLAG)|ZSTable[j]|((RA^i^j)&H_FLAG)|( BC ? V_FLAG:0)|N_FLAG;");
 D("  } while (BC && !(RF&Z_FLAG));");
}

static void cpi(void)
{
D("  i=mem[HL++];j=RA-i;");
D("  --BC;");
D("  RF=(RF&C_FLAG)|ZSTable[j]|((RA^i^j)&H_FLAG)|( BC ? V_FLAG:0)|N_FLAG;");
}

static void cpir(void)
{
 D("  do {");
 D("    i=mem[HL++];j=RA-i;");
 D("    --BC;");
 D("    RF=(RF&C_FLAG)|ZSTable[j]|((RA^i^j)&H_FLAG)|( BC ? V_FLAG:0)|N_FLAG;");
 D("  } while (BC && !(RF&Z_FLAG));");
}

static void cpl(void) { D("  RA^=0xFF; RF|=(H_FLAG|N_FLAG);"); }

static void daa(void)
{
D("  i=RA;");
D("  if (RF&C_FLAG) i|=256;");
D("  if (RF&H_FLAG) i|=512;");
D("  if (RF&N_FLAG) i|=1024;");
D("  AF=DAATable[i];");
};

static void dec_xhl(void)
{
D("  %s;", M_DEC_S("mem[HL]"));
}
static void dec_xix(void)
{
D("  %s;", M_DEC_S(S("mem[%s]", M_XIX)));
}
static void dec_xiy(void)
{
D("  %s;", M_DEC_S(S("mem[%s]", M_XIY)));
}
static void dec_a(void) { D("  %s;", M_DEC_S("RA")); }
static void dec_b(void) { D("  %s;", M_DEC_S("RB")); }
static void dec_c(void) { D("  %s;", M_DEC_S("RC")); }
static void dec_d(void) { D("  %s;", M_DEC_S("RD")); }
static void dec_e(void) { D("  %s;", M_DEC_S("RE")); }
static void dec_h(void) { D("  %s;", M_DEC_S("RH")); }
static void dec_l(void) { D("  %s;", M_DEC_S("RL")); }
static void dec_ixh(void) { D("  %s;", M_DEC_S("RI")); }
static void dec_ixl(void) { D("  %s;", M_DEC_S("RX")); }
static void dec_iyh(void) { D("  %s;", M_DEC_S("RJ")); }
static void dec_iyl(void) { D("  %s;", M_DEC_S("RY")); }

static void dec_bc(void) { D("  --BC;"); }
static void dec_de(void) { D("  --DE;"); }
static void dec_hl(void) { D("  --HL;"); }
static void dec_ix(void) { D("  --IX;"); }
static void dec_iy(void) { D("  --IY;"); }
static void dec_sp(void) { D("  --SP;"); }

static void di(void) { D("  IFF1=IFF2=0;"); }

static void djnz(void) { D("  if (--RB) %s;", M_JR_S); }

static void ex_xsp_hl(void)
{
D("  i=mem[SP]+(mem[SP+1]<<8);");
D("  mem[SP]=RH; mem[SP+1]=RL;");
D("  HL=i;");
}

static void ex_xsp_ix(void)
{
D("  i=mem[SP]+(mem[SP+1]<<8);");
D("  mem[SP]=RX; mem[SP+1]=RI;");
D("  IX=i;");
}

static void ex_xsp_iy(void)
{
D("  i=mem[SP]+(mem[SP+1]<<8);");
D("  mem[SP]=RJ; mem[SP+1]=RY;");
D("  IY=i;");
}

static void ex_af_af(void)
{
D("  i=AF;");
D("  AF=AF2;");
D("  AF2=i;");
}

static void ex_de_hl(void)
{
D("  i=DE;");
D("  DE=HL;");
D("  HL=i;");
}

static void exx(void)
{
D("  i=BC;");
D("  BC=BC2;");
D("  BC2=i;");
D("  i=DE;");
D("  DE=DE2;");
D("  DE2=i;");
D("  i=HL;");
D("  HL=HL2;");
D("  HL2=i;");
}

static void halt(void)
{
// In Ms Pacman, the code does EI:HALT then waits for an
// interrupt which takes us to address 3000...
D("  R.HALT=1; goto L3000;");
}

static void im_0(void) { D("  R.IM=0;"); }
static void im_1(void) { D("  R.IM=1;"); }
static void im_2(void) { D("  R.IM=2;"); }

static void in_a_c(void) { D("  %s;", M_IN_S("RA")); }
static void in_b_c(void) { D("  %s;", M_IN_S("RB")); }
static void in_c_c(void) { D("  %s;", M_IN_S("RC")); }
static void in_d_c(void) { D("  %s;", M_IN_S("RD")); }
static void in_e_c(void) { D("  %s;", M_IN_S("RE")); }
static void in_h_c(void) { D("  %s;", M_IN_S("RH")); }
static void in_l_c(void) { D("  %s;", M_IN_S("RL")); }
static void in_0_c(void) { D("  %s; /*CHECK THIS!*/", M_IN_S("i")); }

static void in_a_byte(void)
{
D("  RA=DoIn(0x%02x,RA);", M_RDMEM_OPCODE());
}

static void inc_xhl(void)
{
D("  %s;", M_INC_S("mem[HL]"));
}
static void inc_xix(void)
{
 D("  %s;", M_INC_S(S("mem[%s]", M_XIX)));
}
static void inc_xiy(void)
{
 D("  %s;", M_INC_S(S("mem[%s]", M_XIY)));
}
static void inc_a(void) { D("  %s;", M_INC_S("RA")); }
static void inc_b(void) { D("  %s;", M_INC_S("RB")); }
static void inc_c(void) { D("  %s;", M_INC_S("RC")); }
static void inc_d(void) { D("  %s;", M_INC_S("RD")); }
static void inc_e(void) { D("  %s;", M_INC_S("RE")); }
static void inc_h(void) { D("  %s;", M_INC_S("RH")); }
static void inc_l(void) { D("  %s;", M_INC_S("RL")); }
static void inc_ixh(void) { D("  %s;", M_INC_S("RI")); }
static void inc_ixl(void) { D("  %s;", M_INC_S("RX")); }
static void inc_iyh(void) { D("  %s;", M_INC_S("RJ")); }
static void inc_iyl(void) { D("  %s;", M_INC_S("RY")); }

static void inc_bc(void) { D("  RB += PostIncCarry[++RC];"); }
static void inc_de(void) { D("  RD += PostIncCarry[++RE];"); }
static void inc_hl(void) { D("  ++HL;"); }
static void inc_ix(void) { D("  ++IX;"); }
static void inc_iy(void) { D("  ++IY;"); }
static void inc_sp(void) { D("  ++SP;"); }

static void ind(void)
{
D("  --RB;");
D("  mem[HL]=DoIn(RC,RB);");
D("  --HL;");
D("  RF=RB ? N_FLAG:(N_FLAG|Z_FLAG);");
}

static void indr(void)
{
 ind ();
D("  if (RB) { Z80_ICount-=5; PC-=2; }");
}

static void ini(void)
{
D("  --RB;");
D("  mem[HL]=DoIn(RC,RB);");
D("  ++HL;");
D("  RF=RB ? N_FLAG:(N_FLAG|Z_FLAG);");
}

static void inir(void)
{
 ini ();
D("  if (RB) { Z80_ICount-=5; PC-=2; }");
}

static void jp(void) { D("  %s;", M_JP_S); }
static void jp_hl(void) { D("  PC=HL; goto *lab[PC];"); }
static void jp_ix(void) { D("  PC=IX; goto *lab[PC];"); }
static void jp_iy(void) { D("  PC=IY; goto *lab[PC];"); }
static void jp_c(void) { D("  if (%s) {%s;}", M_C, M_JP_S); }
static void jp_m(void) { D("  if (%s) {%s;}", M_M, M_JP_S); }
static void jp_nc(void) { D("  if (%s) {%s;}", M_NC, M_JP_S); }
static void jp_nz(void) { D("  if (%s) {%s;}", M_NZ, M_JP_S); }
static void jp_p(void) { D("  if (%s) {%s;}", M_P, M_JP_S); }
static void jp_pe(void) { D("  if (%s) {%s;}", M_PE, M_JP_S); }
static void jp_po(void) { D("  if (%s) {%s;}", M_PO, M_JP_S); }
static void jp_z(void) { D("  if (%s) {%s;}", M_Z, M_JP_S); }

static void jr(void) { D("  %s;", M_JR_S); }
static void jr_c(void) { D("  if (%s) {%s;}", M_C, M_JR_S); }
static void jr_nc(void) { D("  if (%s) {%s;}", M_NC, M_JR_S); }
static void jr_nz(void) { D("  if (%s) {%s;}", M_NZ, M_JR_S); }
static void jr_z(void) { D("  if (%s) {%s;}", M_Z, M_JR_S); }

static void ld_xbc_a(void) { D("  mem[BC]=RA;"); }
static void ld_xde_a(void) { D("  mem[DE]=RA;"); }
static void ld_xhl_a(void) { D("  mem[HL]=RA;"); }
static void ld_xhl_b(void) { D("  mem[HL]=RB;"); }
static void ld_xhl_c(void) { D("  mem[HL]=RC;"); }
static void ld_xhl_d(void) { D("  mem[HL]=RD;"); }
static void ld_xhl_e(void) { D("  mem[HL]=RE;"); }
static void ld_xhl_h(void) { D("  mem[HL]=RH;"); }
static void ld_xhl_l(void) { D("  mem[HL]=RL;"); }
static void ld_xhl_byte(void) { D("  mem[HL]=0x%02x;", M_RDMEM_OPCODE()); }
static void ld_xix_a(void) { M_WR_XIX_S("RA"); }
static void ld_xix_b(void) { M_WR_XIX_S("RB"); }
static void ld_xix_c(void) { M_WR_XIX_S("RC"); }
static void ld_xix_d(void) { M_WR_XIX_S("RD"); }
static void ld_xix_e(void) { M_WR_XIX_S("RE"); }
static void ld_xix_h(void) { M_WR_XIX_S("RH"); }
static void ld_xix_l(void) { M_WR_XIX_S("RL"); }
static void ld_xix_byte(void)
{
char *s = M_XIX; // force correct order of evaluation
D("  mem[%s]=0x%02x;", s, M_RDMEM_OPCODE());
}
static void ld_xiy_a(void) { M_WR_XIY_S("RA"); }
static void ld_xiy_b(void) { M_WR_XIY_S("RB"); }
static void ld_xiy_c(void) { M_WR_XIY_S("RC"); }
static void ld_xiy_d(void) { M_WR_XIY_S("RD"); }
static void ld_xiy_e(void) { M_WR_XIY_S("RE"); }
static void ld_xiy_h(void) { M_WR_XIY_S("RH"); }
static void ld_xiy_l(void) { M_WR_XIY_S("RL"); }
static void ld_xiy_byte(void)
{
char *s = M_XIY; // force correct order of evaluation
D("  mem[%s]=0x%02x;", s, M_RDMEM_OPCODE());
}
static char *writemems(int addr, char *value) {
  static char s[128];
  sprintf(s, "mem[0x%04x]=%s", addr, value);
  return s;
}
static char *readmems(int addr) {
  static char s[128];
  sprintf(s, "mem[0x%04x]", addr);
  return s;
}
static void ld_xbyte_a(void)
{ int i=M_RDMEM_OPCODE_WORD(); D("  %s;", writemems(i, "RA")); }
static void ld_xword_bc(void) { D("  BC=%s;", readmems(M_RDMEM_OPCODE_WORD())); }
static void ld_xword_de(void) { D("  DE=%s;", readmems(M_RDMEM_OPCODE_WORD())); }
static void ld_xword_hl(void) { D("  HL=%s;", readmems(M_RDMEM_OPCODE_WORD())); }
static void ld_xword_ix(void) { D("  IX=%s;", readmems(M_RDMEM_OPCODE_WORD())); }
static void ld_xword_iy(void) { D("  IY=%s;", readmems(M_RDMEM_OPCODE_WORD())); }
static void ld_xword_sp(void) { D("  SP=%s;", readmems(M_RDMEM_OPCODE_WORD())); }

static void ld_a_xbc(void) { D("  RA=mem[BC];"); }
static void ld_a_xde(void) { D("  RA=mem[DE];"); }
static void ld_a_xhl(void) { D("  RA=mem[HL];"); }
static void ld_a_xix(void) { D("  RA=%s;", M_RD_XIX); }
static void ld_a_xiy(void) { D("  RA=%s;", M_RD_XIY); }
static void ld_a_xbyte(void) { D("  RA=%s;", readmems(M_RDMEM_OPCODE_WORD())); }

static void ld_a_byte(void) { D("  RA=0x%02x;", M_RDMEM_OPCODE()); }
static void ld_b_byte(void) { D("  RB=0x%02x;", M_RDMEM_OPCODE()); }
static void ld_c_byte(void) { D("  RC=0x%02x;", M_RDMEM_OPCODE()); }
static void ld_d_byte(void) { D("  RD=0x%02x;", M_RDMEM_OPCODE()); }
static void ld_e_byte(void) { D("  RE=0x%02x;", M_RDMEM_OPCODE()); }
static void ld_h_byte(void) { D("  RH=0x%02x;", M_RDMEM_OPCODE()); }
static void ld_l_byte(void) { D("  RL=0x%02x;;", M_RDMEM_OPCODE()); }
static void ld_ixh_byte(void) { D("  RI=0x%02x;", M_RDMEM_OPCODE()); }
static void ld_ixl_byte(void) { D("  RX=0x%02x;", M_RDMEM_OPCODE()); }
static void ld_iyh_byte(void) { D("  RJ=0x%02x;", M_RDMEM_OPCODE()); }
static void ld_iyl_byte(void) { D("  RY=0x%02x;", M_RDMEM_OPCODE()); }

static void ld_b_xhl(void) { D("  RB=mem[HL];"); }
static void ld_c_xhl(void) { D("  RC=mem[HL];"); }
static void ld_d_xhl(void) { D("  RD=mem[HL];"); }
static void ld_e_xhl(void) { D("  RE=mem[HL];"); }
static void ld_h_xhl(void) { D("  RH=mem[HL];"); }
static void ld_l_xhl(void) { D("  RL=mem[HL];"); }
static void ld_b_xix(void) { D("  RB=%s;", M_RD_XIX); }
static void ld_c_xix(void) { D("  RC=%s;", M_RD_XIX); }
static void ld_d_xix(void) { D("  RD=%s;", M_RD_XIX); }
static void ld_e_xix(void) { D("  RE=%s;", M_RD_XIX); }
static void ld_h_xix(void) { D("  RH=%s;", M_RD_XIX); }
static void ld_l_xix(void) { D("  RL=%s;", M_RD_XIX); }
static void ld_b_xiy(void) { D("  RB=%s;", M_RD_XIY); }
static void ld_c_xiy(void) { D("  RC=%s;", M_RD_XIY); }
static void ld_d_xiy(void) { D("  RD=%s;", M_RD_XIY); }
static void ld_e_xiy(void) { D("  RE=%s;", M_RD_XIY); }
static void ld_h_xiy(void) { D("  RH=%s;", M_RD_XIY); }
static void ld_l_xiy(void) { D("  RL=%s;", M_RD_XIY); }
static void ld_a_a(void) { }
static void ld_a_b(void) { D("  RA=RB;"); }
static void ld_a_c(void) { D("  RA=RC;"); }
static void ld_a_d(void) { D("  RA=RD;"); }
static void ld_a_e(void) { D("  RA=RE;"); }
static void ld_a_h(void) { D("  RA=RH;"); }
static void ld_a_l(void) { D("  RA=RL;"); }
static void ld_a_ixh(void) { D("  RA=RI;"); }
static void ld_a_ixl(void) { D("  RA=RX;"); }
static void ld_a_iyh(void) { D("  RA=RJ;"); }
static void ld_a_iyl(void) { D("  RA=RY;"); }
static void ld_b_b(void) { }
static void ld_b_a(void) { D("  RB=RA;"); }
static void ld_b_c(void) { D("  RB=RC;"); }
static void ld_b_d(void) { D("  RB=RD;"); }
static void ld_b_e(void) { D("  RB=RE;"); }
static void ld_b_h(void) { D("  RB=RH;"); }
static void ld_b_l(void) { D("  RB=RL;"); }
static void ld_b_ixh(void) { D("  RB=RI;"); }
static void ld_b_ixl(void) { D("  RB=RX;"); }
static void ld_b_iyh(void) { D("  RB=RJ;"); }
static void ld_b_iyl(void) { D("  RB=RY;"); }
static void ld_c_c(void) { }
static void ld_c_a(void) { D("  RC=RA;"); }
static void ld_c_b(void) { D("  RC=RB;"); }
static void ld_c_d(void) { D("  RC=RD;"); }
static void ld_c_e(void) { D("  RC=RE;"); }
static void ld_c_h(void) { D("  RC=RH;"); }
static void ld_c_l(void) { D("  RC=RL;"); }
static void ld_c_ixh(void) { D("  RC=RI;"); }
static void ld_c_ixl(void) { D("  RC=RX;"); }
static void ld_c_iyh(void) { D("  RC=RJ;"); }
static void ld_c_iyl(void) { D("  RC=RY;"); }
static void ld_d_d(void) { }
static void ld_d_a(void) { D("  RD=RA;"); }
static void ld_d_c(void) { D("  RD=RC;"); }
static void ld_d_b(void) { D("  RD=RB;"); }
static void ld_d_e(void) { D("  RD=RE;"); }
static void ld_d_h(void) { D("  RD=RH;"); }
static void ld_d_l(void) { D("  RD=RL;"); }
static void ld_d_ixh(void) { D("  RD=RI;"); }
static void ld_d_ixl(void) { D("  RD=RX;"); }
static void ld_d_iyh(void) { D("  RD=RJ;"); }
static void ld_d_iyl(void) { D("  RD=RY;"); }
static void ld_e_e(void) { }
static void ld_e_a(void) { D("  RE=RA;"); }
static void ld_e_c(void) { D("  RE=RC;"); }
static void ld_e_b(void) { D("  RE=RB;"); }
static void ld_e_d(void) { D("  RE=RD;"); }
static void ld_e_h(void) { D("  RE=RH;"); }
static void ld_e_l(void) { D("  RE=RL;"); }
static void ld_e_ixh(void) { D("  RE=RI;"); }
static void ld_e_ixl(void) { D("  RE=RX;"); }
static void ld_e_iyh(void) { D("  RE=RJ;"); }
static void ld_e_iyl(void) { D("  RE=RY;"); }
static void ld_h_h(void) { }
static void ld_h_a(void) { D("  RH=RA;"); }
static void ld_h_c(void) { D("  RH=RC;"); }
static void ld_h_b(void) { D("  RH=RB;"); }
static void ld_h_e(void) { D("  RH=RE;"); }
static void ld_h_d(void) { D("  RH=RD;"); }
static void ld_h_l(void) { D("  RH=RL;"); }
static void ld_l_l(void) { }
static void ld_l_a(void) { D("  RL=RA;"); }
static void ld_l_c(void) { D("  RL=RC;"); }
static void ld_l_b(void) { D("  RL=RB;"); }
static void ld_l_e(void) { D("  RL=RE;"); }
static void ld_l_d(void) { D("  RL=RD;"); }
static void ld_l_h(void) { D("  RL=RH;"); }
static void ld_ixh_a(void) { D("  RI=RA;"); }
static void ld_ixh_b(void) { D("  RI=RB;"); }
static void ld_ixh_c(void) { D("  RI=RC;"); }
static void ld_ixh_d(void) { D("  RI=RD;"); }
static void ld_ixh_e(void) { D("  RI=RE;"); }
static void ld_ixh_ixh(void) { }
static void ld_ixh_ixl(void) { D("  RI=RX;"); }
static void ld_ixl_a(void) { D("  RX=RA;"); }
static void ld_ixl_b(void) { D("  RX=RB;"); }
static void ld_ixl_c(void) { D("  RX=RC;"); }
static void ld_ixl_d(void) { D("  RX=RD;"); }
static void ld_ixl_e(void) { D("  RX=RE;"); }
static void ld_ixl_ixh(void) { D("  RX=RI;"); }
static void ld_ixl_ixl(void) { }
static void ld_iyh_a(void) { D("  RJ=RA;"); }
static void ld_iyh_b(void) { D("  RJ=RB;"); }
static void ld_iyh_c(void) { D("  RJ=RC;"); }
static void ld_iyh_d(void) { D("  RJ=RD;"); }
static void ld_iyh_e(void) { D("  RJ=RE;"); }
static void ld_iyh_iyh(void) { }
static void ld_iyh_iyl(void) { D("  RJ=RY;"); }
static void ld_iyl_a(void) { D("  RY=RA;"); }
static void ld_iyl_b(void) { D("  RY=RB;"); }
static void ld_iyl_c(void) { D("  RY=RC;"); }
static void ld_iyl_d(void) { D("  RY=RD;"); }
static void ld_iyl_e(void) { D("  RY=RE;"); }
static void ld_iyl_iyh(void) { D("  RY=RJ;"); }
static void ld_iyl_iyl(void) { }

static void ld_bc_xword(void)
{
  int i = M_RDMEM_OPCODE_WORD();
  D("  RB=mem[0x%04x];RC=mem[0x%04x];", i+1, i);
}
static void ld_bc_word(void)
{
  int i = M_RDMEM_OPCODE_WORD();
  D("  BC=0x%04x;", i&65535);
}

static void ld_de_xword(void)
{
  int i = M_RDMEM_OPCODE_WORD();
  D("  RD=mem[0x%04x];RE=mem[0x%04x];", i+1, i);
}

static void ld_de_word(void)
{
  int i = M_RDMEM_OPCODE_WORD();
  D("  DE=0x%04x;", i&65535);
}

static void ld_hl_xword(void)
{
  int i = M_RDMEM_OPCODE_WORD();
  D("  RH=mem[0x%04x];", i+1);
  D("  RL=mem[0x%04x];", i);
}
static void ld_hl_word(void) { D("  HL=0x%04x;", M_RDMEM_OPCODE_WORD()); }

static void ld_ix_xword(void)
{
  int i = M_RDMEM_OPCODE_WORD();
  D("  RI=mem[0x%04x];", i+1);
  D("  RX=mem[0x%04x];", i);
}
static void ld_ix_word(void) { D("  IX=0x%04x;", M_RDMEM_OPCODE_WORD()); }

static void ld_iy_xword(void)
{
  int i = M_RDMEM_OPCODE_WORD();
  D("  RJ=mem[0x%04x];", i+1);
  D("  RY=mem[0x%04x];", i);
}
static void ld_iy_word(void) { D("  IY=0x%04x;", M_RDMEM_OPCODE_WORD()); }

static void ld_sp_xword(void)
{
  int i = M_RDMEM_OPCODE_WORD();
  D("  SP_lo=mem[0x%04x];SP_hi=mem[0x%04x];", i, i+1);
}
static void ld_sp_word(void) { D("  SP=0x%04x;", M_RDMEM_OPCODE_WORD()); }

static void ld_sp_hl(void) { D("  SP=HL;"); }
static void ld_sp_ix(void) { D("  SP=IX;"); }
static void ld_sp_iy(void) { D("  SP=IY;"); }
static void ld_a_i(void)
{
D("  RA=R.I;");
D("  RF=(RF&C_FLAG)|ZSTable[R.I]|(IFF2<<2);");
}
static void ld_i_a(void) { D("  R.I=RA;"); }
static void ld_a_r(void)
{
D("  RA=rand(); // RA=(R.R&127)|(R.R2&128);");
D("  RF=(RF&C_FLAG)|ZSTable[RA]|(IFF2<<2);");
}
static void ld_r_a(void) {
  //D("  // R.R=R.R2=RA;");
}

static void ldd(void)
{
D("  mem[DE--]=mem[HL--];");
D("  --BC;");
D("  RF=(RF&0xE9)|( BC ? V_FLAG:0);");
}
static void lddr(void)
{
 D("  do { /* Might later optimise to a memmove() call? */");
 D("    mem[DE--]=mem[HL--];");
 D("  } while (--BC);");
 D("  RF&=0xE9;");
//D("  if (BC) { Z80_ICount-=5; PC-=2; }");
}
static void ldi(void)
{
D("  mem[DE++]=mem[HL++];");
D("  --BC;");
D("  RF=(RF&0xE9)|( BC ? V_FLAG:0);");
}

static void ldir(void)
{
 D("  do { /* Might later optimise to a memmove() call? */");
 D("    mem[DE++]=mem[HL++];");
 D("  } while (--BC);");
 D("  RF&=0xE9;");
//D("  if (BC) { Z80_ICount-=5; PC-=2; }");
}

static void neg(void)
{
D("  i=RA;");
D("  RA=0;");
D("  %s;", M_SUB_S("i"));
}

static void nop(void) { };

static void or_xhl(void) { D("  %s;", M_OR_S("mem[HL]")); }
static void or_xix(void) { D("  %s;", M_OR_S(M_RD_XIX)); }
static void or_xiy(void) { D("  %s;", M_OR_S(M_RD_XIY)); }
static void or_a(void) { D("  RF=ZSPTable[RA];"); }
static void or_b(void) { D("  %s;", M_OR_S("RB")); }
static void or_c(void) { D("  %s;", M_OR_S("RC")); }
static void or_d(void) { D("  %s;", M_OR_S("RD")); }
static void or_e(void) { D("  %s;", M_OR_S("RE")); }
static void or_h(void) { D("  %s;", M_OR_S("RH")); }
static void or_l(void) { D("  %s;", M_OR_S("RL")); }
static void or_ixh(void) { D("  %s;", M_OR_S("RI")); }
static void or_ixl(void) { D("  %s;", M_OR_S("RX")); }
static void or_iyh(void) { D("  %s;", M_OR_S("RJ")); }
static void or_iyl(void) { D("  %s;", M_OR_S("RY")); }
static void or_byte(void) { D("  %s;", M_OR_S(S("0x%02x", M_RDMEM_OPCODE()))); }

static void outd(void)
{
D("    --RB;");
D("    DoOut (RC,RB,mem[HL]);");
D("    --HL;");
D("    RF=RB ? N_FLAG:(Z_FLAG|N_FLAG);");
}
static void otdr(void)
{
D("  do {");
     outd ();
D("  } while (RB);");
//D("  if (RB) { Z80_ICount-=5; PC-=2; }");
}
static void outi(void)
{
D("  --RB;");
D("  DoOut (RC,RB,mem[HL]);");
D("  ++HL;");
D("  RF=RB ? N_FLAG:(Z_FLAG|N_FLAG);");
}
static void otir(void)
{
D("  do {");
     outi ();
D("  } while (RB);");
//D("  if (RB) { Z80_ICount-=5; PC-=2; }");
}

static void out_c_a(void) { D("  DoOut(RC,RB,RA);"); }
static void out_c_b(void) { D("  DoOut(RC,RB,RB);"); }
static void out_c_c(void) { D("  DoOut(RC,RB,RC);"); }
static void out_c_d(void) { D("  DoOut(RC,RB,RD);"); }
static void out_c_e(void) { D("  DoOut(RC,RB,RE);"); }
static void out_c_h(void) { D("  DoOut(RC,RB,RH);"); }
static void out_c_l(void) { D("  DoOut(RC,RB,RL);"); }
static void out_c_0(void) { D("  DoOut(RC,RB,0);"); }
static void out_byte_a(void)
{
D("  DoOut(0x%02x,RA,RA);", M_RDMEM_OPCODE());
}

static void pop_af(void) { D("  %s;", M_POP2_S("RA","RF")); }
static void pop_bc(void) { D("  %s;", M_POP2X_S("BC","RB","RC")); }
static void pop_de(void) { D("  %s;", M_POP2X_S("DE","RD","RE")); }
static void pop_hl(void) { D("  %s;", M_POP_S("HL")); }
static void pop_ix(void) { D("  %s;", M_POP_S("IX")); }
static void pop_iy(void) { D("  %s;", M_POP_S("IY")); }

static void push_af(void) { M_PUSH2_S("RA","RF"); }
static void push_bc(void) { M_PUSH2_S("RB","RC"); }
static void push_de(void) { M_PUSH2_S("RD","RE"); }
static void push_hl(void) { M_PUSH_S("HL"); }
static void push_ix(void) { M_PUSH_S("IX"); }
static void push_iy(void) { M_PUSH_S("IY"); }

static void res_0_xhl(void)
{
D("  %s;", M_RES_S("0","mem[HL]"));
};
static void res_0_xix(void)
{
D("  j=%s;", M_XIX);
D("  i=mem[j];");
D("  %s;", M_RES_S("0","i"));
D("  mem[j]=i;");
};
static void res_0_xiy(void)
{
D("  j=%s;", M_XIY);
D("  i=mem[j];");
D("  %s;", M_RES_S("0","i"));
D("  mem[j]=i;");
};
static void res_0_a(void) { D("  %s;", M_RES_S("0","RA")); };
static void res_0_b(void) { D("  %s;", M_RES_S("0","RB")); };
static void res_0_c(void) { D("  %s;", M_RES_S("0","RC")); };
static void res_0_d(void) { D("  %s;", M_RES_S("0","RD")); };
static void res_0_e(void) { D("  %s;", M_RES_S("0","RE")); };
static void res_0_h(void) { D("  %s;", M_RES_S("0","RH")); };
static void res_0_l(void) { D("  %s;", M_RES_S("0","RL")); };

static void res_1_xhl(void)
{
D("  %s;", M_RES_S("1","mem[HL]"));
};
static void res_1_xix(void)
{
D("  j=%s;", M_XIX);
D("  i=mem[j];");
D("  %s;", M_RES_S("1","i"));
D("  mem[j]=i;");
};
static void res_1_xiy(void)
{
D("  j=%s;", M_XIY);
D("  i=mem[j];");
D("  %s;", M_RES_S("1","i"));
D("  mem[j]=i;");
};
static void res_1_a(void) { D("  %s;", M_RES_S("1","RA")); };
static void res_1_b(void) { D("  %s;", M_RES_S("1","RB")); };
static void res_1_c(void) { D("  %s;", M_RES_S("1","RC")); };
static void res_1_d(void) { D("  %s;", M_RES_S("1","RD")); };
static void res_1_e(void) { D("  %s;", M_RES_S("1","RE")); };
static void res_1_h(void) { D("  %s;", M_RES_S("1","RH")); };
static void res_1_l(void) { D("  %s;", M_RES_S("1","RL")); };

static void res_2_xhl(void)
{
D("  %s;", M_RES_S("2","mem[HL]"));
};
static void res_2_xix(void)
{
D("  j=%s;", M_XIX);
D("  i=mem[j];");
D("  %s;", M_RES_S("2","i"));
D("  mem[j]=i;");
};
static void res_2_xiy(void)
{
D("  j=%s;", M_XIY);
D("  i=mem[j];");
D("  %s;", M_RES_S("2","i"));
D("  mem[j]=i;");
};
static void res_2_a(void) { D("  %s;", M_RES_S("2","RA")); };
static void res_2_b(void) { D("  %s;", M_RES_S("2","RB")); };
static void res_2_c(void) { D("  %s;", M_RES_S("2","RC")); };
static void res_2_d(void) { D("  %s;", M_RES_S("2","RD")); };
static void res_2_e(void) { D("  %s;", M_RES_S("2","RE")); };
static void res_2_h(void) { D("  %s;", M_RES_S("2","RH")); };
static void res_2_l(void) { D("  %s;", M_RES_S("2","RL")); };

static void res_3_xhl(void)
{
D("  %s;", M_RES_S("3","mem[HL]"));
};
static void res_3_xix(void)
{
D("  j=%s;", M_XIX);
D("  i=mem[j];");
D("  %s;", M_RES_S("3","i"));
D("  mem[j]=i;");
};
static void res_3_xiy(void)
{
D("  j=%s;", M_XIY);
D("  i=mem[j];");
D("  %s;", M_RES_S("3","i"));
D("  mem[j]=i;");
};
static void res_3_a(void) { D("  %s;", M_RES_S("3","RA")); };
static void res_3_b(void) { D("  %s;", M_RES_S("3","RB")); };
static void res_3_c(void) { D("  %s;", M_RES_S("3","RC")); };
static void res_3_d(void) { D("  %s;", M_RES_S("3","RD")); };
static void res_3_e(void) { D("  %s;", M_RES_S("3","RE")); };
static void res_3_h(void) { D("  %s;", M_RES_S("3","RH")); };
static void res_3_l(void) { D("  %s;", M_RES_S("3","RL")); };

static void res_4_xhl(void)
{
D("  %s;", M_RES_S("4","mem[HL]"));
};
static void res_4_xix(void)
{
D("  j=%s;", M_XIX);
D("  i=mem[j];");
D("  %s;", M_RES_S("4","i"));
D("  mem[j]=i;");
};
static void res_4_xiy(void)
{
D("  j=%s;", M_XIY);
D("  i=mem[j];");
D("  %s;", M_RES_S("4","i"));
D("  mem[j]=i;");
};
static void res_4_a(void) { D("  %s;", M_RES_S("4","RA")); };
static void res_4_b(void) { D("  %s;", M_RES_S("4","RB")); };
static void res_4_c(void) { D("  %s;", M_RES_S("4","RC")); };
static void res_4_d(void) { D("  %s;", M_RES_S("4","RD")); };
static void res_4_e(void) { D("  %s;", M_RES_S("4","RE")); };
static void res_4_h(void) { D("  %s;", M_RES_S("4","RH")); };
static void res_4_l(void) { D("  %s;", M_RES_S("4","RL")); };

static void res_5_xhl(void)
{
D("  %s;", M_RES_S("5","mem[HL]"));
};
static void res_5_xix(void)
{
D("  j=%s;", M_XIX);
D("  i=mem[j];");
D("  %s;", M_RES_S("5","i"));
D("  mem[j]=i;");
};
static void res_5_xiy(void)
{
D("  j=%s;", M_XIY);
D("  i=mem[j];");
D("  %s;", M_RES_S("5","i"));
D("  mem[j]=i;");
};
static void res_5_a(void) { D("  %s;", M_RES_S("5","RA")); };
static void res_5_b(void) { D("  %s;", M_RES_S("5","RB")); };
static void res_5_c(void) { D("  %s;", M_RES_S("5","RC")); };
static void res_5_d(void) { D("  %s;", M_RES_S("5","RD")); };
static void res_5_e(void) { D("  %s;", M_RES_S("5","RE")); };
static void res_5_h(void) { D("  %s;", M_RES_S("5","RH")); };
static void res_5_l(void) { D("  %s;", M_RES_S("5","RL")); };

static void res_6_xhl(void)
{
D("  %s;", M_RES_S("6","mem[HL]"));
};
static void res_6_xix(void)
{
D("  j=%s;", M_XIX);
D("  i=mem[j];");
D("  %s;", M_RES_S("6","i"));
D("  mem[j]=i;");
};
static void res_6_xiy(void)
{
D("  j=%s;", M_XIY);
D("  i=mem[j];");
D("  %s;", M_RES_S("6","i"));
D("  mem[j]=i;");
};
static void res_6_a(void) { D("  %s;", M_RES_S("6","RA")); };
static void res_6_b(void) { D("  %s;", M_RES_S("6","RB")); };
static void res_6_c(void) { D("  %s;", M_RES_S("6","RC")); };
static void res_6_d(void) { D("  %s;", M_RES_S("6","RD")); };
static void res_6_e(void) { D("  %s;", M_RES_S("6","RE")); };
static void res_6_h(void) { D("  %s;", M_RES_S("6","RH")); };
static void res_6_l(void) { D("  %s;", M_RES_S("6","RL")); };

static void res_7_xhl(void)
{
D("  %s;", M_RES_S("7","mem[HL]"));
};
static void res_7_xix(void)
{
D("  j=%s;", M_XIX);
D("  i=mem[j];");
D("  %s;", M_RES_S("7","i"));
D("  mem[j]=i;");
};
static void res_7_xiy(void)
{
D("  j=%s;", M_XIY);
D("  i=mem[j];");
D("  %s;", M_RES_S("7","i"));
D("  mem[j]=i;");
};
static void res_7_a(void) { D("  %s;", M_RES_S("7","RA")); };
static void res_7_b(void) { D("  %s;", M_RES_S("7","RB")); };
static void res_7_c(void) { D("  %s;", M_RES_S("7","RC")); };
static void res_7_d(void) { D("  %s;", M_RES_S("7","RD")); };
static void res_7_e(void) { D("  %s;", M_RES_S("7","RE")); };
static void res_7_h(void) { D("  %s;", M_RES_S("7","RH")); };
static void res_7_l(void) { D("  %s;", M_RES_S("7","RL")); };

static void ret(void) { D("  %s;", M_RET_S); deflab(PC); }
#ifdef COUNTINGCYCLES
static void ret_c(void) { D("  if (%s) { %s; } else { %s; }", M_C, M_RET_S, M_SKIP_RET); }
static void ret_m(void) { D("  if (%s) { %s; } else { %s; }", M_M, M_RET_S, M_SKIP_RET); }
static void ret_nc(void) { D("  if (%s) { %s; } else { %s; }", M_NC, M_RET_S, M_SKIP_RET); }
static void ret_nz(void) { D("  if (%s) { %s; } else { %s; }", M_NZ, M_RET_S, M_SKIP_RET); }
static void ret_p(void) { D("  if (%s) { %s; } else { %s; }", M_P, M_RET_S, M_SKIP_RET); }
static void ret_pe(void) { D("  if (%s) { %s; } else { %s; }", M_PE, M_RET_S, M_SKIP_RET); }
static void ret_po(void) { D("  if (%s) { %s; } else { %s; }", M_PO, M_RET_S, M_SKIP_RET); }
static void ret_z(void) { D("  if (%s) { %s; } else { %s; }", M_Z, M_RET_S, M_SKIP_RET); }
#else
static void ret_c(void) { D("  if (%s) {%s;}", M_C, M_RET_S); }
static void ret_m(void) { D("  if (%s) {%s;}", M_M, M_RET_S); }
static void ret_nc(void) { D("  if (%s) {%s;}", M_NC, M_RET_S); }
static void ret_nz(void) { D("  if (%s) {%s;}", M_NZ, M_RET_S); }
static void ret_p(void) { D("  if (%s) {%s;}", M_P, M_RET_S); }
static void ret_pe(void) { D("  if (%s) {%s;}", M_PE, M_RET_S); }
static void ret_po(void) { D("  if (%s) {%s;}", M_PO, M_RET_S); }
static void ret_z(void) { D("  if (%s) {%s;}", M_Z, M_RET_S); }
#endif

static void reti(void) { D("  Z80_Reti(); %s;", M_RET_S); }
static void retn(void) { D("  IFF1=IFF2; Z80_Retn(); %s;", M_RET_S); }

static void rl_xhl(void)
{
D("  %s;", M_RL_S("mem[HL]"));
}
static void rl_xix(void)
{
D("  %s;", M_RL_S(S("mem[%s]", M_XIX)));
}
static void rl_xiy(void)
{
D("  %s;", M_RL_S(S("mem[%s]", M_XIY)));
}
static void rl_a(void) { D("  %s;", M_RL_S("RA")); }
static void rl_b(void) { D("  %s;", M_RL_S("RB")); }
static void rl_c(void) { D("  %s;", M_RL_S("RC")); }
static void rl_d(void) { D("  %s;", M_RL_S("RD")); }
static void rl_e(void) { D("  %s;", M_RL_S("RE")); }
static void rl_h(void) { D("  %s;", M_RL_S("RH")); }
static void rl_l(void) { D("  %s;", M_RL_S("RL")); }
static void rla(void)  { D("  %s;", M_RLA_S); }

static void rlc_xhl(void)
{
D("  %s;", M_RLC_S("mem[HL]"));
}
static void rlc_xix(void)
{
D("  %s;", M_RLC_S(S("mem[%s]", M_XIX)));
}
static void rlc_xiy(void)
{
D("  %s;", M_RLC_S(S("mem[%s]", M_XIY)));
}
static void rlc_a(void) { D("  %s;", M_RLC_S("RA")); }
static void rlc_b(void) { D("  %s;", M_RLC_S("RB")); }
static void rlc_c(void) { D("  %s;", M_RLC_S("RC")); }
static void rlc_d(void) { D("  %s;", M_RLC_S("RD")); }
static void rlc_e(void) { D("  %s;", M_RLC_S("RE")); }
static void rlc_h(void) { D("  %s;", M_RLC_S("RH")); }
static void rlc_l(void) { D("  %s;", M_RLC_S("RL")); }
static void rlca(void)  { D("  %s;", M_RLCA_S); }

static void rld(void)
{
//D("  byte i;");
D("  i=mem[HL];");
D("  mem[HL]=(i<<4|(RA&0x0F));");
D("  RA=(RA&0xF0)|(i>>4);");
D("  RF=(RF&C_FLAG)|ZSPTable[RA];");
}

static void rr_xhl(void)
{
D("  %s;", M_RR_S("mem[HL]"));
}
static void rr_xix(void)
{
D("  %s;", M_RR_S(S("mem[%s]", M_XIX)));
}
static void rr_xiy(void)
{
D("  %s;", M_RR_S(S("mem[%s]", M_XIY)));
}
static void rr_a(void) { D("  %s;", M_RR_S("RA")); }
static void rr_b(void) { D("  %s;", M_RR_S("RB")); }
static void rr_c(void) { D("  %s;", M_RR_S("RC")); }
static void rr_d(void) { D("  %s;", M_RR_S("RD")); }
static void rr_e(void) { D("  %s;", M_RR_S("RE")); }
static void rr_h(void) { D("  %s;", M_RR_S("RH")); }
static void rr_l(void) { D("  %s;", M_RR_S("RL")); }
static void rra(void)  { D("  %s;", M_RRA_S); }

static void rrc_xhl(void)
{
  D("  %s;", M_RRC_S("mem[HL]")); ///////////////////////////////////////////////////////////////////
}
static void rrc_xix(void)
{
D("  %s;", M_RRC_S(S("mem[%s]", M_XIX)));
}
static void rrc_xiy(void)
{
D("  %s;", M_RRC_S(S("mem[%s]", M_XIY)));
}
static void rrc_a(void) { D("  %s;", M_RRC_S("RA")); }
static void rrc_b(void) { D("  %s;", M_RRC_S("RB")); }
static void rrc_c(void) { D("  %s;", M_RRC_S("RC")); }
static void rrc_d(void) { D("  %s;", M_RRC_S("RD")); }
static void rrc_e(void) { D("  %s;", M_RRC_S("RE")); }
static void rrc_h(void) { D("  %s;", M_RRC_S("RH")); }
static void rrc_l(void) { D("  %s;", M_RRC_S("RL")); }
static void rrca(void)  { D("  %s;", M_RRCA_S); }

static void rrd(void)
{
//D("  byte i;");
D("  i=mem[HL];");
D("  mem[HL]=(i>>4|(RA<<4));");
D("  RA=(RA&0xF0)|(i&0x0F);");
D("  RF=(RF&C_FLAG)|ZSPTable[RA];");
}

void M_RST(int addr)
{
  M_PUSH2_S(H2(PC>>8), H2(PC&255));
  D("  goto L%04x;", addr);
  // Generally there is no drop-through code following these
  // except for:
#ifdef MSPAC
  if (addr <= 0x18)
#endif
    deflab(PC);
}
static void rst_00(void) { M_RST(0x00); }
static void rst_08(void) { M_RST(0x08); }
static void rst_10(void) { M_RST(0x10); }
static void rst_18(void) { M_RST(0x18); }
static void rst_20(void) { M_RST(0x20);
#ifdef MSPAC
  (void)(M_RDMEM_OPCODE(), M_RDMEM_OPCODE(), M_RDMEM_OPCODE(), M_RDMEM_OPCODE()); deflab(PC);
#endif
}
static void rst_28(void) { M_RST(0x28);
#ifdef MSPAC
  (void)(M_RDMEM_OPCODE(), M_RDMEM_OPCODE()); deflab(PC);
#endif
}
static void rst_30(void) { M_RST(0x30);
#ifdef MSPAC
  (void)(M_RDMEM_OPCODE(), M_RDMEM_OPCODE(), M_RDMEM_OPCODE()); deflab(PC);
#endif
}
static void rst_38(void) { M_RST(0x38); }

static void sbc_a_byte(void) { D("  %s;", M_SBC_S(S("0x%02x", M_RDMEM_OPCODE()))); }
static void sbc_a_xhl(void) { D("  %s;", M_SBC_S("mem[HL]")); }
static void sbc_a_xix(void) { D("  %s;", M_SBC_S(M_RD_XIX)); }
static void sbc_a_xiy(void) { D("  %s;", M_SBC_S(M_RD_XIY)); }
static void sbc_a_a(void) { D("  %s;", M_SBC_S("RA")); }
static void sbc_a_b(void) { D("  %s;", M_SBC_S("RB")); }
static void sbc_a_c(void) { D("  %s;", M_SBC_S("RC")); }
static void sbc_a_d(void) { D("  %s;", M_SBC_S("RD")); }
static void sbc_a_e(void) { D("  %s;", M_SBC_S("RE")); }
static void sbc_a_h(void) { D("  %s;", M_SBC_S("RH")); }
static void sbc_a_l(void) { D("  %s;", M_SBC_S("RL")); }
static void sbc_a_ixh(void) { D("  %s;", M_SBC_S("RI")); }
static void sbc_a_ixl(void) { D("  %s;", M_SBC_S("RX")); }
static void sbc_a_iyh(void) { D("  %s;", M_SBC_S("RJ")); }
static void sbc_a_iyl(void) { D("  %s;", M_SBC_S("RY")); }

static void sbc_hl_bc(void) { D("  %s;", M_SBCW_S("BC")); }
static void sbc_hl_de(void) { D("  %s;", M_SBCW_S("DE")); }
static void sbc_hl_hl(void) { D("  %s;", M_SBCW_S("HL")); }
static void sbc_hl_sp(void) { D("  %s;", M_SBCW_S("SP")); }

static void scf(void) { D("  RF=(RF&0xEC)|C_FLAG;"); }

static void set_0_xhl(void)
{
D("  %s;", M_SET_S("0","mem[HL]"));
};
static void set_0_xix(void)
{
D("  %s;", M_SET_S("0",S("mem[%s]", M_XIX)));
};
static void set_0_xiy(void)
{
D("  %s;", M_SET_S("0",S("mem[%s]", M_XIY)));
};
static void set_0_a(void) { D("  %s;", M_SET_S("0","RA")); };
static void set_0_b(void) { D("  %s;", M_SET_S("0","RB")); };
static void set_0_c(void) { D("  %s;", M_SET_S("0","RC")); };
static void set_0_d(void) { D("  %s;", M_SET_S("0","RD")); };
static void set_0_e(void) { D("  %s;", M_SET_S("0","RE")); };
static void set_0_h(void) { D("  %s;", M_SET_S("0","RH")); };
static void set_0_l(void) { D("  %s;", M_SET_S("0","RL")); };

static void set_1_xhl(void)
{
D("  %s;", M_SET_S("1","mem[HL]"));
};
static void set_1_xix(void)
{
D("  %s;", M_SET_S("1",S("mem[%s]", M_XIX)));
};
static void set_1_xiy(void)
{
D("  %s;", M_SET_S("1",S("mem[%s]", M_XIY)));
};
static void set_1_a(void) { D("  %s;", M_SET_S("1","RA")); };
static void set_1_b(void) { D("  %s;", M_SET_S("1","RB")); };
static void set_1_c(void) { D("  %s;", M_SET_S("1","RC")); };
static void set_1_d(void) { D("  %s;", M_SET_S("1","RD")); };
static void set_1_e(void) { D("  %s;", M_SET_S("1","RE")); };
static void set_1_h(void) { D("  %s;", M_SET_S("1","RH")); };
static void set_1_l(void) { D("  %s;", M_SET_S("1","RL")); };

static void set_2_xhl(void)
{
D("  %s;", M_SET_S("2","mem[HL]"));
};
static void set_2_xix(void)
{
D("  %s;", M_SET_S("2",S("mem[%s]", M_XIX)));
};
static void set_2_xiy(void)
{
D("  %s;", M_SET_S("2",S("mem[%s]", M_XIY)));
};
static void set_2_a(void) { D("  %s;", M_SET_S("2","RA")); };
static void set_2_b(void) { D("  %s;", M_SET_S("2","RB")); };
static void set_2_c(void) { D("  %s;", M_SET_S("2","RC")); };
static void set_2_d(void) { D("  %s;", M_SET_S("2","RD")); };
static void set_2_e(void) { D("  %s;", M_SET_S("2","RE")); };
static void set_2_h(void) { D("  %s;", M_SET_S("2","RH")); };
static void set_2_l(void) { D("  %s;", M_SET_S("2","RL")); };

static void set_3_xhl(void)
{
D("  %s;", M_SET_S("3","mem[HL]"));
};
static void set_3_xix(void)
{
D("  %s;", M_SET_S("3",S("mem[%s]", M_XIX)));
};
static void set_3_xiy(void)
{
D("  %s;", M_SET_S("3",S("mem[%s]", M_XIY)));
};
static void set_3_a(void) { D("  %s;", M_SET_S("3","RA")); };
static void set_3_b(void) { D("  %s;", M_SET_S("3","RB")); };
static void set_3_c(void) { D("  %s;", M_SET_S("3","RC")); };
static void set_3_d(void) { D("  %s;", M_SET_S("3","RD")); };
static void set_3_e(void) { D("  %s;", M_SET_S("3","RE")); };
static void set_3_h(void) { D("  %s;", M_SET_S("3","RH")); };
static void set_3_l(void) { D("  %s;", M_SET_S("3","RL")); };

static void set_4_xhl(void)
{
D("  %s;", M_SET_S("4","mem[HL]"));
};
static void set_4_xix(void)
{
D("  %s;", M_SET_S("4",S("mem[%s]", M_XIX)));
};
static void set_4_xiy(void)
{
D("  %s;", M_SET_S("4",S("mem[%s]", M_XIY)));
};
static void set_4_a(void) { D("  %s;", M_SET_S("4","RA")); };
static void set_4_b(void) { D("  %s;", M_SET_S("4","RB")); };
static void set_4_c(void) { D("  %s;", M_SET_S("4","RC")); };
static void set_4_d(void) { D("  %s;", M_SET_S("4","RD")); };
static void set_4_e(void) { D("  %s;", M_SET_S("4","RE")); };
static void set_4_h(void) { D("  %s;", M_SET_S("4","RH")); };
static void set_4_l(void) { D("  %s;", M_SET_S("4","RL")); };

static void set_5_xhl(void)
{
D("  %s;", M_SET_S("5","mem[HL]"));
};
static void set_5_xix(void)
{
D("  %s;", M_SET_S("5",S("mem[%s]", M_XIX)));
};
static void set_5_xiy(void)
{
D("  %s;", M_SET_S("5",S("mem[%s]", M_XIY)));
};
static void set_5_a(void) { D("  %s;", M_SET_S("5","RA")); };
static void set_5_b(void) { D("  %s;", M_SET_S("5","RB")); };
static void set_5_c(void) { D("  %s;", M_SET_S("5","RC")); };
static void set_5_d(void) { D("  %s;", M_SET_S("5","RD")); };
static void set_5_e(void) { D("  %s;", M_SET_S("5","RE")); };
static void set_5_h(void) { D("  %s;", M_SET_S("5","RH")); };
static void set_5_l(void) { D("  %s;", M_SET_S("5","RL")); };

static void set_6_xhl(void)
{
D("  %s;", M_SET_S("6","mem[HL]"));
};
static void set_6_xix(void)
{
D("  %s;", M_SET_S("6",S("mem[%s]", M_XIX)));
};
static void set_6_xiy(void)
{
D("  %s;", M_SET_S("6",S("mem[%s]", M_XIY)));
};
static void set_6_a(void) { D("  %s;", M_SET_S("6","RA")); };
static void set_6_b(void) { D("  %s;", M_SET_S("6","RB")); };
static void set_6_c(void) { D("  %s;", M_SET_S("6","RC")); };
static void set_6_d(void) { D("  %s;", M_SET_S("6","RD")); };
static void set_6_e(void) { D("  %s;", M_SET_S("6","RE")); };
static void set_6_h(void) { D("  %s;", M_SET_S("6","RH")); };
static void set_6_l(void) { D("  %s;", M_SET_S("6","RL")); };

static void set_7_xhl(void)
{
D("  %s;", M_SET_S("7","mem[HL]"));
};
static void set_7_xix(void)
{
D("  %s;", M_SET_S("7",S("mem[%s]", M_XIX)));
};
static void set_7_xiy(void)
{
D("  %s;", M_SET_S("7",S("mem[%s]", M_XIY)));
};
static void set_7_a(void) { D("  %s;", M_SET_S("7","RA")); };
static void set_7_b(void) { D("  %s;", M_SET_S("7","RB")); };
static void set_7_c(void) { D("  %s;", M_SET_S("7","RC")); };
static void set_7_d(void) { D("  %s;", M_SET_S("7","RD")); };
static void set_7_e(void) { D("  %s;", M_SET_S("7","RE")); };
static void set_7_h(void) { D("  %s;", M_SET_S("7","RH")); };
static void set_7_l(void) { D("  %s;", M_SET_S("7","RL")); };

static void sla_xhl(void)
{
D("  i=mem[HL];");
D("  j=i>>7; i<<=1; RF=ZSPTable[i]|j;");
D("  mem[HL]=i;");
}
static void sla_xix(void)
{
D("  j=%s;", M_XIX);
D("  i=mem[j];");
D("  k=i>>7; i<<=1; RF=ZSPTable[i]|k;");
D("  mem[j]=i;");
}
static void sla_xiy(void)
{
D("  j=%s;", M_XIY);
D("  i=mem[j];");
D("  k=i>>7; i<<=1; RF=ZSPTable[i]|k;");
D("  mem[j]=i;");
}
static void sla_a(void) { D("  %s;", M_SLA_S("RA")); }
static void sla_b(void) { D("  %s;", M_SLA_S("RB")); }
static void sla_c(void) { D("  %s;", M_SLA_S("RC")); }
static void sla_d(void) { D("  %s;", M_SLA_S("RD")); }
static void sla_e(void) { D("  %s;", M_SLA_S("RE")); }
static void sla_h(void) { D("  %s;", M_SLA_S("RH")); }
static void sla_l(void) { D("  %s;", M_SLA_S("RL")); }

static void sll_xhl(void)
{
D("  i=mem[HL];");
D("  %s;", M_SLL_S("i")); /////////////////////////////////////////////////////////////////////////
D("  mem[HL]=i;");
}
static void sll_xix(void)
{
D("  j=%s;", M_XIX);
D("  i=mem[j];");
D("  %s;", M_SLL_S("i")); /////////////////////////////////////////////////////////////////////////
D("  mem[j]=i;");
}
static void sll_xiy(void)
{
D("  j=%s;", M_XIY);
D("  i=mem[j];");
D("  %s;", M_SLL_S("i")); /////////////////////////////////////////////////////////////////////////
D("  mem[j]=i;");

}
static void sll_a(void) { D("  %s;", M_SLL_S("RA")); }
static void sll_b(void) { D("  %s;", M_SLL_S("RB")); }
static void sll_c(void) { D("  %s;", M_SLL_S("RC")); }
static void sll_d(void) { D("  %s;", M_SLL_S("RD")); }
static void sll_e(void) { D("  %s;", M_SLL_S("RE")); }
static void sll_h(void) { D("  %s;", M_SLL_S("RH")); }
static void sll_l(void) { D("  %s;", M_SLL_S("RL")); }

static void sra_xhl(void)
{
D("  i=mem[HL];");
D("  %s;", M_SRA_S("i")); /////////////////////////////////////////////////////////////////////////
D("  mem[HL]=i;");
}
static void sra_xix(void)
{
D("  j=%s;", M_XIX);
D("  i=mem[j];");
D("  %s;", M_SRA_S("i")); /////////////////////////////////////////////////////////////////////////
D("  mem[j]=i;");

}
static void sra_xiy(void)
{
D("  j=%s;", M_XIY);
D("  i=mem[j];");
D("  %s;", M_SRA_S("i")); /////////////////////////////////////////////////////////////////////////
D("  mem[j]=i;");
}
static void sra_a(void) { D("  %s;", M_SRA_S("RA")); }
static void sra_b(void) { D("  %s;", M_SRA_S("RB")); }
static void sra_c(void) { D("  %s;", M_SRA_S("RC")); }
static void sra_d(void) { D("  %s;", M_SRA_S("RD")); }
static void sra_e(void) { D("  %s;", M_SRA_S("RE")); }
static void sra_h(void) { D("  %s;", M_SRA_S("RH")); }
static void sra_l(void) { D("  %s;", M_SRA_S("RL")); }

static void srl_xhl(void)
{
D("  i=mem[HL];");
D("  %s;", M_SRL_S("i")); /////////////////////////////////////////////////////////////////////////
D("  mem[HL]=i;");
}
static void srl_xix(void)
{
D("  j=%s;", M_XIX);
D("  i=mem[j];");
D("  %s;", M_SRL_S("i")); /////////////////////////////////////////////////////////////////////////
D("  mem[j]=i;");
}
static void srl_xiy(void)
{
D("  j=%s;", M_XIY);
D("  i=mem[j];");
D("  M_SRL(i);"); /////////////////////////////////////////////////////////////////////////
D("  mem[j]=i;");
}
static void srl_a(void) { D("  %s;", M_SRL_S("RA")); }
static void srl_b(void) { D("  %s;", M_SRL_S("RB")); }
static void srl_c(void) { D("  %s;", M_SRL_S("RC")); }
static void srl_d(void) { D("  %s;", M_SRL_S("RD")); }
static void srl_e(void) { D("  %s;", M_SRL_S("RE")); }
static void srl_h(void) { D("  %s;", M_SRL_S("RH")); }
static void srl_l(void) { D("  %s;", M_SRL_S("RL")); }

static void sub_xhl(void) { D("  %s;", M_SUB_S("mem[HL]")); }
static void sub_xix(void) { D("  %s;", M_SUB_S(M_RD_XIX)); }
static void sub_xiy(void) { D("  %s;", M_SUB_S(M_RD_XIY)); }
static void sub_a(void) { D("  RA=0;RF=Z_FLAG|N_FLAG;"); }
static void sub_b(void) { D("  %s;", M_SUB_S("RB")); }
static void sub_c(void) { D("  %s;", M_SUB_S("RC")); }
static void sub_d(void) { D("  %s;", M_SUB_S("RD")); }
static void sub_e(void) { D("  %s;", M_SUB_S("RE")); }
static void sub_h(void) { D("  %s;", M_SUB_S("RH")); }
static void sub_l(void) { D("  %s;", M_SUB_S("RL")); }
static void sub_ixh(void) { D("  %s;", M_SUB_S("RI")); }
static void sub_ixl(void) { D("  %s;", M_SUB_S("RX")); }
static void sub_iyh(void) { D("  %s;", M_SUB_S("RJ")); }
static void sub_iyl(void) { D("  %s;", M_SUB_S("RY")); }
static void sub_byte(void) { D("  %s;", M_SUB_S(S("0x%02x", M_RDMEM_OPCODE()))); }

static void xor_xhl(void) { D("  %s;", M_XOR_S("mem[HL]")); }
static void xor_xix(void) { D("  %s;", M_XOR_S(M_RD_XIX)); }
static void xor_xiy(void) { D("  %s;", M_XOR_S(M_RD_XIY)); }
static void xor_a(void) { D("  RA=0;RF=Z_FLAG|V_FLAG;"); }
static void xor_b(void) { D("  %s;", M_XOR_S("RB")); }
static void xor_c(void) { D("  %s;", M_XOR_S("RC")); }
static void xor_d(void) { D("  %s;", M_XOR_S("RD")); }
static void xor_e(void) { D("  %s;", M_XOR_S("RE")); }
static void xor_h(void) { D("  %s;", M_XOR_S("RH")); }
static void xor_l(void) { D("  %s;", M_XOR_S("RL")); }
static void xor_ixh(void) { D("  %s;", M_XOR_S("RI")); }
static void xor_ixl(void) { D("  %s;", M_XOR_S("RX")); }
static void xor_iyh(void) { D("  %s;", M_XOR_S("RJ")); }
static void xor_iyl(void) { D("  %s;", M_XOR_S("RY")); }
static void xor_byte(void) { D("  %s;", M_XOR_S(S("0x%02x", M_RDMEM_OPCODE()))); }

static void no_op(void)
{
D("  --PC;");
}

static void patch(void) { Z80_Patch(&R); }

static unsigned cycles_main[256]=
{
  4,10,7,6,4,4,7,4,
  4,11,7,6,4,4,7,4,
  8,10,7,6,4,4,7,4,
  7,11,7,6,4,4,7,4,
  7,10,16,6,4,4,7,4,
  7,11,16,6,4,4,7,4,
  7,10,13,6,11,11,10,4,
  7,11,13,6,4,4,7,4,
  4,4,4,4,4,4,7,4,
  4,4,4,4,4,4,7,4,
  4,4,4,4,4,4,7,4,
  4,4,4,4,4,4,7,4,
  4,4,4,4,4,4,7,4,
  4,4,4,4,4,4,7,4,
  7,7,7,7,7,7,4,7,
  4,4,4,4,4,4,7,4,
  4,4,4,4,4,4,7,4,
  4,4,4,4,4,4,7,4,
  4,4,4,4,4,4,7,4,
  4,4,4,4,4,4,7,4,
  4,4,4,4,4,4,7,4,
  4,4,4,4,4,4,7,4,
  4,4,4,4,4,4,7,4,
  4,4,4,4,4,4,7,4,
  5,10,10,10,10,11,7,11,
  5,4,10,0,10,10,7,11,
  5,10,10,11,10,11,7,11,
  5,4,10,11,10,0,7,11,
  5,10,10,19,10,11,7,11,
  5,4,10,4,10,0,7,11,
  5,10,10,4,10,11,7,11,
  5,6,10,4,10,0,7,11
};

static unsigned cycles_cb[256]=
{
  8,8,8,8,8,8,15,8,
  8,8,8,8,8,8,15,8,
  8,8,8,8,8,8,15,8,
  8,8,8,8,8,8,15,8,
  8,8,8,8,8,8,15,8,
  8,8,8,8,8,8,15,8,
  8,8,8,8,8,8,15,8,
  8,8,8,8,8,8,15,8,
  8,8,8,8,8,8,12,8,
  8,8,8,8,8,8,12,8,
  8,8,8,8,8,8,12,8,
  8,8,8,8,8,8,12,8,
  8,8,8,8,8,8,12,8,
  8,8,8,8,8,8,12,8,
  8,8,8,8,8,8,12,8,
  8,8,8,8,8,8,12,8,
  8,8,8,8,8,8,15,8,
  8,8,8,8,8,8,15,8,
  8,8,8,8,8,8,15,8,
  8,8,8,8,8,8,15,8,
  8,8,8,8,8,8,15,8,
  8,8,8,8,8,8,15,8,
  8,8,8,8,8,8,15,8,
  8,8,8,8,8,8,15,8,
  8,8,8,8,8,8,15,8,
  8,8,8,8,8,8,15,8,
  8,8,8,8,8,8,15,8,
  8,8,8,8,8,8,15,8,
  8,8,8,8,8,8,15,8,
  8,8,8,8,8,8,15,8,
  8,8,8,8,8,8,15,8,
  8,8,8,8,8,8,15,8
};
static unsigned cycles_xx_cb[]=
{
  0,0,0,0,0,0,23,0,
  0,0,0,0,0,0,23,0,
  0,0,0,0,0,0,23,0,
  0,0,0,0,0,0,23,0,
  0,0,0,0,0,0,23,0,
  0,0,0,0,0,0,23,0,
  0,0,0,0,0,0,23,0,
  0,0,0,0,0,0,23,0,
  20,20,20,20,20,20,20,20,
  20,20,20,20,20,20,20,20,
  20,20,20,20,20,20,20,20,
  20,20,20,20,20,20,20,20,
  20,20,20,20,20,20,20,20,
  20,20,20,20,20,20,20,20,
  20,20,20,20,20,20,20,20,
  20,20,20,20,20,20,20,20,
  0,0,0,0,0,0,23,0,
  0,0,0,0,0,0,23,0,
  0,0,0,0,0,0,23,0,
  0,0,0,0,0,0,23,0,
  0,0,0,0,0,0,23,0,
  0,0,0,0,0,0,23,0,
  0,0,0,0,0,0,23,0,
  0,0,0,0,0,0,23,0,
  0,0,0,0,0,0,23,0,
  0,0,0,0,0,0,23,0,
  0,0,0,0,0,0,23,0,
  0,0,0,0,0,0,23,0,
  0,0,0,0,0,0,23,0,
  0,0,0,0,0,0,23,0,
  0,0,0,0,0,0,23,0,
  0,0,0,0,0,0,23,0
};
static unsigned cycles_xx[256]=
{
  0,0,0,0,0,0,0,0,
  0,15,0,0,0,0,0,0,
  0,0,0,0,0,0,0,0,
  0,15,0,0,0,0,0,0,
  0,14,20,10,9,9,9,0,
  0,15,20,10,9,9,9,0,
  0,0,0,0,23,23,19,0,
  0,15,0,0,0,0,0,0,
  0,0,0,0,9,9,19,0,
  0,0,0,0,9,9,19,0,
  0,0,0,0,9,9,19,0,
  0,0,0,0,9,9,19,0,
  9,9,9,9,9,9,9,9,
  9,9,9,9,9,9,9,9,
  19,19,19,19,19,19,19,19,
  0,0,0,0,9,9,19,0,
  0,0,0,0,9,9,19,0,
  0,0,0,0,9,9,19,0,
  0,0,0,0,9,9,19,0,
  0,0,0,0,9,9,19,0,
  0,0,0,0,9,9,19,0,
  0,0,0,0,9,9,19,0,
  0,0,0,0,9,9,19,0,
  0,0,0,0,9,9,19,0,
  0,0,0,0,0,0,0,0,
  0,0,0,0,0,0,0,0,
  0,0,0,0,0,0,0,0,
  0,0,0,0,0,0,0,0,
  0,14,0,23,0,15,0,0,
  0,8,0,0,0,0,0,0,
  0,0,0,0,0,0,0,0,
  0,10,0,0,0,0,0,0
};
static unsigned cycles_ed[256]=
{
  0,0,0,0,0,0,0,0,
  0,0,0,0,0,0,0,0,
  0,0,0,0,0,0,0,0,
  0,0,0,0,0,0,0,0,
  0,0,0,0,0,0,0,0,
  0,0,0,0,0,0,0,0,
  0,0,0,0,0,0,0,0,
  0,0,0,0,0,0,0,0,
  12,12,15,20,8,8,8,9,
  12,12,15,20,8,8,8,9,
  12,12,15,20,8,8,8,9,
  12,12,15,20,8,8,8,9,
  12,12,15,20,8,8,8,18,
  12,12,15,20,8,8,8,18,
  12,12,15,20,8,8,8,0,
  12,12,15,20,8,8,8,0,
  0,0,0,0,0,0,0,0,
  0,0,0,0,0,0,0,0,
  0,0,0,0,0,0,0,0,
  0,0,0,0,0,0,0,0,
  16,16,16,16,0,0,0,0,
  16,16,16,16,0,0,0,0,
  0,0,0,0,0,0,0,0,
  0,0,0,0,0,0,0,0,
  0,0,0,0,0,0,0,0,
  0,0,0,0,0,0,0,0,
  0,0,0,0,0,0,0,0,
  0,0,0,0,0,0,0,0,
  0,0,0,0,0,0,0,0,
  0,0,0,0,0,0,0,0,
  0,0,0,0,0,0,0,0,
  0,0,0,0,0,0,0,0
};

static void no_op_xx(void) { D("  ++PC;"); }

static opcode_fn opcode_dd_cb[256]=
{
 no_op_xx ,no_op_xx ,no_op_xx ,no_op_xx ,no_op_xx ,no_op_xx ,rlc_xix  ,no_op_xx ,
 no_op_xx ,no_op_xx ,no_op_xx ,no_op_xx ,no_op_xx ,no_op_xx ,rrc_xix  ,no_op_xx ,
 no_op_xx ,no_op_xx ,no_op_xx ,no_op_xx ,no_op_xx ,no_op_xx ,rl_xix   ,no_op_xx ,
 no_op_xx ,no_op_xx ,no_op_xx ,no_op_xx ,no_op_xx ,no_op_xx ,rr_xix   ,no_op_xx ,
 no_op_xx ,no_op_xx ,no_op_xx ,no_op_xx ,no_op_xx ,no_op_xx ,sla_xix  ,no_op_xx ,
 no_op_xx ,no_op_xx ,no_op_xx ,no_op_xx ,no_op_xx ,no_op_xx ,sra_xix  ,no_op_xx ,
 no_op_xx ,no_op_xx ,no_op_xx ,no_op_xx ,no_op_xx ,no_op_xx ,sll_xix  ,no_op_xx ,
 no_op_xx ,no_op_xx ,no_op_xx ,no_op_xx ,no_op_xx ,no_op_xx ,srl_xix  ,no_op_xx ,
 bit_0_xix,bit_0_xix,bit_0_xix,bit_0_xix,bit_0_xix,bit_0_xix,bit_0_xix,bit_0_xix,
 bit_1_xix,bit_1_xix,bit_1_xix,bit_1_xix,bit_1_xix,bit_1_xix,bit_1_xix,bit_1_xix,
 bit_2_xix,bit_2_xix,bit_2_xix,bit_2_xix,bit_2_xix,bit_2_xix,bit_2_xix,bit_2_xix,
 bit_3_xix,bit_3_xix,bit_3_xix,bit_3_xix,bit_3_xix,bit_3_xix,bit_3_xix,bit_3_xix,
 bit_4_xix,bit_4_xix,bit_4_xix,bit_4_xix,bit_4_xix,bit_4_xix,bit_4_xix,bit_4_xix,
 bit_5_xix,bit_5_xix,bit_5_xix,bit_5_xix,bit_5_xix,bit_5_xix,bit_5_xix,bit_5_xix,
 bit_6_xix,bit_6_xix,bit_6_xix,bit_6_xix,bit_6_xix,bit_6_xix,bit_6_xix,bit_6_xix,
 bit_7_xix,bit_7_xix,bit_7_xix,bit_7_xix,bit_7_xix,bit_7_xix,bit_7_xix,bit_7_xix,
 no_op_xx ,no_op_xx ,no_op_xx ,no_op_xx ,no_op_xx ,no_op_xx ,res_0_xix,no_op_xx ,
 no_op_xx ,no_op_xx ,no_op_xx ,no_op_xx ,no_op_xx ,no_op_xx ,res_1_xix,no_op_xx ,
 no_op_xx ,no_op_xx ,no_op_xx ,no_op_xx ,no_op_xx ,no_op_xx ,res_2_xix,no_op_xx ,
 no_op_xx ,no_op_xx ,no_op_xx ,no_op_xx ,no_op_xx ,no_op_xx ,res_3_xix,no_op_xx ,
 no_op_xx ,no_op_xx ,no_op_xx ,no_op_xx ,no_op_xx ,no_op_xx ,res_4_xix,no_op_xx ,
 no_op_xx ,no_op_xx ,no_op_xx ,no_op_xx ,no_op_xx ,no_op_xx ,res_5_xix,no_op_xx ,
 no_op_xx ,no_op_xx ,no_op_xx ,no_op_xx ,no_op_xx ,no_op_xx ,res_6_xix,no_op_xx ,
 no_op_xx ,no_op_xx ,no_op_xx ,no_op_xx ,no_op_xx ,no_op_xx ,res_7_xix,no_op_xx ,
 no_op_xx ,no_op_xx ,no_op_xx ,no_op_xx ,no_op_xx ,no_op_xx ,set_0_xix,no_op_xx ,
 no_op_xx ,no_op_xx ,no_op_xx ,no_op_xx ,no_op_xx ,no_op_xx ,set_1_xix,no_op_xx ,
 no_op_xx ,no_op_xx ,no_op_xx ,no_op_xx ,no_op_xx ,no_op_xx ,set_2_xix,no_op_xx ,
 no_op_xx ,no_op_xx ,no_op_xx ,no_op_xx ,no_op_xx ,no_op_xx ,set_3_xix,no_op_xx ,
 no_op_xx ,no_op_xx ,no_op_xx ,no_op_xx ,no_op_xx ,no_op_xx ,set_4_xix,no_op_xx ,
 no_op_xx ,no_op_xx ,no_op_xx ,no_op_xx ,no_op_xx ,no_op_xx ,set_5_xix,no_op_xx ,
 no_op_xx ,no_op_xx ,no_op_xx ,no_op_xx ,no_op_xx ,no_op_xx ,set_6_xix,no_op_xx ,
 no_op_xx ,no_op_xx ,no_op_xx ,no_op_xx ,no_op_xx ,no_op_xx ,set_7_xix,no_op_xx
};

static opcode_fn opcode_fd_cb[256]=
{
 no_op_xx ,no_op_xx ,no_op_xx ,no_op_xx ,no_op_xx ,no_op_xx ,rlc_xiy  ,no_op_xx ,
 no_op_xx ,no_op_xx ,no_op_xx ,no_op_xx ,no_op_xx ,no_op_xx ,rrc_xiy  ,no_op_xx ,
 no_op_xx ,no_op_xx ,no_op_xx ,no_op_xx ,no_op_xx ,no_op_xx ,rl_xiy   ,no_op_xx ,
 no_op_xx ,no_op_xx ,no_op_xx ,no_op_xx ,no_op_xx ,no_op_xx ,rr_xiy   ,no_op_xx ,
 no_op_xx ,no_op_xx ,no_op_xx ,no_op_xx ,no_op_xx ,no_op_xx ,sla_xiy  ,no_op_xx ,
 no_op_xx ,no_op_xx ,no_op_xx ,no_op_xx ,no_op_xx ,no_op_xx ,sra_xiy  ,no_op_xx ,
 no_op_xx ,no_op_xx ,no_op_xx ,no_op_xx ,no_op_xx ,no_op_xx ,sll_xiy  ,no_op_xx ,
 no_op_xx ,no_op_xx ,no_op_xx ,no_op_xx ,no_op_xx ,no_op_xx ,srl_xiy  ,no_op_xx ,
 bit_0_xiy,bit_0_xiy,bit_0_xiy,bit_0_xiy,bit_0_xiy,bit_0_xiy,bit_0_xiy,bit_0_xiy,
 bit_1_xiy,bit_1_xiy,bit_1_xiy,bit_1_xiy,bit_1_xiy,bit_1_xiy,bit_1_xiy,bit_1_xiy,
 bit_2_xiy,bit_2_xiy,bit_2_xiy,bit_2_xiy,bit_2_xiy,bit_2_xiy,bit_2_xiy,bit_2_xiy,
 bit_3_xiy,bit_3_xiy,bit_3_xiy,bit_3_xiy,bit_3_xiy,bit_3_xiy,bit_3_xiy,bit_3_xiy,
 bit_4_xiy,bit_4_xiy,bit_4_xiy,bit_4_xiy,bit_4_xiy,bit_4_xiy,bit_4_xiy,bit_4_xiy,
 bit_5_xiy,bit_5_xiy,bit_5_xiy,bit_5_xiy,bit_5_xiy,bit_5_xiy,bit_5_xiy,bit_5_xiy,
 bit_6_xiy,bit_6_xiy,bit_6_xiy,bit_6_xiy,bit_6_xiy,bit_6_xiy,bit_6_xiy,bit_6_xiy,
 bit_7_xiy,bit_7_xiy,bit_7_xiy,bit_7_xiy,bit_7_xiy,bit_7_xiy,bit_7_xiy,bit_7_xiy,
 no_op_xx ,no_op_xx ,no_op_xx ,no_op_xx ,no_op_xx ,no_op_xx ,res_0_xiy,no_op_xx ,
 no_op_xx ,no_op_xx ,no_op_xx ,no_op_xx ,no_op_xx ,no_op_xx ,res_1_xiy,no_op_xx ,
 no_op_xx ,no_op_xx ,no_op_xx ,no_op_xx ,no_op_xx ,no_op_xx ,res_2_xiy,no_op_xx ,
 no_op_xx ,no_op_xx ,no_op_xx ,no_op_xx ,no_op_xx ,no_op_xx ,res_3_xiy,no_op_xx ,
 no_op_xx ,no_op_xx ,no_op_xx ,no_op_xx ,no_op_xx ,no_op_xx ,res_4_xiy,no_op_xx ,
 no_op_xx ,no_op_xx ,no_op_xx ,no_op_xx ,no_op_xx ,no_op_xx ,res_5_xiy,no_op_xx ,
 no_op_xx ,no_op_xx ,no_op_xx ,no_op_xx ,no_op_xx ,no_op_xx ,res_6_xiy,no_op_xx ,
 no_op_xx ,no_op_xx ,no_op_xx ,no_op_xx ,no_op_xx ,no_op_xx ,res_7_xiy,no_op_xx ,
 no_op_xx ,no_op_xx ,no_op_xx ,no_op_xx ,no_op_xx ,no_op_xx ,set_0_xiy,no_op_xx ,
 no_op_xx ,no_op_xx ,no_op_xx ,no_op_xx ,no_op_xx ,no_op_xx ,set_1_xiy,no_op_xx ,
 no_op_xx ,no_op_xx ,no_op_xx ,no_op_xx ,no_op_xx ,no_op_xx ,set_2_xiy,no_op_xx ,
 no_op_xx ,no_op_xx ,no_op_xx ,no_op_xx ,no_op_xx ,no_op_xx ,set_3_xiy,no_op_xx ,
 no_op_xx ,no_op_xx ,no_op_xx ,no_op_xx ,no_op_xx ,no_op_xx ,set_4_xiy,no_op_xx ,
 no_op_xx ,no_op_xx ,no_op_xx ,no_op_xx ,no_op_xx ,no_op_xx ,set_5_xiy,no_op_xx ,
 no_op_xx ,no_op_xx ,no_op_xx ,no_op_xx ,no_op_xx ,no_op_xx ,set_6_xiy,no_op_xx ,
 no_op_xx ,no_op_xx ,no_op_xx ,no_op_xx ,no_op_xx ,no_op_xx ,set_7_xiy,no_op_xx
};

static void dd_cb(void)
{
 unsigned opcode;
 opcode=M_RDOP_ARG((PC+1)&0xFFFF);
 if (counting_cycles) D("  Z80_ICount-=cycles_xx_cb[opcode];");
 (*(opcode_dd_cb[opcode]))();
 ++PC;
};
static void fd_cb(void)
{
 unsigned opcode;
 opcode=M_RDOP_ARG((PC+1)&0xFFFF);
 if (counting_cycles) D("  Z80_ICount-=cycles_xx_cb[opcode];");
 (*(opcode_fd_cb[opcode]))();
 ++PC;
};

static opcode_fn opcode_cb[256]=
{
 rlc_b  ,rlc_c  ,rlc_d  ,rlc_e  ,rlc_h  ,rlc_l  ,rlc_xhl  ,rlc_a  ,
 rrc_b  ,rrc_c  ,rrc_d  ,rrc_e  ,rrc_h  ,rrc_l  ,rrc_xhl  ,rrc_a  ,
 rl_b   ,rl_c   ,rl_d   ,rl_e   ,rl_h   ,rl_l   ,rl_xhl   ,rl_a   ,
 rr_b   ,rr_c   ,rr_d   ,rr_e   ,rr_h   ,rr_l   ,rr_xhl   ,rr_a   ,
 sla_b  ,sla_c  ,sla_d  ,sla_e  ,sla_h  ,sla_l  ,sla_xhl  ,sla_a  ,
 sra_b  ,sra_c  ,sra_d  ,sra_e  ,sra_h  ,sra_l  ,sra_xhl  ,sra_a  ,
 sll_b  ,sll_c  ,sll_d  ,sll_e  ,sll_h  ,sll_l  ,sll_xhl  ,sll_a  ,
 srl_b  ,srl_c  ,srl_d  ,srl_e  ,srl_h  ,srl_l  ,srl_xhl  ,srl_a  ,
 bit_0_b,bit_0_c,bit_0_d,bit_0_e,bit_0_h,bit_0_l,bit_0_xhl,bit_0_a,
 bit_1_b,bit_1_c,bit_1_d,bit_1_e,bit_1_h,bit_1_l,bit_1_xhl,bit_1_a,
 bit_2_b,bit_2_c,bit_2_d,bit_2_e,bit_2_h,bit_2_l,bit_2_xhl,bit_2_a,
 bit_3_b,bit_3_c,bit_3_d,bit_3_e,bit_3_h,bit_3_l,bit_3_xhl,bit_3_a,
 bit_4_b,bit_4_c,bit_4_d,bit_4_e,bit_4_h,bit_4_l,bit_4_xhl,bit_4_a,
 bit_5_b,bit_5_c,bit_5_d,bit_5_e,bit_5_h,bit_5_l,bit_5_xhl,bit_5_a,
 bit_6_b,bit_6_c,bit_6_d,bit_6_e,bit_6_h,bit_6_l,bit_6_xhl,bit_6_a,
 bit_7_b,bit_7_c,bit_7_d,bit_7_e,bit_7_h,bit_7_l,bit_7_xhl,bit_7_a,
 res_0_b,res_0_c,res_0_d,res_0_e,res_0_h,res_0_l,res_0_xhl,res_0_a,
 res_1_b,res_1_c,res_1_d,res_1_e,res_1_h,res_1_l,res_1_xhl,res_1_a,
 res_2_b,res_2_c,res_2_d,res_2_e,res_2_h,res_2_l,res_2_xhl,res_2_a,
 res_3_b,res_3_c,res_3_d,res_3_e,res_3_h,res_3_l,res_3_xhl,res_3_a,
 res_4_b,res_4_c,res_4_d,res_4_e,res_4_h,res_4_l,res_4_xhl,res_4_a,
 res_5_b,res_5_c,res_5_d,res_5_e,res_5_h,res_5_l,res_5_xhl,res_5_a,
 res_6_b,res_6_c,res_6_d,res_6_e,res_6_h,res_6_l,res_6_xhl,res_6_a,
 res_7_b,res_7_c,res_7_d,res_7_e,res_7_h,res_7_l,res_7_xhl,res_7_a,
 set_0_b,set_0_c,set_0_d,set_0_e,set_0_h,set_0_l,set_0_xhl,set_0_a,
 set_1_b,set_1_c,set_1_d,set_1_e,set_1_h,set_1_l,set_1_xhl,set_1_a,
 set_2_b,set_2_c,set_2_d,set_2_e,set_2_h,set_2_l,set_2_xhl,set_2_a,
 set_3_b,set_3_c,set_3_d,set_3_e,set_3_h,set_3_l,set_3_xhl,set_3_a,
 set_4_b,set_4_c,set_4_d,set_4_e,set_4_h,set_4_l,set_4_xhl,set_4_a,
 set_5_b,set_5_c,set_5_d,set_5_e,set_5_h,set_5_l,set_5_xhl,set_5_a,
 set_6_b,set_6_c,set_6_d,set_6_e,set_6_h,set_6_l,set_6_xhl,set_6_a,
 set_7_b,set_7_c,set_7_d,set_7_e,set_7_h,set_7_l,set_7_xhl,set_7_a
};

static opcode_fn opcode_dd[256]=
{
  no_op   ,no_op     ,no_op      ,no_op    ,no_op      ,no_op      ,no_op      ,no_op   ,
  no_op   ,add_ix_bc ,no_op      ,no_op    ,no_op      ,no_op      ,no_op      ,no_op   ,
  no_op   ,no_op     ,no_op      ,no_op    ,no_op      ,no_op      ,no_op      ,no_op   ,
  no_op   ,add_ix_de ,no_op      ,no_op    ,no_op      ,no_op      ,no_op      ,no_op   ,
  no_op   ,ld_ix_word,ld_xword_ix,inc_ix   ,inc_ixh    ,dec_ixh    ,ld_ixh_byte,no_op   ,
  no_op   ,add_ix_ix ,ld_ix_xword,dec_ix   ,inc_ixl    ,dec_ixl    ,ld_ixl_byte,no_op   ,
  no_op   ,no_op     ,no_op      ,no_op    ,inc_xix    ,dec_xix    ,ld_xix_byte,no_op   ,
  no_op   ,add_ix_sp ,no_op      ,no_op    ,no_op      ,no_op      ,no_op      ,no_op   ,
  no_op   ,no_op     ,no_op      ,no_op    ,ld_b_ixh   ,ld_b_ixl   ,ld_b_xix   ,no_op   ,
  no_op   ,no_op     ,no_op      ,no_op    ,ld_c_ixh   ,ld_c_ixl   ,ld_c_xix   ,no_op   ,
  no_op   ,no_op     ,no_op      ,no_op    ,ld_d_ixh   ,ld_d_ixl   ,ld_d_xix   ,no_op   ,
  no_op   ,no_op     ,no_op      ,no_op    ,ld_e_ixh   ,ld_e_ixl   ,ld_e_xix   ,no_op   ,
  ld_ixh_b,ld_ixh_c  ,ld_ixh_d   ,ld_ixh_e ,ld_ixh_ixh ,ld_ixh_ixl ,ld_h_xix   ,ld_ixh_a,
  ld_ixl_b,ld_ixl_c  ,ld_ixl_d   ,ld_ixl_e ,ld_ixl_ixh ,ld_ixl_ixl ,ld_l_xix   ,ld_ixl_a,
  ld_xix_b,ld_xix_c  ,ld_xix_d   ,ld_xix_e ,ld_xix_h   ,ld_xix_l   ,no_op      ,ld_xix_a,
  no_op   ,no_op     ,no_op      ,no_op    ,ld_a_ixh   ,ld_a_ixl   ,ld_a_xix   ,no_op   ,
  no_op   ,no_op     ,no_op      ,no_op    ,add_a_ixh  ,add_a_ixl  ,add_a_xix  ,no_op   ,
  no_op   ,no_op     ,no_op      ,no_op    ,adc_a_ixh  ,adc_a_ixl  ,adc_a_xix  ,no_op   ,
  no_op   ,no_op     ,no_op      ,no_op    ,sub_ixh    ,sub_ixl    ,sub_xix    ,no_op   ,
  no_op   ,no_op     ,no_op      ,no_op    ,sbc_a_ixh  ,sbc_a_ixl  ,sbc_a_xix  ,no_op   ,
  no_op   ,no_op     ,no_op      ,no_op    ,and_ixh    ,and_ixl    ,and_xix    ,no_op   ,
  no_op   ,no_op     ,no_op      ,no_op    ,xor_ixh    ,xor_ixl    ,xor_xix    ,no_op   ,
  no_op   ,no_op     ,no_op      ,no_op    ,or_ixh     ,or_ixl     ,or_xix     ,no_op   ,
  no_op   ,no_op     ,no_op      ,no_op    ,cp_ixh     ,cp_ixl     ,cp_xix     ,no_op   ,
  no_op   ,no_op     ,no_op      ,no_op    ,no_op      ,no_op      ,no_op      ,no_op   ,
  no_op   ,no_op     ,no_op      ,dd_cb    ,no_op      ,no_op      ,no_op      ,no_op   ,
  no_op   ,no_op     ,no_op      ,no_op    ,no_op      ,no_op      ,no_op      ,no_op   ,
  no_op   ,no_op     ,no_op      ,no_op    ,no_op      ,no_op      ,no_op      ,no_op   ,
  no_op   ,pop_ix    ,no_op      ,ex_xsp_ix,no_op      ,push_ix    ,no_op      ,no_op   ,
  no_op   ,jp_ix     ,no_op      ,no_op    ,no_op      ,no_op      ,no_op      ,no_op   ,
  no_op   ,no_op     ,no_op      ,no_op    ,no_op      ,no_op      ,no_op      ,no_op   ,
  no_op   ,ld_sp_ix  ,no_op      ,no_op    ,no_op      ,no_op      ,no_op      ,no_op
};

static opcode_fn opcode_ed[256]=
{
 nop   ,nop    ,nop      ,nop        ,nop,nop ,nop  ,nop   ,
 nop   ,nop    ,nop      ,nop        ,nop,nop ,nop  ,nop   ,
 nop   ,nop    ,nop      ,nop        ,nop,nop ,nop  ,nop   ,
 nop   ,nop    ,nop      ,nop        ,nop,nop ,nop  ,nop   ,
 nop   ,nop    ,nop      ,nop        ,nop,nop ,nop  ,nop   ,
 nop   ,nop    ,nop      ,nop        ,nop,nop ,nop  ,nop   ,
 nop   ,nop    ,nop      ,nop        ,nop,nop ,nop  ,nop   ,
 nop   ,nop    ,nop      ,nop        ,nop,nop ,nop  ,nop   ,
 in_b_c,out_c_b,sbc_hl_bc,ld_xword_bc,neg,retn,im_0 ,ld_i_a,
 in_c_c,out_c_c,adc_hl_bc,ld_bc_xword,neg,reti,im_0 ,ld_r_a,
 in_d_c,out_c_d,sbc_hl_de,ld_xword_de,neg,retn,im_1 ,ld_a_i,
 in_e_c,out_c_e,adc_hl_de,ld_de_xword,neg,reti,im_2 ,ld_a_r,
 in_h_c,out_c_h,sbc_hl_hl,ld_xword_hl,neg,retn,im_0 ,rrd   ,
 in_l_c,out_c_l,adc_hl_hl,ld_hl_xword,neg,reti,im_0 ,rld   ,
 in_0_c,out_c_0,sbc_hl_sp,ld_xword_sp,neg,retn,im_1 ,nop   ,
 in_a_c,out_c_a,adc_hl_sp,ld_sp_xword,neg,reti,im_2 ,nop   ,
 nop   ,nop    ,nop      ,nop        ,nop,nop ,nop  ,nop   ,
 nop   ,nop    ,nop      ,nop        ,nop,nop ,nop  ,nop   ,
 nop   ,nop    ,nop      ,nop        ,nop,nop ,nop  ,nop   ,
 nop   ,nop    ,nop      ,nop        ,nop,nop ,nop  ,nop   ,
 ldi   ,cpi    ,ini      ,outi       ,nop,nop ,nop  ,nop   ,
 ldd   ,cpd    ,ind      ,outd       ,nop,nop ,nop  ,nop   ,
 ldir  ,cpir   ,inir     ,otir       ,nop,nop ,nop  ,nop   ,
 lddr  ,cpdr   ,indr     ,otdr       ,nop,nop ,nop  ,nop   ,
 nop   ,nop    ,nop      ,nop        ,nop,nop ,nop  ,nop   ,
 nop   ,nop    ,nop      ,nop        ,nop,nop ,nop  ,nop   ,
 nop   ,nop    ,nop      ,nop        ,nop,nop ,nop  ,nop   ,
 nop   ,nop    ,nop      ,nop        ,nop,nop ,nop  ,nop   ,
 nop   ,nop    ,nop      ,nop        ,nop,nop ,nop  ,nop   ,
 nop   ,nop    ,nop      ,nop        ,nop,nop ,nop  ,nop   ,
 nop   ,nop    ,nop      ,nop        ,nop,nop ,nop  ,nop   ,
 nop   ,nop    ,nop      ,nop        ,nop,nop ,patch,nop
};

static opcode_fn opcode_fd[256]=
{
  no_op   ,no_op     ,no_op      ,no_op    ,no_op      ,no_op      ,no_op      ,no_op   ,
  no_op   ,add_iy_bc ,no_op      ,no_op    ,no_op      ,no_op      ,no_op      ,no_op   ,
  no_op   ,no_op     ,no_op      ,no_op    ,no_op      ,no_op      ,no_op      ,no_op   ,
  no_op   ,add_iy_de ,no_op      ,no_op    ,no_op      ,no_op      ,no_op      ,no_op   ,
  no_op   ,ld_iy_word,ld_xword_iy,inc_iy   ,inc_iyh    ,dec_iyh    ,ld_iyh_byte,no_op   ,
  no_op   ,add_iy_iy ,ld_iy_xword,dec_iy   ,inc_iyl    ,dec_iyl    ,ld_iyl_byte,no_op   ,
  no_op   ,no_op     ,no_op      ,no_op    ,inc_xiy    ,dec_xiy    ,ld_xiy_byte,no_op   ,
  no_op   ,add_iy_sp ,no_op      ,no_op    ,no_op      ,no_op      ,no_op      ,no_op   ,
  no_op   ,no_op     ,no_op      ,no_op    ,ld_b_iyh   ,ld_b_iyl   ,ld_b_xiy   ,no_op   ,
  no_op   ,no_op     ,no_op      ,no_op    ,ld_c_iyh   ,ld_c_iyl   ,ld_c_xiy   ,no_op   ,
  no_op   ,no_op     ,no_op      ,no_op    ,ld_d_iyh   ,ld_d_iyl   ,ld_d_xiy   ,no_op   ,
  no_op   ,no_op     ,no_op      ,no_op    ,ld_e_iyh   ,ld_e_iyl   ,ld_e_xiy   ,no_op   ,
  ld_iyh_b,ld_iyh_c  ,ld_iyh_d   ,ld_iyh_e ,ld_iyh_iyh ,ld_iyh_iyl ,ld_h_xiy   ,ld_iyh_a,
  ld_iyl_b,ld_iyl_c  ,ld_iyl_d   ,ld_iyl_e ,ld_iyl_iyh ,ld_iyl_iyl ,ld_l_xiy   ,ld_iyl_a,
  ld_xiy_b,ld_xiy_c  ,ld_xiy_d   ,ld_xiy_e ,ld_xiy_h   ,ld_xiy_l   ,no_op      ,ld_xiy_a,
  no_op   ,no_op     ,no_op      ,no_op    ,ld_a_iyh   ,ld_a_iyl   ,ld_a_xiy   ,no_op   ,
  no_op   ,no_op     ,no_op      ,no_op    ,add_a_iyh  ,add_a_iyl  ,add_a_xiy  ,no_op   ,
  no_op   ,no_op     ,no_op      ,no_op    ,adc_a_iyh  ,adc_a_iyl  ,adc_a_xiy  ,no_op   ,
  no_op   ,no_op     ,no_op      ,no_op    ,sub_iyh    ,sub_iyl    ,sub_xiy    ,no_op   ,
  no_op   ,no_op     ,no_op      ,no_op    ,sbc_a_iyh  ,sbc_a_iyl  ,sbc_a_xiy  ,no_op   ,
  no_op   ,no_op     ,no_op      ,no_op    ,and_iyh    ,and_iyl    ,and_xiy    ,no_op   ,
  no_op   ,no_op     ,no_op      ,no_op    ,xor_iyh    ,xor_iyl    ,xor_xiy    ,no_op   ,
  no_op   ,no_op     ,no_op      ,no_op    ,or_iyh     ,or_iyl     ,or_xiy     ,no_op   ,
  no_op   ,no_op     ,no_op      ,no_op    ,cp_iyh     ,cp_iyl     ,cp_xiy     ,no_op   ,
  no_op   ,no_op     ,no_op      ,no_op    ,no_op      ,no_op      ,no_op      ,no_op   ,
  no_op   ,no_op     ,no_op      ,fd_cb    ,no_op      ,no_op      ,no_op      ,no_op   ,
  no_op   ,no_op     ,no_op      ,no_op    ,no_op      ,no_op      ,no_op      ,no_op   ,
  no_op   ,no_op     ,no_op      ,no_op    ,no_op      ,no_op      ,no_op      ,no_op   ,
  no_op   ,pop_iy    ,no_op      ,ex_xsp_iy,no_op      ,push_iy    ,no_op      ,no_op   ,
  no_op   ,jp_iy     ,no_op      ,no_op    ,no_op      ,no_op      ,no_op      ,no_op   ,
  no_op   ,no_op     ,no_op      ,no_op    ,no_op      ,no_op      ,no_op      ,no_op   ,
  no_op   ,ld_sp_iy  ,no_op      ,no_op    ,no_op      ,no_op      ,no_op      ,no_op
};

static void cb(void)
{
 unsigned opcode;
 opcode=M_RDOP(PC);
 PC++;
 if (counting_cycles) D("  Z80_ICount-=cycles_cb[opcode];");
 (*(opcode_cb[opcode]))();
}
static void dd(void)
{
 unsigned opcode;
 opcode=M_RDOP(PC);
 PC++;
 if (counting_r) D("  Z80_ICount-=cycles_xx[opcode];");
 (*(opcode_dd[opcode]))();
}
static void ed(void)  // TODO: this opcode decodes further info therefore
{                     // must update virtual PC.  Check for other similar ones
 unsigned opcode;
 opcode=M_RDOP(PC);
 PC++;
 if (counting_cycles) D("  Z80_ICount-=cycles_ed[opcode];");
 (*(opcode_ed[opcode]))();
}
static void fd (void)
{
 unsigned opcode;
 opcode=M_RDOP(PC);
 PC++;
 if (counting_cycles) D("  Z80_ICount-=cycles_xx[opcode];");
 (*(opcode_fd[opcode]))();
}

static opcode_fn opcode_main[256]=
{
 nop     ,ld_bc_word,ld_xbc_a   ,inc_bc    ,inc_b   ,dec_b   ,ld_b_byte  ,rlca    ,
 ex_af_af,add_hl_bc ,ld_a_xbc   ,dec_bc    ,inc_c   ,dec_c   ,ld_c_byte  ,rrca    ,
 djnz    ,ld_de_word,ld_xde_a   ,inc_de    ,inc_d   ,dec_d   ,ld_d_byte  ,rla     ,
 jr      ,add_hl_de ,ld_a_xde   ,dec_de    ,inc_e   ,dec_e   ,ld_e_byte  ,rra     ,
 jr_nz   ,ld_hl_word,ld_xword_hl,inc_hl    ,inc_h   ,dec_h   ,ld_h_byte  ,daa     ,
 jr_z    ,add_hl_hl ,ld_hl_xword,dec_hl    ,inc_l   ,dec_l   ,ld_l_byte  ,cpl     ,
 jr_nc   ,ld_sp_word,ld_xbyte_a ,inc_sp    ,inc_xhl ,dec_xhl ,ld_xhl_byte,scf     ,
 jr_c    ,add_hl_sp ,ld_a_xbyte ,dec_sp    ,inc_a   ,dec_a   ,ld_a_byte  ,ccf     ,
 ld_b_b  ,ld_b_c    ,ld_b_d     ,ld_b_e    ,ld_b_h  ,ld_b_l  ,ld_b_xhl   ,ld_b_a  ,
 ld_c_b  ,ld_c_c    ,ld_c_d     ,ld_c_e    ,ld_c_h  ,ld_c_l  ,ld_c_xhl   ,ld_c_a  ,
 ld_d_b  ,ld_d_c    ,ld_d_d     ,ld_d_e    ,ld_d_h  ,ld_d_l  ,ld_d_xhl   ,ld_d_a  ,
 ld_e_b  ,ld_e_c    ,ld_e_d     ,ld_e_e    ,ld_e_h  ,ld_e_l  ,ld_e_xhl   ,ld_e_a  ,
 ld_h_b  ,ld_h_c    ,ld_h_d     ,ld_h_e    ,ld_h_h  ,ld_h_l  ,ld_h_xhl   ,ld_h_a  ,
 ld_l_b  ,ld_l_c    ,ld_l_d     ,ld_l_e    ,ld_l_h  ,ld_l_l  ,ld_l_xhl   ,ld_l_a  ,
 ld_xhl_b,ld_xhl_c  ,ld_xhl_d   ,ld_xhl_e  ,ld_xhl_h,ld_xhl_l,halt       ,ld_xhl_a,
 ld_a_b  ,ld_a_c    ,ld_a_d     ,ld_a_e    ,ld_a_h  ,ld_a_l  ,ld_a_xhl   ,ld_a_a  ,
 add_a_b ,add_a_c   ,add_a_d    ,add_a_e   ,add_a_h ,add_a_l ,add_a_xhl  ,add_a_a ,
 adc_a_b ,adc_a_c   ,adc_a_d    ,adc_a_e   ,adc_a_h ,adc_a_l ,adc_a_xhl  ,adc_a_a ,
 sub_b   ,sub_c     ,sub_d      ,sub_e     ,sub_h   ,sub_l   ,sub_xhl    ,sub_a   ,
 sbc_a_b ,sbc_a_c   ,sbc_a_d    ,sbc_a_e   ,sbc_a_h ,sbc_a_l ,sbc_a_xhl  ,sbc_a_a ,
 and_b   ,and_c     ,and_d      ,and_e     ,and_h   ,and_l   ,and_xhl    ,and_a   ,
 xor_b   ,xor_c     ,xor_d      ,xor_e     ,xor_h   ,xor_l   ,xor_xhl    ,xor_a   ,
 or_b    ,or_c      ,or_d       ,or_e      ,or_h    ,or_l    ,or_xhl     ,or_a    ,
 cp_b    ,cp_c      ,cp_d       ,cp_e      ,cp_h    ,cp_l    ,cp_xhl     ,cp_a    ,
 ret_nz  ,pop_bc    ,jp_nz      ,jp        ,call_nz ,push_bc ,add_a_byte ,rst_00  ,
 ret_z   ,ret       ,jp_z       ,cb        ,call_z  ,call    ,adc_a_byte ,rst_08  ,
 ret_nc  ,pop_de    ,jp_nc      ,out_byte_a,call_nc ,push_de ,sub_byte   ,rst_10  ,
 ret_c   ,exx       ,jp_c       ,in_a_byte ,call_c  ,dd      ,sbc_a_byte ,rst_18  ,
 ret_po  ,pop_hl    ,jp_po      ,ex_xsp_hl ,call_po ,push_hl ,and_byte   ,rst_20  ,
 ret_pe  ,jp_hl     ,jp_pe      ,ex_de_hl  ,call_pe ,ed      ,xor_byte   ,rst_28  ,
 ret_p   ,pop_af    ,jp_p       ,di        ,call_p  ,push_af ,or_byte    ,rst_30  ,
 ret_m   ,ld_sp_hl  ,jp_m       ,ei        ,call_m  ,fd      ,cp_byte    ,rst_38
};

static void ei(void)
{
 unsigned opcode;
 /* If interrupts were disabled, execute one more instruction and check the */
 /* IRQ line. If not, simply set interrupt flip-flop 2                      */
D("  if (!IFF1)");
D("  { /* After EI, the interrupt is not taken until after the next instruction... */");
D("  IFF1=IFF2=1; /* We look ahead to the next instruction and execute it now      */");
D("               /* - we need to be careful about cycle counts, debugging, etc    */");
D("               /* A halt or jump could cause real confusion, and halt is quite  */");
D("               /* likely as it is a mechanism to wait for interrupt.  FIX THIS! */");
  opcode=M_RDOP(PC);
if (debug) D("  PC++;");
if (debug) D("  Z80_ICount-=cycles_main[opcode];");
  (*(opcode_main[opcode]))();
D("  Interrupt(Z80_IRQ);");
D("  }");
D("  else");
D("  IFF2=1;");
}

/****************************************************************************/
/* Reset registers to their initial values                                  */
/****************************************************************************/
void Z80_Reset (void)
{
 memset (&R,0,sizeof(Z80_Regs));
 SP=0xF000;
 R.R=rand();
 Z80_ICount=Z80_IPeriod;
}

/****************************************************************************/
/* Initialise the various lookup tables used by the emulation code          */
/****************************************************************************/
static void InitTables (void)
{
 static int InitTables_virgin=1;
 byte zs;
 int i,p;
 if (!InitTables_virgin) return;
 InitTables_virgin=0;
 for (i=0;i<256;++i)
 {
  zs=0;
  if (i==0)
   zs|=Z_FLAG;
  if (i&0x80)
   zs|=S_FLAG;
  p=0;
  if (i&1) ++p;
  if (i&2) ++p;
  if (i&4) ++p;
  if (i&8) ++p;
  if (i&16) ++p;
  if (i&32) ++p;
  if (i&64) ++p;
  if (i&128) ++p;
  PTable[i]=(p&1)? 0:V_FLAG;
  ZSTable[i]=zs;
  IncTable[i]=zs|((i==0x80)?V_FLAG:0)|((i&0x0F)?0:H_FLAG);
  DecTable[i]=(zs&C_FLAG)|N_FLAG|((i==0x7f)?V_FLAG:0)|(((i+1)&0x0F)?0:H_FLAG)|ZSTable[i];
  ZSPTable[i]=zs|PTable[i];
  ZSPHTable[i]=zs|PTable[i]|H_FLAG;
 }
 for (i=0;i<256;++i)
 {
  PostIncCarry[i] = 0;
  ZSTable[i+256]=ZSTable[i]|C_FLAG;
  ZSPTable[i+256]=ZSPTable[i]|C_FLAG;
  ZSPHTable[i+256]=ZSPTable[i]|C_FLAG;
  IncTable[i+256]=IncTable[i]|C_FLAG;
  DecTable[i+256]=DecTable[i]|C_FLAG;
  PTable[i+256]=PTable[i]|C_FLAG;
 }
 {int RA, RB, i;
  for (RA = 0; RA < 256; RA++) {
    for (RB = 0; RB < 256; RB++) {
      i = RA+RB;
      AddFlags[RA][RB] = ZSTable[i&255]|((i&256)>>8)|((RA^i^RB)&H_FLAG)|(((RB^RA^0x80)&(RB^i)&0x80)>>5);
    }
  }
 }
 PostIncCarry[0] = 1; // ff -> 00 means next byte gets a carry
}

/****************************************************************************/
/* Issue an interrupt if necessary                                          */
/****************************************************************************/
static void Interrupt (int j)
{
#ifdef NEVER
 if (j==Z80_IGNORE_INT) return;
 if (j==Z80_NMI_INT || IFF1)
 {
  /* Clear interrupt flip-flop 1 */
  IFF1=0;
  /* Check if processor was halted */
  if (R.HALT)
  {
   ++PC;
   R.HALT=0;
  }
  if (j==Z80_NMI_INT)
  {
   M_PUSH (PC);
   PC=0x0066;
  }
  else
  {
   /* Interrupt mode 2. Call [R.I:databyte] */
   if (R.IM==2)
   {
    M_PUSH (PC);
    PC=M_RDMEM_WORD((j&255)|(R.I<<8));
   }
   else
    /* Interrupt mode 1. RST 38h */
    if (R.IM==1)
    {
     Z80_ICount-=cycles_main[0xFF];
     (*(opcode_main[0xFF]))();
    }
    else
    /* Interrupt mode 0. We check for CALL and JP instructions, if neither  */
    /* of these were found we assume a 1 byte opcode was placed on the      */
    /* databus                                                              */
    {
     switch (j&0xFF0000)
     {
      case 0xCD:
       M_PUSH("PC");
      case 0xC3:
       PC=j&0xFFFF;
       break;
      default:
       j&=255;
       Z80_ICount-=cycles_main[j];
       (*(opcode_main[j]))();
       break;
     }
    }
  }
 }
#endif
}

/****************************************************************************/
/* Set all registers to given values                                        */
/****************************************************************************/
void Z80_SetRegs (Z80_Regs *Regs)
{
 R=*Regs;
}

/****************************************************************************/
/* Get all registers in given buffer                                        */
/****************************************************************************/
void Z80_GetRegs (Z80_Regs *Regs)
{
 *Regs=R;
}

/****************************************************************************/
/* Return program counter                                                   */
/****************************************************************************/
unsigned Z80_GetPC (void)
{
 return PC;
}

/****************************************************************************/
/* Execute IPeriod T-States. Return 0 if emulation should be stopped        */
/****************************************************************************/
int Z80_Translate (int pc)
{
  int i;
  unsigned opcode = mem[pc&65535];
  PC = (pc+1)&65535;
  if (counting_cycles) D("  Z80_ICount-=cycles_main[opcode];");
  (*(opcode_main[opcode]))();
}

/****************************************************************************/
/* Interpret Z80 code                                                       */
/****************************************************************************/
word Z80 (void)
{
// while (Z80_Execute());
 return(PC);
}

/****************************************************************************/
/* Dump register contents and (optionally) a PC trace to stdout             */
/****************************************************************************/
void Z80_RegisterDump (void)
{
#ifdef NEVER
 int i;
 printf
 (
   "AF:%04X HL:%04X DE:%04X BC:%04X PC:%04X SP:%04X IX:%04X IY:%04X\n",
   AF,HL,DE,BC,PC,SP,IX,IY
 ); 
 printf ("STACK: ");
 for (i=0;i<10;++i) printf ("%04X ",M_RDMEM_WORD((SP+i*2)&0xFFFF));
 puts ("");
#ifdef TRACE
 puts ("PC TRACE:");
 for (i=1;i<=256;++i) printf ("%04X\n",pc_trace[(pc_count-i)&255]);
#endif
#endif
}

/****************************************************************************/
/* Set number of memory refresh wait states (i.e. extra cycles inserted     */
/* when the refresh register is being incremented)                          */
/****************************************************************************/
void Z80_SetWaitStates (int n)
{
 int i;
 for (i=0;i<256;++i)
 {
  cycles_main[i]+=n;
  cycles_cb[i]+=n;
  cycles_ed[i]+=n;
  cycles_xx[i]+=n;
 }
}
