/* rx.c --- opcode semantics for stand-alone RX simulator.
-Copyright (C) 2008, 2009 Free Software Foundation, Inc.
+Copyright (C) 2008-2014 Free Software Foundation, Inc.
Contributed by Red Hat, Inc.
This file is part of the GNU simulators.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>. */
+#include "config.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "syscalls.h"
#include "fpu.h"
#include "err.h"
+#include "misc.h"
+
+#ifdef CYCLE_STATS
+static const char * id_names[] = {
+ "RXO_unknown",
+ "RXO_mov", /* d = s (signed) */
+ "RXO_movbi", /* d = [s,s2] (signed) */
+ "RXO_movbir", /* [s,s2] = d (signed) */
+ "RXO_pushm", /* s..s2 */
+ "RXO_popm", /* s..s2 */
+ "RXO_xchg", /* s <-> d */
+ "RXO_stcc", /* d = s if cond(s2) */
+ "RXO_rtsd", /* rtsd, 1=imm, 2-0 = reg if reg type */
+
+ /* These are all either d OP= s or, if s2 is set, d = s OP s2. Note
+ that d may be "None". */
+ "RXO_and",
+ "RXO_or",
+ "RXO_xor",
+ "RXO_add",
+ "RXO_sub",
+ "RXO_mul",
+ "RXO_div",
+ "RXO_divu",
+ "RXO_shll",
+ "RXO_shar",
+ "RXO_shlr",
+
+ "RXO_adc", /* d = d + s + carry */
+ "RXO_sbb", /* d = d - s - ~carry */
+ "RXO_abs", /* d = |s| */
+ "RXO_max", /* d = max(d,s) */
+ "RXO_min", /* d = min(d,s) */
+ "RXO_emul", /* d:64 = d:32 * s */
+ "RXO_emulu", /* d:64 = d:32 * s (unsigned) */
+
+ "RXO_rolc", /* d <<= 1 through carry */
+ "RXO_rorc", /* d >>= 1 through carry*/
+ "RXO_rotl", /* d <<= #s without carry */
+ "RXO_rotr", /* d >>= #s without carry*/
+ "RXO_revw", /* d = revw(s) */
+ "RXO_revl", /* d = revl(s) */
+ "RXO_branch", /* pc = d if cond(s) */
+ "RXO_branchrel",/* pc += d if cond(s) */
+ "RXO_jsr", /* pc = d */
+ "RXO_jsrrel", /* pc += d */
+ "RXO_rts",
+ "RXO_nop",
+ "RXO_nop2",
+ "RXO_nop3",
+
+ "RXO_scmpu",
+ "RXO_smovu",
+ "RXO_smovb",
+ "RXO_suntil",
+ "RXO_swhile",
+ "RXO_smovf",
+ "RXO_sstr",
+
+ "RXO_rmpa",
+ "RXO_mulhi",
+ "RXO_mullo",
+ "RXO_machi",
+ "RXO_maclo",
+ "RXO_mvtachi",
+ "RXO_mvtaclo",
+ "RXO_mvfachi",
+ "RXO_mvfacmi",
+ "RXO_mvfaclo",
+ "RXO_racw",
+
+ "RXO_sat", /* sat(d) */
+ "RXO_satr",
+
+ "RXO_fadd", /* d op= s */
+ "RXO_fcmp",
+ "RXO_fsub",
+ "RXO_ftoi",
+ "RXO_fmul",
+ "RXO_fdiv",
+ "RXO_round",
+ "RXO_itof",
+
+ "RXO_bset", /* d |= (1<<s) */
+ "RXO_bclr", /* d &= ~(1<<s) */
+ "RXO_btst", /* s & (1<<s2) */
+ "RXO_bnot", /* d ^= (1<<s) */
+ "RXO_bmcc", /* d<s> = cond(s2) */
+
+ "RXO_clrpsw", /* flag index in d */
+ "RXO_setpsw", /* flag index in d */
+ "RXO_mvtipl", /* new IPL in s */
+
+ "RXO_rtfi",
+ "RXO_rte",
+ "RXO_rtd", /* undocumented */
+ "RXO_brk",
+ "RXO_dbt", /* undocumented */
+ "RXO_int", /* vector id in s */
+ "RXO_stop",
+ "RXO_wait",
+
+ "RXO_sccnd", /* d = cond(s) ? 1 : 0 */
+};
+
+static const char * optype_names[] = {
+ " - ",
+ "#Imm", /* #addend */
+ " Rn ", /* Rn */
+ "[Rn]", /* [Rn + addend] */
+ "Ps++", /* [Rn+] */
+ "--Pr", /* [-Rn] */
+ " cc ", /* eq, gtu, etc */
+ "Flag", /* [UIOSZC] */
+ "RbRi" /* [Rb + scale * Ri] */
+};
+
+#define N_RXO (sizeof(id_names)/sizeof(id_names[0]))
+#define N_RXT (sizeof(optype_names)/sizeof(optype_names[0]))
+#define N_MAP 30
+
+static unsigned long long benchmark_start_cycle;
+static unsigned long long benchmark_end_cycle;
+
+static int op_cache[N_RXT][N_RXT][N_RXT];
+static int op_cache_rev[N_MAP];
+static int op_cache_idx = 0;
+
+static int
+op_lookup (int a, int b, int c)
+{
+ if (op_cache[a][b][c])
+ return op_cache[a][b][c];
+ op_cache_idx ++;
+ if (op_cache_idx >= N_MAP)
+ {
+ printf("op_cache_idx exceeds %d\n", N_MAP);
+ exit(1);
+ }
+ op_cache[a][b][c] = op_cache_idx;
+ op_cache_rev[op_cache_idx] = (a<<8) | (b<<4) | c;
+ return op_cache_idx;
+}
+
+static char *
+op_cache_string (int map)
+{
+ static int ci;
+ static char cb[5][20];
+ int a, b, c;
+
+ map = op_cache_rev[map];
+ a = (map >> 8) & 15;
+ b = (map >> 4) & 15;
+ c = (map >> 0) & 15;
+ ci = (ci + 1) % 5;
+ sprintf(cb[ci], "%s %s %s", optype_names[a], optype_names[b], optype_names[c]);
+ return cb[ci];
+}
+
+static unsigned long long cycles_per_id[N_RXO][N_MAP];
+static unsigned long long times_per_id[N_RXO][N_MAP];
+static unsigned long long memory_stalls;
+static unsigned long long register_stalls;
+static unsigned long long branch_stalls;
+static unsigned long long branch_alignment_stalls;
+static unsigned long long fast_returns;
+
+static unsigned long times_per_pair[N_RXO][N_MAP][N_RXO][N_MAP];
+static int prev_opcode_id = RXO_unknown;
+static int po0;
-#define tprintf if (trace) printf
+#define STATS(x) x
+
+#else
+#define STATS(x)
+#endif /* CYCLE_STATS */
+
+
+#ifdef CYCLE_ACCURATE
+
+static int new_rt = -1;
+
+/* Number of cycles to add if an insn spans an 8-byte boundary. */
+static int branch_alignment_penalty = 0;
+
+#endif
+
+static int running_benchmark = 1;
+
+#define tprintf if (trace && running_benchmark) printf
jmp_buf decode_jmp_buf;
unsigned int rx_cycles = 0;
+#ifdef CYCLE_ACCURATE
+/* If nonzero, memory was read at some point and cycle latency might
+ take effect. */
+static int memory_source = 0;
+/* If nonzero, memory was written and extra cycles might be
+ needed. */
+static int memory_dest = 0;
+
+static void
+cycles (int throughput)
+{
+ tprintf("%d cycles\n", throughput);
+ regs.cycle_count += throughput;
+}
+
+/* Number of execution (E) cycles the op uses. For memory sources, we
+ include the load micro-op stall as two extra E cycles. */
+#define E(c) cycles (memory_source ? c + 2 : c)
+#define E1 cycles (1)
+#define E2 cycles (2)
+#define EBIT cycles (memory_source ? 2 : 1)
+
+/* Check to see if a read latency must be applied for a given register. */
+#define RL(r) \
+ if (regs.rt == r ) \
+ { \
+ tprintf("register %d load stall\n", r); \
+ regs.cycle_count ++; \
+ STATS(register_stalls ++); \
+ regs.rt = -1; \
+ }
+
+#define RLD(r) \
+ if (memory_source) \
+ { \
+ tprintf ("Rt now %d\n", r); \
+ new_rt = r; \
+ }
+
+static int
+lsb_count (unsigned long v, int is_signed)
+{
+ int i, lsb;
+ if (is_signed && (v & 0x80000000U))
+ v = (unsigned long)(long)(-v);
+ for (i=31; i>=0; i--)
+ if (v & (1 << i))
+ {
+ /* v is 0..31, we want 1=1-2, 2=3-4, 3=5-6, etc. */
+ lsb = (i + 2) / 2;
+ return lsb;
+ }
+ return 0;
+}
+
+static int
+divu_cycles(unsigned long num, unsigned long den)
+{
+ int nb = lsb_count (num, 0);
+ int db = lsb_count (den, 0);
+ int rv;
+
+ if (nb < db)
+ rv = 2;
+ else
+ rv = 3 + nb - db;
+ E (rv);
+ return rv;
+}
+
+static int
+div_cycles(long num, long den)
+{
+ int nb = lsb_count ((unsigned long)num, 1);
+ int db = lsb_count ((unsigned long)den, 1);
+ int rv;
+
+ if (nb < db)
+ rv = 3;
+ else
+ rv = 5 + nb - db;
+ E (rv);
+ return rv;
+}
+
+#else /* !CYCLE_ACCURATE */
+
+#define cycles(t)
+#define E(c)
+#define E1
+#define E2
+#define EBIT
+#define RL(r)
+#define RLD(r)
+
+#define divu_cycles(n,d)
+#define div_cycles(n,d)
+
+#endif /* else CYCLE_ACCURATE */
+
static int size2bytes[] = {
4, 1, 1, 1, 2, 2, 2, 3, 4
};
abort();
}
-static int
-rx_get_byte (void *vdata)
+static unsigned char *get_byte_base;
+static RX_Opcode_Decoded **decode_cache_base;
+static SI get_byte_page;
+
+void
+reset_decoder (void)
{
- int saved_trace = trace;
- unsigned char rv;
+ get_byte_base = 0;
+ decode_cache_base = 0;
+ get_byte_page = 0;
+}
- if (trace == 1)
- trace = 0;
+static inline void
+maybe_get_mem_page (SI tpc)
+{
+ if (((tpc ^ get_byte_page) & NONPAGE_MASK) || enable_counting)
+ {
+ get_byte_page = tpc & NONPAGE_MASK;
+ get_byte_base = rx_mem_ptr (get_byte_page, MPA_READING) - get_byte_page;
+ decode_cache_base = rx_mem_decode_cache (get_byte_page) - get_byte_page;
+ }
+}
+/* This gets called a *lot* so optimize it. */
+static int
+rx_get_byte (void *vdata)
+{
RX_Data *rx_data = (RX_Data *)vdata;
+ SI tpc = rx_data->dpc;
+
+ /* See load.c for an explanation of this. */
if (rx_big_endian)
- /* See load.c for an explanation of this. */
- rv = mem_get_pc (rx_data->dpc ^ 3);
- else
- rv = mem_get_pc (rx_data->dpc);
+ tpc ^= 3;
+
+ maybe_get_mem_page (tpc);
+
rx_data->dpc ++;
- trace = saved_trace;
- return rv;
+ return get_byte_base [tpc];
}
static int
-get_op (RX_Opcode_Decoded *rd, int i)
+get_op (const RX_Opcode_Decoded *rd, int i)
{
- RX_Opcode_Operand *o = rd->op + i;
+ const RX_Opcode_Operand *o = rd->op + i;
int addr, rv = 0;
switch (o->type)
return o->addend;
case RX_Operand_Register: /* Rn */
+ RL (o->reg);
rv = get_reg (o->reg);
break;
/* fall through */
case RX_Operand_Postinc: /* [Rn+] */
case RX_Operand_Indirect: /* [Rn + addend] */
+ case RX_Operand_TwoReg: /* [Rn + scale * R2] */
+#ifdef CYCLE_ACCURATE
+ RL (o->reg);
+ if (o->type == RX_Operand_TwoReg)
+ RL (rd->op[2].reg);
+ regs.rt = -1;
+ if (regs.m2m == M2M_BOTH)
+ {
+ tprintf("src memory stall\n");
+#ifdef CYCLE_STATS
+ memory_stalls ++;
+#endif
+ regs.cycle_count ++;
+ regs.m2m = 0;
+ }
+
+ memory_source = 1;
+#endif
+
+ if (o->type == RX_Operand_TwoReg)
+ addr = get_reg (o->reg) * size2bytes[rd->size] + get_reg (rd->op[2].reg);
+ else
+ addr = get_reg (o->reg) + o->addend;
- addr = get_reg (o->reg) + o->addend;
switch (o->size)
{
case RX_AnySize:
}
static void
-put_op (RX_Opcode_Decoded *rd, int i, int v)
+put_op (const RX_Opcode_Decoded *rd, int i, int v)
{
- RX_Opcode_Operand *o = rd->op + i;
+ const RX_Opcode_Operand *o = rd->op + i;
int addr;
switch (o->size)
case RX_Operand_Register: /* Rn */
put_reg (o->reg, v);
+ RLD (o->reg);
break;
case RX_Operand_Predec: /* [-Rn] */
/* fall through */
case RX_Operand_Postinc: /* [Rn+] */
case RX_Operand_Indirect: /* [Rn + addend] */
+ case RX_Operand_TwoReg: /* [Rn + scale * R2] */
+
+#ifdef CYCLE_ACCURATE
+ if (regs.m2m == M2M_BOTH)
+ {
+ tprintf("dst memory stall\n");
+ regs.cycle_count ++;
+#ifdef CYCLE_STATS
+ memory_stalls ++;
+#endif
+ regs.m2m = 0;
+ }
+ memory_dest = 1;
+#endif
+
+ if (o->type == RX_Operand_TwoReg)
+ addr = get_reg (o->reg) * size2bytes[rd->size] + get_reg (rd->op[2].reg);
+ else
+ addr = get_reg (o->reg) + o->addend;
- addr = get_reg (o->reg) + o->addend;
switch (o->size)
{
case RX_AnySize:
}
}
-#define PD(x) put_op (&opcode, 0, x)
-#define PS(x) put_op (&opcode, 1, x)
-#define PS2(x) put_op (&opcode, 2, x)
-#define GD() get_op (&opcode, 0)
-#define GS() get_op (&opcode, 1)
-#define GS2() get_op (&opcode, 2)
-#define DSZ() size2bytes[opcode.op[0].size]
-#define SSZ() size2bytes[opcode.op[0].size]
-#define S2SZ() size2bytes[opcode.op[0].size]
+#define PD(x) put_op (opcode, 0, x)
+#define PS(x) put_op (opcode, 1, x)
+#define PS2(x) put_op (opcode, 2, x)
+#define GD() get_op (opcode, 0)
+#define GS() get_op (opcode, 1)
+#define GS2() get_op (opcode, 2)
+#define DSZ() size2bytes[opcode->op[0].size]
+#define SSZ() size2bytes[opcode->op[0].size]
+#define S2SZ() size2bytes[opcode->op[0].size]
/* "Universal" sources. */
-#define US1() ((opcode.op[2].type == RX_Operand_None) ? GD() : GS())
-#define US2() ((opcode.op[2].type == RX_Operand_None) ? GS() : GS2())
+#define US1() ((opcode->op[2].type == RX_Operand_None) ? GD() : GS())
+#define US2() ((opcode->op[2].type == RX_Operand_None) ? GS() : GS2())
static void
push(int val)
#define MATH_OP(vop,c) \
{ \
- uma = US1(); \
umb = US2(); \
+ uma = US1(); \
ll = (unsigned long long) uma vop (unsigned long long) umb vop c; \
tprintf ("0x%x " #vop " 0x%x " #vop " 0x%x = 0x%llx\n", uma, umb, c, ll); \
ma = sign_ext (uma, DSZ() * 8); \
tprintf ("%d " #vop " %d " #vop " %d = %lld\n", ma, mb, c, sll); \
set_oszc (sll, DSZ(), (long long) ll > ((1 vop 1) ? (long long) b2mask[DSZ()] : (long long) -1)); \
PD (sll); \
+ E (1); \
}
#define LOGIC_OP(vop) \
{ \
- ma = US1(); \
mb = US2(); \
+ ma = US1(); \
v = ma vop mb; \
tprintf("0x%x " #vop " 0x%x = 0x%x\n", ma, mb, v); \
set_sz (v, DSZ()); \
PD(v); \
+ E (1); \
}
#define SHIFT_OP(val, type, count, OP, carry_mask) \
{ \
int i, c=0; \
- val = (type)US1(); \
count = US2(); \
+ val = (type)US1(); \
tprintf("%lld " #OP " %d\n", val, count); \
for (i = 0; i < count; i ++) \
{ \
c = val & carry_mask; \
val OP 1; \
} \
- if (count) \
- set_oszc (val, 4, c); \
+ set_oszc (val, 4, c); \
PD (val); \
}
int do_store; \
fp_t fa, fb, fc; \
FPCLEAR(); \
- fa = GD (); \
fb = GS (); \
+ fa = GD (); \
do_store = fop_##func (fa, fb, &fc); \
tprintf("%g " #func " %g = %g %08x\n", int2float(fa), int2float(fb), int2float(fc), fc); \
FPCHECK(); \
return RX_MAKE_STEPPED ();
}
+static int
+op_is_memory (const RX_Opcode_Decoded *rd, int i)
+{
+ switch (rd->op[i].type)
+ {
+ case RX_Operand_Predec:
+ case RX_Operand_Postinc:
+ case RX_Operand_Indirect:
+ return 1;
+ default:
+ return 0;
+ }
+}
+#define OM(i) op_is_memory (opcode, i)
+
+#define DO_RETURN(x) { longjmp (decode_jmp_buf, x); }
+
int
decode_opcode ()
{
long long sll;
unsigned long opcode_pc;
RX_Data rx_data;
- RX_Opcode_Decoded opcode;
- int rv;
-
- if ((rv = setjmp (decode_jmp_buf)))
- return rv;
+ const RX_Opcode_Decoded *opcode;
+#ifdef CYCLE_STATS
+ unsigned long long prev_cycle_count;
+#endif
+#ifdef CYCLE_ACCURATE
+ unsigned int tx;
+#endif
+
+#ifdef CYCLE_STATS
+ prev_cycle_count = regs.cycle_count;
+#endif
+
+#ifdef CYCLE_ACCURATE
+ memory_source = 0;
+ memory_dest = 0;
+#endif
rx_cycles ++;
- rx_data.dpc = opcode_pc = regs.r_pc;
- opcode_size = rx_decode_opcode (opcode_pc, &opcode, rx_get_byte, &rx_data);
+ maybe_get_mem_page (regs.r_pc);
+
+ opcode_pc = regs.r_pc;
+
+ /* Note that we don't word-swap this point, there's no point. */
+ if (decode_cache_base[opcode_pc] == NULL)
+ {
+ RX_Opcode_Decoded *opcode_w;
+ rx_data.dpc = opcode_pc;
+ opcode_w = decode_cache_base[opcode_pc] = calloc (1, sizeof (RX_Opcode_Decoded));
+ opcode_size = rx_decode_opcode (opcode_pc, opcode_w,
+ rx_get_byte, &rx_data);
+ opcode = opcode_w;
+ }
+ else
+ {
+ opcode = decode_cache_base[opcode_pc];
+ opcode_size = opcode->n_bytes;
+ }
+
+#ifdef CYCLE_ACCURATE
+ if (branch_alignment_penalty)
+ {
+ if ((regs.r_pc ^ (regs.r_pc + opcode_size - 1)) & ~7)
+ {
+ tprintf("1 cycle branch alignment penalty\n");
+ cycles (branch_alignment_penalty);
+#ifdef CYCLE_STATS
+ branch_alignment_stalls ++;
+#endif
+ }
+ branch_alignment_penalty = 0;
+ }
+#endif
+
regs.r_pc += opcode_size;
- rx_flagmask = opcode.flags_s;
- rx_flagand = ~(int)opcode.flags_0;
- rx_flagor = opcode.flags_1;
+ rx_flagmask = opcode->flags_s;
+ rx_flagand = ~(int)opcode->flags_0;
+ rx_flagor = opcode->flags_1;
- switch (opcode.id)
+ switch (opcode->id)
{
case RXO_abs:
sll = GS ();
tprintf("%lld\n", sll);
PD (sll);
set_osz (sll, 4);
+ E (1);
break;
case RXO_adc:
case RXO_bclr:
ma = GD ();
mb = GS ();
- if (opcode.op[0].type == RX_Operand_Register)
+ if (opcode->op[0].type == RX_Operand_Register)
mb &= 0x1f;
else
mb &= 0x07;
ma &= ~(1 << mb);
PD (ma);
+ EBIT;
break;
case RXO_bmcc:
ma = GD ();
mb = GS ();
- if (opcode.op[0].type == RX_Operand_Register)
+ if (opcode->op[0].type == RX_Operand_Register)
mb &= 0x1f;
else
mb &= 0x07;
else
ma &= ~(1 << mb);
PD (ma);
+ EBIT;
break;
case RXO_bnot:
ma = GD ();
mb = GS ();
- if (opcode.op[0].type == RX_Operand_Register)
+ if (opcode->op[0].type == RX_Operand_Register)
mb &= 0x1f;
else
mb &= 0x07;
ma ^= (1 << mb);
PD (ma);
+ EBIT;
break;
case RXO_branch:
- if (GS())
- regs.r_pc = GD();
+ if (opcode->op[1].type == RX_Operand_None || GS())
+ {
+#ifdef CYCLE_ACCURATE
+ SI old_pc = regs.r_pc;
+ int delta;
+#endif
+ regs.r_pc = GD();
+#ifdef CYCLE_ACCURATE
+ delta = regs.r_pc - old_pc;
+ if (delta >= 0 && delta < 16
+ && opcode_size > 1)
+ {
+ tprintf("near forward branch bonus\n");
+ cycles (2);
+ }
+ else
+ {
+ cycles (3);
+ branch_alignment_penalty = 1;
+ }
+#ifdef CYCLE_STATS
+ branch_stalls ++;
+#endif
+#endif
+ }
+#ifdef CYCLE_ACCURATE
+ else
+ cycles (1);
+#endif
break;
case RXO_branchrel:
- if (GS())
- regs.r_pc += GD();
+ if (opcode->op[1].type == RX_Operand_None || GS())
+ {
+ int delta = GD();
+ regs.r_pc = opcode_pc + delta;
+#ifdef CYCLE_ACCURATE
+ /* Note: specs say 3, chip says 2. */
+ if (delta >= 0 && delta < 16
+ && opcode_size > 1)
+ {
+ tprintf("near forward branch bonus\n");
+ cycles (2);
+ }
+ else
+ {
+ cycles (3);
+ branch_alignment_penalty = 1;
+ }
+#ifdef CYCLE_STATS
+ branch_stalls ++;
+#endif
+#endif
+ }
+#ifdef CYCLE_ACCURATE
+ else
+ cycles (1);
+#endif
break;
case RXO_brk:
{
int old_psw = regs.r_psw;
if (rx_in_gdb)
- return RX_MAKE_HIT_BREAK ();
+ DO_RETURN (RX_MAKE_HIT_BREAK ());
if (regs.r_intb == 0)
{
tprintf("BREAK hit, no vector table.\n");
- return RX_MAKE_EXITED(1);
+ DO_RETURN (RX_MAKE_EXITED(1));
}
regs.r_psw &= ~(FLAGBIT_I | FLAGBIT_U | FLAGBIT_PM);
pushpc (old_psw);
pushpc (regs.r_pc);
regs.r_pc = mem_get_si (regs.r_intb);
+ cycles(6);
}
break;
case RXO_bset:
ma = GD ();
mb = GS ();
- if (opcode.op[0].type == RX_Operand_Register)
+ if (opcode->op[0].type == RX_Operand_Register)
mb &= 0x1f;
else
mb &= 0x07;
ma |= (1 << mb);
PD (ma);
+ EBIT;
break;
case RXO_btst:
ma = GS ();
mb = GS2 ();
- if (opcode.op[0].type == RX_Operand_Register)
+ if (opcode->op[1].type == RX_Operand_Register)
mb &= 0x1f;
else
mb &= 0x07;
umb = ma & (1 << mb);
set_zc (! umb, umb);
+ EBIT;
break;
case RXO_clrpsw:
- v = 1 << opcode.op[0].reg;
+ v = 1 << opcode->op[0].reg;
if (FLAG_PM
&& (v == FLAGBIT_I
|| v == FLAGBIT_U))
break;
regs.r_psw &= ~v;
+ cycles (1);
break;
case RXO_div: /* d = d / s */
{
tprintf("#NAN\n");
set_flags (FLAGBIT_O, FLAGBIT_O);
+ cycles (3);
}
else
{
tprintf("%d\n", v);
set_flags (FLAGBIT_O, 0);
PD (v);
+ div_cycles (mb, ma);
}
break;
{
tprintf("#NAN\n");
set_flags (FLAGBIT_O, FLAGBIT_O);
+ cycles (2);
}
else
{
tprintf("%u\n", v);
set_flags (FLAGBIT_O, 0);
PD (v);
- }
- break;
-
- case RXO_ediv:
- ma = GS();
- mb = GD();
- tprintf("%d / %d = ", mb, ma);
- if (ma == 0 || (ma == -1 && (unsigned int) mb == 0x80000000))
- {
- tprintf("#NAN\n");
- set_flags (FLAGBIT_O, FLAGBIT_O);
- }
- else
- {
- v = mb/ma;
- mb = mb%ma;
- tprintf("%d, rem %d\n", v, mb);
- set_flags (FLAGBIT_O, 0);
- PD (v);
- opcode.op[0].reg ++;
- PD (mb);
- }
- break;
-
- case RXO_edivu:
- uma = GS();
- umb = GD();
- tprintf("%u / %u = ", umb, uma);
- if (uma == 0)
- {
- tprintf("#NAN\n");
- set_flags (FLAGBIT_O, FLAGBIT_O);
- }
- else
- {
- v = umb/uma;
- umb = umb%uma;
- tprintf("%u, rem %u\n", v, umb);
- set_flags (FLAGBIT_O, 0);
- PD (v);
- opcode.op[0].reg ++;
- PD (umb);
+ divu_cycles (umb, uma);
}
break;
mb = GS ();
sll = (long long)ma * (long long)mb;
tprintf("%d * %d = %lld\n", ma, mb, sll);
- PD (sll);
- opcode.op[0].reg ++;
- PD (sll >> 32);
+ put_reg (opcode->op[0].reg, sll);
+ put_reg (opcode->op[0].reg + 1, sll >> 32);
+ E2;
break;
case RXO_emulu:
umb = GS ();
ll = (long long)uma * (long long)umb;
tprintf("%#x * %#x = %#llx\n", uma, umb, ll);
- PD (ll);
- opcode.op[0].reg ++;
- PD (ll >> 32);
+ put_reg (opcode->op[0].reg, ll);
+ put_reg (opcode->op[0].reg + 1, ll >> 32);
+ E2;
break;
case RXO_fadd:
FLOAT_OP (fadd);
+ E (4);
break;
case RXO_fcmp:
FPCLEAR ();
rxfp_cmp (ma, mb);
FPCHECK ();
+ E (1);
break;
case RXO_fdiv:
FLOAT_OP (fdiv);
+ E (16);
break;
case RXO_fmul:
FLOAT_OP (fmul);
+ E (3);
break;
case RXO_rtfi:
PRIVILEDGED ();
regs.r_psw = regs.r_bpsw;
regs.r_pc = regs.r_bpc;
+#ifdef CYCLE_ACCURATE
+ regs.fast_return = 0;
+ cycles(3);
+#endif
break;
case RXO_fsub:
FLOAT_OP (fsub);
+ E (4);
break;
case RXO_ftoi:
PD (mb);
tprintf("(int) %g = %d\n", int2float(ma), mb);
set_sz (mb, 4);
+ E (2);
break;
case RXO_int:
v = GS ();
if (v == 255)
{
- return rx_syscall (regs.r[5]);
+ int rc = rx_syscall (regs.r[5]);
+ if (! RX_STEPPED (rc))
+ DO_RETURN (rc);
}
else
{
pushpc (regs.r_pc);
regs.r_pc = mem_get_si (regs.r_intb + 4 * v);
}
+ cycles (6);
break;
case RXO_itof:
tprintf("(float) %d = %x\n", ma, mb);
PD (mb);
set_sz (ma, 4);
+ E (2);
break;
case RXO_jsr:
case RXO_jsrrel:
- v = GD ();
- pushpc (get_reg (pc));
- if (opcode.id == RXO_jsrrel)
- v += regs.r_pc;
- put_reg (pc, v);
+ {
+#ifdef CYCLE_ACCURATE
+ int delta;
+ regs.m2m = 0;
+#endif
+ v = GD ();
+#ifdef CYCLE_ACCURATE
+ regs.link_register = regs.r_pc;
+#endif
+ pushpc (get_reg (pc));
+ if (opcode->id == RXO_jsrrel)
+ v += regs.r_pc;
+#ifdef CYCLE_ACCURATE
+ delta = v - regs.r_pc;
+#endif
+ put_reg (pc, v);
+#ifdef CYCLE_ACCURATE
+ /* Note: docs say 3, chip says 2 */
+ if (delta >= 0 && delta < 16)
+ {
+ tprintf ("near forward jsr bonus\n");
+ cycles (2);
+ }
+ else
+ {
+ branch_alignment_penalty = 1;
+ cycles (3);
+ }
+ regs.fast_return = 1;
+#endif
+ }
break;
case RXO_machi:
ll = (long long)(signed short)(GS() >> 16) * (long long)(signed short)(GS2 () >> 16);
ll <<= 16;
put_reg64 (acc64, ll + regs.r_acc);
+ E1;
break;
case RXO_maclo:
ll = (long long)(signed short)(GS()) * (long long)(signed short)(GS2 ());
ll <<= 16;
put_reg64 (acc64, ll + regs.r_acc);
+ E1;
break;
case RXO_max:
- ma = GD();
mb = GS();
+ ma = GD();
if (ma > mb)
PD (ma);
else
PD (mb);
+ E (1);
break;
case RXO_min:
- ma = GD();
mb = GS();
+ ma = GD();
if (ma < mb)
PD (ma);
else
PD (mb);
+ E (1);
break;
case RXO_mov:
v = GS ();
- if (opcode.op[0].type == RX_Operand_Register
- && opcode.op[0].reg == 16 /* PSW */)
+
+ if (opcode->op[1].type == RX_Operand_Register
+ && opcode->op[1].reg == 17 /* PC */)
+ {
+ /* Special case. We want the address of the insn, not the
+ address of the next insn. */
+ v = opcode_pc;
+ }
+
+ if (opcode->op[0].type == RX_Operand_Register
+ && opcode->op[0].reg == 16 /* PSW */)
{
/* Special case, LDC and POPC can't ever modify PM. */
int pm = regs.r_psw & FLAGBIT_PM;
if (FLAG_PM)
{
/* various things can't be changed in user mode. */
- if (opcode.op[0].type == RX_Operand_Register)
- if (opcode.op[0].reg == 32)
+ if (opcode->op[0].type == RX_Operand_Register)
+ if (opcode->op[0].reg == 32)
{
v &= ~ (FLAGBIT_I | FLAGBIT_U | FLAGBITS_IPL);
v |= regs.r_psw & (FLAGBIT_I | FLAGBIT_U | FLAGBITS_IPL);
}
- if (opcode.op[0].reg == 34 /* ISP */
- || opcode.op[0].reg == 37 /* BPSW */
- || opcode.op[0].reg == 39 /* INTB */
- || opcode.op[0].reg == 38 /* VCT */)
+ if (opcode->op[0].reg == 34 /* ISP */
+ || opcode->op[0].reg == 37 /* BPSW */
+ || opcode->op[0].reg == 39 /* INTB */
+ || opcode->op[0].reg == 38 /* VCT */)
/* These are ignored. */
break;
}
+ if (OM(0) && OM(1))
+ cycles (2);
+ else
+ cycles (1);
+
PD (v);
+
+#ifdef CYCLE_ACCURATE
+ if ((opcode->op[0].type == RX_Operand_Predec
+ && opcode->op[1].type == RX_Operand_Register)
+ || (opcode->op[0].type == RX_Operand_Postinc
+ && opcode->op[1].type == RX_Operand_Register))
+ {
+ /* Special case: push reg doesn't cause a memory stall. */
+ memory_dest = 0;
+ tprintf("push special case\n");
+ }
+#endif
+
set_sz (v, DSZ());
break;
case RXO_movbi:
- /* We cheat to save on code duplication. */
- regs.r_temp = (get_reg (opcode.op[1].reg) * size2bytes[opcode.size]
- + get_reg (opcode.op[2].reg));
- opcode.op[1].reg = r_temp_idx;
- opcode.op[1].type = RX_Operand_Indirect;
- opcode.op[1].addend = 0;
PD (GS ());
+ cycles (1);
break;
case RXO_movbir:
- /* We cheat to save on code duplication. */
- regs.r_temp = (get_reg (opcode.op[1].reg) * size2bytes[opcode.size]
- + get_reg (opcode.op[2].reg));
- opcode.op[1].reg = r_temp_idx;
- opcode.op[1].type = RX_Operand_Indirect;
- opcode.op[1].addend = 0;
PS (GD ());
+ cycles (1);
break;
case RXO_mul:
- ll = (unsigned long long) US1() * (unsigned long long) US2();
+ v = US2 ();
+ ll = (unsigned long long) US1() * (unsigned long long) v;
PD(ll);
+ E (1);
break;
case RXO_mulhi:
- ll = (long long)(signed short)(GS() >> 16) * (long long)(signed short)(GS2 () >> 16);
+ v = GS2 ();
+ ll = (long long)(signed short)(GS() >> 16) * (long long)(signed short)(v >> 16);
ll <<= 16;
put_reg64 (acc64, ll);
+ E1;
break;
case RXO_mullo:
- ll = (long long)(signed short)(GS()) * (long long)(signed short)(GS2 ());
+ v = GS2 ();
+ ll = (long long)(signed short)(GS()) * (long long)(signed short)(v);
ll <<= 16;
put_reg64 (acc64, ll);
+ E1;
break;
case RXO_mvfachi:
PD (get_reg (acchi));
+ E1;
break;
case RXO_mvfaclo:
PD (get_reg (acclo));
+ E1;
break;
case RXO_mvfacmi:
PD (get_reg (accmi));
+ E1;
break;
case RXO_mvtachi:
put_reg (acchi, GS ());
+ E1;
break;
case RXO_mvtaclo:
put_reg (acclo, GS ());
+ E1;
break;
case RXO_mvtipl:
regs.r_psw &= ~ FLAGBITS_IPL;
regs.r_psw |= (GS () << FLAGSHIFT_IPL) & FLAGBITS_IPL;
+ E1;
break;
case RXO_nop:
+ case RXO_nop2:
+ case RXO_nop3:
+ E1;
break;
case RXO_or:
case RXO_popm:
/* POPM cannot pop R0 (sp). */
- if (opcode.op[1].reg == 0 || opcode.op[2].reg == 0)
+ if (opcode->op[1].reg == 0 || opcode->op[2].reg == 0)
EXCEPTION (EX_UNDEFINED);
- if (opcode.op[1].reg >= opcode.op[2].reg)
+ if (opcode->op[1].reg >= opcode->op[2].reg)
{
regs.r_pc = opcode_pc;
- return RX_MAKE_STOPPED (SIGILL);
+ DO_RETURN (RX_MAKE_STOPPED (SIGILL));
+ }
+ for (v = opcode->op[1].reg; v <= opcode->op[2].reg; v++)
+ {
+ cycles (1);
+ RLD (v);
+ put_reg (v, pop ());
}
- for (v = opcode.op[1].reg; v <= opcode.op[2].reg; v++)
- put_reg (v, pop ());
- break;
-
- case RXO_pusha:
- push (get_reg (opcode.op[1].reg) + opcode.op[1].addend);
break;
case RXO_pushm:
/* PUSHM cannot push R0 (sp). */
- if (opcode.op[1].reg == 0 || opcode.op[2].reg == 0)
+ if (opcode->op[1].reg == 0 || opcode->op[2].reg == 0)
EXCEPTION (EX_UNDEFINED);
- if (opcode.op[1].reg >= opcode.op[2].reg)
+ if (opcode->op[1].reg >= opcode->op[2].reg)
{
regs.r_pc = opcode_pc;
return RX_MAKE_STOPPED (SIGILL);
}
- for (v = opcode.op[2].reg; v >= opcode.op[1].reg; v--)
- push (get_reg (v));
+ for (v = opcode->op[2].reg; v >= opcode->op[1].reg; v--)
+ {
+ RL (v);
+ push (get_reg (v));
+ }
+ cycles (opcode->op[2].reg - opcode->op[1].reg + 1);
break;
case RXO_racw:
else
ll &= 0xffffffff00000000ULL;
put_reg64 (acc64, ll);
+ E1;
break;
case RXO_rte:
regs.r_psw = poppc ();
if (FLAG_PM)
regs.r_psw |= FLAGBIT_U;
+#ifdef CYCLE_ACCURATE
+ regs.fast_return = 0;
+ cycles (6);
+#endif
break;
case RXO_revl:
| ((uma << 8) & 0xff0000)
| ((uma << 24) & 0xff000000UL));
PD (umb);
+ E1;
break;
case RXO_revw:
umb = (((uma >> 8) & 0x00ff00ff)
| ((uma << 8) & 0xff00ff00UL));
PD (umb);
+ E1;
break;
case RXO_rmpa:
+ RL(4);
+ RL(5);
+#ifdef CYCLE_ACCURATE
+ tx = regs.r[3];
+#endif
+
while (regs.r[3] != 0)
{
long long tmp;
- switch (opcode.size)
+ switch (opcode->size)
{
case RX_Long:
ma = mem_get_si (regs.r[1]);
set_flags (FLAGBIT_O|FLAGBIT_S, ma | FLAGBIT_O);
else
set_flags (FLAGBIT_O|FLAGBIT_S, ma);
+#ifdef CYCLE_ACCURATE
+ switch (opcode->size)
+ {
+ case RX_Long:
+ cycles (6 + 4 * tx);
+ break;
+ case RX_Word:
+ cycles (6 + 5 * (tx / 2) + 4 * (tx % 2));
+ break;
+ case RX_Byte:
+ cycles (6 + 7 * (tx / 4) + 4 * (tx % 4));
+ break;
+ default:
+ abort ();
+ }
+#endif
break;
case RXO_rolc:
v |= carry;
set_szc (v, 4, ma);
PD (v);
+ E1;
break;
case RXO_rorc:
uma |= (carry ? 0x80000000UL : 0);
set_szc (uma, 4, mb);
PD (uma);
+ E1;
break;
case RXO_rotl:
}
set_szc (uma, 4, mb);
PD (uma);
+ E1;
break;
case RXO_rotr:
}
set_szc (uma, 4, mb);
PD (uma);
+ E1;
break;
case RXO_round:
PD (mb);
tprintf("(int) %g = %d\n", int2float(ma), mb);
set_sz (mb, 4);
+ E (2);
break;
case RXO_rts:
- regs.r_pc = poppc ();
+ {
+#ifdef CYCLE_ACCURATE
+ int cyc = 5;
+#endif
+ regs.r_pc = poppc ();
+#ifdef CYCLE_ACCURATE
+ /* Note: specs say 5, chip says 3. */
+ if (regs.fast_return && regs.link_register == regs.r_pc)
+ {
+#ifdef CYCLE_STATS
+ fast_returns ++;
+#endif
+ tprintf("fast return bonus\n");
+ cyc -= 2;
+ }
+ cycles (cyc);
+ regs.fast_return = 0;
+ branch_alignment_penalty = 1;
+#endif
+ }
break;
case RXO_rtsd:
- if (opcode.op[2].type == RX_Operand_Register)
+ if (opcode->op[2].type == RX_Operand_Register)
{
int i;
/* RTSD cannot pop R0 (sp). */
- put_reg (0, get_reg (0) + GS() - (opcode.op[0].reg-opcode.op[2].reg+1)*4);
- if (opcode.op[2].reg == 0)
+ put_reg (0, get_reg (0) + GS() - (opcode->op[0].reg-opcode->op[2].reg+1)*4);
+ if (opcode->op[2].reg == 0)
EXCEPTION (EX_UNDEFINED);
- for (i = opcode.op[2].reg; i <= opcode.op[0].reg; i ++)
- put_reg (i, pop ());
+#ifdef CYCLE_ACCURATE
+ tx = opcode->op[0].reg - opcode->op[2].reg + 1;
+#endif
+ for (i = opcode->op[2].reg; i <= opcode->op[0].reg; i ++)
+ {
+ RLD (i);
+ put_reg (i, pop ());
+ }
}
else
- put_reg (0, get_reg (0) + GS());
- put_reg (pc, poppc ());
+ {
+#ifdef CYCLE_ACCURATE
+ tx = 0;
+#endif
+ put_reg (0, get_reg (0) + GS());
+ }
+ put_reg (pc, poppc());
+#ifdef CYCLE_ACCURATE
+ if (regs.fast_return && regs.link_register == regs.r_pc)
+ {
+ tprintf("fast return bonus\n");
+#ifdef CYCLE_STATS
+ fast_returns ++;
+#endif
+ cycles (tx < 3 ? 3 : tx + 1);
+ }
+ else
+ {
+ cycles (tx < 5 ? 5 : tx + 1);
+ }
+ regs.fast_return = 0;
+ branch_alignment_penalty = 1;
+#endif
break;
case RXO_sat:
PD (0x7fffffffUL);
else if (FLAG_O && ! FLAG_S)
PD (0x80000000UL);
+ E1;
break;
+ case RXO_satr:
+ if (FLAG_O && ! FLAG_S)
+ {
+ put_reg (6, 0x0);
+ put_reg (5, 0x7fffffff);
+ put_reg (4, 0xffffffff);
+ }
+ else if (FLAG_O && FLAG_S)
+ {
+ put_reg (6, 0xffffffff);
+ put_reg (5, 0x80000000);
+ put_reg (4, 0x0);
+ }
+ E1;
+ break;
+
case RXO_sbb:
MATH_OP (-, ! carry);
break;
PD (1);
else
PD (0);
+ E1;
break;
case RXO_scmpu:
+#ifdef CYCLE_ACCURATE
+ tx = regs.r[3];
+#endif
while (regs.r[3] != 0)
{
uma = mem_get_qi (regs.r[1] ++);
set_zc (1, 1);
else
set_zc (0, ((int)uma - (int)umb) >= 0);
+ cycles (2 + 4 * (tx / 4) + 4 * (tx % 4));
break;
case RXO_setpsw:
- v = 1 << opcode.op[0].reg;
+ v = 1 << opcode->op[0].reg;
if (FLAG_PM
&& (v == FLAGBIT_I
|| v == FLAGBIT_U))
break;
regs.r_psw |= v;
+ cycles (1);
break;
case RXO_smovb:
+ RL (3);
+#ifdef CYCLE_ACCURATE
+ tx = regs.r[3];
+#endif
while (regs.r[3])
{
uma = mem_get_qi (regs.r[2] --);
mem_put_qi (regs.r[1]--, uma);
regs.r[3] --;
}
+#ifdef CYCLE_ACCURATE
+ if (tx > 3)
+ cycles (6 + 3 * (tx / 4) + 3 * (tx % 4));
+ else
+ cycles (2 + 3 * (tx % 4));
+#endif
break;
case RXO_smovf:
+ RL (3);
+#ifdef CYCLE_ACCURATE
+ tx = regs.r[3];
+#endif
while (regs.r[3])
{
uma = mem_get_qi (regs.r[2] ++);
mem_put_qi (regs.r[1]++, uma);
regs.r[3] --;
}
+ cycles (2 + 3 * (int)(tx / 4) + 3 * (tx % 4));
break;
case RXO_smovu:
+#ifdef CYCLE_ACCURATE
+ tx = regs.r[3];
+#endif
while (regs.r[3] != 0)
{
uma = mem_get_qi (regs.r[2] ++);
if (uma == 0)
break;
}
+ cycles (2 + 3 * (int)(tx / 4) + 3 * (tx % 4));
break;
case RXO_shar: /* d = ma >> mb */
SHIFT_OP (sll, int, mb, >>=, 1);
+ E (1);
break;
case RXO_shll: /* d = ma << mb */
SHIFT_OP (ll, int, mb, <<=, 0x80000000UL);
+ E (1);
break;
case RXO_shlr: /* d = ma >> mb */
SHIFT_OP (ll, unsigned int, mb, >>=, 1);
+ E (1);
break;
case RXO_sstr:
- switch (opcode.size)
+ RL (3);
+#ifdef CYCLE_ACCURATE
+ tx = regs.r[3];
+#endif
+ switch (opcode->size)
{
case RX_Long:
while (regs.r[3] != 0)
regs.r[1] += 4;
regs.r[3] --;
}
+ cycles (2 + tx);
break;
case RX_Word:
while (regs.r[3] != 0)
regs.r[1] += 2;
regs.r[3] --;
}
+ cycles (2 + (int)(tx / 2) + tx % 2);
break;
case RX_Byte:
while (regs.r[3] != 0)
regs.r[1] ++;
regs.r[3] --;
}
+ cycles (2 + (int)(tx / 4) + tx % 4);
break;
default:
abort ();
case RXO_stcc:
if (GS2())
PD (GS ());
+ E1;
break;
case RXO_stop:
PRIVILEDGED ();
regs.r_psw |= FLAGBIT_I;
- return RX_MAKE_STOPPED(0);
+ DO_RETURN (RX_MAKE_STOPPED(0));
case RXO_sub:
MATH_OP (-, 0);
break;
case RXO_suntil:
+ RL(3);
+#ifdef CYCLE_ACCURATE
+ tx = 0;
+#endif
if (regs.r[3] == 0)
- break;
- switch (opcode.size)
+ {
+ cycles (3);
+ break;
+ }
+ switch (opcode->size)
{
case RX_Long:
uma = get_reg (2);
regs.r[3] --;
umb = mem_get_si (get_reg (1));
regs.r[1] += 4;
+#ifdef CYCLE_ACCURATE
+ tx ++;
+#endif
if (umb == uma)
break;
}
+#ifdef CYCLE_ACCURATE
+ cycles (3 + 3 * tx);
+#endif
break;
case RX_Word:
uma = get_reg (2) & 0xffff;
regs.r[3] --;
umb = mem_get_hi (get_reg (1));
regs.r[1] += 2;
+#ifdef CYCLE_ACCURATE
+ tx ++;
+#endif
if (umb == uma)
break;
}
+#ifdef CYCLE_ACCURATE
+ cycles (3 + 3 * (tx / 2) + 3 * (tx % 2));
+#endif
break;
case RX_Byte:
uma = get_reg (2) & 0xff;
regs.r[3] --;
umb = mem_get_qi (regs.r[1]);
regs.r[1] += 1;
+#ifdef CYCLE_ACCURATE
+ tx ++;
+#endif
if (umb == uma)
break;
}
+#ifdef CYCLE_ACCURATE
+ cycles (3 + 3 * (tx / 4) + 3 * (tx % 4));
+#endif
break;
default:
abort();
break;
case RXO_swhile:
+ RL(3);
+#ifdef CYCLE_ACCURATE
+ tx = 0;
+#endif
if (regs.r[3] == 0)
break;
- switch (opcode.size)
+ switch (opcode->size)
{
case RX_Long:
uma = get_reg (2);
regs.r[3] --;
umb = mem_get_si (get_reg (1));
regs.r[1] += 4;
+#ifdef CYCLE_ACCURATE
+ tx ++;
+#endif
if (umb != uma)
break;
}
+#ifdef CYCLE_ACCURATE
+ cycles (3 + 3 * tx);
+#endif
break;
case RX_Word:
uma = get_reg (2) & 0xffff;
regs.r[3] --;
umb = mem_get_hi (get_reg (1));
regs.r[1] += 2;
+#ifdef CYCLE_ACCURATE
+ tx ++;
+#endif
if (umb != uma)
break;
}
+#ifdef CYCLE_ACCURATE
+ cycles (3 + 3 * (tx / 2) + 3 * (tx % 2));
+#endif
break;
case RX_Byte:
uma = get_reg (2) & 0xff;
regs.r[3] --;
umb = mem_get_qi (regs.r[1]);
regs.r[1] += 1;
+#ifdef CYCLE_ACCURATE
+ tx ++;
+#endif
if (umb != uma)
break;
}
+#ifdef CYCLE_ACCURATE
+ cycles (3 + 3 * (tx / 4) + 3 * (tx % 4));
+#endif
break;
default:
abort();
case RXO_wait:
PRIVILEDGED ();
regs.r_psw |= FLAGBIT_I;
- return RX_MAKE_STOPPED(0);
+ DO_RETURN (RX_MAKE_STOPPED(0));
case RXO_xchg:
+#ifdef CYCLE_ACCURATE
+ regs.m2m = 0;
+#endif
v = GS (); /* This is the memory operand, if any. */
PS (GD ()); /* and this may change the address register. */
PD (v);
+ E2;
+#ifdef CYCLE_ACCURATE
+ /* all M cycles happen during xchg's cycles. */
+ memory_dest = 0;
+ memory_source = 0;
+#endif
break;
case RXO_xor:
EXCEPTION (EX_UNDEFINED);
}
+#ifdef CYCLE_ACCURATE
+ regs.m2m = 0;
+ if (memory_source)
+ regs.m2m |= M2M_SRC;
+ if (memory_dest)
+ regs.m2m |= M2M_DST;
+
+ regs.rt = new_rt;
+ new_rt = -1;
+#endif
+
+#ifdef CYCLE_STATS
+ if (prev_cycle_count == regs.cycle_count)
+ {
+ printf("Cycle count not updated! id %s\n", id_names[opcode->id]);
+ abort ();
+ }
+#endif
+
+#ifdef CYCLE_STATS
+ if (running_benchmark)
+ {
+ int omap = op_lookup (opcode->op[0].type, opcode->op[1].type, opcode->op[2].type);
+
+
+ cycles_per_id[opcode->id][omap] += regs.cycle_count - prev_cycle_count;
+ times_per_id[opcode->id][omap] ++;
+
+ times_per_pair[prev_opcode_id][po0][opcode->id][omap] ++;
+
+ prev_opcode_id = opcode->id;
+ po0 = omap;
+ }
+#endif
+
return RX_MAKE_STEPPED ();
}
+
+#ifdef CYCLE_STATS
+void
+reset_pipeline_stats (void)
+{
+ memset (cycles_per_id, 0, sizeof(cycles_per_id));
+ memset (times_per_id, 0, sizeof(times_per_id));
+ memory_stalls = 0;
+ register_stalls = 0;
+ branch_stalls = 0;
+ branch_alignment_stalls = 0;
+ fast_returns = 0;
+ memset (times_per_pair, 0, sizeof(times_per_pair));
+ running_benchmark = 1;
+
+ benchmark_start_cycle = regs.cycle_count;
+}
+
+void
+halt_pipeline_stats (void)
+{
+ running_benchmark = 0;
+ benchmark_end_cycle = regs.cycle_count;
+}
+#endif
+
+void
+pipeline_stats (void)
+{
+#ifdef CYCLE_STATS
+ int i, o1;
+ int p, p1;
+#endif
+
+#ifdef CYCLE_ACCURATE
+ if (verbose == 1)
+ {
+ printf ("cycles: %llu\n", regs.cycle_count);
+ return;
+ }
+
+ printf ("cycles: %13s\n", comma (regs.cycle_count));
+#endif
+
+#ifdef CYCLE_STATS
+ if (benchmark_start_cycle)
+ printf ("bmark: %13s\n", comma (benchmark_end_cycle - benchmark_start_cycle));
+
+ printf("\n");
+ for (i = 0; i < N_RXO; i++)
+ for (o1 = 0; o1 < N_MAP; o1 ++)
+ if (times_per_id[i][o1])
+ printf("%13s %13s %7.2f %s %s\n",
+ comma (cycles_per_id[i][o1]),
+ comma (times_per_id[i][o1]),
+ (double)cycles_per_id[i][o1] / times_per_id[i][o1],
+ op_cache_string(o1),
+ id_names[i]+4);
+
+ printf("\n");
+ for (p = 0; p < N_RXO; p ++)
+ for (p1 = 0; p1 < N_MAP; p1 ++)
+ for (i = 0; i < N_RXO; i ++)
+ for (o1 = 0; o1 < N_MAP; o1 ++)
+ if (times_per_pair[p][p1][i][o1])
+ {
+ printf("%13s %s %-9s -> %s %s\n",
+ comma (times_per_pair[p][p1][i][o1]),
+ op_cache_string(p1),
+ id_names[p]+4,
+ op_cache_string(o1),
+ id_names[i]+4);
+ }
+
+ printf("\n");
+ printf("%13s memory stalls\n", comma (memory_stalls));
+ printf("%13s register stalls\n", comma (register_stalls));
+ printf("%13s branches taken (non-return)\n", comma (branch_stalls));
+ printf("%13s branch alignment stalls\n", comma (branch_alignment_stalls));
+ printf("%13s fast returns\n", comma (fast_returns));
+#endif
+}