summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGabe Black <gblack@eecs.umich.edu>2010-06-02 12:58:04 -0500
committerGabe Black <gblack@eecs.umich.edu>2010-06-02 12:58:04 -0500
commit739f23c64c88c2c5d57085eae7687e16cb0a90f6 (patch)
tree84b67b86e49946fc739505e67b1c07ecfeeaa63f
parentcb631d87c3cb676e9d25c3ffbcd76580a3393b05 (diff)
downloadgem5-739f23c64c88c2c5d57085eae7687e16cb0a90f6.tar.xz
ARM: Add base classes for VFP load/store multiple.
-rw-r--r--src/arch/arm/insts/macromem.cc60
-rw-r--r--src/arch/arm/insts/macromem.hh8
2 files changed, 68 insertions, 0 deletions
diff --git a/src/arch/arm/insts/macromem.cc b/src/arch/arm/insts/macromem.cc
index bb69f0991..35ec686fe 100644
--- a/src/arch/arm/insts/macromem.cc
+++ b/src/arch/arm/insts/macromem.cc
@@ -118,4 +118,64 @@ MacroMemOp::MacroMemOp(const char *mnem, ExtMachInst machInst,
lastUop->setLastMicroop();
}
+MacroVFPMemOp::MacroVFPMemOp(const char *mnem, ExtMachInst machInst,
+ OpClass __opClass, IntRegIndex rn,
+ RegIndex vd, bool single, bool up,
+ 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
+ // to be functionally identical except that fldmx is deprecated. For now
+ // we'll assume they're otherwise interchangable.
+ int count = (single ? offset : (offset / 2));
+ if (count == 0 || count > NumFloatArchRegs)
+ warn_once("Bad offset field for VFP load/store multiple.\n");
+ if (count == 0) {
+ // Force there to be at least one microop so the macroop makes sense.
+ writeback = true;
+ }
+ if (count > NumFloatArchRegs)
+ count = NumFloatArchRegs;
+
+ uint32_t addr = 0;
+
+ if (up)
+ addr = -4 * offset;
+
+ for (int j = 0; j < count; j++) {
+ if (load) {
+ microOps[i++] = new MicroLdrFpUop(machInst, vd++, rn,
+ true, addr);
+ if (!single)
+ microOps[i++] = new MicroLdrFpUop(machInst, vd++, rn,
+ true, addr + 4);
+ } else {
+ microOps[i++] = new MicroStrFpUop(machInst, vd++, rn,
+ true, addr);
+ if (!single)
+ microOps[i++] = new MicroStrFpUop(machInst, vd++, rn,
+ true, addr + 4);
+ }
+ addr += (single ? 4 : 8);
+ }
+
+ if (writeback) {
+ if (up) {
+ microOps[i++] =
+ new MicroAddiUop(machInst, rn, rn, 4 * offset);
+ } else {
+ microOps[i++] =
+ new MicroSubiUop(machInst, rn, rn, 4 * offset);
+ }
+ }
+
+ numMicroops = i;
+ assert(numMicroops <= maxMicroops);
+ microOps[numMicroops - 1]->setLastMicroop();
+}
+
}
diff --git a/src/arch/arm/insts/macromem.hh b/src/arch/arm/insts/macromem.hh
index 8cad32710..21a37a29e 100644
--- a/src/arch/arm/insts/macromem.hh
+++ b/src/arch/arm/insts/macromem.hh
@@ -101,6 +101,14 @@ class MacroMemOp : public PredMacroOp
bool writeback, bool load, uint32_t reglist);
};
+class MacroVFPMemOp : public PredMacroOp
+{
+ protected:
+ MacroVFPMemOp(const char *mnem, ExtMachInst machInst, OpClass __opClass,
+ IntRegIndex rn, RegIndex vd, bool single, bool up,
+ bool writeback, bool load, uint32_t offset);
+};
+
}
#endif //__ARCH_ARM_INSTS_MACROMEM_HH__