/*
Freely Distributable C30 Simulator Package

Copyright (c) 1996-1998 The University of Texas
All Rights Reserved.

This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
 
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.
 
The GNU Public License is available in the file LICENSE, or you
can write to the Free Software Foundation, Inc., 59 Temple Place -
Suite 330, Boston, MA 02111-1307, USA, or you can find it on the
World Wide Web at http://www.fsf.org.

Authors: Chi Duong, Brian Evans, and Chris Moy
Version: @(#)execute.cc	1.34	01/19/98

Department of Electrical and Computer Engineering
The University of Texas, Austin, TX 78712-1084
 */

#include <math.h>
#include <string.h>                                         
#include "state.h"
#include "pipeline.h"
#include "execute.h"
#include "tmsfloat.h"
#include "memmap.h"
#include "simmisc.h"

#define C30SIM_UINT32_TO_DOUBLE(s) (double)((int32)(s)) 

// Enable this file to be compiled under either C or C++ 

#ifndef __cpluscplus
#define inline
#endif

// Arithmetic operations

#define C30SIM_ADD_FLOAT 0
#define C30SIM_SUB_FLOAT 1
#define C30SIM_MUL_FLOAT 2

// Define a lookup table for condition codes

#define C30SIM_NUM_CONDITION_CODES 20

static int CondRegisterMask[] = {
// 20 condition codes are from 00000 to 10100, excluding 01011
  0,
  C30_CONDFLAG_CARRY,
  (C30_CONDFLAG_CARRY|C30_CONDFLAG_ZERO),
  (C30_CONDFLAG_CARRY|C30_CONDFLAG_ZERO),
  C30_CONDFLAG_CARRY,
  C30_CONDFLAG_ZERO,
  C30_CONDFLAG_ZERO,
  C30_CONDFLAG_NEGATIVE,
  (C30_CONDFLAG_NEGATIVE|C30_CONDFLAG_ZERO),
  (C30_CONDFLAG_NEGATIVE|C30_CONDFLAG_ZERO),
  C30_CONDFLAG_NEGATIVE,
  0,
  C30_CONDFLAG_OVERFLOW,
  C30_CONDFLAG_OVERFLOW,
  C30_CONDFLAG_UNDERFLOW,
  C30_CONDFLAG_UNDERFLOW,
  C30_CONDFLAG_LATCHED_OVERFLOW,
  C30_CONDFLAG_LATCHED_OVERFLOW,
  C30_CONDFLAG_LATCHED_UNDERFLOW,
  C30_CONDFLAG_LATCHED_UNDERFLOW,
  (C30_CONDFLAG_ZERO|C30_CONDFLAG_UNDERFLOW)
};

static int CondRegisterEqu[] = {
// 20 condition codes are from 00000 to 10100, excluding 01011
  0,
  C30_CONDFLAG_CARRY,
  C30_CONDFLAG_CARRY,     			/* cond 2, or with C30_CONDFLAG_ZERO */
  0,
  0,
  C30_CONDFLAG_ZERO,
  0,
  C30_CONDFLAG_NEGATIVE,
  C30_CONDFLAG_NEGATIVE,         /* cond 8, or with C30_CONDFLAG_ZERO */
  0,
  0,
  1,
  0,
  C30_CONDFLAG_OVERFLOW,
  0,
  C30_CONDFLAG_UNDERFLOW,
  0,
  C30_CONDFLAG_LATCHED_OVERFLOW,
  0,
  C30_CONDFLAG_LATCHED_UNDERFLOW,
  C30_CONDFLAG_UNDERFLOW			/* cond 20, or with C30_CONDFLAG_ZERO */
};

// Test conditional codes using a fast constant-time table lookup.
// Compared with a switch statement, this approach always guarantees
// constant-time lookup regardless of the compiler or optimization
// level used.

static inline int testConditionalCodes(state * st) {
  // Guard against indexing the array out-of-bounds
  int i;
  for(i=0; i<2; i++) {
    if (st->cond[i].flag==0) {
    	if (st->cond[i].val < 0 ||
  			 st->cond[i].val > C30SIM_NUM_CONDITION_CODES)
        return 0;
        //return (st->st & CondRegisterMask[st->cond[i].val]);
      switch (st->cond[i].val) {
      	case 2:
         case 8:
         case 20: if ((st->st & CondRegisterMask[st->cond[i].val])==C30_CONDFLAG_ZERO)
         				return 1;
         default: return (((int32)st->st & CondRegisterMask[st->cond[i].val])==
          						CondRegisterEqu[st->cond[i].val]);
    	}
    }
  }
  return 0;
}

inline void swap_operand(uint32 * op1, uint32 * op2) {
  uint32 temp = *op1;
  *op1 = *op2;
  *op2 = temp;
}

inline void update_arn_s_and_st (pipeline * pipe, state * st) {
  if ((&st->ar0 <= pipe->finalDest1) &&
      (pipe->finalDest1 <= &st->ar7))
      *(pipe->finalDest1-8) = *pipe->finalDest1;
  else if (pipe->finalDest1==&st->st)
      //some of st->st bits are reserved bits 
      *pipe->finalDest1 &= 0x00003dff;
}

static inline void stf_dest1(pipeline * pipe) {
   // FIXME: We do not guard against overwriting ROM on the C30.
   // This is not an issue in the other C3x processors.  The
   // fix should be encoded at a level higher than this file.
   *pipe->finalDest1 = pipe->opfloat1;
}

static inline void stf_dest2(pipeline * pipe) {
   // FIXME: We do not guard against overwriting ROM on the C30.
   // This is not an issue in the other C3x processors.  The
   // fix should be encoded at a level higher than this file.
   *pipe->finalDest2 = pipe->opfloat3;
}

static inline void sti_dest1(pipeline * pipe){
   // FIXME: We do not guard against overwriting ROM on the C30.
   // This is not an issue in the other C3x processors.  The
   // fix should be encoded at a level higher than this file.
   *pipe->finalDest1 = pipe->oprnd1;
}

static inline void sti_dest2(pipeline * pipe) {
   // FIXME: We do not guard against overwriting ROM on the C30.
   // This is not an issue in the other C3x processors.  The 
   // fix should be encoded at a level higher than this file.
   *pipe->finalDest2 = pipe->oprnd3;
}


// 8 exponent bits are stored in the 8-MSBs of the exp register
static inline uint32 dsp_float_40to32_bit(uint32 exp, uint32 man) {
  // chop off 8-LSBs
  return (exp | ((man >> 8) & 0x00ffffffL));
}

static inline void dsp_float_32to40_bit(uint32 dsp32, uint32* exp, uint32* man) {
  *exp = (dsp32 & 0xff000000L);
  *man = (dsp32 << 8);
}

static inline int float_arith_on_arg_1(pipeline* pipe, int operation,
                                  uint32* exp1, uint32* man1, double* test1) {
  uint32 src1 = dsp_float_40to32_bit(pipe->opexp1, pipe->opfloat1);
  uint32 src2 = dsp_float_40to32_bit(pipe->opexp2, pipe->opfloat2);
  float op1 = TMS_IEEE(src1);
  float op2 = TMS_IEEE(src2);
  float dstIEEE;
  switch (operation) {
    case C30SIM_ADD_FLOAT:
      dstIEEE = op1 + op2;
      *test1 = (double) op1 + (double) op2;
      break;
    case C30SIM_SUB_FLOAT:
      dstIEEE = op2 - op1;
      *test1 = (double) op2 - (double) op1;
      break;
    case C30SIM_MUL_FLOAT:
      dstIEEE = op1 * op2;
      *test1 = (double) op1 * (double) op2;
      break;
    default:
      *test1 = 0.0;
      return 1;
  }
  c30reg dstTMS = IEEE_TMS(dstIEEE);
  dsp_float_32to40_bit(dstTMS, exp1, man1);
  return 0;
}

static inline int float_arith_on_arg_2(pipeline* pipe, int operation,
                                  uint32* exp2, uint32* man2, double* test2) {

  uint32 src3 = dsp_float_40to32_bit(pipe->opexp3, pipe->opfloat3);
  uint32 src4 = dsp_float_40to32_bit(pipe->opexp4, pipe->opfloat4);
  float op3 = TMS_IEEE(src3);
  float op4 = TMS_IEEE(src4);
  float dstIEEE;
  switch (operation) {
    case C30SIM_ADD_FLOAT:
      dstIEEE = op3 + op4;
      *test2 = (double) op3 + (double) op4;
      break;
    case C30SIM_SUB_FLOAT:
      dstIEEE = op3 - op4;
      *test2 = (double) op3 - (double) op4;
      break;
    case C30SIM_MUL_FLOAT:
      dstIEEE = op3 * op4;
      *test2 = (double) op3 * (double) op4;
      break;
    default:
      *test2 = 0.0;
      return 1;
  }

  c30reg dstTMS = IEEE_TMS(dstIEEE);
  dsp_float_32to40_bit(dstTMS, exp2, man2);
  return 0;
}


static inline void update_rxn_of_dest1(pipeline* pipe) {
  int32 temp = (*pipe->finalDest1 >> 8) & 0x00ffffffff;
  *(pipe->finalDest1 + 1) = (*(pipe->finalDest1 + 1) & 0xff000000) | temp;
}

static inline void update_rxn_of_dest2(pipeline* pipe) {
  int32 temp = (*pipe->finalDest2 >> 8) & 0x00ffffffff;
  *(pipe->finalDest2 + 1) = (*(pipe->finalDest2 + 1) & 0xff000000) | temp;
}

static inline void update_float_status(state* st, double temp) {
  st->st &= ~C30_CONDFLAG_UNDERFLOW;
  if ((temp > C30_MAX_FLOAT) || (temp < C30_MIN_FLOAT))
    st->st |= (C30_CONDFLAG_LATCHED_OVERFLOW | C30_CONDFLAG_OVERFLOW);
  else
    st->st &= ~C30_CONDFLAG_OVERFLOW;
  if (temp<0)
    st->st |= C30_CONDFLAG_NEGATIVE;
  else
    st->st &= ~C30_CONDFLAG_NEGATIVE;

  if (temp)
    st->st &= ~C30_CONDFLAG_ZERO;
  else
    st->st |= C30_CONDFLAG_ZERO;
}

static inline void set_with_status_float(pipeline* pipe, state* st, double temp, uint32 exp, uint32 man) {
  if (((temp > 0) && (temp < C30_EPSILON)) ||
      ((temp < 0) && (temp > -C30_EPSILON))) {
      *(pipe->finalDest1 + 1) = 0x80000000L;
      *pipe->finalDest1 = 0;
      st->st |= (C30_CONDFLAG_UNDERFLOW | C30_CONDFLAG_LATCHED_UNDERFLOW);
  }
  else {
  		*pipe->finalDest1 = man;
	  	*(pipe->finalDest1 + 1) = exp;
  		update_rxn_of_dest1(pipe);
      update_float_status(st, temp);
  }
}

static inline void set_P_float_status(state* st,double test1,double test2){
  st->st &= ~C30_CONDFLAG_ZERO;
  st->st &= ~C30_CONDFLAG_NEGATIVE;
  if (((test1 > 0) && (test1 < C30_EPSILON)) ||
      ((test1 < 0) && (test1 > -C30_EPSILON)) ||
      ((test2 > 0) && (test2 < C30_EPSILON)) ||
      ((test2 < 0) && (test2 > -C30_EPSILON)))
    st->st |= (C30_CONDFLAG_LATCHED_UNDERFLOW | C30_CONDFLAG_UNDERFLOW);
  else
    st->st &= ~C30_CONDFLAG_UNDERFLOW;
  if ((test1 > C30_MAX_FLOAT) || (test1 < C30_MIN_FLOAT) ||
      (test2 > C30_MAX_FLOAT) || (test2 < C30_MIN_FLOAT))
    st->st |= (C30_CONDFLAG_LATCHED_OVERFLOW | C30_CONDFLAG_OVERFLOW);
  else
    st->st &= ~C30_CONDFLAG_OVERFLOW;
}

static inline void set_dest_float1(pipeline* pipe,uint32 exp1,uint32 man1) {
    *pipe->finalDest1 = man1;
    *(pipe->finalDest1 + 1) = exp1;
    update_rxn_of_dest1(pipe);
}                                                                   

static inline void set_dest_float2(pipeline* pipe,uint32 exp2,uint32 man2){
    *pipe->finalDest2 = man2;
    *(pipe->finalDest2 + 1) = exp2;
    update_rxn_of_dest2(pipe);
}

static inline void set1_with_OVM(pipeline* pipe, state* st, double temp, int32 tempH) {
  if (st->st & C30_CONDFLAG_OVM) {
    if (C30SIM_UINT32_TO_DOUBLE(C30_MIN_SIGNED_INT) > temp)
      *pipe->finalDest1 = 0x80000000L;
    else if (C30SIM_UINT32_TO_DOUBLE(C30_MAX_SIGNED_INT) < temp)
      *pipe->finalDest1 = 0x7fffffffL;
  }
  else
    	*pipe->finalDest1 = tempH;

  if ((&st->Sregs[__r0] <= pipe->finalDest1) &&
      (pipe->finalDest1 <= &st->Sregs[__r7]))
    	update_rxn_of_dest1(pipe);
}

static inline void set2_with_OVM(pipeline* pipe, state* st, double temp, int32 tempH) {
  if (st->st & C30_CONDFLAG_OVM) {
    if (C30SIM_UINT32_TO_DOUBLE(C30_MIN_SIGNED_INT) > temp)
      *pipe->finalDest2 = 0x80000000L;
    else if (C30SIM_UINT32_TO_DOUBLE(C30_MAX_SIGNED_INT) < temp)
      *pipe->finalDest2 = 0x7fffffffL;
  }
  else
    	*pipe->finalDest2 = tempH;

  if ((&st->Sregs[__r0] <= pipe->finalDest2) &&
      (pipe->finalDest2 <= &st->Sregs[__r7]))
    	update_rxn_of_dest2(pipe);
}

static inline void uf_v_lv_z_n_ARITH(pipeline* pipe, state* st, double temp) { 
  st->st &= ~C30_CONDFLAG_UNDERFLOW;
  if ((C30SIM_UINT32_TO_DOUBLE(C30_MIN_SIGNED_INT) > temp) ||
      (temp > C30SIM_UINT32_TO_DOUBLE(C30_MAX_SIGNED_INT))) {
    st->st |= C30_CONDFLAG_OVERFLOW;
    st->st |= C30_CONDFLAG_LATCHED_OVERFLOW;
  }
  else  
    st->st &= ~C30_CONDFLAG_OVERFLOW;
  
  if (*pipe->finalDest1 == 0)
    st->st |= C30_CONDFLAG_ZERO;
  else
    st->st &= ~C30_CONDFLAG_ZERO;
  if ((int32)*pipe->finalDest1 < 0)
    st->st |= C30_CONDFLAG_NEGATIVE;
  else
    st->st &= ~C30_CONDFLAG_NEGATIVE;
}

static inline void uf_n_z_v_logical(state* st, uint32 dest) { 
  st->st &= ~C30_CONDFLAG_UNDERFLOW;
  st->st &= ~C30_CONDFLAG_OVERFLOW;
  if (dest & 0x80000000L )
    st->st |= C30_CONDFLAG_NEGATIVE;
  else
    st->st &= ~C30_CONDFLAG_NEGATIVE;
  if (dest)
    st->st &= ~C30_CONDFLAG_ZERO;
  else
    st->st |= C30_CONDFLAG_ZERO;
}

// Simulator functions to emulator C30 opcodes

// take twos-complement of the mantissa, and keep the exponent the same 
// if mantissa = 0x80000000L, set mantissa = 0, exponent++ 
void S_absf(pipeline* pipe, state* st) {
  c30reg statusReg = st->st;
  uint32 man = pipe->opfloat1;
  uint32 exp = pipe->opexp1;
  statusReg &= ~C30_CONDFLAG_UNDERFLOW;
  statusReg &= ~C30_CONDFLAG_NEGATIVE;
  if (man == 0x80000000L) {
    if (exp == 0x7fL) {
      statusReg |= (C30_CONDFLAG_LATCHED_OVERFLOW |
              C30_CONDFLAG_OVERFLOW);
      statusReg &= ~C30_CONDFLAG_ZERO;
      man = 0x7fffffffL;
    }
    else  {
      man = 0;
      ++exp;  
      statusReg |= C30_CONDFLAG_ZERO;
      statusReg &= ~C30_CONDFLAG_OVERFLOW;
    }
  }
  else {
  		statusReg &= ~C30_CONDFLAG_OVERFLOW;
  		statusReg &= ~C30_CONDFLAG_ZERO;
      if ((int32)man < 0)
        man = -(int32)man;
 }

  if ((&st->Sregs[__r0] <= pipe->finalDest1) && 
      (pipe->finalDest1 <= &st->Sregs[__r7])) {
    st->st = statusReg;
    *pipe->finalDest1 = man;
    *(pipe->finalDest1 + 1) = exp;
    update_rxn_of_dest1(pipe);
  }
  else
    *pipe->finalDest1 = dsp_float_40to32_bit(exp,man);
}

void S_absf_stf(pipeline* pipe, state* st) {
  S_absf(pipe,st);
  stf_dest2(pipe);
}

inline void S_absi(pipeline* pipe, state* st) {
  c30reg statusReg = st->st;
  statusReg &= ~C30_CONDFLAG_UNDERFLOW;
  statusReg &= ~C30_CONDFLAG_NEGATIVE;
  if (pipe->oprnd1 == 0x80000000L) {
    statusReg |= C30_CONDFLAG_LATCHED_OVERFLOW;
    statusReg &= ~C30_CONDFLAG_ZERO;
    statusReg |= C30_CONDFLAG_OVERFLOW;
    if (statusReg & C30_CONDFLAG_OVM) 
      *(pipe->finalDest1) = 0x7fffffffL;
        else
      *(pipe->finalDest1) = 0x80000000L;
  }
  else {
    statusReg &= ~C30_CONDFLAG_OVERFLOW;
    if ((int32)pipe->oprnd1 < 0)
      *(pipe->finalDest1) = -(int32)pipe->oprnd1;
    else 
      *(pipe->finalDest1) = pipe->oprnd1;
    if (pipe->oprnd1) 
      statusReg &= ~C30_CONDFLAG_ZERO;
    else 
      statusReg |= C30_CONDFLAG_ZERO; 
  }
  if ((&st->Sregs[__r0] <= pipe->finalDest1) && 
      (pipe->finalDest1 <= &st->Sregs[__r7])) {
    update_rxn_of_dest1(pipe);
    st->st = statusReg;
  }
  update_arn_s_and_st(pipe,st);
}

void S_absi_sti(pipeline* pipe, state* st)  {
	sti_dest2(pipe);
	S_absi(pipe,st);
}

inline void S_addc(pipeline* pipe, state* st)  {
  double temp = C30SIM_UINT32_TO_DOUBLE(pipe->oprnd1) +
                      C30SIM_UINT32_TO_DOUBLE(pipe->oprnd2) +
                (st->st & C30_CONDFLAG_CARRY);
  int32 tempH = (int32)pipe->oprnd1 + (int32)pipe->oprnd2 +
          (st->st & C30_CONDFLAG_CARRY);

  set1_with_OVM(pipe, st, temp, tempH);
 
  if ((&st->Sregs[__r0] <= pipe->finalDest1) &&
     (pipe->finalDest1 <= &st->Sregs[__r7])) {
    update_rxn_of_dest1(pipe);
      uf_v_lv_z_n_ARITH(pipe, st, temp);
    	if (st->st & C30_CONDFLAG_OVERFLOW)
     		st->st |= C30_CONDFLAG_CARRY;
      else
      	st->st &= ~C30_CONDFLAG_CARRY;
  	//}
  }
  update_arn_s_and_st(pipe,st);
}

void S_addc3(pipeline* pipe, state* st)  {
  S_addc(pipe, st);
}

inline void S_addf(pipeline* pipe, state* st){
  uint32 exp1=0, man1=0;
  double test1=0;
  float_arith_on_arg_1(pipe, C30SIM_ADD_FLOAT, &exp1, &man1, &test1);
  set_with_status_float(pipe,st,test1,exp1,man1);
}

void S_addf3(pipeline* pipe, state* st)  {
  S_addf(pipe,st);
}

void S_addf3_stf(pipeline* pipe, state* st){
  S_addf(pipe,st);
  stf_dest2(pipe);
}

inline void S_addi(pipeline* pipe, state* st)  {
  double temp = C30SIM_UINT32_TO_DOUBLE(pipe->oprnd1) +
          C30SIM_UINT32_TO_DOUBLE(pipe->oprnd2);
  int32 tempH = (int32)pipe->oprnd1 + (int32)pipe->oprnd2;
  set1_with_OVM(pipe, st, temp, tempH);
  if ((&st->Sregs[__r0] <= pipe->finalDest1) &&
      (pipe->finalDest1 <= &st->Sregs[__r7])) {
    update_rxn_of_dest1(pipe);
      uf_v_lv_z_n_ARITH(pipe, st, temp);
    	if (st->st & C30_CONDFLAG_OVERFLOW)
      	st->st |= C30_CONDFLAG_CARRY;
    	else
      	st->st &= ~C30_CONDFLAG_CARRY;
      // FIXME: how to set carry bit?
    //}
  }
  update_arn_s_and_st(pipe,st);
}

void S_addi3(pipeline* pipe, state* st)  {
  S_addi(pipe, st);
}

void S_addi3_sti(pipeline* pipe, state* st)  {
  sti_dest2(pipe);
  S_addi(pipe, st);
}

inline void S_and(pipeline* pipe, state* st)  {
  *(pipe->finalDest1) = (pipe->oprnd1 & pipe->oprnd2);
  if ((&st->Sregs[__r0] <= pipe->finalDest1) &&
      (pipe->finalDest1 <= &st->Sregs[__r7]))  {
    update_rxn_of_dest1(pipe);
    uf_n_z_v_logical(st,*pipe->finalDest1);
  }
  update_arn_s_and_st(pipe,st);
}

void S_and3(pipeline* pipe, state* st)  {
  S_and(pipe, st);
}

void S_and3_sti(pipeline* pipe, state* st) {
  sti_dest2(pipe);
  S_and(pipe,st);
}

inline void S_andn(pipeline* pipe, state* st)  {
  *(pipe->finalDest1) = ~pipe->oprnd1 & pipe->oprnd2;
  if ((&st->Sregs[__r0] <= pipe->finalDest1) && 
      (pipe->finalDest1 <= &st->Sregs[__r7])) {
    update_rxn_of_dest1(pipe);
    uf_n_z_v_logical(st,*pipe->finalDest1);
  }
  update_arn_s_and_st(pipe,st);
}

void S_andn3(pipeline* pipe, state* st)  {
  S_andn(pipe, st);
}

inline void S_ash(pipeline* pipe, state* st) {
  int32 count = pipe->oprnd1 & 0x00000080;     //count is the signed 7-LSB of oprnd1
  if(count)                                    //sign extend for count
  	 count = pipe->oprnd1 | 0xffffff00;
  else
  	 count = pipe->oprnd1 & 0x000000ff;
  int32 src = (int32)pipe->oprnd2;
  c30reg statusReg = st->st;

  // FIXME: when does overflow occur ?
  statusReg &= ~C30_CONDFLAG_LATCHED_OVERFLOW;
  statusReg &= ~C30_CONDFLAG_OVERFLOW;  
  
  statusReg &= ~C30_CONDFLAG_UNDERFLOW;
  
  if (count>0) {
    src <<= (count - 1);
    if (src & 0x80000000L){
      statusReg |= C30_CONDFLAG_CARRY;
      statusReg |= C30_CONDFLAG_LATCHED_OVERFLOW;
      statusReg |= C30_CONDFLAG_OVERFLOW;
    }
    else {
      statusReg &= ~C30_CONDFLAG_CARRY;
      statusReg &= ~C30_CONDFLAG_OVERFLOW;
    }
    src <<= 1;
  }
  else if (count<0) {
// printf("src0 is 0x%08x\n", src);
    src >>= (-count - 1);   // sign-extended automatically !!!
// printf("src1 is 0x%08x\n", src);
    statusReg &= ~C30_CONDFLAG_OVERFLOW;
    if (src & 1) 
      statusReg |= C30_CONDFLAG_CARRY;
    else 
      statusReg &= ~C30_CONDFLAG_CARRY;
    src>>=1;
  }
  else
    statusReg &= ~C30_CONDFLAG_CARRY;

  *pipe->finalDest1 = src;

  if (src & 0x80000000L)
    statusReg |= C30_CONDFLAG_NEGATIVE;
  else
    statusReg &= ~C30_CONDFLAG_NEGATIVE;
  if (src)
    statusReg &= ~C30_CONDFLAG_ZERO;
  else
    statusReg |= C30_CONDFLAG_ZERO;
  if ((&st->Sregs[__r0] <= pipe->finalDest1) && 
      (pipe->finalDest1 <= &st->Sregs[__r7])) {
    update_rxn_of_dest1(pipe);
    st->st = statusReg;
  }
  update_arn_s_and_st(pipe,st);
}

void S_ash3(pipeline* pipe, state* st)  {
  S_ash(pipe, st);
}

void S_ash3_sti(pipeline* pipe, state* st) {
  sti_dest2(pipe);
  S_ash(pipe, st);
}

inline void S_brd(pipeline* pipe, state* st ){ //branch uncond delayed
  st->DSKdebStep = 3;
  pipe->newPC = pipe->oprnd1;
  pipe->modifyPC = 1;
}

void S_br(pipeline* pipe, state* st )  { //branch uncond standard
   pipe->pc = pipe->oprnd1;
   pipe->flushed = 1;
   st->DSKdebStep = 3;
}

void S_bcnd(pipeline* pipe, state* st){    //branch cond standard
  if (testConditionalCodes(st))
    S_br(pipe,st);
}

void S_bdc(pipeline* pipe, state* st){    //branch cond delayed
  if (testConditionalCodes(st))
    S_brd(pipe,st);
  else
  	 st->DSKdebStep = 3;
}

void S_dbc(pipeline* pipe, state* st){    //decrement & branch conditional standard
  int32 temp = (*pipe->finalDest1 << 8) - 1;
  //only decrement 24LSB signed int of *pipe->finalDest1, and keep 8MSB unchanged
  //shift right is signed extended automatically, have to undo the sign-extended
  *pipe->finalDest1 = (*pipe->finalDest1 & 0xff000000) | ((temp >> 8) & 0x00ffffff) ;
  //compare the 24LSB signed int of *pipe->finalDest1
  if ((temp >= 0) && (testConditionalCodes(st)))
    S_br(pipe,st);
}

void S_dbdc(pipeline* pipe, state* st){  //decrement & branch conditional delayed
  int32 temp = (*pipe->finalDest1 << 8) - 1;
  //only decrement 24LSB signed int of *pipe->finalDest1, and keep 8MSB unchanged
  //shift right is signed extended automatically, have to undo the sign-extended
  *pipe->finalDest1 = (*pipe->finalDest1 & 0xff000000) | ((temp >> 8) & 0x00ffffff) ;
  //compare the 24LSB signed int of *pipe->finalDest1
  if ((temp >= 0) && (testConditionalCodes(st)))
	 S_brd(pipe,st);
  else
    st->DSKdebStep = 3;
}

inline void S_call(pipeline* pipe, state* st) {
  st->sp++;
  *C30SimMemMap(st, st->sp) = st->pc + 1;
  pipe->pc = pipe->oprnd1;
  pipe->flushed = 1;
  st->DSKdebStep = 3;
}

void S_callc(pipeline* pipe, state* st){
  if (testConditionalCodes(st)) 
    S_call(pipe,st);
}

inline void S_cmpf(pipeline* pipe, state* st){
    uint32 src1 = dsp_float_40to32_bit(pipe->opexp1, pipe->opfloat1);
    uint32 src2 = dsp_float_40to32_bit(pipe->opexp2, pipe->opfloat2);
    float op1 = TMS_IEEE(src1),
          op2 = TMS_IEEE(src2);
    double result = (double)op2 - (double)op1;

    update_float_status(st, result);
    if (((result > 0) && (result < C30_EPSILON)) ||
      ((result < 0) && (result > -C30_EPSILON)))
    	st->st |= (C30_CONDFLAG_UNDERFLOW | C30_CONDFLAG_LATCHED_UNDERFLOW);
  //}
}

void S_cmpf3(pipeline* pipe, state* st)  {
  S_cmpf(pipe, st);
}  

inline void S_cmpi(pipeline* pipe, state* st)  { 
    st->st &= ~C30_CONDFLAG_UNDERFLOW;
    double result = C30SIM_UINT32_TO_DOUBLE(pipe->oprnd2) -
      C30SIM_UINT32_TO_DOUBLE(pipe->oprnd1);
    if (!result)
    	st->st |= C30_CONDFLAG_ZERO;
  	 else
    	st->st &= ~C30_CONDFLAG_ZERO;
    if (result < 0)
      st->st |= C30_CONDFLAG_NEGATIVE;
    else
      st->st &= ~C30_CONDFLAG_NEGATIVE;
    if ((int32)pipe->oprnd1 > (int32)pipe->oprnd2)
      st->st |= C30_CONDFLAG_CARRY;
    else
      st->st &= ~C30_CONDFLAG_CARRY;

    if ((C30SIM_UINT32_TO_DOUBLE(C30_MIN_SIGNED_INT) > result) ||
      (result > C30SIM_UINT32_TO_DOUBLE(C30_MAX_SIGNED_INT))) {
      st->st |= C30_CONDFLAG_LATCHED_OVERFLOW;
      st->st |= C30_CONDFLAG_OVERFLOW;
    }
    else
      st->st &= ~C30_CONDFLAG_OVERFLOW;
  //}
}

void S_cmpi3(pipeline* pipe, state* st)  {
  S_cmpi(pipe, st);
}

void S_FRIEEE(pipeline* /*pipe*/ , state* /*st*/ ){
// FIXME: FRIEEE is a C4x instruction.
}

inline void S_fix(pipeline* pipe, state* st){
// following the flow chart in the User's Guide page 4-23
  int32 exp = (int32)pipe->opexp1 >> 24;

  c30reg statusReg = st->st;
  if (exp > 30) {
    statusReg |= (C30_CONDFLAG_OVERFLOW | C30_CONDFLAG_LATCHED_OVERFLOW);
    if ((int32)pipe->opfloat1 > 0)
      *pipe->finalDest1 = C30_MAX_SIGNED_INT;
    else if  ((int32)pipe->opfloat1 <0)
      *pipe->finalDest1 = C30_MIN_SIGNED_INT;
  }
  else {
    if (pipe->opfloat1 & 0x80000000L) // inserting implied bit
      *pipe->finalDest1 =
        (((pipe->opfloat1 >> 1) & 0xbfffffffL) >> (30 - exp));
    else
      *pipe->finalDest1 =
        (((pipe->opfloat1 >> 1) | 0x40000000L) >> (30 - exp));

    statusReg &= ~C30_CONDFLAG_OVERFLOW;
  }
  if ((&st->Sregs[__r0] <= pipe->finalDest1) &&
      (pipe->finalDest1 <= &st->Sregs[__r7])) {
    update_rxn_of_dest1(pipe);
      st->st = statusReg;
      st->st &= ~C30_CONDFLAG_UNDERFLOW;
      if (*pipe->finalDest1)
        st->st &= ~C30_CONDFLAG_ZERO;
      else
        st->st |= C30_CONDFLAG_ZERO;
      if ((int32)*pipe->finalDest1 >= 0)
        st->st &= ~C30_CONDFLAG_NEGATIVE;
      else
        st->st |= C30_CONDFLAG_NEGATIVE;
  }
  update_arn_s_and_st(pipe,st);
}

void S_fix_sti(pipeline* pipe, state* st){
  sti_dest2(pipe);
  S_fix(pipe,st);
}

inline void S_float(pipeline* pipe, state* st){
  // following the flow chart in the User's Guide.  Page 4-24
  uint32 man = pipe->oprnd1;
  uint32 exp = 0;
  int k = 0;
  if (!man)
    exp = 0x80000000L;
  else {
    // find the number of leading nonsignificant sign bits
    uint32 x = (man & 0x80000000L);
    uint32 temp = man << 1;
    while ((!(x ^ (temp & 0x80000000L))) && (k < 31)) {
      ++k;
      temp <<= 1;
    }
    exp = (30 - k) << 24;
    man <<= k;
    if (man & 0x80000000L)
      man = (man << 1) | 0x80000000L;
    else
      man = (man << 1) & 0x7fffffffL;
  }
  *pipe->finalDest1 = man;
  *(pipe->finalDest1 +1) = exp;
  uf_n_z_v_logical(st, man);
}

void S_float_stf(pipeline* pipe, state* st){
  S_float(pipe,st);
  stf_dest2(pipe);
}  

void S_iack(pipeline* /*pipe*/ , state* /*st*/ ){
// FIXME: C30 simulator is not modelled to handle iack instruction
}

void S_idle(pipeline* /*pipe*/ , state* st){
  st->st |= C30_CONDFLAG_GIE;
  // FIXME: C30 simulator is not modelled to handle idle instruction  
}

void S_idle2(pipeline* /*pipe*/ , state* st ){
// FIXME: idle2 is a C31 instruction, which operates just like idle as far as the simulator concern.
  st->st |= C30_CONDFLAG_GIE;
}

void S_LDA(pipeline* /*pipe*/ , state* /*st*/ ){
// FIXME: LDA is a C4x instruction.  
}

void S_lde(pipeline* pipe, state* st){ 
  if ((&st->Sregs[__r0] <= pipe->finalDest1) &&
      (pipe->finalDest1 <= &st->Sregs[__r7])) {
    *(pipe->finalDest1 + 1) = pipe->opexp1;
    if (pipe->opexp1 == 0x80000000L)
      *pipe->finalDest1 = 0;
    update_rxn_of_dest1(pipe);
  }
  else {
    if (pipe->opexp1 == 0x80000000L)
      *pipe->finalDest1 = 0x80000000L;
    else
      *pipe->finalDest1 = ((*pipe->finalDest1 & 0x00ffffffL) |
               pipe->opexp1); 
  }
}

inline void S_ldf(pipeline* pipe, state* st){
  *(pipe->finalDest1 + 1) = pipe->opexp1;
  *pipe->finalDest1 = pipe->opfloat1;
  if ((&st->Sregs[__r0] <= pipe->finalDest1) &&
      (pipe->finalDest1) <= &st->Sregs[__r7]) {
    update_rxn_of_dest1(pipe);
    uf_n_z_v_logical(st,*pipe->finalDest1);
  }
}

void S_ldfc(pipeline* pipe, state* st){
  if (testConditionalCodes(st)){
    *(pipe->finalDest1 + 1) = pipe->opexp1;
    *pipe->finalDest1 = pipe->opfloat1;
    if ((&st->Sregs[__r0] <= pipe->finalDest1) &&
      (pipe->finalDest1) <= &st->Sregs[__r7])
    		update_rxn_of_dest1(pipe);
  }
}

void S_ldfi(pipeline* pipe, state* st){
  // FIXME: C30 simulator is not modelled for external (pin XF0, XF1) interlocked operations. 
  S_ldf(pipe,st);
}

void S_ldf_ldf(pipeline* pipe, state* /*st*/ ){

  *(pipe->finalDest1 + 1) = pipe->opexp1;
  *pipe->finalDest1 = pipe->opfloat1;
  update_rxn_of_dest1(pipe);
  *(pipe->finalDest2 + 1) = pipe->opexp3;
  *pipe->finalDest2 = pipe->opfloat3;
  update_rxn_of_dest2(pipe);
}

void S_ldf_stf(pipeline* pipe, state* /* st */){
  stf_dest2(pipe);
  *(pipe->finalDest1 + 1) = pipe->opexp1;
  *pipe->finalDest1 = pipe->opfloat1;
  update_rxn_of_dest1(pipe);
}

inline void S_ldi(pipeline* pipe, state* st)  {

  *pipe->finalDest1 = pipe->oprnd1;
  if ((&st->Sregs[__r0] <= pipe->finalDest1) &&
      (pipe->finalDest1 <= &st->Sregs[__r7])) {
    update_rxn_of_dest1(pipe);
    uf_n_z_v_logical(st, *pipe->finalDest1);
  }
  else update_arn_s_and_st(pipe,st);
}

void S_ldic(pipeline* pipe, state* st){
  if (testConditionalCodes(st)) {
    *pipe->finalDest1 = pipe->oprnd1;
    if ((&st->Sregs[__r0] <= pipe->finalDest1) &&
      (pipe->finalDest1 <= &st->Sregs[__r7]))
    	update_rxn_of_dest1(pipe);
    else update_arn_s_and_st(pipe,st);
  }
}

void S_ldii(pipeline* pipe, state* st){
  // FIXME: C30 simulator is not modeled for external (pin XF0, XF1) interlocked operations. 
  S_ldi(pipe, st);
}

void S_ldi_ldi(pipeline* pipe, state* /*st*/  )  {
  *pipe->finalDest1 = pipe->oprnd1;
  update_rxn_of_dest1(pipe);
  *pipe->finalDest2 = pipe->oprnd3;
  update_rxn_of_dest2(pipe);
}

void S_ldi_sti(pipeline* pipe, state* /* st */ )  {
  sti_dest1(pipe);
  update_rxn_of_dest1(pipe);
  sti_dest2(pipe);
}

void S_ldm(pipeline* pipe, state* st){
  if ((&st->Sregs[__r0] <= pipe->finalDest1) && 
      (pipe->finalDest1 <= &st->Sregs[__r7])) {
    *pipe->finalDest1 = pipe->opfloat1;
    update_rxn_of_dest1(pipe);
  }
  else {
    *pipe->finalDest1 &= 0xff000000L;
    *pipe->finalDest1 |= ((pipe->opfloat1 >> 8) & 0x00ffffffL); 
  }
  if (st->ldm==21) {// indirect/direct case
    *pipe->finalDest1 = ( pipe->opexp1 | ((pipe->opfloat1 >> 8) & 0x00ffffffL));
    st->ldm = 0;	//reset st->ldm
  }
    // FIXME:  Keith implemented immediate mode ???
}

void S_ldp(pipeline* pipe, state* st)  {
  st->dp = pipe->oprnd1;
}

void S_lopower(pipeline* /*pipe*/ , state* /*st*/ ){
// FIXME: C30 simulator is not modelled to handle lopower instruction. 
}

inline void S_lsh(pipeline* pipe, state* st) {
  c30reg statusReg = st->st;
  int32 count = pipe->oprnd1 & 0x00000080;     //count is the signed 7-LSB of oprnd1
  if(count)
  	 count = pipe->oprnd1 | 0xffffff00;       //sign extend for count
  else
  	 count = pipe->oprnd1 & 0x000000ff;
  int32 src = (int32)pipe->oprnd2;

  if (count>0) {
    src <<= (count - 1);
    if (src & 0x80000000L)
      statusReg |= C30_CONDFLAG_CARRY;
    else 
      statusReg &= ~C30_CONDFLAG_CARRY;
    src <<= 1;
  }
  else if (count<0) {
    int32 i;
    for (i=0; i<(-count-1); i++) {  
      src>>=1;  // sign-extended automatically  
      src &= 0x7fffffffL; // undo sign-extended  
    }
    if (src & 1)
      statusReg |= C30_CONDFLAG_CARRY;
    else
      statusReg &= ~C30_CONDFLAG_CARRY;
    src>>=1;
    src &= 0x7fffffffL;
  }
  else
    statusReg &= ~C30_CONDFLAG_CARRY;
  *(pipe->finalDest1) = src;

  if ((&st->Sregs[__r0] <= pipe->finalDest1) &&
      (pipe->finalDest1 <= &st->Sregs[__r7])) {
    update_rxn_of_dest1(pipe);
      st->st = statusReg;
      uf_n_z_v_logical(st,*pipe->finalDest1);
  }  
  update_arn_s_and_st(pipe,st);
}

void S_lsh3(pipeline* pipe, state* st)  {
  S_lsh(pipe, st);
}

void S_lsh3_sti(pipeline* pipe, state* st) {
  sti_dest2(pipe);
  S_lsh(pipe, st);
}

void S_maxspeed(pipeline* /*pipe*/ , state* /*st*/ ){
  //FIXME: C30 simulaor is not modelled to handle maxspeed instruction. 
}

inline void S_mpyf(pipeline* pipe, state* st){ 
  uint32 exp1 = 0, man1 = 0;
  double test1 = 0.0;
  float_arith_on_arg_1(pipe, C30SIM_MUL_FLOAT, &exp1, &man1, &test1);
  set_with_status_float(pipe,st,test1,exp1,man1);   
}

void S_mpyf3(pipeline* pipe, state* st)  {
  S_mpyf(pipe, st);
}

void S_mpyf3_addf3(pipeline* pipe, state* st){
  uint32 exp1=0, man1=0,exp2=0,man2=0;
  double test1=0,test2=0;

  float_arith_on_arg_1(pipe, C30SIM_MUL_FLOAT, &exp1, &man1, &test1);
  float_arith_on_arg_2(pipe, C30SIM_ADD_FLOAT, &exp2, &man2, &test2);
  set_P_float_status(st,test1,test2);
  set_dest_float1(pipe,exp1,man1);
  set_dest_float2(pipe,exp2,man2);  
}

void S_mpyf3_stf(pipeline* pipe, state* st){
	stf_dest2(pipe);
	S_mpyf(pipe,st);
}

void S_mpyf3_subf3(pipeline* pipe, state* st){
  uint32 exp1=0, man1=0, exp2=0, man2=0;
  double test1=0, test2=0;
  float_arith_on_arg_1(pipe, C30SIM_MUL_FLOAT, &exp1, &man1, &test1);
  float_arith_on_arg_2(pipe, C30SIM_SUB_FLOAT, &exp2, &man2, &test2);

  set_P_float_status(st,test1,test2);
  set_dest_float1(pipe,exp1,man1);
  set_dest_float2(pipe,exp2,man2);
}

inline void S_mpyi(pipeline* pipe, state* st){
  int32 op1 = ((int32)pipe->oprnd1 << 8 ) >> 8;//sign-extend 24-bit number  
  int32 op2 = ((int32)pipe->oprnd2 << 8 ) >> 8;
  double temp = C30SIM_UINT32_TO_DOUBLE(op1) *
                C30SIM_UINT32_TO_DOUBLE(op2);
  int32 tempH = (int32)op1 * (int32)op2;

  set1_with_OVM(pipe, st, temp, tempH);
  if ((&st->Sregs[__r0] <= pipe->finalDest1) &&
     (pipe->finalDest1 <= &st->Sregs[__r7])) {
    update_rxn_of_dest1(pipe);
    uf_v_lv_z_n_ARITH(pipe, st, temp);
  }     
  update_arn_s_and_st(pipe,st);
}

void S_mpyi3(pipeline* pipe, state* st)  {
  S_mpyi(pipe, st);
}

void S_mpyi3_addi3(pipeline* pipe, state* st){ 
  int32 op1 = ((int32)pipe->oprnd1 << 8 ) >> 8;//sign-extend 24-bit number  
  int32 op2 = ((int32)pipe->oprnd2 << 8 ) >> 8;
  double temp1 = C30SIM_UINT32_TO_DOUBLE(op1) *
  				     C30SIM_UINT32_TO_DOUBLE(op2);
  int32 tempH1 = (int32)op1 * (int32)op2;
  
	double temp2 =  C30SIM_UINT32_TO_DOUBLE(pipe->oprnd3) +
      				 C30SIM_UINT32_TO_DOUBLE(pipe->oprnd4);
  int32 tempH2 =  (int32)pipe->oprnd3 + (int32)pipe->oprnd4;

  set1_with_OVM(pipe, st, temp1, tempH1);
  set2_with_OVM(pipe, st, temp2, tempH2);
  
    st->st &= ~C30_CONDFLAG_UNDERFLOW;
    st->st &= ~C30_CONDFLAG_ZERO;
    st->st &= ~C30_CONDFLAG_NEGATIVE;
    if ((C30SIM_UINT32_TO_DOUBLE(C30_MIN_SIGNED_INT) > temp1) ||
      (temp1 > C30SIM_UINT32_TO_DOUBLE(C30_MAX_SIGNED_INT)) ||
      (C30SIM_UINT32_TO_DOUBLE(C30_MIN_SIGNED_INT) > temp2) ||
      (temp2 > C30SIM_UINT32_TO_DOUBLE(C30_MAX_SIGNED_INT))) {
      st->st |= C30_CONDFLAG_OVERFLOW;
      st->st |= C30_CONDFLAG_LATCHED_OVERFLOW;
    }
    else
      st->st &= ~C30_CONDFLAG_OVERFLOW;
  //}    
}

void S_mpyi3_sti(pipeline* pipe, state* st){
	sti_dest2(pipe);
	S_mpyi(pipe, st);
}

void S_mpyi3_subi3(pipeline* pipe, state* st){
  // FIXME:  how to set UF, underflow
  int32 op1 = ((int32)pipe->oprnd1 << 8 ) >> 8;//24-bit signed-extended number
  int32 op2 = ((int32)pipe->oprnd2 << 8 ) >> 8;
  double temp1 = C30SIM_UINT32_TO_DOUBLE(op1) *
                       C30SIM_UINT32_TO_DOUBLE(op2);
  int32 tempH1 = (int32)op1 * (int32)op2;

  int32 tempH2 = (int32)pipe->oprnd3 - (int32)pipe->oprnd4;
  double temp2 = C30SIM_UINT32_TO_DOUBLE(pipe->oprnd3) -
           C30SIM_UINT32_TO_DOUBLE(pipe->oprnd4);
  set1_with_OVM(pipe, st, temp1, tempH1);
  set2_with_OVM(pipe, st, temp2, tempH2);
  st->st &= ~C30_CONDFLAG_ZERO;
  st->st &= ~C30_CONDFLAG_NEGATIVE;
  if ((C30SIM_UINT32_TO_DOUBLE(C30_MIN_SIGNED_INT) > temp1) ||
  		(temp1 > C30SIM_UINT32_TO_DOUBLE(C30_MAX_SIGNED_INT)) ||
      (C30SIM_UINT32_TO_DOUBLE(C30_MIN_SIGNED_INT) > temp2) ||
      (temp2 > C30SIM_UINT32_TO_DOUBLE(C30_MAX_SIGNED_INT))) {
      st->st |= C30_CONDFLAG_OVERFLOW;
      st->st |= C30_CONDFLAG_LATCHED_OVERFLOW;
      st->st &= ~C30_CONDFLAG_UNDERFLOW;
  }
  else {
      st->st &= ~C30_CONDFLAG_OVERFLOW;
      st->st &= ~C30_CONDFLAG_UNDERFLOW;
  }
}

void S_negb(pipeline* pipe, state* st)  {
  int32 tempH = -((int32)pipe->oprnd1 + (int32)(st->st & C30_CONDFLAG_CARRY));
  double temp = -(C30SIM_UINT32_TO_DOUBLE(pipe->oprnd1) +
           (st->st & C30_CONDFLAG_CARRY));
  set1_with_OVM(pipe, st, temp, tempH);
  if ((&st->Sregs[__r0] <= pipe->finalDest1) &&
      (pipe->finalDest1 <= &st->Sregs[__r7])) {
    update_rxn_of_dest1(pipe);
    uf_v_lv_z_n_ARITH(pipe, st, temp);
    if ((int32)*pipe->finalDest1 >= 0)
        st->st &= ~C30_CONDFLAG_CARRY;
    else
        st->st |= C30_CONDFLAG_CARRY;
  } 
  update_arn_s_and_st(pipe,st);
}

void S_negf(pipeline* pipe, state* st){
  uint32 src1 = dsp_float_40to32_bit(pipe->opexp1, pipe->opfloat1);
  float op1= TMS_IEEE(src1);
  float dstIEEE = - op1; 
  c30reg dstTMS = IEEE_TMS(dstIEEE);
  uint32 exp=0, man=0;
  dsp_float_32to40_bit(dstTMS, &exp, &man);

  double test =  - (double) op1;
  set_with_status_float(pipe,st,test,exp,man);
}

void S_negf_stf(pipeline* pipe, state* st){
	stf_dest2(pipe);
  	S_negf(pipe,st);
}

inline void S_negi(pipeline* pipe, state* st){
  double temp = -(C30SIM_UINT32_TO_DOUBLE(pipe->oprnd1));
  int32 tempH = -(int32)pipe->oprnd1;
  set1_with_OVM(pipe, st, temp, tempH);
  if ((&st->Sregs[__r0] <= pipe->finalDest1) && 
      (pipe->finalDest1 <= &st->Sregs[__r7])) {
    update_rxn_of_dest1(pipe);
    uf_v_lv_z_n_ARITH(pipe, st, temp);
    if ((int32)*pipe->finalDest1 >= 0)
      	st->st &= ~C30_CONDFLAG_CARRY;
    else
      	st->st |= C30_CONDFLAG_CARRY;
  }   
  update_arn_s_and_st(pipe,st);
}

void S_negi_sti(pipeline* pipe, state* st){
	sti_dest2(pipe);
	S_negi(pipe,st);
}

void S_nop(pipeline* /*pipe*/ , state* /*st*/ ){
}

void S_norm(pipeline* pipe, state* st){   
// following the algorithm in the User's Guide page 4-19 
  double exp = C30SIM_UINT32_TO_DOUBLE(pipe->opexp1 >> 24);
  uint32 man = pipe->opfloat1;
  int k = 0;
  uint32 x=0;
  if (! man)  
    exp = 0x80L;
  else {
    //find the number of leading nonsignificant sign bits     
    x = (man & 0x80000000L);
    uint32 temp = man;
    while (!(x ^ (temp & 0x80000000L)) && (k < 32)) {
      ++k;
      temp <<= 1;
    }
    x = man & 0x00000001L;
    man >>= 1;
    if (x)
      man = ((man << 1) | 1) << (k-1);
    else
      man <<= k;
    if(man & 0x80000000L)
      man = (man << 1) | 0x80000000L;
    else
      man = (man << 1) & 0x7fffffffL;

    exp = exp - k;
    if (exp < C30SIM_UINT32_TO_DOUBLE(C30_MIN_SIGNED_INT)) {
      exp = -128;
      x = 1;
    } else
      x = 0;
  }
   if ((&st->Sregs[__r0] <= pipe->finalDest1) &&
      (pipe->finalDest1 <= &st->Sregs[__r7])) {
    *pipe->finalDest1 = man;
    *(pipe->finalDest1 +1) = (int32)exp << 24;
    update_rxn_of_dest1(pipe);
    if (x) {
    	st->st |= C30_CONDFLAG_UNDERFLOW;
      st->st |= C30_CONDFLAG_LATCHED_UNDERFLOW;
    }
    else
    	st->st &= ~C30_CONDFLAG_UNDERFLOW;
    if ((int32)man < 0)
    	st->st |= C30_CONDFLAG_NEGATIVE;
    else
    	st->st &= ~C30_CONDFLAG_NEGATIVE;
    if (!man)
    	st->st |= C30_CONDFLAG_ZERO;
    else
    	st->st &= ~C30_CONDFLAG_ZERO;
    st->st &= ~C30_CONDFLAG_OVERFLOW;
  }
  else
    *pipe->finalDest1 = dsp_float_40to32_bit(man,(int32)exp << 24);
  update_arn_s_and_st(pipe,st);
}

inline void S_not(pipeline* pipe, state* st)  {
  *pipe->finalDest1 = ~pipe->oprnd1;
   if ((&st->Sregs[__r0] <= pipe->finalDest1) &&
     (pipe->finalDest1 <= &st->Sregs[__r7])) {
    update_rxn_of_dest1(pipe);
    uf_n_z_v_logical( st,*pipe->finalDest1);
   }
  update_arn_s_and_st(pipe,st);
}

void S_not_sti(pipeline* pipe, state* st)  {
  sti_dest2(pipe);
  S_not(pipe,st);
}

inline void S_or(pipeline* pipe, state* st)  {
  *pipe->finalDest1 = (pipe->oprnd1 | pipe->oprnd2);
  if ((&st->Sregs[__r0] <= pipe->finalDest1) &&
      (pipe->finalDest1 <= &st->Sregs[__r7])) {
    update_rxn_of_dest1(pipe);
    uf_n_z_v_logical(st,*pipe->finalDest1);
  }
  update_arn_s_and_st(pipe,st);
}

void S_or3(pipeline* pipe, state* st)  {
  S_or(pipe, st);
}

void S_or3_sti(pipeline* pipe, state* st)  {
  sti_dest2(pipe);
  S_or(pipe,st);
}

void S_pop(pipeline* pipe, state* st)  {
  *(pipe->finalDest1) = *C30SimMemMap(st, st->sp--);
  if ((&st->Sregs[__r0] <= pipe->finalDest1) &&
      (pipe->finalDest1 <= &st->Sregs[__r7])) {
    update_rxn_of_dest1(pipe);
    uf_n_z_v_logical(st,*pipe->finalDest1);
  }
  update_arn_s_and_st (pipe,st);
}

void S_popf(pipeline* pipe, state* st)  {
  uint32 dsp_32 = *C30SimMemMap(st, st->sp--);
  *(pipe->finalDest1) = dsp_32 << 8;
  *(pipe->finalDest1 + 1) = dsp_32 & 0xff000000L;
  uf_n_z_v_logical(st,*pipe->finalDest1);
}

void S_push(pipeline* pipe, state* st)  {
  *C30SimMemMap(st, ++st->sp) = pipe->oprnd2;
}

void S_pushf(pipeline* pipe, state* st)  {
  *C30SimMemMap(st, ++st->sp) = dsp_float_40to32_bit(pipe->opexp2, pipe->opfloat2);
}

void S_retsc(pipeline * pipe, state * st) {
  if (testConditionalCodes(st)){
    pipe->pc = *C30SimMemMap(st,st->sp--);
    pipe->flushed = 1;
    st->DSKdebStep = 3;
  }
}

void S_retic(pipeline * pipe, state * st) {
  if (testConditionalCodes(st)){
    pipe->newPC = *C30SimMemMap(st,st->sp--);
    pipe->modifyPC = 1;
    st->st |= C30_CONDFLAG_GIE;
  }
}

void S_rnd(pipeline* pipe, state* st) {
// following the algorithm in the User's Guide, page 4-21
  c30reg statusReg = st->st;
  uint32 exp = pipe->opexp1 >> 24;
  uint32 man = pipe->opfloat1;
  double temp = C30SIM_UINT32_TO_DOUBLE(man) + 128;
  if ((C30SIM_UINT32_TO_DOUBLE(C30_MIN_SIGNED_INT) > temp) ||
      (C30SIM_UINT32_TO_DOUBLE(C30_MAX_SIGNED_INT) < temp)) {
    man = int32(man >> 1) + 0x40L;
    exp++;
    if (exp > 0x7fL) {
      statusReg |= (C30_CONDFLAG_LATCHED_OVERFLOW |
              C30_CONDFLAG_OVERFLOW);
      if (man > 0) {
        man = 0x7fffffL;
        exp = 0x7fL;
      } 
      else {
        exp = 0x80L;
        man = 0x800000L;
      }
    } 
    else
      statusReg &= ~C30_CONDFLAG_OVERFLOW;
  } 
  else if (!temp) { 
      exp = 0x80L;
      man = 0;
      // FIXME:  should zero be set according to the flow chart 4-16 
      statusReg |= C30_CONDFLAG_ZERO;  
  }
  else 
    man = (int32)man + 0x00000080L;

  *pipe->finalDest1 = man & 0xffffff00L ;
  *(pipe->finalDest1 + 1) = (exp << 24) ; 
// FIXME:  underflow never occurs, and Z bit should be affected by this operation ?  
	st->st = statusReg;
   if ((int32)man<0)
      st->st |= C30_CONDFLAG_NEGATIVE;
   else
      st->st &= ~C30_CONDFLAG_NEGATIVE;
}

void S_rol(pipeline* pipe, state* st) {  
  *(pipe->finalDest1) = ((int32)pipe->oprnd2 << 1);
  if (pipe->oprnd2 & 0x80000000L) 
    *pipe->finalDest1 |= 1;
  if ((&st->Sregs[__r0] <= pipe->finalDest1) && 
      (pipe->finalDest1 <= &st->Sregs[__r7])) {
    update_rxn_of_dest1(pipe);
    if (pipe->oprnd2 & 0x80000000L)
        st->st |= C30_CONDFLAG_CARRY;
    else
        st->st &= ~C30_CONDFLAG_CARRY;
    uf_n_z_v_logical(st,*pipe->finalDest1);
  }        
  update_arn_s_and_st(pipe,st);
}

void S_ror(pipeline* pipe, state* st) { 
  *(pipe->finalDest1) = ((int32)pipe->oprnd2 >> 1);
  if (pipe->oprnd2 & 1) 
    *pipe->finalDest1 |= 0x80000000L;
  if ((&st->Sregs[__r0] <= pipe->finalDest1) && 
      (pipe->finalDest1 <= &st->Sregs[__r7])) {
    update_rxn_of_dest1(pipe);
    if (pipe->oprnd2 & 1)
        st->st |= C30_CONDFLAG_CARRY;
    else
        st->st &= ~C30_CONDFLAG_CARRY;
    uf_n_z_v_logical(st,*pipe->finalDest1);
  } 
  update_arn_s_and_st(pipe,st);
}

void S_rolc(pipeline* pipe, state* st) {  
  *(pipe->finalDest1) = ((int32)pipe->oprnd2 << 1);
  if (st->st & C30_CONDFLAG_CARRY)
    *pipe->finalDest1 |= C30_CONDFLAG_CARRY;
  if ((&st->Sregs[__r0] <= pipe->finalDest1) &&
     (pipe->finalDest1 <= &st->Sregs[__r7])) { 
    update_rxn_of_dest1(pipe);
    if (pipe->oprnd2 & 0x80000000L)
        st->st |= C30_CONDFLAG_CARRY;
    else
        st->st &= ~C30_CONDFLAG_CARRY;
    uf_n_z_v_logical(st,*pipe->finalDest1);
  } 
  update_arn_s_and_st(pipe,st);
}

void S_rorc(pipeline* pipe, state* st){
  *(pipe->finalDest1) = ((int32)pipe->oprnd2>> 1);
  if (st->st & C30_CONDFLAG_CARRY)
    *pipe->finalDest1 |= 0x80000000L;
  if ((&st->Sregs[__r0] <= pipe->finalDest1) && 
      (pipe->finalDest1 <= &st->Sregs[__r7])) { 
    update_rxn_of_dest1(pipe);
    if (pipe->oprnd2 & 1)
        st->st |= C30_CONDFLAG_CARRY;
    else
        st->st &= ~C30_CONDFLAG_CARRY;
    uf_n_z_v_logical(st,*pipe->finalDest1);
  }
  update_arn_s_and_st(pipe,st);
}

void S_rptb(pipeline* pipe, state* st)  {
  st->re = pipe->oprnd1;
  st->st |= C30_CONDFLAG_REPEAT_MODE;
  pipe->pc -= 2;
  st->rs = pipe->pc;
  pipe->flushed = 1;
  st->DSKdebStep = 3;
  pipe->repeatModeModifyRC = 1;
}

void S_rpts(pipeline* pipe, state* st)  {
  st->rc = pipe->rc = pipe->rci[0] = pipe->rci[1] = pipe->oprnd1;
  pipe->repeatModeModifyRC = 1;
  st->st |= C30_CONDFLAG_REPEAT_MODE;
  pipe->pc -= 2;
  st->rs = st->re = pipe->pc;
  pipe->flushed = 1;
  st->DSKdebStep = st->rc + 4;	/*rc+1 is the number of repetition, +3 for flushed */
}

void S_sigi(pipeline* /*pipe*/ , state* /*st*/ ){
// FIXME: C30 simulator is not modelled for external (pin XF0, XF1) interlocked operations. 
}

inline void S_stf(pipeline* pipe, state* /* st */){
  stf_dest1(pipe);
}

void S_stfi(pipeline* pipe, state* st){
  S_stf(pipe,st);
// FIXME: C30 simulator is not modelled for external (pin XF0, XF1) interlocked operations. 
}

void S_stf_stf(pipeline* pipe, state* /* st */){
  stf_dest1(pipe);
  stf_dest2(pipe);
}

void S_sti(pipeline* pipe, state* /* st */)  {
  sti_dest1(pipe);
}

void S_stii(pipeline* pipe, state* /* st */ ){
// FIXME: C30 simulator is not modelled for external (pin XF0, XF1) interlocked operations.  
  sti_dest1(pipe);
}

void S_sti_sti(pipeline* pipe, state* /* st */){
  sti_dest1(pipe);
  sti_dest2(pipe);
}

inline void S_subb(pipeline* pipe, state* st)  {
  double tempp = C30SIM_UINT32_TO_DOUBLE(pipe->oprnd1) +
           (st->st & C30_CONDFLAG_CARRY);
  double temp = C30SIM_UINT32_TO_DOUBLE(pipe->oprnd2) - tempp;
  int32 tempH = (int32)pipe->oprnd2 - (int32)tempp;
  set1_with_OVM(pipe, st, temp, tempH);
  if ((&st->Sregs[__r0] <= pipe->finalDest1) &&
      (pipe->finalDest1 <= &st->Sregs[__r7])) {
    update_rxn_of_dest1(pipe);
    uf_v_lv_z_n_ARITH(pipe, st, temp);
    if (C30SIM_UINT32_TO_DOUBLE(pipe->oprnd2) < tempp)
    	st->st |= C30_CONDFLAG_CARRY;
    else
     	st->st &= ~C30_CONDFLAG_CARRY;
  } 
  update_arn_s_and_st(pipe,st);
}

void S_subb3(pipeline* pipe, state* st)  {
  S_subb(pipe, st);
}

void S_subrb(pipeline* pipe, state* st)  {
  swap_operand(&pipe->oprnd1,&pipe->oprnd2);
  S_subb(pipe,st);
}

void S_subc(pipeline* pipe, state* st ){
  if (pipe->oprnd2 >= pipe->oprnd1)
    *pipe->finalDest1 = (((int32)pipe->oprnd2 - (int32)pipe->oprnd1) << 1) | 1;
  else 
    *pipe->finalDest1 = pipe->oprnd2 << 1;   
  update_arn_s_and_st(pipe,st);
}

inline void S_subf(pipeline* pipe, state* st){ 
  uint32 exp1=0, man1=0;
  double test1=0;
  float_arith_on_arg_1(pipe, C30SIM_SUB_FLOAT, &exp1, &man1, &test1);
  set_with_status_float(pipe,st,test1,exp1,man1);      
}

void S_subrf(pipeline* pipe, state* st){
  swap_operand(&pipe->opexp1, &pipe->opexp2);
  swap_operand(&pipe->opfloat1, &pipe->opfloat2);
  S_subf(pipe, st);
}

void S_subf3(pipeline* pipe, state* st)  {
  S_subf(pipe, st);
}

void S_subf3_stf(pipeline* pipe, state* st){
   stf_dest2(pipe);
   S_subf(pipe,st);
}

inline void S_subi(pipeline* pipe, state* st)  {
  double temp = C30SIM_UINT32_TO_DOUBLE(pipe->oprnd2) -
          C30SIM_UINT32_TO_DOUBLE(pipe->oprnd1);
  int32 tempH = (int32)pipe->oprnd2 - (int32)pipe->oprnd1;
  set1_with_OVM(pipe, st, temp, tempH);
  if ((&st->Sregs[__r0] <= pipe->finalDest1) && 
      (pipe->finalDest1 <= &st->Sregs[__r7])) {
    update_rxn_of_dest1(pipe);
    uf_v_lv_z_n_ARITH(pipe, st,temp);
    if (C30SIM_UINT32_TO_DOUBLE(pipe->oprnd2) <
              C30SIM_UINT32_TO_DOUBLE(pipe->oprnd1))
    	st->st |= C30_CONDFLAG_CARRY;
    else
    	st->st &= ~C30_CONDFLAG_CARRY;
  }   
  update_arn_s_and_st(pipe,st);
}

void S_subi3(pipeline* pipe, state* st)  {
  S_subi(pipe, st);
}

void S_subri(pipeline *pipe, state *st) {
  swap_operand(&pipe->oprnd1,&pipe->oprnd2);
  S_subi(pipe,st);
}

void S_subi3_sti(pipeline* pipe, state* st ) {
  sti_dest2(pipe);
  S_subi(pipe,st);
}

void S_TOIEEE(pipeline* /*pipe*/ , state* /*st*/  ){
// FIXME: TOIEEE is a C4x instruction.  
}

void S_trap(pipeline* pipe, state* st){ // FIXME: why does trap take 5 cycles?
  if (testConditionalCodes(st)) {
    st->st &= C30_CONDFLAG_GIE;
    *C30SimMemMap(st,++st->sp) = pipe->pc + 1;
    pipe->pc = pipe->oprnd1;
    pipe->flushed = 1;
  }
}

void S_trap4x(pipeline* /*pipe*/, state* /*st*/){
//FIXME:  TRAP4X is a C4x instruction.
}

inline void S_tstb(pipeline* pipe, state* st)  {
  uint32 num = pipe->oprnd1 & pipe->oprnd2;
  if ((&st->Sregs[__r0] <= pipe->source2) &&
      (pipe->source2 <= &st->rc)) 
    uf_n_z_v_logical(st, num);
}

void S_tstb3(pipeline* pipe, state* st)  {
  S_tstb(pipe, st);
}

void S_swi(pipeline* /*pipe*/ , state* /*st*/ ){
// FIXME: C30 simulator is not modelled for swi operation.
}

void S_word(pipeline* /*pipe*/ , state* /*st*/ )  {
// FIXME: S_word is not a C3x instruction.  Inform Keith to fix his version.
}

inline void S_xor(pipeline* pipe, state* st) {
  *pipe->finalDest1 = (pipe->oprnd1 ^ pipe->oprnd2);

  if ((&st->Sregs[__r0] <= pipe->finalDest1) &&
      (pipe->finalDest1 <= &st->Sregs[__r7])) {
    update_rxn_of_dest1(pipe);
    uf_n_z_v_logical(st, *pipe->finalDest1);
  } 
  update_arn_s_and_st(pipe,st);
}

void S_xor3(pipeline* pipe, state* st)  {
  S_xor(pipe, st);
}

void S_xor3_sti(pipeline* pipe, state* st) {
  sti_dest2(pipe);
  S_xor(pipe, st);
}
