xref: /netbsd-src/external/gpl3/gdb/dist/sim/rx/rx.c (revision 1f4e7eb9e5e045e008f1894823a8e4e6c9f46890)
14e98e3e1Schristos /* rx.c --- opcode semantics for stand-alone RX simulator.
24e98e3e1Schristos 
3*1f4e7eb9Schristos Copyright (C) 2008-2024 Free Software Foundation, Inc.
44e98e3e1Schristos Contributed by Red Hat, Inc.
54e98e3e1Schristos 
64e98e3e1Schristos This file is part of the GNU simulators.
74e98e3e1Schristos 
84e98e3e1Schristos This program is free software; you can redistribute it and/or modify
94e98e3e1Schristos it under the terms of the GNU General Public License as published by
104e98e3e1Schristos the Free Software Foundation; either version 3 of the License, or
114e98e3e1Schristos (at your option) any later version.
124e98e3e1Schristos 
134e98e3e1Schristos This program is distributed in the hope that it will be useful,
144e98e3e1Schristos but WITHOUT ANY WARRANTY; without even the implied warranty of
154e98e3e1Schristos MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
164e98e3e1Schristos GNU General Public License for more details.
174e98e3e1Schristos 
184e98e3e1Schristos You should have received a copy of the GNU General Public License
194e98e3e1Schristos along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
204e98e3e1Schristos 
214b169a6bSchristos /* This must come before any other includes.  */
224b169a6bSchristos #include "defs.h"
234b169a6bSchristos 
244e98e3e1Schristos #include <stdio.h>
254e98e3e1Schristos #include <stdlib.h>
264e98e3e1Schristos #include <string.h>
274e98e3e1Schristos #include <signal.h>
28796c32c9Schristos #include "libiberty.h"
294e98e3e1Schristos 
304e98e3e1Schristos #include "opcode/rx.h"
314e98e3e1Schristos #include "cpu.h"
324e98e3e1Schristos #include "mem.h"
334e98e3e1Schristos #include "syscalls.h"
344e98e3e1Schristos #include "fpu.h"
354e98e3e1Schristos #include "err.h"
364e98e3e1Schristos #include "misc.h"
374e98e3e1Schristos 
384b169a6bSchristos #ifdef WITH_PROFILE
39*1f4e7eb9Schristos static const char * const id_names[] = {
404e98e3e1Schristos   "RXO_unknown",
414e98e3e1Schristos   "RXO_mov",	/* d = s (signed) */
424e98e3e1Schristos   "RXO_movbi",	/* d = [s,s2] (signed) */
434e98e3e1Schristos   "RXO_movbir",	/* [s,s2] = d (signed) */
444e98e3e1Schristos   "RXO_pushm",	/* s..s2 */
454e98e3e1Schristos   "RXO_popm",	/* s..s2 */
464e98e3e1Schristos   "RXO_xchg",	/* s <-> d */
474e98e3e1Schristos   "RXO_stcc",	/* d = s if cond(s2) */
484e98e3e1Schristos   "RXO_rtsd",	/* rtsd, 1=imm, 2-0 = reg if reg type */
494e98e3e1Schristos 
504e98e3e1Schristos   /* These are all either d OP= s or, if s2 is set, d = s OP s2.  Note
514e98e3e1Schristos      that d may be "None".  */
524e98e3e1Schristos   "RXO_and",
534e98e3e1Schristos   "RXO_or",
544e98e3e1Schristos   "RXO_xor",
554e98e3e1Schristos   "RXO_add",
564e98e3e1Schristos   "RXO_sub",
574e98e3e1Schristos   "RXO_mul",
584e98e3e1Schristos   "RXO_div",
594e98e3e1Schristos   "RXO_divu",
604e98e3e1Schristos   "RXO_shll",
614e98e3e1Schristos   "RXO_shar",
624e98e3e1Schristos   "RXO_shlr",
634e98e3e1Schristos 
644e98e3e1Schristos   "RXO_adc",	/* d = d + s + carry */
654e98e3e1Schristos   "RXO_sbb",	/* d = d - s - ~carry */
664e98e3e1Schristos   "RXO_abs",	/* d = |s| */
674e98e3e1Schristos   "RXO_max",	/* d = max(d,s) */
684e98e3e1Schristos   "RXO_min",	/* d = min(d,s) */
694e98e3e1Schristos   "RXO_emul",	/* d:64 = d:32 * s */
704e98e3e1Schristos   "RXO_emulu",	/* d:64 = d:32 * s (unsigned) */
714e98e3e1Schristos 
724e98e3e1Schristos   "RXO_rolc",	/* d <<= 1 through carry */
734e98e3e1Schristos   "RXO_rorc",	/* d >>= 1 through carry*/
744e98e3e1Schristos   "RXO_rotl",	/* d <<= #s without carry */
754e98e3e1Schristos   "RXO_rotr",	/* d >>= #s without carry*/
764e98e3e1Schristos   "RXO_revw",	/* d = revw(s) */
774e98e3e1Schristos   "RXO_revl",	/* d = revl(s) */
784e98e3e1Schristos   "RXO_branch",	/* pc = d if cond(s) */
794e98e3e1Schristos   "RXO_branchrel",/* pc += d if cond(s) */
804e98e3e1Schristos   "RXO_jsr",	/* pc = d */
814e98e3e1Schristos   "RXO_jsrrel",	/* pc += d */
824e98e3e1Schristos   "RXO_rts",
834e98e3e1Schristos   "RXO_nop",
844e98e3e1Schristos   "RXO_nop2",
854e98e3e1Schristos   "RXO_nop3",
86ba340e45Schristos   "RXO_nop4",
87ba340e45Schristos   "RXO_nop5",
88ba340e45Schristos   "RXO_nop6",
89ba340e45Schristos   "RXO_nop7",
904e98e3e1Schristos 
914e98e3e1Schristos   "RXO_scmpu",
924e98e3e1Schristos   "RXO_smovu",
934e98e3e1Schristos   "RXO_smovb",
944e98e3e1Schristos   "RXO_suntil",
954e98e3e1Schristos   "RXO_swhile",
964e98e3e1Schristos   "RXO_smovf",
974e98e3e1Schristos   "RXO_sstr",
984e98e3e1Schristos 
994e98e3e1Schristos   "RXO_rmpa",
1004e98e3e1Schristos   "RXO_mulhi",
1014e98e3e1Schristos   "RXO_mullo",
1024e98e3e1Schristos   "RXO_machi",
1034e98e3e1Schristos   "RXO_maclo",
1044e98e3e1Schristos   "RXO_mvtachi",
1054e98e3e1Schristos   "RXO_mvtaclo",
1064e98e3e1Schristos   "RXO_mvfachi",
1074e98e3e1Schristos   "RXO_mvfacmi",
1084e98e3e1Schristos   "RXO_mvfaclo",
1094e98e3e1Schristos   "RXO_racw",
1104e98e3e1Schristos 
1114e98e3e1Schristos   "RXO_sat",	/* sat(d) */
1124e98e3e1Schristos   "RXO_satr",
1134e98e3e1Schristos 
1144e98e3e1Schristos   "RXO_fadd",	/* d op= s */
1154e98e3e1Schristos   "RXO_fcmp",
1164e98e3e1Schristos   "RXO_fsub",
1174e98e3e1Schristos   "RXO_ftoi",
1184e98e3e1Schristos   "RXO_fmul",
1194e98e3e1Schristos   "RXO_fdiv",
1204e98e3e1Schristos   "RXO_round",
1214e98e3e1Schristos   "RXO_itof",
1224e98e3e1Schristos 
1234e98e3e1Schristos   "RXO_bset",	/* d |= (1<<s) */
1244e98e3e1Schristos   "RXO_bclr",	/* d &= ~(1<<s) */
1254e98e3e1Schristos   "RXO_btst",	/* s & (1<<s2) */
1264e98e3e1Schristos   "RXO_bnot",	/* d ^= (1<<s) */
1274e98e3e1Schristos   "RXO_bmcc",	/* d<s> = cond(s2) */
1284e98e3e1Schristos 
1294e98e3e1Schristos   "RXO_clrpsw",	/* flag index in d */
1304e98e3e1Schristos   "RXO_setpsw",	/* flag index in d */
1314e98e3e1Schristos   "RXO_mvtipl",	/* new IPL in s */
1324e98e3e1Schristos 
1334e98e3e1Schristos   "RXO_rtfi",
1344e98e3e1Schristos   "RXO_rte",
1354e98e3e1Schristos   "RXO_rtd",	/* undocumented */
1364e98e3e1Schristos   "RXO_brk",
1374e98e3e1Schristos   "RXO_dbt",	/* undocumented */
1384e98e3e1Schristos   "RXO_int",	/* vector id in s */
1394e98e3e1Schristos   "RXO_stop",
1404e98e3e1Schristos   "RXO_wait",
1414e98e3e1Schristos 
1424e98e3e1Schristos   "RXO_sccnd",	/* d = cond(s) ? 1 : 0 */
1434e98e3e1Schristos };
1444e98e3e1Schristos 
145*1f4e7eb9Schristos static const char * const optype_names[] = {
1464e98e3e1Schristos   " -  ",
1474e98e3e1Schristos   "#Imm",	/* #addend */
1484e98e3e1Schristos   " Rn ",	/* Rn */
1494e98e3e1Schristos   "[Rn]",	/* [Rn + addend] */
1504e98e3e1Schristos   "Ps++",	/* [Rn+] */
1514e98e3e1Schristos   "--Pr",	/* [-Rn] */
1524e98e3e1Schristos   " cc ",	/* eq, gtu, etc */
1534e98e3e1Schristos   "Flag",	/* [UIOSZC] */
1544e98e3e1Schristos   "RbRi"	/* [Rb + scale * Ri] */
1554e98e3e1Schristos };
1564e98e3e1Schristos 
157796c32c9Schristos #define N_RXO ARRAY_SIZE (id_names)
158796c32c9Schristos #define N_RXT ARRAY_SIZE (optype_names)
159ba340e45Schristos #define N_MAP 90
1604e98e3e1Schristos 
1614e98e3e1Schristos static unsigned long long benchmark_start_cycle;
1624e98e3e1Schristos static unsigned long long benchmark_end_cycle;
1634e98e3e1Schristos 
1644e98e3e1Schristos static int op_cache[N_RXT][N_RXT][N_RXT];
1654e98e3e1Schristos static int op_cache_rev[N_MAP];
1664e98e3e1Schristos static int op_cache_idx = 0;
1674e98e3e1Schristos 
1684e98e3e1Schristos static int
1694e98e3e1Schristos op_lookup (int a, int b, int c)
1704e98e3e1Schristos {
1714e98e3e1Schristos   if (op_cache[a][b][c])
1724e98e3e1Schristos     return op_cache[a][b][c];
1734e98e3e1Schristos   op_cache_idx ++;
1744e98e3e1Schristos   if (op_cache_idx >= N_MAP)
1754e98e3e1Schristos     {
1764e98e3e1Schristos       printf("op_cache_idx exceeds %d\n", N_MAP);
1774e98e3e1Schristos       exit(1);
1784e98e3e1Schristos     }
1794e98e3e1Schristos   op_cache[a][b][c] = op_cache_idx;
1804e98e3e1Schristos   op_cache_rev[op_cache_idx] = (a<<8) | (b<<4) | c;
1814e98e3e1Schristos   return op_cache_idx;
1824e98e3e1Schristos }
1834e98e3e1Schristos 
1844e98e3e1Schristos static char *
1854e98e3e1Schristos op_cache_string (int map)
1864e98e3e1Schristos {
1874e98e3e1Schristos   static int ci;
1884e98e3e1Schristos   static char cb[5][20];
1894e98e3e1Schristos   int a, b, c;
1904e98e3e1Schristos 
1914e98e3e1Schristos   map = op_cache_rev[map];
1924e98e3e1Schristos   a = (map >> 8) & 15;
1934e98e3e1Schristos   b = (map >> 4) & 15;
1944e98e3e1Schristos   c = (map >> 0) & 15;
1954e98e3e1Schristos   ci = (ci + 1) % 5;
1964e98e3e1Schristos   sprintf(cb[ci], "%s %s %s", optype_names[a], optype_names[b], optype_names[c]);
1974e98e3e1Schristos   return cb[ci];
1984e98e3e1Schristos }
1994e98e3e1Schristos 
2004e98e3e1Schristos static unsigned long long cycles_per_id[N_RXO][N_MAP];
2014e98e3e1Schristos static unsigned long long times_per_id[N_RXO][N_MAP];
2024e98e3e1Schristos static unsigned long long memory_stalls;
2034e98e3e1Schristos static unsigned long long register_stalls;
2044e98e3e1Schristos static unsigned long long branch_stalls;
2054e98e3e1Schristos static unsigned long long branch_alignment_stalls;
2064e98e3e1Schristos static unsigned long long fast_returns;
2074e98e3e1Schristos 
2084e98e3e1Schristos static unsigned long times_per_pair[N_RXO][N_MAP][N_RXO][N_MAP];
2094e98e3e1Schristos static int prev_opcode_id = RXO_unknown;
2104e98e3e1Schristos static int po0;
2114e98e3e1Schristos 
2124e98e3e1Schristos #define STATS(x) x
2134e98e3e1Schristos 
2144e98e3e1Schristos #else
2154e98e3e1Schristos #define STATS(x)
2164b169a6bSchristos #endif /* WITH_PROFILE */
2174e98e3e1Schristos 
2184e98e3e1Schristos 
2194e98e3e1Schristos #ifdef CYCLE_ACCURATE
2204e98e3e1Schristos 
2214e98e3e1Schristos static int new_rt = -1;
2224e98e3e1Schristos 
2234e98e3e1Schristos /* Number of cycles to add if an insn spans an 8-byte boundary.  */
2244e98e3e1Schristos static int branch_alignment_penalty = 0;
2254e98e3e1Schristos 
2264e98e3e1Schristos #endif
2274e98e3e1Schristos 
2284e98e3e1Schristos static int running_benchmark = 1;
2294e98e3e1Schristos 
2304e98e3e1Schristos #define tprintf if (trace && running_benchmark) printf
2314e98e3e1Schristos 
2324e98e3e1Schristos jmp_buf decode_jmp_buf;
2334e98e3e1Schristos unsigned int rx_cycles = 0;
2344e98e3e1Schristos 
2354e98e3e1Schristos #ifdef CYCLE_ACCURATE
2364e98e3e1Schristos /* If nonzero, memory was read at some point and cycle latency might
2374e98e3e1Schristos    take effect.  */
2384e98e3e1Schristos static int memory_source = 0;
2394e98e3e1Schristos /* If nonzero, memory was written and extra cycles might be
2404e98e3e1Schristos    needed.  */
2414e98e3e1Schristos static int memory_dest = 0;
2424e98e3e1Schristos 
2434e98e3e1Schristos static void
2444e98e3e1Schristos cycles (int throughput)
2454e98e3e1Schristos {
2464e98e3e1Schristos   tprintf("%d cycles\n", throughput);
2474e98e3e1Schristos   regs.cycle_count += throughput;
2484e98e3e1Schristos }
2494e98e3e1Schristos 
2504e98e3e1Schristos /* Number of execution (E) cycles the op uses.  For memory sources, we
2514e98e3e1Schristos    include the load micro-op stall as two extra E cycles.  */
2524e98e3e1Schristos #define E(c) cycles (memory_source ? c + 2 : c)
2534e98e3e1Schristos #define E1 cycles (1)
2544e98e3e1Schristos #define E2 cycles (2)
2554e98e3e1Schristos #define EBIT cycles (memory_source ? 2 : 1)
2564e98e3e1Schristos 
2574e98e3e1Schristos /* Check to see if a read latency must be applied for a given register.  */
2584e98e3e1Schristos #define RL(r) \
2594e98e3e1Schristos   if (regs.rt == r )							\
2604e98e3e1Schristos     {									\
2614e98e3e1Schristos       tprintf("register %d load stall\n", r);				\
2624e98e3e1Schristos       regs.cycle_count ++;						\
2634e98e3e1Schristos       STATS(register_stalls ++);					\
2644e98e3e1Schristos       regs.rt = -1;							\
2654e98e3e1Schristos     }
2664e98e3e1Schristos 
2674e98e3e1Schristos #define RLD(r)					\
2684e98e3e1Schristos   if (memory_source)				\
2694e98e3e1Schristos     {						\
2704e98e3e1Schristos       tprintf ("Rt now %d\n", r);		\
2714e98e3e1Schristos       new_rt = r;				\
2724e98e3e1Schristos     }
2734e98e3e1Schristos 
2744e98e3e1Schristos static int
2754e98e3e1Schristos lsb_count (unsigned long v, int is_signed)
2764e98e3e1Schristos {
2774e98e3e1Schristos   int i, lsb;
2784e98e3e1Schristos   if (is_signed && (v & 0x80000000U))
2794e98e3e1Schristos     v = (unsigned long)(long)(-v);
2804e98e3e1Schristos   for (i=31; i>=0; i--)
2814e98e3e1Schristos     if (v & (1 << i))
2824e98e3e1Schristos       {
2834e98e3e1Schristos 	/* v is 0..31, we want 1=1-2, 2=3-4, 3=5-6, etc. */
2844e98e3e1Schristos 	lsb = (i + 2) / 2;
2854e98e3e1Schristos 	return lsb;
2864e98e3e1Schristos       }
2874e98e3e1Schristos   return 0;
2884e98e3e1Schristos }
2894e98e3e1Schristos 
2904e98e3e1Schristos static int
2914e98e3e1Schristos divu_cycles(unsigned long num, unsigned long den)
2924e98e3e1Schristos {
2934e98e3e1Schristos   int nb = lsb_count (num, 0);
2944e98e3e1Schristos   int db = lsb_count (den, 0);
2954e98e3e1Schristos   int rv;
2964e98e3e1Schristos 
2974e98e3e1Schristos   if (nb < db)
2984e98e3e1Schristos     rv = 2;
2994e98e3e1Schristos   else
3004e98e3e1Schristos     rv = 3 + nb - db;
3014e98e3e1Schristos   E (rv);
3024e98e3e1Schristos   return rv;
3034e98e3e1Schristos }
3044e98e3e1Schristos 
3054e98e3e1Schristos static int
3064e98e3e1Schristos div_cycles(long num, long den)
3074e98e3e1Schristos {
3084e98e3e1Schristos   int nb = lsb_count ((unsigned long)num, 1);
3094e98e3e1Schristos   int db = lsb_count ((unsigned long)den, 1);
3104e98e3e1Schristos   int rv;
3114e98e3e1Schristos 
3124e98e3e1Schristos   if (nb < db)
3134e98e3e1Schristos     rv = 3;
3144e98e3e1Schristos   else
3154e98e3e1Schristos     rv = 5 + nb - db;
3164e98e3e1Schristos   E (rv);
3174e98e3e1Schristos   return rv;
3184e98e3e1Schristos }
3194e98e3e1Schristos 
3204e98e3e1Schristos #else /* !CYCLE_ACCURATE */
3214e98e3e1Schristos 
3224e98e3e1Schristos #define cycles(t)
3234e98e3e1Schristos #define E(c)
3244e98e3e1Schristos #define E1
3254e98e3e1Schristos #define E2
3264e98e3e1Schristos #define EBIT
3274e98e3e1Schristos #define RL(r)
3284e98e3e1Schristos #define RLD(r)
3294e98e3e1Schristos 
3304e98e3e1Schristos #define divu_cycles(n,d)
3314e98e3e1Schristos #define div_cycles(n,d)
3324e98e3e1Schristos 
3334e98e3e1Schristos #endif /* else CYCLE_ACCURATE */
3344e98e3e1Schristos 
335*1f4e7eb9Schristos static const int size2bytes[] = {
3364e98e3e1Schristos   4, 1, 1, 1, 2, 2, 2, 3, 4
3374e98e3e1Schristos };
3384e98e3e1Schristos 
3394e98e3e1Schristos typedef struct {
3404e98e3e1Schristos   unsigned long dpc;
3414e98e3e1Schristos } RX_Data;
3424e98e3e1Schristos 
3434e98e3e1Schristos #define rx_abort() _rx_abort(__FILE__, __LINE__)
344*1f4e7eb9Schristos static void ATTRIBUTE_NORETURN
3454e98e3e1Schristos _rx_abort (const char *file, int line)
3464e98e3e1Schristos {
3474e98e3e1Schristos   if (strrchr (file, '/'))
3484e98e3e1Schristos     file = strrchr (file, '/') + 1;
3494e98e3e1Schristos   fprintf(stderr, "abort at %s:%d\n", file, line);
3504e98e3e1Schristos   abort();
3514e98e3e1Schristos }
3524e98e3e1Schristos 
3534e98e3e1Schristos static unsigned char *get_byte_base;
3544e98e3e1Schristos static RX_Opcode_Decoded **decode_cache_base;
3554e98e3e1Schristos static SI get_byte_page;
3564e98e3e1Schristos 
3574e98e3e1Schristos void
3584e98e3e1Schristos reset_decoder (void)
3594e98e3e1Schristos {
3604e98e3e1Schristos   get_byte_base = 0;
3614e98e3e1Schristos   decode_cache_base = 0;
3624e98e3e1Schristos   get_byte_page = 0;
3634e98e3e1Schristos }
3644e98e3e1Schristos 
3654e98e3e1Schristos static inline void
3664e98e3e1Schristos maybe_get_mem_page (SI tpc)
3674e98e3e1Schristos {
3684e98e3e1Schristos   if (((tpc ^ get_byte_page) & NONPAGE_MASK) || enable_counting)
3694e98e3e1Schristos     {
3704e98e3e1Schristos       get_byte_page = tpc & NONPAGE_MASK;
3714e98e3e1Schristos       get_byte_base = rx_mem_ptr (get_byte_page, MPA_READING) - get_byte_page;
3724e98e3e1Schristos       decode_cache_base = rx_mem_decode_cache (get_byte_page) - get_byte_page;
3734e98e3e1Schristos     }
3744e98e3e1Schristos }
3754e98e3e1Schristos 
3764e98e3e1Schristos /* This gets called a *lot* so optimize it.  */
3774e98e3e1Schristos static int
3784e98e3e1Schristos rx_get_byte (void *vdata)
3794e98e3e1Schristos {
3804e98e3e1Schristos   RX_Data *rx_data = (RX_Data *)vdata;
3814e98e3e1Schristos   SI tpc = rx_data->dpc;
3824e98e3e1Schristos 
3834e98e3e1Schristos   /* See load.c for an explanation of this.  */
3844e98e3e1Schristos   if (rx_big_endian)
3854e98e3e1Schristos     tpc ^= 3;
3864e98e3e1Schristos 
3874e98e3e1Schristos   maybe_get_mem_page (tpc);
3884e98e3e1Schristos 
3894e98e3e1Schristos   rx_data->dpc ++;
3904e98e3e1Schristos   return get_byte_base [tpc];
3914e98e3e1Schristos }
3924e98e3e1Schristos 
3934e98e3e1Schristos static int
3944e98e3e1Schristos get_op (const RX_Opcode_Decoded *rd, int i)
3954e98e3e1Schristos {
3964e98e3e1Schristos   const RX_Opcode_Operand *o = rd->op + i;
3974e98e3e1Schristos   int addr, rv = 0;
3984e98e3e1Schristos 
3994e98e3e1Schristos   switch (o->type)
4004e98e3e1Schristos     {
4014e98e3e1Schristos     case RX_Operand_None:
4024e98e3e1Schristos       rx_abort ();
4034e98e3e1Schristos 
4044e98e3e1Schristos     case RX_Operand_Immediate:	/* #addend */
4054e98e3e1Schristos       return o->addend;
4064e98e3e1Schristos 
4074e98e3e1Schristos     case RX_Operand_Register:	/* Rn */
4084e98e3e1Schristos       RL (o->reg);
4094e98e3e1Schristos       rv = get_reg (o->reg);
4104e98e3e1Schristos       break;
4114e98e3e1Schristos 
4124e98e3e1Schristos     case RX_Operand_Predec:	/* [-Rn] */
4134e98e3e1Schristos       put_reg (o->reg, get_reg (o->reg) - size2bytes[o->size]);
414*1f4e7eb9Schristos       ATTRIBUTE_FALLTHROUGH;
4154e98e3e1Schristos     case RX_Operand_Postinc:	/* [Rn+] */
416ba340e45Schristos     case RX_Operand_Zero_Indirect:	/* [Rn + 0] */
4174e98e3e1Schristos     case RX_Operand_Indirect:	/* [Rn + addend] */
4184e98e3e1Schristos     case RX_Operand_TwoReg:	/* [Rn + scale * R2] */
4194e98e3e1Schristos #ifdef CYCLE_ACCURATE
4204e98e3e1Schristos       RL (o->reg);
4214e98e3e1Schristos       if (o->type == RX_Operand_TwoReg)
4224e98e3e1Schristos 	RL (rd->op[2].reg);
4234e98e3e1Schristos       regs.rt = -1;
4244e98e3e1Schristos       if (regs.m2m == M2M_BOTH)
4254e98e3e1Schristos 	{
4264e98e3e1Schristos 	  tprintf("src memory stall\n");
4274b169a6bSchristos #ifdef WITH_PROFILE
4284e98e3e1Schristos 	  memory_stalls ++;
4294e98e3e1Schristos #endif
4304e98e3e1Schristos 	  regs.cycle_count ++;
4314e98e3e1Schristos 	  regs.m2m = 0;
4324e98e3e1Schristos 	}
4334e98e3e1Schristos 
4344e98e3e1Schristos       memory_source = 1;
4354e98e3e1Schristos #endif
4364e98e3e1Schristos 
4374e98e3e1Schristos       if (o->type == RX_Operand_TwoReg)
4384e98e3e1Schristos 	addr = get_reg (o->reg) * size2bytes[rd->size] + get_reg (rd->op[2].reg);
4394e98e3e1Schristos       else
4404e98e3e1Schristos 	addr = get_reg (o->reg) + o->addend;
4414e98e3e1Schristos 
4424e98e3e1Schristos       switch (o->size)
4434e98e3e1Schristos 	{
444ba340e45Schristos 	default:
4454e98e3e1Schristos 	case RX_AnySize:
4464e98e3e1Schristos 	  rx_abort ();
4474e98e3e1Schristos 
4484e98e3e1Schristos 	case RX_Byte: /* undefined extension */
4494e98e3e1Schristos 	case RX_UByte:
4504e98e3e1Schristos 	case RX_SByte:
4514e98e3e1Schristos 	  rv = mem_get_qi (addr);
4524e98e3e1Schristos 	  break;
4534e98e3e1Schristos 
4544e98e3e1Schristos 	case RX_Word: /* undefined extension */
4554e98e3e1Schristos 	case RX_UWord:
4564e98e3e1Schristos 	case RX_SWord:
4574e98e3e1Schristos 	  rv = mem_get_hi (addr);
4584e98e3e1Schristos 	  break;
4594e98e3e1Schristos 
4604e98e3e1Schristos 	case RX_3Byte:
4614e98e3e1Schristos 	  rv = mem_get_psi (addr);
4624e98e3e1Schristos 	  break;
4634e98e3e1Schristos 
4644e98e3e1Schristos 	case RX_Long:
4654e98e3e1Schristos 	  rv = mem_get_si (addr);
4664e98e3e1Schristos 	  break;
4674e98e3e1Schristos 	}
4684e98e3e1Schristos 
4694e98e3e1Schristos       if (o->type == RX_Operand_Postinc)
4704e98e3e1Schristos 	put_reg (o->reg, get_reg (o->reg) + size2bytes[o->size]);
4714e98e3e1Schristos 
4724e98e3e1Schristos       break;
4734e98e3e1Schristos 
4744e98e3e1Schristos     case RX_Operand_Condition:	/* eq, gtu, etc */
4754e98e3e1Schristos       return condition_true (o->reg);
4764e98e3e1Schristos 
4774e98e3e1Schristos     case RX_Operand_Flag:	/* [UIOSZC] */
4784e98e3e1Schristos       return (regs.r_psw & (1 << o->reg)) ? 1 : 0;
4794e98e3e1Schristos     }
4804e98e3e1Schristos 
4814e98e3e1Schristos   /* if we've gotten here, we need to clip/extend the value according
4824e98e3e1Schristos      to the size.  */
4834e98e3e1Schristos   switch (o->size)
4844e98e3e1Schristos     {
485ba340e45Schristos     default:
4864e98e3e1Schristos     case RX_AnySize:
4874e98e3e1Schristos       rx_abort ();
4884e98e3e1Schristos 
4894e98e3e1Schristos     case RX_Byte: /* undefined extension */
4904e98e3e1Schristos       rv |= 0xdeadbe00; /* keep them honest */
4914e98e3e1Schristos       break;
4924e98e3e1Schristos 
4934e98e3e1Schristos     case RX_UByte:
4944e98e3e1Schristos       rv &= 0xff;
4954e98e3e1Schristos       break;
4964e98e3e1Schristos 
4974e98e3e1Schristos     case RX_SByte:
4984e98e3e1Schristos       rv = sign_ext (rv, 8);
4994e98e3e1Schristos       break;
5004e98e3e1Schristos 
5014e98e3e1Schristos     case RX_Word: /* undefined extension */
5024e98e3e1Schristos       rv |= 0xdead0000; /* keep them honest */
5034e98e3e1Schristos       break;
5044e98e3e1Schristos 
5054e98e3e1Schristos     case RX_UWord:
5064e98e3e1Schristos       rv &=  0xffff;
5074e98e3e1Schristos       break;
5084e98e3e1Schristos 
5094e98e3e1Schristos     case RX_SWord:
5104e98e3e1Schristos       rv = sign_ext (rv, 16);
5114e98e3e1Schristos       break;
5124e98e3e1Schristos 
5134e98e3e1Schristos     case RX_3Byte:
5144e98e3e1Schristos       rv &= 0xffffff;
5154e98e3e1Schristos       break;
5164e98e3e1Schristos 
5174e98e3e1Schristos     case RX_Long:
5184e98e3e1Schristos       break;
5194e98e3e1Schristos     }
5204e98e3e1Schristos   return rv;
5214e98e3e1Schristos }
5224e98e3e1Schristos 
5234e98e3e1Schristos static void
5244e98e3e1Schristos put_op (const RX_Opcode_Decoded *rd, int i, int v)
5254e98e3e1Schristos {
5264e98e3e1Schristos   const RX_Opcode_Operand *o = rd->op + i;
5274e98e3e1Schristos   int addr;
5284e98e3e1Schristos 
5294e98e3e1Schristos   switch (o->size)
5304e98e3e1Schristos     {
531ba340e45Schristos     default:
5324e98e3e1Schristos     case RX_AnySize:
5334e98e3e1Schristos       if (o->type != RX_Operand_Register)
5344e98e3e1Schristos 	rx_abort ();
5354e98e3e1Schristos       break;
5364e98e3e1Schristos 
5374e98e3e1Schristos     case RX_Byte: /* undefined extension */
5384e98e3e1Schristos       v |= 0xdeadbe00; /* keep them honest */
5394e98e3e1Schristos       break;
5404e98e3e1Schristos 
5414e98e3e1Schristos     case RX_UByte:
5424e98e3e1Schristos       v &= 0xff;
5434e98e3e1Schristos       break;
5444e98e3e1Schristos 
5454e98e3e1Schristos     case RX_SByte:
5464e98e3e1Schristos       v = sign_ext (v, 8);
5474e98e3e1Schristos       break;
5484e98e3e1Schristos 
5494e98e3e1Schristos     case RX_Word: /* undefined extension */
5504e98e3e1Schristos       v |= 0xdead0000; /* keep them honest */
5514e98e3e1Schristos       break;
5524e98e3e1Schristos 
5534e98e3e1Schristos     case RX_UWord:
5544e98e3e1Schristos       v &=  0xffff;
5554e98e3e1Schristos       break;
5564e98e3e1Schristos 
5574e98e3e1Schristos     case RX_SWord:
5584e98e3e1Schristos       v = sign_ext (v, 16);
5594e98e3e1Schristos       break;
5604e98e3e1Schristos 
5614e98e3e1Schristos     case RX_3Byte:
5624e98e3e1Schristos       v &= 0xffffff;
5634e98e3e1Schristos       break;
5644e98e3e1Schristos 
5654e98e3e1Schristos     case RX_Long:
5664e98e3e1Schristos       break;
5674e98e3e1Schristos     }
5684e98e3e1Schristos 
5694e98e3e1Schristos   switch (o->type)
5704e98e3e1Schristos     {
5714e98e3e1Schristos     case RX_Operand_None:
5724e98e3e1Schristos       /* Opcodes like TST and CMP use this.  */
5734e98e3e1Schristos       break;
5744e98e3e1Schristos 
5754e98e3e1Schristos     case RX_Operand_Immediate:	/* #addend */
5764e98e3e1Schristos     case RX_Operand_Condition:	/* eq, gtu, etc */
5774e98e3e1Schristos       rx_abort ();
5784e98e3e1Schristos 
5794e98e3e1Schristos     case RX_Operand_Register:	/* Rn */
5804e98e3e1Schristos       put_reg (o->reg, v);
5814e98e3e1Schristos       RLD (o->reg);
5824e98e3e1Schristos       break;
5834e98e3e1Schristos 
5844e98e3e1Schristos     case RX_Operand_Predec:	/* [-Rn] */
5854e98e3e1Schristos       put_reg (o->reg, get_reg (o->reg) - size2bytes[o->size]);
586*1f4e7eb9Schristos       ATTRIBUTE_FALLTHROUGH;
5874e98e3e1Schristos     case RX_Operand_Postinc:	/* [Rn+] */
588ba340e45Schristos     case RX_Operand_Zero_Indirect:	/* [Rn + 0] */
5894e98e3e1Schristos     case RX_Operand_Indirect:	/* [Rn + addend] */
5904e98e3e1Schristos     case RX_Operand_TwoReg:	/* [Rn + scale * R2] */
5914e98e3e1Schristos 
5924e98e3e1Schristos #ifdef CYCLE_ACCURATE
5934e98e3e1Schristos       if (regs.m2m == M2M_BOTH)
5944e98e3e1Schristos 	{
5954e98e3e1Schristos 	  tprintf("dst memory stall\n");
5964e98e3e1Schristos 	  regs.cycle_count ++;
5974b169a6bSchristos #ifdef WITH_PROFILE
5984e98e3e1Schristos 	  memory_stalls ++;
5994e98e3e1Schristos #endif
6004e98e3e1Schristos 	  regs.m2m = 0;
6014e98e3e1Schristos 	}
6024e98e3e1Schristos       memory_dest = 1;
6034e98e3e1Schristos #endif
6044e98e3e1Schristos 
6054e98e3e1Schristos       if (o->type == RX_Operand_TwoReg)
6064e98e3e1Schristos 	addr = get_reg (o->reg) * size2bytes[rd->size] + get_reg (rd->op[2].reg);
6074e98e3e1Schristos       else
6084e98e3e1Schristos 	addr = get_reg (o->reg) + o->addend;
6094e98e3e1Schristos 
6104e98e3e1Schristos       switch (o->size)
6114e98e3e1Schristos 	{
612ba340e45Schristos 	default:
6134e98e3e1Schristos 	case RX_AnySize:
6144e98e3e1Schristos 	  rx_abort ();
6154e98e3e1Schristos 
6164e98e3e1Schristos 	case RX_Byte: /* undefined extension */
6174e98e3e1Schristos 	case RX_UByte:
6184e98e3e1Schristos 	case RX_SByte:
6194e98e3e1Schristos 	  mem_put_qi (addr, v);
6204e98e3e1Schristos 	  break;
6214e98e3e1Schristos 
6224e98e3e1Schristos 	case RX_Word: /* undefined extension */
6234e98e3e1Schristos 	case RX_UWord:
6244e98e3e1Schristos 	case RX_SWord:
6254e98e3e1Schristos 	  mem_put_hi (addr, v);
6264e98e3e1Schristos 	  break;
6274e98e3e1Schristos 
6284e98e3e1Schristos 	case RX_3Byte:
6294e98e3e1Schristos 	  mem_put_psi (addr, v);
6304e98e3e1Schristos 	  break;
6314e98e3e1Schristos 
6324e98e3e1Schristos 	case RX_Long:
6334e98e3e1Schristos 	  mem_put_si (addr, v);
6344e98e3e1Schristos 	  break;
6354e98e3e1Schristos 	}
6364e98e3e1Schristos 
6374e98e3e1Schristos       if (o->type == RX_Operand_Postinc)
6384e98e3e1Schristos 	put_reg (o->reg, get_reg (o->reg) + size2bytes[o->size]);
6394e98e3e1Schristos 
6404e98e3e1Schristos       break;
6414e98e3e1Schristos 
6424e98e3e1Schristos     case RX_Operand_Flag:	/* [UIOSZC] */
6434e98e3e1Schristos       if (v)
6444e98e3e1Schristos 	regs.r_psw |= (1 << o->reg);
6454e98e3e1Schristos       else
6464e98e3e1Schristos 	regs.r_psw &= ~(1 << o->reg);
6474e98e3e1Schristos       break;
6484e98e3e1Schristos     }
6494e98e3e1Schristos }
6504e98e3e1Schristos 
6514e98e3e1Schristos #define PD(x) put_op (opcode, 0, x)
6524e98e3e1Schristos #define PS(x) put_op (opcode, 1, x)
6534e98e3e1Schristos #define PS2(x) put_op (opcode, 2, x)
6544e98e3e1Schristos #define GD() get_op (opcode, 0)
6554e98e3e1Schristos #define GS() get_op (opcode, 1)
6564e98e3e1Schristos #define GS2() get_op (opcode, 2)
6574e98e3e1Schristos #define DSZ() size2bytes[opcode->op[0].size]
6584e98e3e1Schristos #define SSZ() size2bytes[opcode->op[0].size]
6594e98e3e1Schristos #define S2SZ() size2bytes[opcode->op[0].size]
6604e98e3e1Schristos 
6614e98e3e1Schristos /* "Universal" sources.  */
6624e98e3e1Schristos #define US1() ((opcode->op[2].type == RX_Operand_None) ? GD() : GS())
6634e98e3e1Schristos #define US2() ((opcode->op[2].type == RX_Operand_None) ? GS() : GS2())
6644e98e3e1Schristos 
6654e98e3e1Schristos static void
6664e98e3e1Schristos push(int val)
6674e98e3e1Schristos {
6684e98e3e1Schristos   int rsp = get_reg (sp);
6694e98e3e1Schristos   rsp -= 4;
6704e98e3e1Schristos   put_reg (sp, rsp);
6714e98e3e1Schristos   mem_put_si (rsp, val);
6724e98e3e1Schristos }
6734e98e3e1Schristos 
6744e98e3e1Schristos /* Just like the above, but tag the memory as "pushed pc" so if anyone
6754e98e3e1Schristos    tries to write to it, it will cause an error.  */
6764e98e3e1Schristos static void
6774e98e3e1Schristos pushpc(int val)
6784e98e3e1Schristos {
6794e98e3e1Schristos   int rsp = get_reg (sp);
6804e98e3e1Schristos   rsp -= 4;
6814e98e3e1Schristos   put_reg (sp, rsp);
6824e98e3e1Schristos   mem_put_si (rsp, val);
6834e98e3e1Schristos   mem_set_content_range (rsp, rsp+3, MC_PUSHED_PC);
6844e98e3e1Schristos }
6854e98e3e1Schristos 
6864e98e3e1Schristos static int
6874b169a6bSchristos pop (void)
6884e98e3e1Schristos {
6894e98e3e1Schristos   int rv;
6904e98e3e1Schristos   int rsp = get_reg (sp);
6914e98e3e1Schristos   rv = mem_get_si (rsp);
6924e98e3e1Schristos   rsp += 4;
6934e98e3e1Schristos   put_reg (sp, rsp);
6944e98e3e1Schristos   return rv;
6954e98e3e1Schristos }
6964e98e3e1Schristos 
6974e98e3e1Schristos static int
6984b169a6bSchristos poppc (void)
6994e98e3e1Schristos {
7004e98e3e1Schristos   int rv;
7014e98e3e1Schristos   int rsp = get_reg (sp);
7024e98e3e1Schristos   if (mem_get_content_type (rsp) != MC_PUSHED_PC)
7034e98e3e1Schristos     execution_error (SIM_ERR_CORRUPT_STACK, rsp);
7044e98e3e1Schristos   rv = mem_get_si (rsp);
7054e98e3e1Schristos   mem_set_content_range (rsp, rsp+3, MC_UNINIT);
7064e98e3e1Schristos   rsp += 4;
7074e98e3e1Schristos   put_reg (sp, rsp);
7084e98e3e1Schristos   return rv;
7094e98e3e1Schristos }
7104e98e3e1Schristos 
7114e98e3e1Schristos #define MATH_OP(vop,c)				\
7124e98e3e1Schristos { \
7134e98e3e1Schristos   umb = US2(); \
7144e98e3e1Schristos   uma = US1(); \
7154e98e3e1Schristos   ll = (unsigned long long) uma vop (unsigned long long) umb vop c; \
7164e98e3e1Schristos   tprintf ("0x%x " #vop " 0x%x " #vop " 0x%x = 0x%llx\n", uma, umb, c, ll); \
7174e98e3e1Schristos   ma = sign_ext (uma, DSZ() * 8);					\
7184e98e3e1Schristos   mb = sign_ext (umb, DSZ() * 8);					\
7194e98e3e1Schristos   sll = (long long) ma vop (long long) mb vop c; \
7204e98e3e1Schristos   tprintf ("%d " #vop " %d " #vop " %d = %lld\n", ma, mb, c, sll); \
7214e98e3e1Schristos   set_oszc (sll, DSZ(), (long long) ll > ((1 vop 1) ? (long long) b2mask[DSZ()] : (long long) -1)); \
7224e98e3e1Schristos   PD (sll); \
7234e98e3e1Schristos   E (1);    \
7244e98e3e1Schristos }
7254e98e3e1Schristos 
7264e98e3e1Schristos #define LOGIC_OP(vop) \
7274e98e3e1Schristos { \
7284e98e3e1Schristos   mb = US2(); \
7294e98e3e1Schristos   ma = US1(); \
7304e98e3e1Schristos   v = ma vop mb; \
7314e98e3e1Schristos   tprintf("0x%x " #vop " 0x%x = 0x%x\n", ma, mb, v); \
7324e98e3e1Schristos   set_sz (v, DSZ()); \
7334e98e3e1Schristos   PD(v); \
7344e98e3e1Schristos   E (1); \
7354e98e3e1Schristos }
7364e98e3e1Schristos 
7374e98e3e1Schristos #define SHIFT_OP(val, type, count, OP, carry_mask)	\
7384e98e3e1Schristos { \
7394e98e3e1Schristos   int i, c=0; \
7404e98e3e1Schristos   count = US2(); \
7414e98e3e1Schristos   val = (type)US1();				\
7424e98e3e1Schristos   tprintf("%lld " #OP " %d\n", val, count); \
7434e98e3e1Schristos   for (i = 0; i < count; i ++) \
7444e98e3e1Schristos     { \
7454e98e3e1Schristos       c = val & carry_mask; \
7464e98e3e1Schristos       val OP 1; \
7474e98e3e1Schristos     } \
7484e98e3e1Schristos   set_oszc (val, 4, c); \
7494e98e3e1Schristos   PD (val); \
7504e98e3e1Schristos }
7514e98e3e1Schristos 
7524e98e3e1Schristos typedef union {
7534e98e3e1Schristos   int i;
7544e98e3e1Schristos   float f;
7554e98e3e1Schristos } FloatInt;
7564e98e3e1Schristos 
757*1f4e7eb9Schristos ATTRIBUTE_UNUSED
7584e98e3e1Schristos static inline int
7594e98e3e1Schristos float2int (float f)
7604e98e3e1Schristos {
7614e98e3e1Schristos   FloatInt fi;
7624e98e3e1Schristos   fi.f = f;
7634e98e3e1Schristos   return fi.i;
7644e98e3e1Schristos }
7654e98e3e1Schristos 
7664e98e3e1Schristos static inline float
7674e98e3e1Schristos int2float (int i)
7684e98e3e1Schristos {
7694e98e3e1Schristos   FloatInt fi;
7704e98e3e1Schristos   fi.i = i;
7714e98e3e1Schristos   return fi.f;
7724e98e3e1Schristos }
7734e98e3e1Schristos 
7744e98e3e1Schristos static int
7754e98e3e1Schristos fop_fadd (fp_t s1, fp_t s2, fp_t *d)
7764e98e3e1Schristos {
7774e98e3e1Schristos   *d = rxfp_add (s1, s2);
7784e98e3e1Schristos   return 1;
7794e98e3e1Schristos }
7804e98e3e1Schristos 
7814e98e3e1Schristos static int
7824e98e3e1Schristos fop_fmul (fp_t s1, fp_t s2, fp_t *d)
7834e98e3e1Schristos {
7844e98e3e1Schristos   *d = rxfp_mul (s1, s2);
7854e98e3e1Schristos   return 1;
7864e98e3e1Schristos }
7874e98e3e1Schristos 
7884e98e3e1Schristos static int
7894e98e3e1Schristos fop_fdiv (fp_t s1, fp_t s2, fp_t *d)
7904e98e3e1Schristos {
7914e98e3e1Schristos   *d = rxfp_div (s1, s2);
7924e98e3e1Schristos   return 1;
7934e98e3e1Schristos }
7944e98e3e1Schristos 
7954e98e3e1Schristos static int
7964e98e3e1Schristos fop_fsub (fp_t s1, fp_t s2, fp_t *d)
7974e98e3e1Schristos {
7984e98e3e1Schristos   *d = rxfp_sub (s1, s2);
7994e98e3e1Schristos   return 1;
8004e98e3e1Schristos }
8014e98e3e1Schristos 
8024e98e3e1Schristos #define FPPENDING() (regs.r_fpsw & (FPSWBITS_CE | (FPSWBITS_FMASK & (regs.r_fpsw << FPSW_EFSH))))
8034e98e3e1Schristos #define FPCLEAR() regs.r_fpsw &= FPSWBITS_CLEAR
8044e98e3e1Schristos #define FPCHECK() \
8054e98e3e1Schristos   if (FPPENDING()) \
8064e98e3e1Schristos     return do_fp_exception (opcode_pc)
8074e98e3e1Schristos 
8084e98e3e1Schristos #define FLOAT_OP(func) \
8094e98e3e1Schristos { \
8104e98e3e1Schristos   int do_store;   \
8114e98e3e1Schristos   fp_t fa, fb, fc; \
8124e98e3e1Schristos   FPCLEAR(); \
8134e98e3e1Schristos   fb = GS (); \
8144e98e3e1Schristos   fa = GD (); \
8154e98e3e1Schristos   do_store = fop_##func (fa, fb, &fc); \
8164e98e3e1Schristos   tprintf("%g " #func " %g = %g %08x\n", int2float(fa), int2float(fb), int2float(fc), fc); \
8174e98e3e1Schristos   FPCHECK(); \
8184e98e3e1Schristos   if (do_store) \
8194e98e3e1Schristos     PD (fc);	\
8204e98e3e1Schristos   mb = 0; \
8214e98e3e1Schristos   if ((fc & 0x80000000UL) != 0) \
8224e98e3e1Schristos     mb |= FLAGBIT_S; \
8234e98e3e1Schristos   if ((fc & 0x7fffffffUL) == 0)			\
8244e98e3e1Schristos     mb |= FLAGBIT_Z; \
8254e98e3e1Schristos   set_flags (FLAGBIT_S | FLAGBIT_Z, mb); \
8264e98e3e1Schristos }
8274e98e3e1Schristos 
8284e98e3e1Schristos #define carry (FLAG_C ? 1 : 0)
8294e98e3e1Schristos 
8304e98e3e1Schristos static struct {
8314e98e3e1Schristos   unsigned long vaddr;
8324e98e3e1Schristos   const char *str;
8334e98e3e1Schristos   int signal;
8344e98e3e1Schristos } exception_info[] = {
8354e98e3e1Schristos   { 0xFFFFFFD0UL, "priviledged opcode", SIGILL },
8364e98e3e1Schristos   { 0xFFFFFFD4UL, "access violation", SIGSEGV },
8374e98e3e1Schristos   { 0xFFFFFFDCUL, "undefined opcode", SIGILL },
8384e98e3e1Schristos   { 0xFFFFFFE4UL, "floating point", SIGFPE }
8394e98e3e1Schristos };
8404e98e3e1Schristos #define EX_PRIVILEDGED	0
8414e98e3e1Schristos #define EX_ACCESS	1
8424e98e3e1Schristos #define EX_UNDEFINED	2
8434e98e3e1Schristos #define EX_FLOATING	3
8444e98e3e1Schristos #define EXCEPTION(n)  \
8454e98e3e1Schristos   return generate_exception (n, opcode_pc)
8464e98e3e1Schristos 
8474e98e3e1Schristos #define PRIVILEDGED() \
8484e98e3e1Schristos   if (FLAG_PM) \
8494e98e3e1Schristos     EXCEPTION (EX_PRIVILEDGED)
8504e98e3e1Schristos 
8514e98e3e1Schristos static int
8524e98e3e1Schristos generate_exception (unsigned long type, SI opcode_pc)
8534e98e3e1Schristos {
8544e98e3e1Schristos   SI old_psw, old_pc, new_pc;
8554e98e3e1Schristos 
8564e98e3e1Schristos   new_pc = mem_get_si (exception_info[type].vaddr);
8574e98e3e1Schristos   /* 0x00020000 is the value used to initialise the known
8584e98e3e1Schristos      exception vectors (see rx.ld), but it is a reserved
8594e98e3e1Schristos      area of memory so do not try to access it, and if the
8604e98e3e1Schristos      value has not been changed by the program then the
8614e98e3e1Schristos      vector has not been installed.  */
8624e98e3e1Schristos   if (new_pc == 0 || new_pc == 0x00020000)
8634e98e3e1Schristos     {
8644e98e3e1Schristos       if (rx_in_gdb)
8654e98e3e1Schristos 	return RX_MAKE_STOPPED (exception_info[type].signal);
8664e98e3e1Schristos 
8674e98e3e1Schristos       fprintf(stderr, "Unhandled %s exception at pc = %#lx\n",
8684e98e3e1Schristos 	      exception_info[type].str, (unsigned long) opcode_pc);
8694e98e3e1Schristos       if (type == EX_FLOATING)
8704e98e3e1Schristos 	{
8714e98e3e1Schristos 	  int mask = FPPENDING ();
8724e98e3e1Schristos 	  fprintf (stderr, "Pending FP exceptions:");
8734e98e3e1Schristos 	  if (mask & FPSWBITS_FV)
8744e98e3e1Schristos 	    fprintf(stderr, " Invalid");
8754e98e3e1Schristos 	  if (mask & FPSWBITS_FO)
8764e98e3e1Schristos 	    fprintf(stderr, " Overflow");
8774e98e3e1Schristos 	  if (mask & FPSWBITS_FZ)
8784e98e3e1Schristos 	    fprintf(stderr, " Division-by-zero");
8794e98e3e1Schristos 	  if (mask & FPSWBITS_FU)
8804e98e3e1Schristos 	    fprintf(stderr, " Underflow");
8814e98e3e1Schristos 	  if (mask & FPSWBITS_FX)
8824e98e3e1Schristos 	    fprintf(stderr, " Inexact");
8834e98e3e1Schristos 	  if (mask & FPSWBITS_CE)
8844e98e3e1Schristos 	    fprintf(stderr, " Unimplemented");
8854e98e3e1Schristos 	  fprintf(stderr, "\n");
8864e98e3e1Schristos 	}
8874e98e3e1Schristos       return RX_MAKE_EXITED (1);
8884e98e3e1Schristos     }
8894e98e3e1Schristos 
8904e98e3e1Schristos   tprintf ("Triggering %s exception\n", exception_info[type].str);
8914e98e3e1Schristos 
8924e98e3e1Schristos   old_psw = regs.r_psw;
8934e98e3e1Schristos   regs.r_psw &= ~ (FLAGBIT_I | FLAGBIT_U | FLAGBIT_PM);
8944e98e3e1Schristos   old_pc = opcode_pc;
8954e98e3e1Schristos   regs.r_pc = new_pc;
8964e98e3e1Schristos   pushpc (old_psw);
8974e98e3e1Schristos   pushpc (old_pc);
8984e98e3e1Schristos   return RX_MAKE_STEPPED ();
8994e98e3e1Schristos }
9004e98e3e1Schristos 
9014e98e3e1Schristos void
9024e98e3e1Schristos generate_access_exception (void)
9034e98e3e1Schristos {
9044e98e3e1Schristos   int rv;
9054e98e3e1Schristos 
9064e98e3e1Schristos   rv = generate_exception (EX_ACCESS, regs.r_pc);
9074e98e3e1Schristos   if (RX_EXITED (rv))
9084e98e3e1Schristos     longjmp (decode_jmp_buf, rv);
9094e98e3e1Schristos }
9104e98e3e1Schristos 
9114e98e3e1Schristos static int
9124e98e3e1Schristos do_fp_exception (unsigned long opcode_pc)
9134e98e3e1Schristos {
9144e98e3e1Schristos   while (FPPENDING())
9154e98e3e1Schristos     EXCEPTION (EX_FLOATING);
9164e98e3e1Schristos   return RX_MAKE_STEPPED ();
9174e98e3e1Schristos }
9184e98e3e1Schristos 
9194e98e3e1Schristos static int
9204e98e3e1Schristos op_is_memory (const RX_Opcode_Decoded *rd, int i)
9214e98e3e1Schristos {
9224e98e3e1Schristos   switch (rd->op[i].type)
9234e98e3e1Schristos     {
9244e98e3e1Schristos     case RX_Operand_Predec:
9254e98e3e1Schristos     case RX_Operand_Postinc:
9264e98e3e1Schristos     case RX_Operand_Indirect:
9274e98e3e1Schristos       return 1;
9284e98e3e1Schristos     default:
9294e98e3e1Schristos       return 0;
9304e98e3e1Schristos     }
9314e98e3e1Schristos }
9324e98e3e1Schristos #define OM(i) op_is_memory (opcode, i)
9334e98e3e1Schristos 
9344e98e3e1Schristos #define DO_RETURN(x) { longjmp (decode_jmp_buf, x); }
9354e98e3e1Schristos 
9364e98e3e1Schristos int
9374b169a6bSchristos decode_opcode (void)
9384e98e3e1Schristos {
9394e98e3e1Schristos   unsigned int uma=0, umb=0;
9404e98e3e1Schristos   int ma=0, mb=0;
9414e98e3e1Schristos   int opcode_size, v;
9424e98e3e1Schristos   unsigned long long ll;
9434e98e3e1Schristos   long long sll;
9444e98e3e1Schristos   unsigned long opcode_pc;
9454e98e3e1Schristos   RX_Data rx_data;
9464e98e3e1Schristos   const RX_Opcode_Decoded *opcode;
9474b169a6bSchristos #ifdef WITH_PROFILE
9484e98e3e1Schristos   unsigned long long prev_cycle_count;
9494e98e3e1Schristos #endif
9504e98e3e1Schristos #ifdef CYCLE_ACCURATE
9514e98e3e1Schristos   unsigned int tx;
9524e98e3e1Schristos #endif
9534e98e3e1Schristos 
9544b169a6bSchristos #ifdef WITH_PROFILE
9554e98e3e1Schristos   prev_cycle_count = regs.cycle_count;
9564e98e3e1Schristos #endif
9574e98e3e1Schristos 
9584e98e3e1Schristos #ifdef CYCLE_ACCURATE
9594e98e3e1Schristos   memory_source = 0;
9604e98e3e1Schristos   memory_dest = 0;
9614e98e3e1Schristos #endif
9624e98e3e1Schristos 
9634e98e3e1Schristos   rx_cycles ++;
9644e98e3e1Schristos 
9654e98e3e1Schristos   maybe_get_mem_page (regs.r_pc);
9664e98e3e1Schristos 
9674e98e3e1Schristos   opcode_pc = regs.r_pc;
9684e98e3e1Schristos 
9694e98e3e1Schristos   /* Note that we don't word-swap this point, there's no point.  */
9704e98e3e1Schristos   if (decode_cache_base[opcode_pc] == NULL)
9714e98e3e1Schristos     {
9724e98e3e1Schristos       RX_Opcode_Decoded *opcode_w;
9734e98e3e1Schristos       rx_data.dpc = opcode_pc;
9744e98e3e1Schristos       opcode_w = decode_cache_base[opcode_pc] = calloc (1, sizeof (RX_Opcode_Decoded));
9754e98e3e1Schristos       opcode_size = rx_decode_opcode (opcode_pc, opcode_w,
9764e98e3e1Schristos 				      rx_get_byte, &rx_data);
9774e98e3e1Schristos       opcode = opcode_w;
9784e98e3e1Schristos     }
9794e98e3e1Schristos   else
9804e98e3e1Schristos     {
9814e98e3e1Schristos       opcode = decode_cache_base[opcode_pc];
9824e98e3e1Schristos       opcode_size = opcode->n_bytes;
9834e98e3e1Schristos     }
9844e98e3e1Schristos 
9854e98e3e1Schristos #ifdef CYCLE_ACCURATE
9864e98e3e1Schristos   if (branch_alignment_penalty)
9874e98e3e1Schristos     {
9884e98e3e1Schristos       if ((regs.r_pc ^ (regs.r_pc + opcode_size - 1)) & ~7)
9894e98e3e1Schristos 	{
9904e98e3e1Schristos 	  tprintf("1 cycle branch alignment penalty\n");
9914e98e3e1Schristos 	  cycles (branch_alignment_penalty);
9924b169a6bSchristos #ifdef WITH_PROFILE
9934e98e3e1Schristos 	  branch_alignment_stalls ++;
9944e98e3e1Schristos #endif
9954e98e3e1Schristos 	}
9964e98e3e1Schristos       branch_alignment_penalty = 0;
9974e98e3e1Schristos     }
9984e98e3e1Schristos #endif
9994e98e3e1Schristos 
10004e98e3e1Schristos   regs.r_pc += opcode_size;
10014e98e3e1Schristos 
10024e98e3e1Schristos   rx_flagmask = opcode->flags_s;
10034e98e3e1Schristos   rx_flagand = ~(int)opcode->flags_0;
10044e98e3e1Schristos   rx_flagor = opcode->flags_1;
10054e98e3e1Schristos 
10064e98e3e1Schristos   switch (opcode->id)
10074e98e3e1Schristos     {
10084e98e3e1Schristos     case RXO_abs:
10094e98e3e1Schristos       sll = GS ();
10104e98e3e1Schristos       tprintf("|%lld| = ", sll);
10114e98e3e1Schristos       if (sll < 0)
10124e98e3e1Schristos 	sll = -sll;
10134e98e3e1Schristos       tprintf("%lld\n", sll);
10144e98e3e1Schristos       PD (sll);
10154e98e3e1Schristos       set_osz (sll, 4);
10164e98e3e1Schristos       E (1);
10174e98e3e1Schristos       break;
10184e98e3e1Schristos 
10194e98e3e1Schristos     case RXO_adc:
10204e98e3e1Schristos       MATH_OP (+,carry);
10214e98e3e1Schristos       break;
10224e98e3e1Schristos 
10234e98e3e1Schristos     case RXO_add:
10244e98e3e1Schristos       MATH_OP (+,0);
10254e98e3e1Schristos       break;
10264e98e3e1Schristos 
10274e98e3e1Schristos     case RXO_and:
10284e98e3e1Schristos       LOGIC_OP (&);
10294e98e3e1Schristos       break;
10304e98e3e1Schristos 
10314e98e3e1Schristos     case RXO_bclr:
10324e98e3e1Schristos       ma = GD ();
10334e98e3e1Schristos       mb = GS ();
10344e98e3e1Schristos       if (opcode->op[0].type == RX_Operand_Register)
10354e98e3e1Schristos 	mb &= 0x1f;
10364e98e3e1Schristos       else
10374e98e3e1Schristos 	mb &= 0x07;
10384e98e3e1Schristos       ma &= ~(1 << mb);
10394e98e3e1Schristos       PD (ma);
10404e98e3e1Schristos       EBIT;
10414e98e3e1Schristos       break;
10424e98e3e1Schristos 
10434e98e3e1Schristos     case RXO_bmcc:
10444e98e3e1Schristos       ma = GD ();
10454e98e3e1Schristos       mb = GS ();
10464e98e3e1Schristos       if (opcode->op[0].type == RX_Operand_Register)
10474e98e3e1Schristos 	mb &= 0x1f;
10484e98e3e1Schristos       else
10494e98e3e1Schristos 	mb &= 0x07;
10504e98e3e1Schristos       if (GS2 ())
10514e98e3e1Schristos 	ma |= (1 << mb);
10524e98e3e1Schristos       else
10534e98e3e1Schristos 	ma &= ~(1 << mb);
10544e98e3e1Schristos       PD (ma);
10554e98e3e1Schristos       EBIT;
10564e98e3e1Schristos       break;
10574e98e3e1Schristos 
10584e98e3e1Schristos     case RXO_bnot:
10594e98e3e1Schristos       ma = GD ();
10604e98e3e1Schristos       mb = GS ();
10614e98e3e1Schristos       if (opcode->op[0].type == RX_Operand_Register)
10624e98e3e1Schristos 	mb &= 0x1f;
10634e98e3e1Schristos       else
10644e98e3e1Schristos 	mb &= 0x07;
10654e98e3e1Schristos       ma ^= (1 << mb);
10664e98e3e1Schristos       PD (ma);
10674e98e3e1Schristos       EBIT;
10684e98e3e1Schristos       break;
10694e98e3e1Schristos 
10704e98e3e1Schristos     case RXO_branch:
10714e98e3e1Schristos       if (opcode->op[1].type == RX_Operand_None || GS())
10724e98e3e1Schristos 	{
10734e98e3e1Schristos #ifdef CYCLE_ACCURATE
10744e98e3e1Schristos 	  SI old_pc = regs.r_pc;
10754e98e3e1Schristos 	  int delta;
10764e98e3e1Schristos #endif
10774e98e3e1Schristos 	  regs.r_pc = GD();
10784e98e3e1Schristos #ifdef CYCLE_ACCURATE
10794e98e3e1Schristos 	  delta = regs.r_pc - old_pc;
10804e98e3e1Schristos 	  if (delta >= 0 && delta < 16
10814e98e3e1Schristos 	      && opcode_size > 1)
10824e98e3e1Schristos 	    {
10834e98e3e1Schristos 	      tprintf("near forward branch bonus\n");
10844e98e3e1Schristos 	      cycles (2);
10854e98e3e1Schristos 	    }
10864e98e3e1Schristos 	  else
10874e98e3e1Schristos 	    {
10884e98e3e1Schristos 	      cycles (3);
10894e98e3e1Schristos 	      branch_alignment_penalty = 1;
10904e98e3e1Schristos 	    }
10914b169a6bSchristos #ifdef WITH_PROFILE
10924e98e3e1Schristos 	  branch_stalls ++;
10934e98e3e1Schristos #endif
10944e98e3e1Schristos #endif
10954e98e3e1Schristos 	}
10964e98e3e1Schristos #ifdef CYCLE_ACCURATE
10974e98e3e1Schristos       else
10984e98e3e1Schristos 	cycles (1);
10994e98e3e1Schristos #endif
11004e98e3e1Schristos       break;
11014e98e3e1Schristos 
11024e98e3e1Schristos     case RXO_branchrel:
11034e98e3e1Schristos       if (opcode->op[1].type == RX_Operand_None || GS())
11044e98e3e1Schristos 	{
11054e98e3e1Schristos 	  int delta = GD();
11064e98e3e1Schristos 	  regs.r_pc = opcode_pc + delta;
11074e98e3e1Schristos #ifdef CYCLE_ACCURATE
11084e98e3e1Schristos 	  /* Note: specs say 3, chip says 2.  */
11094e98e3e1Schristos 	  if (delta >= 0 && delta < 16
11104e98e3e1Schristos 	      && opcode_size > 1)
11114e98e3e1Schristos 	    {
11124e98e3e1Schristos 	      tprintf("near forward branch bonus\n");
11134e98e3e1Schristos 	      cycles (2);
11144e98e3e1Schristos 	    }
11154e98e3e1Schristos 	  else
11164e98e3e1Schristos 	    {
11174e98e3e1Schristos 	      cycles (3);
11184e98e3e1Schristos 	      branch_alignment_penalty = 1;
11194e98e3e1Schristos 	    }
11204b169a6bSchristos #ifdef WITH_PROFILE
11214e98e3e1Schristos 	  branch_stalls ++;
11224e98e3e1Schristos #endif
11234e98e3e1Schristos #endif
11244e98e3e1Schristos 	}
11254e98e3e1Schristos #ifdef CYCLE_ACCURATE
11264e98e3e1Schristos       else
11274e98e3e1Schristos 	cycles (1);
11284e98e3e1Schristos #endif
11294e98e3e1Schristos       break;
11304e98e3e1Schristos 
11314e98e3e1Schristos     case RXO_brk:
11324e98e3e1Schristos       {
11334e98e3e1Schristos 	int old_psw = regs.r_psw;
11344e98e3e1Schristos 	if (rx_in_gdb)
11354e98e3e1Schristos 	  DO_RETURN (RX_MAKE_HIT_BREAK ());
11364e98e3e1Schristos 	if (regs.r_intb == 0)
11374e98e3e1Schristos 	  {
11384e98e3e1Schristos 	    tprintf("BREAK hit, no vector table.\n");
11394e98e3e1Schristos 	    DO_RETURN (RX_MAKE_EXITED(1));
11404e98e3e1Schristos 	  }
11414e98e3e1Schristos 	regs.r_psw &= ~(FLAGBIT_I | FLAGBIT_U | FLAGBIT_PM);
11424e98e3e1Schristos 	pushpc (old_psw);
11434e98e3e1Schristos 	pushpc (regs.r_pc);
11444e98e3e1Schristos 	regs.r_pc = mem_get_si (regs.r_intb);
11454e98e3e1Schristos 	cycles(6);
11464e98e3e1Schristos       }
11474e98e3e1Schristos       break;
11484e98e3e1Schristos 
11494e98e3e1Schristos     case RXO_bset:
11504e98e3e1Schristos       ma = GD ();
11514e98e3e1Schristos       mb = GS ();
11524e98e3e1Schristos       if (opcode->op[0].type == RX_Operand_Register)
11534e98e3e1Schristos 	mb &= 0x1f;
11544e98e3e1Schristos       else
11554e98e3e1Schristos 	mb &= 0x07;
11564e98e3e1Schristos       ma |= (1 << mb);
11574e98e3e1Schristos       PD (ma);
11584e98e3e1Schristos       EBIT;
11594e98e3e1Schristos       break;
11604e98e3e1Schristos 
11614e98e3e1Schristos     case RXO_btst:
11624e98e3e1Schristos       ma = GS ();
11634e98e3e1Schristos       mb = GS2 ();
11644e98e3e1Schristos       if (opcode->op[1].type == RX_Operand_Register)
11654e98e3e1Schristos 	mb &= 0x1f;
11664e98e3e1Schristos       else
11674e98e3e1Schristos 	mb &= 0x07;
11684e98e3e1Schristos       umb = ma & (1 << mb);
11694e98e3e1Schristos       set_zc (! umb, umb);
11704e98e3e1Schristos       EBIT;
11714e98e3e1Schristos       break;
11724e98e3e1Schristos 
11734e98e3e1Schristos     case RXO_clrpsw:
11744e98e3e1Schristos       v = 1 << opcode->op[0].reg;
11754e98e3e1Schristos       if (FLAG_PM
11764e98e3e1Schristos 	  && (v == FLAGBIT_I
11774e98e3e1Schristos 	      || v == FLAGBIT_U))
11784e98e3e1Schristos 	break;
11794e98e3e1Schristos       regs.r_psw &= ~v;
11804e98e3e1Schristos       cycles (1);
11814e98e3e1Schristos       break;
11824e98e3e1Schristos 
11834e98e3e1Schristos     case RXO_div: /* d = d / s */
11844e98e3e1Schristos       ma = GS();
11854e98e3e1Schristos       mb = GD();
11864e98e3e1Schristos       tprintf("%d / %d = ", mb, ma);
11874e98e3e1Schristos       if (ma == 0 || (ma == -1 && (unsigned int) mb == 0x80000000))
11884e98e3e1Schristos 	{
11894e98e3e1Schristos 	  tprintf("#NAN\n");
11904e98e3e1Schristos 	  set_flags (FLAGBIT_O, FLAGBIT_O);
11914e98e3e1Schristos 	  cycles (3);
11924e98e3e1Schristos 	}
11934e98e3e1Schristos       else
11944e98e3e1Schristos 	{
11954e98e3e1Schristos 	  v = mb/ma;
11964e98e3e1Schristos 	  tprintf("%d\n", v);
11974e98e3e1Schristos 	  set_flags (FLAGBIT_O, 0);
11984e98e3e1Schristos 	  PD (v);
11994e98e3e1Schristos 	  div_cycles (mb, ma);
12004e98e3e1Schristos 	}
12014e98e3e1Schristos       break;
12024e98e3e1Schristos 
12034e98e3e1Schristos     case RXO_divu: /* d = d / s */
12044e98e3e1Schristos       uma = GS();
12054e98e3e1Schristos       umb = GD();
12064e98e3e1Schristos       tprintf("%u / %u = ", umb, uma);
12074e98e3e1Schristos       if (uma == 0)
12084e98e3e1Schristos 	{
12094e98e3e1Schristos 	  tprintf("#NAN\n");
12104e98e3e1Schristos 	  set_flags (FLAGBIT_O, FLAGBIT_O);
12114e98e3e1Schristos 	  cycles (2);
12124e98e3e1Schristos 	}
12134e98e3e1Schristos       else
12144e98e3e1Schristos 	{
12154e98e3e1Schristos 	  v = umb / uma;
12164e98e3e1Schristos 	  tprintf("%u\n", v);
12174e98e3e1Schristos 	  set_flags (FLAGBIT_O, 0);
12184e98e3e1Schristos 	  PD (v);
12194e98e3e1Schristos 	  divu_cycles (umb, uma);
12204e98e3e1Schristos 	}
12214e98e3e1Schristos       break;
12224e98e3e1Schristos 
12234e98e3e1Schristos     case RXO_emul:
12244e98e3e1Schristos       ma = GD ();
12254e98e3e1Schristos       mb = GS ();
12264e98e3e1Schristos       sll = (long long)ma * (long long)mb;
12274e98e3e1Schristos       tprintf("%d * %d = %lld\n", ma, mb, sll);
12284e98e3e1Schristos       put_reg (opcode->op[0].reg, sll);
12294e98e3e1Schristos       put_reg (opcode->op[0].reg + 1, sll >> 32);
12304e98e3e1Schristos       E2;
12314e98e3e1Schristos       break;
12324e98e3e1Schristos 
12334e98e3e1Schristos     case RXO_emulu:
12344e98e3e1Schristos       uma = GD ();
12354e98e3e1Schristos       umb = GS ();
12364e98e3e1Schristos       ll = (long long)uma * (long long)umb;
12374e98e3e1Schristos       tprintf("%#x * %#x = %#llx\n", uma, umb, ll);
12384e98e3e1Schristos       put_reg (opcode->op[0].reg, ll);
12394e98e3e1Schristos       put_reg (opcode->op[0].reg + 1, ll >> 32);
12404e98e3e1Schristos       E2;
12414e98e3e1Schristos       break;
12424e98e3e1Schristos 
12434e98e3e1Schristos     case RXO_fadd:
12444e98e3e1Schristos       FLOAT_OP (fadd);
12454e98e3e1Schristos       E (4);
12464e98e3e1Schristos       break;
12474e98e3e1Schristos 
12484e98e3e1Schristos     case RXO_fcmp:
12494e98e3e1Schristos       ma = GD();
12504e98e3e1Schristos       mb = GS();
12514e98e3e1Schristos       FPCLEAR ();
12524e98e3e1Schristos       rxfp_cmp (ma, mb);
12534e98e3e1Schristos       FPCHECK ();
12544e98e3e1Schristos       E (1);
12554e98e3e1Schristos       break;
12564e98e3e1Schristos 
12574e98e3e1Schristos     case RXO_fdiv:
12584e98e3e1Schristos       FLOAT_OP (fdiv);
12594e98e3e1Schristos       E (16);
12604e98e3e1Schristos       break;
12614e98e3e1Schristos 
12624e98e3e1Schristos     case RXO_fmul:
12634e98e3e1Schristos       FLOAT_OP (fmul);
12644e98e3e1Schristos       E (3);
12654e98e3e1Schristos       break;
12664e98e3e1Schristos 
12674e98e3e1Schristos     case RXO_rtfi:
12684e98e3e1Schristos       PRIVILEDGED ();
12694e98e3e1Schristos       regs.r_psw = regs.r_bpsw;
12704e98e3e1Schristos       regs.r_pc = regs.r_bpc;
12714e98e3e1Schristos #ifdef CYCLE_ACCURATE
12724e98e3e1Schristos       regs.fast_return = 0;
12734e98e3e1Schristos       cycles(3);
12744e98e3e1Schristos #endif
12754e98e3e1Schristos       break;
12764e98e3e1Schristos 
12774e98e3e1Schristos     case RXO_fsub:
12784e98e3e1Schristos       FLOAT_OP (fsub);
12794e98e3e1Schristos       E (4);
12804e98e3e1Schristos       break;
12814e98e3e1Schristos 
12824e98e3e1Schristos     case RXO_ftoi:
12834e98e3e1Schristos       ma = GS ();
12844e98e3e1Schristos       FPCLEAR ();
12854e98e3e1Schristos       mb = rxfp_ftoi (ma, FPRM_ZERO);
12864e98e3e1Schristos       FPCHECK ();
12874e98e3e1Schristos       PD (mb);
12884e98e3e1Schristos       tprintf("(int) %g = %d\n", int2float(ma), mb);
12894e98e3e1Schristos       set_sz (mb, 4);
12904e98e3e1Schristos       E (2);
12914e98e3e1Schristos       break;
12924e98e3e1Schristos 
12934e98e3e1Schristos     case RXO_int:
12944e98e3e1Schristos       v = GS ();
12954e98e3e1Schristos       if (v == 255)
12964e98e3e1Schristos 	{
12974e98e3e1Schristos 	  int rc = rx_syscall (regs.r[5]);
12984e98e3e1Schristos 	  if (! RX_STEPPED (rc))
12994e98e3e1Schristos 	    DO_RETURN (rc);
13004e98e3e1Schristos 	}
13014e98e3e1Schristos       else
13024e98e3e1Schristos 	{
13034e98e3e1Schristos 	  int old_psw = regs.r_psw;
13044e98e3e1Schristos 	  regs.r_psw &= ~(FLAGBIT_I | FLAGBIT_U | FLAGBIT_PM);
13054e98e3e1Schristos 	  pushpc (old_psw);
13064e98e3e1Schristos 	  pushpc (regs.r_pc);
13074e98e3e1Schristos 	  regs.r_pc = mem_get_si (regs.r_intb + 4 * v);
13084e98e3e1Schristos 	}
13094e98e3e1Schristos       cycles (6);
13104e98e3e1Schristos       break;
13114e98e3e1Schristos 
13124e98e3e1Schristos     case RXO_itof:
13134e98e3e1Schristos       ma = GS ();
13144e98e3e1Schristos       FPCLEAR ();
13154e98e3e1Schristos       mb = rxfp_itof (ma, regs.r_fpsw);
13164e98e3e1Schristos       FPCHECK ();
13174e98e3e1Schristos       tprintf("(float) %d = %x\n", ma, mb);
13184e98e3e1Schristos       PD (mb);
13194e98e3e1Schristos       set_sz (ma, 4);
13204e98e3e1Schristos       E (2);
13214e98e3e1Schristos       break;
13224e98e3e1Schristos 
13234e98e3e1Schristos     case RXO_jsr:
13244e98e3e1Schristos     case RXO_jsrrel:
13254e98e3e1Schristos       {
13264e98e3e1Schristos #ifdef CYCLE_ACCURATE
13274e98e3e1Schristos 	int delta;
13284e98e3e1Schristos 	regs.m2m = 0;
13294e98e3e1Schristos #endif
13304e98e3e1Schristos 	v = GD ();
13314e98e3e1Schristos #ifdef CYCLE_ACCURATE
13324e98e3e1Schristos 	regs.link_register = regs.r_pc;
13334e98e3e1Schristos #endif
13344e98e3e1Schristos 	pushpc (get_reg (pc));
13354e98e3e1Schristos 	if (opcode->id == RXO_jsrrel)
13364e98e3e1Schristos 	  v += regs.r_pc;
13374e98e3e1Schristos #ifdef CYCLE_ACCURATE
13384e98e3e1Schristos 	delta = v - regs.r_pc;
13394e98e3e1Schristos #endif
13404e98e3e1Schristos 	put_reg (pc, v);
13414e98e3e1Schristos #ifdef CYCLE_ACCURATE
13424e98e3e1Schristos 	/* Note: docs say 3, chip says 2 */
13434e98e3e1Schristos 	if (delta >= 0 && delta < 16)
13444e98e3e1Schristos 	  {
13454e98e3e1Schristos 	    tprintf ("near forward jsr bonus\n");
13464e98e3e1Schristos 	    cycles (2);
13474e98e3e1Schristos 	  }
13484e98e3e1Schristos 	else
13494e98e3e1Schristos 	  {
13504e98e3e1Schristos 	    branch_alignment_penalty = 1;
13514e98e3e1Schristos 	    cycles (3);
13524e98e3e1Schristos 	  }
13534e98e3e1Schristos 	regs.fast_return = 1;
13544e98e3e1Schristos #endif
13554e98e3e1Schristos       }
13564e98e3e1Schristos       break;
13574e98e3e1Schristos 
13584e98e3e1Schristos     case RXO_machi:
13594e98e3e1Schristos       ll = (long long)(signed short)(GS() >> 16) * (long long)(signed short)(GS2 () >> 16);
13604e98e3e1Schristos       ll <<= 16;
13614e98e3e1Schristos       put_reg64 (acc64, ll + regs.r_acc);
13624e98e3e1Schristos       E1;
13634e98e3e1Schristos       break;
13644e98e3e1Schristos 
13654e98e3e1Schristos     case RXO_maclo:
13664e98e3e1Schristos       ll = (long long)(signed short)(GS()) * (long long)(signed short)(GS2 ());
13674e98e3e1Schristos       ll <<= 16;
13684e98e3e1Schristos       put_reg64 (acc64, ll + regs.r_acc);
13694e98e3e1Schristos       E1;
13704e98e3e1Schristos       break;
13714e98e3e1Schristos 
13724e98e3e1Schristos     case RXO_max:
13734e98e3e1Schristos       mb = GS();
13744e98e3e1Schristos       ma = GD();
13754e98e3e1Schristos       if (ma > mb)
13764e98e3e1Schristos 	PD (ma);
13774e98e3e1Schristos       else
13784e98e3e1Schristos 	PD (mb);
13794e98e3e1Schristos       E (1);
13804e98e3e1Schristos       break;
13814e98e3e1Schristos 
13824e98e3e1Schristos     case RXO_min:
13834e98e3e1Schristos       mb = GS();
13844e98e3e1Schristos       ma = GD();
13854e98e3e1Schristos       if (ma < mb)
13864e98e3e1Schristos 	PD (ma);
13874e98e3e1Schristos       else
13884e98e3e1Schristos 	PD (mb);
13894e98e3e1Schristos       E (1);
13904e98e3e1Schristos       break;
13914e98e3e1Schristos 
13924e98e3e1Schristos     case RXO_mov:
13934e98e3e1Schristos       v = GS ();
13944e98e3e1Schristos 
13954e98e3e1Schristos       if (opcode->op[1].type == RX_Operand_Register
13964e98e3e1Schristos 	  && opcode->op[1].reg == 17 /* PC */)
13974e98e3e1Schristos 	{
13984e98e3e1Schristos 	  /* Special case.  We want the address of the insn, not the
13994e98e3e1Schristos 	     address of the next insn.  */
14004e98e3e1Schristos 	  v = opcode_pc;
14014e98e3e1Schristos 	}
14024e98e3e1Schristos 
14034e98e3e1Schristos       if (opcode->op[0].type == RX_Operand_Register
14044e98e3e1Schristos 	  && opcode->op[0].reg == 16 /* PSW */)
14054e98e3e1Schristos 	{
14064e98e3e1Schristos 	  /* Special case, LDC and POPC can't ever modify PM.  */
14074e98e3e1Schristos 	  int pm = regs.r_psw & FLAGBIT_PM;
14084e98e3e1Schristos 	  v &= ~ FLAGBIT_PM;
14094e98e3e1Schristos 	  v |= pm;
14104e98e3e1Schristos 	  if (pm)
14114e98e3e1Schristos 	    {
14124e98e3e1Schristos 	      v &= ~ (FLAGBIT_I | FLAGBIT_U | FLAGBITS_IPL);
14134e98e3e1Schristos 	      v |= pm;
14144e98e3e1Schristos 	    }
14154e98e3e1Schristos 	}
14164e98e3e1Schristos       if (FLAG_PM)
14174e98e3e1Schristos 	{
14184e98e3e1Schristos 	  /* various things can't be changed in user mode.  */
14194e98e3e1Schristos 	  if (opcode->op[0].type == RX_Operand_Register)
14204e98e3e1Schristos 	    if (opcode->op[0].reg == 32)
14214e98e3e1Schristos 	      {
14224e98e3e1Schristos 		v &= ~ (FLAGBIT_I | FLAGBIT_U | FLAGBITS_IPL);
14234e98e3e1Schristos 		v |= regs.r_psw & (FLAGBIT_I | FLAGBIT_U | FLAGBITS_IPL);
14244e98e3e1Schristos 	      }
14254e98e3e1Schristos 	  if (opcode->op[0].reg == 34 /* ISP */
14264e98e3e1Schristos 	      || opcode->op[0].reg == 37 /* BPSW */
14274e98e3e1Schristos 	      || opcode->op[0].reg == 39 /* INTB */
14284e98e3e1Schristos 	      || opcode->op[0].reg == 38 /* VCT */)
14294e98e3e1Schristos 	    /* These are ignored.  */
14304e98e3e1Schristos 	    break;
14314e98e3e1Schristos 	}
14324e98e3e1Schristos       if (OM(0) && OM(1))
14334e98e3e1Schristos 	cycles (2);
14344e98e3e1Schristos       else
14354e98e3e1Schristos 	cycles (1);
14364e98e3e1Schristos 
14374e98e3e1Schristos       PD (v);
14384e98e3e1Schristos 
14394e98e3e1Schristos #ifdef CYCLE_ACCURATE
14404e98e3e1Schristos       if ((opcode->op[0].type == RX_Operand_Predec
14414e98e3e1Schristos 	   && opcode->op[1].type == RX_Operand_Register)
14424e98e3e1Schristos 	  || (opcode->op[0].type == RX_Operand_Postinc
14434e98e3e1Schristos 	      && opcode->op[1].type == RX_Operand_Register))
14444e98e3e1Schristos 	{
14454e98e3e1Schristos 	  /* Special case: push reg doesn't cause a memory stall.  */
14464e98e3e1Schristos 	  memory_dest = 0;
14474e98e3e1Schristos 	  tprintf("push special case\n");
14484e98e3e1Schristos 	}
14494e98e3e1Schristos #endif
14504e98e3e1Schristos 
14514e98e3e1Schristos       set_sz (v, DSZ());
14524e98e3e1Schristos       break;
14534e98e3e1Schristos 
14544e98e3e1Schristos     case RXO_movbi:
14554e98e3e1Schristos       PD (GS ());
14564e98e3e1Schristos       cycles (1);
14574e98e3e1Schristos       break;
14584e98e3e1Schristos 
14594e98e3e1Schristos     case RXO_movbir:
14604e98e3e1Schristos       PS (GD ());
14614e98e3e1Schristos       cycles (1);
14624e98e3e1Schristos       break;
14634e98e3e1Schristos 
14644e98e3e1Schristos     case RXO_mul:
14654e98e3e1Schristos       v = US2 ();
14664e98e3e1Schristos       ll = (unsigned long long) US1() * (unsigned long long) v;
14674e98e3e1Schristos       PD(ll);
14684e98e3e1Schristos       E (1);
14694e98e3e1Schristos       break;
14704e98e3e1Schristos 
14714e98e3e1Schristos     case RXO_mulhi:
14724e98e3e1Schristos       v = GS2 ();
14734e98e3e1Schristos       ll = (long long)(signed short)(GS() >> 16) * (long long)(signed short)(v >> 16);
14744e98e3e1Schristos       ll <<= 16;
14754e98e3e1Schristos       put_reg64 (acc64, ll);
14764e98e3e1Schristos       E1;
14774e98e3e1Schristos       break;
14784e98e3e1Schristos 
14794e98e3e1Schristos     case RXO_mullo:
14804e98e3e1Schristos       v = GS2 ();
14814e98e3e1Schristos       ll = (long long)(signed short)(GS()) * (long long)(signed short)(v);
14824e98e3e1Schristos       ll <<= 16;
14834e98e3e1Schristos       put_reg64 (acc64, ll);
14844e98e3e1Schristos       E1;
14854e98e3e1Schristos       break;
14864e98e3e1Schristos 
14874e98e3e1Schristos     case RXO_mvfachi:
14884e98e3e1Schristos       PD (get_reg (acchi));
14894e98e3e1Schristos       E1;
14904e98e3e1Schristos       break;
14914e98e3e1Schristos 
14924e98e3e1Schristos     case RXO_mvfaclo:
14934e98e3e1Schristos       PD (get_reg (acclo));
14944e98e3e1Schristos       E1;
14954e98e3e1Schristos       break;
14964e98e3e1Schristos 
14974e98e3e1Schristos     case RXO_mvfacmi:
14984e98e3e1Schristos       PD (get_reg (accmi));
14994e98e3e1Schristos       E1;
15004e98e3e1Schristos       break;
15014e98e3e1Schristos 
15024e98e3e1Schristos     case RXO_mvtachi:
15034e98e3e1Schristos       put_reg (acchi, GS ());
15044e98e3e1Schristos       E1;
15054e98e3e1Schristos       break;
15064e98e3e1Schristos 
15074e98e3e1Schristos     case RXO_mvtaclo:
15084e98e3e1Schristos       put_reg (acclo, GS ());
15094e98e3e1Schristos       E1;
15104e98e3e1Schristos       break;
15114e98e3e1Schristos 
15124e98e3e1Schristos     case RXO_mvtipl:
15134e98e3e1Schristos       regs.r_psw &= ~ FLAGBITS_IPL;
15144e98e3e1Schristos       regs.r_psw |= (GS () << FLAGSHIFT_IPL) & FLAGBITS_IPL;
15154e98e3e1Schristos       E1;
15164e98e3e1Schristos       break;
15174e98e3e1Schristos 
15184e98e3e1Schristos     case RXO_nop:
15194e98e3e1Schristos     case RXO_nop2:
15204e98e3e1Schristos     case RXO_nop3:
1521ba340e45Schristos     case RXO_nop4:
1522ba340e45Schristos     case RXO_nop5:
1523ba340e45Schristos     case RXO_nop6:
1524ba340e45Schristos     case RXO_nop7:
15254e98e3e1Schristos       E1;
15264e98e3e1Schristos       break;
15274e98e3e1Schristos 
15284e98e3e1Schristos     case RXO_or:
15294e98e3e1Schristos       LOGIC_OP (|);
15304e98e3e1Schristos       break;
15314e98e3e1Schristos 
15324e98e3e1Schristos     case RXO_popm:
15334e98e3e1Schristos       /* POPM cannot pop R0 (sp).  */
15344e98e3e1Schristos       if (opcode->op[1].reg == 0 || opcode->op[2].reg == 0)
15354e98e3e1Schristos 	EXCEPTION (EX_UNDEFINED);
15364e98e3e1Schristos       if (opcode->op[1].reg >= opcode->op[2].reg)
15374e98e3e1Schristos 	{
15384e98e3e1Schristos 	  regs.r_pc = opcode_pc;
15394e98e3e1Schristos 	  DO_RETURN (RX_MAKE_STOPPED (SIGILL));
15404e98e3e1Schristos 	}
15414e98e3e1Schristos       for (v = opcode->op[1].reg; v <= opcode->op[2].reg; v++)
15424e98e3e1Schristos 	{
15434e98e3e1Schristos 	  cycles (1);
15444e98e3e1Schristos 	  RLD (v);
15454e98e3e1Schristos 	  put_reg (v, pop ());
15464e98e3e1Schristos 	}
15474e98e3e1Schristos       break;
15484e98e3e1Schristos 
15494e98e3e1Schristos     case RXO_pushm:
15504e98e3e1Schristos       /* PUSHM cannot push R0 (sp).  */
15514e98e3e1Schristos       if (opcode->op[1].reg == 0 || opcode->op[2].reg == 0)
15524e98e3e1Schristos 	EXCEPTION (EX_UNDEFINED);
15534e98e3e1Schristos       if (opcode->op[1].reg >= opcode->op[2].reg)
15544e98e3e1Schristos 	{
15554e98e3e1Schristos 	  regs.r_pc = opcode_pc;
15564e98e3e1Schristos 	  return RX_MAKE_STOPPED (SIGILL);
15574e98e3e1Schristos 	}
15584e98e3e1Schristos       for (v = opcode->op[2].reg; v >= opcode->op[1].reg; v--)
15594e98e3e1Schristos 	{
15604e98e3e1Schristos 	  RL (v);
15614e98e3e1Schristos 	  push (get_reg (v));
15624e98e3e1Schristos 	}
15634e98e3e1Schristos       cycles (opcode->op[2].reg - opcode->op[1].reg + 1);
15644e98e3e1Schristos       break;
15654e98e3e1Schristos 
15664e98e3e1Schristos     case RXO_racw:
15674e98e3e1Schristos       ll = get_reg64 (acc64) << GS ();
15684e98e3e1Schristos       ll += 0x80000000ULL;
15694e98e3e1Schristos       if ((signed long long)ll > (signed long long)0x00007fff00000000ULL)
15704e98e3e1Schristos 	ll = 0x00007fff00000000ULL;
15714e98e3e1Schristos       else if ((signed long long)ll < (signed long long)0xffff800000000000ULL)
15724e98e3e1Schristos 	ll = 0xffff800000000000ULL;
15734e98e3e1Schristos       else
15744e98e3e1Schristos 	ll &= 0xffffffff00000000ULL;
15754e98e3e1Schristos       put_reg64 (acc64, ll);
15764e98e3e1Schristos       E1;
15774e98e3e1Schristos       break;
15784e98e3e1Schristos 
15794e98e3e1Schristos     case RXO_rte:
15804e98e3e1Schristos       PRIVILEDGED ();
15814e98e3e1Schristos       regs.r_pc = poppc ();
15824e98e3e1Schristos       regs.r_psw = poppc ();
15834e98e3e1Schristos       if (FLAG_PM)
15844e98e3e1Schristos 	regs.r_psw |= FLAGBIT_U;
15854e98e3e1Schristos #ifdef CYCLE_ACCURATE
15864e98e3e1Schristos       regs.fast_return = 0;
15874e98e3e1Schristos       cycles (6);
15884e98e3e1Schristos #endif
15894e98e3e1Schristos       break;
15904e98e3e1Schristos 
15914e98e3e1Schristos     case RXO_revl:
15924e98e3e1Schristos       uma = GS ();
15934e98e3e1Schristos       umb = (((uma >> 24) & 0xff)
15944e98e3e1Schristos 	     | ((uma >> 8) & 0xff00)
15954e98e3e1Schristos 	     | ((uma << 8) & 0xff0000)
15964e98e3e1Schristos 	     | ((uma << 24) & 0xff000000UL));
15974e98e3e1Schristos       PD (umb);
15984e98e3e1Schristos       E1;
15994e98e3e1Schristos       break;
16004e98e3e1Schristos 
16014e98e3e1Schristos     case RXO_revw:
16024e98e3e1Schristos       uma = GS ();
16034e98e3e1Schristos       umb = (((uma >> 8) & 0x00ff00ff)
16044e98e3e1Schristos 	     | ((uma << 8) & 0xff00ff00UL));
16054e98e3e1Schristos       PD (umb);
16064e98e3e1Schristos       E1;
16074e98e3e1Schristos       break;
16084e98e3e1Schristos 
16094e98e3e1Schristos     case RXO_rmpa:
16104e98e3e1Schristos       RL(4);
16114e98e3e1Schristos       RL(5);
16124e98e3e1Schristos #ifdef CYCLE_ACCURATE
16134e98e3e1Schristos       tx = regs.r[3];
16144e98e3e1Schristos #endif
16154e98e3e1Schristos 
16164e98e3e1Schristos       while (regs.r[3] != 0)
16174e98e3e1Schristos 	{
16184e98e3e1Schristos 	  long long tmp;
16194e98e3e1Schristos 
16204e98e3e1Schristos 	  switch (opcode->size)
16214e98e3e1Schristos 	    {
16224e98e3e1Schristos 	    case RX_Long:
16234e98e3e1Schristos 	      ma = mem_get_si (regs.r[1]);
16244e98e3e1Schristos 	      mb = mem_get_si (regs.r[2]);
16254e98e3e1Schristos 	      regs.r[1] += 4;
16264e98e3e1Schristos 	      regs.r[2] += 4;
16274e98e3e1Schristos 	      break;
16284e98e3e1Schristos 	    case RX_Word:
16294e98e3e1Schristos 	      ma = sign_ext (mem_get_hi (regs.r[1]), 16);
16304e98e3e1Schristos 	      mb = sign_ext (mem_get_hi (regs.r[2]), 16);
16314e98e3e1Schristos 	      regs.r[1] += 2;
16324e98e3e1Schristos 	      regs.r[2] += 2;
16334e98e3e1Schristos 	      break;
16344e98e3e1Schristos 	    case RX_Byte:
16354e98e3e1Schristos 	      ma = sign_ext (mem_get_qi (regs.r[1]), 8);
16364e98e3e1Schristos 	      mb = sign_ext (mem_get_qi (regs.r[2]), 8);
16374e98e3e1Schristos 	      regs.r[1] += 1;
16384e98e3e1Schristos 	      regs.r[2] += 1;
16394e98e3e1Schristos 	      break;
16404e98e3e1Schristos 	    default:
16414e98e3e1Schristos 	      abort ();
16424e98e3e1Schristos 	    }
16434e98e3e1Schristos 	  /* We do the multiply as a signed value.  */
16444e98e3e1Schristos 	  sll = (long long)ma * (long long)mb;
16454e98e3e1Schristos 	  tprintf("        %016llx = %d * %d\n", sll, ma, mb);
16464e98e3e1Schristos 	  /* but we do the sum as unsigned, while sign extending the operands.  */
16474e98e3e1Schristos 	  tmp = regs.r[4] + (sll & 0xffffffffUL);
16484e98e3e1Schristos 	  regs.r[4] = tmp & 0xffffffffUL;
16494e98e3e1Schristos 	  tmp >>= 32;
16504e98e3e1Schristos 	  sll >>= 32;
16514e98e3e1Schristos 	  tmp += regs.r[5] + (sll & 0xffffffffUL);
16524e98e3e1Schristos 	  regs.r[5] = tmp & 0xffffffffUL;
16534e98e3e1Schristos 	  tmp >>= 32;
16544e98e3e1Schristos 	  sll >>= 32;
16554e98e3e1Schristos 	  tmp += regs.r[6] + (sll & 0xffffffffUL);
16564e98e3e1Schristos 	  regs.r[6] = tmp & 0xffffffffUL;
16574e98e3e1Schristos 	  tprintf("%08lx\033[36m%08lx\033[0m%08lx\n",
16584e98e3e1Schristos 		  (unsigned long) regs.r[6],
16594e98e3e1Schristos 		  (unsigned long) regs.r[5],
16604e98e3e1Schristos 		  (unsigned long) regs.r[4]);
16614e98e3e1Schristos 
16624e98e3e1Schristos 	  regs.r[3] --;
16634e98e3e1Schristos 	}
16644e98e3e1Schristos       if (regs.r[6] & 0x00008000)
16654e98e3e1Schristos 	regs.r[6] |= 0xffff0000UL;
16664e98e3e1Schristos       else
16674e98e3e1Schristos 	regs.r[6] &= 0x0000ffff;
16684e98e3e1Schristos       ma = (regs.r[6] & 0x80000000UL) ? FLAGBIT_S : 0;
16694e98e3e1Schristos       if (regs.r[6] != 0 && regs.r[6] != 0xffffffffUL)
16704e98e3e1Schristos 	set_flags (FLAGBIT_O|FLAGBIT_S, ma | FLAGBIT_O);
16714e98e3e1Schristos       else
16724e98e3e1Schristos 	set_flags (FLAGBIT_O|FLAGBIT_S, ma);
16734e98e3e1Schristos #ifdef CYCLE_ACCURATE
16744e98e3e1Schristos       switch (opcode->size)
16754e98e3e1Schristos 	{
16764e98e3e1Schristos 	case RX_Long:
16774e98e3e1Schristos 	  cycles (6 + 4 * tx);
16784e98e3e1Schristos 	  break;
16794e98e3e1Schristos 	case RX_Word:
16804e98e3e1Schristos 	  cycles (6 + 5 * (tx / 2) + 4 * (tx % 2));
16814e98e3e1Schristos 	  break;
16824e98e3e1Schristos 	case RX_Byte:
16834e98e3e1Schristos 	  cycles (6 + 7 * (tx / 4) + 4 * (tx % 4));
16844e98e3e1Schristos 	  break;
16854e98e3e1Schristos 	default:
16864e98e3e1Schristos 	  abort ();
16874e98e3e1Schristos 	}
16884e98e3e1Schristos #endif
16894e98e3e1Schristos       break;
16904e98e3e1Schristos 
16914e98e3e1Schristos     case RXO_rolc:
16924e98e3e1Schristos       v = GD ();
16934e98e3e1Schristos       ma = v & 0x80000000UL;
16944e98e3e1Schristos       v <<= 1;
16954e98e3e1Schristos       v |= carry;
16964e98e3e1Schristos       set_szc (v, 4, ma);
16974e98e3e1Schristos       PD (v);
16984e98e3e1Schristos       E1;
16994e98e3e1Schristos       break;
17004e98e3e1Schristos 
17014e98e3e1Schristos     case RXO_rorc:
17024e98e3e1Schristos       uma = GD ();
17034e98e3e1Schristos       mb = uma & 1;
17044e98e3e1Schristos       uma >>= 1;
17054e98e3e1Schristos       uma |= (carry ? 0x80000000UL : 0);
17064e98e3e1Schristos       set_szc (uma, 4, mb);
17074e98e3e1Schristos       PD (uma);
17084e98e3e1Schristos       E1;
17094e98e3e1Schristos       break;
17104e98e3e1Schristos 
17114e98e3e1Schristos     case RXO_rotl:
17124e98e3e1Schristos       mb = GS ();
17134e98e3e1Schristos       uma = GD ();
17144e98e3e1Schristos       if (mb)
17154e98e3e1Schristos 	{
17164e98e3e1Schristos 	  uma = (uma << mb) | (uma >> (32-mb));
17174e98e3e1Schristos 	  mb = uma & 1;
17184e98e3e1Schristos 	}
17194e98e3e1Schristos       set_szc (uma, 4, mb);
17204e98e3e1Schristos       PD (uma);
17214e98e3e1Schristos       E1;
17224e98e3e1Schristos       break;
17234e98e3e1Schristos 
17244e98e3e1Schristos     case RXO_rotr:
17254e98e3e1Schristos       mb = GS ();
17264e98e3e1Schristos       uma = GD ();
17274e98e3e1Schristos       if (mb)
17284e98e3e1Schristos 	{
17294e98e3e1Schristos 	  uma = (uma >> mb) | (uma << (32-mb));
17304e98e3e1Schristos 	  mb = uma & 0x80000000;
17314e98e3e1Schristos 	}
17324e98e3e1Schristos       set_szc (uma, 4, mb);
17334e98e3e1Schristos       PD (uma);
17344e98e3e1Schristos       E1;
17354e98e3e1Schristos       break;
17364e98e3e1Schristos 
17374e98e3e1Schristos     case RXO_round:
17384e98e3e1Schristos       ma = GS ();
17394e98e3e1Schristos       FPCLEAR ();
17404e98e3e1Schristos       mb = rxfp_ftoi (ma, regs.r_fpsw);
17414e98e3e1Schristos       FPCHECK ();
17424e98e3e1Schristos       PD (mb);
17434e98e3e1Schristos       tprintf("(int) %g = %d\n", int2float(ma), mb);
17444e98e3e1Schristos       set_sz (mb, 4);
17454e98e3e1Schristos       E (2);
17464e98e3e1Schristos       break;
17474e98e3e1Schristos 
17484e98e3e1Schristos     case RXO_rts:
17494e98e3e1Schristos       {
17504e98e3e1Schristos #ifdef CYCLE_ACCURATE
17514e98e3e1Schristos 	int cyc = 5;
17524e98e3e1Schristos #endif
17534e98e3e1Schristos 	regs.r_pc = poppc ();
17544e98e3e1Schristos #ifdef CYCLE_ACCURATE
17554e98e3e1Schristos 	/* Note: specs say 5, chip says 3.  */
17564e98e3e1Schristos 	if (regs.fast_return && regs.link_register == regs.r_pc)
17574e98e3e1Schristos 	  {
17584b169a6bSchristos #ifdef WITH_PROFILE
17594e98e3e1Schristos 	    fast_returns ++;
17604e98e3e1Schristos #endif
17614e98e3e1Schristos 	    tprintf("fast return bonus\n");
17624e98e3e1Schristos 	    cyc -= 2;
17634e98e3e1Schristos 	  }
17644e98e3e1Schristos 	cycles (cyc);
17654e98e3e1Schristos 	regs.fast_return = 0;
17664e98e3e1Schristos 	branch_alignment_penalty = 1;
17674e98e3e1Schristos #endif
17684e98e3e1Schristos       }
17694e98e3e1Schristos       break;
17704e98e3e1Schristos 
17714e98e3e1Schristos     case RXO_rtsd:
17724e98e3e1Schristos       if (opcode->op[2].type == RX_Operand_Register)
17734e98e3e1Schristos 	{
17744e98e3e1Schristos 	  int i;
17754e98e3e1Schristos 	  /* RTSD cannot pop R0 (sp).  */
17764e98e3e1Schristos 	  put_reg (0, get_reg (0) + GS() - (opcode->op[0].reg-opcode->op[2].reg+1)*4);
17774e98e3e1Schristos 	  if (opcode->op[2].reg == 0)
17784e98e3e1Schristos 	    EXCEPTION (EX_UNDEFINED);
17794e98e3e1Schristos #ifdef CYCLE_ACCURATE
17804e98e3e1Schristos 	  tx = opcode->op[0].reg - opcode->op[2].reg + 1;
17814e98e3e1Schristos #endif
17824e98e3e1Schristos 	  for (i = opcode->op[2].reg; i <= opcode->op[0].reg; i ++)
17834e98e3e1Schristos 	    {
17844e98e3e1Schristos 	      RLD (i);
17854e98e3e1Schristos 	      put_reg (i, pop ());
17864e98e3e1Schristos 	    }
17874e98e3e1Schristos 	}
17884e98e3e1Schristos       else
17894e98e3e1Schristos 	{
17904e98e3e1Schristos #ifdef CYCLE_ACCURATE
17914e98e3e1Schristos 	  tx = 0;
17924e98e3e1Schristos #endif
17934e98e3e1Schristos 	  put_reg (0, get_reg (0) + GS());
17944e98e3e1Schristos 	}
17954e98e3e1Schristos       put_reg (pc, poppc());
17964e98e3e1Schristos #ifdef CYCLE_ACCURATE
17974e98e3e1Schristos       if (regs.fast_return && regs.link_register == regs.r_pc)
17984e98e3e1Schristos 	{
17994e98e3e1Schristos 	  tprintf("fast return bonus\n");
18004b169a6bSchristos #ifdef WITH_PROFILE
18014e98e3e1Schristos 	  fast_returns ++;
18024e98e3e1Schristos #endif
18034e98e3e1Schristos 	  cycles (tx < 3 ? 3 : tx + 1);
18044e98e3e1Schristos 	}
18054e98e3e1Schristos       else
18064e98e3e1Schristos 	{
18074e98e3e1Schristos 	  cycles (tx < 5 ? 5 : tx + 1);
18084e98e3e1Schristos 	}
18094e98e3e1Schristos       regs.fast_return = 0;
18104e98e3e1Schristos       branch_alignment_penalty = 1;
18114e98e3e1Schristos #endif
18124e98e3e1Schristos       break;
18134e98e3e1Schristos 
18144e98e3e1Schristos     case RXO_sat:
18154e98e3e1Schristos       if (FLAG_O && FLAG_S)
18164e98e3e1Schristos 	PD (0x7fffffffUL);
18174e98e3e1Schristos       else if (FLAG_O && ! FLAG_S)
18184e98e3e1Schristos 	PD (0x80000000UL);
18194e98e3e1Schristos       E1;
18204e98e3e1Schristos       break;
18214e98e3e1Schristos 
1822a2e2270fSchristos     case RXO_satr:
1823a2e2270fSchristos       if (FLAG_O && ! FLAG_S)
1824a2e2270fSchristos 	{
1825a2e2270fSchristos 	  put_reg (6, 0x0);
1826a2e2270fSchristos 	  put_reg (5, 0x7fffffff);
1827a2e2270fSchristos 	  put_reg (4, 0xffffffff);
1828a2e2270fSchristos 	}
1829a2e2270fSchristos       else if (FLAG_O && FLAG_S)
1830a2e2270fSchristos 	{
1831a2e2270fSchristos 	  put_reg (6, 0xffffffff);
1832a2e2270fSchristos 	  put_reg (5, 0x80000000);
1833a2e2270fSchristos 	  put_reg (4, 0x0);
1834a2e2270fSchristos 	}
1835a2e2270fSchristos       E1;
1836a2e2270fSchristos       break;
1837a2e2270fSchristos 
18384e98e3e1Schristos     case RXO_sbb:
18394e98e3e1Schristos       MATH_OP (-, ! carry);
18404e98e3e1Schristos       break;
18414e98e3e1Schristos 
18424e98e3e1Schristos     case RXO_sccnd:
18434e98e3e1Schristos       if (GS())
18444e98e3e1Schristos 	PD (1);
18454e98e3e1Schristos       else
18464e98e3e1Schristos 	PD (0);
18474e98e3e1Schristos       E1;
18484e98e3e1Schristos       break;
18494e98e3e1Schristos 
18504e98e3e1Schristos     case RXO_scmpu:
18514e98e3e1Schristos #ifdef CYCLE_ACCURATE
18524e98e3e1Schristos       tx = regs.r[3];
18534e98e3e1Schristos #endif
18544e98e3e1Schristos       while (regs.r[3] != 0)
18554e98e3e1Schristos 	{
18564e98e3e1Schristos 	  uma = mem_get_qi (regs.r[1] ++);
18574e98e3e1Schristos 	  umb = mem_get_qi (regs.r[2] ++);
18584e98e3e1Schristos 	  regs.r[3] --;
18594e98e3e1Schristos 	  if (uma != umb || uma == 0)
18604e98e3e1Schristos 	    break;
18614e98e3e1Schristos 	}
18624e98e3e1Schristos       if (uma == umb)
18634e98e3e1Schristos 	set_zc (1, 1);
18644e98e3e1Schristos       else
18654e98e3e1Schristos 	set_zc (0, ((int)uma - (int)umb) >= 0);
18664e98e3e1Schristos       cycles (2 + 4 * (tx / 4) + 4 * (tx % 4));
18674e98e3e1Schristos       break;
18684e98e3e1Schristos 
18694e98e3e1Schristos     case RXO_setpsw:
18704e98e3e1Schristos       v = 1 << opcode->op[0].reg;
18714e98e3e1Schristos       if (FLAG_PM
18724e98e3e1Schristos 	  && (v == FLAGBIT_I
18734e98e3e1Schristos 	      || v == FLAGBIT_U))
18744e98e3e1Schristos 	break;
18754e98e3e1Schristos       regs.r_psw |= v;
18764e98e3e1Schristos       cycles (1);
18774e98e3e1Schristos       break;
18784e98e3e1Schristos 
18794e98e3e1Schristos     case RXO_smovb:
18804e98e3e1Schristos       RL (3);
18814e98e3e1Schristos #ifdef CYCLE_ACCURATE
18824e98e3e1Schristos       tx = regs.r[3];
18834e98e3e1Schristos #endif
18844e98e3e1Schristos       while (regs.r[3])
18854e98e3e1Schristos 	{
18864e98e3e1Schristos 	  uma = mem_get_qi (regs.r[2] --);
18874e98e3e1Schristos 	  mem_put_qi (regs.r[1]--, uma);
18884e98e3e1Schristos 	  regs.r[3] --;
18894e98e3e1Schristos 	}
18904e98e3e1Schristos #ifdef CYCLE_ACCURATE
18914e98e3e1Schristos       if (tx > 3)
18924e98e3e1Schristos 	cycles (6 + 3 * (tx / 4) + 3 * (tx % 4));
18934e98e3e1Schristos       else
18944e98e3e1Schristos 	cycles (2 + 3 * (tx % 4));
18954e98e3e1Schristos #endif
18964e98e3e1Schristos       break;
18974e98e3e1Schristos 
18984e98e3e1Schristos     case RXO_smovf:
18994e98e3e1Schristos       RL (3);
19004e98e3e1Schristos #ifdef CYCLE_ACCURATE
19014e98e3e1Schristos       tx = regs.r[3];
19024e98e3e1Schristos #endif
19034e98e3e1Schristos       while (regs.r[3])
19044e98e3e1Schristos 	{
19054e98e3e1Schristos 	  uma = mem_get_qi (regs.r[2] ++);
19064e98e3e1Schristos 	  mem_put_qi (regs.r[1]++, uma);
19074e98e3e1Schristos 	  regs.r[3] --;
19084e98e3e1Schristos 	}
19094e98e3e1Schristos       cycles (2 + 3 * (int)(tx / 4) + 3 * (tx % 4));
19104e98e3e1Schristos       break;
19114e98e3e1Schristos 
19124e98e3e1Schristos     case RXO_smovu:
19134e98e3e1Schristos #ifdef CYCLE_ACCURATE
19144e98e3e1Schristos       tx = regs.r[3];
19154e98e3e1Schristos #endif
19164e98e3e1Schristos       while (regs.r[3] != 0)
19174e98e3e1Schristos 	{
19184e98e3e1Schristos 	  uma = mem_get_qi (regs.r[2] ++);
19194e98e3e1Schristos 	  mem_put_qi (regs.r[1]++, uma);
19204e98e3e1Schristos 	  regs.r[3] --;
19214e98e3e1Schristos 	  if (uma == 0)
19224e98e3e1Schristos 	    break;
19234e98e3e1Schristos 	}
19244e98e3e1Schristos       cycles (2 + 3 * (int)(tx / 4) + 3 * (tx % 4));
19254e98e3e1Schristos       break;
19264e98e3e1Schristos 
19274e98e3e1Schristos     case RXO_shar: /* d = ma >> mb */
19284e98e3e1Schristos       SHIFT_OP (sll, int, mb, >>=, 1);
19294e98e3e1Schristos       E (1);
19304e98e3e1Schristos       break;
19314e98e3e1Schristos 
19324e98e3e1Schristos     case RXO_shll: /* d = ma << mb */
19334e98e3e1Schristos       SHIFT_OP (ll, int, mb, <<=, 0x80000000UL);
19344e98e3e1Schristos       E (1);
19354e98e3e1Schristos       break;
19364e98e3e1Schristos 
19374e98e3e1Schristos     case RXO_shlr: /* d = ma >> mb */
19384e98e3e1Schristos       SHIFT_OP (ll, unsigned int, mb, >>=, 1);
19394e98e3e1Schristos       E (1);
19404e98e3e1Schristos       break;
19414e98e3e1Schristos 
19424e98e3e1Schristos     case RXO_sstr:
19434e98e3e1Schristos       RL (3);
19444e98e3e1Schristos #ifdef CYCLE_ACCURATE
19454e98e3e1Schristos       tx = regs.r[3];
19464e98e3e1Schristos #endif
19474e98e3e1Schristos       switch (opcode->size)
19484e98e3e1Schristos 	{
19494e98e3e1Schristos 	case RX_Long:
19504e98e3e1Schristos 	  while (regs.r[3] != 0)
19514e98e3e1Schristos 	    {
19524e98e3e1Schristos 	      mem_put_si (regs.r[1], regs.r[2]);
19534e98e3e1Schristos 	      regs.r[1] += 4;
19544e98e3e1Schristos 	      regs.r[3] --;
19554e98e3e1Schristos 	    }
19564e98e3e1Schristos 	  cycles (2 + tx);
19574e98e3e1Schristos 	  break;
19584e98e3e1Schristos 	case RX_Word:
19594e98e3e1Schristos 	  while (regs.r[3] != 0)
19604e98e3e1Schristos 	    {
19614e98e3e1Schristos 	      mem_put_hi (regs.r[1], regs.r[2]);
19624e98e3e1Schristos 	      regs.r[1] += 2;
19634e98e3e1Schristos 	      regs.r[3] --;
19644e98e3e1Schristos 	    }
19654e98e3e1Schristos 	  cycles (2 + (int)(tx / 2) + tx % 2);
19664e98e3e1Schristos 	  break;
19674e98e3e1Schristos 	case RX_Byte:
19684e98e3e1Schristos 	  while (regs.r[3] != 0)
19694e98e3e1Schristos 	    {
19704e98e3e1Schristos 	      mem_put_qi (regs.r[1], regs.r[2]);
19714e98e3e1Schristos 	      regs.r[1] ++;
19724e98e3e1Schristos 	      regs.r[3] --;
19734e98e3e1Schristos 	    }
19744e98e3e1Schristos 	  cycles (2 + (int)(tx / 4) + tx % 4);
19754e98e3e1Schristos 	  break;
19764e98e3e1Schristos 	default:
19774e98e3e1Schristos 	  abort ();
19784e98e3e1Schristos 	}
19794e98e3e1Schristos       break;
19804e98e3e1Schristos 
19814e98e3e1Schristos     case RXO_stcc:
19824e98e3e1Schristos       if (GS2())
19834e98e3e1Schristos 	PD (GS ());
19844e98e3e1Schristos       E1;
19854e98e3e1Schristos       break;
19864e98e3e1Schristos 
19874e98e3e1Schristos     case RXO_stop:
19884e98e3e1Schristos       PRIVILEDGED ();
19894e98e3e1Schristos       regs.r_psw |= FLAGBIT_I;
19904e98e3e1Schristos       DO_RETURN (RX_MAKE_STOPPED(0));
19914e98e3e1Schristos 
19924e98e3e1Schristos     case RXO_sub:
19934e98e3e1Schristos       MATH_OP (-, 0);
19944e98e3e1Schristos       break;
19954e98e3e1Schristos 
19964e98e3e1Schristos     case RXO_suntil:
19974e98e3e1Schristos       RL(3);
19984e98e3e1Schristos #ifdef CYCLE_ACCURATE
19994e98e3e1Schristos       tx = 0;
20004e98e3e1Schristos #endif
20014e98e3e1Schristos       if (regs.r[3] == 0)
20024e98e3e1Schristos 	{
20034e98e3e1Schristos 	  cycles (3);
20044e98e3e1Schristos 	  break;
20054e98e3e1Schristos 	}
20064e98e3e1Schristos       switch (opcode->size)
20074e98e3e1Schristos 	{
20084e98e3e1Schristos 	case RX_Long:
20094e98e3e1Schristos 	  uma = get_reg (2);
20104e98e3e1Schristos 	  while (regs.r[3] != 0)
20114e98e3e1Schristos 	    {
20124e98e3e1Schristos 	      regs.r[3] --;
20134e98e3e1Schristos 	      umb = mem_get_si (get_reg (1));
20144e98e3e1Schristos 	      regs.r[1] += 4;
20154e98e3e1Schristos #ifdef CYCLE_ACCURATE
20164e98e3e1Schristos 	      tx ++;
20174e98e3e1Schristos #endif
20184e98e3e1Schristos 	      if (umb == uma)
20194e98e3e1Schristos 		break;
20204e98e3e1Schristos 	    }
20214e98e3e1Schristos #ifdef CYCLE_ACCURATE
20224e98e3e1Schristos 	  cycles (3 + 3 * tx);
20234e98e3e1Schristos #endif
20244e98e3e1Schristos 	  break;
20254e98e3e1Schristos 	case RX_Word:
20264e98e3e1Schristos 	  uma = get_reg (2) & 0xffff;
20274e98e3e1Schristos 	  while (regs.r[3] != 0)
20284e98e3e1Schristos 	    {
20294e98e3e1Schristos 	      regs.r[3] --;
20304e98e3e1Schristos 	      umb = mem_get_hi (get_reg (1));
20314e98e3e1Schristos 	      regs.r[1] += 2;
20324e98e3e1Schristos #ifdef CYCLE_ACCURATE
20334e98e3e1Schristos 	      tx ++;
20344e98e3e1Schristos #endif
20354e98e3e1Schristos 	      if (umb == uma)
20364e98e3e1Schristos 		break;
20374e98e3e1Schristos 	    }
20384e98e3e1Schristos #ifdef CYCLE_ACCURATE
20394e98e3e1Schristos 	  cycles (3 + 3 * (tx / 2) + 3 * (tx % 2));
20404e98e3e1Schristos #endif
20414e98e3e1Schristos 	  break;
20424e98e3e1Schristos 	case RX_Byte:
20434e98e3e1Schristos 	  uma = get_reg (2) & 0xff;
20444e98e3e1Schristos 	  while (regs.r[3] != 0)
20454e98e3e1Schristos 	    {
20464e98e3e1Schristos 	      regs.r[3] --;
20474e98e3e1Schristos 	      umb = mem_get_qi (regs.r[1]);
20484e98e3e1Schristos 	      regs.r[1] += 1;
20494e98e3e1Schristos #ifdef CYCLE_ACCURATE
20504e98e3e1Schristos 	      tx ++;
20514e98e3e1Schristos #endif
20524e98e3e1Schristos 	      if (umb == uma)
20534e98e3e1Schristos 		break;
20544e98e3e1Schristos 	    }
20554e98e3e1Schristos #ifdef CYCLE_ACCURATE
20564e98e3e1Schristos 	  cycles (3 + 3 * (tx / 4) + 3 * (tx % 4));
20574e98e3e1Schristos #endif
20584e98e3e1Schristos 	  break;
20594e98e3e1Schristos 	default:
20604e98e3e1Schristos 	  abort();
20614e98e3e1Schristos 	}
20624e98e3e1Schristos       if (uma == umb)
20634e98e3e1Schristos 	set_zc (1, 1);
20644e98e3e1Schristos       else
20654e98e3e1Schristos 	set_zc (0, ((int)uma - (int)umb) >= 0);
20664e98e3e1Schristos       break;
20674e98e3e1Schristos 
20684e98e3e1Schristos     case RXO_swhile:
20694e98e3e1Schristos       RL(3);
20704e98e3e1Schristos #ifdef CYCLE_ACCURATE
20714e98e3e1Schristos       tx = 0;
20724e98e3e1Schristos #endif
20734e98e3e1Schristos       if (regs.r[3] == 0)
20744e98e3e1Schristos 	break;
20754e98e3e1Schristos       switch (opcode->size)
20764e98e3e1Schristos 	{
20774e98e3e1Schristos 	case RX_Long:
20784e98e3e1Schristos 	  uma = get_reg (2);
20794e98e3e1Schristos 	  while (regs.r[3] != 0)
20804e98e3e1Schristos 	    {
20814e98e3e1Schristos 	      regs.r[3] --;
20824e98e3e1Schristos 	      umb = mem_get_si (get_reg (1));
20834e98e3e1Schristos 	      regs.r[1] += 4;
20844e98e3e1Schristos #ifdef CYCLE_ACCURATE
20854e98e3e1Schristos 	      tx ++;
20864e98e3e1Schristos #endif
20874e98e3e1Schristos 	      if (umb != uma)
20884e98e3e1Schristos 		break;
20894e98e3e1Schristos 	    }
20904e98e3e1Schristos #ifdef CYCLE_ACCURATE
20914e98e3e1Schristos 	  cycles (3 + 3 * tx);
20924e98e3e1Schristos #endif
20934e98e3e1Schristos 	  break;
20944e98e3e1Schristos 	case RX_Word:
20954e98e3e1Schristos 	  uma = get_reg (2) & 0xffff;
20964e98e3e1Schristos 	  while (regs.r[3] != 0)
20974e98e3e1Schristos 	    {
20984e98e3e1Schristos 	      regs.r[3] --;
20994e98e3e1Schristos 	      umb = mem_get_hi (get_reg (1));
21004e98e3e1Schristos 	      regs.r[1] += 2;
21014e98e3e1Schristos #ifdef CYCLE_ACCURATE
21024e98e3e1Schristos 	      tx ++;
21034e98e3e1Schristos #endif
21044e98e3e1Schristos 	      if (umb != uma)
21054e98e3e1Schristos 		break;
21064e98e3e1Schristos 	    }
21074e98e3e1Schristos #ifdef CYCLE_ACCURATE
21084e98e3e1Schristos 	  cycles (3 + 3 * (tx / 2) + 3 * (tx % 2));
21094e98e3e1Schristos #endif
21104e98e3e1Schristos 	  break;
21114e98e3e1Schristos 	case RX_Byte:
21124e98e3e1Schristos 	  uma = get_reg (2) & 0xff;
21134e98e3e1Schristos 	  while (regs.r[3] != 0)
21144e98e3e1Schristos 	    {
21154e98e3e1Schristos 	      regs.r[3] --;
21164e98e3e1Schristos 	      umb = mem_get_qi (regs.r[1]);
21174e98e3e1Schristos 	      regs.r[1] += 1;
21184e98e3e1Schristos #ifdef CYCLE_ACCURATE
21194e98e3e1Schristos 	      tx ++;
21204e98e3e1Schristos #endif
21214e98e3e1Schristos 	      if (umb != uma)
21224e98e3e1Schristos 		break;
21234e98e3e1Schristos 	    }
21244e98e3e1Schristos #ifdef CYCLE_ACCURATE
21254e98e3e1Schristos 	  cycles (3 + 3 * (tx / 4) + 3 * (tx % 4));
21264e98e3e1Schristos #endif
21274e98e3e1Schristos 	  break;
21284e98e3e1Schristos 	default:
21294e98e3e1Schristos 	  abort();
21304e98e3e1Schristos 	}
21314e98e3e1Schristos       if (uma == umb)
21324e98e3e1Schristos 	set_zc (1, 1);
21334e98e3e1Schristos       else
21344e98e3e1Schristos 	set_zc (0, ((int)uma - (int)umb) >= 0);
21354e98e3e1Schristos       break;
21364e98e3e1Schristos 
21374e98e3e1Schristos     case RXO_wait:
21384e98e3e1Schristos       PRIVILEDGED ();
21394e98e3e1Schristos       regs.r_psw |= FLAGBIT_I;
21404e98e3e1Schristos       DO_RETURN (RX_MAKE_STOPPED(0));
21414e98e3e1Schristos 
21424e98e3e1Schristos     case RXO_xchg:
21434e98e3e1Schristos #ifdef CYCLE_ACCURATE
21444e98e3e1Schristos       regs.m2m = 0;
21454e98e3e1Schristos #endif
21464e98e3e1Schristos       v = GS (); /* This is the memory operand, if any.  */
21474e98e3e1Schristos       PS (GD ()); /* and this may change the address register.  */
21484e98e3e1Schristos       PD (v);
21494e98e3e1Schristos       E2;
21504e98e3e1Schristos #ifdef CYCLE_ACCURATE
21514e98e3e1Schristos       /* all M cycles happen during xchg's cycles.  */
21524e98e3e1Schristos       memory_dest = 0;
21534e98e3e1Schristos       memory_source = 0;
21544e98e3e1Schristos #endif
21554e98e3e1Schristos       break;
21564e98e3e1Schristos 
21574e98e3e1Schristos     case RXO_xor:
21584e98e3e1Schristos       LOGIC_OP (^);
21594e98e3e1Schristos       break;
21604e98e3e1Schristos 
21614e98e3e1Schristos     default:
21624e98e3e1Schristos       EXCEPTION (EX_UNDEFINED);
21634e98e3e1Schristos     }
21644e98e3e1Schristos 
21654e98e3e1Schristos #ifdef CYCLE_ACCURATE
21664e98e3e1Schristos   regs.m2m = 0;
21674e98e3e1Schristos   if (memory_source)
21684e98e3e1Schristos     regs.m2m |= M2M_SRC;
21694e98e3e1Schristos   if (memory_dest)
21704e98e3e1Schristos     regs.m2m |= M2M_DST;
21714e98e3e1Schristos 
21724e98e3e1Schristos   regs.rt = new_rt;
21734e98e3e1Schristos   new_rt = -1;
21744e98e3e1Schristos #endif
21754e98e3e1Schristos 
21764b169a6bSchristos #ifdef WITH_PROFILE
21774e98e3e1Schristos   if (prev_cycle_count == regs.cycle_count)
21784e98e3e1Schristos     {
21794e98e3e1Schristos       printf("Cycle count not updated! id %s\n", id_names[opcode->id]);
21804e98e3e1Schristos       abort ();
21814e98e3e1Schristos     }
21824e98e3e1Schristos #endif
21834e98e3e1Schristos 
21844b169a6bSchristos #ifdef WITH_PROFILE
21854e98e3e1Schristos   if (running_benchmark)
21864e98e3e1Schristos     {
21874e98e3e1Schristos       int omap = op_lookup (opcode->op[0].type, opcode->op[1].type, opcode->op[2].type);
21884e98e3e1Schristos 
21894e98e3e1Schristos 
21904e98e3e1Schristos       cycles_per_id[opcode->id][omap] += regs.cycle_count - prev_cycle_count;
21914e98e3e1Schristos       times_per_id[opcode->id][omap] ++;
21924e98e3e1Schristos 
21934e98e3e1Schristos       times_per_pair[prev_opcode_id][po0][opcode->id][omap] ++;
21944e98e3e1Schristos 
21954e98e3e1Schristos       prev_opcode_id = opcode->id;
21964e98e3e1Schristos       po0 = omap;
21974e98e3e1Schristos     }
21984e98e3e1Schristos #endif
21994e98e3e1Schristos 
22004e98e3e1Schristos   return RX_MAKE_STEPPED ();
22014e98e3e1Schristos }
22024e98e3e1Schristos 
22034b169a6bSchristos #ifdef WITH_PROFILE
22044e98e3e1Schristos void
22054e98e3e1Schristos reset_pipeline_stats (void)
22064e98e3e1Schristos {
22074e98e3e1Schristos   memset (cycles_per_id, 0, sizeof(cycles_per_id));
22084e98e3e1Schristos   memset (times_per_id, 0, sizeof(times_per_id));
22094e98e3e1Schristos   memory_stalls = 0;
22104e98e3e1Schristos   register_stalls = 0;
22114e98e3e1Schristos   branch_stalls = 0;
22124e98e3e1Schristos   branch_alignment_stalls = 0;
22134e98e3e1Schristos   fast_returns = 0;
22144e98e3e1Schristos   memset (times_per_pair, 0, sizeof(times_per_pair));
22154e98e3e1Schristos   running_benchmark = 1;
22164e98e3e1Schristos 
22174e98e3e1Schristos   benchmark_start_cycle = regs.cycle_count;
22184e98e3e1Schristos }
22194e98e3e1Schristos 
22204e98e3e1Schristos void
22214e98e3e1Schristos halt_pipeline_stats (void)
22224e98e3e1Schristos {
22234e98e3e1Schristos   running_benchmark = 0;
22244e98e3e1Schristos   benchmark_end_cycle = regs.cycle_count;
22254e98e3e1Schristos }
22264e98e3e1Schristos #endif
22274e98e3e1Schristos 
22284e98e3e1Schristos void
22294e98e3e1Schristos pipeline_stats (void)
22304e98e3e1Schristos {
22314b169a6bSchristos #ifdef WITH_PROFILE
22324e98e3e1Schristos   int i, o1;
22334e98e3e1Schristos   int p, p1;
22344e98e3e1Schristos #endif
22354e98e3e1Schristos 
22364e98e3e1Schristos #ifdef CYCLE_ACCURATE
22374e98e3e1Schristos   if (verbose == 1)
22384e98e3e1Schristos     {
22394e98e3e1Schristos       printf ("cycles: %llu\n", regs.cycle_count);
22404e98e3e1Schristos       return;
22414e98e3e1Schristos     }
22424e98e3e1Schristos 
22434e98e3e1Schristos   printf ("cycles: %13s\n", comma (regs.cycle_count));
22444e98e3e1Schristos #endif
22454e98e3e1Schristos 
22464b169a6bSchristos #ifdef WITH_PROFILE
22474e98e3e1Schristos   if (benchmark_start_cycle)
22484e98e3e1Schristos     printf ("bmark:  %13s\n", comma (benchmark_end_cycle - benchmark_start_cycle));
22494e98e3e1Schristos 
22504e98e3e1Schristos   printf("\n");
22514e98e3e1Schristos   for (i = 0; i < N_RXO; i++)
22524e98e3e1Schristos     for (o1 = 0; o1 < N_MAP; o1 ++)
22534e98e3e1Schristos       if (times_per_id[i][o1])
22544e98e3e1Schristos 	printf("%13s %13s %7.2f  %s %s\n",
22554e98e3e1Schristos 	       comma (cycles_per_id[i][o1]),
22564e98e3e1Schristos 	       comma (times_per_id[i][o1]),
22574e98e3e1Schristos 	       (double)cycles_per_id[i][o1] / times_per_id[i][o1],
22584e98e3e1Schristos 	       op_cache_string(o1),
22594e98e3e1Schristos 	       id_names[i]+4);
22604e98e3e1Schristos 
22614e98e3e1Schristos   printf("\n");
22624e98e3e1Schristos   for (p = 0; p < N_RXO; p ++)
22634e98e3e1Schristos     for (p1 = 0; p1 < N_MAP; p1 ++)
22644e98e3e1Schristos       for (i = 0; i < N_RXO; i ++)
22654e98e3e1Schristos 	for (o1 = 0; o1 < N_MAP; o1 ++)
22664e98e3e1Schristos 	  if (times_per_pair[p][p1][i][o1])
22674e98e3e1Schristos 	    {
22684e98e3e1Schristos 	      printf("%13s   %s %-9s  ->  %s %s\n",
22694e98e3e1Schristos 		     comma (times_per_pair[p][p1][i][o1]),
22704e98e3e1Schristos 		     op_cache_string(p1),
22714e98e3e1Schristos 		     id_names[p]+4,
22724e98e3e1Schristos 		     op_cache_string(o1),
22734e98e3e1Schristos 		     id_names[i]+4);
22744e98e3e1Schristos 	    }
22754e98e3e1Schristos 
22764e98e3e1Schristos   printf("\n");
22774e98e3e1Schristos   printf("%13s memory stalls\n", comma (memory_stalls));
22784e98e3e1Schristos   printf("%13s register stalls\n", comma (register_stalls));
22794e98e3e1Schristos   printf("%13s branches taken (non-return)\n", comma (branch_stalls));
22804e98e3e1Schristos   printf("%13s branch alignment stalls\n", comma (branch_alignment_stalls));
22814e98e3e1Schristos   printf("%13s fast returns\n", comma (fast_returns));
22824e98e3e1Schristos #endif
22834e98e3e1Schristos }
2284