[RX] v2 instructions support

Message ID 1450719297-15073-1-git-send-email-ysato@users.sourceforge.jp
State Superseded
Delegated to: Mike Frysinger
Headers

Commit Message

Yoshinori Sato Dec. 21, 2015, 5:34 p.m. UTC
  ChangeLog
include/gdb/ChangeLog
	* sim-rx.h: Add v2 enhanced registers.

sim/rx/ChangeLog
	* Makefile.in: Add libm.
	* cpu.h(acc_t): extend to 96bit.
	(regs_type): Add v2 registers.
	(extb): New define.
	(li): Likewise.
	(acc0): Rename from acc64.
	(acc1): New define.
	(acchi,accmi,acclo): Remove.
	(get_acc): New function.
	(put_acc): Likewise.
	(get_reg64): Remove.
	(put_reg64): Likewise.
	* fpu.c(rx_sqrt_tab): New.
 	(rxfp_fsqrt): New.
 	(rxfp_ftou): New.
 	(rxfp_utof): New.
	* fpu.h: Add new function prototype.
	* gdb-if.c(reg_size): New registers support.
	(sim_fetch_register): Likewise.
	(sim_store_register): Likewise.
	* reg.c(reg_names): Add new registers.

---
 include/gdb/sim-rx.h |   4 +-
 sim/rx/Makefile.in   |   1 +
 sim/rx/cpu.h         |  24 +++--
 sim/rx/fpu.c         | 171 ++++++++++++++++++++++++++++++++++
 sim/rx/fpu.h         |   3 +
 sim/rx/gdb-if.c      |  78 ++++++++++++++--
 sim/rx/reg.c         |  93 ++++++++----------
 sim/rx/rx.c          | 259 +++++++++++++++++++++++++++++++++++++++++++--------
 8 files changed, 521 insertions(+), 112 deletions(-)
  

Comments

Mike Frysinger Dec. 24, 2015, 7:35 a.m. UTC | #1
On 22 Dec 2015 02:34, Yoshinori Sato wrote:
> --- a/sim/rx/fpu.c
> +++ b/sim/rx/fpu.c
>  
> +double sqrt(double x);

never declare your own prototype for system funcs.  include math.h instead.

> +static FP_ExceptionCases ex_sqrt_tab[5][5] = {

please constify this.  you might have to update check_exceptions too.

> +  tprintf("sqrt(%g) = %g\n", da, sqrt(da));

space before the (.  this comes up a few times in your patch, so please
fix them all.

> +      /* Less than 0.49999 */

period at the end and two spaces:
	/* Less than 0.49999.  */

this comes up a few times in your patch, so please fix them all.

> +	if (rx_big_endian)
> +	  {
> +	    put_be (buf, 8, acc.lo);
> +	  }
> +	else
> +	  {
> +	    put_le (buf, 8, acc.lo);
> +	  }

no need for braces here

> +  for(i = 0; i < 2; i++)

space before the (

>      {
> -      if (tag) { printf (tag); tag = 0; }
> -      printf("  acc %016llx:", oldregs.r_acc);
> -      printf("%016llx", regs.r_acc);
> -      oldregs.r_acc = regs.r_acc;
> +      if (oldregs.r_acc[i].hi != regs.r_acc[i].hi ||
> +	  oldregs.r_acc[i].lo != regs.r_acc[i].lo)
> +	{
> +	  if (tag) { printf (tag); tag = 0; }
> +	  printf("  acc%d %08x%016lx:", i, oldregs.r_acc[i].hi,
> +		 oldregs.r_acc[i].lo);
> +	  printf("%08x%016lx", regs.r_acc[i].hi,
> +		 oldregs.r_acc[i].lo);
> +	  oldregs.r_acc[i] = regs.r_acc[i];
> +	}

i know you aren't writing this code, but please fix the style in the process.

> +#define MULADD(val, s)				\

the trailing \ style in these macros is inconsistent.  if you don't want to
align them to 80 cols, then just put one space before them.
-mike
  

Patch

diff --git a/include/gdb/sim-rx.h b/include/gdb/sim-rx.h
index 40e18c1..b55c902 100644
--- a/include/gdb/sim-rx.h
+++ b/include/gdb/sim-rx.h
@@ -49,7 +49,9 @@  enum sim_rx_regnum
     sim_rx_bpc_regnum,
     sim_rx_fintv_regnum,
     sim_rx_fpsw_regnum,
-    sim_rx_acc_regnum,
+    sim_rx_acc0_regnum,
+    sim_rx_extb_regnum,
+    sim_rx_acc1_regnum,
     sim_rx_num_regs
   };
 
diff --git a/sim/rx/Makefile.in b/sim/rx/Makefile.in
index 64d9f3c..73475fe 100644
--- a/sim/rx/Makefile.in
+++ b/sim/rx/Makefile.in
@@ -40,6 +40,7 @@  SIM_OBJS = \
 	$(ENDLIST)
 
 LIBS = $B/bfd/libbfd.a $B/libiberty/libiberty.a
+SIM_EXTRA_LIBS = -lm
 
 ## COMMON_POST_CONFIG_FRAG
 
diff --git a/sim/rx/cpu.h b/sim/rx/cpu.h
index 9a82e5e..45e6612 100644
--- a/sim/rx/cpu.h
+++ b/sim/rx/cpu.h
@@ -35,6 +35,12 @@  extern int rx_big_endian;
 
 typedef struct
 {
+  SI hi;
+  DI lo;
+} acc_t;
+
+typedef struct
+{
   SI r[16];
 
   SI r_psw;
@@ -51,8 +57,8 @@  typedef struct
   SI r_isp;
   SI r_fintv;
   SI r_intb;
-  SI r__reserved_cr_13;
-  SI r__reserved_cr_14;
+  SI r_extb;
+  SI r_li;
   SI r__reserved_cr_15;
 
   SI r__reserved_cr_16;
@@ -75,7 +81,7 @@  typedef struct
 
   SI r_temp;
 
-  DI r_acc;
+  acc_t r_acc[2];
 
 #ifdef CYCLE_ACCURATE
   /* If set, RTS/RTSD take 2 fewer cycles.  */
@@ -105,12 +111,12 @@  typedef struct
 #define isp	26
 #define fintv	27
 #define intb	28
+#define extb	29
+#define li	30
 
 #define r_temp_idx 48
-#define acc64	49
-#define acchi	50
-#define accmi	51
-#define acclo	52
+#define acc0	49
+#define acc1	50
 
 extern regs_type regs;
 
@@ -170,9 +176,9 @@  void init_regs (void);
 void stack_heap_stats (void);
 void set_pointer_width (int bytes);
 unsigned int get_reg (int id);
-unsigned long long get_reg64 (int id);
+void get_acc (int id, acc_t *valuel);
 void put_reg (int id, unsigned int value);
-void put_reg64 (int id, unsigned long long value);
+void put_acc (int id, acc_t *value);
 
 void set_flags (int mask, int newbits);
 void set_oszc (long long value, int bytes, int c);
diff --git a/sim/rx/fpu.c b/sim/rx/fpu.c
index 9e4a103..d5a7665 100644
--- a/sim/rx/fpu.c
+++ b/sim/rx/fpu.c
@@ -790,3 +790,174 @@  rxfp_itof (long fa, int round_mode)
   return rv;
 }
 
+double sqrt(double x);
+
+static FP_ExceptionCases ex_sqrt_tab[5][5] = {
+  /* N   +0   -0   +In  -In */
+  { eNR, eDZ, eDZ, eSZ, eSZ }, /* Normal */
+  { eSZ, eIn, eIn, ePZ, eNZ }, /* +0   */
+  { eSZ, eIn, eIn, eNZ, ePZ }, /* -0   */
+  { eSI, ePI, eNI, eIn, eIn }, /* +Inf */
+  { eSI, eNI, ePI, eIn, eIn }, /* -Inf */
+};
+
+fp_t
+rxfp_fsqrt (fp_t fa)
+{
+  FP_Parts a, b, c;
+  fp_t rv;
+  double da;
+
+  fp_explode (fa, &a);
+  fp_explode (fa, &b);
+  CHECK_EXCEPTIONS (a, b, rv, ex_sqrt_tab);
+
+  da = fp_to_double (&a);
+  tprintf("sqrt(%g) = %g\n", da, sqrt(da));
+
+  double_to_fp (sqrt(da), &c);
+  rv = fp_implode (&c);
+
+  return rv;
+}
+
+unsigned long
+rxfp_ftou (fp_t fa, int round_mode)
+{
+  FP_Parts a;
+  fp_t rv;
+  int sign;
+  int whole_bits, frac_bits;
+
+  fp_explode (fa, &a);
+  sign = fa & 0x80000000UL;
+
+  switch (a.type)
+    {
+    case FP_NORMAL:
+      break;
+    case FP_PZERO:
+    case FP_NZERO:
+      return 0;
+    case FP_PINFINITY:
+      FP_RAISE (V);
+      return 0xffffffffL;
+    case FP_NINFINITY:
+      FP_RAISE (V);
+      return 0x00000000L;
+    case FP_DENORMAL:
+      FP_RAISE (E);
+      return 0;
+    case FP_QNAN:
+    case FP_SNAN:
+      FP_RAISE (V);
+      return sign ? 0x00000000 : 0xffffffff;
+    }
+
+  if (sign)
+    return 0;
+  if (a.exp >= 32)
+    {
+      FP_RAISE (V);
+      return 0xffffffff;
+    }
+
+  a.exp -= 23;
+
+  if (a.exp <= -25)
+    {
+      /* Less than 0.49999 */
+      frac_bits = a.mant;
+      whole_bits = 0;
+    }
+  else if (a.exp < 0)
+    {
+      frac_bits = a.mant << (33 + a.exp);
+      whole_bits = a.mant >> (-a.exp);
+    }
+  else
+    {
+      frac_bits = 0;
+      whole_bits = a.mant << a.exp;
+    }
+
+  if (frac_bits)
+    {
+      switch (round_mode & 3)
+	{
+	case FPRM_NEAREST:
+	  if (frac_bits & 0x80000000UL)
+	    whole_bits ++;
+	  break;
+	case FPRM_ZERO:
+	case FPRM_NINF:
+	  break;
+	case FPRM_PINF:
+	  if (!sign)
+	    whole_bits ++;
+	  break;
+	}
+    }
+
+  rv = whole_bits;
+  
+  return rv;
+}
+
+fp_t
+rxfp_utof (unsigned long fa, int round_mode)
+{
+  fp_t rv;
+  int sign = 0;
+  unsigned int frac_bits;
+  volatile unsigned int whole_bits;
+  FP_Parts a;
+
+  if (fa == 0)
+    return PLUS_ZERO;
+
+  a.sign = 1;
+
+  whole_bits = fa;
+  a.exp = 31;
+
+  while (! (whole_bits & 0x80000000UL))
+    {
+      a.exp --;
+      whole_bits <<= 1;
+    }
+  frac_bits = whole_bits & 0xff;
+  whole_bits = whole_bits >> 8;
+
+  if (frac_bits)
+    {
+      /* We must round */
+      switch (round_mode & 3)
+	{
+	case FPRM_NEAREST:
+	  if (frac_bits & 0x80)
+	    whole_bits ++;
+	  break;
+	case FPRM_ZERO:
+	  break;
+	case FPRM_PINF:
+	  if (!sign)
+	    whole_bits ++;
+	  break;
+	case FPRM_NINF:
+	  if (sign)
+	    whole_bits ++;
+	  break;
+	}
+    }
+
+  a.mant = whole_bits;
+  if (whole_bits & 0xff000000UL)
+    {
+      a.mant >>= 1;
+      a.exp ++;
+    }
+
+  rv = fp_implode (&a);
+  return rv;
+}
diff --git a/sim/rx/fpu.h b/sim/rx/fpu.h
index a20c2a0..dcddf11 100644
--- a/sim/rx/fpu.h
+++ b/sim/rx/fpu.h
@@ -27,3 +27,6 @@  extern fp_t rxfp_div (fp_t fa, fp_t fb);
 extern void rxfp_cmp (fp_t fa, fp_t fb);
 extern long rxfp_ftoi (fp_t fa, int round_mode);
 extern fp_t rxfp_itof (long fa, int round_mode);
+extern fp_t rxfp_fsqrt (fp_t fa);
+extern unsigned long rxfp_ftou (fp_t fa, int round_mode);
+extern fp_t rxfp_utof (unsigned long fa, int round_mode);
diff --git a/sim/rx/gdb-if.c b/sim/rx/gdb-if.c
index 762c3d2..7037c64 100644
--- a/sim/rx/gdb-if.c
+++ b/sim/rx/gdb-if.c
@@ -387,6 +387,9 @@  reg_size (enum sim_rx_regnum regno)
     case sim_rx_intb_regnum:
       size = sizeof (regs.r_intb);
       break;
+    case sim_rx_extb_regnum:
+      size = sizeof (regs.r_extb);
+      break;
     case sim_rx_pc_regnum:
       size = sizeof (regs.r_pc);
       break;
@@ -405,8 +408,9 @@  reg_size (enum sim_rx_regnum regno)
     case sim_rx_fpsw_regnum:
       size = sizeof (regs.r_fpsw);
       break;
-    case sim_rx_acc_regnum:
-      size = sizeof (regs.r_acc);
+    case sim_rx_acc0_regnum:
+    case sim_rx_acc1_regnum:
+      size = 8;
       break;
     default:
       size = 0;
@@ -490,6 +494,9 @@  sim_fetch_register (SIM_DESC sd, int regno, unsigned char *buf, int length)
     case sim_rx_intb_regnum:
       val = get_reg (intb);
       break;
+    case sim_rx_extb_regnum:
+      val = get_reg (extb);
+      break;
     case sim_rx_pc_regnum:
       val = get_reg (pc);
       break;
@@ -508,9 +515,34 @@  sim_fetch_register (SIM_DESC sd, int regno, unsigned char *buf, int length)
     case sim_rx_fpsw_regnum:
       val = get_reg (fpsw);
       break;
-    case sim_rx_acc_regnum:
-      val = ((DI) get_reg (acchi) << 32) | get_reg (acclo);
-      break;
+    case sim_rx_acc0_regnum:
+      {
+	acc_t acc;
+	get_acc(0, &acc);
+	if (rx_big_endian)
+	  {
+	    put_be (buf, 8, acc.lo);
+	  }
+	else
+	  {
+	    put_le (buf, 8, acc.lo);
+	  }
+	return 8;
+      }
+    case sim_rx_acc1_regnum:
+      {
+	acc_t acc;
+	get_acc(1, &acc);
+	if (rx_big_endian)
+	  {
+	    put_be (buf, 8, acc.lo);
+	  }
+	else
+	  {
+	    put_le (buf, 8, acc.lo);
+	  }
+	return 8;
+      }
     default:
       fprintf (stderr, "rx minisim: unrecognized register number: %d\n",
 	       regno);
@@ -623,10 +655,38 @@  sim_store_register (SIM_DESC sd, int regno, unsigned char *buf, int length)
     case sim_rx_fpsw_regnum:
       put_reg (fpsw, val);
       break;
-    case sim_rx_acc_regnum:
-      put_reg (acclo, val & 0xffffffff);
-      put_reg (acchi, (val >> 32) & 0xffffffff);
-      break;
+    case sim_rx_acc0_regnum:
+      {
+	acc_t acc;
+	if (rx_big_endian)
+	  {
+	    acc.hi = get_be (buf, 8);
+	    acc.lo = get_be (buf + 8, 8);
+	  }
+	else
+	  {
+	    acc.lo = get_le (buf, 8);
+	    acc.hi = get_le (buf + 8, 8);
+	  }
+	put_acc (0, &acc);
+	break;
+      }
+    case sim_rx_acc1_regnum:
+      {
+	acc_t acc;
+	if (rx_big_endian)
+	  {
+	    acc.hi = get_be (buf, 8);
+	    acc.lo = get_be (buf + 8, 8);
+	  }
+	else
+	  {
+	    acc.lo = get_le (buf, 8);
+	    acc.hi = get_le (buf + 8, 8);
+	  }
+	put_acc (1, &acc);
+	break;
+      }
     default:
       fprintf (stderr, "rx minisim: unrecognized register number: %d\n",
 	       regno);
diff --git a/sim/rx/reg.c b/sim/rx/reg.c
index 6effe4b..0d78d9d 100644
--- a/sim/rx/reg.c
+++ b/sim/rx/reg.c
@@ -50,10 +50,10 @@  char *reg_names[] = {
   "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15",
   /* control register */
   "psw", "pc", "usp", "fpsw", "RES", "RES", "RES", "RES",
-  "bpsw", "bpc", "isp", "fintv", "intb", "RES", "RES", "RES",
+  "bpsw", "bpc", "isp", "fintv", "intb", "extb", "li", "RES",
   "RES", "RES", "RES", "RES", "RES", "RES", "RES", "RES",
   "RES", "RES", "RES", "RES", "RES", "RES", "RES", "RES",
-  "temp", "acc", "acchi", "accmi", "acclo"
+  "temp", "acc0", "acc1",
 };
 
 unsigned int b2mask[] = { 0, 0xff, 0xffff, 0xffffff, 0xffffffff };
@@ -69,6 +69,9 @@  init_regs (void)
   memset (&regs, 0, sizeof (regs));
   memset (&oldregs, 0, sizeof (oldregs));
 
+  regs.r_extb = 0xffffff80;
+  oldregs.r_extb = 0xffffff80;
+  
 #ifdef CYCLE_ACCURATE
   regs.rt = -1;
   oldregs.rt = -1;
@@ -102,16 +105,14 @@  get_reg_i (int id)
       return regs.r_fintv;
     case intb:
       return regs.r_intb;
+    case extb:
+      return regs.r_extb;
+    case li:
+      return regs.r_li;
     case pc:
       return regs.r_pc;
     case r_temp_idx:
       return regs.r_temp;
-    case acchi:
-      return (SI)(regs.r_acc >> 32);
-    case accmi:
-      return (SI)(regs.r_acc >> 16);
-    case acclo:
-      return (SI)regs.r_acc;
     }
   abort();
 }
@@ -125,25 +126,14 @@  get_reg (int id)
   return rv;
 }
 
-static unsigned long long
-get_reg64_i (int id)
-{
-  switch (id)
-    {
-    case acc64:
-      return regs.r_acc;
-    default:
-      abort ();
-    }
-}
-
-unsigned long long
-get_reg64 (int id)
+void
+get_acc (int id, acc_t *acc)
 {
-  unsigned long long rv = get_reg64_i (id);
-  if (trace > ((id != pc && id != sp) ? 0 : 1))
-    printf ("get_reg (%s) = %016llx\n", reg_names[id], rv);
-  return rv;
+  if (id >= 2)
+    abort ();
+  *acc = regs.r_acc[id];
+  if (trace > 0)
+    printf ("get_reg (%s) = %08x%016lx\n", reg_names[acc0 + id], acc->hi, acc->lo);
 }
 
 static int highest_sp = 0, lowest_sp = 0xffffff;
@@ -203,18 +193,14 @@  put_reg (int id, unsigned int v)
     case intb:
       regs.r_intb = v;
       break;
-    case pc:
-      regs.r_pc = v;
+    case extb:
+      regs.r_extb = v;
       break;
-
-    case acchi:
-      regs.r_acc = (regs.r_acc & 0xffffffffULL) | ((DI)v << 32);
+    case li:
+      regs.r_li = v;
       break;
-    case accmi:
-      regs.r_acc = (regs.r_acc & ~0xffffffff0000ULL) | ((DI)v << 16);
-      break;
-    case acclo:
-      regs.r_acc = (regs.r_acc & ~0xffffffffULL) | ((DI)v);
+    case pc:
+      regs.r_pc = v;
       break;
 
     case 0: /* Stack pointer is "in" R0.  */
@@ -261,19 +247,15 @@  put_reg (int id, unsigned int v)
 }
 
 void
-put_reg64 (int id, unsigned long long v)
+put_acc (int id, acc_t *acc)
 {
-  if (trace > ((id != pc) ? 0 : 1))
-    printf ("put_reg (%s) = %016llx\n", reg_names[id], v);
 
-  switch (id)
-    {
-    case acc64:
-      regs.r_acc = v;
-      break;
-    default:
-      abort ();
-    }
+  if (id >= 2)
+    abort ();
+  if (trace > 0)
+    printf ("put_reg (%s) = %08x%016lx\n", reg_names[acc0 + id], acc->hi, acc->lo);
+
+  regs.r_acc[id] = *acc;
 }
 
 int
@@ -545,14 +527,19 @@  trace_register_changes (void)
       oldregs.r_fpsw = regs.r_fpsw;
     }
 
-  if (oldregs.r_acc != regs.r_acc)
+  for(i = 0; i < 2; i++)
     {
-      if (tag) { printf (tag); tag = 0; }
-      printf("  acc %016llx:", oldregs.r_acc);
-      printf("%016llx", regs.r_acc);
-      oldregs.r_acc = regs.r_acc;
+      if (oldregs.r_acc[i].hi != regs.r_acc[i].hi ||
+	  oldregs.r_acc[i].lo != regs.r_acc[i].lo)
+	{
+	  if (tag) { printf (tag); tag = 0; }
+	  printf("  acc%d %08x%016lx:", i, oldregs.r_acc[i].hi,
+		 oldregs.r_acc[i].lo);
+	  printf("%08x%016lx", regs.r_acc[i].hi,
+		 oldregs.r_acc[i].lo);
+	  oldregs.r_acc[i] = regs.r_acc[i];
+	}
     }
-
   if (tag == 0)
     printf ("\033[0m\n");
 }
diff --git a/sim/rx/rx.c b/sim/rx/rx.c
index e48f6c8..07654fa 100644
--- a/sim/rx/rx.c
+++ b/sim/rx/rx.c
@@ -137,6 +137,25 @@  static const char * id_names[] = {
   "RXO_wait",
 
   "RXO_sccnd",	/* d = cond(s) ? 1 : 0 */
+
+  "RXO_fsqrt",
+  "RXO_ftou",
+  "RXO_utof",
+  "RXO_movco",
+  "RXO_movli",
+  "RXO_emaca",
+  "RXO_emsba",
+  "RXO_emula",
+  "RXO_maclh",
+  "RXO_msbhi",
+  "RXO_msblh",
+  "RXO_msblo",
+  "RXO_mullh",
+  "RXO_mvfacgu",
+  "RXO_mvtacgu",
+  "RXO_racl",
+  "RXO_rdacl",
+  "RXO_rdacw",
 };
 
 static const char * optype_names[] = {
@@ -806,8 +825,8 @@  fop_fsub (fp_t s1, fp_t s2, fp_t *d)
   int do_store;   \
   fp_t fa, fb, fc; \
   FPCLEAR(); \
-  fb = GS (); \
-  fa = GD (); \
+  fb = US2 (); \
+  fa = US1 (); \
   do_store = fop_##func (fa, fb, &fc); \
   tprintf("%g " #func " %g = %g %08x\n", int2float(fa), int2float(fb), int2float(fc), fc); \
   FPCHECK(); \
@@ -929,6 +948,66 @@  op_is_memory (const RX_Opcode_Decoded *rd, int i)
 
 #define DO_RETURN(x) { longjmp (decode_jmp_buf, x); }
 
+#define MULADD(val, s)				\
+{ \
+ get_acc(opcode->op[0].reg - 32, &acc); \
+ sll = val; \
+ sll <<= s; \
+ if (sll > 0 && (unsigned long long)acc.lo > (unsigned long long)(acc.lo + sll))	\
+   acc.hi++; \
+ else if (sll < 0 && (unsigned long long)(acc.lo + sll) > (unsigned long long)acc.lo)	\
+   acc.hi--; \
+ acc.lo += sll; \
+ put_acc (opcode->op[0].reg - 32, &acc); \
+ E1; \
+ break; \
+}
+
+#define MULSUB(val, s)				\
+{ \
+ get_acc(opcode->op[0].reg - 32, &acc); \
+ sll = val; \
+ sll <<= s;					\
+ if (sll > 0 && (unsigned long long)(sll - acc.lo) > (unsigned long long)acc.lo) \
+   acc.hi--; \
+ else if (sll < 0 && (unsigned long long)acc.lo >(unsigned long long)(sll - acc.lo))	\
+   acc.hi++; \
+ acc.hi = (signed char)acc.hi; \
+ acc.lo -= sll; \
+ put_acc (opcode->op[0].reg - 32, &acc); \
+ E1; \
+ break;						\
+}
+
+#define MULACC(val, s) \
+{ \
+ sll = val; \
+ sll <<= s; \
+ acc.lo = sll;					\
+ acc.hi = (sll < 0)? -1 : 0; \
+ put_acc (opcode->op[0].reg - 32, &acc); \
+ E1; \
+ break; \
+}
+
+#define RAC(add, pl, ml) \
+{ \
+ get_acc(opcode->op[0].reg - 32, &acc); \
+ ll = acc.lo << GS (); \
+ ll += add; \
+ if ((signed long long)ll > (signed long long)0x00007fff00000000ULL) \
+   ll = 0x00007fff00000000ULL; \
+ else if ((signed long long)ll < (signed long long)0xffff800000000000ULL) \
+   ll = 0xffff800000000000ULL; \
+ else \
+   ll &= 0xffffffff00000000ULL; \
+ acc.hi = ((signed long long)ll < 0) ? -1 : 0; \
+ acc.lo = ll; \
+ put_acc (opcode->op[0].reg - 32, &acc); \
+ E1; \
+ break; \
+}
+
 int
 decode_opcode ()
 {
@@ -940,6 +1019,7 @@  decode_opcode ()
   unsigned long opcode_pc;
   RX_Data rx_data;
   const RX_Opcode_Decoded *opcode;
+  acc_t acc;
 #ifdef CYCLE_STATS
   unsigned long long prev_cycle_count;
 #endif
@@ -1216,6 +1296,12 @@  decode_opcode ()
 	}
       break;
 
+    case RXO_emaca:
+      MULADD((long long)GS2 () * (long long)GS (), 0)
+
+    case RXO_emsba:
+      MULSUB((long long)GS2 () * (long long)GS (), 0)
+
     case RXO_emul:
       ma = GD ();
       mb = GS ();
@@ -1226,6 +1312,18 @@  decode_opcode ()
       E2;
       break;
 
+    case RXO_emula:
+      ma = GS2 ();
+      mb = GS ();
+      acc.lo = (long long)ma * (long long)mb;
+      if (acc.lo < 0)
+	acc.hi = -1;
+      else
+	acc.hi = 0;
+      put_acc (opcode->op[0].reg - 32, &acc);
+      E (3);
+      break;
+
     case RXO_emulu:
       uma = GD ();
       umb = GS ();
@@ -1264,12 +1362,24 @@  decode_opcode ()
       PRIVILEDGED ();
       regs.r_psw = regs.r_bpsw;
       regs.r_pc = regs.r_bpc;
+      regs.r_li = 0;
 #ifdef CYCLE_ACCURATE
       regs.fast_return = 0;
       cycles(3);
 #endif
       break;
 
+    case RXO_fsqrt:
+      ma = GS ();
+      FPCLEAR ();
+      mb = rxfp_fsqrt (ma);
+      FPCHECK ();
+      PD (mb);
+      tprintf("(int) %g = %d\n", int2float(ma), mb);
+      set_sz (mb, 4);
+      E (16);
+      break;
+
     case RXO_fsub:
       FLOAT_OP (fsub);
       E (4);
@@ -1286,6 +1396,17 @@  decode_opcode ()
       E (2);
       break;
 
+    case RXO_ftou:
+      ma = GS ();
+      FPCLEAR ();
+      mb = rxfp_ftou (ma, FPRM_ZERO);
+      FPCHECK ();
+      PD (mb);
+      tprintf("(int) %g = %d\n", int2float(ma), mb);
+      set_sz (mb, 4);
+      E (2);
+      break;
+
     case RXO_int:
       v = GS ();
       if (v == 255)
@@ -1352,18 +1473,13 @@  decode_opcode ()
       break;
 
     case RXO_machi:
-      ll = (long long)(signed short)(GS() >> 16) * (long long)(signed short)(GS2 () >> 16);
-      ll <<= 16;
-      put_reg64 (acc64, ll + regs.r_acc);
-      E1;
-      break;
+      MULADD((long long)(signed short)(GS() >> 16) * (long long)(signed short)(GS2 () >> 16), 16)
+
+    case RXO_maclh:
+      MULADD((long long)(signed short)(GS()) * (long long)(signed short)(GS2 () >> 16), 16)
 
     case RXO_maclo:
-      ll = (long long)(signed short)(GS()) * (long long)(signed short)(GS2 ());
-      ll <<= 16;
-      put_reg64 (acc64, ll + regs.r_acc);
-      E1;
-      break;
+      MULADD((long long)(signed short)(GS()) * (long long)(signed short)(GS2 ()), 16)
 
     case RXO_max:
       mb = GS();
@@ -1457,6 +1573,33 @@  decode_opcode ()
       cycles (1);
       break;
 
+    case RXO_movli:
+      PD (mem_get_si (GS ()));
+      regs.r_li = 1;
+      E1;
+      break;
+
+    case RXO_movco:
+      if (regs.r_li == 1)
+	{
+	  mem_put_si (GD (), GS ());
+	  PS (0);
+	}
+      else
+	PS (1);
+      regs.r_li = 0;
+      E1;
+      break;
+
+    case RXO_msbhi:
+      MULSUB((long long)(signed short)(GS() >> 16) * (long long)(signed short)(GS2 () >> 16), 16)
+
+    case RXO_msblh:
+      MULSUB((long long)(signed short)(GS()) * (long long)(signed short)(GS2 () >> 16), 16)
+
+    case RXO_msblo:
+      MULSUB((long long)(signed short)(GS()) * (long long)(signed short)(GS2 ()), 16)
+
     case RXO_mul:
       v = US2 ();
       ll = (unsigned long long) US1() * (unsigned long long) v;
@@ -1465,43 +1608,64 @@  decode_opcode ()
       break;
 
     case RXO_mulhi:
-      v = GS2 ();
-      ll = (long long)(signed short)(GS() >> 16) * (long long)(signed short)(v >> 16);
-      ll <<= 16;
-      put_reg64 (acc64, ll);
-      E1;
-      break;
+      MULACC((long long)(signed short)(GS() >> 16) * (long long)(signed short)(GS2 () >> 16), 16)
+    case RXO_mullh:
+      MULACC((long long)(signed short)(GS()) * (long long)(signed short)(GS2 () >> 16), 16)
 
     case RXO_mullo:
-      v = GS2 ();
-      ll = (long long)(signed short)(GS()) * (long long)(signed short)(v);
-      ll <<= 16;
-      put_reg64 (acc64, ll);
-      E1;
-      break;
+      MULACC((long long)(signed short)(GS()) * (long long)(signed short)(GS2 ()), 16)
 
     case RXO_mvfachi:
-      PD (get_reg (acchi));
+      get_acc (opcode->op[1].reg - 32, &acc);
+      PD ((acc.lo << GS2 ()) >> 32);
       E1;
       break;
 
     case RXO_mvfaclo:
-      PD (get_reg (acclo));
+      get_acc (opcode->op[1].reg - 32, &acc);
+      PD (acc.lo << GS2 ());
       E1;
       break;
 
     case RXO_mvfacmi:
-      PD (get_reg (accmi));
+      get_acc (opcode->op[1].reg - 32, &acc);
+      PD ((acc.lo << GS2 ()) >> 16);
+      E1;
+      break;
+
+    case RXO_mvfacgu:
+      get_acc (opcode->op[1].reg - 32, &acc);
+      uma = (signed char)acc.hi;
+      umb = GS2 ();
+      if (umb)
+	{
+	  uma <<= umb;
+	  uma |= ((acc.lo >> (64 - umb)) & 3);
+	}
+      PD (uma);
       E1;
       break;
 
     case RXO_mvtachi:
-      put_reg (acchi, GS ());
+      get_acc (opcode->op[0].reg - 32, &acc);
+      acc.lo &= ((1ULL << 32) - 1);
+      acc.lo |= (unsigned long long) GS () << 32ULL;
+      put_acc (opcode->op[0].reg - 32, &acc);
       E1;
       break;
 
     case RXO_mvtaclo:
-      put_reg (acclo, GS ());
+      get_acc (opcode->op[0].reg - 32, &acc);
+      acc.lo &= ~((1ULL << 32ULL) - 1);
+      acc.lo |= (unsigned long) GS ();
+      put_acc (opcode->op[0].reg - 32, &acc);
+      E1;
+      break;
+
+    case RXO_mvtacgu:
+      get_acc (opcode->op[0].reg - 32, &acc);
+      acc.hi = GS ();
+      put_acc (opcode->op[0].reg - 32, &acc);
       E1;
       break;
 
@@ -1560,22 +1724,22 @@  decode_opcode ()
       break;
 
     case RXO_racw:
-      ll = get_reg64 (acc64) << GS ();
-      ll += 0x80000000ULL;
-      if ((signed long long)ll > (signed long long)0x00007fff00000000ULL)
-	ll = 0x00007fff00000000ULL;
-      else if ((signed long long)ll < (signed long long)0xffff800000000000ULL)
-	ll = 0xffff800000000000ULL;
-      else
-	ll &= 0xffffffff00000000ULL;
-      put_reg64 (acc64, ll);
-      E1;
-      break;
+      RAC(0x80000000ULL, 0x00007fff00000000ULL, 0xffff800000000000ULL)
+
+    case RXO_rdacw:
+      RAC(0, 0x00007fff00000000ULL, 0xffffffff80000000ULL)
+
+    case RXO_racl:
+      RAC(0x80000000ULL, 0x7fffffff00000000ULL, 0xffffffff80000000ULL)
+      
+    case RXO_rdacl:
+      RAC(0, 0x7fffffff00000000ULL, 0xffff800000000000ULL)
 
     case RXO_rte:
       PRIVILEDGED ();
       regs.r_pc = poppc ();
       regs.r_psw = poppc ();
+      regs.r_li = 0;
       if (FLAG_PM)
 	regs.r_psw |= FLAGBIT_U;
 #ifdef CYCLE_ACCURATE
@@ -2130,6 +2294,21 @@  decode_opcode ()
 	set_zc (0, ((int)uma - (int)umb) >= 0);
       break;
 
+    case RXO_utof:
+      ma = GS ();
+      FPCLEAR ();
+      mb = rxfp_utof (ma, regs.r_fpsw);
+      FPCHECK ();
+      tprintf("(float) %d = %x\n", ma, mb);
+      PD (mb);
+      if (mb)
+	set_flags (FLAGBIT_Z, 0);
+      else
+	set_flags (FLAGBIT_Z, FLAGBIT_Z);
+      set_flags (FLAGBIT_S, 0);
+      E (2);
+      break;
+
     case RXO_wait:
       PRIVILEDGED ();
       regs.r_psw |= FLAGBIT_I;