aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--sim/rx/ChangeLog8
-rw-r--r--sim/rx/rx.c93
2 files changed, 94 insertions, 7 deletions
diff --git a/sim/rx/ChangeLog b/sim/rx/ChangeLog
index 8728ebf..16678f8 100644
--- a/sim/rx/ChangeLog
+++ b/sim/rx/ChangeLog
@@ -1,3 +1,11 @@
+2010-11-11 DJ Delorie <dj@redhat.com>
+
+ * rx.c (lsb_count): New.
+ (divu_cycles): New.
+ (div_cycles): New.
+ (decode_opcode): Fix cycle count math for div, divu, suntil, and
+ swhile.
+
2010-09-29 Kevin Buettner <kevinb@redhat.com>
* mem.c (rx_mem_ptr): When invalidating the decode cache, account
diff --git a/sim/rx/rx.c b/sim/rx/rx.c
index 247d624..881dc66 100644
--- a/sim/rx/rx.c
+++ b/sim/rx/rx.c
@@ -136,7 +136,7 @@ static const char * id_names[] = {
};
static const char * optype_names[] = {
- " ",
+ " - ",
"#Imm", /* #addend */
" Rn ", /* Rn */
"[Rn]", /* [Rn + addend] */
@@ -264,6 +264,52 @@ cycles (int throughput)
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)
@@ -274,6 +320,9 @@ cycles (int throughput)
#define RL(r)
#define RLD(r)
+#define divu_cycles(n,d)
+#define div_cycles(n,d)
+
#endif /* else CYCLE_ACCURATE */
static int size2bytes[] = {
@@ -1126,6 +1175,7 @@ decode_opcode ()
{
tprintf("#NAN\n");
set_flags (FLAGBIT_O, FLAGBIT_O);
+ cycles (3);
}
else
{
@@ -1133,9 +1183,8 @@ decode_opcode ()
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 */
@@ -1146,6 +1195,7 @@ decode_opcode ()
{
tprintf("#NAN\n");
set_flags (FLAGBIT_O, FLAGBIT_O);
+ cycles (2);
}
else
{
@@ -1153,9 +1203,8 @@ decode_opcode ()
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:
@@ -1906,7 +1955,7 @@ decode_opcode ()
case RXO_suntil:
RL(3);
#ifdef CYCLE_ACCURATE
- tx = regs.r[3];
+ tx = 0;
#endif
if (regs.r[3] == 0)
{
@@ -1922,10 +1971,15 @@ decode_opcode ()
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;
@@ -1934,10 +1988,15 @@ decode_opcode ()
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;
@@ -1946,10 +2005,15 @@ decode_opcode ()
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();
@@ -1963,7 +2027,7 @@ decode_opcode ()
case RXO_swhile:
RL(3);
#ifdef CYCLE_ACCURATE
- tx = regs.r[3];
+ tx = 0;
#endif
if (regs.r[3] == 0)
break;
@@ -1976,10 +2040,15 @@ decode_opcode ()
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;
@@ -1988,10 +2057,15 @@ decode_opcode ()
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;
@@ -2000,10 +2074,15 @@ decode_opcode ()
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();