summaryrefslogtreecommitdiff
path: root/sim
diff options
context:
space:
mode:
authorMike Frysinger <vapier@gentoo.org>2012-04-09 05:52:38 +0000
committerMike Frysinger <vapier@gentoo.org>2012-04-09 05:52:38 +0000
commitaaedd91cbe43e5d8ef89f7d68312eccd9d9ca0ff (patch)
tree396af3a04407d9a68191ac984764b7cca4d12274 /sim
parent8ab28f25aa3521c6941d3b4be0258d64807ba174 (diff)
downloadgdb-aaedd91cbe43e5d8ef89f7d68312eccd9d9ca0ff.tar.gz
sim: bfin: fix ASTAT/correctness issues with arithmetic shifts
This improves some of the arithmetic shifts to better match the hardware (especially wrt ASTAT behavior). We hit areas where the published documentation is thin so we have to rely on tests run on the hardware to figure out how things should behave. Signed-off-by: Robin Getz <robin.getz@analog.com> Signed-off-by: Mike Frysinger <vapier@gentoo.org>
Diffstat (limited to 'sim')
-rw-r--r--sim/bfin/ChangeLog7
-rw-r--r--sim/bfin/bfin-sim.c70
2 files changed, 67 insertions, 10 deletions
diff --git a/sim/bfin/ChangeLog b/sim/bfin/ChangeLog
index cf6beb1b9df..14cb28d26d0 100644
--- a/sim/bfin/ChangeLog
+++ b/sim/bfin/ChangeLog
@@ -1,3 +1,10 @@
+2012-04-09 Robin Getz <robin.getz@analog.com>
+
+ * bfin-sim.c (sgn_extend): New helper.
+ (decode_dsp32shiftimm_0): Call lshift when newimmag is more
+ than 16, otherwise call ashiftrt. Set ASTAT fields as needed.
+ For accumulator shifts, call new sgn_extend helper.
+
2012-04-08 Mike Frysinger <vapier@gentoo.org>
* bfin-sim.c (illegal_instruction_or_combination): New helper.
diff --git a/sim/bfin/bfin-sim.c b/sim/bfin/bfin-sim.c
index 03b9d7a12ce..e3201ef2b66 100644
--- a/sim/bfin/bfin-sim.c
+++ b/sim/bfin/bfin-sim.c
@@ -5716,6 +5716,26 @@ decode_dsp32shift_0 (SIM_CPU *cpu, bu16 iw0, bu16 iw1)
illegal_instruction (cpu);
}
+static bu64
+sgn_extend (bu40 org, bu40 val, int size)
+{
+ bu64 ret = val;
+
+ if (org & (1ULL << (size - 1)))
+ {
+ /* We need to shift in to the MSB which is set. */
+ int n;
+
+ for (n = 40; n >= 0; n--)
+ if (ret & (1ULL << n))
+ break;
+ ret |= (-1ULL << n);
+ }
+ else
+ ret &= ~(-1ULL << 39);
+
+ return ret;
+}
static void
decode_dsp32shiftimm_0 (SIM_CPU *cpu, bu16 iw0, bu16 iw1)
{
@@ -5765,8 +5785,37 @@ decode_dsp32shiftimm_0 (SIM_CPU *cpu, bu16 iw0, bu16 iw1)
{
TRACE_INSN (cpu, "R%i.%c = R%i.%c >>> %i (S);",
dst0, (HLs & 2) ? 'H' : 'L',
- src1, (HLs & 1) ? 'H' : 'L', immag);
- result = lshift (cpu, in, immag, 16, 1, 1);
+ src1, (HLs & 1) ? 'H' : 'L', newimmag);
+ if (newimmag > 16)
+ {
+ int shift = 32 - newimmag;
+ bu16 inshift = in << shift;
+
+ if (((inshift & ~0xFFFF)
+ && ((inshift & ~0xFFFF) >> 16) != ~(~0 << shift))
+ || (inshift & 0x8000) != (in & 0x8000))
+ {
+ if (in & 0x8000)
+ result = 0x8000;
+ else
+ result = 0x7fff;
+ SET_ASTATREG (v, 1);
+ SET_ASTATREG (vs, 1);
+ }
+ else
+ {
+ result = inshift;
+ SET_ASTATREG (v, 0);
+ }
+
+ SET_ASTATREG (az, !result);
+ SET_ASTATREG (an, !!(result & 0x8000));
+ }
+ else
+ {
+ result = ashiftrt (cpu, in, newimmag, 16);
+ result = sgn_extend (in, result, 16);
+ }
}
else if (sop == 2 && bit8)
{
@@ -5808,22 +5857,23 @@ decode_dsp32shiftimm_0 (SIM_CPU *cpu, bu16 iw0, bu16 iw1)
else if (sop == 0 && sopcde == 3 && bit8 == 1)
{
/* Arithmetic shift, so shift in sign bit copies. */
- bu64 acc;
+ bu64 acc, val;
int shift = uimm5 (newimmag);
HLs = !!HLs;
TRACE_INSN (cpu, "A%i = A%i >>> %i;", HLs, HLs, shift);
acc = get_extended_acc (cpu, HLs);
- acc >>= shift;
+ val = acc >> shift;
+
/* Sign extend again. */
- if (acc & (1ULL << 39))
- acc |= -(1ULL << 39);
- else
- acc &= ~(-(1ULL << 39));
+ val = sgn_extend (acc, val, 40);
- STORE (AXREG (HLs), (acc >> 32) & 0xFF);
- STORE (AWREG (HLs), acc & 0xFFFFFFFF);
+ STORE (AXREG (HLs), (val >> 32) & 0xFF);
+ STORE (AWREG (HLs), val & 0xFFFFFFFF);
+ STORE (ASTATREG (an), !!(val & (1ULL << 39)));
+ STORE (ASTATREG (az), !val);
+ STORE (ASTATREG (av[HLs]), 0);
}
else if ((sop == 0 && sopcde == 3 && bit8 == 0)
|| (sop == 1 && sopcde == 3))