/*** Z80Em: Portable Z80 emulator *******************************************/
/***                                                                      ***/
/***                              Z80Codes.h                              ***/
/***                                                                      ***/
/*** This file contains various macros used by the emulation engine       ***/
/***                                                                      ***/
/*** 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          ***/
/****************************************************************************/

#ifndef TRUE
#define TRUE (0==0)
#define FALSE (0!=0)
#endif

char *RS, *RS2, *Q; /* Used to avoid multiple macro expansion side-effects */

extern int pass;
int lab[0x10000];
char *tags[0x10000];

int deflab(int pc)
{
  if (pass == 2) return pc;
//  fprintf(stderr, "LABEL AT %04x\n", pc);
  lab[pc] = TRUE;
  return pc;
}

//        R.Rg.D=M_RDSTACK(SP)+(M_RDSTACK((SP+1)&65535)<<8); \
//        SP+=2
char *M_POP_S(char *Rg)
{
  if (strcmp(Rg, "BC") == 0) {
    return S("RC=mem[SP++];RB=mem[SP++];");
  } else if (strcmp(Rg, "DE") == 0) {
    return S("RE=mem[SP++];RD=mem[SP++];");
  } else if (strcmp(Rg, "HL") == 0) {
    return S("RL=mem[SP++];RH=mem[SP++];");
  } else if (strcmp(Rg, "IX") == 0) {
    return S("RX=mem[SP++];RI=mem[SP++];");
  } else if (strcmp(Rg, "IY") == 0) {
    return S("RY=mem[SP++];RJ=mem[SP++];");
  } else if (strcmp(Rg, "AF") == 0) {
    return S("RF=mem[SP++];RA=mem[SP++];");
  } else if (strcmp(Rg, "PC") == 0) {
    return S("PC_lo=mem[SP++];PC_hi=mem[SP++];");
  } else {
    return S("%s=mem[SP++];%s+=(mem[SP++]<<8)", Rg, Rg);
  }
}


char *M_POP2X_S(char *Rg, char *R1, char *R2)
{
  //return S("%s=%s=mem[SP++];%s+=((%s=mem[SP++])<<8)", Rg, R2, Rg, R1);
  return S("%s=mem[SP++];%s=mem[SP++];", R2, R1);
}



char *M_POP2_S(char *R1, char *R2)
{
  //return S("%s=mem[SP++];%s=mem[SP++]<<8 /* check order! */", R2, R1); <<---- if R1 and R2 were byte regs then this was a bug.
  return S("%s=mem[SP++];%s=mem[SP++];", R2, R1); // however it looks like it was only used for AF so we're good with this fix.
}

void M_PUSH_S(char *Rg)
{
  if (strcmp(Rg, "BC") == 0) {
    D("  mem[--SP]=RB; mem[--SP]=RC;");
  } else if (strcmp(Rg, "DE") == 0) {
    D("  mem[--SP]=RD; mem[--SP]=RE;");
  } else if (strcmp(Rg, "HL") == 0) {
    D("  mem[--SP]=RH; mem[--SP]=RL;");
  } else if (strcmp(Rg, "IX") == 0) {
    D("  mem[--SP]=RI; mem[--SP]=RX;");
  } else if (strcmp(Rg, "IY") == 0) {
    D("  mem[--SP]=RJ; mem[--SP]=RY;");
  } else if (strcmp(Rg, "AF") == 0) {
    D("  mem[--SP]=RA; mem[--SP]=RF;");
  } else if (strcmp(Rg, "PC") == 0) {
    D("  mem[--SP]=PC_hi; mem[--SP]=PC_lo;");
  } else {
    D("  mem[--SP]=(%s)>>8; mem[--SP]=(%s)&255;", Rg, Rg); // PC and SP
  }
}

void M_PUSH2_S(char *R1, char *R2)
{
        D("  mem[--SP]=%s; mem[--SP]=%s;", R1, R2);
}

char *M_call_s(void)
{
 int q=M_RDMEM_OPCODE_WORD();
 char *c;
 deflab(PC); deflab(q);
 c = S("mem[--SP]=0x%02x; mem[--SP]=0x%02x; goto L%04x", PC>>8, PC&255, q);
 PC=q;
 return c;
}
#define M_CALL_S M_call_s()

char *M_jp_s(void)
{
  deflab(PC+2);
// bug fix?  PC=M_RDOP_ARG(PC)+((M_RDOP_ARG((PC+1)&65535))<<8);
  PC=(M_RDOP_ARG(PC)&255) | ((M_RDOP_ARG(PC+1)&255)<<8);
  return S("goto L%04x", deflab(PC));
}
#define M_JP_S            M_jp_s()

char *M_jr_s(void)
{
  deflab(PC+1);// +1 is to skip the relative offset byte.  Then points to next inst
  PC+=((signed char)M_RDOP_ARG(PC))+1;
  return S("goto L%04x", deflab(PC));
}
#define M_JR_S            M_jr_s()

#define M_RET_S           "PC_lo=mem[SP++]; PC_hi=mem[SP++]; goto *lab[PC]"

// now in z80.c #define M_RST(Addr)     M_PUSH(PC); PC=Addr
#define M_SET_S(Bit,Reg)  S("%s|=1<<%s", Reg, Bit)
#define M_RES_S(Bit,Reg)  S("%s&=~(1<<%s)", Reg, Bit)

char *M_bit_s(char *Bit, char *Reg) {
  RS = Bit;
  if ((strlen(Bit) == 1) && ('0' <= Bit[0] && Bit[0] <= '7')) {
    if (strcmp(Bit, "7") == 0) {
      return S("RF=(RF&C_FLAG)|H_FLAG| ((%s&(1<<%s)) ? S_FLAG : Z_FLAG)", Reg, Bit, Bit);
    } else {
      return S("RF=(RF&C_FLAG)|H_FLAG| ((%s&(1<<%s)) ? 0 : Z_FLAG)", Reg, Bit, Bit);
    }
  } else {
    return S("RF=(RF&C_FLAG)|H_FLAG| ((%s&(1<<%s)) ? ((%s==7)?S_FLAG:0) : Z_FLAG)", Reg, Bit, Bit);
  }
}
#define M_BIT_S(Bit,Reg) M_bit_s(Bit, Reg)
#define M_AND_S(Reg)    S("RA&=%s; RF=ZSPTable[RA]|H_FLAG /* ZSPHTable? */", Reg)
#define M_OR_S(Reg)     S("RA|=%s; RF=ZSPTable[RA]", Reg)
#define M_XOR_S(Reg)    S("RA^=%s; RF=ZSPTable[RA]", Reg)
#define M_IN_S(Reg)     S("%s=DoIn(RC,RB); RF=(RF&C_FLAG)|ZSPTable[%s]", Reg, Reg)

#define M_RLCA_S  "RA=(RA<<1)|((RA&0x80)>>7);\n  RF=(RF&0xEC)|(RA&C_FLAG)"

#define M_RRCA_S  "RF=(RF&0xEC)|(RA&0x01);\n  RA=(RA>>1)|(RA<<7)"

#define M_RLA_S   "i=RF&C_FLAG; RF=(RF&0xEC)|((RA&0x80)>>7); RA=(RA<<1)|i"

#define M_RRA_S   "i=RF&C_FLAG; RF=(RF&0xEC)|(RA&0x01); RA=(RA>>1)|(i<<7)"

#define M_RLC_S(Reg) (RS=Reg, Q=S("i=%s>>7; %s=(%s<<1)|i; RF=ZSPTable[%s]|i", RS, RS, RS, RS), Q)

#define M_RRC_S(Reg) (RS=Reg, Q=S("i=%s&1; %s=(%s>>1)|(i<<7); RF=ZSPTable[%s]|i", RS, RS, RS, RS), Q)

#define M_RL_S(Reg)  (RS=Reg, Q=S("i=%s>>7; %s=(%s<<1)|(RF&1); RF=ZSPTable[%s]|i;", RS, RS, RS, RS), Q)

#define M_RR_S(Reg)  (RS=Reg, S("i=%s&1; %s=(%s>>1)|(RF<<7); RF=ZSPTable[%s]|i", RS, RS, RS, RS), Q)

#define M_SLL_S(Reg) (RS=Reg, Q=S("i=%s>>7; %s=(%s<<1)|1; RF=ZSPTable[%s]|i", RS, RS, RS, RS), Q)

#define M_SLA_S(Reg) (RS=Reg, Q=S("i=%s>>7; %s<<=1; RF=ZSPTable[%s]|i", RS, RS, RS),Q)

#define M_SRL_S(Reg) (RS=Reg, Q=S("i=%s&1; %s>>=1; RF=ZSPTable[%s]|i", RS, RS, RS), Q)

#define M_SRA_S(Reg) (RS=Reg, Q=S("i=%s&1; %s=(%s>>1)|(%s&0x80); RF=ZSPTable[%s]|i", RS=Reg, RS, RS, RS, RS), Q)

// |ZSTable[RB]|((RB==0x80)?V_FLAG:0)|((RB&0x0F)?0:H_FLAG)
// is now replaced with |IncTable[RB]

#define M_INC_S(Str) S("RF=(RF&C_FLAG)|IncTable[++%s]", Str)

#define M_DEC_S(Str) S("RF=DecTable[--%s]", Str)

#define M_ADD_S(Reg) (RS=Reg, Q=S("RF=AddFlags[RA][%s];\n  RA=RA+%s", RS, RS), Q)

#define M_ADC_S(Reg) (RS=Reg, Q=S("i=RA+%s+(RF&1);\n  RF=ZSTable[i&255]|((i&256)>>8)|((RA^i^%s)&H_FLAG)|(((%s^RA^0x80)&(%s^i)&0x80)>>5);\n  RA=i", RS, RS, RS, RS), Q)
// to do, if safe.  Not sure if table lookup needs carry bit as input: #define M_ADC(Reg) S("i=RA+%s+(RF&1);\n  RF = AddFlags[RA][%s];\n  RA=i", #Reg, #Reg)

#define M_SUB_S(Reg) (RS=Reg, Q=S("i=RA-%s; RF=ZSTable[i&255]|((i&256)>>8)|N_FLAG|((RA^i^%s)&H_FLAG)|(((%s^RA)&(%s^i)&0x80)>>5); RA=i", RS, RS, RS, RS), Q)

#define M_SBC_S(Reg)  (RS=Reg, Q=S("i=RA-%s-(RF&1); RF=ZSTable[i&255]|((i&256)>>8)|N_FLAG|((RA^i^%s)&H_FLAG)|(((%s^RA)&(%s^i)&0x80)>>5); RA=i", RS, RS, RS, RS), Q)

#define M_CP_S(Reg)   (RS=Reg, Q=S("i=RA-%s; RF=ZSTable[i&255]|((i&256)>>8)|N_FLAG|((RA^i^%s)&H_FLAG)|(((%s^RA)&(%s^i)&0x80)>>5)", RS, RS, RS, RS), Q)

// todo: check the logic of this: what is the 0x1000 for?  Should it be 0x10000?
#define M_ADDW_S(Reg1,Reg2) (RS=Reg1, RS2=Reg2, Q=S("i=%s+%s; RF=(RF&(S_FLAG|Z_FLAG|V_FLAG))|(((%s^i^%s)&0x1000)>>8)|((i>>16)&1); %s=i", RS, RS2, RS, RS2, RS), Q)

#define M_ADCW_S(Reg) (RS=Reg, Q=S("i=HL+%s+(AF&1);RF=(((HL^i^%s)&0x1000)>>8)|((i>>16)&1)|((i&0x8000)>>8)|((i&65535)?0:Z_FLAG)|(((%s^HL^0x8000)&(%s^i)&0x8000)>>13); HL=i", RS, RS, RS, RS), Q)

#define M_SBCW_S(Reg) (RS=Reg, Q=S("i=HL-%s-(AF&1);RF=(((HL^i^%s)&0x1000)>>8)|((i>>16)&1)|((i&0x8000)>>8)|((i&65535)?0:Z_FLAG)|(((%s^HL)&(%s^i)&0x8000)>>13)|N_FLAG; HL=i", RS, RS, RS, RS), Q)
