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