* rx.c (lsb_count): New.

(divu_cycles): New.
(div_cycles): New.
(decode_opcode): Fix cycle count math for div, divu, suntil, and
swhile.
This commit is contained in:
DJ Delorie 2010-11-12 01:01:12 +00:00
parent e493c3b7f3
commit 5cbc4f2ea1
2 changed files with 94 additions and 7 deletions

View File

@ -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

View File

@ -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();