/* 
   Pcm: a PC eMulator
   Copyright (C) 1992 Electronetics, Inc.  All rights reserved.

   This program 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.

   This program 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 this program; if not, write to the Free Software
   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 */

/*
 * Routines to implement logical instructions
 */
#include "sim.h"

unsigned char *i_08(pc)
unsigned char *pc; {  /* or */
  pc = byte_operand(pc);
  *EAPTRL |= *REGPTR;
  PFLAG2(*EAPTRL, CBOOL);
  return pc;
}

unsigned char *i_09(pc)
unsigned char *pc; {  /* or */
  pc = word_operand(pc);
  FL1L = *EAPTRL |= *REGPTRL;
  FL1H = *EAPTRH |= *REGPTRH;
  PFLAG1(WBOOL);
  return pc;
}

unsigned char *i_0a(pc)
unsigned char *pc; {  /* or */
  pc = byte_operand(pc);
  *REGPTR |= *EAPTRL;
  PFLAG2(*REGPTR, CBOOL);
  return pc;
}

unsigned char *i_0b(pc)
unsigned char *pc; {  /* or */
  pc = word_operand(pc);
  *REGPTRH |= *EAPTRH;
  *REGPTRL |= *EAPTRL;
  PFLAG2(*(unsigned short *)REGPTR,WBOOL);
  return pc;
}

unsigned char *i_0c(pc)
unsigned char *pc; {
  AL |= *pc++;
  PFLAG2(AL, CBOOL);
  return pc;
}

unsigned char *i_0d(pc)
unsigned char *pc; {
  AL |= *pc++;
  AH |= *pc++;
  PFLAG2(AX, WBOOL);
  return pc;
}

unsigned char *i_20(pc)
unsigned char *pc; {  /* and */
  pc = byte_operand(pc);
  *EAPTRL &= *REGPTR;
  PFLAG2(*EAPTRL,CBOOL);
  return pc;
}

unsigned char *i_21(pc)
unsigned char *pc; { /* and */
  pc = word_operand(pc);
  FL1L = *EAPTRL &= *REGPTRL;
  FL1H = *EAPTRH &= *REGPTRH;
  PFLAG1(WBOOL);
  return pc;
}


unsigned char *i_22(pc)
unsigned char *pc; {  /* and */
  pc = byte_operand(pc);
  *REGPTR &= *EAPTRL;
  PFLAG2(*REGPTR, CBOOL);
  return pc;
}

unsigned char *i_23(pc)
unsigned char *pc; {  /* and */
  pc = word_operand(pc);
  FL1L = *REGPTRL &= *EAPTRL;
  FL1H = *REGPTRH &= *EAPTRH;
  PFLAG1(CBOOL);
  return pc;
}

unsigned char *i_24(pc)
unsigned char *pc; {  /* and */
  AL &= *pc++;
  PFLAG2(AL, CBOOL);
  return pc;
}

unsigned char *i_25(pc)
unsigned char *pc; {  /* and */
  FL1L = AL &= *pc++;
  FL1H = AH &= *pc++;
  PFLAG1(WBOOL);
  return pc;
}

unsigned char *i_30(pc)
unsigned char *pc; {  /* xor */
  pc = byte_operand(pc);
  FL1 = *EAPTRL ^= *REGPTR;
  PFLAG1(CBOOL);
  return pc;
}

unsigned char *i_31(pc)
unsigned char *pc; {  /* xor */
  pc = word_operand(pc);
  FL1L = *EAPTRL ^= *REGPTRL;
  FL1H = *EAPTRH ^= *REGPTRH;
  PFLAG1(WBOOL);
  return pc;
}

unsigned char *i_32(pc)
unsigned char *pc; {  /* xor */
  pc = byte_operand(pc);
  *REGPTR ^= *EAPTRL;
  PFLAG2(*REGPTR, CBOOL);
  return pc;
}

unsigned char *i_33(pc)
unsigned char *pc; {  /* xor */
  pc = word_operand(pc);
  FL1L = *REGPTRH ^= *EAPTRH;
  FL1H = *REGPTRL ^= *EAPTRL;
  PFLAG1(WBOOL);
  return pc;
}

unsigned char *i_34(pc)
unsigned char *pc; {  /* xor */
  AL ^= *pc++;
  PFLAG2(AL, CBOOL);
  return pc;
}

unsigned char *i_35(pc)
unsigned char *pc; { /* xor */
  AL ^= *pc++;
  AH ^= *pc++;
  PFLAG2(AX,WBOOL);
  return pc;
}

unsigned char *i_84(pc)
unsigned char *pc; {
  pc = byte_operand(pc);
  PFLAG2(*EAPTRL & *REGPTR, CBOOL);
  return pc;
}

unsigned char *i_85(pc)
unsigned char *pc; {
  pc = word_operand(pc);
  FL1L = *EAPTRL & *REGPTRL;
  FL1H = *EAPTRH & *REGPTRH;
  PFLAG1(WBOOL);
  return pc;
}

unsigned char *i_a8(pc)
unsigned char *pc; {
  PFLAG2(AL & *pc++, CBOOL);
  return pc;
}

unsigned char *i_a9(pc)
unsigned char *pc; {
  FL1L = AL & *pc++;
  FL1H = AH & *pc++;
  PFLAG1(WBOOL);
  return pc;
}

unsigned char *i_d0(pc)
unsigned char *pc; {
  unsigned char res;
  unsigned long ulong;
  long slong;
  pc = byte_operand(pc);
  switch ((unsigned char *)REGPTR-(unsigned char *)qmem) {
  case _AH: /* AH, SAL */
    ulong = *EAPTRL;
    ulong <<= 1;
    *EAPTRL = (res=ulong);
    CARRY = ((ulong & 0x100) != 0);
    OVERFLOW = ((ulong & 0x80) != 0) ^ CARRY;
    ZERO = !res;
    SIGN = ((char)res < 0);
    FLAGS_OK = 1;
  break;
  case _AL: /* AL, ROL */
    compute_flags(); /* need sign and zero */
    res = *EAPTRL;
    CARRY = ((res & 0x80) != 0);
    OVERFLOW = ((res & 0x40) != 0) ^ CARRY;
    res <<= 1;
    *EAPTRL = res | CARRY;
  break;
  case _CH: /* CH, SHR */
    ulong = *EAPTRL;
    CARRY = ulong & 01;
    OVERFLOW = ((ulong & 0x80) != 0);
    res = ulong >> 1;
    *EAPTRL = res;
    SIGN = ((char)res < 0);
    ZERO = !res;
    FLAGS_OK = 1;
  break;
  case _CL: /* CL, ROR */
    compute_flags(); /* need sign and zero */
    ulong = *EAPTRL;
    CARRY = (ulong & 01);
    OVERFLOW = ((ulong & 0x80) != 0) ^ CARRY;
    ulong |= ulong << 8;
    res = ulong >> 1;
    *EAPTRL = res;
  break;
  case _DL: /* DL, RCL */
    compute_flags(); /* need sign and zero */
    ulong = *EAPTRL << 1 | CARRY;
    CARRY = ((ulong & 0x100) != 0);
    OVERFLOW = ((ulong & 0x80) != 0) ^ CARRY;
    res = ulong;
    *EAPTRL = res;
  break;
  case _BH: /* BH, SAR */
    slong = (char)*EAPTRL;
    OVERFLOW = 0;
    CARRY = slong & 01;
    res = slong >> 1;
    *EAPTRL = res;
    ZERO = !res;
    SIGN = ((char)res < 0);
    FLAGS_OK = 1;
  break;
  case _BL: /* BL, RCR */
    compute_flags(); /* need sign and zero */
    ulong = *EAPTRL | ((unsigned int)CARRY << 8);
    OVERFLOW = ((ulong & 0x80) != 0) ^ CARRY;
    CARRY = ulong & 01;
    res = ulong >> 1;
    *EAPTRL = res;
  break;
  default: return unk_op(pc);
  }
  return pc;
}

unsigned char *i_d1(pc)
unsigned char *pc; {
  unsigned short res;
  unsigned long ulong;
  long slong;
  pc = word_operand(pc);
  switch ((unsigned short *)REGPTR-(unsigned short *)qmem) {
  case 0: /* AX, ROL */
    compute_flags(); /* need sign and zero */
    res = *EAPTRL | (unsigned int)*EAPTRH << 8;
    CARRY = ((res & 0x8000) != 0);
    OVERFLOW = ((res & 0x4000) != 0) ^ CARRY;
    res <<= 1;
    res |= CARRY;
    *EAPTRL = res;
    *EAPTRH = res >> 8;
  break;
  case 1: /* CX, ROR */
    compute_flags(); /* need sign and zero */
    res = *EAPTRL | (unsigned int)*EAPTRH << 8;
    CARRY = (res & 01);
    OVERFLOW = ((res & 0x8000) != 0) ^ CARRY;
    ulong = res | ((unsigned int)res << 16);
    res = ulong >> 1;
    *EAPTRL = res;
    *EAPTRH = res >> 8;
  break;
  case 2: /* DX, RCL */
    compute_flags(); /* need sign and zero */
    res = *EAPTRL | (unsigned int)*EAPTRH << 8;
    ulong = ((unsigned int)res << 1) | CARRY;
    CARRY = ((ulong & 0x10000) != 0);
    OVERFLOW = ((ulong & 0x8000) != 0) ^ CARRY;
    res = ulong;
    *EAPTRL = res;
    *EAPTRH = res >> 8;
  break;
  case 3: /* BX, RCR */
    compute_flags(); /* need sign and zero */
    res = *EAPTRL | (unsigned int)*EAPTRH << 8;
    ulong = res | ((unsigned int)CARRY << 16);
    OVERFLOW = ((ulong & 0x8000) != 0) ^ CARRY;
    CARRY = ulong & 01;
    res = ulong >> 1;
    *EAPTRL = res;
    *EAPTRH = res >> 8;
  break;
  case 4: /* SP, SAL */
    res = *EAPTRL | (unsigned int)*EAPTRH << 8;
    CARRY = ((res & 0x8000) != 0);
    OVERFLOW = ((res & 0x4000) != 0) ^ CARRY;
    res <<= 1;
    *EAPTRL = res;
    *EAPTRH = res >> 8;
    ZERO = !res;
    SIGN = ((short)res < 0);
    FLAGS_OK = 1;
  break;
  case 5: /* BP, SHR */
    res = *EAPTRL | (unsigned int)*EAPTRH << 8;
    CARRY = res & 01;
    OVERFLOW = ((res & 0x8000) != 0);
    res >>= 1;
    *EAPTRL = res;
    *EAPTRH = res >> 8;
    SIGN = ((short)res < 0);
    ZERO = !res;
    FLAGS_OK = 1;
  break;
  case 7: /* DI, SAR */
    res = *EAPTRL | (unsigned int)*EAPTRH << 8;
    OVERFLOW = 0;
    CARRY = res & 01;
    res = (short)res >> 1;
    *EAPTRL = res;
    *EAPTRH = res >> 8;
    ZERO = !res;
    SIGN = ((short)res < 0);
    FLAGS_OK = 1;
  break;
  default: return unk_op(pc);
  }
  return pc;
}

unsigned char *i_d2(pc)
unsigned char *pc; {
  int count;
  unsigned char  res;
  unsigned long ulong;
  long slong;
  count = CL & 0x1f;  /* shift/rotate % 32 */
  pc = byte_operand(pc);
  switch ((unsigned char *)REGPTR-(unsigned char *)qmem) {
  case _AH: /* AH, SAL */
    ulong = *EAPTRL;
    ulong <<= count;
    *EAPTRL = res = ulong;
    CARRY = ((ulong & 0x100) != 0);
    ZERO = !res;
    FLAGS_OK = 1;
  break;
  case _CH: /* CH, SHR */
    ulong = *EAPTRL << 1;
    ulong >>= count;
    CARRY = ulong & 01;
    res = ulong >> 1;
    *EAPTRL = res;
    ZERO = !res;
    FLAGS_OK = 1;
  break;
  case _BH: /* BH, SAR */
    slong = ((char)*EAPTRL) << 1;
    slong >>= count;
    CARRY = slong & 01;
    res = slong >> 1;
    *EAPTRL = res;
    ZERO = !res;
    OVERFLOW = 0;
    FLAGS_OK = 1;
  break;
  default: return unk_op(pc);
  }
  return pc;
}

unsigned char *i_d3(pc)
unsigned char *pc; {
  int count;
  unsigned short  res;
  unsigned long ulong;
  long slong;
  count = CL & 0x1f;  /* shift/rotate % 32 */
  pc = word_operand(pc);
  switch ((unsigned short *)REGPTR-(unsigned short *)qmem) {
  case 0: /* AX, ROL */
    compute_flags(); /* need sign and zero */
    ulong = *EAPTRL | ((unsigned int)*EAPTRH) << 8;
    CARRY = ulong >> 15;
    ulong |= ulong << 16;
    res = (ulong << count) | (ulong >> (32 - count));
    *EAPTRL = res;
    *EAPTRH = res >> 8;
    FLAGS_OK = 1;
  break;
  case 1: /* CX, ROR */
    ulong = *EAPTRL | ((unsigned int)*EAPTRH) << 8;
    ulong |= ulong << 16;
    res = (ulong >> count) | (ulong << (32 - count));
    CARRY = res >> 15;
    OVERFLOW = 0;
    *EAPTRL = res;
    *EAPTRH = res >> 8;
    FLAGS_OK = 1;
  break;
  case 3: /* BX, RCR */
    compute_flags(); /* need sign and zero */
    res = *EAPTRL | (unsigned int)*EAPTRH << 8;
    ulong =  res | ((unsigned int)CARRY << 16);
    res = ulong = (ulong >> count) | (ulong << (32 - count));
    CARRY = (ulong >> 16) & 01;
    *EAPTRL = res;
    *EAPTRH = res >> 8;
    FLAGS_OK = 1;
  break;
  case 4: /* SP, SAL */
    ulong = *EAPTRL | ((unsigned int)*EAPTRH) << 8;
    res = (ulong <<= count);
    *EAPTRL = res;
    *EAPTRH = res >> 8;
    CARRY = (ulong >> 16) & 01;
    ZERO = !res;
    FLAGS_OK = 1;
  break;
  case 5: /* BP, SHR */
    ulong = *EAPTRL | ((unsigned int)*EAPTRH) << 8;
    ulong <<= 1;
    ulong >>= count;
    CARRY = ulong & 01;
    res = ulong >> 1;
    *EAPTRL = res;
    *EAPTRH = res >> 8;
    ZERO = !res;
    FLAGS_OK = 1;
  break;
  case 7: /* DI, SAR */
    slong = *EAPTRL | ((unsigned int)*EAPTRH) << 8;
    slong <<= 1;
    slong >>= count;
    CARRY = slong & 01;
    res = slong >> 1;
    *EAPTRL = res;
    *EAPTRH = res >> 8;
    ZERO = !res;
    OVERFLOW = 0;
    FLAGS_OK = 1;
  break;
  default: return unk_op(pc);
  }
  return pc;
}

