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

Reply via email to