/* SPIM S20 MIPS Cycle Level simulator.
   Definitions for the SPIM S20 Cycle Level Simulator (SPIM-CL).
   Copyright (C) 1991-1992 by Anne Rogers (amr@cs.princeton.edu) and
   Scott Rosenberg (scottr@cs.princeton.edu)
   ALL RIGHTS RESERVED.

   SPIM-CL is distributed under the following conditions:

     You may make copies of SPIM-CL for your own use and modify those copies.

     All copies of SPIM-CL must retain our names and copyright notice.

     You may not sell SPIM-CL or distributed SPIM-CL in conjunction with a
     commerical product or service without the expressed written consent of
     Anne Rogers.

   THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
   IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
   WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
   PURPOSE.
*/

/* $Header: /home/primost/larus/Software/SPIM/RCS/cl-cycle.c,v 1.6 1993/05/17 20:46:00 larus Exp $
*/

/* Cycle Level Simulator -- Anne Rogers, 4 July 91 */


#ifdef mips
#define _IEEE 1
#include <nan.h>
#else
#define NaN(X) 0
#endif

#include <math.h>
#include <stdio.h>
#include <X11/Intrinsic.h>
#include <X11/StringDefs.h>

#include "spim.h"
#include "inst.h"
#include "reg.h"
#include "mem.h"
#include "read-aout.h"
#include "spim-utils.h"
#include "sym-tbl.h"
#include "y.tab.h"
#include "mips-syscall.h"

#include "cl-mem.h"
#include "cl-cache.h"
#include "cl-cycle.h"
#include "cl-tlb.h"
#include "cl-except.h"


#define END_OF_CYCLE 	{						\
			(*steps)--;					\
			if (display) print_pipeline ();			\
			continue;					\
			}

/* Imported functions: */
#ifdef __STDC__
long atol (const char *);
#else
long atol ();
#endif


/* Exported Variables: */

int cycle_level, cycle_running, cycle_steps;
int EX_bp_reg, MEM_bp_reg, CP_bp_reg, CP_bp_cc, CP_bp_z;
reg_word EX_bp_val, MEM_bp_val, CP_bp_val;
int FP_add_cnt, FP_mul_cnt, FP_div_cnt;
PIPE_STAGE alu[5] = {NULL, NULL, NULL, NULL, NULL};
PIPE_STAGE fpa[6] = {NULL, NULL, NULL, NULL, NULL, NULL};


/* Local functions: */

#ifdef __STDC__
static int cycle_spim (int *steps, int display);
static int can_issue (short int oc);
static int process_ID (PIPE_STAGE ps, int *stall, int mult_div_busy);
static int process_EX (PIPE_STAGE ps, struct mult_div_unit *pMDU);
static int process_MEM (PIPE_STAGE ps, MEM_SYSTEM mem_sys);
static int process_WB (PIPE_STAGE ps);
static int process_f_ex1 (PIPE_STAGE ps);
static int process_f_ex2 (PIPE_STAGE ps);
static int process_f_fwb (PIPE_STAGE ps);
static void init_stage_pool (void);
static PIPE_STAGE stage_alloc (void);
static int stage_dealloc (PIPE_STAGE ps);
static int pipe_dealloc (int stage, PIPE_STAGE alu[], PIPE_STAGE fpa[]);
static void long_multiply (reg_word v1, reg_word v2, reg_word *hi, reg_word
			   *lo);
#else
static int cycle_spim ();
static int can_issue ();
static int process_ID ();
static int process_EX ();
static int process_MEM ();
static int process_WB ();
static int process_f_ex1 ();
static int process_f_ex2 ();
static int process_f_fwb ();
static void init_stage_pool ();
static PIPE_STAGE stage_alloc ();
static int stage_dealloc ();
static int pipe_dealloc ();
static void long_multiply ();
#endif


/* local counters for collecting statistics */
static int mem_stall_count;
static int total_mem_ops;

static int bd_slot;
struct mult_div_unit MDU;



/* function cl_run_program:
 * responsible for calling cycle_spim; completes when <steps> cycles have
 * been completed or when exception processing indicates that execution has
 * paused or ended.
 */

#ifdef __STDC__
void
cl_run_program (mem_addr addr, int steps, int display)
#else
void
cl_run_program (addr, steps, display)
  mem_addr addr;
  int steps, display;
#endif
{
  PC = addr;
  cycle_steps = steps;
  cycle_running = 1;

  while (cycle_steps > 0)
    {
      if (cycle_spim (&cycle_steps, display)) {

	switch (process_excpt ()) {

	  /* exception processed ok, continue execution */
	case 0:
	  cycle_init ();
	  break;

	  /* exception processed ok, but stop execution */
	case 1:
	  cycle_init ();
	  return;

	  /* bad exception, signal, or exit; reinit for next time */
	case -1:
	  PC = 0;
	  nPC = 0;
	  cycle_init ();
	  kill_prog_fds ();
	  cycle_running = 0;

	  return;
	}
      }
    }
}


/* for initialization of counting stuff and between runs of program */

#ifdef __STDC__
void
cl_initialize_world (int run)
#else
void
cl_initialize_world (run)
     int run;
#endif
{
  initialize_registers ();
  initialize_run_stack (0, 0);
  initialize_catch_signals ();
  if (cycle_level) {
    if (run) 
      initialize_prog_fds ();
    initialize_sighandlers ();
    initialize_excpt_counts ();
    cycle_init ();
    mdu_and_fp_init ();
    tlb_init();
    cache_init (mem_system, DATA_CACHE);
    cache_init (mem_system, INST_CACHE);
  }
}


/* cleanup after exceptions */

#ifdef __STDC__
void
cycle_init (void)
#else
void
cycle_init ()
#endif
{
  R[0] = 0;
  EPC = 0;
  Cause = 0;
  bd_slot = FALSE;
  bp_clear ();
  pipe_dealloc (WB+1, alu, fpa);

  program_break = ((program_break / 32) + 1) * 32;
}


/* should be called when floating point and mdu unit are starting fresh */

#ifdef __STDC__
void
mdu_and_fp_init (void)
#else
void
mdu_and_fp_init ()
#endif
{
  MDU.count = 0;
  FP_add_cnt = 0;
  FP_mul_cnt = 0;
  FP_div_cnt = 0;
  FP_reg_present = 0xffffffff;
  HI_present = 1;
  LO_present = 1;
}




/* function cycle_spim:
 * responsible for stepping through code until an exception occurs; returns
 * 1 upon finding an exception, 0 upon completing number of steps.
 */

#ifdef __STDC__
static int
cycle_spim (int *steps, int display)
#else
static int
cycle_spim (steps, display)
     int *steps, display;
#endif
{
  PIPE_STAGE ps_ptr, fp_ptr, fp_prev;
  mem_addr bus_req;
  int id_stall = FALSE, mem_stall = FALSE, cmiss = 0;

  while (*steps > 0) {

    bus_req = bus_service (mem_system);

    /* increment Random register each cycle */
    Random = (((Random >> 8) < 63) ? ((Random >> 8) + 1) : 8) << 8;
    cmiss = 0;

    /* Service mult/div unit */
    if (MDU.count == 1) {
      MDU.count = 0;
      HI_present = 1;
      HI = MDU.hi_val;
      LO_present = 1;
      LO = MDU.lo_val;
    }
    else if (MDU.count > 1)
      MDU.count--;

    /* service fpa unit available counts */
    FP_add_cnt = ((FP_add_cnt == 0) ? 0 : FP_add_cnt - 1);
    FP_mul_cnt = ((FP_mul_cnt == 0) ? 0 : FP_mul_cnt - 1);
    FP_div_cnt = ((FP_div_cnt == 0) ? 0 : FP_div_cnt - 1);


    /* Floating Point Write Back */
    fp_ptr = fpa[FPA_FWB];
    while (fp_ptr != NULL) {
      PIPE_STAGE tmp_ptr;

      process_f_fwb(fp_ptr);
      tmp_ptr = fp_ptr->next;
      stage_dealloc(fp_ptr);
      fp_ptr = tmp_ptr;
    }

    fpa[FPA_FWB] = NULL;



    /* Write Back Stage */
    ps_ptr = alu[WB];
    if (ps_ptr != NULL) {

      if (EXCPT (ps_ptr) != 0) {
	/* exception is about to be handled, set up registers */
	Cause = EXCPT (ps_ptr);
	if (DSLOT(ps_ptr)) Cause |= 0x80000000;
	else Cause &= 0x7fffffff;
	EPC = STAGE_PC(ps_ptr) - (DSLOT (ps_ptr) ? BYTES_PER_WORD : 0);
	return (1);
      }

      process_WB(ps_ptr);

      /* maintain invariant */
      R[0] = 0;
      stage_dealloc(ps_ptr);
      alu[WB] = NULL;
    }



    /* FPA WB stage -- there maybe up to 4 entries in this stage
     * one for each of the functional units */
    /* If an instruction gets this far, then all previous instructions
     * will complete without causing an exception */
    fp_ptr = fpa[FPA_EX3];
    fp_prev = NULL;
    while (fp_ptr != NULL) {
      PIPE_STAGE tmp_ptr;

      process_f_ex2(fp_ptr);
      /* This one is ready to go to wb if count is 0 */
      if (Count (fp_ptr) == 0) {

	/* fix up list */
	if (fp_prev == NULL)
	  fpa[FPA_EX3] = fp_ptr->next;
	else
	  fp_prev->next = fp_ptr->next;

	tmp_ptr = fp_ptr->next;
	fp_ptr->next = fpa[FPA_FWB];
	fpa[FPA_FWB] = fp_ptr;
	fp_ptr = tmp_ptr;
      }
      else { /* Count > 0 */
	fp_prev = fp_ptr;
	fp_ptr = fp_ptr->next;
      }

    }



    /* FPA MEM stage */
    /* Any FP exception will have already been signaled. */
    fp_ptr = fpa[FPA_EX2];
    if (fp_ptr != NULL) {
      process_f_ex2(fp_ptr);
      fp_ptr->next = fpa[FPA_EX3];
      fpa[FPA_EX3] = fp_ptr;
      fpa[FPA_EX2] = NULL;
    }



    /* MEM STALL stage */
    /* Cannot get to MEM STALL if an instruction earlier
     * in the pipeline causes an exception. */
    ps_ptr = alu[MEM];
    if ((ps_ptr != NULL) && STAGE (ps_ptr) == MEM_STALL) {
      if (RNUM (ps_ptr) == bus_req) {
	if (((OPCODE (ps_ptr->inst) == Y_LWC1_OP) ||
	     (OPCODE (ps_ptr->inst) == Y_MTC1_OP))) {
	  ps_ptr->next = fpa[FPA_EX3];
	  fpa[FPA_EX3] = ps_ptr;
	  alu[MEM] = NULL;
	}
	else {
	  STAGE (ps_ptr) = WB;
	  alu[WB] = ps_ptr;
	  alu[MEM] = NULL;
	}
	mem_stall = FALSE;
      }
      else mem_stall = TRUE;
    }



    /* MEM Stage */
    ps_ptr = alu[MEM];
    if ((ps_ptr != NULL) && (STAGE (ps_ptr) == MEM)) {

      /* use SWC2 to print memory stats */
      if ((EXCPT(ps_ptr) == 0) && (OPCODE(ps_ptr->inst) == Y_SWC2_OP)) {
	write_output (message_out, "memory system counts:\n");
	write_output (message_out, "\t%d stalls, %d total memory ops.\n",
		      mem_stall_count, total_mem_ops);
	stat_print();
	fflush(stdout);
      }

      else if (EXCPT (ps_ptr) == 0)
	cmiss = process_MEM(ps_ptr, mem_system);

      if (EXCPT (ps_ptr) != 0) {
	STAGE (ps_ptr) = WB;
	alu[WB] = ps_ptr;
	alu[MEM] = NULL;
	pipe_dealloc(MEM, alu, fpa);
	END_OF_CYCLE
      }

      else if (cmiss == CACHE_MISS) {
	STAGE (ps_ptr) = MEM_STALL;
	mem_stall = TRUE;
      }

      /* If this is a floating point load or a MTC1, move it to
       * the floating point pipeline */
      else if ((OPCODE (ps_ptr->inst) == Y_LWC1_OP) ||
	       (OPCODE (ps_ptr->inst) == Y_MTC1_OP)) {
	ps_ptr->next = fpa[FPA_EX3];
	fpa[FPA_EX3] = ps_ptr;
	alu[MEM] = NULL;
      }

      else {
	STAGE (ps_ptr) = WB;
	alu[WB] = ps_ptr;
	alu[MEM] = NULL;
      }
  }




    /* FPA EX Stage */
    fp_ptr = fpa[FPA_EX1];
    if (fp_ptr != NULL) {
      process_f_ex1(fp_ptr);
      fpa[FPA_EX2] = fp_ptr;
      fpa[FPA_EX1] = NULL;
      if (EXCPT (fp_ptr) != 0) {
	pipe_dealloc(FPA_EX1, alu, fpa);
	END_OF_CYCLE
      }
    }



    /* EX Stage */
    ps_ptr = alu[EX];
    if ((ps_ptr != NULL) && (! mem_stall)) {

      if (EXCPT (ps_ptr) == 0)
	process_EX(ps_ptr, &(MDU));

      STAGE (ps_ptr) = MEM;
      alu[MEM] = ps_ptr;
      alu[EX] = NULL;

      if (EXCPT (ps_ptr) != 0) {
	pipe_dealloc(EX, alu, fpa);
	END_OF_CYCLE
      }
    }



    /* ID Stage */

    ps_ptr = alu[ID];
    if ((ps_ptr != NULL) && (STAGE(ps_ptr) == ID) && !mem_stall) {
      id_stall = FALSE;

      DSLOT(ps_ptr) = bd_slot;
      if (EXCPT (ps_ptr) == 0) {
	process_ID (ps_ptr, &id_stall, MDU.count);
	if (!id_stall)
	  bd_slot = ((DSLOT(ps_ptr) == TRUE) ? FALSE :
		      (IS_BRANCH (OPCODE(ps_ptr->inst)) ? TRUE : FALSE));
      }

      if (!id_stall) {
	STAGE (ps_ptr) = EX;
	/* If it's a floating point op move it to the floating point
	 * pipeline */
	if ((EXCPT(ps_ptr) == 0) && (is_fp_op(OPCODE (ps_ptr->inst))))
	  fpa[FPA_EX1] = ps_ptr;
	else
	  alu[EX] = ps_ptr;
	alu[ID] = NULL;
      }

      if (EXCPT (ps_ptr) != 0) {
	pipe_dealloc(ID, alu, fpa);
	END_OF_CYCLE
      }
    }




    /* IF STALL stage */
    ps_ptr = alu[IF];
    if ((ps_ptr != NULL) && (STAGE (ps_ptr) == IF_STALL)) {
      if (RNUM (ps_ptr) == bus_req)
	if (mem_stall || id_stall) {
	  STAGE(ps_ptr) = IF;
	  END_OF_CYCLE
	}
	else {
	  STAGE (ps_ptr) = ID;
	  alu[ID] = ps_ptr;
	  alu[IF] = NULL;
	  PC = (nPC ? nPC : PC + BYTES_PER_WORD);
	}
      else END_OF_CYCLE
    }


    /* IF Stage */
    else if (ps_ptr != NULL && (STAGE(ps_ptr) == IF))  {
      CL_READ_MEM_INST(mem_system, ps_ptr->inst, STAGE_PC(ps_ptr),
		       PADDR(ps_ptr), cmiss, EXCPT(ps_ptr), RNUM(ps_ptr))

      /* reinsert a breakpoint (occurs only after break excpt was caught) */
      if (STAGE_PC(ps_ptr) == breakpoint_reinsert) {
	add_breakpoint (STAGE_PC(ps_ptr));
	breakpoint_reinsert = 0;
      }

      /* if exception, must be tlb, read instruction for viewing purposes */
      if (EXCPT(ps_ptr) != 0) {
	if (! (mem_stall || id_stall)) {
	  alu[ID] = ps_ptr;
	  alu[IF] = NULL;
	  STAGE (ps_ptr) = ID;
	  PC = (nPC ? nPC : PC + BYTES_PER_WORD);
	}
	END_OF_CYCLE
      }

      else if (cmiss == CACHE_MISS) {
	STAGE (ps_ptr) = IF_STALL;
	END_OF_CYCLE
	}

      else if (mem_stall || id_stall)
	END_OF_CYCLE

      else {
	alu[ID] = ps_ptr;
	alu[IF] = NULL;
	STAGE (ps_ptr) = ID;
	PC = (nPC ? nPC : PC + BYTES_PER_WORD);
      }
    }


    /* if we got this far, get next instruction into IF stage */
    alu[IF] = stage_alloc();
    STAGE (alu[IF]) = IF;
    STAGE_PC (alu[IF]) = PC;
    /* do a dummy read just so we can see the instruction in the pipeline */
    READ_MEM_INST (alu[IF]->inst, PC);

    END_OF_CYCLE

  }
  return 0;
}


#ifdef __STDC__
static int
can_issue (short int oc)
#else
static int
can_issue (oc)
     short oc;
#endif
{
  /* Can't issue anything if the adder is busy or about to be busy */
  if ((FP_add_cnt > 0) || (FP_mul_cnt == 1) || ((FP_div_cnt <= 3) && (FP_div_cnt > 0)))
    return(0);

  switch (oc)
    {
    case Y_ADD_S_OP:
    case Y_ADD_D_OP:
    case Y_CVT_S_D_OP:
    case Y_CVT_W_D_OP:
    case Y_CVT_W_S_OP:
    case Y_SUB_S_OP:
    case Y_SUB_D_OP:
      /* Need adder for 2 cycles.  First one is already known
	 to be free.  As long as mul_cnt > 2 or = 0, and div_cnt > 4 or = 0
	 ok */
      return (((FP_mul_cnt == 0) || (FP_mul_cnt > 2)) &&
	      ((FP_div_cnt == 0) || (FP_div_cnt > 4)));
      break;

    case Y_CVT_D_W_OP:
    case Y_CVT_S_W_OP:
      /* Need adder for 3 cycles.  First one is already known
	 to be free.  As long as mul_cnt > 3, and div_cnt > 5
	 ok */
      return (((FP_mul_cnt == 0) || (FP_mul_cnt > 2)) &&
	      ((FP_div_cnt == 0) || (FP_div_cnt > 4)));

    case Y_DIV_S_OP:
    case Y_DIV_D_OP:
      /* Need adder for 3 cycles in > 8 cycles.  If there is
 	 an outstanding multiply it must be finished before then. */
      return (FP_div_cnt == 0); break;

    case Y_MUL_S_OP:
      /* Need adder for 1 cycle in 2 cycles.  */
      return ((FP_mul_cnt == 0) &&
	      ((FP_div_cnt > 2) || (FP_div_cnt == 0)));

      case Y_MUL_D_OP:
      /* Need adder for 1 cycle in 3 cycles */
      return ((FP_mul_cnt == 0) && ((FP_div_cnt > 3) || (FP_div_cnt == 0)));
      break;

    default:
      return (1);
      break;
    }
}


#define stall2(op, r1, r2) 						\
  (!(can_issue((op)) && is_present((r1)) && is_present ((r2))))

#define stall3(op, r1, r2, r3) 						\
  (!(can_issue((op)) && is_present((r1)) && is_present ((r2)) 		\
     && is_present((r3))))




/* simulate ID stage */
/* must process WB stage before this one to make sure the right values
   are available */

/* Branches in the delay slot are treated as Nops.  */
#ifdef __STDC__
static int
process_ID (PIPE_STAGE ps, int *stall, int mult_div_busy)
#else
static int
process_ID (ps, stall, mult_div_busy)
  PIPE_STAGE ps;
  int *stall, mult_div_busy;
#endif
{
  instruction *inst;
  mem_addr tmp_PC;
  int excpt = -1;

  inst = ps->inst;
  tmp_PC = PC + BYTES_PER_WORD;

  switch (OPCODE (inst))
    {
    case Y_ADD_OP:
      Operand1 (ps) = read_R_reg(RS (inst));
      Operand2 (ps) = read_R_reg(RT (inst));
      break;


    case Y_ADDI_OP:
      Operand1 (ps) = read_R_reg(RS (inst));
      Operand2 (ps) = IMM (inst);

    case Y_ADDIU_OP:
      Operand1 (ps) = read_R_reg(RS (inst));
      Operand2 (ps) = IMM (inst);
      break;

    case Y_ADDU_OP:
      Operand1 (ps) = read_R_reg(RS (inst));
      Operand2 (ps) = read_R_reg(RT (inst));
      break;

    case Y_AND_OP:
      Operand1 (ps) = read_R_reg(RS (inst));
      Operand2 (ps) = read_R_reg(RT (inst));
      break;

    case Y_ANDI_OP:
      Operand1 (ps) = read_R_reg(RS (inst));
      Operand2 (ps) = IMM (inst);
      break;

    case Y_BC0F_OP:
    case Y_BC2F_OP:
    case Y_BC3F_OP:
      if (!DSLOT(ps))
	/* arg to COP_Available divided by two to find which coprocessor, */
	/* see opcode table in y.tab.c */
	if (!COP_Available( (OPCODE (inst) - Y_BC0F_OP)/2 ))
	  CL_RAISE_EXCEPTION(CPU_EXCPT, (OPCODE(inst)-Y_BC0F_OP)/2, EXCPT (ps))
	else if (CpCond[(OPCODE (inst) - Y_BC0F_OP)/2] == 0)
	  tmp_PC = PC + (SIGN_EX (IOFFSET (inst)) << 2);
      break;

    case Y_BC1F_OP:
      if (!DSLOT(ps))
	if (!COP_Available( (OPCODE (inst) - Y_BC0F_OP)/2 ))
	  CL_RAISE_EXCEPTION(CPU_EXCPT, (OPCODE(inst)-Y_BC0F_OP)/2, EXCPT(ps))
	else if (FpCond == 0)
	  tmp_PC = PC + (SIGN_EX (IOFFSET (inst)) << 2);
      break;


    case Y_BC0T_OP:
    case Y_BC2T_OP:
    case Y_BC3T_OP:
      if (!DSLOT(ps)) {
	if (!COP_Available( (OPCODE (inst) - Y_BC0T_OP)/2 ))
	  CL_RAISE_EXCEPTION(CPU_EXCPT, (OPCODE(inst)-Y_BC0T_OP)/2, EXCPT(ps))
	else if (CpCond[(OPCODE (inst) - Y_BC0T_OP)/2] != 0)
	  tmp_PC = PC + (SIGN_EX (IOFFSET (inst)) << 2);
      }
      break;

    case Y_BC1T_OP:
      if (!DSLOT(ps)) {
	if (!COP_Available( (OPCODE (inst) - Y_BC0T_OP)/2 ))
	  CL_RAISE_EXCEPTION(CPU_EXCPT, (OPCODE(inst)-Y_BC0T_OP)/2, EXCPT(ps))
	else if (FpCond != 0)
	  tmp_PC = PC + (SIGN_EX (IOFFSET (inst)) << 2);
      }
      break;

    case Y_BEQ_OP:
      if (!DSLOT(ps) &&  (read_R_reg(RS (inst)) == read_R_reg(RT (inst))))
	  tmp_PC = PC + (SIGN_EX (IOFFSET (inst)) << 2);
      break;

    case Y_BGEZ_OP:
      if (!DSLOT(ps) && (SIGN_BIT (read_R_reg(RS (inst))) == 0))
	tmp_PC = PC + (SIGN_EX (IOFFSET (inst)) << 2);
      break;

    case Y_BGEZAL_OP:
      if (!DSLOT(ps) && (SIGN_BIT (read_R_reg(RS (inst))) == 0))
	tmp_PC = PC + (SIGN_EX (IOFFSET (inst)) << 2);
      break;

    case Y_BGTZ_OP:
      if ((!DSLOT(ps)) &&
	  (read_R_reg(RS (inst)) != 0 && SIGN_BIT (read_R_reg(RS (inst))) == 0))
	tmp_PC = PC + (SIGN_EX (IOFFSET (inst)) << 2);
      break;

    case Y_BLEZ_OP:
      if ((!DSLOT(ps)) &&
	  (read_R_reg(RS (inst)) == 0 || SIGN_BIT (read_R_reg(RS (inst))) != 0))
	tmp_PC = PC + (SIGN_EX (IOFFSET (inst)) << 2);
      break;

    case Y_BLTZ_OP:
      if ((!DSLOT(ps)) &&
	  (SIGN_BIT (read_R_reg(RS (inst))) != 0))
	tmp_PC = PC + (SIGN_EX (IOFFSET (inst)) << 2);
      break;

    case Y_BLTZAL_OP:
      if ((!DSLOT(ps)) &&
	  (SIGN_BIT (read_R_reg(RS (inst))) != 0))
	tmp_PC = PC + (SIGN_EX (IOFFSET (inst)) << 2);
      break;

    case Y_BNE_OP:
      if ((!DSLOT(ps)) &&
	  (read_R_reg(RS (inst)) != read_R_reg(RT (inst))))
	tmp_PC = PC + (SIGN_EX (IOFFSET (inst)) << 2);
      break;

    case Y_BREAK_OP:
      CL_RAISE_EXCEPTION(BKPT_EXCPT, 0, EXCPT(ps));
      break;

    case Y_CFC0_OP:
    case Y_CFC2_OP:
    case Y_CFC3_OP:
      if (!COP_Available(OPCODE (inst) - Y_CFC0_OP))
	CL_RAISE_EXCEPTION(CPU_EXCPT, (OPCODE (inst) - Y_CFC0_OP) , EXCPT(ps));
      Operand1 (ps) = read_CP_reg((OPCODE (inst) - Y_CFC0_OP), RD (inst), 0);
      break;

    case Y_COP0_OP:
    case Y_COP1_OP:
    case Y_COP2_OP:
    case Y_COP3_OP:
      if (!COP_Available(OPCODE (inst) - Y_COP0_OP))
	CL_RAISE_EXCEPTION(CPU_EXCPT, (OPCODE (inst) - Y_COP0_OP) , EXCPT(ps));
      Operand2 (ps) = read_R_reg(RT (inst));
      break;

    case Y_CTC0_OP:
    case Y_CTC2_OP:
    case Y_CTC3_OP:
      if (!COP_Available(OPCODE (inst) - Y_CTC0_OP))
	CL_RAISE_EXCEPTION(CPU_EXCPT, (OPCODE (inst) - Y_CTC0_OP) , EXCPT(ps));
      Operand2 (ps) = read_R_reg(RT (inst));
      break;

    case Y_DIV_OP:
    case Y_DIVU_OP:
      if (mult_div_busy)
	*stall = 1;
      else {
	Operand1 (ps) = read_R_reg(RS (inst));
	Operand2 (ps) = read_R_reg(RT (inst));
      }
      break;

    case Y_J_OP:
      if (!DSLOT (ps))
	tmp_PC = ((PC & 0xf0000000) | (TARGET (inst) & 0x03ffffff) << 2);
      break;

    case Y_JAL_OP:
      if (!DSLOT (ps))
	tmp_PC = ((PC & 0xf0000000) | ((TARGET (inst) & 0x03ffffff) << 2));
      break;

    case Y_JALR_OP:
    case Y_JR_OP:
      if (!DSLOT (ps))
	tmp_PC = read_R_reg(RS (inst));
      break;

    case Y_LB_OP:
    case Y_LBU_OP:
    case Y_LH_OP:
    case Y_LHU_OP:
    case Y_LW_OP:
    case Y_LWL_OP:
    case Y_LWR_OP:
      Operand1 (ps) = read_R_reg(BASE (inst));
      Operand2 (ps) = IOFFSET (inst);
      break;

    case Y_LWC0_OP:
    case Y_LWC2_OP:
    case Y_LWC3_OP:
      if (!COP_Available(OPCODE (inst) - Y_LWC0_OP))
	CL_RAISE_EXCEPTION(CPU_EXCPT, (OPCODE (inst) - Y_LWC0_OP) , EXCPT(ps));
      Operand1 (ps) = read_R_reg(BASE (inst));
      Operand2 (ps) = IOFFSET (inst);
      break;

    case Y_LUI_OP:
      Operand2 (ps) = IMM (inst);
      break;

    case Y_MFC0_OP:
    case Y_MFC2_OP:
    case Y_MFC3_OP:
      if (!COP_Available(OPCODE (inst) - Y_MFC0_OP))
	CL_RAISE_EXCEPTION(CPU_EXCPT, (OPCODE (inst) - Y_MFC0_OP), EXCPT(ps));
      Operand1 (ps) = read_CP_reg((OPCODE (inst) - Y_MFC0_OP), RD (inst), 1);
      break;

    case Y_MFHI_OP:
      if (HI_present)
	Operand1 (ps) = HI;
      else
	*stall = 1;
      break;

    case Y_MFLO_OP:
      if (LO_present)
	Operand1 (ps) = LO;
      else
	*stall = 1;
      break;

    case Y_MTC0_OP:
    case Y_MTC2_OP:
    case Y_MTC3_OP:
      if (!COP_Available(OPCODE (inst) - Y_MTC0_OP))
	CL_RAISE_EXCEPTION(CPU_EXCPT, (OPCODE (inst) - Y_MTC0_OP), EXCPT(ps));
      Operand2 (ps) = read_R_reg(RT (inst));
      break;

    case Y_MTC1_OP:
      if (!COP_Available(OPCODE (inst) - Y_MTC0_OP))
	CL_RAISE_EXCEPTION(CPU_EXCPT, (OPCODE (inst) - Y_MTC0_OP), EXCPT(ps));
      Operand2 (ps) = read_R_reg(RT (inst));
      *stall = ! (is_present(RD (inst)));
      clr_single_present(RD (inst));
      break;


    case Y_MTHI_OP:
    case Y_MTLO_OP:
      Operand1 (ps) = read_R_reg(RS (inst));
      break;

    case Y_MULT_OP:
    case Y_MULTU_OP:
      if (mult_div_busy)
	*stall = 1;
      else {
	Operand1 (ps) = read_R_reg(RS (inst));
	Operand2 (ps) = read_R_reg(RT (inst));
      }
      break;

    case Y_NOR_OP:
    case Y_OR_OP:
      Operand1 (ps) = read_R_reg(RS (inst));
      Operand2 (ps) = read_R_reg(RT (inst));
      break;

    case Y_ORI_OP:
      Operand1 (ps) = read_R_reg(RS (inst));
      Operand2 (ps) = IMM (inst);
      break;


    case Y_RFE_OP:
      if (!COP_Available(0))
	CL_RAISE_EXCEPTION(CPU_EXCPT, 0x0 , EXCPT(ps));
      Operand1 (ps) = (Status_Reg & 0xfffffff0);
      Operand2 (ps) = ((Status_Reg & 0x3c) >> 2);
      break;

    case Y_SB_OP:
    case Y_SH_OP:
      Operand1 (ps) = read_R_reg(RT (inst));
      Operand2 (ps) = read_R_reg(BASE (inst));
      Operand3 (ps) = IOFFSET (inst);
      break;

    case Y_SLL_OP:
      Operand2 (ps) = read_R_reg(RT (inst));
      break;

    case Y_SLLV_OP:
      Operand1 (ps) = read_R_reg(RS (inst));
      Operand2 (ps) =  0x1f;

    case Y_SLT_OP:
      Operand1 (ps) = read_R_reg(RS (inst));
      Operand2 (ps) = read_R_reg(RT (inst));
      break;

    case Y_SLTI_OP:
    case Y_SLTIU_OP:
      Operand1 (ps) = read_R_reg(RS (inst));
      Operand2 (ps) = IMM (inst);
      break;


    case Y_SLTU_OP:
      Operand1 (ps) = read_R_reg(RS (inst));
      Operand2 (ps) = read_R_reg(RT (inst));
      break;

    case Y_SRA_OP:
      Operand2 (ps) = read_R_reg(RT (inst));
      break;

    case Y_SRAV_OP:
      Operand1 (ps) = read_R_reg(RS (inst));
      Operand2 (ps) = read_R_reg(RT (inst));
      break;

    case Y_SRL_OP:
      Operand2 (ps) = read_R_reg(RT (inst));
      break;

    case Y_SRLV_OP:
    case Y_SUB_OP:
    case Y_SUBU_OP:
      Operand1 (ps) = read_R_reg(RS (inst));
      Operand2 (ps) = read_R_reg(RT (inst));
      break;

    case Y_SW_OP:
    case Y_SWL_OP:
    case Y_SWR_OP:
      Operand1 (ps) = read_R_reg(RT (inst));
      Operand2 (ps) = read_R_reg(BASE (inst));
      Operand3 (ps) = IOFFSET (inst);
      break;

    case Y_SWC1_OP:
      if (!COP_Available(OPCODE (inst) - Y_SWC0_OP))
	CL_RAISE_EXCEPTION(CPU_EXCPT, (OPCODE (inst) - Y_SWC0_OP), EXCPT(ps));
      Operand2 (ps) = read_R_reg(BASE (inst));
      Operand3 (ps) = IOFFSET (inst);

      *stall = !is_single_present(RT (inst));
      break;

    case Y_SWC0_OP:
    case Y_SWC3_OP:
      if (!COP_Available(OPCODE (inst) - Y_SWC0_OP))
	CL_RAISE_EXCEPTION(CPU_EXCPT, (OPCODE (inst) - Y_SWC0_OP), EXCPT(ps));
      Operand1 (ps) = read_CP_reg((OPCODE (inst) - Y_SWC0_OP), RT (inst), 1);
      Operand2 (ps) = read_R_reg(BASE (inst));
      Operand3 (ps) = IOFFSET (inst);
      break;

    case Y_SWC2_OP:
      /* do nothing, SWC2 is being used to print memory stats */
      break;

    case Y_SYSCALL_OP:
      CL_RAISE_EXCEPTION(SYSCALL_EXCPT, 0, EXCPT(ps));
      break;

    case Y_TLBP_OP:
    case Y_TLBR_OP:
    case Y_TLBWI_OP:
    case Y_TLBWR_OP:
      if (!COP_Available(0))
	CL_RAISE_EXCEPTION(CPU_EXCPT, 0, EXCPT(ps));
      break;

    case Y_XOR_OP:
      Operand1 (ps) = read_R_reg(RS (inst));
      Operand2 (ps) = read_R_reg(RT (inst));
      break;

    case Y_XORI_OP:
      Operand1 (ps) = read_R_reg(RS (inst));
      Operand2 (ps) = IMM (inst);
      break;

    /* Floating point operations */
    case Y_ABS_S_OP:
      FPoperand1 (ps) = FPR_S (FS (inst));
      *stall = stall2(OPCODE (inst), FS (inst), FD (inst));
      break;


    case Y_ABS_D_OP:
      FPoperand1 (ps) = FPR_D (FS (inst));
      *stall = stall2(OPCODE (inst), FS (inst), FD (inst));
      break;

    case Y_ADD_S_OP:
      FPoperand1 (ps) = FPR_S (FS (inst));
      FPoperand2 (ps) = FPR_S (FT (inst));
      *stall = stall3(OPCODE (inst), FS (inst), FT (inst), FD (inst));
      break;

    case Y_ADD_D_OP:
      FPoperand1 (ps) = FPR_D (FS (inst));
      FPoperand2 (ps) = FPR_D (FT (inst));
      *stall = stall3(OPCODE (inst), FS (inst), FT(inst), FD (inst));
      break;


    case Y_C_F_S_OP:
    case Y_C_UN_S_OP:
    case Y_C_EQ_S_OP:
    case Y_C_UEQ_S_OP:
    case Y_C_OLE_S_OP:
    case Y_C_ULE_S_OP:
    case Y_C_SF_S_OP:
    case Y_C_NGLE_S_OP:
    case Y_C_SEQ_S_OP:
    case Y_C_NGL_S_OP:
    case Y_C_LT_S_OP:
    case Y_C_NGE_S_OP:
    case Y_C_LE_S_OP:
    case Y_C_NGT_S_OP:
      FPoperand1 (ps) = FPR_S (FS (inst));
      FPoperand2 (ps) = FPR_S (FT (inst));
      *stall = stall2(OPCODE (inst), FS (inst), FT (inst));
      break;


    case Y_C_F_D_OP:
    case Y_C_UN_D_OP:
    case Y_C_EQ_D_OP:
    case Y_C_UEQ_D_OP:
    case Y_C_OLE_D_OP:
    case Y_C_ULE_D_OP:
    case Y_C_SF_D_OP:
    case Y_C_NGLE_D_OP:
    case Y_C_SEQ_D_OP:
    case Y_C_NGL_D_OP:
    case Y_C_LT_D_OP:
    case Y_C_NGE_D_OP:
    case Y_C_LE_D_OP:
    case Y_C_NGT_D_OP:
      FPoperand1 (ps) = FPR_D (FS (inst));
      FPoperand2 (ps) = FPR_D (FT (inst));
      *stall = stall3(OPCODE (inst), FS (inst), FT (inst), FD (inst));
      break;

    case Y_CFC1_OP:
      /* What to do */
      break;

    case Y_CTC1_OP:
      /* What to do */
      break;

    case Y_CVT_D_S_OP:
      FPoperand1 (ps) = FPR_S (FS (inst));
      *stall = stall2(OPCODE (inst), FS (inst), FD (inst));
      break;

    case Y_CVT_D_W_OP:
      FPoperand1 (ps) = FPR_W (FS (inst));
      *stall = stall2(OPCODE (inst), FS (inst), FD (inst));
      break;

    case Y_CVT_S_D_OP:
      FPoperand1 (ps) = FPR_D (FS (inst));
      *stall = stall2(OPCODE (inst), FS (inst), FD (inst));
      break;


    case Y_CVT_S_W_OP:
      FPoperand1 (ps) = FPR_W (FS (inst));
      *stall = stall2(OPCODE (inst), FS (inst), FD (inst));
      break;

    case Y_CVT_W_D_OP:
      FPoperand1 (ps) = FPR_D (FS (inst));
      *stall = stall2(OPCODE (inst), FS (inst), FD (inst));
      break;


    case Y_CVT_W_S_OP:
      FPoperand1 (ps) = FPR_S (FS (inst));
      *stall = stall2(OPCODE (inst), FS (inst), FD (inst));
      break;

    case Y_DIV_S_OP:
      FPoperand1 (ps) = FPR_S (FS (inst));
      FPoperand2 (ps) = FPR_S (FT (inst));
      *stall = stall3(OPCODE (inst), FS (inst), FT (inst), FD (inst));
      break;

    case Y_DIV_D_OP:
      FPoperand1 (ps) = FPR_D (FS (inst));
      FPoperand2 (ps) = FPR_D (FT (inst));
      *stall = stall3(OPCODE (inst), FS (inst), FT (inst), FD (inst));
      break;


    case Y_LWC1_OP:
      if (!COP_Available(OPCODE (inst) - Y_LWC0_OP))
	CL_RAISE_EXCEPTION(CPU_EXCPT, (OPCODE (inst) - Y_LWC0_OP) , EXCPT(ps));
      Operand1 (ps) = read_R_reg(BASE (inst));
      Operand2 (ps) = IOFFSET (inst);
      /* can't issue the load if some instruction in the floating
	 point-pipeline is going to write to the dest */
      *stall = ! is_single_present(FT (inst));
      break;

    case Y_MFC1_OP:
      if (!COP_Available(OPCODE (inst) - Y_MFC0_OP))
	CL_RAISE_EXCEPTION(CPU_EXCPT, (OPCODE (inst) - Y_MFC0_OP), EXCPT(ps));
      *stall = ! (is_single_present (RD (inst)));
      break;

    case Y_MOV_S_OP:
      FPoperand1 (ps) = FPR_S (FS (inst));
      *stall = stall2(OPCODE (inst), FS (inst), FD (inst));
      break;


    case Y_MOV_D_OP:
      FPoperand1 (ps) = FPR_D (FS (inst));
      *stall = stall2(OPCODE (inst), FS (inst), FD (inst));
       break;

    case Y_MUL_S_OP:
      FPoperand1 (ps) = FPR_S (FS (inst));
      FPoperand2 (ps) = FPR_S (FT (inst));
      *stall = stall3(OPCODE (inst), FS (inst), FT (inst), FD (inst));
      break;


    case Y_MUL_D_OP:
      FPoperand1 (ps) = FPR_D (FS (inst));
      FPoperand2 (ps) = FPR_D (FT (inst));
      *stall = stall3(OPCODE (inst), FS (inst), FT (inst), FD (inst));
      break;

    case Y_NEG_S_OP:
      FPoperand1 (ps) = FPR_S (FS (inst));
      *stall = stall2(OPCODE (inst), FS (inst), FD (inst));
      break;


    case Y_NEG_D_OP:
      FPoperand1 (ps) = FPR_D (FS (inst));
      *stall = stall2(OPCODE (inst), FS (inst), FD (inst));
      break;


    case Y_SUB_S_OP:
      FPoperand1 (ps) = FPR_S (FS (inst));
      FPoperand2 (ps) = FPR_S (FT (inst));
      *stall = stall3(OPCODE (inst), FS (inst), FT (inst), FD (inst));
      break;


    case Y_SUB_D_OP:
      FPoperand1 (ps)  = FPR_D (FS (inst));
      FPoperand2 (ps) = FPR_D (FT (inst));
      *stall = stall3(OPCODE (inst), FS (inst), FT (inst), FD (inst));
      break;


    default:
      excpt = RI_EXCPT << 2;
      *stall = 0;
      break;
    }

  if (*stall == 0) {
    nPC = tmp_PC;
  }

  return (excpt);

}




/* Simulate EX stage */
/* integer unit only */
/* where do bypass values get set? */
/* Goal of EX to to compute value or address and to set the
   necessary bypass values. */

#ifdef __STDC__
static int
process_EX (PIPE_STAGE ps, struct mult_div_unit *pMDU)
#else
static int
process_EX (ps, pMDU)
     PIPE_STAGE ps;
     struct mult_div_unit *pMDU;
#endif
{
  instruction *inst;

  inst = ps->inst;

  switch (OPCODE (inst))
    {
    case Y_ADD_OP:
      {	register reg_word vs, vt;
	register reg_word sum;

	vs = Operand1 (ps);
	vt = Operand2 (ps);
	sum = vs + vt;

	if (ARITH_OVFL (sum, vs, vt))
	  CL_RAISE_EXCEPTION (OVF_EXCPT, 0, EXCPT(ps));

	VALUE (ps) = sum;
	set_ex_bypass(RD (inst), sum);
	break;
      }

    case Y_ADDI_OP:
      {	register reg_word vs, imm;
	register reg_word sum;

	vs = Operand1 (ps);
	imm = (short) Operand2 (ps);
	sum = vs + imm;

	if (ARITH_OVFL (sum, vs, imm))
	  CL_RAISE_EXCEPTION (OVF_EXCPT, 0, EXCPT(ps));
	VALUE (ps) = sum;
	set_ex_bypass(RT (inst), sum);
	break;
      }

    case Y_ADDIU_OP:
      VALUE (ps) = Operand1 (ps) + (short) Operand2 (ps);
      set_ex_bypass(RT (inst), VALUE (ps));
      break;

    case Y_ADDU_OP:
      VALUE (ps) = Operand1 (ps) + Operand2 (ps);
      set_ex_bypass(RD (inst), VALUE (ps));
      break;

    case Y_AND_OP:
      VALUE (ps) = Operand1 (ps) & Operand2 (ps);
      set_ex_bypass(RD (inst), VALUE (ps));
      break;

    case Y_ANDI_OP:
      /* why is the 0xffff necessary? */
      VALUE (ps) = Operand1 (ps) & (0xffff & Operand2 (ps));
      set_ex_bypass(RT (inst), VALUE (ps));
      break;

    case Y_BC0F_OP:
    case Y_BC1F_OP:
    case Y_BC2F_OP:
    case Y_BC3F_OP:
    case Y_BC0T_OP:
    case Y_BC1T_OP:
    case Y_BC2T_OP:
    case Y_BC3T_OP:
    case Y_BEQ_OP:
    case Y_BGEZ_OP:
      set_ex_bypass(0, 0);
      break;

    case Y_BGEZAL_OP:
      VALUE (ps) = STAGE_PC(ps) + 2 * BYTES_PER_WORD;
      /* where is the link value computed and stored?  should it be
	 available through bypass?  */
      set_ex_bypass(31, VALUE (ps));
      break;

    case Y_BGTZ_OP:
    case Y_BLEZ_OP:
    case Y_BLTZ_OP:
      set_ex_bypass(0, 0);
      break;

    case Y_BLTZAL_OP:
      VALUE (ps) = STAGE_PC(ps) + 2 * BYTES_PER_WORD;
      set_ex_bypass(31, VALUE (ps));
      break;

    case Y_BNE_OP:
      set_ex_bypass(0, 0);
      break;

    case Y_BREAK_OP:
      /* what to do? */
      break;

    case Y_CFC0_OP:
    case Y_CFC2_OP:
    case Y_CFC3_OP:
      VALUE (ps) = Operand1 (ps);
      set_ex_bypass(0, 0);
      break;

    case Y_COP0_OP:
    case Y_COP1_OP:
    case Y_COP2_OP:
    case Y_COP3_OP:
      VALUE (ps) = Operand2 (ps);
      /* bypass? */
      set_ex_bypass(0, 0);
      break;

    case Y_CTC0_OP:
    case Y_CTC2_OP:
    case Y_CTC3_OP:
      VALUE (ps) = Operand2 (ps);
      /* bypass? */
      set_ex_bypass(0, 0);
      break;

    case Y_DIV_OP:
      { reg_word hi, lo;

	if (Operand2 (ps) != 0)
	  {
	    hi = (long) Operand1 (ps) % (long) Operand2 (ps);
	    lo = (long) Operand1 (ps) / (long) Operand2 (ps);
	  }
	else
	  {
	    hi = HI;
	    lo = LO;
	  }

	HI_present = 0;
	LO_present = 0;
	pMDU->hi_val = hi;
	pMDU->lo_val = lo;
	/* -1 is for this cycle */
	pMDU->count = DIV_COST - 1;

	set_ex_bypass(0, 0);
	break;
      }

    case Y_DIVU_OP:
      {reg_word hi, lo;

       if (Operand2 (ps) != 0)
	 {
	   hi = (unsigned long) Operand1 (ps) % (unsigned long) Operand2 (ps);
	   lo = (unsigned long) Operand1 (ps) / (unsigned long) Operand2 (ps);
	 }
       else
	 {
	   hi = HI;
	   lo = LO;
	 }

       HI_present = 0;
       LO_present = 0;
       pMDU->hi_val = hi;
       pMDU->lo_val = lo;
       /* -1 is for this cycle */
       pMDU->count = DIV_COST - 1;
       set_ex_bypass(0, 0);
       break;
     }

    case Y_J_OP:
      set_ex_bypass(0, 0);
      break;

    case Y_JAL_OP:
      VALUE (ps) = STAGE_PC(ps) + 2 * BYTES_PER_WORD;
      set_ex_bypass(31, VALUE (ps));
      break;

    case Y_JALR_OP:
      VALUE (ps) =  STAGE_PC(ps) + 2 * BYTES_PER_WORD;
      set_ex_bypass(RD (inst), VALUE (ps));
      break;

    case Y_JR_OP:
      set_ex_bypass(0, 0);
      break;

    case Y_LB_OP:
    case Y_LBU_OP:
    case Y_LH_OP:
    case Y_LHU_OP:
    case Y_LW_OP:
    case Y_LWC0_OP:
    case Y_LWC2_OP:
    case Y_LWC3_OP:
    case Y_LWL_OP:
    case Y_LWR_OP:
      ADDR (ps) = read_R_reg(BASE (inst)) + IOFFSET (inst);
      set_ex_bypass(0, 0);
      break;

    case Y_LWC1_OP:
      clr_single_present(FT (inst));
      ADDR (ps) = read_R_reg(BASE (inst)) + IOFFSET (inst);
      set_ex_bypass(0, 0);
      break;

    case Y_LUI_OP:
      VALUE (ps) = (Operand2 (ps) << 16) & 0xffff0000;
      set_ex_bypass(RT (inst), VALUE (ps));
      break;

    case Y_MFC0_OP:
    case Y_MFC2_OP:
    case Y_MFC3_OP:
      VALUE (ps) = Operand1 (ps);
      set_ex_bypass(0, 0);
      break;

    case Y_MFC1_OP:
      /* DO nothing...value is read in MEM */
      set_ex_bypass(0, 0);
      break;

    case Y_MFHI_OP:
      VALUE (ps) = Operand1 (ps);
      set_ex_bypass(RD (inst), VALUE (ps));
      break;

    case Y_MFLO_OP:
      VALUE (ps) = Operand1 (ps);
      set_ex_bypass(RD (inst), VALUE (ps));
      break;

    case Y_MTC0_OP:
    case Y_MTC2_OP:
    case Y_MTC3_OP:
      VALUE (ps) = Operand2 (ps);
      set_ex_bypass(0, 0);
      break;

    case Y_MTC1_OP:
      VALUE (ps) = Operand2 (ps);
      set_ex_bypass(0, 0);
      break;

    case Y_MTHI_OP:
      HI = Operand1 (ps);
      set_ex_bypass(0, 0);
      break;

    case Y_MTLO_OP:
      LO = Operand1 (ps);
      set_ex_bypass(0, 0);
      break;

    case Y_MULT_OP:
      {
	reg_word v1 = Operand1 (ps), v2 = Operand2 (ps);
	reg_word lo, hi;
	int neg_sign = 0;

	if (v1 < 0)
	  v1 = - v1, neg_sign = 1;
	if (v2 < 0)
	  v2 = - v2, neg_sign = ! neg_sign;


	long_multiply (v1, v2, &hi, &lo);
	if (neg_sign)
	  {
	    int carry = 0;

	    lo = ~ lo;
	    hi = ~ hi;
	    carry = lo & 0x80000000;
	    lo += 1;
	    if ((lo ^ carry) == 1)
	      hi += 1;
	  }

	HI_present = 0;
	LO_present = 0;
	pMDU->hi_val = hi;
	pMDU->lo_val = lo;
	/* -1 is for this cycle */
	pMDU->count = MULT_COST - 1;

	set_ex_bypass(0, 0);
	break;
      }

    case Y_MULTU_OP:
      {reg_word hi, lo;

       long_multiply (Operand1 (ps), Operand2 (ps), &hi, &lo);

       HI_present = 0;
       LO_present = 0;
       pMDU->hi_val = hi;
       pMDU->lo_val = lo;
       /* -1 is for this cycle */
       pMDU->count = MULT_COST - 1;

       set_ex_bypass(0, 0);
       break;
     }

    case Y_NOR_OP:
      VALUE (ps) = ~ (Operand1 (ps) | Operand2 (ps));
      set_ex_bypass(RD (inst), VALUE (ps));
      break;


    case Y_OR_OP:
      VALUE (ps) = Operand1 (ps) | Operand2 (ps);
      set_ex_bypass(RD (inst), VALUE (ps));
      break;

    case Y_ORI_OP:
      /* why is the 0xffff necessary */
      VALUE (ps) = Operand1 (ps) | (0xffff & Operand2 (ps));
      set_ex_bypass(RT (inst), VALUE (ps));
      break;

    case Y_RFE_OP:
      /* but without kernel code, this should never occur */
      Status_Reg = (Status_Reg & 0xfffffff0) | ((Status_Reg & 0x3c) >> 2);
      set_ex_bypass(0, 0);
      break;

    case Y_SB_OP:
    case Y_SH_OP:
      ADDR (ps) = Operand2 (ps) + Operand3 (ps);
      VALUE (ps) = Operand1 (ps);
      set_ex_bypass(0, 0);
      break;

    case Y_SLL_OP:
      {
	int shamt = SHAMT (inst);

	if (shamt >= 0 && shamt < 32)
	  VALUE (ps) = Operand2 (ps) << shamt;
	else
	  VALUE (ps) = Operand2 (ps);

	set_ex_bypass(RD (inst), VALUE (ps));
	break;
      }

    case Y_SLLV_OP:
      {
	int shamt = (Operand1 (ps) & 0x1f);

	if (shamt >= 0 && shamt < 32)
	  VALUE (ps) = Operand2 (ps) << shamt;
	else
	  VALUE (ps) = Operand2 (ps);

	set_ex_bypass(RD (inst), VALUE (ps));
	break;
      }

    case Y_SLT_OP:
      if (Operand1 (ps) < Operand2 (ps))
	VALUE (ps) = 1;
      else
	VALUE (ps) = 0;

      set_ex_bypass(RD (inst), VALUE (ps));
      break;

    case Y_SLTI_OP:
      if (Operand1 (ps) < (short) Operand2 (ps))
	VALUE (ps) = 1;
      else
	VALUE (ps) = 0;

      set_ex_bypass(RT (inst), VALUE (ps));
      break;

    case Y_SLTIU_OP:
      {
	int x = (short) Operand2 (ps);

	if ((unsigned long) Operand1 (ps) < (unsigned long) x)
	  VALUE (ps) = 1;
	else
	  VALUE (ps) = 0;

	set_ex_bypass(RT (inst), VALUE (ps));
	break;
      }

    case Y_SLTU_OP:
      if ((unsigned long) Operand1 (ps) < (unsigned long) Operand2 (ps))
	VALUE (ps) = 1;
      else
	VALUE (ps) = 0;

      set_ex_bypass(RD (inst), VALUE (ps));
      break;

    case Y_SRA_OP:
      {
	int shamt = SHAMT (inst);
	long val = Operand2 (ps);

	if (shamt >= 0 && shamt < 32)
	  VALUE (ps) = val >> shamt;
	else
	  VALUE (ps) = val;

	set_ex_bypass(RD (inst), VALUE (ps));
	break;
      }

    case Y_SRAV_OP:
      {
	int shamt = Operand1 (ps) & 0x1f;
	long val = Operand2 (ps);

	if (shamt >= 0 && shamt < 32)
	  VALUE (ps) = val >> shamt;
	else
	  VALUE (ps) = val;

	set_ex_bypass(RD (inst), VALUE (ps));
	break;
      }

    case Y_SRL_OP:
      {
	int shamt = SHAMT (inst);
	unsigned long val = Operand2 (ps);

	if (shamt >= 0 && shamt < 32)
	  VALUE (ps) = val >> shamt;
	else
	  VALUE (ps) = val;

	set_ex_bypass(RD (inst), VALUE (ps));
	break;
      }

    case Y_SRLV_OP:
      {
	int shamt = Operand1 (ps) & 0x1f;
	unsigned long val = Operand2 (ps);

	if (shamt >= 0 && shamt < 32)
	  VALUE (ps) = val >> shamt;
	else
	  VALUE (ps) = val;

	set_ex_bypass(RD (inst), VALUE (ps));
	break;
      }

    case Y_SUB_OP:
      {
	register reg_word vs = Operand1 (ps), vt = Operand2 (ps);
	register reg_word diff = vs - vt;

	if (SIGN_BIT (vs) != SIGN_BIT (vt)
	    && SIGN_BIT (vs) != SIGN_BIT (diff))
	  CL_RAISE_EXCEPTION (OVF_EXCPT, 0, EXCPT(ps));

	VALUE (ps) = diff;

	set_ex_bypass(RD (inst), diff);
	break;
      }

    case Y_SUBU_OP:
      VALUE (ps) = (unsigned long) Operand1 (ps) - (unsigned long) Operand2 (ps);

      set_ex_bypass(RD (inst), VALUE (ps));
      break;

    case Y_SW_OP:
    case Y_SWC0_OP:
    case Y_SWC1_OP:
    case Y_SWC3_OP:
    case Y_SWL_OP:
    case Y_SWR_OP:
      ADDR (ps) = Operand2 (ps) + Operand3 (ps);
      VALUE (ps) = Operand1 (ps);
      set_ex_bypass(0, 0);
      break;

    case Y_SWC2_OP:
      /* do nothing, SWC2 is being used to print memory stats */
      break;

    case Y_SYSCALL_OP:
      break;

    case Y_TLBP_OP:
    case Y_TLBR_OP:
    case Y_TLBWI_OP:
    case Y_TLBWR_OP:
      /* what to do? */
      break;

    case Y_XOR_OP:
      VALUE (ps) = Operand1 (ps) ^ Operand2 (ps);
      set_ex_bypass(RD (inst), VALUE (ps));
      break;

    case Y_XORI_OP:
      /* why is the 0xffff necessary */
      VALUE (ps) = Operand1 (ps) ^ (0xffff & Operand2 (ps));
      set_ex_bypass(RT (inst), VALUE (ps));
      break;


    default:
      /* What to do? */
      break;
    }

}



/* process memory stage */
/* need to handle misses and faults */

#ifdef __STDC__
static int
process_MEM (PIPE_STAGE ps, MEM_SYSTEM mem_sys)
#else
static int
process_MEM (ps, mem_sys)
     PIPE_STAGE ps;
     MEM_SYSTEM mem_sys;
#endif
{
  instruction *inst;
  int cmiss = -1;

  inst = ps->inst;

  /* only load instructions update the MEM bypass variables
     to something other than the values generated by the EX stage */
  set_mem_bypass(EX_bp_reg, EX_bp_val);
  /* Kill old CP bypass values */
  set_CP_bypass(-1, -1 , -1, -1);

  switch (OPCODE (inst))
    {
    case Y_LB_OP:
      CL_READ_MEM_BYTE(mem_sys, VALUE(ps), ADDR (ps), PADDR (ps), cmiss, EXCPT (ps), RNUM (ps));
      if (EXCPT (ps) == 0)
	set_mem_bypass(RT (inst), VALUE (ps));
      break;

    case Y_LBU_OP:
      CL_READ_MEM_BYTE(mem_sys, VALUE(ps), ADDR (ps), PADDR (ps), cmiss, EXCPT (ps), RNUM (ps));
      if (EXCPT (ps) == 0) {
	/* 0xff is probably not necessary */
	VALUE (ps) &= 0xff;
	set_mem_bypass(RT (inst), VALUE (ps));
      }
      break;

    case Y_LH_OP:
      CL_READ_MEM_HALF(mem_sys, VALUE(ps), ADDR (ps), PADDR (ps), cmiss, EXCPT (ps), RNUM (ps));
      if (EXCPT (ps) == 0)
	set_mem_bypass(RT (inst), VALUE (ps));
      break;

    case Y_LHU_OP:
      CL_READ_MEM_HALF(mem_sys, VALUE(ps), ADDR (ps), PADDR (ps), cmiss, EXCPT (ps), RNUM (ps));
      if (EXCPT (ps) == 0) {
	/* 0xffff is probably not necessary */
	VALUE (ps) &= 0xffff;
	set_mem_bypass(RT (inst), VALUE (ps));
      }
      break;

    case Y_LW_OP:
      CL_READ_MEM_WORD(mem_sys, VALUE(ps), ADDR (ps), PADDR (ps), cmiss, EXCPT (ps), RNUM (ps));
      if (EXCPT (ps) == 0)
	set_mem_bypass(RT (inst), VALUE (ps));
      break;

    case Y_LWC0_OP:
    case Y_LWC2_OP:
    case Y_LWC3_OP:
      CL_READ_MEM_WORD(mem_sys, VALUE(ps), ADDR (ps), PADDR (ps), cmiss, EXCPT (ps), RNUM (ps));
      if (EXCPT (ps) == 0)
	set_CP_bypass((OPCODE (inst) - Y_LWC0_OP), RT (inst), VALUE (ps), 1)
      else
	/* Exception occurred.  Need to reset the register
	 * presence bits, so that after the fault, the instruction
	 * can restart */
	set_single_present(FT (inst));
      break;


    case Y_LWC1_OP:
      CL_READ_MEM_WORD(mem_sys, VALUE(ps), ADDR (ps), PADDR (ps), cmiss, EXCPT (ps), RNUM (ps));
      if (EXCPT (ps) == 0)
	set_CP_bypass((OPCODE (inst) - Y_LWC0_OP), RT (inst), VALUE (ps), 1)
      else
	/* Exception occurred.  Need to reset the register
	 * presence bits, so that after the fault, the instruction
	 * can restart */
	set_single_present(FT (inst));
      break;

    case Y_LWL_OP:
      {
	register mem_addr addr = ADDR (ps);
	reg_word word;	/* Can't be register */
	register int byte = addr & 0x3;
	/* is this right? -- NO need bypass value from memory stage of previous
	   instruction. */
	reg_word reg_val = R[RT (inst)];

	CL_READ_MEM_WORD(mem_sys, word, addr & 0xfffffffc, PADDR (ps), cmiss,
			 EXCPT (ps), RNUM (ps));
	/* Fix this */
/*	if ((Cause >> 2) > LAST_REAL_EXCEPT) */
	if (Cause == 0)
#ifdef BIGENDIAN
	  switch (byte)
	    {
	    case 0:
	      VALUE (ps) = word;
	      break;

	    case 1:
	      VALUE (ps) = (word & 0xffffff) << 8 | (reg_val & 0xff);
	      break;

	    case 2:
	      VALUE (ps) = (word & 0xffff) << 16 | (reg_val & 0xffff);
	      break;

	    case 3:
	      VALUE (ps) = (word & 0xff) << 24 | (reg_val & 0xffffff);
	      break;
	      }
#else
	switch (byte)
	  {
	  case 0:
	    VALUE (ps) = (word & 0xff) << 24 | (reg_val & 0xffffff);
	    break;

	  case 1:
	    VALUE (ps) = (word & 0xffff) << 16 | (reg_val & 0xffff);
	    break;

	  case 2:
	    VALUE (ps) = (word & 0xffffff) << 8 | (reg_val & 0xff);
	    break;

	  case 3:
	    VALUE (ps) = word;
	    break;
	  }
#endif
	set_mem_bypass(RT (inst), VALUE (ps));

	break;
      }

    case Y_LWR_OP:
      {
	register mem_addr addr = ADDR (ps);
	reg_word word;	/* Can't be register */
	register int byte = addr & 0x3;
	/* is this right? */
	reg_word reg_val = R[RT (inst)];

        CL_READ_MEM_WORD(mem_sys, word, addr & 0xfffffffc, PADDR (ps), cmiss,
			 EXCPT (ps), RNUM (ps));
	/* fix this */

/*	if ((Cause >> 2) > LAST_REAL_EXCEPT) */
	if (Cause == 0)
#ifdef BIGENDIAN
	  switch (byte)
	    {
	    case 0:
	      VALUE (ps) = (reg_val & 0xffffff00)
		| ((word & 0xff000000) >> 24);
	      break;

	    case 1:
	      VALUE (ps) = (reg_val & 0xffff0000)
		| ((word & 0xffff0000) >> 16);
	      break;

	    case 2:
	      VALUE (ps) = (reg_val & 0xff000000)
		| ((word & 0xffffff00) >> 8);
	      break;

	    case 3:
	      VALUE (ps) = word;
	      break;
	    }
#else
	switch (byte)
	  {
	    /* NB: The description of the little-endian case in Kane is
	       totally wrong. */
	  case 0:		/* 3 in book */
	    VALUE (ps) = reg_val;
	    break;

	  case 1:		/* 0 in book */
	    VALUE (ps) = (reg_val & 0xff000000)
	      | ((word & 0xffffff00) >> 8);
	    break;

	  case 2:		/* 1 in book */
	    VALUE (ps) = (reg_val & 0xffff0000)
	      | ((word & 0xffff0000) >> 16);
	    break;

	  case 3:		/* 2 in book */
	    VALUE (ps) = (reg_val & 0xffffff00)
	      | ((word & 0xff000000) >> 24);
	    break;
	  }
#endif
	set_mem_bypass(RT (inst), VALUE (ps));
	break;
      }


    case Y_SB_OP:
      CL_SET_MEM_BYTE(mem_sys, ADDR (ps), PADDR (ps), VALUE (ps), cmiss, EXCPT(ps),
		      RNUM (ps));
      break;

    case Y_SH_OP:
      CL_SET_MEM_HALF(mem_sys, ADDR (ps), PADDR (ps), VALUE (ps), cmiss, EXCPT(ps),
		      RNUM (ps));
      break;

    case Y_SW_OP:
      CL_SET_MEM_WORD(mem_sys, ADDR (ps), PADDR (ps), VALUE (ps), cmiss, EXCPT(ps),
		      RNUM (ps));
      break;

    case Y_SWC1_OP:
      {
	float val = FGR [RT (inst)];
	reg_word *vp = (reg_word *) &val;

	CL_SET_MEM_WORD (mem_sys, ADDR (ps), PADDR (ps), *vp, cmiss, EXCPT (ps),
			 RNUM (ps));
	break;
      }

    case Y_SWC0_OP:
    case Y_SWC3_OP:
      CL_SET_MEM_WORD(mem_sys, ADDR (ps), PADDR (ps), VALUE (ps), cmiss, EXCPT(ps),
		      RNUM (ps));
      break;


    case Y_SWC2_OP:
      /* do nothing, SWC2 is being used to print memory stats */
      break;

    case Y_SWL_OP:
      {
	register mem_addr addr = ADDR (ps);
	mem_word data;
	reg_word reg = R[RT (inst)];
	register int byte = addr & 0x3;

	CL_READ_MEM_WORD (mem_sys, data, addr & 0xfffffffc, PADDR (ps), cmiss,
			  EXCPT (ps), RNUM (ps));

#ifdef BIGENDIAN
	switch (byte)
	  {
	  case 0:
	    data = reg;
	    break;

	  case 1:
	    data = (data & 0xff000000) | (reg >> 8 & 0xffffff);
	    break;

	  case 2:
	    data = (data & 0xffff0000) | (reg >> 16 & 0xffff);
	    break;

	  case 3:
	    data = (data & 0xffffff00) | (reg >> 24 & 0xff);
	    break;
	  }
#else
	switch (byte)
	  {
	  case 0:
	    data = (data & 0xffffff00) | (reg >> 24 & 0xff);
	    break;

	  case 1:
	    data = (data & 0xffff0000) | (reg >> 16 & 0xffff);
	    break;

	  case 2:
	    data = (data & 0xff000000) | (reg >> 8 & 0xffffff);
	    break;

	  case 3:
	    data = reg;
	    break;
	  }
#endif
	CL_SET_MEM_WORD (mem_sys, addr & 0xfffffffc, PADDR (ps), data, cmiss,
			 EXCPT(ps), RNUM (ps));
	break;
      }

    case Y_SWR_OP:
      {
	register mem_addr addr = R[BASE (inst)] + IOFFSET (inst);
	mem_word data;
	reg_word reg = R[RT (inst)];
	register int byte = addr & 0x3;

	CL_READ_MEM_WORD (mem_sys, data, addr & 0xfffffffc, PADDR (ps), cmiss,
			  EXCPT (ps), RNUM (ps));

#ifdef BIGENDIAN
	switch (byte)
	  {
	  case 0:
	    data = ((reg << 24) & 0xff000000) | (data & 0xffffff);
	    break;

	  case 1:
	    data = ((reg << 16) & 0xffff0000) | (data & 0xffff);
	    break;

	  case 2:
	    data = ((reg << 8) & 0xffffff00) | (data & 0xff) ;
	    break;

	  case 3:
	    data = reg;
	    break;
	  }
#else
	switch (byte)
	  {
	  case 0:
	    data = reg;
	    break;

	  case 1:
	    data = ((reg << 8) & 0xffffff00) | (data & 0xff) ;
	    break;

	  case 2:
	    data = ((reg << 16) & 0xffff0000) | (data & 0xffff);
	    break;

	  case 3:
	    data = ((reg << 24) & 0xff000000) | (data & 0xffffff);
	    break;
	  }
#endif
	CL_SET_MEM_WORD (mem_sys, addr & 0xfffffffc, PADDR (ps), data, cmiss,
			 EXCPT(ps), RNUM (ps));
	break;
      }

    case Y_SYSCALL_OP:
      break;

    case Y_TLBP_OP:
      tlbp();
      break;

    case Y_TLBR_OP:
      tlbr();
      break;

    case Y_TLBWI_OP:
      tlbwi();
      break;

    case Y_TLBWR_OP:
      tlbwr();
      break;

    case Y_CFC0_OP:
    case Y_CFC2_OP:
    case Y_CFC3_OP:
    case Y_MFC0_OP:
    case Y_MFC2_OP:
    case Y_MFC3_OP:
      set_mem_bypass(RT (inst), VALUE (ps));
      break;

    case Y_MFC1_OP:
      {  /* Read value from register file to avoid extra
	 conversion to double precision */
	float val = FGR [RD (inst)]; /* RD not FS */
	reg_word *vp = (reg_word *) &val;

	set_mem_bypass(RT (inst), *vp);
	break;
      }

    case Y_CTC0_OP:
    case Y_CTC2_OP:
    case Y_CTC3_OP:
      set_CP_bypass((OPCODE (inst) - Y_CTC0_OP), RD (inst), VALUE (ps), 0);
      break;

    case Y_MTC0_OP:
    case Y_MTC2_OP:
    case Y_MTC3_OP:
      set_CP_bypass((OPCODE (inst) - Y_MTC0_OP), RD (inst), VALUE (ps), 1);
      break;

    default:
      /* nothing to do for the following op codes
	case Y_ADD_OP:	case Y_ADDI_OP:	      case Y_ADDIU_OP:     case Y_ADDU_OP:
	case Y_AND_OP:     case Y_ANDI_OP:    case Y_BC0F_OP:      case Y_BC2F_OP:
	case Y_BC3F_OP:    case Y_BC0T_OP:    case Y_BC2T_OP:      case Y_BC3T_OP:
	case Y_BEQ_OP:     case Y_BGEZ_OP:    case Y_BGEZAL_OP:    case Y_BGTZ_OP:
	case Y_BLEZ_OP:    case Y_BLTZ_OP:    case Y_BLTZAL_OP:    case Y_BNE_OP:
	case Y_BREAK_OP:   case Y_COP0_OP:    case Y_COP1_OP:      case Y_COP2_OP:
	case Y_COP3_OP:    case Y_DIV_OP:     case Y_DIVU_OP:      case Y_J_OP:
	case Y_JAL_OP:     case Y_JALR_OP:    case Y_JR_OP:        case Y_LUI_OP
	case Y_MFHI_OP:    case Y_MFLO_OP:    case Y_MTHI_OP:      case Y_MTLO_OP:
	case Y_MULT_OP:	   case Y_MULTU_OP:   case Y_NOR_OP:	   case Y_OR_OP:
	case Y_ORI_OP:	   case Y_RFE_OP:     case Y_SLL_OP:	   case Y_SLLV_OP:
	case Y_SLT_OP:	   case Y_SLTI_OP:    case Y_SLTIU_OP:	   case Y_SLTU_OP:
	case Y_SRA_OP:	   case Y_SRAV_OP:    case Y_SRL_OP:	   case Y_SRLV_OP:
	case Y_SUB_OP:	   case Y_SUBU_OP:    case Y_XOR_OP:	   case Y_XORI_OP:
	*/
      break;
    }

  return (cmiss);
}


/* Simulate WB stage */
/* when sure it's right combine cases that have the same code. */

#ifdef __STDC__
static int
process_WB (PIPE_STAGE ps)
#else
static int
process_WB (ps)
     PIPE_STAGE ps;
#endif
{
  register instruction *inst;
  register int value;

  inst = ps->inst;
  value = VALUE (ps);

  switch (OPCODE (inst))
    {
    case Y_ADD_OP:   case Y_ADDU_OP:  case Y_AND_OP:  case Y_JALR_OP:
    case Y_MFHI_OP:  case Y_MFLO_OP:  case Y_NOR_OP:  case Y_OR_OP:
    case Y_SRLV_OP:  case Y_SRL_OP:   case Y_SRAV_OP: case Y_SRA_OP:
    case Y_SLTU_OP:  case Y_SLT_OP:   case Y_SLLV_OP: case Y_SLL_OP:
    case Y_SUBU_OP:  case Y_SUB_OP:   case Y_XOR_OP:
      R[RD (inst)] = value;
      break;

    case Y_ADDI_OP:  case Y_ADDIU_OP:  case Y_ANDI_OP:  case Y_CFC0_OP:
    case Y_CFC2_OP:  case Y_CFC3_OP:   case Y_LB_OP:
    case Y_LBU_OP:   case Y_LH_OP:     case Y_LHU_OP:   case Y_LUI_OP:
    case Y_LW_OP:    case Y_LWL_OP:    case Y_LWR_OP:   case Y_MFC0_OP:
    case Y_MFC2_OP:  case Y_MFC3_OP:   case Y_ORI_OP:   case Y_SLTI_OP:
    case Y_SLTIU_OP: case Y_XORI_OP:

      R[RT (inst)] = value;
      break;

    case Y_MFC1_OP:
      /* Read value from register file to avoid extra
	 conversion to double precision */
      { float val = FGR [RD (inst)]; /* RD not FS */
	reg_word *vp = (reg_word *) &val;

	R[RT (inst)] = *vp;	/* Fool coercion */
	break;
      }


    case Y_BC0F_OP:  case Y_BC2F_OP:  case Y_BC3F_OP:  case Y_BC0T_OP:
    case Y_BC1F_OP:  case Y_BC1T_OP:
    case Y_BC2T_OP:  case Y_BC3T_OP:  case Y_BEQ_OP:   case Y_BGEZ_OP:
    case Y_BGTZ_OP:  case Y_BLEZ_OP:  case Y_BLTZ_OP:  case Y_BNE_OP:
    case Y_J_OP:     case Y_JR_OP:    case Y_SB_OP:    case Y_SH_OP:
    case Y_SW_OP:    case Y_SWC0_OP:  case Y_SWC3_OP:
    case Y_SWL_OP:   case Y_SWR_OP:   case Y_TLBP_OP:  case Y_TLBR_OP:
    case Y_TLBWI_OP: case Y_TLBWR_OP: case Y_SWC1_OP:
      /* no write back */    break;

    case Y_SWC2_OP:
      /* do nothing, SWC2 is being used to print memory stats */
      break;

    case Y_BGEZAL_OP: case Y_BLTZAL_OP: case Y_JAL_OP:
      if (!DSLOT (ps))
	R[31] = value;
      break;

    case Y_BREAK_OP:
      break;

    case Y_COP0_OP: case Y_COP1_OP:
    case Y_COP2_OP: case Y_COP3_OP:
      CCR [OPCODE (inst) - Y_COP0_OP] [RD (inst)] = value;
      break;

    case Y_CTC0_OP:
    case Y_CTC2_OP:
    case Y_CTC3_OP:
      CCR [OPCODE (inst) - Y_CTC0_OP] [RD (inst)] = value;
      break;

    case Y_DIV_OP:
    case Y_DIVU_OP:
    case Y_MTHI_OP:
    case Y_MTLO_OP:
    case Y_MULT_OP:
    case Y_MULTU_OP:
      /* nothing to do...these values are set in EX/MDU */
      break;


    case Y_LWC0_OP:
    case Y_LWC2_OP:
    case Y_LWC3_OP:
      CPR [OPCODE (inst) - Y_LWC0_OP] [RT (inst)] = value;
      break;

    case Y_MTC0_OP:
    case Y_MTC2_OP:
    case Y_MTC3_OP:
      CPR [OPCODE (inst) - Y_MTC0_OP] [RD (inst)] = value;
      break;


    case Y_RFE_OP:
      /* Do nothing.  Status_Reg is set in EX */
      break;

    case Y_SYSCALL_OP:
      /* we won't ever get here, syscall causes exception */
      break;

    default:
      /* no EX */
      break;
    }

  return (0);
  /* Executed enough steps, return, but are able to continue. */
  /*  return (1);  */

}


#ifdef __STDC__
static int
process_f_ex1 (PIPE_STAGE ps)
#else
static int
process_f_ex1(ps)
     PIPE_STAGE ps;
#endif
{ instruction *inst;
  int excpt = -1;

  inst = ps->inst;

  switch (OPCODE (inst))
    {

      /* FPA Operations */
      /* All counts include a (- 1) to account for this cycle. */


    case Y_ABS_S_OP:
    case Y_ABS_D_OP:
      clr_present(FD (inst));
      FPvalue (ps) =  fabs (FPoperand1 (ps));
      Count (ps) = 1 - 1;
      FP_add_cnt = Count (ps);
      break;

    case Y_ADD_S_OP:
    case Y_ADD_D_OP:
      clr_present(FD (inst));
      FPvalue (ps) =  FPoperand1 (ps) + FPoperand2 (ps);
      Count (ps) = 2 - 1;
      FP_add_cnt = Count (ps);
      /* Should trap on inexact/overflow/underflow */
      break;

    case Y_C_F_S_OP:
    case Y_C_UN_S_OP:
    case Y_C_EQ_S_OP:
    case Y_C_UEQ_S_OP:
    case Y_C_OLE_S_OP:
    case Y_C_ULE_S_OP:
    case Y_C_SF_S_OP:
    case Y_C_NGLE_S_OP:
    case Y_C_SEQ_S_OP:
    case Y_C_NGL_S_OP:
    case Y_C_LT_S_OP:
    case Y_C_NGE_S_OP:
    case Y_C_LE_S_OP:
    case Y_C_NGT_S_OP:
      {
	float v1 = FPoperand1 (ps), v2 = FPoperand2 (ps);
	double dv1 = v1, dv2 = v2;
	int less, equal, unordered;
	int cond = COND (inst);
	reg_word tmp_fpcond;

	if (NaN (dv1) || NaN (dv2))
	  {
	    less = 0;
	    equal = 0;
	    unordered = 1;
	    if (cond & COND_IN)
	      CL_RAISE_EXCEPTION (INVALID_EXCEPT, 0, EXCPT(ps))
	  }
	else
	  {
	    less = v1 < v2;
	    equal = v1 == v2;
	    unordered = 0;
	  }
	tmp_fpcond = 0;
	if (cond & COND_LT)
	  tmp_fpcond |= less;
	if (cond & COND_EQ)
	  tmp_fpcond |= equal;
	if (cond & COND_UN)
	  tmp_fpcond |= unordered;

	VALUE (ps) = tmp_fpcond;
	Count (ps) = 1-1;
	FP_add_cnt = Count (ps);
	break;
      }

    case Y_C_F_D_OP:
    case Y_C_UN_D_OP:
    case Y_C_EQ_D_OP:
    case Y_C_UEQ_D_OP:
    case Y_C_OLE_D_OP:
    case Y_C_ULE_D_OP:
    case Y_C_SF_D_OP:
    case Y_C_NGLE_D_OP:
    case Y_C_SEQ_D_OP:
    case Y_C_NGL_D_OP:
    case Y_C_LT_D_OP:
    case Y_C_NGE_D_OP:
    case Y_C_LE_D_OP:
    case Y_C_NGT_D_OP:
      {
	double v1 = FPoperand1 (ps), v2 = FPoperand2 (ps);
	int less, equal, unordered;
	int cond = COND (inst);
	reg_word tmp_fpcond;

	if (NaN (v1) || NaN (v2))
	  {
	    less = 0;
	    equal = 0;
	    unordered = 1;
	    if (cond & COND_IN)
	      CL_RAISE_EXCEPTION (INVALID_EXCEPT, 0, EXCPT(ps))
	  }
	else
	  {
	    less = v1 < v2;
	    equal = v1 == v2;
	    unordered = 0;
	  }
	tmp_fpcond = 0;
	if (cond & COND_LT)
	  tmp_fpcond |= less;
	if (cond & COND_EQ)
	  tmp_fpcond |= equal;
	if (cond & COND_UN)
	  tmp_fpcond |= unordered;

	VALUE (ps) = tmp_fpcond;
	Count (ps) = 1-1;
	FP_add_cnt = Count (ps);
	break;
      }

    case Y_CFC1_OP:
      /* What to do? */
      break;

    case Y_CTC1_OP:
      /* What to do? */
      break;

    case Y_CVT_D_S_OP:
    case Y_CVT_D_W_OP:
      clr_present(FD (inst));
      FPvalue (ps) =  (double) FPoperand1 (ps);
      Count (ps) = ((OPCODE (inst) == Y_CVT_D_S_OP) ? 1 : 3) - 1;
      FP_add_cnt = Count (ps);
      break;


    case Y_CVT_S_D_OP:
    case Y_CVT_S_W_OP:
      clr_present(FD (inst));
      FPvalue (ps) =  (float) FPoperand1 (ps);
      Count (ps) =  ((OPCODE (inst) == Y_CVT_S_D_OP) ? 2 : 3) - 1;
      FP_add_cnt = Count (ps);
      break;


    case Y_CVT_W_D_OP:
    case Y_CVT_W_S_OP:
      clr_present(FD (inst));
      FPvalue (ps) =  (float) FPoperand1 (ps);
      Count (ps) = 2 - 1;
      FP_add_cnt = Count (ps);
      break;

    case Y_DIV_S_OP:
    case Y_DIV_D_OP:
      clr_present(FD (inst));
      FPvalue (ps) =  FPoperand1 (ps) / FPoperand2 (ps);
      Count (ps) = ((OPCODE (inst) == Y_DIV_S_OP) ? 12 : 19) - 1;
      FP_div_cnt = Count (ps);
      break;

    case Y_LWC1_OP:
      break;


    case Y_MOV_S_OP:
    case Y_MOV_D_OP:
      clr_present(FD (inst));
      FPvalue (ps) = FPoperand1 (ps);
      Count (ps) = 1 - 1;
      FP_add_cnt = Count (ps);
      break;

    case Y_MUL_S_OP:
    case Y_MUL_D_OP:
      clr_present(FD (inst));
      FPvalue (ps) = FPoperand1 (ps) * FPoperand2 (ps);
      Count (ps) =  ((OPCODE (inst) == Y_MUL_S_OP) ? 4 : 5) - 1;
      FP_mul_cnt = Count (ps);
      break;


    case Y_NEG_S_OP:
    case Y_NEG_D_OP:
      clr_present(FD (inst));
      FPvalue (ps) =  - FPoperand1 (ps);
      Count (ps) = 1 - 1;
      FP_add_cnt = Count (ps);
      break;

    case Y_SUB_S_OP:
    case Y_SUB_D_OP:
      clr_present(FD (inst));
      FPvalue (ps) =  FPoperand1 (ps) - FPoperand2 (ps);
      Count (ps) =  2 - 1;
      FP_add_cnt = Count (ps);
      break;

    default:
      break;
    }

  return (excpt);
}



#ifdef __STDC__
static int
process_f_ex2 (PIPE_STAGE ps)
#else
static int
process_f_ex2 (ps)
  PIPE_STAGE ps;
#endif
{ instruction *inst;
  int excpt = -1;

  inst = ps->inst;

  switch (OPCODE (inst))
    {

    case Y_ABS_S_OP:
    case Y_ABS_D_OP:
    case Y_ADD_S_OP:
    case Y_ADD_D_OP:
      Count (ps) = ((Count (ps) == 0) ? 0 : Count (ps) - 1);
      /* Should trap on inexact/overflow/underflow */
      break;


    case Y_C_F_S_OP:
    case Y_C_UN_S_OP:
    case Y_C_EQ_S_OP:
    case Y_C_UEQ_S_OP:
    case Y_C_OLE_S_OP:
    case Y_C_ULE_S_OP:
    case Y_C_SF_S_OP:
    case Y_C_NGLE_S_OP:
    case Y_C_SEQ_S_OP:
    case Y_C_NGL_S_OP:
    case Y_C_LT_S_OP:
    case Y_C_NGE_S_OP:
    case Y_C_LE_S_OP:
    case Y_C_NGT_S_OP:
      /* FpCond is set in Ex2 but not in Ex3 */
      if (Count (ps) == 0) {
	FpCond = VALUE (ps);
	Count (ps) = -1;
      }
      else
	Count (ps) = 0;
      break;


    case Y_C_F_D_OP:
    case Y_C_UN_D_OP:
    case Y_C_EQ_D_OP:
    case Y_C_UEQ_D_OP:
    case Y_C_OLE_D_OP:
    case Y_C_ULE_D_OP:
    case Y_C_SF_D_OP:
    case Y_C_NGLE_D_OP:
    case Y_C_SEQ_D_OP:
    case Y_C_NGL_D_OP:
    case Y_C_LT_D_OP:
    case Y_C_NGE_D_OP:
    case Y_C_LE_D_OP:
    case Y_C_NGT_D_OP:
      /* What to do? */
      if (Count (ps) == 0) {
	FpCond = VALUE (ps);
	Count (ps) = -1;
      }
      else
	Count (ps) = 0;
      break;

    case Y_CFC1_OP:
      /* What to do? */
      break;

    case Y_CTC1_OP:
      /* What to do? */
      break;

    case Y_CVT_D_S_OP:
    case Y_CVT_D_W_OP:
    case Y_CVT_S_D_OP:
    case Y_CVT_S_W_OP:
    case Y_CVT_W_D_OP:
    case Y_CVT_W_S_OP:
      Count (ps) = ((Count (ps) == 0) ? 0 : Count (ps) - 1);
      break;

    case Y_DIV_S_OP:
    case Y_DIV_D_OP:
      Count (ps) = ((Count (ps) == 0) ? 0 : Count (ps) - 1);
      break;

    case Y_LWC1_OP:
    case Y_MFC1_OP:
    case Y_MTC1_OP:
      Count (ps) = 0;
      break;

    case Y_MOV_S_OP:
    case Y_MOV_D_OP:
    case Y_NEG_S_OP:
    case Y_NEG_D_OP:
    case Y_SUB_S_OP:
    case Y_SUB_D_OP:
      Count (ps) = ((Count (ps) == 0) ? 0 : Count (ps) - 1);
      break;

    case Y_MUL_S_OP:
    case Y_MUL_D_OP:
      Count (ps) = ((Count (ps) == 0) ? 0 : Count (ps) - 1);
      break;

    default:
      /* What to do?  */
      break;
    }

  return (excpt);

}




/* Process FPA FWB */

#ifdef __STDC__
static int
process_f_fwb (PIPE_STAGE ps)
#else
static int
process_f_fwb (ps)
  PIPE_STAGE ps;
#endif
{ instruction *inst;

  inst = ps->inst;

  switch (OPCODE (inst))
    { 	  /* FPA Operations */

    case Y_DIV_S_OP:
      set_present(FD (inst));
      SET_FPR_S (FD (inst), FPvalue (ps));
      break;

    case Y_DIV_D_OP:
      set_present(FD (inst));
      SET_FPR_D (FD (inst), FPvalue (ps));
      break;

    case Y_MUL_S_OP:
      set_present(FD (inst));
      SET_FPR_S (FD (inst), FPvalue (ps));
      break;

    case Y_MUL_D_OP:
      set_present(FD (inst));
      SET_FPR_D (FD (inst), FPvalue (ps));
      break;

    case Y_ABS_S_OP:
      set_present(FD (inst));
      SET_FPR_S (FD (inst), FPvalue (ps));
      break;

    case Y_ABS_D_OP:
      set_present(FD (inst));
      SET_FPR_D (FD (inst), FPvalue (ps));
      break;

    case Y_ADD_S_OP:
      set_present(FD (inst));
      SET_FPR_S (FD (inst), FPvalue (ps));
      /* Should trap on inexact/overflow/underflow */
      break;

    case Y_ADD_D_OP:
      { set_present(FD (inst));
	SET_FPR_D (FD (inst), FPvalue (ps));

	/* Should trap on inexact/overflow/underflow */
	break;
      }

    case Y_C_F_S_OP:
    case Y_C_UN_S_OP:
    case Y_C_EQ_S_OP:
    case Y_C_UEQ_S_OP:
    case Y_C_OLE_S_OP:
    case Y_C_ULE_S_OP:
    case Y_C_SF_S_OP:
    case Y_C_NGLE_S_OP:
    case Y_C_SEQ_S_OP:
    case Y_C_NGL_S_OP:
    case Y_C_LT_S_OP:
    case Y_C_NGE_S_OP:
    case Y_C_LE_S_OP:
    case Y_C_NGT_S_OP:
      /* Nothing to do.  FpCond is computed in EX1 and
	 written in EX2.  */
      break;

    case Y_C_F_D_OP:
    case Y_C_UN_D_OP:
    case Y_C_EQ_D_OP:
    case Y_C_UEQ_D_OP:
    case Y_C_OLE_D_OP:
    case Y_C_ULE_D_OP:
    case Y_C_SF_D_OP:
    case Y_C_NGLE_D_OP:
    case Y_C_SEQ_D_OP:
    case Y_C_NGL_D_OP:
    case Y_C_LT_D_OP:
    case Y_C_NGE_D_OP:
    case Y_C_LE_D_OP:
    case Y_C_NGT_D_OP:
      /* Nothing to do.  FpCond is computed in EX1 and
	 written in EX2.  */
      break;

    case Y_CFC1_OP:
      /* What to do? */
      break;

    case Y_CTC1_OP:
      /* What to do? */
      break;

    case Y_CVT_D_S_OP:
      set_present(FD (inst));
      SET_FPR_D (FD (inst), FPvalue (ps));
      break;

    case Y_CVT_D_W_OP:
      set_present(FD (inst));
      SET_FPR_D (FD (inst), FPvalue (ps));
      break;

    case Y_CVT_S_D_OP:
      set_present(FD (inst));
      SET_FPR_S (FD (inst), FPvalue (ps));
      break;

    case Y_CVT_S_W_OP:
      set_present(FD (inst));
      SET_FPR_S (FD (inst), FPvalue (ps));
      break;

    case Y_CVT_W_D_OP:
      { int val = FPvalue (ps);
	set_present(FD (inst));
	SET_FPR_W (FD (inst), val);
	break;
      }

    case Y_CVT_W_S_OP:
      set_present(FD (inst));
      SET_FPR_W (FD (inst), FPvalue (ps));
      break;


    case Y_LWC1_OP:
      {
	reg_word word;
	float *wp = (float *) &word;


	word = VALUE (ps);
	set_single_present(FT (inst));
	FGR [FT (inst)] = *wp; /* Fool coercion */

      }


    case Y_MFC1_OP:
      /* Nothing to do */
      break;


    case Y_MOV_S_OP:
      set_present(FD (inst));
      SET_FPR_S (FD (inst), FPvalue (ps));
      break;

    case Y_MOV_D_OP:
      set_present(FD (inst));
      SET_FPR_D (FD (inst), FPvalue (ps));
      break;

    case Y_MTC1_OP:
      { reg_word word = VALUE (ps);
	float *wp = (float *) &word;

	word = VALUE (ps);
	set_single_present(RD (inst));
	FGR [RD (inst)] = *wp; /* RD not FS, fool coercion */
	break;
      }

    case Y_NEG_S_OP:
      set_present(FD (inst));
      SET_FPR_S (FD (inst), FPvalue (ps));
      break;

    case Y_NEG_D_OP:
      set_present(FD (inst));
      SET_FPR_D (FD (inst), FPvalue (ps));
      break;

    case Y_SUB_S_OP:
      set_present(FD (inst));
      SET_FPR_S (FD (inst), FPvalue (ps));
      break;

    case Y_SUB_D_OP:
      set_present(FD (inst));
      SET_FPR_D (FD (inst), FPvalue (ps));
      break;

    default:
      fatal_error ("Unknown instruction type: %d\n", OPCODE (inst));
      break;
    }
}



/* Auxiliary functions. */
PIPE_STAGE head_pool;

#ifdef __STDC__
static void
init_stage_pool (void)
#else
static void
init_stage_pool ()
#endif
{
  PIPE_STAGE tmp;
  int i;

  head_pool = (PIPE_STAGE) malloc(12 * sizeof(struct pipe_stage));
  tmp = head_pool;

  /* chain up the pool of entries */
  for (i=0; i < 11; i++) {
    tmp->next = tmp + 1;
    tmp = tmp->next;
  }

  /* fix up the end */
  tmp->next = NULL;
}


#ifdef __STDC__
static PIPE_STAGE
stage_alloc (void)
#else
static PIPE_STAGE
stage_alloc ()
#endif
{
  PIPE_STAGE tmp;

  if (head_pool == NULL)
    init_stage_pool();

  tmp = head_pool;
  head_pool = head_pool->next;
  tmp->exception = 0;
  tmp->next = NULL;
  return tmp;
}


#ifdef __STDC__
static int
stage_dealloc (PIPE_STAGE ps)
#else
static int
stage_dealloc (ps)
  PIPE_STAGE ps;
#endif
{
  if (ps == NULL)
    return(0);

  if (head_pool == NULL) {
    head_pool = ps;
    ps->next = NULL;
  }
  else {
    ps->next = head_pool;
    head_pool = ps;
  }
}



#ifdef __STDC__
static int
pipe_dealloc (int stage, PIPE_STAGE alu[], PIPE_STAGE fpa[])
#else
static int
pipe_dealloc (stage, alu, fpa)
  int stage;
  PIPE_STAGE alu[], fpa[];
#endif
{
  int i;

  for(i=0; i < stage; i++) {
    stage_dealloc(alu[i]);
    alu[i] = NULL;
    stage_dealloc(fpa[i]);
    fpa[i] = NULL;
  }
}




#ifdef __STDC__
static void
long_multiply (reg_word v1, reg_word v2, reg_word *hi, reg_word *lo)
#else
static void
long_multiply (v1, v2, hi, lo)
     reg_word v1, v2;
     reg_word *hi, *lo;
#endif
{
  register long a, b, c, d;
  register long bd, ad, cb, ac;
  register long mid, mid2, carry_mid = 0;

  a = (v1 >> 16) & 0xffff;
  b = v1 & 0xffff;
  c = (v2 >> 16) & 0xffff;
  d = v2 & 0xffff;

  bd = b * d;
  ad = a * d;
  cb = c * b;
  ac = a * c;

  mid = ad + cb;
  if (ARITH_OVFL (mid, ad, cb))
    carry_mid = 1;

  mid2 = mid + ((bd >> 16) & 0xffff);
  if (ARITH_OVFL (mid2, mid, ((bd >> 16) & 0xffff)))
    carry_mid += 1;

  *lo = (bd & 0xffff) | ((mid2 & 0xffff) << 16);
  *hi = ac + (carry_mid << 16) + ((mid2 >> 16) & 0xffff);
}



#ifdef __STDC__
void
print_pipeline (void)
#else
void
print_pipeline ()
#endif
{
  char *buf;
  int limit;

  buf = (char *) malloc (8*K);
  *buf = '\0';
  limit = 8*K;

  print_pipeline_internal (buf);
  write_output (pipe_out, buf);
  free (buf);
}


#ifdef __STDC__
void
print_pipeline_internal (char *buf)
#else
void
print_pipeline_internal (buf)
  char *buf;
#endif
{
  int i;
  PIPE_STAGE tmp;

  sprintf(buf,"*** Control processor pipeline\n");
  buf += strlen(buf);

  sprintf (buf, "WB\t"); buf += strlen(buf);
  if (alu[WB]) {
    buf += print_inst_internal (buf, 8*K, alu[WB]->inst, alu[WB]->pc) - 1;
    if (EXCPT(alu[WB])) {
      sprintf (buf, "\t[%s EXCPT]", EXCPT_STR((EXCPT(alu[WB])>>2) & 0xf));
      buf += strlen(buf);
    }
  }
  else {
    sprintf (buf, "<none>");
    buf += strlen(buf);
  }
  sprintf (buf++, "\n");

  sprintf (buf, "MEM\t"); buf += strlen(buf);
  if (alu[MEM]) {
    buf += print_inst_internal (buf, 8*K, alu[MEM]->inst, alu[MEM]->pc) - 1;
    if (EXCPT(alu[MEM])) {
      sprintf (buf, "\t[%s EXCPT]", EXCPT_STR((EXCPT(alu[MEM])>>2) & 0xf));
      buf += strlen(buf);
    }
    if (STAGE(alu[MEM]) == MEM_STALL) {
      sprintf(buf,"\t(STALLED)");
      buf += strlen(buf);
    }
  }
  else {
    sprintf (buf, "<none>");
    buf += strlen(buf);
  }
  sprintf (buf++, "\n");

  sprintf (buf, "EX\t"); buf += strlen(buf);
  if (alu[EX]) {
    buf += print_inst_internal (buf, 8*K, alu[EX]->inst, alu[EX]->pc) - 1;
    if (EXCPT(alu[EX])) {
      sprintf (buf, "\t[%s EXCPT]", EXCPT_STR(EXCPT(alu[EX])>>2 & 0xf));
      buf += strlen(buf);
    }
  }
  else {
    sprintf (buf,"<none>");
    buf += strlen(buf);
  }
  sprintf (buf++, "\n");

  sprintf (buf, "ID\t"); buf += strlen(buf);
  if (alu[ID]) {
    buf += print_inst_internal (buf, 8*K, alu[ID]->inst, alu[ID]->pc) - 1;
    if (EXCPT(alu[ID])) {
      sprintf (buf, "\t[%s EXCPT]", EXCPT_STR((EXCPT(alu[ID])>>2) & 0xf));
      buf += strlen(buf);
    }
  }
  else {
    sprintf (buf,"<none>");
    buf += strlen(buf);
  }
  sprintf (buf++, "\n");

  sprintf (buf, "IF\t"); buf += strlen(buf);
  if (alu[IF]) {
    buf += print_inst_internal (buf, 8*K, alu[IF]->inst, alu[IF]->pc) - 1;
    if (STAGE(alu[IF]) == IF_STALL) {
      sprintf(buf,"\t(STALLED)");
      buf += strlen(buf);
    }
  }
  else {
    sprintf (buf, "<none>");
    buf += strlen(buf);
  }
  sprintf (buf++, "\n");

  sprintf (buf, "*** Multiply/Divide Unit\n"); buf += strlen(buf);
  sprintf (buf, "HI 0x%08x\tLO 0x%08x\n", MDU.hi_val, MDU.lo_val);
  buf += strlen(buf);

  sprintf (buf, "*** Floating point pipeline\n"); buf += strlen(buf);

  sprintf (buf, "FWB\t"); buf += strlen(buf);

  tmp = fpa[FPA_FWB];
  for (i = 0; i < 2; i++)
    {
      if (i>0) {
	sprintf (buf, "\t");
	buf++;
      }
      if (!tmp)	{
	sprintf (buf,"<none>");
	buf += strlen(buf);
      }
      else {
	buf += print_inst_internal (buf, 8*K, tmp->inst, tmp->pc) - 1;
	tmp = tmp->next;
      }
      sprintf (buf++, "\n");
    }

  sprintf (buf, "FEX3\t"); buf += strlen(buf);
  tmp = fpa[FPA_EX3];
  for (i = 0; i < 4; i++)
    {
      if (i>0) {
	sprintf (buf, "\t");
	buf++;
      }
      if (!tmp)	{
	sprintf (buf,"<none>");
	buf += strlen(buf);
      }
      else {
	buf += print_inst_internal (buf, 8*K, tmp->inst, tmp->pc) - 1;
	tmp = tmp->next;
      }
      sprintf (buf++, "\n");
    }

  sprintf (buf, "FEX2\t"); buf += strlen(buf);
  if (fpa[FPA_EX2])
    buf += print_inst_internal(buf, 8*K,fpa[FPA_EX2]->inst,fpa[FPA_EX2]->pc) - 1;
  else {
    sprintf (buf,"<none>");
    buf += strlen(buf);
  }
  sprintf (buf++, "\n");

   sprintf (buf, "FEX1\t"); buf += strlen(buf);
  if (fpa[FPA_EX1])
    buf += print_inst_internal(buf, 8*K,fpa[FPA_EX1]->inst,fpa[FPA_EX1]->pc) - 1;
  else {
    sprintf (buf,"<none>");
    buf += strlen(buf);
  }
  sprintf (buf++, "\n");

  sprintf (buf, "*** Bypass Registers, Values\n");
  buf += strlen(buf);

  sprintf (buf, "MEM %$%d 0x%08x   EX %$%d 0x%08x\n",MEM_bp_reg, MEM_bp_val, EX_bp_reg, EX_bp_val);
  buf += strlen(buf);

  sprintf (buf, "*** Write Back Buffer\n");
  buf += strlen(buf);

  sprintf (buf, "%s\n", print_write_buffer());
  buf += strlen(buf);
}


