/* rx.c --- opcode semantics for stand-alone RX simulator.
-Copyright (C) 2008, 2009, 2010 Free Software Foundation, Inc.
+Copyright (C) 2008-2020 Free Software Foundation, Inc.
Contributed by Red Hat, Inc.
This file is part of the GNU simulators.
#include <stdlib.h>
#include <string.h>
#include <signal.h>
+#include "libiberty.h"
#include "opcode/rx.h"
#include "cpu.h"
"RXO_nop",
"RXO_nop2",
"RXO_nop3",
+ "RXO_nop4",
+ "RXO_nop5",
+ "RXO_nop6",
+ "RXO_nop7",
"RXO_scmpu",
"RXO_smovu",
};
static const char * optype_names[] = {
- " ",
+ " - ",
"#Imm", /* #addend */
" Rn ", /* Rn */
"[Rn]", /* [Rn + addend] */
"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
+#define N_RXO ARRAY_SIZE (id_names)
+#define N_RXT ARRAY_SIZE (optype_names)
+#define N_MAP 90
static unsigned long long benchmark_start_cycle;
static unsigned long long benchmark_end_cycle;
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 RL(r)
#define RLD(r)
+#define divu_cycles(n,d)
+#define div_cycles(n,d)
+
#endif /* else CYCLE_ACCURATE */
static int size2bytes[] = {
put_reg (o->reg, get_reg (o->reg) - size2bytes[o->size]);
/* fall through */
case RX_Operand_Postinc: /* [Rn+] */
+ case RX_Operand_Zero_Indirect: /* [Rn + 0] */
case RX_Operand_Indirect: /* [Rn + addend] */
case RX_Operand_TwoReg: /* [Rn + scale * R2] */
#ifdef CYCLE_ACCURATE
switch (o->size)
{
+ default:
case RX_AnySize:
rx_abort ();
to the size. */
switch (o->size)
{
+ default:
case RX_AnySize:
rx_abort ();
switch (o->size)
{
+ default:
case RX_AnySize:
if (o->type != RX_Operand_Register)
rx_abort ();
put_reg (o->reg, get_reg (o->reg) - size2bytes[o->size]);
/* fall through */
case RX_Operand_Postinc: /* [Rn+] */
+ case RX_Operand_Zero_Indirect: /* [Rn + 0] */
case RX_Operand_Indirect: /* [Rn + addend] */
case RX_Operand_TwoReg: /* [Rn + scale * R2] */
switch (o->size)
{
+ default:
case RX_AnySize:
rx_abort ();
c = val & carry_mask; \
val OP 1; \
} \
- if (count) \
- set_oszc (val, 4, c); \
+ set_oszc (val, 4, c); \
PD (val); \
}
break;
case RXO_branchrel:
- if (GS())
+ if (opcode->op[1].type == RX_Operand_None || GS())
{
int delta = GD();
- regs.r_pc += delta;
+ regs.r_pc = opcode_pc + delta;
#ifdef CYCLE_ACCURATE
/* Note: specs say 3, chip says 2. */
if (delta >= 0 && delta < 16
{
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);
}
- /* Note: spec says 3 to 22 cycles, we are pessimistic. */
- cycles (22);
break;
case RXO_divu: /* d = d / s */
{
tprintf("#NAN\n");
set_flags (FLAGBIT_O, FLAGBIT_O);
+ cycles (2);
}
else
{
tprintf("%u\n", v);
set_flags (FLAGBIT_O, 0);
PD (v);
+ divu_cycles (umb, uma);
}
- /* Note: spec says 2 to 20 cycles, we are pessimistic. */
- cycles (20);
break;
case RXO_emul:
v = GS ();
if (v == 255)
{
- DO_RETURN (rx_syscall (regs.r[5]));
+ int rc = rx_syscall (regs.r[5]);
+ if (! RX_STEPPED (rc))
+ DO_RETURN (rc);
}
else
{
case RXO_mov:
v = GS ();
+ 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 */)
{
case RXO_nop:
case RXO_nop2:
case RXO_nop3:
+ case RXO_nop4:
+ case RXO_nop5:
+ case RXO_nop6:
+ case RXO_nop7:
E1;
break;
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;
case RXO_suntil:
RL(3);
#ifdef CYCLE_ACCURATE
- tx = regs.r[3];
+ tx = 0;
#endif
if (regs.r[3] == 0)
{
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_swhile:
RL(3);
#ifdef CYCLE_ACCURATE
- tx = regs.r[3];
+ tx = 0;
#endif
if (regs.r[3] == 0)
break;
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();