diff options
Diffstat (limited to 'src/arch/arm/insts')
-rw-r--r-- | src/arch/arm/insts/branch.hh | 1 | ||||
-rw-r--r-- | src/arch/arm/insts/macromem.cc | 86 | ||||
-rw-r--r-- | src/arch/arm/insts/macromem.hh | 21 | ||||
-rw-r--r-- | src/arch/arm/insts/mem.hh | 8 |
4 files changed, 87 insertions, 29 deletions
diff --git a/src/arch/arm/insts/branch.hh b/src/arch/arm/insts/branch.hh index fbdd10d68..0e33a9214 100644 --- a/src/arch/arm/insts/branch.hh +++ b/src/arch/arm/insts/branch.hh @@ -57,6 +57,7 @@ class BranchImm : public PredOp int32_t _imm) : PredOp(mnem, _machInst, __opClass), imm(_imm) {} + }; // Conditionally Branch to a target computed with an immediate diff --git a/src/arch/arm/insts/macromem.cc b/src/arch/arm/insts/macromem.cc index 2a45cf2e6..8a82bd319 100644 --- a/src/arch/arm/insts/macromem.cc +++ b/src/arch/arm/insts/macromem.cc @@ -58,8 +58,13 @@ MacroMemOp::MacroMemOp(const char *mnem, ExtMachInst machInst, { uint32_t regs = reglist; uint32_t ones = number_of_ones(reglist); - // Remember that writeback adds a uop - numMicroops = ones + (writeback ? 1 : 0) + 1; + // Remember that writeback adds a uop or two and the temp register adds one + numMicroops = ones + (writeback ? (load ? 2 : 1) : 0) + 1; + + // It's technically legal to do a lot of nothing + if (!ones) + numMicroops = 1; + microOps = new StaticInstPtr[numMicroops]; uint32_t addr = 0; @@ -70,28 +75,13 @@ MacroMemOp::MacroMemOp(const char *mnem, ExtMachInst machInst, 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. *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; + unsigned regIdx = 0; bool force_user = user & !bits(reglist, 15); bool exception_ret = user & bits(reglist, 15); @@ -101,19 +91,28 @@ MacroMemOp::MacroMemOp(const char *mnem, ExtMachInst machInst, reg++; replaceBits(regs, reg, 0); - unsigned regIdx = reg; + regIdx = reg; if (force_user) { regIdx = intRegInMode(MODE_USER, regIdx); } if (load) { - if (reg == INTREG_PC && exception_ret) { - // This must be the exception return form of ldm. - *++uop = new MicroLdrRetUop(machInst, regIdx, - INTREG_UREG0, up, addr); + if (writeback && i == ones - 1) { + // If it's a writeback and this is the last register + // do the load into a temporary register which we'll move + // into the final one later + *++uop = new MicroLdrUop(machInst, INTREG_UREG1, INTREG_UREG0, + up, addr); } else { - *++uop = new MicroLdrUop(machInst, regIdx, - INTREG_UREG0, up, addr); + // Otherwise just do it normally + if (reg == INTREG_PC && exception_ret) { + // This must be the exception return form of ldm. + *++uop = new MicroLdrRetUop(machInst, regIdx, + INTREG_UREG0, up, addr); + } else { + *++uop = new MicroLdrUop(machInst, regIdx, + INTREG_UREG0, up, addr); + } } } else { *++uop = new MicroStrUop(machInst, regIdx, INTREG_UREG0, up, addr); @@ -125,8 +124,32 @@ MacroMemOp::MacroMemOp(const char *mnem, ExtMachInst machInst, addr -= 4; } - if (!load && writeback) { - *++uop = wbUop; + if (writeback && ones) { + // put the register update after we're done all loading + if (up) + *++uop = new MicroAddiUop(machInst, rn, rn, ones * 4); + else + *++uop = new MicroSubiUop(machInst, rn, rn, ones * 4); + + // If this was a load move the last temporary value into place + // this way we can't take an exception after we update the base + // register. + if (load && reg == INTREG_PC && exception_ret) { + *++uop = new MicroUopRegMovRet(machInst, 0, INTREG_UREG1); + warn("creating instruction with exception return at curTick:%d\n", + curTick()); + } else if (load) { + *++uop = new MicroUopRegMov(machInst, regIdx, INTREG_UREG1); + if (reg == INTREG_PC) { + (*uop)->setFlag(StaticInstBase::IsControl); + (*uop)->setFlag(StaticInstBase::IsCondControl); + (*uop)->setFlag(StaticInstBase::IsIndirectControl); + // This is created as a RAS POP + if (rn == INTREG_SP) + (*uop)->setFlag(StaticInstBase::IsReturn); + + } + } } (*uop)->setLastMicroop(); @@ -896,6 +919,15 @@ MicroIntImmOp::generateDisassembly(Addr pc, const SymbolTable *symtab) const } std::string +MicroSetPCCPSR::generateDisassembly(Addr pc, const SymbolTable *symtab) const +{ + std::stringstream ss; + printMnemonic(ss); + ss << "[PC,CPSR]"; + return ss.str(); +} + +std::string MicroIntMov::generateDisassembly(Addr pc, const SymbolTable *symtab) const { std::stringstream ss; diff --git a/src/arch/arm/insts/macromem.hh b/src/arch/arm/insts/macromem.hh index 1a2db8b9a..4933a1e7c 100644 --- a/src/arch/arm/insts/macromem.hh +++ b/src/arch/arm/insts/macromem.hh @@ -134,6 +134,27 @@ class MicroNeonMixLaneOp : public MicroNeonMixOp { } }; + +/** + * Microops of the form + * PC = IntRegA + * CPSR = IntRegB + */ +class MicroSetPCCPSR : public MicroOp +{ + protected: + IntRegIndex ura, urb, urc; + + MicroSetPCCPSR(const char *mnem, ExtMachInst machInst, OpClass __opClass, + IntRegIndex _ura, IntRegIndex _urb, IntRegIndex _urc) + : MicroOp(mnem, machInst, __opClass), + ura(_ura), urb(_urb), urc(_urc) + { + } + + std::string generateDisassembly(Addr pc, const SymbolTable *symtab) const; +}; + /** * Microops of the form IntRegA = IntRegB */ diff --git a/src/arch/arm/insts/mem.hh b/src/arch/arm/insts/mem.hh index a4fc62603..324d86fed 100644 --- a/src/arch/arm/insts/mem.hh +++ b/src/arch/arm/insts/mem.hh @@ -97,14 +97,18 @@ class RfeOp : public MightBeMicro IntRegIndex base; AddrMode mode; bool wb; - static const unsigned numMicroops = 2; + IntRegIndex ura, urb, urc; + static const unsigned numMicroops = 3; StaticInstPtr *uops; RfeOp(const char *mnem, ExtMachInst _machInst, OpClass __opClass, IntRegIndex _base, AddrMode _mode, bool _wb) : MightBeMicro(mnem, _machInst, __opClass), - base(_base), mode(_mode), wb(_wb), uops(NULL) + base(_base), mode(_mode), wb(_wb), + ura(INTREG_UREG0), urb(INTREG_UREG1), + urc(INTREG_UREG2), + uops(NULL) {} virtual |