/*-----------------------------------------------------------------------
-------------------------------------------------------------------------


   FILE:    sim.c

   PURPOSE: Functional simulation of the 68000 microprocessor.
        This simulator simulates the 68000 microprocessor at 
        the behavioral level. 

        SI serves as the user interface.  SI window displays
        serve as probes into the 68000 CPU internal resources.

   AUTHOR:      Jay Lloyd
   DATE:        1990

   USAGE:   See the 'make' file.

   HISTORY: Spring 1989 -- Creation

   Copyright 1990-1991 North Carolina State University. All Rights Reserved.

-------------------------------------------------------------------------
------------------------------------------------------------------------*/
#include "SI.h"
#include "sim.h"
#include <stdio.h>
#include <math.h>
#define TRUE	0xFF
#define FALSE	0


unsigned int   reg[18], pc = 0;

unsigned int   f_C, f_V, f_N, f_Z, f_X,
               Sbit, Tbit, I0Bit, I1Bit, I2Bit;
char *Un1 = "X\0";
char *Un2 = "X\0";
char *Un3 = "X\0";
char *Un4 = "X\0";
char *Un5 = "X\0";
char *Un6 = "X\0";

unsigned int   port1_st, port1_cn, port1_tr, port1_rc;

int   strace_on = 0,
      sstep_on = 0;



main (int argc, char *argv[]) {
   void driver ();


   /* Set up everything needed for SI:                  */
   /* This routine ONLY needs to be called ONCE.            */
   if (!SI_init ()) {
      printf ("\nUnable to start simulator!!!\n");
      printf ("\nIs the file SI.h in the correct path?");
      printf ("\nAre you using an X Window terminal?\n\n");
      exit ();
   };

   /* Call the simulator command loop driver:               */
   driver ();
}


void init_all () {
   int   i;

   for (i = 0; i < 18; i++)
      reg[i] = 0;
   f_C = f_V = f_N = f_Z = f_X = 0;
   Sbit = 1;
   Tbit = 0;
   I0Bit = 1;
   I1Bit = 0;
   I2Bit = 1;
   reg[A7] = reg[SSP] = 0x500;
   reg[USP] = 0x1000;
}


/*-----------------------------------------------------------------------
   exec_driver:

   The execution loop must also include a call to SI_event_process().
   The execution loop is the loop that actually simulate an instruction
   cycle.

------------------------------------------------------------------------*/
void exec_driver () {
   int   done;
   int   cbutton;
   int   take_a_step,
         sf;
   int   exec_instruction ();


   done = 0;
   take_a_step = 0;
   sf = 0;
   while (!done) {
      /* Do instruction cycle here:                 */
      /* An instruction cycle is simulated by calling exec_instruction() */
      if (!sstep_on) {
	 sf = exec_instruction ();
	 if (sf != 0)		/* sf==0:  instr. exec. OK  */
	    done = 1;
	 if (strace_on)
	    SI_update_window (1);
      }
      else
	 if (take_a_step) {	/* single stepping      */
	    sf = exec_instruction ();
	    if (sf != 0)
	       done = 1;
	    take_a_step = 0;
	    if (strace_on)
	       SI_update_window (1);
	 };


      /*----------------------------------------------------------------*/
      /* Run SI:                            */
      cbutton = SI_event_process ();
      switch (cbutton) {
	 case HALT_SIM_CB: 	/* Halt simulation:     */
	    done = 1;
	    break;

	 case VIEW_MEM_CB: 	/* Display content of memory:       */
	    SI_do_memory_dynamic ();
	    break;

	 case TAKE_STEP_CB: 	/* Take a step:         */
	    if (sstep_on)
	       take_a_step = 1;
	    break;

	 case SSTEP_ON_CB: 	/* Turn on single step mode:        */
	    SI_do_single_step_on ();
	    SI_do_screen_trace_on ();
	    break;

	 case SSTEP_OFF_CB: 	/* Turn single step off:        */
	    SI_do_single_step_off ();
	    SI_do_screen_trace_off ();
	    break;

	 case STRACE_ON_CB: 	/* Turn screen trace on:        */
	    SI_do_screen_trace_on ();
	    break;

	 case STRACE_OFF_CB: 	/* Turn screen trace off:       */
	    SI_do_screen_trace_off ();
	    break;

	 case CLEAR_ALL_CB: 	/* Initialize the CPU and other related
				   resources:               */
	    init_all ();
	    SI_update_window (1);
	    break;

	 case INT_CB: 
	    doInt ();
	    SI_update_window(1);
	    break;
      };
   };				/* end while                          */

   /* Update SI window:                         */
   if (!strace_on)		/* Update if trace is not tracing:  */
      SI_update_window (1);

   /* Display simulation status:                    */
   if (sf != 0)
      switch (sf) {
	 case 1: 		/* normal halt                  */
	    SI_prompt_error ("Simulation Completed.");
	    break;
	 case -1: 
	    SI_prompt_error ("Simulation Error: Memory Address Out Of Range.");
	    break;
	 case -2: 
	    SI_prompt_error ("Simulation Error: Illegal Opcode.");
	    break;
	 case -3: 
	    SI_prompt_error ("Simulation Error: Illegal Addressing Mode.");
	    break;
	 case -4: 
	    SI_prompt_error ("Simulation Halted: BreakPoint.");
	    break;
	 case -5: 
	    SI_prompt_error ("Trap");
	    break;
      };

   SI_do_halt_sim ();
}



/*-----------------------------------------------------------------------
-------------------------------------------------------------------------
   driver:

   Drives the main command loop of the simulator.
   The simulator command loop is the one that parse the commands buttons
   at the bottom of SI window.
------------------------------------------------------------------------*/
void driver () {
   int   done;
   int   cbutton;


   /* Do the variables init for the simulator:              */
   init_all ();

   /* Do the main event loop for simulator command parsing:     */
   done = 0;
   while (!done) {		/* Run SI and get any pressed command button:  
				*/
      cbutton = SI_event_process ();
      switch (cbutton) {
	 case LOAD_CODE_CB: 	/* Load object code:            */
	    SI_do_load_code ();
	    break;

	 case START_SIM_CB: 	/* Go start simulation of execution:    */
	    SI_do_start_sim ();
	    exec_driver ();
	    break;

	 case VIEW_MEM_CB: 	/* Display content of memory:       */
	    SI_do_memory_dynamic ();
	    break;

	 case STRACE_ON_CB: 	/* Turn screen trace on:        */
	    SI_do_screen_trace_on ();
	    break;

	 case SSTEP_ON_CB: 	/* Turn on single step mode:        */
	    SI_do_single_step_on ();
	    SI_do_screen_trace_on ();
	    break;

	 case EXIT_PROG_CB: 	/* Exit the simulator:          */
	    done = 1;
	    break;

	 case HALT_SIM_CB: 	/* Halt simulated execution:        */
	    /* Since this is the simulator command loop, there is not execution
	       here.  This command button is insignificant here. Ignore it
	       here.                   */
	    break;

	 case STRACE_OFF_CB: 	/* Turn screen trace off:       */
	    SI_do_screen_trace_off ();
	    break;

	 case SSTEP_OFF_CB: 	/* Turn single step off:        */
	    SI_do_single_step_off ();
	    SI_do_screen_trace_off ();
	    break;

	    /*-------------------------------------------------------------*/
	    /* These are for the buttons on the right side of SI window:   */

	 case CLEAR_ALL_CB: 	/* Initialize the CPU and other related
				   resources:               */
	    init_all ();
	    SI_update_window (1);
	    break;

      };			/* end switch                          */
   };				/* end while                          */
}


/*
 * Start execution model here
 */
int   getRegVal (int regNum, int opSize) {
   int   val;

   switch (opSize) {
      case Short: 
	 val = reg[regNum] & 0xff;
	 break;
      case Word: 
	 val = reg[regNum] & 0xffff;
	 break;
      case Long: 
	 val = reg[regNum];
	 break;
   }
   return val;
}

int   getMemVal (int opSize, int address) {
   int   val;

   switch (opSize) {
      case Short: 
	 val = SI_mem_fetch (address);
	 break;

      case Word: 
	 val = SI_mem_fetch (address);
	 val <<= 8;
	 val += SI_mem_fetch (address + 1);
	 break;

      case Long: 
	 val = SI_mem_fetch (address);
	 val <<= 8;
	 val += SI_mem_fetch (address + 1);
	 val <<= 8;
	 val += SI_mem_fetch (address + 2);
	 val <<= 8;
	 val += SI_mem_fetch (address + 3);
	 break;
   }
   return val;
}

/*
 * Sign extend an operand
 */
int   signExtend (int operand, int size) {
   switch (size) {
      case  Short: 
	 if    (operand & 0x80)
            return ((operand&0xff) + 0xffffff00);
	 else
	    return (operand&0xff);
	 break;

      case Word: 
	 if (operand & 0x8000)
	    return ((operand&0xffff) + 0xffff0000);
	 else
	    return (operand&0xffff);
	 break;

      case Long: 
	 return operand;
	 break;
   }
}

/*
 * Get a data operand. Parse the addressing modes and return
 * the operand in opr. Function returns SI error codes as required.
 */
getData (int addMode, int registr, int *opr, int size, int *addr) {
   int   registrA, IXreg, extenWord;

   registrA = registr + 8;
   switch (addMode) {
      case DDirect: 
	 *opr = getRegVal (registr, size);
	 break;

      case ADirect: 
	 *opr = getRegVal (registrA, size);
	 break;

      case AIndirect: 
	 if (reg[registrA] >= MAX_MEM_SIZE)
	    return (MemErr);
	 *addr = reg[registrA];
	 *opr = getMemVal (size, reg[registrA]);
	 break;

      case AIndInc: 
	 if (reg[registrA] >= MAX_MEM_SIZE)
	    return (MemErr);
	 *addr = reg[registrA];
	 *opr = getMemVal (size, reg[registrA]);
	 switch (size) {
	    case Short: 
	       reg[registrA]++;
	       break;

	    case Word: 
	       reg[registrA] += 2;
	       break;

	    case Long: 
	       reg[registrA] += 4;
	       break;
	 }
	 break;

      case AIndDec: 
	 if (reg[registrA] >= MAX_MEM_SIZE)
	    return (MemErr);
	 switch (size) {
	    case Short: 
	       reg[registrA]--;
	       break;

	    case Word: 
	       reg[registrA] -= 2;
	       break;

	    case Long: 
	       reg[registrA] -= 4;
	       break;
	 }
	 *opr = getMemVal (size, reg[registrA]);
	 *addr = reg[registrA];
	 break;

      case AIndDisp: 
	 extenWord = getMemVal (Word, pc);
	 extenWord = signExtend (extenWord, Word);
	 pc += 2;
	 *addr = reg[registrA] + extenWord;
	 *opr = getMemVal (size, *addr);
	 break;

      case AIndIx: 
	 extenWord = getMemVal (Word, pc);
	 extenWord = signExtend (extenWord, Word);
	 pc += 2;
	 IXreg = (extenWord & AddrMask) >> 12;
	 if (extenWord < 0)
	    IXreg += 8;
	 *addr = reg[registrA] + signExtend ((DispMask & extenWord), Short);
	 *addr += reg[IXreg];
	 *opr = getMemVal (size, *addr);
	 break;

      case SpecModes: 
	 switch (registr) {
	    case AbShort: 
	       *addr = getMemVal (Word, pc);
	       *addr = signExtend (*addr, Word);
	       pc += 2;
	       break;

	    case AbLong: 
	       *addr = getMemVal (Long, pc);
	       pc += 4;
	       break;

	    case PCDis: 
	       extenWord = getMemVal (Word, pc);
	       extenWord = signExtend (extenWord, Word);
	       *addr = pc + extenWord;
	       pc += 2;
	       break;

	    case PCIx: 
	       extenWord = getMemVal (Word, pc);
	       extenWord = signExtend (extenWord, Word);
	       IXreg = (extenWord & AddrMask) >> 12;
	       if (extenWord < 0)
		  IXreg = IXreg + 8;
	       *addr = pc + signExtend ((DispMask & extenWord), Short);
	       *addr += reg[IXreg];
	       pc += 2;
	       break;

	    case Immed: 
	       *addr = pc;
	       if (size == Short || size == Word) {
		     size = Word;
		     pc += 2;
	       } else
		     pc += 4;
	       break;
	 }
	 *opr = getMemVal (size, *addr);
	 break;

      default:
	 return IllAddMode;
   }
   return (NORMAL);
}

/*
 * Write a data value to a register. Clear the required size
 * for proper operation.
 */
setRegVal (int regNum, int size, int operand) {
   switch (size) {
      case Short: 
	 reg[regNum] &= 0xffffff00;
	 reg[regNum] += (operand & 0xff);
	 break;

      case Word: 
	 reg[regNum] &= 0xffff0000;
	 reg[regNum] += (operand & 0xffff);
	 break;

      case Long: 
	 reg[regNum] = operand;
	 break;
   }
}

/*
 * Write a value to memory at the specified location and the
 * specified size.
 */
setMemVal (int location, int size, unsigned int opr) {
   if (location >= MAX_MEM_SIZE)
      return (MemErr);
   switch (size) {
      case Short: 
	 SI_mem_write (location, opr);
	 break;

      case Word: 
	 SI_mem_write (location, (opr >> 8));
	 SI_mem_write (location + 1, opr);
	 break;

      case Long: 
	 SI_mem_write (location, (opr >> 24));
	 SI_mem_write (location + 1, (opr >> 16));
	 SI_mem_write (location + 2, (opr >> 8));
	 SI_mem_write (location + 3, opr);
	 break;
   }
   return NORMAL;
}

/*
 *
 * Write a data operand. Write the operand to the address/register
 * specified. Function returns SI error codes as required.
 *
 */
putData (int addMode, int registr, int operand, int size, int addr) {
   int   registrA, IXreg, extenWord, status;

   registrA = registr + 8;
   status = NORMAL;
   switch (addMode) {
      case DDirect: 
	 setRegVal (registr, size, operand);
	 break;

      case ADirect: 
	 setRegVal (registrA, size, operand);
	 break;

      case AIndirect: 
      case AIndInc:
      case AIndDec:
      case AIndDisp: 
      case AIndIx: 
      case SpecModes: 
	 if (addr >= MAX_MEM_SIZE)
	    return (MemErr);
	 status = setMemVal (addr, size, operand);
	 break;

      default:
	 return IllAddMode;
   }
   return status;
}

/*
 * Get the addressing mode for most of the instructions. The source
 * mode starts at bit 3 and the destination mode starts at bit 6.
 */
getMode (unsigned int opcode, int destOrSource) {
   switch (destOrSource) {
      case SOURCE: 
	 return ((opcode >> 3) & ModeMask);
	 break;

      case DEST: 
	 return ((opcode >> 6) & ModeMask);
	 break;
   }
}

/*
 * Get the addressing register for most of the instructions. The source
 * register starts at bit 0 and the destination register starts at bit 9.
 */
getReg (unsigned int opcode, int destOrSource) {
   switch (destOrSource) {
      case SOURCE: 
	 return (opcode & ModeMask);
	 break;

      case DEST: 
	 return ((opcode >> 9) & ModeMask);
	 break;
   }
}

/*
 * Do normal move.B,W,L. Get the size,then the operand then move it.
 */
doMove (int size, unsigned int opcode) {
   int   status, destMode, sourceMode, sourceReg, destReg;
   int   sourceOp, dummy, addr;

   size = opcode >> 12;
   destMode = getMode (opcode, DEST);
   destReg = getReg (opcode, DEST);
   sourceMode = getMode (opcode, SOURCE);
   sourceReg = getReg (opcode, SOURCE);
   if ((destMode == SpecModes) && (destReg > AbLong))
      return IllAddMode;
   status = getData(sourceMode, sourceReg, &sourceOp, size, &addr);
   if (!status) {
      sourceOp = signExtend (sourceOp, size);
      status = getData(destMode, destReg, &dummy, size, &addr);
      if (!status) {
	 status = putData (destMode, destReg, sourceOp, size, addr);

	 /* 
	  * Set the status register bits
	  */
	 if (destMode != 1) {
	    f_V = 0;
	    f_C = 0;
	    f_N = signExtend(sourceOp,size) < 0;
	    f_Z = !sourceOp;
	 }
      }
   }
   return status;
}


/*
 * Sets bit flags for determining condition codes
 */
setSDRm (int dataOp,int EAOp,int result,int *Sm,int *Dm,int *Rm,int size)
{
   switch (size) {
      case Short: 
	 *Sm = dataOp >> 7 & 1;
	 *Dm = EAOp >> 7 & 1;
	 *Rm = result >> 7 & 1;
	 break;
      case Word: 
	 *Sm = dataOp >> 15 & 1;
	 *Dm = EAOp >> 15 & 1;
	 *Rm = result >> 15 & 1;
	 break;
      case Long: 
	 *Sm = dataOp >> 31 & 1;
	 *Dm = EAOp >> 31 & 1;
	 *Rm = result >> 31 & 1;
	 break;
   }
}



/*
 * Find the size for instructions with different modes of operation
 * depending on the destination field of the opcode: 0 - Byte,
 * 1 - word,2 - long.
 */
findSize (int opMode) {
   switch (opMode & 3) {
      case 0: 
	 return Short;
	 break;

      case 1: 
	 return Word;
	 break;

      case 2: 
	 return Long;
	 break;
   }
}

/*
 * Do the normal add instruction. Decode the instruction fields to
 * determine the mode. Get the operands, add them, store the result.
 * Set the status bits.
 */
DoAdd (unsigned int opcode) {
#define add 0
#define addX 1

   int   operation, size, status, opMode, EAMode, EAReg,
         Sm, Dm, Rm, opReg, adrMode;
   int   temp, dataOp, EAOp, result, addrOp, addrEA;

   opMode = getMode (opcode, DEST);
   operation = add;
   if (opMode == 3) {
      adrMode = ADirect;
      size = Word;
   } else if (opMode == 7) {
      adrMode = ADirect;
      size = Long;
   } else {
      adrMode = DDirect;
      size = findSize (opMode);
   }
   opReg = getReg (opcode, DEST);
   EAMode = getMode (opcode, SOURCE);
   EAReg = getReg (opcode, SOURCE);
   if (opMode >= 4 && EAMode < 2)
      if (EAMode) {
	 opMode = 3;
	 adrMode = AIndDec;
	 EAMode = AIndDec;
	 operation = addX;
      }
   status = getData(adrMode, opReg, &dataOp, size, &addrOp);
   if (!status) {
      status = getData(EAMode, EAReg, &EAOp, size, &addrEA);
      dataOp = signExtend (dataOp, size);
      EAOp = signExtend (EAOp, size);
      if (!status) {
	 if (operation == addX)
	    result = dataOp + EAOp + (f_X & 1);
	 else
	    result = dataOp + EAOp;
	 if (opMode<4 || opMode==7)
	    status = putData (adrMode,opReg, result, size, addrOp);
	 else
	    status = putData (EAMode, EAReg, result, size, addrEA);
	 }

	 /* 
	  * Set the status register bits.
	  */
	 if (operation == addX)
	    f_Z = !result && f_Z;
	 else
	    f_Z = !result;
	 f_N = signExtend(result,size) < 0;
	 setSDRm (dataOp, EAOp, result, &Sm, &Dm, &Rm, size);
	 f_V = (Sm && Dm && !Rm || !Sm && !Dm && Rm);
	 f_X = f_C = (Sm && Dm || !Rm && Dm || Sm && !Rm);
   }
   return status;
}


doDiv (int opMode, int opReg, int EAMode, int EAReg) {
   int   status;
   int   dataOp, EAOp, result, addr, loResult, hiResult;

   if (EAMode == 1)
      return IllAddMode;
   status = getData(EAMode, EAReg, &EAOp, Word, &addr);
   if (!status)
      status = getData(DDirect, opReg, &dataOp, Long, &addr);
   if (!status) {
      if (!EAOp)		/* division by zero,put a TRAP in here */
	 return IllOpcode;
      if (opMode == 7)
	 dataOp = signExtend (dataOp, Word);
      if (EAOp >> 16 >= dataOp) {/* check for overflow before operation */
	 f_V = 1;
	 return NORMAL;
      }
      else
	 f_V = 0;
      hiResult = dataOp % EAOp;
      hiResult <<= 16;
      loResult = dataOp / EAOp;
      loResult &= 0x0000FFFF;
      result = hiResult + loResult;
      status = putData (DDirect, opReg, result, Long, addr);

	/* 
	 * Set status register bits
	 */
      f_C = 0;
      f_Z = !loResult;
      f_N = signExtend(loResult,Word) < 0;
   }
   return status;
}


/*
 * Check the 8 Opcode for Or/Div/SBCD instructions
 */
doOrDiv (unsigned int opcode) {
   int   status, opMode, operation, opReg, EAMode, EAReg, adrMode, size;
   int   temp, dataOp, EAOp, result, addrOp, addrEA;

   opMode = getMode (opcode, DEST);
   opReg = getReg (opcode, DEST);
   EAMode = getMode (opcode, SOURCE);
   EAReg = getReg (opcode, SOURCE);
   if (opMode == 3 || opMode == 7) {
      status = doDiv (opMode, opReg, EAMode, EAReg);
      return status;
   }
   else
      if (opMode >= 4 && EAMode < 2) {
	 status = doSBCD (opReg, EAMode, EAReg);
	 return status;
      } else {
	 size = findSize (opMode);
	 adrMode = DDirect;
	 if (opMode<3) {
	    temp = EAMode;
	    EAMode = adrMode;
	    adrMode = temp;
	 }
	 status = getData(adrMode, opReg, &dataOp, size, &addrOp);
	 if (!status) {
	    status = getData(EAMode, EAReg, &EAOp, size, &addrEA);
	    if (!status) {
	       dataOp = signExtend (dataOp, size);
	       EAOp = signExtend (EAOp, size);
	       result = dataOp | EAOp;
	       if (opMode < 4) {
		  if (EAMode == 1)
		     return IllAddMode;
	       } else {
		  if ((EAMode == SpecModes) && (EAReg > AbLong))
		     return IllAddMode;
	       }
	       status = putData (EAMode, EAReg, result, size, addrEA);
	       f_N = signExtend(result,size) < 0;
	       f_Z = !result;
	       f_V = 0;
	       f_C = 0;
	    }
	 }
      }
   return status;
}

/*
 * Handle subtraction of binary coded decimal numbers
 */
doSBCD (int opReg, int EAMode, int EAReg) {
   int   adrMode, srcMode, status;
   int   aResult, result, dataOp, EAOp, quot, rem, addr;

   if (EAMode)
      adrMode = srcMode = AIndDec;
   else
      adrMode = srcMode = DDirect;

   status = getData(adrMode, opReg, &dataOp, Short, &addr);
   if (!status) {
      quot = dataOp / 16;
      rem = dataOp % 16;
      dataOp = quot * 10 + rem;
      status = getData(srcMode, EAReg, &EAOp, Short, &addr);
      if (!status) {
	 quot = EAOp / 16;
	 rem = EAOp % 16;
	 EAOp = quot * 10 + rem;
	 aResult = abs (dataOp - EAOp - (f_X & 1));
	 result = aResult / 10 * 16;
	 result += (aResult % 10);
	 status = putData (adrMode, opReg, result, Short, addr);

	 f_Z = !result && f_Z;
	 f_C = f_X = EAOp + (f_X & 1) > dataOp;
      }
   }
   return status;
}


/*
 * Handle subtraction instructions
 */
doSubX (unsigned int opcode) {
#define sub 0
#define subX 1

   int   operation, size, status, opMode, EAMode, EAReg,
         Sm, Rm, Dm, opReg, adrMode;
   int   dataOp, EAOp, result, srcOP, destOP, addrOp, addrEA;

   opMode = getMode (opcode, DEST);
   operation = sub;
   if (opMode == 3) {
      adrMode = ADirect;
      size = Word;
   }
   else
      if (opMode == 7) {
	 adrMode = ADirect;
	 size = Long;
      }
      else {
	 adrMode = DDirect;
	 size = findSize (opMode);
      }
   opReg = getReg (opcode, DEST);
   EAMode = getMode (opcode, SOURCE);
   EAReg = getReg (opcode, SOURCE);
   if (opMode >= 4 && EAMode < 2)
      if (EAMode) {
	 opMode = 3;
	 adrMode = AIndDec;
	 EAMode = AIndDec;
	 operation = subX;
      }
   status = getData(adrMode, opReg, &dataOp, size, &addrOp);
   if (!status) {
      status = getData(EAMode, EAReg, &EAOp, size, &addrEA);
      dataOp = signExtend (dataOp, size);
      EAOp = signExtend (EAOp, size);
      destOP = dataOp;
      srcOP = EAOp;
      if (!status) {
	 if (operation == subX)
	    result = dataOp - EAOp - (f_X & 1);
	 else
	    if (opMode < 4)
	       result = dataOp - EAOp;
	    else {
	       destOP = EAOp;
	       srcOP = dataOp;
	       result = EAOp - dataOp;
	    }
	 if (opMode < 4)
	    status = putData (adrMode, opReg, result, size, addrOp);
	 else {
	    if ((EAMode == SpecModes) && (EAReg > AbLong))
	       return IllAddMode;
	    status = putData (EAMode, EAReg, result, size, addrEA);
	 }

	 /* 
	  * Set the status register bits.
	  */
	 if (operation == subX)
	    f_Z = !result && f_Z;
	 else
	    f_Z = !result;
	 f_N = signExtend(result,size) < 0;
	 setSDRm (srcOP, destOP, result, &Sm, &Dm, &Rm, size);
	 f_V = (!Sm && Dm && !Rm || Sm && !Dm && Rm);
	 f_X = f_C = (Sm && !Dm || Rm && !Dm || Sm && Rm);
      }
   }
   return status;
}


/*
 * Handle AND,MUL,ABCD,EXG instructions
 */
DoAnd (unsigned int opcode) {
   int   status, opMode, operation, opReg, EAMode, EAReg, adrMode, size;
   int   temp, dataOp, EAOp, result, addrOp, addrEA;

   opMode = getMode (opcode, DEST);
   opReg = getReg (opcode, DEST);
   EAMode = getMode (opcode, SOURCE);
   EAReg = getReg (opcode, SOURCE);
   if (opMode == 3 || opMode == 7) {
      status = doMul (opMode, opReg, EAMode, EAReg);
      return status;
   } else if (opMode == 4 && EAMode < 2) {
	 status = doABCD (opReg, EAMode, EAReg);
	 return status;
   } else if (opMode == 5 && EAMode < 2 || opMode == 6 && EAMode == 1) {
         status = doExg (opMode, opReg, EAMode, EAReg);
         return status;
   } else {
	    size = findSize (opMode);
	    adrMode = DDirect;
	    if (opMode<3) {
		temp = EAMode;
		EAMode = adrMode;
		adrMode = temp;
	    }
	    status = getData(adrMode, opReg, &dataOp, size, &addrOp);
	    if (!status) {
	       status = getData(EAMode, EAReg, &EAOp, size, &addrEA);
	       if (!status) {
		  dataOp = signExtend (dataOp, size);
		  EAOp = signExtend (EAOp, size);
		  result = dataOp & EAOp;
		  if (opMode < 4) {
		     if (EAMode == 1)
			return IllAddMode;
		  } else {
		     if ((EAMode == SpecModes) && (EAReg > AbLong))
			return IllAddMode;
		  }
		  status = putData (EAMode, EAReg, result, size, addrEA);
		  f_N = signExtend(result,size) < 0;
		  f_Z = !result;
		  f_V = 0;
		  f_C = 0;
	       }
	    }
	 }
   return status;
}


doMul (int opMode, int opReg, int EAMode, int EAReg) {
   int   status;
   int   dataOp, EAOp, result, addr;

   if (EAMode == 1)
	 return IllAddMode;
   else
	 status = getData(EAMode, EAReg, &EAOp, Word, &addr);
   if (!status)
      status = getData(DDirect, opReg, &dataOp, Word, &addr);
   if (!status) {
      if (opMode == 7) {
	 dataOp = signExtend (dataOp, Word);
	 EAOp = signExtend (EAOp, Word);
      }
      result = dataOp * EAOp;
      status = putData (DDirect, opReg, result, Long, addr);

      /* 
       * Set status register bits
       */
      f_C = 0;
      f_V = 0;
      f_Z = !result;
      f_N = result < 0;
   }
   return status;
}


/*
 * Handle addition of binary coded decimal numbers
 */
doABCD (int opReg, int EAMode, int EAReg) {
   int   adrMode, srcMode, status;
   int   quot, rem, aResult, result, dataOp, EAOp, addr;

   if (EAMode)
      adrMode = srcMode = AIndDec;
   else
      adrMode = srcMode = DDirect;

   status = getData(adrMode, opReg, &dataOp, Short, &addr);
   if (!status) {
      quot = dataOp / 16;
      rem = dataOp % 16;
      dataOp = quot * 10 + rem;
      status = getData(srcMode, EAReg, &EAOp, Short, &addr);
      if (!status) {
	 quot = EAOp / 16;
	 rem = EAOp % 16;
	 EAOp = quot * 10 + rem;
	 aResult = dataOp + EAOp + (f_X & 1);
	 if (aResult > 99)
	    f_X = f_C = 1;
	 else
	    f_X = f_C = 0;
	 result = aResult / 10 % 10 * 16;
	 result += (aResult % 10);
	 status = putData (adrMode, opReg, result, Short, addr);

	 f_Z = f_Z && !result;
      }
   }
   return status;
}


/*
 * Handle the register exchange instructions
 */
doExg (int opMode, int opReg, int EAMode, int EAReg) {
   int   srcMode, destMode, status;
   int   EAOp, dataOp, addr;

   if (opMode == 5) {
      if (EAMode)
	 srcMode = destMode = ADirect;
      else
	 srcMode = destMode = DDirect;
   }
   else {
      destMode = DDirect;
      srcMode = ADirect;
   }
   status = getData(destMode, opReg, &dataOp, Long, &addr);
   if (!status) {
      status = getData(srcMode, EAReg, &EAOp, Long, &addr);
      if (!status) {
	 status = putData (srcMode, opReg, dataOp, Long, addr);
	 if (!status)
	    status = putData (destMode, EAReg, EAOp, Long, addr);
      }
   }
   return status;
}

/*
 * Handle all the shift and rotate instructions
 */
doShftRot (unsigned int opcode) {
   int   status, opMode, opReg, EAMode, EAReg, size, adrMode, right;
   int   EAOp, addr;
   int   count, x;

   opMode = getMode (opcode, DEST);
   opReg = getReg (opcode, DEST);
   EAMode = getMode (opcode, SOURCE);
   EAReg = getReg (opcode, SOURCE);
   if (opMode == 3 || opMode == 7)
      return (doRotMem (opMode, opReg, EAMode, EAReg));
   else {
      right = !(opMode & 4);
      adrMode = DDirect;
      if (EAMode >= 4) {
	 getData(adrMode, opReg, &EAOp, Long, &addr);
	 count = EAOp;
      } else {
	 count = opReg;
	 if (!count)
	    count = 8;
      }
      size = findSize (opMode);
      getData(adrMode, EAReg, &EAOp, size, &addr);
      EAOp = signExtend (EAOp, size);
      switch (size) {
	 case Short: 
	    for (x = 0; x < count; x++)
	       ShftRotShort (&EAOp, right, EAMode);
	    break;
	 case Word: 
	    for (x = 0; x < count; x++)
	       ShftRotWord (&EAOp, right, EAMode);
	    break;
	 case Long: 
	    for (x = 0; x < count; x++)
	       ShftRotLong (&EAOp, right, EAMode);
	    break;
      }
      status = putData (adrMode, EAReg, EAOp, size, addr);
      f_Z = !EAOp;
      f_N = signExtend(EAOp,size) < 0;
   }
   return status;
}



/*
 * Handle rotating of memory
 */
doRotMem (int opMode, int opReg, int EAMode, int EAReg) {
   int   status, adrMode, right;
   int   EAOp, addr;

   adrMode = EAMode;
   right = opMode == 3;
   if ((EAMode == SpecModes) && (EAReg > AbLong))
      return IllAddMode;
   else {
      status = getData(adrMode, EAReg, &EAOp, Word, &addr);
      EAOp = signExtend (EAOp, Word);
      if (!status) {
	 ShftRotWord (&EAOp, right, opReg);
	 status = putData (adrMode, EAReg, EAOp, Word, addr);
	 f_Z = !EAOp;
	 f_N = EAOp & 0x00008000;
      }
   }
   return status;
}


ShftRotShort (int *data, int dir, int type) {
   char  tempOp;
   double   temp;

   tempOp = (char) * data;
   temp = (double) tempOp;
   if (dir) {			/* go to the right */
      *data = (int) floor (temp / 2);
      switch (type) {
	 case 0: 
	    break;
	 case 1: 
	    *data &= 0xFFFFFF7F;
	    break;
	 case 2: 
	    if (f_X)
	       *data |= 0x00000080;
	    else
	       *data &= 0xFFFFFF7F;
	    break;
	 case 3: 
	    if (tempOp & 0x01)
	       *data |= 0x00000080;
	    else
	       *data &= 0xFFFFFF7F;
      }
      f_C = tempOp & 0x01;
   }
   else {			/* we're going to the left */
      *data = tempOp * 2;
      switch (type) {
	 case 0: 
	 case 1: 
	    break;
	 case 2: 
	    if (f_X)
	       *data += 1;
	    break;
	 case 3: 
	    if (tempOp & 0x80)
	       *data += 1;
      }
      f_C = tempOp & 0x80;
   }
   if (type != 3)
      f_X = f_C;
   if (!type)
      f_V = (*data & 0x00000080) != (tempOp & 0x80);
}


ShftRotWord (int *data, int dir, int type) {
   int   tempOp;
   double   temp1, temp2;

   tempOp = *data;
   temp1 = (double) tempOp;
   if (dir) {
      *data = (int) floor (temp1 / 2.0);
      switch (type) {
	 case 0: 
	    break;
	 case 1: 
	    *data &= 0xFFFF7FFF;
	    break;
	 case 2: 
	    if (f_X)
	       *data |= 0x00008000;
	    else
	       *data &= 0xFFFF7FFF;
	    break;
	 case 3: 
	    if (tempOp & 0x0001)
	       *data |= 0x00008000;
	    else
	       *data &= 0xFFFF7FFF;
      }
      f_C = tempOp & 0x0001;
   }
   else {			/* we're going to the left */
      *data = tempOp * 2;
      switch (type) {
	 case 0: 
	 case 1: 
	    break;
	 case 2: 
	    if (f_X)
	       *data += 1;
	    break;
	 case 3: 
	    if (tempOp & 0x8000)
	       *data += 1;
      }
      f_C = tempOp & 0x8000;
   }
   if (type != 3)
      f_X = f_C;
   if (!type)
      f_V = (*data & 0x00008000) != (tempOp & 0x8000);
}


ShftRotLong (int *data, int dir, int type) {
   int   tempOp;
   double   temp;

   tempOp = *data;
   temp = (double) tempOp;
   if (dir) {
      *data = (int) floor (temp / 2);
      switch (type) {
	 case 0: 
	    break;
	 case 1: 
	    *data &= 0x7FFFFFFF;
	    break;
	 case 2: 
	    if (f_X)
	       *data |= 0x80000000;
	    else
	       *data &= 0x7FFFFFFF;
	    break;
	 case 3: 
	    if (tempOp & 0x00000001)
	       *data |= 0x80000000;
	    else
	       *data &= 0x7FFFFFFF;
      }
      f_C = tempOp & 0x00000001;
   }
   else {			/* we're going to the left */
      *data = tempOp * 2;
      switch (type) {
	 case 0: 
	 case 1: 
	    break;
	 case 2: 
	    if (f_X)
	       *data += 1;
	    break;
	 case 3: 
	    if (tempOp & 0x80000000)
	       *data += 1;
      }
      f_C = tempOp & 0x80000000;
   }
   if (type != 3)
      f_X = f_C;
   if (!type)
      f_V = (*data & 0x80000000) != (tempOp & 0x80000000);
}


/*
 * Handle a bunch of instuctions that start with 0xxx
 */
doBitImmed (unsigned int opcode) {
   int   EAMode, EAReg, opMode, opReg, size;


   opMode = getMode (opcode, DEST);
   opReg = getReg (opcode, DEST);
   EAMode = getMode (opcode, SOURCE);
   EAReg = getReg (opcode, SOURCE);
   if (!opReg && opMode < 3) {
      if (EAMode <= SpecModes && EAReg <= AbLong) {
	 size = findSize (opMode);
	 return (doOrI (EAMode, EAReg, size));
      } else if (opMode == 1 && EAMode == SpecModes && EAReg == 4)
	 return (doOrSR ());
      else if (opMode == 0 && EAMode == SpecModes && EAReg == 4)
	 return (doOrCCR ());
   }
   else if (opMode > 3 && EAMode != 1)
      return (doBitDyn (opMode, opReg, EAMode, EAReg));
   else if (opMode > 3 && EAMode == 1)
      return (doMoveP (opReg, opMode, EAReg));
   else if (opReg == 1) {
      if (EAMode <= SpecModes && EAReg <= AbLong) {
	  size = findSize (opMode);
	  return (doAndI (EAMode, EAReg, size));
      } else if (opMode == 1 && EAMode == SpecModes && EAReg == 4)
	  return (doAndSR ());
      else if (opMode == 0 && EAMode == SpecModes && EAReg == 4)
	  return (doAndCCR ());
   } else if (opReg == 2) {
      size = findSize (opMode);
      return (doSubI (EAMode, EAReg, size));
   } else if (opReg == 3) {
      size = findSize (opMode);
      return (doAddI (EAMode, EAReg, size));
   } else if (opReg == 4 && opMode < 4)
      return (doBitStat (opMode, EAMode, EAReg));
   else if (opReg == 5) {
      if (EAMode <= SpecModes && EAReg <= AbLong) {
	 size = findSize (opMode);
	 return (doEorI (EAMode, EAReg, size));
      } else if (opMode == 1 && EAMode == SpecModes && EAReg == 4)
	 return (doEorSR ());
      else if (opMode == 0 && EAMode == SpecModes && EAReg == 4)
	 return (doEorCCR ());
   } else if (opReg == 6) {
      size = findSize (opMode);
      return (doCmpI (EAMode, EAReg, size));
   } else return IllAddMode;
}


doOrI (int EAMode, int EAReg, int size) {
   int   status, sMode, dMode;
   int   EAOp, iOp, result, addr;

   sMode = SpecModes;
   dMode = EAMode;
   status = getData(sMode, Immed, &iOp, size, &addr);
   if (!status) {
      status = getData(dMode, EAReg, &EAOp, size, &addr);
      if (!status) {
	 iOp = signExtend (iOp, size);
	 EAOp = signExtend (EAOp, size);
	 result = iOp | EAOp;
	 status = putData (dMode, EAReg, result, size, addr);
      }
   }
   f_V = 0;
   f_C = 0;
   f_Z = !result;
   f_N = signExtend(result,size) < 0;
   return status;
}

doOrCCR () {
   int   status, sMode;
   int   iOp, addr;

   sMode = SpecModes;
   status = getData(sMode, Immed, &iOp, Short, &addr);
   if (!status) {
      f_C = (iOp & 1) || f_C;
      f_V = (iOp & 2) || f_V;
      f_Z = (iOp & 4) || f_Z;
      f_N = (iOp & 8) || f_N;
      f_X = (iOp & 16) || f_X;
   }
   return status;
}


doOrSR () {
   int   status, sMode;
   int   iOp, addr;

   sMode = SpecModes;
   if (Sbit) {
      status = getData(sMode, Immed, &iOp, Word, &addr);
      if (!status) {
	 f_C = (iOp & 1) || f_C;
	 f_V = (iOp & 2) || f_V;
	 f_Z = (iOp & 4) || f_Z;
	 f_N = (iOp & 8) || f_N;
	 f_X = (iOp & 16) || f_X;
	 I0Bit = (iOp & 0x0100) || I0Bit;
	 I1Bit = (iOp & 0x0200) || I1Bit;
	 I2Bit = (iOp & 0x0400) || I2Bit;
	 Tbit = (iOp & 0x8000) || Tbit;
      }
   }
   else
      return IllOpcode;		/* put a trap in here */
   return status;
}


doBitDyn (int opMode, int opReg, int EAMode, int EAReg) {
   int   sMode, dMode, size, status;
   int   EAOp, BitNum, mask, addr;

   sMode = DDirect;
   dMode = EAMode;
   if (EAMode == SpecModes && EAReg > AbLong)
      return IllAddMode;
   status = getData(sMode, opReg, &BitNum, Long, &addr);
   if (EAMode) {
      BitNum %= 8;
      size = Short;
   }
   else {
      BitNum %= 32;
      size = Long;
   }
   status = getData(dMode, EAReg, &EAOp, size, &addr);
   if (!status) {
      mask = (int) pow (2.0, (double) BitNum);
      f_Z = !(EAOp & ((int) pow (2.0, (double) BitNum)));
      switch (opMode & 3) {
	 case 0: 
	    break;
	 case 1: 
	    if (f_Z)
	       EAOp |= mask;
	    else
	       EAOp &= ~mask;
	    break;
	 case 2: 
	    EAOp &= ~mask;
	    break;
	 case 3: 
	    EAOp |= mask;
	    break;
      }
      status = putData (dMode, EAReg, EAOp, size, addr);
   }
   return status;
}



/*
 * Move peripheral data
 */
doMoveP (int opReg, int opMode, int EAReg) {
   int   size, status, adMode;
   int   dataOp, address, result, addr;

   if (opMode & 1)
      size = Long;
   else
      size = Word;
   adMode = DDirect;
   address = getMemVal (Word, pc);
   pc = pc + 2;
   if (pc >= MAX_MEM_SIZE)
      return (MemErr);
   address = signExtend (address, Word);
   address += reg[EAReg + 8];
   if (opMode > 5) {
      status = getData(adMode, opReg, &result, size, &addr);
      if (size == Word) {
	 status = setMemVal (address, Word, result & 0x0000FF00);
	 if (!status) {
	    address += 2;
	    status = setMemVal (address, Word, result << 8 & 0x0000FF00);
	 }
	 return status;
      }
      else {
	 if (address + 6 >= MAX_MEM_SIZE)
	    return (MemErr);
	 setMemVal (address, Word, result >> 16 & 0x0000FF00);
	 address += 2;
	 setMemVal (address, Word, result >> 8 & 0x0000FF00);
	 address += 2;
	 setMemVal (address, Word, result & 0x0000FF00);
	 address += 2;
	 setMemVal (address, Word, result << 8 & 0x0000FF00);
      }
   }
   else {
      if (opMode != 5) {
	 if (address + 2 >= MAX_MEM_SIZE)
	    return MemErr;
	 result = getMemVal (Word, address);
	 address = address + 2;
	 if (address & 1) {
	    result = (result & 0x000000FF) << 8;
	    result += (getMemVal (Word, address) & 0x000000FF);
	 }
	 else {
	    result &= 0x0000FF00;
	    result += ((getMemVal (Word, address) & 0x0000FF00) >> 8);
	 }
	 status = putData (DDirect, opReg, result, Word, addr);
      }
      else {
	 if (address + 6 >= MAX_MEM_SIZE)
	    return MemErr;
	 result = getMemVal (Word, address);
	 address += 2;
	 if (address & 1) {
	    result = (result & 0x000000FF) << 24;
	    result += ((getMemVal (Word, address) & 0x000000FF) << 16);
	    address += 2;
	    result += ((getMemVal (Word, address) & 0x000000FF) << 8);
	    address += 2;
	    result += (getMemVal (Word, address) & 0x000000FF);
	 }
	 status = putData (DDirect, opReg, result, Long, addr);
      }
   }
   return status;
}


doAndI (int EAMode, int EAReg, int size) {
   int   status, sMode, dMode;
   int   EAOp, iOp, result, addr;

   sMode = SpecModes;
   dMode = EAMode;
   status = getData(sMode, Immed, &iOp, size, &addr);
   if (!status) {
      status = getData(dMode, EAReg, &EAOp, size, &addr);
      if (!status) {
	 iOp = signExtend (iOp, size);
	 EAOp = signExtend (EAOp, size);
	 result = iOp & EAOp;
	 status = putData (dMode, EAReg, result, size, addr);
      }
   }
   f_V = 0;
   f_C = 0;
   f_Z = !result;
   f_N = signExtend(result,size) < 0;
   return status;
}

doAndCCR () {
   int   status, sMode;
   int   iOp, addr;

   sMode = SpecModes;
   status = getData(sMode, Immed, &iOp, Short, &addr);
   if (!status) {
      f_C = (iOp & 1) && f_C;
      f_V = (iOp & 2) && f_V;
      f_Z = (iOp & 4) && f_Z;
      f_N = (iOp & 8) && f_N;
      f_X = (iOp & 16) && f_X;
   }
   return status;
}


doAndSR () {
   int   status, sMode;
   int   iOp, addr;

   sMode = SpecModes;
   if (Sbit) {
      status = getData(sMode, Immed, &iOp, Word, &addr);
      if (!status) {
	 f_C = (iOp & 1) && f_C;
	 f_V = (iOp & 2) && f_V;
	 f_Z = (iOp & 4) && f_Z;
	 f_N = (iOp & 8) && f_N;
	 f_X = (iOp & 16) && f_X;
	 I0Bit = (iOp & 0x0100) && I0Bit;
	 I1Bit = (iOp & 0x0200) && I1Bit;
	 I2Bit = (iOp & 0x0400) && I2Bit;
	 Sbit = (iOp & 0x2000) && Sbit;
	 Tbit = (iOp & 0x8000) && Tbit;
      }
   }
   else
      return IllOpcode;		/* put a trap in here */
   return status;
}


doSubI (int EAMode, int EAReg, int size) {
   int   status, Sm, Dm, Rm, adrMode, dMode;
   int   EAOp, immedOp, result, addr;

   adrMode = SpecModes;
   dMode = EAMode;
   status = getData(adrMode, Immed, &immedOp, size, &addr);
   if (!status) {
      status = getData(EAMode, EAReg, &EAOp, size, &addr);
      if (!status) {
	 immedOp = signExtend (immedOp, size);
	 EAOp = signExtend (EAOp, size);
	 result = EAOp - immedOp;
	 status = putData (EAMode, EAReg, result, size, addr);
	 if (!status) {
	    setSDRm (immedOp, EAOp, result, &Sm, &Dm, &Rm, size);
	    f_V = (!Sm && Dm && !Rm || Sm && !Dm && Rm);
	    f_X = f_C = (Sm && !Dm || Rm && !Dm || Sm && Rm);
	    f_Z = !result;
	    f_N = signExtend(result,size) < 0;
	 }
      }
   }
   return status;
}


doAddI (int EAMode, int EAReg, int size) {
   int   status, Sm, Dm, Rm, adrMode, dMode;
   int   EAOp, immedOp, result, addr;
   adrMode = SpecModes;
   dMode = EAMode;
   status = getData(adrMode, Immed, &immedOp, size, &addr);
   if (!status) {
      status = getData(EAMode, EAReg, &EAOp, size, &addr);
      if (!status) {
	 immedOp = signExtend (immedOp, size);
	 EAOp = signExtend (EAOp, size);
	 result = EAOp + immedOp;
	 status = putData (EAMode, EAReg, result, size, addr);
	 if (!status) {
	    setSDRm (immedOp, EAOp, result, &Sm, &Dm, &Rm, size);
	    f_V = (Sm && Dm && !Rm || !Sm && !Dm && Rm);
	    f_X = f_C = (Sm && Dm || !Rm && Dm || Sm && !Rm);
	    f_Z = !result;
	    f_N = signExtend(result,size) < 0;
	 }
      }
   }
   return status;
}


doBitStat (int opMode, int EAMode, int EAReg) {
   int   status, adrMode, dMode, size;
   int   BitNum, EAOp, mask, addr;
   adrMode = SpecModes;
   dMode = EAMode;
   if (EAMode == SpecModes && EAReg > AbLong)
      return IllAddMode;
   status = getData(adrMode, Immed, &BitNum, Short, &addr);
   if (!status) {
      if (EAMode) {
	 BitNum %= 8;
	 size = Short;
      }
      else {
	 BitNum %= 32;
	 size = Long;
      }
      status = getData(dMode, EAReg, &EAOp, size, &addr);
      if (!status) {
	 mask = (int) pow (2.0, (double) BitNum);
	 f_Z = !(EAOp & ((int) pow (2.0, (double) BitNum)));
	 switch (opMode & 3) {
	    case 0: 
	       break;
	    case 1: 
	       if (f_Z)
		  EAOp |= mask;
	       else
		  EAOp &= ~mask;
	       break;
	    case 2: 
	       EAOp &= ~mask;
	       break;
	    case 3: 
	       EAOp |= mask;
	       break;
	 }
	 status = putData (dMode, EAReg, EAOp, size, addr);
      }
   }
   return status;
}


doEorI (int EAMode, int EAReg, int size) {
   int   status, sMode, dMode;
   int   EAOp, iOp, result, addr;
   sMode = SpecModes;
   dMode = EAMode;
   status = getData(sMode, Immed, &iOp, size, &addr);
   if (!status) {
      status = getData(dMode, EAReg, &EAOp, size, &addr);
      if (!status) {
	 iOp = signExtend (iOp, size);
	 EAOp = signExtend (EAOp, size);
	 result = iOp ^ EAOp;
	 status = putData (dMode, EAReg, result, size, addr);
      }
   }
   f_V = 0;
   f_C = 0;
   f_Z = !result;
   f_N = signExtend(result,size) < 0;
   return status;
}

doEorCCR () {
   int   status, sMode;
   int   iOp, addr;
   sMode = SpecModes;
   status = getData(sMode, Immed, &iOp, Short, &addr);
   if (!status) {
      f_C = (iOp & 1) && !f_C || !(iOp & 1) && f_C;
      f_V = (iOp & 2) && !f_V || !(iOp & 2) && f_V;
      f_Z = (iOp & 4) && !f_Z || !(iOp & 4) && f_Z;
      f_N = (iOp & 8) && !f_N || !(iOp & 8) && f_N;
      f_X = (iOp & 16) && !f_X || !(iOp & 16) && f_X;
   }
   return status;
}


doEorSR () {
   int   status, sMode;
   int   iOp, addr;
   sMode = SpecModes;
   if (Sbit) {
      status = getData(sMode, Immed, &iOp, Word, &addr);
      if (!status) {
	 f_C = (iOp & 1) && !f_C || !(iOp & 1) && f_C;
	 f_V = (iOp & 2) && !f_V || !(iOp & 2) && f_V;
	 f_Z = (iOp & 4) && !f_Z || !(iOp & 4) && f_Z;
	 f_N = (iOp & 8) && !f_N || !(iOp & 8) && f_N;
	 f_X = (iOp & 16) && !f_X || !(iOp & 16) && f_X;
	 I0Bit = (iOp & 0x0100) && !I0Bit || !(iOp & 0x0100) && I0Bit;
	 I1Bit = (iOp & 0x0200) && !I1Bit || !(iOp & 0x0200) && I1Bit;
	 I2Bit = (iOp & 0x0400) && !I2Bit || !(iOp & 0x0400) && I2Bit;
	 Sbit = (iOp & 0x2000) && !Sbit || !(iOp & 0x2000) && Sbit;
	 Tbit = (iOp & 0x8000) && !Tbit || !(iOp & 0x8000) && Tbit;
      }
   }
   else
      return IllOpcode;		/* put a trap in here */
   return status;
}



doCmpI (int EAMode, int EAReg, int size) {
   int   status, Sm, Dm, Rm, adrMode, dMode;
   int   EAOp, immedOp, result, addr;
   adrMode = SpecModes;
   dMode = EAMode;
   status = getData(adrMode, Immed, &immedOp, size, &addr);
   if (!status) {
      status = getData(EAMode, EAReg, &EAOp, size, &addr);
      if (!status) {
	 immedOp = signExtend (immedOp, size);
	 EAOp = signExtend (EAOp, size);
	 result = EAOp - immedOp;
	 setSDRm (immedOp, EAOp, result, &Sm, &Dm, &Rm, size);
	 f_V = (!Sm && Dm && !Rm || Sm && !Dm && Rm);
	 f_C = (Sm && !Dm || Rm && !Dm || Sm && Rm);
	 f_Z = !result;
	 f_N = signExtend(result,size) < 0;
      }
   }
   return status;
}



/*
 * Handle compare and exclusive or functions
 */
doCmp (unsigned int opcode) {
   int   status, opMode, opReg, EAMode, EAReg, size,
         Sm, Dm, Rm;
   int   dataOp, EAOp, result, addr;

   opMode = getMode (opcode, DEST);
   opReg = getReg (opcode, DEST);
   EAMode = getMode (opcode, SOURCE);
   EAReg = getReg (opcode, SOURCE);
   size = findSize (opMode);
   if (opMode == 3) {
      size = Word;
      opMode = ADirect;
   }
   else
      if (opMode == 7) {
	 size = Long;
	 opMode = ADirect;
      }
      else
	 if (opMode > 3 && EAMode == 1) {
	    opMode = AIndInc;
	    EAMode = AIndInc;
	 }
	 else
	    opMode = DDirect;
   status = getData(opMode, opReg, &dataOp, size, &addr);
   if (!status) {
      status = getData(EAMode, EAReg, &EAOp, size, &addr);
      if (!status) {
	 dataOp = signExtend (dataOp, size);
	 EAOp = signExtend (EAOp, size);
	 if (opMode > 3 && EAMode != 1) {
	    result = EAOp ^ dataOp;
	    status = putData (EAMode, EAReg, result, size, addr);
	    f_V = 0;
	    f_C = 0;
	 }
	 else {
	    result = dataOp - EAOp;
	    setSDRm (EAOp, dataOp, result, &Sm, &Dm, &Rm, size);
	    f_V = (!Sm && Dm && !Rm || Sm && !Dm && Rm);
	    f_C = (Sm && !Dm || Rm && !Dm || Sm && Rm);
	 }
	 f_N = signExtend(result,size) < 0;
	 f_Z = !result;
      }
   }
   return status;
}



/*
 * Do the move quick instruction
 */
doMoveq (unsigned int opcode) {
   int   status, opMode, opReg, EAMode, EAReg, size;
   int   dataOp, EAOp, result, addr;

   opReg = getReg (opcode, DEST);
   result = opcode & 0x00FF;
   result = signExtend (result, Short);
   status = putData (DDirect, opReg, result, Long, addr);
   f_V = 0;
   f_Z = !result;
   f_C = 0;
   f_N = result < 0;
   return status;
}


/*
 * Handle a bunch of miscellaneous instructions
 */
doMisc (unsigned int opcode) {
   int   opMode, opReg, EAMode, EAReg, size;

   opMode = getMode (opcode, DEST);
   opReg = getReg (opcode, DEST);
   EAMode = getMode (opcode, SOURCE);
   EAReg = getReg (opcode, SOURCE);
   size = findSize (opMode);
   if (opMode < 3 && opReg == 0)
      return (doNegX (EAMode, EAReg, size));
   else if (opMode == 3 && opReg == 0)
      return (doIll ());
   else if (opMode == 6)
      return (doChk (opReg, EAMode, EAReg));
   else if (opMode == 7)
      return (doLea (opReg, EAMode, EAReg));
   else if (opMode < 3 && opReg == 1) {
      size = findSize (opMode);
      return (doClr (EAMode, EAReg, size));
   } else if (opMode == 3 && opReg == 1)
      return (doIll ());
   else if (opMode < 3 && opReg == 2) {
      size = findSize (opMode);
      return (doNeg (EAMode, EAReg, size));
   } else if (opMode == 3 && opReg == 2)
      return (doMovCCR (EAMode, EAReg));
   else if (opMode < 3 && opReg == 3) {
      size = findSize (opMode);
      return (doNot (EAMode, EAReg, size));
   } else if (opMode == 3 && opReg == 3)
      return (doMovSR (EAMode, EAReg));
   else if (opMode == 0 && opReg == 4)
      return (doNBCD (EAMode, EAReg));
   else if (opMode == 1 && opReg == 4 && EAMode == 0)
      return (doSwap (EAReg));
   else if (opMode == 1 && opReg == 4 && EAMode == 1)
      return (doIll ());
   else if (opMode == 1 && opReg == 4 && EAMode >= 2)
      return (doPEA (EAMode, EAReg));
   else if ((opMode == 2 || opMode == 3) && opReg == 4 && EAMode == 0)
      return (doExt (opMode, EAReg));
   else if ((opMode == 2 || opMode == 3) && opReg == 4 && EAMode > 1)
      return (doMOVEMR (opMode, EAMode, EAReg));
   else if (opMode < 3 && opReg == 5) {
      size = findSize (opMode);
      return (doTst (EAMode, EAReg, size));
   } else if (opMode==3 && opReg==5 && EAMode<=SpecModes && EAReg<=AbLong)
      return (doTas (EAMode, EAReg));
   else if (opMode == 3 && opReg == 5 && EAMode == SpecModes && EAReg == 4)
      return (doIll ());
   else if (opReg == 6 && (opMode == 2 || opMode == 3))
      return (doMOVEA (opMode, EAMode, EAReg));
   else if (opReg == 7 && opMode == 1 && EAMode < 2)
      return (doTRAP (EAMode, EAReg));
   else if (opReg == 7 && opMode == 1 && EAMode == 2)
      return (doLnk (EAReg));
   else if (opReg == 7 && opMode == 1 && EAMode == 3)
      return (doUnlk (EAReg));
   else if (opReg == 7 && opMode == 1 && EAMode == 4)
      return (doMovToUSP (EAReg));
   else if (opReg == 7 && opMode == 1 && EAMode == 5)
      return (doMovFromUSP (EAReg));
   else if (opReg == 7 && opMode == 1 && EAMode == 6 && EAReg == 0)
      return (doReset ());
   else if (opReg == 7 && opMode == 1 && EAMode == 6 && EAReg == 1)
      return NORMAL;
   else if (opReg == 7 && opMode == 1 && EAMode == 6 && EAReg == 2)
      return (doStop ());
   else if (opReg == 7 && opMode == 1 && EAMode == 6 && EAReg == 3)
      return (doRTE ());
   else if (opReg == 7 && opMode == 1 && EAMode == 6 && EAReg == 4)
      return (doIll ());
   else if (opReg == 7 && opMode == 1 && EAMode == 6 && EAReg == 5)
      return (doRTS ());
   else if (opReg == 7 && opMode == 1 && EAMode == 6 && EAReg == 6)
      return (doTrapV ());
   else if (opReg == 7 && opMode == 1 && EAMode == 6 && EAReg == 7)
      return (doRTR ());
   else if (opReg == 7 && opMode == 2)
      return (doJSR (EAMode, EAReg));
   else if (opReg == 7 && opMode == 3)
      return (doJMP (EAMode, EAReg));
}


doNegX (int EAMode, int EAReg, int size) {
   int   Sm, Dm, Rm, status;
   int   EAOp, result, addr;

   status = getData(EAMode, EAReg, &EAOp, size, &addr);
   if (!status) {
      EAOp = signExtend (EAOp, size);
      result = 0 - EAOp - (f_X & 1);
      status = putData (EAMode, EAReg, result, size, addr);
      setSDRm (0, EAOp, result, &Sm, &Dm, &Rm, size);
      f_V = (!Sm && Dm && !Rm || Sm && !Dm && Rm);
      f_X = f_C = (Sm && !Dm || Rm && !Dm || Sm && Rm);
      f_N = signExtend(result,size) < 0;
      f_Z = !result;
   }
   return status;
}


doChk (int opReg, int EAMode, int EAReg) {
   int   status, adrMode, dMode;
   int   EAOp, dOp, addr;

   adrMode = EAMode;
   dMode = DDirect;
   status = getData(adrMode, EAReg, &EAOp, Word, &addr);
   if (!status) {
      status = getData(dMode, opReg, &dOp, Word, &addr);
      EAOp = signExtend (EAOp, Word);
      dOp = signExtend (dOp, Word);
      if (dOp < 0)
	 f_N = TRUE;		/* * put a CHK exception here * */
      else
	 if (dOp > EAOp)
	    f_N = FALSE;	/* * put a CHK exception here * */
   }
   return status;
}



doLea (int opReg, int EAMode, int EAReg) {
   int   status, adrMode;
   int   EAOp, dOp, addr;
   adrMode = EAMode;
   status = getData(adrMode, EAReg, &EAOp, Long, &addr);
   if (!status) {
      status = putData (ADirect, opReg, addr, Long, addr);
   }
   return status;
}


doClr (int EAMode, int EAReg, int size) {
   int   status, adrMode;
   int   addr, dumm;
   adrMode = EAMode;
   status = getData(adrMode, EAReg, &dumm, size, &addr);
   if (!status) {
      status = putData (adrMode, EAReg, 0, size, addr);
      f_V = f_N = f_C = FALSE;
      f_Z = TRUE;
   }
   return status;
}


doNeg (int EAMode, int EAReg, int size) {
   int   Sm, Dm, Rm, status;
   int   EAOp, result, addr;
   status = getData(EAMode, EAReg, &EAOp, size, &addr);
   if (!status) {
      EAOp = signExtend (EAOp, size);
      result = 0 - EAOp;
      status = putData (EAMode, EAReg, result, size, addr);
      setSDRm (0, EAOp, result, &Sm, &Dm, &Rm, size);
      f_V = (!Sm && Dm && !Rm || Sm && !Dm && Rm);
      f_X = f_C = (Sm && !Dm || Rm && !Dm || Sm && Rm);
      f_N = signExtend(result,size) < 0;
      f_Z = !result;
   }
   return status;
}


doMovCCR (int EAMode, int EAReg) {
   int   status, adrMode;
   int   op, addr;
   adrMode = EAMode;
   status = getData(adrMode, EAReg, &op, Word, &addr);
   if (!status) {
      f_C = op & 1;
      f_V = op & 2;
      f_Z = op & 4;
      f_N = op & 8;
      f_X = op & 16;
   }
   return status;
}



doNot (int EAMode, int EAReg, int size) {
   int   status, adrMode;
   int   result, op, addr;
   adrMode = EAMode;
   status = getData(adrMode, EAReg, &op, size, &addr);
   if (!status) {
      op = signExtend (op, size);
      result = ~op;
      putData (adrMode, EAReg, result, size, addr);
      f_V = f_C = FALSE;
      f_Z = !result;
      f_N = signExtend(result,size) < 0;
   }
   return status;
}


doMovSR (int EAMode, int EAReg) {
   int   status, adrMode;
   int   op, addr;
   adrMode = EAMode;
   if (!Sbit)
      return IllOpcode;		/* put a trap here */
   status = getData(adrMode, EAReg, &op, Word, &addr);
   if (!status) {
      f_C = op & 1;
      f_V = op & 2;
      f_Z = op & 4;
      f_N = op & 8;
      f_X = op & 16;
      I0Bit = op & 0x0100;
      I1Bit = op & 0x0200;
      I2Bit = op & 0x0400;
      Sbit = op & 0x2000;
      Tbit = op & 0x8000;
   }
   return status;
}



doNBCD (int EAMode, int EAReg) {
   int   adrMode, status;
   int   quot, rem, op, aResult, result, addr;

   adrMode = EAMode;
   status = getData(adrMode, EAReg, &op, Short, &addr);
   if (!status) {
      quot = op / 16;
      rem = op % 16;
      op = quot * 10 + rem;
      aResult = abs (0 - op - (f_X & 1));
      result = aResult / 10 * 16;
      result += (aResult % 10);
      status = putData (adrMode, EAReg, result, Short, addr);
      f_Z = !result && f_Z;
      f_C = f_X = op || f_X;
   }
   return status;
}


doSwap (int EAReg) {
   int   status, adrMode;
   int   op, temp, addr;
   adrMode = DDirect;
   status = getData(adrMode, EAReg, &op, Long, &addr);
   temp = op;
   temp >>= 16;
   op <<= 16;
   op += temp;
   status = putData (adrMode, EAReg, op, Long, addr);
   f_V = f_C = FALSE;
   f_N = op < 0;
   f_Z = !op;
   return status;
}


doPEA (int EAMode, int EAReg) {
   int   status, adrMode;
   int   dum, addr;
   adrMode = EAMode;
   status = getData(adrMode, EAReg, &dum, Long, &addr);
   if (!status) {
      reg[A7] -= 4;
      Sbit ? (reg[SSP] = reg[A7]) : (reg[USP] = reg[A7]);
      setMemVal (reg[A7], Long, addr);
   }
   return status;
}


doExt (int opMode, int EAReg) {
   int   status, adrMode;
   int   op, addr;
   adrMode = DDirect;
   status = getData(adrMode, EAReg, &op, Word, &addr);
   if (opMode == 2) {
      op = signExtend (op, Short);
      status = putData (adrMode, EAReg, op, Word, addr);
   }
   else {
      op = signExtend (op, Word);
      status = putData (adrMode, EAReg, op, Long, addr);
   }
   f_V = f_C = FALSE;
   f_N = op < 0;
   f_Z = !op;
   return status;
}



doMOVEMR (int opMode, int EAMode, int EAReg) {
   int   status, adrMode, regMask, cnt, mult, size;
   int   result, addr, regList, dumm;
   if (pc + 2 >= MAX_MEM_SIZE)
      return MemErr;
   regList = getMemVal (Word, pc);
   pc += 2;
   adrMode = EAMode;
   size = (opMode == 2) ? Word : Long;
   status = getData(adrMode, EAReg, &result, size, &addr);
   if (status)
      return status;
   adrMode = DDirect;
   if (size == Word) {
      if (EAMode != 4) {
	 for (cnt = 0, mult = 1; cnt < 16; cnt++, mult *= 2)
	    if (regList & mult) {
	       status = setMemVal (addr, Word, reg[cnt]);
	       addr += 2;
	       if (status)
		  break;
	    }
      } else {
	 EAReg += 8;
	 reg[EAReg] += 2;
	 for (cnt = 15, mult = 1; cnt >= 0; cnt--, mult *= 2)
	    if (regList & mult) {
	       reg[EAReg] -= 2;
	       status = setMemVal (reg[EAReg], Word, reg[cnt]);
	       if (status)
		  break;
	    }
      }
   } else {
      if (EAMode != 4) {
	 for (cnt = 0, mult = 1; cnt < 16; cnt++, mult *= 2)
	    if (regList & mult) {
	       status = setMemVal (addr, Long, reg[cnt]);
	       addr += 4;
	       if (status)
		  break;
	    }
      } else {
	 EAReg += 8;
	 reg[EAReg] += 4;
	 for (cnt = 15, mult = 1; cnt >= 0; cnt--, mult *= 2)
	    if (regList & mult) {
	       reg[EAReg] -= 4;
	       status = setMemVal (reg[EAReg], Long, reg[cnt]);
	       if (status)
		  break;
	    }
      }
   }
   return status;
}



doTst (int EAMode, int EAReg, int size) {
   int   status, adrMode;
   int   op, addr;
   adrMode = EAMode;
   status = getData(adrMode, EAReg, &op, size, &addr);
   if (!status) {
      op = signExtend (op, size);
      f_N = op < 0;
      f_Z = !op;
   }
   return status;
}


doTas (int EAMode, int EAReg) {
   int   status, adrMode;
   int   op, addr;
   adrMode = EAMode;
   status = getData(adrMode, EAReg, &op, Short, &addr);
   if (!status) {
      op = signExtend (op, Short);
      f_N = op < 0;
      f_Z = !op;
      op |= 0x80;
      status = putData (adrMode, EAReg, op, Short, addr);
      f_V = f_C = FALSE;
   }
   return status;
}


bldSR () {
   int   op;
   f_C ? (op = 1) : (op = 0);
   if (f_V)
      op += 2;
   if (f_Z)
      op += 4;
   if (f_N)
      op += 8;
   if (f_X)
      op += 16;
   if (I0Bit)
      op += 0x0100;
   if (I1Bit)
      op += 0x0200;
   if (I2Bit)
      op += 0x0400;
   if (Sbit)
      op += 0x2000;
   if (Tbit)
      op += 0x8000;
   return op;
}

/*
 * Simulate an illegal instruction exception
 */
doIll () {
   reg[A7] -= 4;
   setMemVal (reg[A7], Long, pc);
   reg[A7] -= 2;
   setMemVal (reg[A7], Word, bldSR ());
   pc = 0x00000010;
   Sbit = TRUE;
   Tbit = FALSE;
   return IllOpcode;
}


doMOVEA (int opMode, int EAMode, int EAReg) {
   int   status, adrMode, regMask, cnt, mult, size;
   int   result, addr, regList, dumm;

   if (pc + 2 >= MAX_MEM_SIZE)
      return MemErr;
   regList = getMemVal (Word, pc);
   pc += 2;
   adrMode = EAMode;
   size = (opMode == 2) ? Word : Long;
   status = getData(adrMode, EAReg, &result, size, &addr);
   if (status)
      return status;
   adrMode = DDirect;
   if (size == Word) {
      if (EAMode != 3) {
	 for (cnt = 0, mult = 1; cnt < 16; cnt++, mult *= 2)
	    if (regList & mult) {
	       if (addr + 2 >= MAX_MEM_SIZE)
		  return MemErr;
	       result = getMemVal (Word, addr);
	       result = signExtend (result, Word);
	       reg[cnt] = result;
	       addr += 2;
	    }
      } else {
	 EAReg += 8;
	 reg[EAReg] -= 2;
	 for (cnt = 0, mult = 1; cnt < 16; cnt++, mult *= 2)
	    if (regList & mult) {
	       if (reg[EAReg] + 2 >= MAX_MEM_SIZE)
		  return MemErr;
	       result = getMemVal (Word, reg[EAReg]);
	       result = signExtend (result, Word);
	       reg[cnt] = result;
	       reg[EAReg] += 2;
	    }
      }
   }
   else {
      if (EAMode != 3) {
	 for (cnt = 0, mult = 1; cnt < 16; cnt++, mult *= 2)
	    if (regList & mult) {
	       if (addr + 4 >= MAX_MEM_SIZE)
		  return MemErr;
	       result = getMemVal (Long, addr);
	       reg[cnt] = result;
	       addr += 4;
	    }
      }
      else {
	 EAReg += 8;
	 reg[EAReg] -= 4;
	 for (cnt = 0, mult = 1; cnt < 16; cnt++, mult *= 2)
	    if (regList & mult) {
	       if (reg[EAReg] + 4 >= MAX_MEM_SIZE)
		  return MemErr;
	       result = getMemVal (Long, reg[EAReg]);
	       reg[cnt] = result;
	       reg[EAReg] += 4;
	    }
      }
   }
   return status;
}



doTRAP (int EAMode, int EAReg) {
   reg[A7] -= 4;
   setMemVal (reg[A7], Long, pc);
   Sbit = TRUE;
   reg[A7] -= 2;
   setMemVal (reg[A7], Word, bldSR ());
   pc = 32 + EAReg;
   pc += (EAMode * 8);
   pc *= 4;
   return TrapCode;
}



doLnk (int EAReg) {
   int   status;
   int   op;

   reg[A7] -= 4;
   status = setMemVal (reg[A7], Long, reg[EAReg + 8]);
   reg[EAReg + 8] = reg[A7];
   op = getMemVal (Word, pc);
   pc += 2;
   op = signExtend (op, Word);
   reg[A7] += op;
   return status;
}


doUnlk (int EAReg) {
   reg[A7] = reg[EAReg + 8];
   reg[EAReg + 8] = getMemVal (Long, reg[A7]);
   reg[A7] += 4;
   return NORMAL;
}



doMovToUSP (int EAReg) {
   if (Sbit) {
      reg[USP] = reg[EAReg + 8];
      return NORMAL;
   }
   else
      return TrapCode;
}



doMovFromUSP (int EAReg) {
   if (Sbit) {
      reg[EAReg + 8] = reg[USP];
      return NORMAL;
   }
   else
      return TrapCode;
}


doReset () {
   if (Sbit)
      return NORMAL;
   else
      return TrapCode;
}

doStop () {
   int   op;

   if (Sbit) {
      op = getMemVal (Word, pc);
      pc += 2;
      f_C = op & 1;
      f_V = op & 2;
      f_Z = op & 4;
      f_N = op & 8;
      f_X = op & 16;
      I0Bit = op & 0x0100;
      I1Bit = op & 0x0200;
      I2Bit = op & 0x0400;
      Sbit = op & 0x2000;
      Tbit = op & 0x8000;
      return STOP;
   }
   else
      return TrapCode;
}


doRTE () {
   int   op;

   if (Sbit) {
      op = getMemVal (Word, reg[A7]);
      reg[A7] += 2;
      f_C = op & 1;
      f_V = op & 2;
      f_Z = op & 4;
      f_N = op & 8;
      f_X = op & 16;
      I0Bit = op & 0x0100;
      I1Bit = op & 0x0200;
      I2Bit = op & 0x0400;
      Sbit = op & 0x2000;
      Tbit = op & 0x8000;
      pc = getMemVal (Long, reg[A7]);
      reg[A7] += 4;
      return NORMAL;
   }
   else
      return TrapCode;
}


doRTS () {
   pc = getMemVal (Long, reg[A7]);
   reg[A7] += 4;
   return NORMAL;
}


doTrapV () {
   if (f_V)
      return (doTRAP (0, -25));
   else
      return NORMAL;
}

doRTR () {
   int   op;

   op = getMemVal (Word, reg[A7]);
   reg[A7] += 2;
   f_C = op & 1;
   f_V = op & 2;
   f_Z = op & 4;
   f_N = op & 8;
   f_X = op & 16;
   pc = getMemVal (Long, reg[A7]);
   reg[A7] += 4;
   return NORMAL;
}


doJSR (int EAMode, int EAReg) {
   int   status, adrMode,size;
   int   addr, dumm;

   reg[A7] -= 4;
   size = Word;
   if (EAMode==7 && EAReg==1)
   	status = setMemVal (reg[A7], size=Long, pc+4);
    else
	status = setMemVal(reg[A7],Long,signExtend(pc+2,Word));
   if (!status) {
      adrMode = EAMode;
      status = getData(adrMode, EAReg, &dumm,size, &addr);
      pc = addr;
   }
   return status;
}



doJMP (int EAMode, int EAReg) {
   int   status, adrMode;
   int   addr, dumm;

   adrMode = EAMode;
   status = getData(adrMode, EAReg, &dumm, Long, &addr);
   pc = addr;
   return status;
}



doDBcc (unsigned int opcode) {
   int   opMode, opReg, EAMode, EAReg, size, cond;
   int   op, cntr;

   opMode = getMode (opcode, DEST);
   opReg = getReg (opcode, DEST);
   EAMode = getMode (opcode, SOURCE);
   EAReg = getReg (opcode, SOURCE);
   size = findSize (opMode);
   if (opMode < 3)
      return (doAddQ (opReg, EAMode, EAReg, size));
   else
      if (opMode > 3 && opMode < 7)
	 return (doSubQ (opReg, EAMode, EAReg, size));
      else {
	 cond = (opReg << 1);
	 if (opMode == 7)
	    cond++;
	 if (EAMode != 1)
	    return (doScc (cond, EAMode, EAReg));
	 else {
	    op = signExtend (getMemVal (Word, pc), Word);
	    if (isCond (cond)) {
	       pc += 2;
	       return NORMAL;
	    }
	    else {
	       cntr = getRegVal (EAReg, Word);
	       cntr--;
	       setRegVal (EAReg, Word, cntr);
	       if (cntr != -1)
		  pc += op;
	       else
		  pc += 2;
	    }
	 }
      }
   return NORMAL;
}


doAddQ (int opReg, int EAMode, int EAReg, int size) {
   int   status, adrMode, Sm, Dm, Rm;
   int   op, addr, result;

   adrMode = EAMode;
   if (!opReg)
      opReg = 8;
   status = getData(adrMode, EAReg, &op, size, &addr);
   if (!status) {
      op = signExtend (op, size);
      result = op + opReg;
      status = putData (adrMode, EAReg, result, size, addr);
      if (EAMode != 1) {
	 setSDRm (opReg, op, result, &Sm, &Dm, &Rm, size);
	 f_V = (Sm && Dm && !Rm || !Sm && !Dm && Rm);
	 f_X = f_C = (Sm && Dm || !Rm && Dm || Sm && !Rm);
	 f_N = signExtend(result,size) < 0;
	 f_Z = !result;
      }
   }
   return status;
}


doSubQ (int opReg, int EAMode, int EAReg, int size) {
   int   status, adrMode, Sm, Dm, Rm;
   int   op, addr, result;

   adrMode = EAMode;
   if (!opReg)
      opReg = 8;
   status = getData(adrMode, EAReg, &op, size, &addr);
   if (!status) {
      op = signExtend (op, size);
      result = op - opReg;
      status = putData (adrMode, EAReg, result, size, addr);
      if (EAMode != 1) {
	 setSDRm (opReg, op, result, &Sm, &Dm, &Rm, size);
	 f_V = (!Sm && Dm && !Rm || Sm && !Dm && Rm);
	 f_X = f_C = (Sm && !Dm || Rm && !Dm || Sm && Rm);
	 f_N = signExtend(result,size) < 0;
	 f_Z = !result;
      }
   }
   return status;
}


doScc (int cond, int EAMode, int EAReg) {
   int   status, adrMode;
   int   op, addr;

   adrMode = EAMode;
   status = getData(adrMode, EAReg, &op, Short, &addr);
   if (!status) {
      if (isCond (cond))
	 status = putData (adrMode, EAReg, 255, Short, addr);
      else
	 status = putData (adrMode, EAReg, 0, Short, addr);
   }
   return status;
}


isCond (cond) {
   switch (cond) {
      case 4: 
	 return ! f_C;
	 break;
      case 5: 
	 return f_C;
	 break;
      case 7: 
	 return f_Z;
	 break;
      case 1: 
	 return FALSE;
	 break;
      case 12: 
	 return (f_N && f_V || !f_N && !f_V);
	 break;
      case 14: 
	 return (f_N && f_V && !f_Z || !f_N && !f_V && !f_Z);
	 break;
      case 2: 
	 return (!f_C && !f_Z);
	 break;
      case 15: 
	 return (f_Z || f_N && !f_V || !f_N && f_V);
	 break;
      case 3: 
	 return (f_C || f_Z);
	 break;
      case 13: 
	 return (f_N && !f_V || !f_N && f_V);
	 break;
      case 11: 
	 return f_N;
	 break;
      case 6: 
	 return ! f_Z;
	 break;
      case 10: 
	 return ! f_N;
	 break;
      case 0: 
	 return TRUE;
	 break;
      case 8: 
	 return ! f_V;
	 break;
      case 9: 
	 return f_V;
	 break;
   }
}



doBSR (unsigned int opcode) {
   int   opMode, opReg, EAMode, EAReg, size, cond, status;
   int   op, disp;

   opMode = getMode (opcode, DEST);
   opReg = getReg (opcode, DEST);
   EAMode = getMode (opcode, SOURCE);
   EAReg = getReg (opcode, SOURCE);
   cond = (opReg << 1);
   if (opMode & 4)
      cond++;
   disp = (opMode & 3) << 6;
   disp += (EAMode << 3);
   disp += EAReg;
   disp = signExtend (disp, Short);
   if (cond > 1)
      return (doBcc (cond, disp));
   else
      if (!cond)
	 return (doBRA (disp));
      else {
	 reg[A7] -= 4;
	 status = setMemVal (reg[A7], Long, pc + 2);
	 if (!disp) {
	    op = getMemVal (Word, pc);
	    op = signExtend (op, Word);
	    pc += op;
	 }
	 else
	    pc += disp;
      }
   return status;
}


doBcc (int cond, int disp) {
   int   op;

   if (isCond (cond)) {
      if (!disp) {
	 op = getMemVal (Word, pc);
	 op = signExtend (op, Word);
	 pc += op;
      }
      else
	 pc += disp;
   }
   else if (!disp)
      pc += 2;
   return NORMAL;
}


doBRA (int disp) {
   int   op;

   if (!disp) {
      op = getMemVal (Word, pc);
      op = signExtend (op, Word);
      pc += op;
   }
   else
      pc += disp;
   return NORMAL;
}

doInt () {
   reg[A7] -= 4;
   setMemVal (reg[A7], Long, pc);
   Sbit = TRUE;
   reg[A7] -= 2;
   setMemVal (reg[A7], Word, bldSR ());
   Tbit = FALSE;
   I0Bit = I2Bit = TRUE;
   I1Bit = FALSE;
   pc = 0x00000074;
   reg[SSP] = reg[A7];
   return NORMAL;
}



/*
 * Check for breakpoint at current pc location. If break has already
 * been acknowledged at that location continue.  Get an instruction
 * opcode and do initial decoding of instructions according to bits
 * 15 - 12 of the opcode.
 */
exec_instruction () {
   unsigned int   opcode;
   int   status,
         opType;
   static int  atBreak;

   status = NORMAL;
   if (pc >= MAX_MEM_SIZE)
      return (MemErr);
   if (SI_mem_fetch_bp (pc))
      if (!atBreak) {
	 atBreak = TRUE;
	 return BrkPt;
      }
      else
	 atBreak = FALSE;
   opcode = SI_mem_fetch (pc++);
   opcode = opcode << 8;
   opcode += SI_mem_fetch (pc++);
   opType = opcode >> 12;
   switch (opType) {
      case BitImmed: 
	 status = doBitImmed (opcode);
	 break;

      case MOVEB: 
	 status = doMove (Short, opcode);
	 break;

      case MOVEL: 
	 status = doMove (Long, opcode);
	 break;

      case MOVEW: 
	 status = doMove (Word, opcode);
	 break;

      case MISC: 
	 status = doMisc (opcode);
	 break;

      case DBcc: 
	 status = doDBcc (opcode);
	 break;

      case BSR: 
	 status = doBSR (opcode);
	 break;

      case MOVEQ: 
	 status = doMoveq (opcode);
	 break;

      case ORDIV: 
	 status = doOrDiv (opcode);
	 break;

      case SUBX: 
	 status = doSubX (opcode);
	 break;

      case CMP: 
	 status = doCmp (opcode);
	 break;

      case ANDMUL: 
	 status = DoAnd (opcode);
	 break;

      case ADDX: 
	 status = DoAdd (opcode);
	 break;

      case SHFTROT: 
	 status = doShftRot (opcode);
	 break;

      default: 
	 return (doIll ());
	 break;
   }
   reg[SSP] = reg[A7];
   return status;
}
