summaryrefslogtreecommitdiff
path: root/src/arch/arm
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
commitb6e2f5d33f5afc61face993f60667afbfd0d8ac7 (patch)
treee162d20a8f1786eb3e94fc2fc7c166c4c9a757e1 /src/arch/arm
parent89060f1fd80b032c92cf4f38c8459901c4f7a898 (diff)
downloadgem5-b6e2f5d33f5afc61face993f60667afbfd0d8ac7.tar.xz
ARM: Make sure ldm exception return writes back its base in the right mode.
This change moves the writeback of load multiple instructions to the beginning of the macroop. That way, the MicroLdrRetUop that changes the mode will necessarily happen later, ensuring the writeback happens in the original mode. The actual value in the base register if it also shows up in the register list is undefined, so it's fine if it gets clobbered by one of the loads. For stores where the base register is the lowest numbered in the register list, the original value should be written back. That means stores can't write back at the beginning, but the mode changing problem doesn't affect them so they can continue to write back at the end.
Diffstat (limited to 'src/arch/arm')
-rw-r--r--src/arch/arm/insts/macromem.cc46
1 files changed, 29 insertions, 17 deletions
diff --git a/src/arch/arm/insts/macromem.cc b/src/arch/arm/insts/macromem.cc
index 35ec686fe..5c4c2522d 100644
--- a/src/arch/arm/insts/macromem.cc
+++ b/src/arch/arm/insts/macromem.cc
@@ -67,15 +67,33 @@ MacroMemOp::MacroMemOp(const char *mnem, ExtMachInst machInst,
if (!index)
addr += 4;
+ StaticInstPtr *uop = microOps;
+ StaticInstPtr wbUop;
+ if (writeback) {
+ if (up) {
+ wbUop = new MicroAddiUop(machInst, rn, rn, ones * 4);
+ } else {
+ wbUop = new MicroSubiUop(machInst, rn, rn, ones * 4);
+ }
+ }
+
// Add 0 to Rn and stick it in ureg0.
// This is equivalent to a move.
- microOps[0] = new MicroAddiUop(machInst, INTREG_UREG0, rn, 0);
+ *uop = new MicroAddiUop(machInst, INTREG_UREG0, rn, 0);
+
+ // Write back at the start for loads. This covers the ldm exception return
+ // case where the base needs to be written in the old mode. Stores may need
+ // the original value of the base, but they don't change mode and can
+ // write back at the end like before.
+ if (load && writeback) {
+ *++uop = wbUop;
+ }
unsigned reg = 0;
bool force_user = user & !bits(reglist, 15);
bool exception_ret = user & bits(reglist, 15);
- for (int i = 1; i < ones + 1; i++) {
+ for (int i = 0; i < ones; i++) {
// Find the next register.
while (!bits(regs, reg))
reg++;
@@ -89,16 +107,14 @@ MacroMemOp::MacroMemOp(const char *mnem, ExtMachInst machInst,
if (load) {
if (reg == INTREG_PC && exception_ret) {
// This must be the exception return form of ldm.
- microOps[i] =
- new MicroLdrRetUop(machInst, regIdx,
- INTREG_UREG0, up, addr);
+ *++uop = new MicroLdrRetUop(machInst, regIdx,
+ INTREG_UREG0, up, addr);
} else {
- microOps[i] =
- new MicroLdrUop(machInst, regIdx, INTREG_UREG0, up, addr);
+ *++uop = new MicroLdrUop(machInst, regIdx,
+ INTREG_UREG0, up, addr);
}
} else {
- microOps[i] =
- new MicroStrUop(machInst, regIdx, INTREG_UREG0, up, addr);
+ *++uop = new MicroStrUop(machInst, regIdx, INTREG_UREG0, up, addr);
}
if (up)
@@ -107,15 +123,11 @@ MacroMemOp::MacroMemOp(const char *mnem, ExtMachInst machInst,
addr -= 4;
}
- StaticInstPtr &lastUop = microOps[numMicroops - 1];
- if (writeback) {
- if (up) {
- lastUop = new MicroAddiUop(machInst, rn, rn, ones * 4);
- } else {
- lastUop = new MicroSubiUop(machInst, rn, rn, ones * 4);
- }
+ if (!load && writeback) {
+ *++uop = wbUop;
}
- lastUop->setLastMicroop();
+
+ (*uop)->setLastMicroop();
}
MacroVFPMemOp::MacroVFPMemOp(const char *mnem, ExtMachInst machInst,