/* 
   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.
 */

/*
 * miscellaneous routines which don't fit elsewhere
 */
#include "sim.h"

extern int pcm_quit;

unsigned char *i_0f(pc)
unsigned char *pc; {
  switch (*pc++) {
  case 0:
    switch (*pc++) {
    case 0x08: int_08(); break;
    case 0x11: int_11(); break;
    case 0x12: int_12(); break;
    case 0x10: int_10(); break;
    case 0x13: int_13(); break;
    case 0x14: int_14(); break;
    case 0x15: int_15(); break;
    case 0x17: int_17(); break;
    case 0x1a: int_1a(); break;
    default: pcmexit("panic: unknown interrupt 0x%x\n",*(pc-1));
      break;
    }
  break;
  case 1:
    pcm_quit = 1;
    pcmexit("simulation terminated\n",*(pc-1));
  break;
  case 2:
    init_redirect();
  break;
  default:
    pcm_quit = 1;
    pcmexit("simulation terminated: bad 0f code %d\n",*(pc-1));
  break;
  }
  return pc;
}

unsigned char *i_26(pc)
unsigned char *pc; {
  DSEA = SSEA = ESPTR;
  pc = atomic_interpret(pc);
  SETDS;
  SETSS;
  return pc;
}

unsigned char *i_27(pc)
unsigned char *pc; {
  compute_flags();
  switch (FL4) {
  case ADDB: case INCB: FL3 = 0;
  case ADCB:
    if ((AL & 0xf) > 9 ||
        (FL1 & 0xf) + (FL2 & 0xf) + FL3 > 0xf)
      AL += 6;
    if (AL > 0x9f || CARRY) {
      AL += 0x60;
      CARRY = 1;
    }
    else {
      CARRY = 0;
    }
  break;
  case SUBW:
    FL3 = 0;
    if ((AL & 0xf) > 9 ||
        (short)((FL1 & 0xf) - (FL2 & 0xf) - FL3) < 0) {
      AL += 6;
      CARRY = 1;
    }
    else {
      CARRY = 0;
    }
  break;
  default: pcmexit("panic: DAA code = %d\n",FL4);
  break;
  }
  return pc;
}

unsigned char *i_2e(pc)
unsigned char *pc; {
  DSEA = SSEA = CSPTR;
  pc = atomic_interpret(pc);
  SETDS;
  SETSS;
  return pc;
}

unsigned char *i_36(pc)
unsigned char *pc; {
  DSEA = SSPTR;
  pc = atomic_interpret(pc);
  SETDS;
  return pc;
}

unsigned char *i_37(pc)
unsigned char *pc; {
  unsigned char aux_flag;
  compute_flags();
  switch (FL4) {
  case ADDB: case INCB: FL3 = 0;
  case ADCB:
    aux_flag = ((FL1 & 0xf) + (FL2 & 0xf) + FL3 > 0xf);
  break;
  case SUBW:
    FL3 = 0;
    aux_flag = ((short)((FL1 & 0xf) - (FL2 & 0xf) - FL3) < 0);
  break;
  default: pcmexit("panic: AAA code = %d at %4.4x:%4.4x\n",FL4,
     CS,(--pc-CSPTR));
  break;
  }
  if ((AL & 0xf) > 9 || aux_flag) {
    AL += 6;
    AH++;
  }
  AL &= 0xf;
  CARRY = aux_flag;
  return pc;
}

unsigned char *i_3e(pc)
unsigned char *pc; {
  SSEA = DSPTR;
  pc = atomic_interpret(pc);
  SETSS;
  return pc;
}



unsigned char *i_86(pc)
unsigned char *pc; {
  unsigned char ctmp;
  pc = byte_operand(pc);
  ctmp = *REGPTR;
  *REGPTR = *EAPTRL;
  *EAPTRL = ctmp;
  return pc;
}

unsigned char *i_87(pc)
unsigned char *pc; {
  unsigned char ctmp;
  unsigned short stmp;
  pc = word_operand(pc);
  stmp = *(unsigned short *)REGPTR;
  *REGPTRH = *EAPTRH;
  *REGPTRL   = *EAPTRL;
  *EAPTRL = stmp;
  *EAPTRH = stmp >> 8;
  return pc;
}

unsigned char *i_8d(pc)
unsigned char *pc; {
  pc = word_operand2(pc); /* Load reg with offset */
  return pc;
}

unsigned char *i_90(pc)
unsigned char *pc; {
  return pc;
}

unsigned char *i_91(pc)
unsigned char *pc; {
  unsigned short opr;
  opr = AX;
  AX = CX;
  CX = opr;
  return pc;
}

unsigned char *i_92(pc)
unsigned char *pc; {
  unsigned short opr;
  opr = AX;
  AX = DX;
  DX = opr;
  return pc;
}

unsigned char *i_93(pc)
unsigned char *pc; {
  unsigned short opr;
  opr = AX;
  AX = BX;
  BX = opr;
  return pc;
}

unsigned char *i_94(pc)
unsigned char *pc; {
  unsigned short opr;
  opr = AX;
  AX = SP;
  SP = opr;
  return pc;
}

unsigned char *i_95(pc)
unsigned char *pc; {
  unsigned short opr;
  opr = AX;
  AX = BP;
  BP = opr;
  return pc;
}

unsigned char *i_96(pc)
unsigned char *pc; {
  unsigned short opr;
  opr = AX;
  AX = SI;
  SI = opr;
  return pc;
}

unsigned char *i_97(pc)
unsigned char *pc; {
  unsigned short opr;
  opr = AX;
  AX = DI;
  DI = opr;
  return pc;
}

unsigned char *i_98(pc)
unsigned char *pc; {
  AX = (char)AL;
  return pc;
}

unsigned char *i_99(pc)
unsigned char *pc; {
  DX = (AX & 0x8000) ? 0xffff : 0;
  return pc;
}

unsigned char *i_9b(pc)
unsigned char *pc; { /* wait */
  TIMELEFT = 1;
  return --pc;
}

unsigned char *i_d4(pc)
unsigned char *pc; {
  if (*pc++ != 0xa) {
    return unk_op(pc);
  }
  AH = AL / 10;
  AL %= 10;
  PFLAG2(AL, CBOOL);
  return pc;
}

unsigned char *i_d5(pc)
unsigned char *pc; {
  if (*pc++ != 0xa) {
    return unk_op(pc);
  }
  AL += AH * 10;
  AH = 0;
  PFLAG2(AL, CBOOL);
  return pc;
}

unsigned char *i_d7(pc)
unsigned char *pc; {
  AL = *(DSEA+(AL+BX));
  return pc;
}

unsigned char *i_esc(pc)
unsigned char *pc; {
  static unsigned char warned = 0;
  pc = word_operand(pc);
  if (!warned) {
    printf("Warning: Numeric Co-processor escapes not implemented yet!\n");
    warned++;
  }
  return pc;
}

unsigned char *i_f0(pc)
unsigned char *pc; {
  return pc;
}

unsigned char *i_f4(pc)
unsigned char *pc; {
  pcmexit("Processor Halted\n");
}
