/*
 * Simulator of microcontrollers (inst.cc)
 *
 * some z80 code base from Karl Bongers karl@turbobit.com
 *
 * Copyright (C) 1999,99 Drotos Daniel, Talker Bt.
 *
 * To contact author send email to drdani@mazsola.iit.uni-miskolc.hu
 *
 */

/* This file is part of microcontroller simulator: ucsim.

UCSIM is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.

UCSIM is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with UCSIM; see the file COPYING.  If not, write to the Free
Software Foundation, 59 Temple Place - Suite 330, Boston, MA
02111-1307, USA. */
/*@1@*/

#include "ddconfig.h"

#include <stdlib.h>

// local
#include "z80cl.h"
#include "regsz80.h"
#include "z80mac.h"


/*
 * No Instruction
 * NOP
 * 0000 0000 0000 0000
 *----------------------------------------------------------------------------
 */

int
cl_z80::inst_nop(t_mem code)
{
  return(resGO);
}

/*
 * Load Instruction
 * LD
 *
 *----------------------------------------------------------------------------
 */

int
cl_z80::inst_ld(t_mem code)
{
  switch(code)
    {
    case 1:  // LD BC,nnnn
      regs.BC = fetch2();
      break;
    case 2: // LD (BC),A
      store1(regs.BC, regs.raf.A);
      vc.wr++;
      break;
    case 6: // LD B,nn
      regs.bc.h = fetch();
      break;
    case 0xa: // LD A,(BC)
      regs.raf.A = get1(regs.BC);
      vc.rd++;
      break;
    case 0x0e: // LD C,nn
      regs.bc.l = fetch();
      break;
    case 0x11: // LD DE,nnnn
      regs.DE = fetch2();
      break;
    case 0x12: // LD (DE),A
      store1(regs.DE, regs.raf.A);
      vc.wr++;
      break;
    case 0x16: // LD D,nn
      regs.de.h = fetch();
      break;
    case 0x1A: // LD A,(DE)
      regs.raf.A = get1(regs.DE);
      vc.rd++;
      break;
    case 0x1E: // LD E,nn
      regs.de.l = fetch();
      break;
    case 0x21: // LD HL,nnnn
      regs.HL = fetch2();
      break;
    case 0x22: // LD (nnnn),HL
      {
	unsigned short tw;
	tw = fetch2();
	store2(tw, regs.HL);
	vc.wr+= 2;
	break;
      }
    case 0x26: // LD H,nn
      regs.hl.h = fetch();
      break;
    case 0x2A: // LD HL,(nnnn)
      {
	unsigned short tw;
	tw = fetch2();
	regs.HL = get2(tw);
	vc.rd+= 2;
	break;
      }
    case 0x2E: // LD L,nn
      regs.hl.l = fetch();
      break;
    case 0x31: // LD SP,nnnn
      regs.SP = fetch2();
      break;
    case 0x32: // LD (nnnn),A
      {
	unsigned short tw;
	tw = fetch2();
	store1(tw, regs.raf.A);
	vc.wr++;
	break;
      }
    case 0x36: // LD (HL),nn
      store1(regs.HL, fetch());
      vc.wr++;
      break;
    case 0x3A: // LD A,(nnnn)
      regs.raf.A = get1(fetch2());
      vc.rd++;
      break;
    case 0x3E: // LD A,nn
      regs.raf.A = fetch();
      break;
    case 0x40: // LD B,B
      break;
    case 0x41: // LD B,C
      regs.bc.h = regs.bc.l;
      break;
    case 0x42: // LD B,D
      regs.bc.h = regs.de.h;
      break;
    case 0x43: // LD B,E
      regs.bc.h = regs.de.l;
      break;
    case 0x44: // LD B,H
      regs.bc.h = regs.hl.h;
      break;
    case 0x45: // LD B,L
      regs.bc.h = regs.hl.l;
      break;
    case 0x46: // LD B,(HL)
      regs.bc.h = get1(regs.HL);
      vc.rd++;
      break;
    case 0x47: // LD B,A
      regs.bc.h = regs.raf.A;
      break;
    case 0x48: // LD C,B
      regs.bc.l = regs.bc.h;
      break;
    case 0x49: // LD C,C
      break;
    case 0x4A: // LD C,D
      regs.bc.l = regs.de.h;
      break;
    case 0x4B: // LD C,E
      regs.bc.l = regs.de.l;
      break;
    case 0x4C: // LD C,H
      regs.bc.l = regs.hl.h;
      break;
    case 0x4D: // LD C,L
      regs.bc.l = regs.hl.l;
      break;
    case 0x4E: // LD C,(HL)
      regs.bc.l = get1(regs.HL);
      vc.rd++;
      break;
    case 0x4F: // LD C,A
      regs.bc.l = regs.raf.A;
      break;
    case 0x50: // LD D,B
      regs.de.h = regs.bc.h;
      break;
    case 0x51: // LD D,C
      regs.de.h = regs.bc.l;
      break;
    case 0x52: // LD D,D
      break;
    case 0x53: // LD D,E
      regs.de.h = regs.de.l;
      break;
    case 0x54: // LD D,H
      regs.de.h = regs.hl.h;
      break;
    case 0x55: // LD D,L
      regs.de.h = regs.hl.l;
      break;
    case 0x56: // LD D,(HL)
      regs.de.h = get1(regs.HL);
      vc.rd++;
      break;
    case 0x57: // LD D,A
      regs.de.h = regs.raf.A;
      break;
    case 0x58: // LD E,B
      regs.de.l = regs.bc.h;
      break;
    case 0x59: // LD E,C
      regs.de.l = regs.bc.l;
      break;
    case 0x5A: // LD E,D
      regs.de.l = regs.de.h;
      break;
    case 0x5B: // LD E,E
      break;
    case 0x5C: // LD E,H
      regs.de.l = regs.hl.h;
      break;
    case 0x5D: // LD E,L
      regs.de.l = regs.hl.l;
      break;
    case 0x5E: // LD E,(HL)
      regs.de.l = get1(regs.HL);
      vc.rd++;
      break;
    case 0x5F: // LD E,A
      regs.de.l = regs.raf.A;
      break;
    case 0x60: // LD H,B
      regs.hl.h = regs.bc.h;
      break;
    case 0x61: // LD H,C
      regs.hl.h = regs.bc.l;
      break;
    case 0x62: // LD H,D
      regs.hl.h = regs.de.h;
      break;
    case 0x63: // LD H,E
      regs.hl.h = regs.de.l;
      break;
    case 0x64: // LD H,H
      regs.hl.h = regs.hl.h;
      break;
    case 0x65: // LD H,L
      regs.hl.h = regs.hl.l;
      break;
    case 0x66: // LD H,(HL)
      regs.hl.h = get1(regs.HL);
      vc.rd++;
      break;
    case 0x67: // LD H,A
      regs.hl.h = regs.raf.A;
      break;
    case 0x68: // LD L,B
      regs.hl.l = regs.bc.h;
      break;
    case 0x69: // LD L,C
      regs.hl.l = regs.bc.l;
      break;
    case 0x6A: // LD L,D
      regs.hl.l = regs.de.h;
      break;
    case 0x6B: // LD L,E
      regs.hl.l = regs.de.l;
      break;
    case 0x6C: // LD L,H
      regs.hl.l = regs.hl.h;
      break;
    case 0x6D: // LD L,L
      break;
    case 0x6E: // LD L,(HL)
      regs.hl.l = get1(regs.HL);
      vc.rd++;
      break;
    case 0x6F: // LD L,A
      regs.hl.l = regs.raf.A;
      break;
    case 0x70: // LD (HL),B
      store1(regs.HL, regs.bc.h);
      vc.wr++;
      break;
    case 0x71: // LD (HL),C
      store1(regs.HL, regs.bc.l);
      vc.wr++;
      break;
    case 0x72: // LD (HL),D
      store1(regs.HL, regs.de.h);
      vc.wr++;
      break;
    case 0x73: // LD (HL),E
      store1(regs.HL, regs.de.l);
      vc.wr++;
      break;
    case 0x74: // LD (HL),H
      store1(regs.HL, regs.hl.h);
      vc.wr++;
      break;
    case 0x75: // LD (HL),L
      store1(regs.HL, regs.hl.l);
      vc.wr++;
      break;
    case 0x76: // HALT
      return(resHALT);

    case 0x77: // LD (HL),A
      store1(regs.HL, regs.raf.A);
      vc.wr++;
      break;
    case 0x78: // LD A,B
      regs.raf.A = regs.bc.h;
      break;
    case 0x79: // LD A,C
      regs.raf.A = regs.bc.l;
      break;
    case 0x7A: // LD A,D
      regs.raf.A = regs.de.h;
      break;
    case 0x7B: // LD A,E
      regs.raf.A = regs.de.l;
      break;
    case 0x7C: // LD A,H
      regs.raf.A = regs.hl.h;
      break;
    case 0x7D: // LD A,L
      regs.raf.A = regs.hl.l;
      break;
    case 0x7E: // LD A,(HL)
      regs.raf.A = get1(regs.HL);
      vc.rd++;
      break;
    case 0x7F: // LD A,A
      break;
    case 0xF9: // LD SP,HL
      regs.SP = regs.HL;
      break;
    default:
      return(resINV_INST);
      break;
    }
  return(resGO);
}

int
cl_z80::inst_inc(t_mem code)
{
  switch(code)
    {
    case 0x03: // INC BC
      ++regs.BC;
      break;
    case 0x04: // INC B
      inc(regs.bc.h);
      break;
    case 0x0C: // INC C
      inc(regs.bc.l);
      break;
    case 0x13: // INC DE
      ++regs.DE;
      break;
    case 0x14: // INC D
      inc(regs.de.h);
      break;
    case 0x1C: // INC E
      inc(regs.de.l);
      break;
    case 0x23: // INC HL
      ++regs.HL;
      break;
    case 0x24: // INC H
      inc(regs.hl.h);
      break;
    case 0x2C: // INC L
      inc(regs.hl.l);
      break;
    case 0x33: // INC SP
      ++regs.SP;
      break;
    case 0x34: // INC (HL)
      {
	unsigned char t=get1(regs.HL);
         inc(t);
         store1(regs.HL, t);
	 vc.rd++;
	 vc.wr++;
	 break;
      }
    case 0x3C: // INC A
      inc(regs.raf.A);
      break;
    default:
      return(resINV_INST);
      break;
    }
  return(resGO);
}

int
cl_z80::inst_dec(t_mem code)
{
  switch(code)
    {
    case 0x05: // DEC B
      dec(regs.bc.h);
      break;
    case 0x0B: // DEC BC
      --regs.BC;
      break;
    case 0x0D: // DEC C
      dec(regs.bc.l);
      break;
    case 0x15: // DEC D
      dec(regs.de.h);
      break;
    case 0x1B: // DEC DE
      --regs.DE;
      break;
    case 0x1D: // DEC E
      dec(regs.de.l);
      break;
    case 0x25: // DEC H
      dec(regs.hl.h);
      break;
    case 0x2B: // DEC HL
      --regs.HL;
      break;
    case 0x2D: // DEC L
      dec(regs.hl.l);
      break;
    case 0x35: // DEC (HL)
      {
	unsigned char t=get1(regs.HL);
	dec(t);
	store1(regs.HL, t);
	vc.rd++;
	vc.wr++;
	break;
      }
    case 0x3B: // DEC SP
      --regs.SP;
      break;
    case 0x3D: // DEC A
      dec(regs.raf.A);
      break;
    default:
      return(resINV_INST);
      break;
    }
  return(resGO);
}

int
cl_z80::inst_rlca(t_mem code)
{
  regs.raf.F &= ~(BIT_A | BIT_N | BIT_C);
  if (regs.raf.A & 0x80) {
     regs.raf.F |= BIT_C;
     regs.raf.A = (regs.raf.A << 1) | 0x01;
   } else
     regs.raf.A = (regs.raf.A << 1);

  return(resGO);
}

int
cl_z80::inst_rrca(t_mem code)
{
  regs.raf.F &= ~(BIT_A | BIT_N | BIT_C);
  if (regs.raf.A & 0x01) {
     regs.raf.F |= BIT_C;
     regs.raf.A = (regs.raf.A >> 1) | 0x80;
   }
   else
     regs.raf.A = (regs.raf.A >> 1);
  return(resGO);
}

int
cl_z80::inst_ex(t_mem code)
{
  /* 0x08 // EX AF,AF' */
  unsigned char tmp;
  u16_t tempw;

  switch (code) {
    case 0x08: // EX AF,AF'
      tmp = regs.ralt_af.aA;
      regs.ralt_af.aA = regs.raf.A;
      regs.raf.A = tmp;

      tmp = regs.ralt_af.aF;
      regs.ralt_af.aF = regs.raf.F;
      regs.raf.F = tmp;
    break;

    case 0xE3: // EX (SP),HL
      tempw = regs.HL;
      regs.HL = get2(regs.SP);
      store2(regs.SP, tempw);
      vc.rd+= 2;
      vc.wr+= 2;
    break;

    case 0xEB: // EX DE,HL
      tempw = regs.DE;
      regs.DE = regs.HL;
      regs.HL = tempw;
    break;

    default:
      return(resINV_INST);
    break;
  }

  return(resGO);
}

int
cl_z80::inst_add(t_mem code)
{
  switch(code)
    {
    case 0x09: // ADD HL,BC
      add_HL_Word(regs.BC);
      break;
    case 0x19: // ADD HL,DE
      add_HL_Word(regs.DE);
      break;
    case 0x29: // ADD HL,HL
      add_HL_Word(regs.HL);
      break;
    case 0x39: // ADD HL,SP
      add_HL_Word(regs.SP);
      break;
      
    case 0x80: // ADD A,B
      add_A_bytereg(regs.bc.h);
      break;
    case 0x81: // ADD A,C
      add_A_bytereg(regs.bc.l);
      break;
    case 0x82: // ADD A,D
      add_A_bytereg(regs.de.h);
      break;
    case 0x83: // ADD A,E
      add_A_bytereg(regs.de.l);
      break;
    case 0x84: // ADD A,H
      add_A_bytereg(regs.hl.h);
      break;
    case 0x85: // ADD A,L
      add_A_bytereg(regs.hl.l);
      break;
      
    case 0x86: // ADD A,(HL)
      {
	unsigned char utmp;
        utmp = get1(regs.HL);
        add_A_bytereg(utmp);
	vc.rd++;
	break;
      }
      
    case 0x87: // ADD A,A
      add_A_bytereg(regs.raf.A);
      break;
      
    case 0xC6: // ADD A,nn
      {
        unsigned char utmp1;
        utmp1 = fetch();
        add_A_bytereg(utmp1);
	break;
      }
      
    default:
      return(resINV_INST);
      break;
    }

  return(resGO);
}

int
cl_z80::inst_djnz(t_mem code)
{
  signed char j;

  // 0x10: DJNZ dd

  j = fetch1();
  if ((--regs.bc.h != 0)) {
    PC += j;
  } else {
  }
  return(resGO);
}

int
cl_z80::inst_rra(t_mem code)
{
  rr_byte(regs.raf.A);
  return(resGO);
}

int
cl_z80::inst_rla(t_mem code)
{
  rl_byte(regs.raf.A);
  return(resGO);
}

int
cl_z80::inst_jr(t_mem code)
{
  signed char j;

  j = fetch1();
  switch(code) {
    case 0x18: // JR dd
      PC += j;
    break;
    case 0x20: // JR NZ,dd
      if (!(regs.raf.F & BIT_Z)) {
        PC += j;
      }
    break;
    case 0x28: // JR Z,dd
      if ((regs.raf.F & BIT_Z)) {
        PC += j;
      }
    break;
    case 0x30: // JR NC,dd
      if (!(regs.raf.F & BIT_C)) {
        PC += j;
      }
    break;
    case 0x38: // JR C,dd
      if ((regs.raf.F & BIT_C)) {
        PC += j;
      }
    break;
    default:
      return(resINV_INST);
    break;
  }
  return(resGO);
}

int
cl_z80::inst_daa(t_mem code)
{
  /************* from MH's z80ops.c:
      unsigned char incr=0, carry=cy;
      if((f&0x10) || (a&0x0f)>9) incr=6;
      if((f&1) || (a>>4)>9) incr|=0x60;
      if(f&2)suba(incr,0);
      else {
         if(a>0x90 && (a&15)>9)incr|=0x60;
         adda(incr,0);
      }
      f=((f|carry)&0xfb);
   ********/
  /* I have not tried to understand this archaic bit of BCD logic(kpb),
     taking the lazy way out for now and just transcribing MH's code.
   */
  unsigned char incr;
  unsigned char N = regs.raf.F & BIT_N; /* save N */
  unsigned char C = regs.raf.F & BIT_C; /* save C */
  if ((regs.raf.F & BIT_A) || ((regs.raf.A & 0x0f) > 9))
       incr = 6;
  else incr = 0;

  if ((regs.raf.F & BIT_C) || ((regs.raf.A & 0xf0) > 0x90) || (regs.raf.A > 0x99))
    incr |= 0x60;

  if (regs.raf.F & BIT_N) {  /* not addition */
    sub_A_bytereg(incr);
  } else {
    add_A_bytereg(incr);
  }
  regs.raf.F &= ~(BIT_P | BIT_N);
  if (parity(regs.raf.A))
    regs.raf.F |= BIT_P;
  regs.raf.F |= N; /* restore N */
  regs.raf.F |= C; /* or with original C */

  return(resGO);
}

int
cl_z80::inst_cpl(t_mem code)
{
  regs.raf.F |= (BIT_A | BIT_N);
  regs.raf.A = ~regs.raf.A;
  return(resGO);
}

int
cl_z80::inst_scf(t_mem code)
{
  /* Set Carry Flag */
  regs.raf.F &= ~(BIT_A | BIT_N);
  regs.raf.F |= BIT_C;
  return(resGO);
}

int
cl_z80::inst_ccf(t_mem code)
{
  /* Complement Carry Flag */
  regs.raf.F &= ~(BIT_A | BIT_N);
  if (regs.raf.F & BIT_C)
    regs.raf.F |= BIT_A;
  regs.raf.F ^= BIT_C;
  return(resGO);
}

int
cl_z80::inst_halt(t_mem code)
{
  return(resHALT);
}

int
cl_z80::inst_adc(t_mem code)
{
  switch(code)
    {
    case 0x88: // ADC A,B
      adc_A_bytereg(regs.bc.h);
      break;
    case 0x89: // ADC A,C
      adc_A_bytereg(regs.bc.l);
      break;
    case 0x8A: // ADC A,D
      adc_A_bytereg(regs.de.h);
      break;
    case 0x8B: // ADC A,E
      adc_A_bytereg(regs.de.l);
      break;
    case 0x8C: // ADC A,H
      adc_A_bytereg(regs.hl.h);
      break;
    case 0x8D: // ADC A,L
      adc_A_bytereg(regs.hl.l);
      break;
    case 0x8E: // ADC A,(HL)
      {
	unsigned char utmp;
        utmp = get1(regs.HL);
        adc_A_bytereg(utmp);
	vc.rd++;
	break;
      }
    case 0x8F: // ADC A,A
      adc_A_bytereg(regs.raf.A);
      break;
      
    case 0xCE: // ADC A,nn
      {
	unsigned char utmp;
        utmp = fetch();
        adc_A_bytereg(utmp);
      }
      break;
      
    default:
      return(resINV_INST);
      break;
    }
  return(resGO);
}

int
cl_z80::inst_sbc(t_mem code)
{
  switch(code)
    {
    case 0x98: // SBC A,B
      sbc_A_bytereg(regs.bc.h);
      break;
    case 0x99: // SBC A,C
      sbc_A_bytereg(regs.bc.l);
      break;
    case 0x9A: // SBC A,D
      sbc_A_bytereg(regs.de.h);
      break;
    case 0x9B: // SBC A,E
      sbc_A_bytereg(regs.de.l);
      break;
    case 0x9C: // SBC A,H
      sbc_A_bytereg(regs.hl.h);
      break;
    case 0x9D: // SBC A,L
      sbc_A_bytereg(regs.hl.l);
      break;
    case 0x9E: // SBC A,(HL)
      {
	unsigned char utmp;
        utmp = get1(regs.HL);
        sbc_A_bytereg(utmp);
	vc.rd++;
	break;
      }
    case 0x9F: // SBC A,A
      sbc_A_bytereg(regs.raf.A);
      break;
    case 0xDE: // SBC A,nn
      {
	unsigned char utmp;
        utmp = fetch();
        sbc_A_bytereg(utmp);
	break;
      }
    default:
      return(resINV_INST);
      break;
    }
  return(resGO);
}

int
cl_z80::inst_and(t_mem code)
{
  switch(code)
    {
    case 0xA0: // AND B
      and_A_bytereg(regs.bc.h);
      break;
    case 0xA1: // AND C
      and_A_bytereg(regs.bc.l);
      break;
    case 0xA2: // AND D
      and_A_bytereg(regs.de.h);
      break;
    case 0xA3: // AND E
      and_A_bytereg(regs.de.l);
      break;
    case 0xA4: // AND H
      and_A_bytereg(regs.hl.h);
      break;
    case 0xA5: // AND L
      and_A_bytereg(regs.hl.l);
      break;
    case 0xA6: // AND (HL)
      {
	unsigned char utmp;
        utmp = get1(regs.HL);
        and_A_bytereg(utmp);
	vc.rd++;
	break;
      }
    case 0xA7: // AND A
      and_A_bytereg(regs.raf.A);
      break;
    case 0xE6: // AND nn
      and_A_bytereg(fetch());
      break;
      
    default:
      return(resINV_INST);
      break;
    }
  return(resGO);
}

int
cl_z80::inst_xor(t_mem code)
{
  switch(code)
    {
    case 0xA8: // XOR B
      xor_A_bytereg(regs.bc.h);
      break;
    case 0xA9: // XOR C
      xor_A_bytereg(regs.bc.l);
      break;
    case 0xAA: // XOR D
      xor_A_bytereg(regs.de.h);
      break;
    case 0xAB: // XOR E
      xor_A_bytereg(regs.de.l);
      break;
    case 0xAC: // XOR H
      xor_A_bytereg(regs.hl.h);
      break;
    case 0xAD: // XOR L
      xor_A_bytereg(regs.hl.l);
      break;
    case 0xAE: // XOR (HL)
      {
	unsigned char utmp;
        utmp = get1(regs.HL);
        xor_A_bytereg(utmp);
	vc.rd++;
	break;
      }
    case 0xAF: // XOR A
      xor_A_bytereg(regs.raf.A);
      break;
    case 0xEE: // XOR nn
      xor_A_bytereg(fetch());
      break;
      
    default:
      return(resINV_INST);
      break;
    }
  return(resGO);
}

int
cl_z80::inst_or(t_mem code)
{
  switch(code)
    {
    case 0xB0: // OR B
      or_A_bytereg(regs.bc.h);
      break;
    case 0xB1: // OR C
      or_A_bytereg(regs.bc.l);
      break;
    case 0xB2: // OR D
      or_A_bytereg(regs.de.h);
      break;
    case 0xB3: // OR E
      or_A_bytereg(regs.de.l);
      break;
    case 0xB4: // OR H
      or_A_bytereg(regs.hl.h);
      break;
    case 0xB5: // OR L
      or_A_bytereg(regs.hl.l);
      break;
    case 0xB6: // OR (HL)
      {
	unsigned char utmp;
        utmp = get1(regs.HL);
        or_A_bytereg(utmp);
	vc.rd++;
	break;
      }
    case 0xB7: // OR A
      or_A_bytereg(regs.raf.A);
      break;
    case 0xF6: // OR nn
      or_A_bytereg(fetch());
      break;
    default:
      return(resINV_INST);
      break;
    }
  return(resGO);
}

int
cl_z80::inst_cp(t_mem code)
{
  /* Compare with Accumulator - subtract and test, leave A unchanged */
  switch(code)
    {
    case 0xB8: // CP B
      cp_bytereg(regs.bc.h);
      break;
    case 0xB9: // CP C
      cp_bytereg(regs.bc.l);
      break;
    case 0xBA: // CP D
      cp_bytereg(regs.de.h);
      break;
    case 0xBB: // CP E
      cp_bytereg(regs.de.l);
      break;
    case 0xBC: // CP H
      cp_bytereg(regs.hl.h);
      break;
    case 0xBD: // CP L
      cp_bytereg(regs.hl.l);
      break;
    case 0xBE: // CP (HL)
      {
	unsigned char utmp;
        utmp = get1(regs.HL);
        cp_bytereg(utmp);
	vc.rd++;
	break;
      }
    case 0xBF: // CP A
      cp_bytereg(regs.raf.A);
      break;
    case 0xFE: // CP nn
      {
	unsigned char utmp;
        utmp = fetch();
        cp_bytereg(utmp);
	break;
      }
    default:
      return(resINV_INST);
      break;
    }
  return(resGO);
}

int
cl_z80::inst_rst(t_mem code)
{
  switch(code)
    {
    case 0xC7: // RST 0
      push2(PC+2);
      PC = 0x0;
      vc.wr+= 2;
      break;
    case 0xCF: // RST 8
      //PC = 0x08;
      switch (regs.raf.A)
	{
	case 0:
	  return(resBREAKPOINT);
	  //          ::exit(0);
	  break;
	  
	case 1:
	  //printf("PUTCHAR-----> %xH\n", regs.hl.l);
	  putchar(regs.hl.l);
	  fflush(stdout);
	  break;
	}
      break;
    case 0xD7: // RST 10H
      push2(PC+2);
      PC = 0x10;
      vc.wr+= 2;
      break;
    case 0xDF: // RST 18H
      push2(PC+2);
      PC = 0x18;
      vc.wr+= 2;
      break;
    case 0xE7: // RST 20H
      push2(PC+2);
      PC = 0x20;
      vc.wr+= 2;
      break;
    case 0xEF: // RST 28H
      push2(PC+2);
      PC = 0x28;
      vc.wr+= 2;
      break;
    case 0xF7: // RST 30H
      push2(PC+2);
      PC = 0x30;
      vc.wr+= 2;
      break;
    case 0xFF: // RST 38H
      push2(PC+2);
      PC = 0x38;
      vc.wr+= 2;
      break;
    default:
      return(resINV_INST);
      break;
    }
  return(resGO);
}

int
cl_z80::inst_ret(t_mem code)
{
  switch(code)
    {
    case 0xC0: // RET NZ
      if (!(regs.raf.F & BIT_Z)) {
        pop2(PC);
	vc.rd+= 2;
      }
      break;
    case 0xC8: // RET Z
      if ((regs.raf.F & BIT_Z)) {
        pop2(PC);
	vc.rd+= 2;
      }
      break;
    case 0xC9: // RET
      pop2(PC);
      vc.rd+= 2;
      break;
    case 0xD0: // RET NC
      if (!(regs.raf.F & BIT_C)) {
        pop2(PC);
	vc.rd+= 2;
      }
      break;
    case 0xD8: // RET C
      if ((regs.raf.F & BIT_C)) {
        pop2(PC);
	vc.rd+= 2;
      }
      break;
    case 0xE0: // RET PO
      if (!(regs.raf.F & BIT_P)) {
        pop2(PC);
	vc.rd+= 2;
      }
      break;
    case 0xE8: // RET PE
      if ((regs.raf.F & BIT_P)) {
        pop2(PC);
	vc.rd+= 2;
      }
      break;
    case 0xF0: // RET P
      if (!(regs.raf.F & BIT_S)) {
        pop2(PC);
	vc.rd+= 2;
      }
      break;
    case 0xF8: // RET M
      if ((regs.raf.F & BIT_S)) {
        pop2(PC);
	vc.rd+= 2;
      }
      break;
    default:
      return(resINV_INST);
      break;
    }
  return(resGO);
}

int
cl_z80::inst_call(t_mem code)
{
  switch(code)
    {
    case 0xC4: // CALL NZ,nnnn
      if (!(regs.raf.F & BIT_Z)) {
        push2(PC+2);
        PC = fetch2();
	vc.wr+= 2;
      } else {
        fetch2();
      }
      break;
    case 0xCC: // CALL Z,nnnn
      if (regs.raf.F & BIT_Z) {
        push2(PC+2);
        PC = fetch2();
	vc.wr+= 2;
      } else {
        fetch2();
      }
      break;
    case 0xCD: // CALL nnnn
      push2(PC+2);
      PC = fetch2();
      vc.wr+= 2;
      break;
    case 0xD4: // CALL NC,nnnn
      if (!(regs.raf.F & BIT_C)) {
        push2(PC+2);
        PC = fetch2();
	vc.wr+= 2;
      } else {
        fetch2();
      }
      break;
    case 0xDC: // CALL C,nnnn
      if (regs.raf.F & BIT_C) {
        push2(PC+2);
        PC = fetch2();
	vc.wr+= 2;
      } else {
        fetch2();
      }
      break;
    case 0xE4: // CALL PO,nnnn
      if (!(regs.raf.F & BIT_P)) {
        push2(PC+2);
        PC = fetch2();
	vc.wr+= 2;
      } else {
        fetch2();
      }
      break;
    case 0xEC: // CALL PE,nnnn
      if (regs.raf.F & BIT_P) {
        push2(PC+2);
        PC = fetch2();
	vc.wr+= 2;
      } else {
        fetch2();
      }
      break;
    case 0xF4: // CALL P,nnnn
      if (!(regs.raf.F & BIT_S)) {
        push2(PC+2);
        PC = fetch2();
	vc.wr+= 2;
      } else {
        fetch2();
      }
      break;
    case 0xFC: // CALL M,nnnn
      if (regs.raf.F & BIT_S) {
        push2(PC+2);
        PC = fetch2();
	vc.wr+= 2;
      } else {
        fetch2();
      }
      break;
    default:
      return(resINV_INST);
      break;
    }
  
  return(resGO);
}

int
cl_z80::inst_out(t_mem code)
{
  t_addr a= fetch();
  outputs->write(a, regs.raf.A);
  return(resGO);
}

int
cl_z80::inst_push(t_mem code)
{
  switch(code)
    {
    case 0xC5: // PUSH BC
      push2(regs.BC);
      vc.wr+= 2;
      break;
    case 0xD5: // PUSH DE
      push2(regs.DE);
      vc.wr+= 2;
      break;
    case 0xE5: // PUSH HL
      push2(regs.HL);
      vc.wr+= 2;
      break;
    case 0xF5: // PUSH AF
      push1(regs.raf.A);
      push1(regs.raf.F);
      vc.wr+= 2;
      break;
    default:
      return(resINV_INST);
      break;
    }
  return(resGO);
}

int
cl_z80::inst_exx(t_mem code)
{
  /* case 0xD9: // EXX - swap BC,DE,HL with alternates */
  u16_t tempw;

  tempw = regs.aHL;
  regs.aHL = regs.HL;
  regs.HL = tempw;

  tempw = regs.aDE;
  regs.aDE = regs.DE;
  regs.DE = tempw;

  tempw = regs.aBC;
  regs.aBC = regs.BC;
  regs.BC = tempw;

  return(resGO);
}

int
cl_z80::inst_in(t_mem code)
{
  t_addr a= fetch();
  regs.raf.A= inputs->read(a);
  return(resGO);
}

int
cl_z80::inst_sub(t_mem code)
{
  switch(code)
    {
    case 0x90: // SUB B
      sub_A_bytereg(regs.bc.h);
      break;
    case 0x91: // SUB C
      sub_A_bytereg(regs.bc.l);
      break;
    case 0x92: // SUB D
      sub_A_bytereg(regs.de.h);
      break;
    case 0x93: // SUB E
      sub_A_bytereg(regs.de.l);
      break;
    case 0x94: // SUB H
      sub_A_bytereg(regs.hl.h);
      break;
    case 0x95: // SUB L
      sub_A_bytereg(regs.hl.l);
      break;
    case 0x96: // SUB (HL)
      {
	unsigned char tmp1;
        tmp1 = get1(regs.HL);
        sub_A_bytereg(tmp1);
	vc.rd++;
      }
      break;
    case 0x97: // SUB A
      sub_A_bytereg(regs.raf.A);
      break;
    case 0xD6: // SUB nn
      {
	unsigned char tmp1;
        tmp1 = fetch();
        sub_A_bytereg(tmp1);
      }
      break;
    default:
      return(resINV_INST);
      break;
    }
  return(resGO);
}

int
cl_z80::inst_pop(t_mem code)
{
  switch (code)
    {
    case 0xC1: // POP BC
      regs.BC = get2(regs.SP);
      regs.SP+=2;
      vc.rd+= 2;
      break;
    case 0xD1: // POP DE
      regs.DE = get2(regs.SP);
      regs.SP+=2;
      vc.rd+= 2;
      break;
    case 0xE1: // POP HL
      regs.HL = get2(regs.SP);
      regs.SP+=2;
      vc.rd+= 2;
      break;
    case 0xF1: // POP AF
      regs.raf.F = get1(regs.SP++);
      regs.raf.A = get1(regs.SP++);
      vc.rd+= 2;
      break;
    default:
      return(resINV_INST);
      break;
    }
  return(resGO);
}

int
cl_z80::inst_jp(t_mem code)
{
  switch (code)
    {
    case 0xC2: // JP NZ,nnnn
      if (!(regs.raf.F & BIT_Z)) {
        PC = fetch2();
      } else {
        fetch2();
      }
      break;
      
    case 0xC3: // JP nnnn
      PC = fetch2();
      break;
      
    case 0xCA: // JP Z,nnnn
      if (regs.raf.F & BIT_Z) {
        PC = fetch2();
      } else {
        fetch2();
      }
      break;
      
    case 0xD2: // JP NC,nnnn
      if (!(regs.raf.F & BIT_C)) {
        PC = fetch2();
      } else {
        fetch2();
      }
      break;
      
    case 0xDA: // JP C,nnnn
      if (regs.raf.F & BIT_C) {
        PC = fetch2();
      } else {
        fetch2();
      }
      break;
      
    case 0xE2: // JP PO,nnnn
      if (!(regs.raf.F & BIT_P)) {
        PC = fetch2();
      } else {
        fetch2();
      }
      break;
      
    case 0xE9: // JP (HL)
      PC = regs.HL;
      break;
      
    case 0xEA: // JP PE,nnnn
      if (regs.raf.F & BIT_P) {
        PC = fetch2();
      } else {
        fetch2();
      }
      break;
      
    case 0xF2: // JP P,nnnn (positive)
      if (!(regs.raf.F & BIT_S)) {
        PC = fetch2();
      } else {
        fetch2();
      }
      break;
      
    case 0xFA: // JP M,nnnn (sign negative)
      if (regs.raf.F & BIT_S) {
        PC = fetch2();
      } else {
        fetch2();
      }
      break;
    default:
      return(resINV_INST);
      break;
    }
  return(resGO);
}

int
cl_z80::inst_di(t_mem code)
{
  /* disable interrupts */
  return(resGO);
}

int
cl_z80::inst_ei(t_mem code)
{
  /* enable interrupts */
  return(resGO);
}

/* End of z80.src/inst.cc */
