changeset d96b61d843b2 in /z/repo/gem5
details: http://repo.gem5.org/gem5?cmd=changeset;node=d96b61d843b2
description:
arm: Make memory ops work on 64bit/128-bit quantities
Multiple instructions assume only 32-bit load operations are available,
this patch increases load sizes to 64-bit or 128-bit for many load pair
and
load multiple instructions.
diffstat:
src/arch/arm/insts/macromem.cc | 388 ++++++++++++++++++-------------
src/arch/arm/insts/macromem.hh | 22 +-
src/arch/arm/isa/insts/ldr64.isa | 90 +++---
src/arch/arm/isa/insts/macromem.isa | 24 +-
src/arch/arm/isa/insts/mem.isa | 4 +-
src/arch/arm/isa/templates/macromem.isa | 35 ++-
6 files changed, 355 insertions(+), 208 deletions(-)
diffs (truncated from 864 to 300 lines):
diff -r b5bef3c8e070 -r d96b61d843b2 src/arch/arm/insts/macromem.cc
--- a/src/arch/arm/insts/macromem.cc Fri Jun 27 12:29:00 2014 -0500
+++ b/src/arch/arm/insts/macromem.cc Wed Sep 03 07:42:52 2014 -0400
@@ -61,14 +61,29 @@
{
uint32_t regs = reglist;
uint32_t ones = number_of_ones(reglist);
- // Remember that writeback adds a uop or two and the temp register adds one
- numMicroops = ones + (writeback ? (load ? 2 : 1) : 0) + 1;
+ uint32_t mem_ops = ones;
- // It's technically legal to do a lot of nothing
- if (!ones)
+ // Copy the base address register if we overwrite it, or if this
instruction
+ // is basically a no-op (we have to do something)
+ bool copy_base = (bits(reglist, rn) && load) || !ones;
+ bool force_user = user & !bits(reglist, 15);
+ bool exception_ret = user & bits(reglist, 15);
+ bool pc_temp = load && writeback && bits(reglist, 15);
+
+ if (!ones) {
numMicroops = 1;
+ } else if (load) {
+ numMicroops = ((ones + 1) / 2)
+ + ((ones % 2 == 0 && exception_ret) ? 1 : 0)
+ + (copy_base ? 1 : 0)
+ + (writeback? 1 : 0)
+ + (pc_temp ? 1 : 0);
+ } else {
+ numMicroops = ones + (writeback ? 1 : 0);
+ }
microOps = new StaticInstPtr[numMicroops];
+
uint32_t addr = 0;
if (!up)
@@ -81,94 +96,129 @@
// Add 0 to Rn and stick it in ureg0.
// This is equivalent to a move.
- *uop = new MicroAddiUop(machInst, INTREG_UREG0, rn, 0);
+ if (copy_base)
+ *uop++ = new MicroAddiUop(machInst, INTREG_UREG0, rn, 0);
unsigned reg = 0;
- unsigned regIdx = 0;
- bool force_user = user & !bits(reglist, 15);
- bool exception_ret = user & bits(reglist, 15);
+ while (mem_ops != 0) {
+ // Do load operations in pairs if possible
+ if (load && mem_ops >= 2 &&
+ !(mem_ops == 2 && bits(regs,INTREG_PC) && exception_ret)) {
+ // 64-bit memory operation
+ // Find 2 set register bits (clear them after finding)
+ unsigned reg_idx1;
+ unsigned reg_idx2;
- for (int i = 0; i < ones; i++) {
- // Find the next register.
- while (!bits(regs, reg))
- reg++;
- replaceBits(regs, reg, 0);
+ // Find the first register
+ while (!bits(regs, reg)) reg++;
+ replaceBits(regs, reg, 0);
+ reg_idx1 = force_user ? intRegInMode(MODE_USER, reg) : reg;
- regIdx = reg;
- if (force_user) {
- regIdx = intRegInMode(MODE_USER, regIdx);
- }
+ // Find the second register
+ while (!bits(regs, reg)) reg++;
+ replaceBits(regs, reg, 0);
+ reg_idx2 = force_user ? intRegInMode(MODE_USER, reg) : reg;
- if (load) {
- 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 {
- // 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);
+ // Load into temp reg if necessary
+ if (reg_idx2 == INTREG_PC && pc_temp)
+ reg_idx2 = INTREG_UREG1;
+
+ // Actually load both registers from memory
+ *uop = new MicroLdr2Uop(machInst, reg_idx1, reg_idx2,
+ copy_base ? INTREG_UREG0 : rn, up, addr);
+
+ if (!writeback && reg_idx2 == INTREG_PC) {
+ // No writeback if idx==pc, set appropriate flags
+ (*uop)->setFlag(StaticInst::IsControl);
+ (*uop)->setFlag(StaticInst::IsIndirectControl);
+
+ if (!(condCode == COND_AL || condCode == COND_UC))
+ (*uop)->setFlag(StaticInst::IsCondControl);
+ else
+ (*uop)->setFlag(StaticInst::IsUncondControl);
+ }
+
+ if (up) addr += 8;
+ else addr -= 8;
+ mem_ops -= 2;
+ } else {
+ // 32-bit memory operation
+ // Find register for operation
+ unsigned reg_idx;
+ while(!bits(regs, reg)) reg++;
+ replaceBits(regs, reg, 0);
+ reg_idx = force_user ? intRegInMode(MODE_USER, reg) : reg;
+
+ if (load) {
+ if (writeback && reg_idx == INTREG_PC) {
+ // If this instruction changes the PC and performs a
+ // writeback, ensure the pc load/branch is the last uop.
+ // Load into a temp reg here.
+ *uop = new MicroLdrUop(machInst, INTREG_UREG1,
+ copy_base ? INTREG_UREG0 : rn, up, addr);
+ } else if (reg_idx == INTREG_PC && exception_ret) {
+ // Special handling for exception return
+ *uop = new MicroLdrRetUop(machInst, reg_idx,
+ copy_base ? INTREG_UREG0 : rn, up, addr);
+ } else {
+ // standard single load uop
+ *uop = new MicroLdrUop(machInst, reg_idx,
+ copy_base ? INTREG_UREG0 : rn, up, addr);
+ }
+
+ // Loading pc as last operation? Set appropriate flags.
+ if (!writeback && reg_idx == INTREG_PC) {
+ (*uop)->setFlag(StaticInst::IsControl);
+ (*uop)->setFlag(StaticInst::IsIndirectControl);
+
if (!(condCode == COND_AL || condCode == COND_UC))
(*uop)->setFlag(StaticInst::IsCondControl);
else
(*uop)->setFlag(StaticInst::IsUncondControl);
- } else {
- *++uop = new MicroLdrUop(machInst, regIdx,
- INTREG_UREG0, up, addr);
- if (reg == INTREG_PC) {
- (*uop)->setFlag(StaticInst::IsControl);
- if (!(condCode == COND_AL || condCode == COND_UC))
- (*uop)->setFlag(StaticInst::IsCondControl);
- else
- (*uop)->setFlag(StaticInst::IsUncondControl);
- (*uop)->setFlag(StaticInst::IsIndirectControl);
- }
}
+ } else {
+ *uop = new MicroStrUop(machInst, reg_idx, rn, up, addr);
}
- } else {
- *++uop = new MicroStrUop(machInst, regIdx, INTREG_UREG0, up, addr);
+
+ if (up) addr += 4;
+ else addr -= 4;
+ --mem_ops;
}
- if (up)
- addr += 4;
- else
- addr -= 4;
+ // Load/store micro-op generated, go to next uop
+ ++uop;
}
if (writeback && ones) {
- // put the register update after we're done all loading
+ // Perform writeback uop operation
if (up)
- *++uop = new MicroAddiUop(machInst, rn, rn, ones * 4);
+ *uop++ = new MicroAddiUop(machInst, rn, rn, ones * 4);
else
- *++uop = new MicroSubiUop(machInst, rn, rn, ones * 4);
+ *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);
+ // Write PC after address writeback?
+ if (pc_temp) {
+ if (exception_ret) {
+ *uop = new MicroUopRegMovRet(machInst, 0, INTREG_UREG1);
+ } else {
+ *uop = new MicroUopRegMov(machInst, INTREG_PC, INTREG_UREG1);
+ }
+ (*uop)->setFlag(StaticInst::IsControl);
+ (*uop)->setFlag(StaticInst::IsIndirectControl);
+
if (!(condCode == COND_AL || condCode == COND_UC))
(*uop)->setFlag(StaticInst::IsCondControl);
else
(*uop)->setFlag(StaticInst::IsUncondControl);
- } else if (load) {
- *++uop = new MicroUopRegMov(machInst, regIdx, INTREG_UREG1);
- if (reg == INTREG_PC) {
- (*uop)->setFlag(StaticInst::IsControl);
- (*uop)->setFlag(StaticInst::IsCondControl);
- (*uop)->setFlag(StaticInst::IsIndirectControl);
- // This is created as a RAS POP
- if (rn == INTREG_SP)
- (*uop)->setFlag(StaticInst::IsReturn);
- }
+ if (rn == INTREG_SP)
+ (*uop)->setFlag(StaticInst::IsReturn);
+
+ ++uop;
}
}
+ --uop;
(*uop)->setLastMicroop();
/* Take the control flags from the last microop for the macroop */
@@ -176,16 +226,15 @@
setFlag(StaticInst::IsControl);
if ((*uop)->isCondCtrl())
setFlag(StaticInst::IsCondControl);
+ if ((*uop)->isUncondCtrl())
+ setFlag(StaticInst::IsUncondControl);
if ((*uop)->isIndirectCtrl())
setFlag(StaticInst::IsIndirectControl);
if ((*uop)->isReturn())
setFlag(StaticInst::IsReturn);
- for (StaticInstPtr *curUop = microOps;
- !(*curUop)->isLastMicroop(); curUop++) {
- MicroOp * uopPtr = dynamic_cast<MicroOp *>(curUop->get());
- assert(uopPtr);
- uopPtr->setDelayedCommit();
+ for (StaticInstPtr *uop = microOps; !(*uop)->isLastMicroop(); uop++) {
+ (*uop)->setDelayedCommit();
}
}
@@ -196,95 +245,96 @@
IntRegIndex rn, IntRegIndex rt, IntRegIndex rt2) :
PredMacroOp(mnem, machInst, __opClass)
{
+ bool post = (mode == AddrMd_PostIndex);
bool writeback = (mode != AddrMd_Offset);
- numMicroops = 1 + (size / 4) + (writeback ? 1 : 0);
+
+ if (load) {
+ // Use integer rounding to round up loads of size 4
+ numMicroops = (post ? 0 : 1) + ((size + 4) / 8) + (writeback ? 1 : 0);
+ } else {
+ numMicroops = (post ? 0 : 1) + (size / 4) + (writeback ? 1 : 0);
+ }
microOps = new StaticInstPtr[numMicroops];
StaticInstPtr *uop = microOps;
- bool post = (mode == AddrMd_PostIndex);
-
rn = makeSP(rn);
- *uop = new MicroAddXiSpAlignUop(machInst, INTREG_UREG0, rn, post ? 0 :
imm);
+ if (!post) {
+ *uop++ = new MicroAddXiSpAlignUop(machInst, INTREG_UREG0, rn,
+ post ? 0 : imm);
+ }
if (fp) {
if (size == 16) {
if (load) {
- *++uop = new MicroLdrQBFpXImmUop(machInst, rt,
- INTREG_UREG0, 0, noAlloc, exclusive, acrel);
- *++uop = new MicroLdrQTFpXImmUop(machInst, rt,
- INTREG_UREG0, 0, noAlloc, exclusive, acrel);
- *++uop = new MicroLdrQBFpXImmUop(machInst, rt2,
- INTREG_UREG0, 16, noAlloc, exclusive, acrel);
- *++uop = new MicroLdrQTFpXImmUop(machInst, rt2,
- INTREG_UREG0, 16, noAlloc, exclusive, acrel);
+ *uop++ = new MicroLdFp16Uop(machInst, rt,
+ post ? rn : INTREG_UREG0, 0, noAlloc, exclusive,
acrel);
+ *uop++ = new MicroLdFp16Uop(machInst, rt2,
+ post ? rn : INTREG_UREG0, 16, noAlloc, exclusive,
acrel);
} else {
- *++uop = new MicroStrQBFpXImmUop(machInst, rt,
- INTREG_UREG0, 0, noAlloc, exclusive, acrel);
- *++uop = new MicroStrQTFpXImmUop(machInst, rt,
- INTREG_UREG0, 0, noAlloc, exclusive, acrel);
- *++uop = new MicroStrQBFpXImmUop(machInst, rt2,
- INTREG_UREG0, 16, noAlloc, exclusive, acrel);
- *++uop = new MicroStrQTFpXImmUop(machInst, rt2,
_______________________________________________
gem5-dev mailing list
[email protected]
http://m5sim.org/mailman/listinfo/gem5-dev