ARM: Fix the implementation of the VFP ldm and stm macroops.

There were four bugs in these instructions. First, the loaded value was being
stored into a floating point register as floating point, changing the value as
it was transfered. Second, the meaning of the "up" bit had been reversed.
Third, the statically sized microop array wasn't bit enough for all possible
inputs. It's now dynamically sized and should always be big enough. Fourth,
the offset was stored as an unsigned 8 bit value. Negative offsets would look
like moderately large positive offsets.
This commit is contained in:
Gabe Black 2010-06-02 12:58:12 -05:00
parent d149e43c41
commit 67766cbf17
2 changed files with 22 additions and 12 deletions

View file

@ -136,8 +136,6 @@ MacroVFPMemOp::MacroVFPMemOp(const char *mnem, ExtMachInst machInst,
bool writeback, bool load, uint32_t offset) :
PredMacroOp(mnem, machInst, __opClass)
{
const int maxMicroops = 17;
microOps = new StaticInstPtr[maxMicroops];
int i = 0;
// The lowest order bit selects fldmx (set) or fldmd (clear). These seem
@ -153,26 +151,39 @@ MacroVFPMemOp::MacroVFPMemOp(const char *mnem, ExtMachInst machInst,
if (count > NumFloatArchRegs)
count = NumFloatArchRegs;
numMicroops = count * (single ? 1 : 2) + (writeback ? 1 : 0);
microOps = new StaticInstPtr[numMicroops];
uint32_t addr = 0;
if (up)
addr = -4 * offset;
if (!up)
addr = 4 * offset;
bool tempUp = up;
for (int j = 0; j < count; j++) {
if (load) {
microOps[i++] = new MicroLdrFpUop(machInst, vd++, rn,
true, addr);
tempUp, addr);
if (!single)
microOps[i++] = new MicroLdrFpUop(machInst, vd++, rn,
true, addr + 4);
tempUp, addr + 4);
} else {
microOps[i++] = new MicroStrFpUop(machInst, vd++, rn,
true, addr);
tempUp, addr);
if (!single)
microOps[i++] = new MicroStrFpUop(machInst, vd++, rn,
true, addr + 4);
tempUp, addr + 4);
}
if (!tempUp) {
addr -= (single ? 4 : 8);
// The microops don't handle negative displacement, so turn if we
// hit zero, flip polarity and start adding.
if (addr == 0) {
tempUp = true;
}
} else {
addr += (single ? 4 : 8);
}
addr += (single ? 4 : 8);
}
if (writeback) {
@ -185,8 +196,7 @@ MacroVFPMemOp::MacroVFPMemOp(const char *mnem, ExtMachInst machInst,
}
}
numMicroops = i;
assert(numMicroops <= maxMicroops);
assert(numMicroops == i);
microOps[numMicroops - 1]->setLastMicroop();
}

View file

@ -59,7 +59,7 @@ let {{
'predicate_test': predicateTest},
['IsMicroop'])
microLdrFpUopCode = "Fa = cSwap(Mem.uw, ((CPSR)Cpsr).e);"
microLdrFpUopCode = "Fa.uw = cSwap(Mem.uw, ((CPSR)Cpsr).e);"
microLdrFpUopIop = InstObjParams('ldrfp_uop', 'MicroLdrFpUop',
'MicroMemOp',
{'memacc_code': microLdrFpUopCode,