includes: sort all includes
[gem5.git] / src / cpu / o3 / lsq_unit_impl.hh
index 9ee1de45ae6317f5fa4c731ac9b3300b323558af..6a366d056ac0f0f4b16a92cb82a707ea3b594014 100644 (file)
@@ -1,4 +1,16 @@
 /*
+ * Copyright (c) 2010 ARM Limited
+ * All rights reserved
+ *
+ * The license below extends only to copyright in the software and shall
+ * not be construed as granting a license to any other intellectual
+ * property including but not limited to intellectual property relating
+ * to a hardware implementation of the functionality of the software
+ * licensed hereunder.  You may use the software subject to the license
+ * terms below provided that you ensure that this notice is replicated
+ * unmodified and in its entirety in all distributions of the software,
+ * modified or unmodified, in source code or in binary form.
+ *
  * Copyright (c) 2004-2005 The Regents of The University of Michigan
  * All rights reserved.
  *
  */
 
 #include "arch/locked_mem.hh"
+#include "base/str.hh"
 #include "config/the_isa.hh"
 #include "config/use_checker.hh"
 #include "cpu/o3/lsq.hh"
 #include "cpu/o3/lsq_unit.hh"
-#include "base/str.hh"
 #include "mem/packet.hh"
 #include "mem/request.hh"
 
@@ -78,18 +90,30 @@ LSQUnit<Impl>::completeDataAccess(PacketPtr pkt)
 {
     LSQSenderState *state = dynamic_cast<LSQSenderState *>(pkt->senderState);
     DynInstPtr inst = state->inst;
-    DPRINTF(IEW, "Writeback event [sn:%lli]\n", inst->seqNum);
-    DPRINTF(Activity, "Activity: Writeback event [sn:%lli]\n", inst->seqNum);
+    DPRINTF(IEW, "Writeback event [sn:%lli].\n", inst->seqNum);
+    DPRINTF(Activity, "Activity: Writeback event [sn:%lli].\n", inst->seqNum);
 
     //iewStage->ldstQueue.removeMSHR(inst->threadNumber,inst->seqNum);
 
     assert(!pkt->wasNacked());
 
+    // If this is a split access, wait until all packets are received.
+    if (TheISA::HasUnalignedMemAcc && !state->complete()) {
+        delete pkt->req;
+        delete pkt;
+        return;
+    }
+
     if (isSwitchedOut() || inst->isSquashed()) {
         iewStage->decrWb(inst->seqNum);
     } else {
         if (!state->noWB) {
-            writeback(inst, pkt);
+            if (!TheISA::HasUnalignedMemAcc || !state->isSplit ||
+                !state->isLoad) {
+                writeback(inst, pkt);
+            } else {
+                writeback(inst, state->mainPkt);
+            }
         }
 
         if (inst->isStore()) {
@@ -97,6 +121,10 @@ LSQUnit<Impl>::completeDataAccess(PacketPtr pkt)
         }
     }
 
+    if (TheISA::HasUnalignedMemAcc && state->isSplit && state->isLoad) {
+        delete state->mainPkt->req;
+        delete state->mainPkt;
+    }
     delete state;
     delete pkt->req;
     delete pkt;
@@ -106,7 +134,7 @@ template <class Impl>
 LSQUnit<Impl>::LSQUnit()
     : loads(0), stores(0), storesToWB(0), stalled(false),
       isStoreBlocked(false), isLoadBlocked(false),
-      loadBlockedHandled(false)
+      loadBlockedHandled(false), hasPendingPkt(false)
 {
 }
 
@@ -134,6 +162,9 @@ LSQUnit<Impl>::init(O3CPU *cpu_ptr, IEW *iew_ptr, DerivO3CPUParams *params,
     loadQueue.resize(LQEntries);
     storeQueue.resize(SQEntries);
 
+    depCheckShift = params->LSQDepCheckShift;
+    checkLoads = params->LSQCheckLoads;
+
     loadHead = loadTail = 0;
 
     storeHead = storeWBIdx = storeTail = 0;
@@ -324,8 +355,8 @@ LSQUnit<Impl>::insertLoad(DynInstPtr &load_inst)
     assert((loadTail + 1) % LQEntries != loadHead);
     assert(loads < LQEntries);
 
-    DPRINTF(LSQUnit, "Inserting load PC %#x, idx:%i [sn:%lli]\n",
-            load_inst->readPC(), loadTail, load_inst->seqNum);
+    DPRINTF(LSQUnit, "Inserting load PC %s, idx:%i [sn:%lli]\n",
+            load_inst->pcState(), loadTail, load_inst->seqNum);
 
     load_inst->lqIdx = loadTail;
 
@@ -350,8 +381,8 @@ LSQUnit<Impl>::insertStore(DynInstPtr &store_inst)
     assert((storeTail + 1) % SQEntries != storeHead);
     assert(stores < SQEntries);
 
-    DPRINTF(LSQUnit, "Inserting store PC %#x, idx:%i [sn:%lli]\n",
-            store_inst->readPC(), storeTail, store_inst->seqNum);
+    DPRINTF(LSQUnit, "Inserting store PC %s, idx:%i [sn:%lli]\n",
+            store_inst->pcState(), storeTail, store_inst->seqNum);
 
     store_inst->sqIdx = storeTail;
     store_inst->lqIdx = loadTail;
@@ -408,6 +439,55 @@ LSQUnit<Impl>::numLoadsReady()
     return retval;
 }
 
+template <class Impl>
+Fault
+LSQUnit<Impl>::checkViolations(int load_idx, DynInstPtr &inst)
+{
+    Addr inst_eff_addr1 = inst->effAddr >> depCheckShift;
+    Addr inst_eff_addr2 = (inst->effAddr + inst->effSize - 1) >> depCheckShift;
+
+    /** @todo in theory you only need to check an instruction that has executed
+     * however, there isn't a good way in the pipeline at the moment to check
+     * all instructions that will execute before the store writes back. Thus,
+     * like the implementation that came before it, we're overly conservative.
+     */
+    while (load_idx != loadTail) {
+        DynInstPtr ld_inst = loadQueue[load_idx];
+        if (!ld_inst->effAddrValid || ld_inst->uncacheable()) {
+            incrLdIdx(load_idx);
+            continue;
+        }
+
+        Addr ld_eff_addr1 = ld_inst->effAddr >> depCheckShift;
+        Addr ld_eff_addr2 =
+            (ld_inst->effAddr + ld_inst->effSize - 1) >> depCheckShift;
+
+        if ((inst_eff_addr2 > ld_eff_addr1 && inst_eff_addr1 < ld_eff_addr2) ||
+               inst_eff_addr1 == ld_eff_addr1) {
+            // A load/store incorrectly passed this load/store.
+            // Check if we already have a violator, or if it's newer
+            // squash and refetch.
+            if (memDepViolator && ld_inst->seqNum > memDepViolator->seqNum)
+                break;
+
+            DPRINTF(LSQUnit, "Detected fault with inst [sn:%lli] and [sn:%lli]"
+                    " at address %#x\n", inst->seqNum, ld_inst->seqNum,
+                    ld_eff_addr1);
+            memDepViolator = ld_inst;
+
+            ++lsqMemOrderViolation;
+
+            return TheISA::genMachineCheckFault();
+        }
+
+        incrLdIdx(load_idx);
+    }
+    return NoFault;
+}
+
+
+
+
 template <class Impl>
 Fault
 LSQUnit<Impl>::executeLoad(DynInstPtr &inst)
@@ -416,20 +496,29 @@ LSQUnit<Impl>::executeLoad(DynInstPtr &inst)
     // Execute a specific load.
     Fault load_fault = NoFault;
 
-    DPRINTF(LSQUnit, "Executing load PC %#x, [sn:%lli]\n",
-            inst->readPC(),inst->seqNum);
+    DPRINTF(LSQUnit, "Executing load PC %s, [sn:%lli]\n",
+            inst->pcState(), inst->seqNum);
 
     assert(!inst->isSquashed());
 
     load_fault = inst->initiateAcc();
 
-    // If the instruction faulted, then we need to send it along to commit
-    // without the instruction completing.
-    if (load_fault != NoFault) {
+    if (inst->isTranslationDelayed() &&
+        load_fault == NoFault)
+        return load_fault;
+
+    // If the instruction faulted or predicated false, then we need to send it
+    // along to commit without the instruction completing.
+    if (load_fault != NoFault || inst->readPredicate() == false) {
         // Send this instruction to commit, also make sure iew stage
         // realizes there is activity.
         // Mark it as executed unless it is an uncached load that
         // needs to hit the head of commit.
+        if (inst->readPredicate() == false)
+            inst->forwardOldRegs();
+        DPRINTF(LSQUnit, "Load [sn:%lli] not executed from %s\n",
+                inst->seqNum,
+                (load_fault != NoFault ? "fault" : "predication"));
         if (!(inst->hasRequest() && inst->uncacheable()) ||
             inst->isAtCommit()) {
             inst->setExecuted();
@@ -440,34 +529,9 @@ LSQUnit<Impl>::executeLoad(DynInstPtr &inst)
         assert(inst->effAddrValid);
         int load_idx = inst->lqIdx;
         incrLdIdx(load_idx);
-        while (load_idx != loadTail) {
-            // Really only need to check loads that have actually executed
-
-            // @todo: For now this is extra conservative, detecting a
-            // violation if the addresses match assuming all accesses
-            // are quad word accesses.
-
-            // @todo: Fix this, magic number being used here
-            if (loadQueue[load_idx]->effAddrValid &&
-                (loadQueue[load_idx]->effAddr >> 8) ==
-                (inst->effAddr >> 8)) {
-                // A load incorrectly passed this load.  Squash and refetch.
-                // For now return a fault to show that it was unsuccessful.
-                DynInstPtr violator = loadQueue[load_idx];
-                if (!memDepViolator ||
-                    (violator->seqNum < memDepViolator->seqNum)) {
-                    memDepViolator = violator;
-                } else {
-                    break;
-                }
-
-                ++lsqMemOrderViolation;
 
-                return genMachineCheckFault();
-            }
-
-            incrLdIdx(load_idx);
-        }
+        if (checkLoads)
+            return checkViolations(load_idx, inst);
     }
 
     return load_fault;
@@ -483,8 +547,8 @@ LSQUnit<Impl>::executeStore(DynInstPtr &store_inst)
 
     int store_idx = store_inst->sqIdx;
 
-    DPRINTF(LSQUnit, "Executing store PC %#x [sn:%lli]\n",
-            store_inst->readPC(), store_inst->seqNum);
+    DPRINTF(LSQUnit, "Executing store PC %s [sn:%lli]\n",
+            store_inst->pcState(), store_inst->seqNum);
 
     assert(!store_inst->isSquashed());
 
@@ -494,11 +558,22 @@ LSQUnit<Impl>::executeStore(DynInstPtr &store_inst)
 
     Fault store_fault = store_inst->initiateAcc();
 
+    if (store_inst->isTranslationDelayed() &&
+        store_fault == NoFault)
+        return store_fault;
+
+    if (store_inst->readPredicate() == false)
+        store_inst->forwardOldRegs();
+
     if (storeQueue[store_idx].size == 0) {
-        DPRINTF(LSQUnit,"Fault on Store PC %#x, [sn:%lli],Size = 0\n",
-                store_inst->readPC(),store_inst->seqNum);
+        DPRINTF(LSQUnit,"Fault on Store PC %s, [sn:%lli], Size = 0\n",
+                store_inst->pcState(), store_inst->seqNum);
 
         return store_fault;
+    } else if (store_inst->readPredicate() == false) {
+        DPRINTF(LSQUnit, "Store [sn:%lli] not executed from predication\n",
+                store_inst->seqNum);
+        return store_fault;
     }
 
     assert(store_fault == NoFault);
@@ -511,39 +586,8 @@ LSQUnit<Impl>::executeStore(DynInstPtr &store_inst)
         ++storesToWB;
     }
 
-    assert(store_inst->effAddrValid);
-    while (load_idx != loadTail) {
-        // Really only need to check loads that have actually executed
-        // It's safe to check all loads because effAddr is set to
-        // InvalAddr when the dyn inst is created.
-
-        // @todo: For now this is extra conservative, detecting a
-        // violation if the addresses match assuming all accesses
-        // are quad word accesses.
-
-        // @todo: Fix this, magic number being used here
-        if (loadQueue[load_idx]->effAddrValid &&
-            (loadQueue[load_idx]->effAddr >> 8) ==
-            (store_inst->effAddr >> 8)) {
-            // A load incorrectly passed this store.  Squash and refetch.
-            // For now return a fault to show that it was unsuccessful.
-            DynInstPtr violator = loadQueue[load_idx];
-            if (!memDepViolator ||
-                (violator->seqNum < memDepViolator->seqNum)) {
-                memDepViolator = violator;
-            } else {
-                break;
-            }
+    return checkViolations(load_idx, store_inst);
 
-            ++lsqMemOrderViolation;
-
-            return genMachineCheckFault();
-        }
-
-        incrLdIdx(load_idx);
-    }
-
-    return store_fault;
 }
 
 template <class Impl>
@@ -552,8 +596,8 @@ LSQUnit<Impl>::commitLoad()
 {
     assert(loadQueue[loadHead]);
 
-    DPRINTF(LSQUnit, "Committing head load instruction, PC %#x\n",
-            loadQueue[loadHead]->readPC());
+    DPRINTF(LSQUnit, "Committing head load instruction, PC %s\n",
+            loadQueue[loadHead]->pcState());
 
     loadQueue[loadHead] = NULL;
 
@@ -590,8 +634,8 @@ LSQUnit<Impl>::commitStores(InstSeqNum &youngest_inst)
                 break;
             }
             DPRINTF(LSQUnit, "Marking store as able to write back, PC "
-                    "%#x [sn:%lli]\n",
-                    storeQueue[store_idx].inst->readPC(),
+                    "%s [sn:%lli]\n",
+                    storeQueue[store_idx].inst->pcState(),
                     storeQueue[store_idx].inst->seqNum);
 
             storeQueue[store_idx].canWB = true;
@@ -603,10 +647,32 @@ LSQUnit<Impl>::commitStores(InstSeqNum &youngest_inst)
     }
 }
 
+template <class Impl>
+void
+LSQUnit<Impl>::writebackPendingStore()
+{
+    if (hasPendingPkt) {
+        assert(pendingPkt != NULL);
+
+        // If the cache is blocked, this will store the packet for retry.
+        if (sendStore(pendingPkt)) {
+            storePostSend(pendingPkt);
+        }
+        pendingPkt = NULL;
+        hasPendingPkt = false;
+    }
+}
+
 template <class Impl>
 void
 LSQUnit<Impl>::writebackStores()
 {
+    // First writeback the second packet from any split store that didn't
+    // complete last cycle because there weren't enough cache ports available.
+    if (TheISA::HasUnalignedMemAcc) {
+        writebackPendingStore();
+    }
+
     while (storesToWB > 0 &&
            storeWBIdx != storeTail &&
            storeQueue[storeWBIdx].inst &&
@@ -640,6 +706,11 @@ LSQUnit<Impl>::writebackStores()
         assert(storeQueue[storeWBIdx].req);
         assert(!storeQueue[storeWBIdx].committed);
 
+        if (TheISA::HasUnalignedMemAcc && storeQueue[storeWBIdx].isSplit) {
+            assert(storeQueue[storeWBIdx].sreqLow);
+            assert(storeQueue[storeWBIdx].sreqHigh);
+        }
+
         DynInstPtr inst = storeQueue[storeWBIdx].inst;
 
         Request *req = storeQueue[storeWBIdx].req;
@@ -653,24 +724,51 @@ LSQUnit<Impl>::writebackStores()
         MemCmd command =
             req->isSwap() ? MemCmd::SwapReq :
             (req->isLLSC() ? MemCmd::StoreCondReq : MemCmd::WriteReq);
-        PacketPtr data_pkt = new Packet(req, command,
-                                        Packet::Broadcast);
-        data_pkt->dataStatic(inst->memData);
+        PacketPtr data_pkt;
+        PacketPtr snd_data_pkt = NULL;
 
         LSQSenderState *state = new LSQSenderState;
         state->isLoad = false;
         state->idx = storeWBIdx;
         state->inst = inst;
-        data_pkt->senderState = state;
 
-        DPRINTF(LSQUnit, "D-Cache: Writing back store idx:%i PC:%#x "
+        if (!TheISA::HasUnalignedMemAcc || !storeQueue[storeWBIdx].isSplit) {
+
+            // Build a single data packet if the store isn't split.
+            data_pkt = new Packet(req, command, Packet::Broadcast);
+            data_pkt->dataStatic(inst->memData);
+            data_pkt->senderState = state;
+        } else {
+            RequestPtr sreqLow = storeQueue[storeWBIdx].sreqLow;
+            RequestPtr sreqHigh = storeQueue[storeWBIdx].sreqHigh;
+
+            // Create two packets if the store is split in two.
+            data_pkt = new Packet(sreqLow, command, Packet::Broadcast);
+            snd_data_pkt = new Packet(sreqHigh, command, Packet::Broadcast);
+
+            data_pkt->dataStatic(inst->memData);
+            snd_data_pkt->dataStatic(inst->memData + sreqLow->getSize());
+
+            data_pkt->senderState = state;
+            snd_data_pkt->senderState = state;
+
+            state->isSplit = true;
+            state->outstanding = 2;
+
+            // Can delete the main request now.
+            delete req;
+            req = sreqLow;
+        }
+
+        DPRINTF(LSQUnit, "D-Cache: Writing back store idx:%i PC:%s "
                 "to Addr:%#x, data:%#x [sn:%lli]\n",
-                storeWBIdx, inst->readPC(),
+                storeWBIdx, inst->pcState(),
                 req->getPaddr(), (int)*(inst->memData),
                 inst->seqNum);
 
         // @todo: Remove this SC hack once the memory system handles it.
         if (inst->isStoreConditional()) {
+            assert(!storeQueue[storeWBIdx].isSplit);
             // Disable recording the result temporarily.  Writing to
             // misc regs normally updates the result, but this is not
             // the desired behavior when handling store conditionals.
@@ -684,7 +782,7 @@ LSQUnit<Impl>::writebackStores()
                         "Instantly completing it.\n",
                         inst->seqNum);
                 WritebackEvent *wb = new WritebackEvent(inst, data_pkt, this);
-                cpu->schedule(wb, curTick + 1);
+                cpu->schedule(wb, curTick() + 1);
                 completeStore(storeWBIdx);
                 incrStIdx(storeWBIdx);
                 continue;
@@ -694,18 +792,44 @@ LSQUnit<Impl>::writebackStores()
             state->noWB = true;
         }
 
-        if (!dcachePort->sendTiming(data_pkt)) {
-            // Need to handle becoming blocked on a store.
+        if (!sendStore(data_pkt)) {
             DPRINTF(IEW, "D-Cache became blocked when writing [sn:%lli], will"
                     "retry later\n",
                     inst->seqNum);
-            isStoreBlocked = true;
-            ++lsqCacheBlocked;
-            assert(retryPkt == NULL);
-            retryPkt = data_pkt;
-            lsq->setRetryTid(lsqID);
+
+            // Need to store the second packet, if split.
+            if (TheISA::HasUnalignedMemAcc && storeQueue[storeWBIdx].isSplit) {
+                state->pktToSend = true;
+                state->pendingPacket = snd_data_pkt;
+            }
         } else {
-            storePostSend(data_pkt);
+
+            // If split, try to send the second packet too
+            if (TheISA::HasUnalignedMemAcc && storeQueue[storeWBIdx].isSplit) {
+                assert(snd_data_pkt);
+
+                // Ensure there are enough ports to use.
+                if (usedPorts < cachePorts) {
+                    ++usedPorts;
+                    if (sendStore(snd_data_pkt)) {
+                        storePostSend(snd_data_pkt);
+                    } else {
+                        DPRINTF(IEW, "D-Cache became blocked when writing"
+                                " [sn:%lli] second packet, will retry later\n",
+                                inst->seqNum);
+                    }
+                } else {
+
+                    // Store the packet for when there's free ports.
+                    assert(pendingPkt == NULL);
+                    pendingPkt = snd_data_pkt;
+                    hasPendingPkt = true;
+                }
+            } else {
+
+                // Not a split store.
+                storePostSend(data_pkt);
+            }
         }
     }
 
@@ -740,9 +864,9 @@ LSQUnit<Impl>::squash(const InstSeqNum &squashed_num)
     decrLdIdx(load_idx);
 
     while (loads != 0 && loadQueue[load_idx]->seqNum > squashed_num) {
-        DPRINTF(LSQUnit,"Load Instruction PC %#x squashed, "
+        DPRINTF(LSQUnit,"Load Instruction PC %s squashed, "
                 "[sn:%lli]\n",
-                loadQueue[load_idx]->readPC(),
+                loadQueue[load_idx]->pcState(),
                 loadQueue[load_idx]->seqNum);
 
         if (isStalled() && load_idx == stallingLoadIdx) {
@@ -785,9 +909,9 @@ LSQUnit<Impl>::squash(const InstSeqNum &squashed_num)
             break;
         }
 
-        DPRINTF(LSQUnit,"Store Instruction PC %#x squashed, "
+        DPRINTF(LSQUnit,"Store Instruction PC %s squashed, "
                 "idx:%i [sn:%lli]\n",
-                storeQueue[store_idx].inst->readPC(),
+                storeQueue[store_idx].inst->pcState(),
                 store_idx, storeQueue[store_idx].inst->seqNum);
 
         // I don't think this can happen.  It should have been cleared
@@ -808,6 +932,13 @@ LSQUnit<Impl>::squash(const InstSeqNum &squashed_num)
         // memory.  This is quite ugly.  @todo: Figure out the proper
         // place to really handle request deletes.
         delete storeQueue[store_idx].req;
+        if (TheISA::HasUnalignedMemAcc && storeQueue[store_idx].isSplit) {
+            delete storeQueue[store_idx].sreqLow;
+            delete storeQueue[store_idx].sreqHigh;
+
+            storeQueue[store_idx].sreqLow = NULL;
+            storeQueue[store_idx].sreqHigh = NULL;
+        }
 
         storeQueue[store_idx].req = NULL;
         --stores;
@@ -874,6 +1005,9 @@ LSQUnit<Impl>::writeback(DynInstPtr &inst, PacketPtr pkt)
     iewStage->instToCommit(inst);
 
     iewStage->activityThisCycle();
+
+    // see if this load changed the PC
+    iewStage->checkMisprediction(inst);
 }
 
 template <class Impl>
@@ -926,6 +1060,22 @@ LSQUnit<Impl>::completeStore(int store_idx)
 #endif
 }
 
+template <class Impl>
+bool
+LSQUnit<Impl>::sendStore(PacketPtr data_pkt)
+{
+    if (!dcachePort->sendTiming(data_pkt)) {
+        // Need to handle becoming blocked on a store.
+        isStoreBlocked = true;
+        ++lsqCacheBlocked;
+        assert(retryPkt == NULL);
+        retryPkt = data_pkt;
+        lsq->setRetryTid(lsqID);
+        return false;
+    }
+    return true;
+}
+
 template <class Impl>
 void
 LSQUnit<Impl>::recvRetry()
@@ -935,10 +1085,26 @@ LSQUnit<Impl>::recvRetry()
         assert(retryPkt != NULL);
 
         if (dcachePort->sendTiming(retryPkt)) {
-            storePostSend(retryPkt);
+            LSQSenderState *state =
+                dynamic_cast<LSQSenderState *>(retryPkt->senderState);
+
+            // Don't finish the store unless this is the last packet.
+            if (!TheISA::HasUnalignedMemAcc || !state->pktToSend ||
+                    state->pendingPacket == retryPkt) {
+                state->pktToSend = false;
+                storePostSend(retryPkt);
+            }
             retryPkt = NULL;
             isStoreBlocked = false;
             lsq->setRetryTid(InvalidThreadID);
+
+            // Send any outstanding packet.
+            if (TheISA::HasUnalignedMemAcc && state->pktToSend) {
+                assert(state->pendingPacket);
+                if (sendStore(state->pendingPacket)) {
+                    storePostSend(state->pendingPacket);
+                }
+            }
         } else {
             // Still blocked!
             ++lsqCacheBlocked;
@@ -995,7 +1161,7 @@ LSQUnit<Impl>::dumpInsts()
     int load_idx = loadHead;
 
     while (load_idx != loadTail && loadQueue[load_idx]) {
-        cprintf("%#x ", loadQueue[load_idx]->readPC());
+        cprintf("%s ", loadQueue[load_idx]->pcState());
 
         incrLdIdx(load_idx);
     }
@@ -1006,7 +1172,7 @@ LSQUnit<Impl>::dumpInsts()
     int store_idx = storeHead;
 
     while (store_idx != storeTail && storeQueue[store_idx].inst) {
-        cprintf("%#x ", storeQueue[store_idx].inst->readPC());
+        cprintf("%s ", storeQueue[store_idx].inst->pcState());
 
         incrStIdx(store_idx);
     }