📄 busuma.c
字号:
if (!List_IsEmpty(&requestTableFullQ[mreq->machnum])) { itemPtr = List_First(&requestTableFullQ[mreq->machnum]); List_Remove(itemPtr); ASSERT(LIST_TO_MREQ(itemPtr)->state == RT_OVERFLOW); LIST_TO_MREQ(itemPtr)->state = BUS_ARB_WAIT; List_Insert(itemPtr, LIST_ATREAR(&highPri[mreq->machnum])); if (debugMem) CPUPrint("DBGBSU %lld %d issuing RTfullQ addr(0x%x)\n", CPUVec.CycleCount(mreq->cpunum), LIST_TO_MREQ(itemPtr)->cpunum, LIST_TO_MREQ(itemPtr)->addr); } } } /* sharing writeback also go to memory */ if (mreq->result & MEMSYS_RESULT_CACHE) { mreq->state = MEM_BUSY_WAIT; mreq->cmd = MEMSYS_SHARING_WRITEBACK; List_Insert(MREQ_TO_LIST(mreq), LIST_ATREAR(&memState[mreq->memnum]->memoryQueue)); mreq->memQEnter = CPUVec.CycleCount(mreq->cpunum); if (!memState[mreq->memnum]->busy) MemoryArrive(mreq->memnum); } else { mreq->state = REQ_FREE; List_Insert(MREQ_TO_LIST(mreq), LIST_ATREAR(&freeMemReqList)); }}static voidCacheTransferDone(int cpuNum, EventCallbackHdr *hdr, void *arg){ MemRequest *mreq = (MemRequest *)hdr; ASSERT(M_FROM_CPU(cpuNum) == mreq->machnum); if (mreq->cmd & MEMSYS_DMAFLAVOR) { if ((mreq->cmd & MEMSYS_CMDMASK) == MEMSYS_GET) { bcopy(DATA_ADDR(mreq->machnum, mreq->reqAddr), mreq->data, mreq->len); } else { ASSERT((mreq->cmd & MEMSYS_CMDMASK) == MEMSYS_GETX); bcopy(mreq->data, DATA_ADDR(mreq->machnum, mreq->reqAddr), mreq->len); } } else { mreq->data = (byte*)DATA_ADDR(mreq->machnum, mreq->addr); } mreq->state = REPLY_BUS_ARB_WAIT; List_Insert(MREQ_TO_LIST(mreq), LIST_ATREAR(&highPri[mreq->machnum])); Arbitrate(mreq->machnum);}/* Nak all pending upgrades to the same address */static voidNakUpgrades(MemRequest *mreq){ List_Links *queueHead, *itemPtr, *nextPtr; if (mreq->rtIndex == -1) { /* there cannot be a request table entry for this addr, so only check highPri queue */ queueHead = &highPri[mreq->machnum]; } else { /* there cannot be upgrades in highPri queue, so only check requestTable delay queue */ queueHead = &requestTable[mreq->machnum][mreq->rtIndex].delay; } for (itemPtr = List_First(queueHead), nextPtr = NULL; !List_IsAtEnd(queueHead, itemPtr); itemPtr = nextPtr) { MemRequest *req2 = LIST_TO_MREQ(itemPtr); nextPtr = List_Next(itemPtr); if ((req2->addr == mreq->addr) && ((req2->cmd & MEMSYS_CMDMASK) == MEMSYS_UPGRADE)) { List_Remove(itemPtr); NakRequest(req2); } }}/* Check caches and writeback buffers for coherency */static voidCacheSnoop(MemRequest *mreq){ MemRequest *wbReq; int i, way=0, wasDirty, cacheToCache=0; char *data; int machine = M_FROM_CPU(mreq->cpunum); ASSERT(mreq->state == BUS_TRANSFER_WAIT); /* add gets without request table indexes to request table */ if ((mreq->rtIndex == -1) && (((mreq->cmd & MEMSYS_CMDMASK) == MEMSYS_GET) || ((mreq->cmd & MEMSYS_CMDMASK) == MEMSYS_GETX))) { RTInsert(mreq); } switch (mreq->cmd & MEMSYS_CMDMASK) { case MEMSYS_GET: memState[mreq->memnum]->stats.buCounts[BUC_BUS_GETRQST] += arbitrationCycles + transferCycles; /* do the sharing writeback if necessary */ for (i = FIRST_CPU(machine); i <= LAST_CPU(machine); i++) { if ((i == mreq->cpunum) && !(mreq->cmd & MEMSYS_DMAFLAVOR)) continue; if (IsInSCache(i, BACKMAP_PADDR(mreq->addr,i), MEMSYS_EXCLUSIVE, &data, &way)) { CacheWriteback(i, BACKMAP_PADDR(mreq->addr,i), SCACHE_LINE_SIZE, (byte*)DATA_ADDR(mreq->machnum, mreq->addr)); cacheToCache=1; mreq->result |= MEMSYS_RESULT_DOWNGRADE; break; } wbReq = IsInWBBuffer(i, mreq->addr); if (wbReq) {#ifdef DATA_HANDLING bcopy(wbReq->data, DATA_ADDR(mreq->machnum, mreq->addr), SCACHE_LINE_SIZE);#endif /* remove entry from writeback buffer */ FreeWBentry(wbReq); cacheToCache=1; mreq->result |= MEMSYS_RESULT_DOWNGRADE; break; } } break; case MEMSYS_GETX: memState[mreq->memnum]->stats.buCounts[BUC_BUS_GETRQST] += arbitrationCycles + transferCycles; /* do the sharing writeback and invalidate if necessary */ for (i = FIRST_CPU(machine); i <= LAST_CPU(machine); i++) { if ((i == mreq->cpunum) && !(mreq->cmd & MEMSYS_DMAFLAVOR)) continue; if (IsInSCache(i, BACKMAP_PADDR(mreq->addr,i), MEMSYS_EXCLUSIVE, &data, &way)) { CacheExtract(i, BACKMAP_PADDR(mreq->addr,i), SCACHE_LINE_SIZE, &wasDirty, (byte*)DATA_ADDR(mreq->machnum, mreq->addr)); cacheToCache=1; mreq->result |= MEMSYS_RESULT_INVALIDATE; break; } else if (IsInSCache(i, BACKMAP_PADDR(mreq->addr,i), MEMSYS_SHARED, &data, &way)) { CacheInvalidate(i, BACKMAP_PADDR(mreq->addr,i), SCACHE_LINE_SIZE, FALSE, &wasDirty); mreq->result |= MEMSYS_RESULT_INVALIDATE; memState[mreq->memnum]->stats.counts[COUNT_INVALORDNGRADESENT]++; memState[mreq->memnum]->stats.counts[COUNT_EXCLUSIVEONSHARED]++; } else { CacheFakeInvalidate(i,BACKMAP_PADDR(mreq->addr,i),SCACHE_LINE_SIZE); } wbReq = IsInWBBuffer(i, mreq->addr); if (wbReq) {#ifdef DATA_HANDLING bcopy(wbReq->data, DATA_ADDR(mreq->machnum, mreq->addr), SCACHE_LINE_SIZE);#endif /* remove entry from writeback buffer */ FreeWBentry(wbReq); cacheToCache=1; mreq->result |= MEMSYS_RESULT_INVALIDATE; break; } } NakUpgrades(mreq); break; case MEMSYS_UPGRADE: memState[mreq->memnum]->stats.buCounts[BUC_BUS_UPG] += arbitrationCycles + transferCycles; /* send invalidate if necessary */ for (i = FIRST_CPU(machine); i <= LAST_CPU(machine); i++) { if (i == mreq->cpunum) continue; ASSERT(!IsInSCache(i, BACKMAP_PADDR(mreq->addr,i), MEMSYS_EXCLUSIVE, &data, &way)); if (IsInSCache(i, BACKMAP_PADDR(mreq->addr,i), MEMSYS_SHARED, &data, &way)) { CacheInvalidate(i, BACKMAP_PADDR(mreq->addr,i), SCACHE_LINE_SIZE, FALSE, &wasDirty); mreq->result |= MEMSYS_RESULT_INVALIDATE; memState[mreq->memnum]->stats.counts[COUNT_INVALORDNGRADESENT]++; memState[mreq->memnum]->stats.counts[COUNT_EXCLUSIVEONSHARED]++; } else { CacheFakeInvalidate(i,BACKMAP_PADDR(mreq->addr,i),SCACHE_LINE_SIZE); } ASSERT(!IsInWBBuffer(i, mreq->addr)); } NakUpgrades(mreq); break; case MEMSYS_WRITEBACK: memState[mreq->memnum]->stats.buCounts[BUC_BUS_WB] += arbitrationCycles + transferCycles; /* just some sanity checks */ for (i = FIRST_CPU(machine); i < LAST_CPU(machine); i++) { if (i == mreq->cpunum) continue; ASSERT(!IsInSCache(i, BACKMAP_PADDR(mreq->addr,i), MEMSYS_EXCLUSIVE, &data, &way)); ASSERT(!IsInSCache(i, BACKMAP_PADDR(mreq->addr,i), MEMSYS_SHARED, &data, &way)); ASSERT(!IsInWBBuffer(i, mreq->addr)); } break; default: CPUError("Bad mreq->cmd (0x%x)\n", mreq->cmd); } if (cacheToCache) { if (debugMem) CPUPrint("DBGBSU %lld %d cacheToCache addr(0x%x)\n", CPUVec.CycleCount(0), mreq->cpunum, mreq->addr); mreq->state = CACHE_TRANSFER_WAIT; mreq->result |= MEMSYS_RESULT_CACHE|MEMSYS_RESULT_DOWNGRADE; memState[mreq->memnum]->stats.counts[COUNT_REMOTEDIRTY]++; memState[mreq->memnum]->stats.counts[COUNT_INVALORDNGRADESENT]++; EventDoCallback(FIRST_CPU(mreq->machnum), CacheTransferDone, (EventCallbackHdr *) mreq, NULL, memoryCycles + dirtyPenalty); } else if ((mreq->cmd & MEMSYS_CMDMASK) == MEMSYS_UPGRADE) { mreq->result |= MEMSYS_RESULT_MEMORY; /* doesn't really make sense to set this for upgrades, but scache wants it set */ CPUArrive(mreq); } else { mreq->state = MEM_BUSY_WAIT; mreq->result |= MEMSYS_RESULT_MEMORY; List_Insert(MREQ_TO_LIST(mreq), LIST_ATREAR(&memState[mreq->memnum]->memoryQueue)); mreq->memQEnter = CPUVec.CycleCount(mreq->cpunum); if (!memState[mreq->memnum]->busy) MemoryArrive(mreq->memnum); }}/* Bus transfer has finished, so send request to proper place (CPU or memory), * and setup the next arbitration if there's something in the queues */static voidBusFree(int cpuNum, EventCallbackHdr *hdr, void *arg){ MemRequest *mreq = (MemRequest *)hdr; ASSERT(M_FROM_CPU(cpuNum) == mreq->machnum); /* Send request to proper place */ if (mreq->state == BUS_TRANSFER_WAIT) { CacheSnoop(mreq); } else { ASSERT(mreq->state == REPLY_BUS_TRANSFER_WAIT); CPUArrive(mreq); } if (busIdleStart[mreq->machnum]) { memState[FIRST_MEMORY(mreq->machnum)]->stats.buCounts[BUC_BUS_IDLE] += CPUVec.CycleCount(0) - busIdleStart[mreq->machnum] - (arbitrationCycles + transferCycles); busIdleStart[mreq->machnum] = 0; } /* Setup next arbitration */ if (!List_IsEmpty(&highPri[mreq->machnum]) || !List_IsEmpty(&lowPri[mreq->machnum])) { EventDoCallback(FIRST_CPU(mreq->machnum), ArbitrateCallback, (EventCallbackHdr *) &arbitrate[mreq->machnum], NULL, arbitrationCycles); } else { busBusy[mreq->machnum] = 0; busIdleStart[mreq->machnum] = CPUVec.CycleCount(0); }}/* Arbitration cycles are finished, now decide the winner by first checking * the high priority queue, and then the low priority queue. */static voidArbitrateCallback(int cpuNum, EventCallbackHdr *hdr, void *arg){ List_Links *itemPtr; MemRequest *mreq; int machine = M_FROM_CPU(cpuNum); if (!List_IsEmpty(&highPri[machine])) { itemPtr = List_First(&highPri[machine]); } else if (!List_IsEmpty(&lowPri[machine])) { itemPtr = List_First(&lowPri[machine]); } else { /* this could happen if a CPU miss is satisfied from it's own writeback buffer */ /* Kinshuk, DT: BUT, this happens very often if you do a flush * followed by a prefetch exclusive (as in the SIPS code). * So this gets commented out for now. */ /* CPUWarning("ArbitrateCallback called with nothing to do (time: %lld)\n", CPUVec.CycleCount(cpuNum)); */ busBusy[machine] = 0; return; } List_Remove(itemPtr); /* now occupy the bus for the correct number of cycles */ mreq = LIST_TO_MREQ(itemPtr); if (mreq->state == BUS_ARB_WAIT) { mreq->state = BUS_TRANSFER_WAIT; } else { ASSERT(mreq->state == REPLY_BUS_ARB_WAIT); mreq->state = REPLY_BUS_TRANSFER_WAIT; memState[mreq->memnum]->stats.buCounts[BUC_BUS_GETREPLY] += arbitrationCycles + transferCycles; } memState[mreq->memnum]->stats.buCounts[BUC_BUS_BUSY] += arbitrationCycles + transferCycles; EventDoCallback(FIRST_CPU(mreq->machnum), BusFree, (EventCallbackHdr *)mreq, NULL, transferCycles);}static voidArbitrate(int machine){ /* if arbitration callback is already set or will be once bus is free, just return */ if (busBusy[machine]) return; busBusy[machine] = 1; EventDoCallback(FIRST_CPU(machine), ArbitrateCallback, (EventCallbackHdr *) &arbitrate[machine], NULL, arbitrationCycles);}/* Request just arrived from CPU to Bus interface (time to go through caches, etc) */static voidBusArrive(int cpuNum, EventCallbackHdr *hdr, void *arg){ MemRequest *mreq = (MemRequest *)hdr; MemRequest *wbReq; char *data; int i, way=0, requestTableFull; ASSERT(M_FROM_CPU(cpuNum) == mreq->machnum); ASSERT(mreq->state == CPU_TO_BUS_OVERHEAD); /* if this request is for a bogus address, bus error it immediately */ if (!IS_VALID_PA(M_FROM_CPU(cpuNum), mreq->addr)) { ErrorRequest(mreq); return; }#ifndef SOLO /* if firewall is on and cpu is trying to write, check the firewall */ if (CPUVec.CheckFirewall) { int c = mreq->cmd & MEMSYS_CMDMASK; if ((c == MEMSYS_GETX) || (c == MEMSYS_UPGRADE)) { if (!CPUVec.CheckFirewall(cpuNum, mreq->addr)) { ErrorRequest(mreq); return; } } }#endif /* check the writeback buffer first */ switch (mreq->cmd & MEMSYS_CMDMASK) { case MEMSYS_GET: wbReq = IsInWBBuffer(cpuNum, mreq->addr); if (wbReq) { memState[mreq->memnum]->stats.buCounts[BUC_GET_WBBUF]++; /* CPUPrint("DBGBSU %lld GET hit in wbBuffer (0x%x)\n", CPUVec.CycleCount(0), mreq->addr); */#ifdef DATA_HANDLING bcopy(wbReq->data, DATA_ADDR(mreq->machnum, mreq->addr), SCACHE_LINE_SIZE);#endif CacheCmdDone(cpuNum, mreq->transId, mreq->mode, mreq->status, MEMSYS_RESULT_MEMORY|MEMSYS_RESULT_NOTRANSITION, (byte*)DATA_ADDR(mreq->machnum, mreq->addr)); /* free req */ mreq->state = REQ_FREE; List_Insert(MREQ_TO_LIST(mreq), LIST_ATREAR(&freeMemReqList)); return; } break; case MEMSYS_GETX: wbReq = IsInWBBuffer(cpuNum, mreq->addr); if (wbReq) { memState[mreq->memnum]->stats.buCounts[BUC_GET_WBBUF]++; /* CPUPrint("DBGBSU %lld GETX hit in wbBuffer (0x%x)\n", CPUVec.CycleCount(0), mreq->addr); */#ifdef DATA_HANDLING bcopy(wbReq->data, DATA_ADDR(mreq->machnum, mreq->addr), SCACHE_LINE_SIZE);#endif /* remove writeback entry because cache now has the most-recent data */ FreeWBentry(wbReq); CacheCmdDone(cpuNum, mreq->transId, mreq->mode, mreq->status, MEMSYS_RESULT_MEMORY|MEMSYS_RESULT_NOTRANSITION, (byte*)DATA_ADDR(mreq->machnum, mreq->addr)); /* free req */ mreq->state = REQ_FREE; List_Insert(MREQ_TO_LIST(mreq), LIST_ATREAR(&freeMemReqList)); return; } break; case MEMSYS_UPGRADE: wbReq = IsInWBBuffer(cpuNum, mreq->addr); if (wbReq) { memState[mreq->memnum]->stats.buCounts[BUC_UPG_WBBUF]++; CPUPrint("DBGBSU %lld UPGRADE hit in wbBuffer (0x%x)\n", CPUVec.CycleCount(0), mreq->addr); /* remove writeback entry because cache now has the most-recent data */ FreeWBentry(wbReq); CacheCmdDone(cpuNum, mreq->transId, mreq->mode, mreq->status, MEMSYS_RESULT_MEMORY|MEMSYS_RESULT_NOTRANSITION, (byte*)DATA_ADDR(mreq->machnum, mreq->addr)); /* free req */ mreq->state = REQ_FREE; List_Insert(MREQ_TO_LIST(mreq), LIST_ATREAR(&freeMemReqList)); return; } /* Upgrades need to check wether that cache line is still in cache, It could've been invalidated by now */ if (!IsInSCache(mreq->cpunum, BACKMAP_PADDR(mreq->addr, mreq->cpunum), MEMSYS_SHARED, &data, &way)) { NakRequest(mreq); return; } break; case MEMSYS_WRITEBACK: /* for writebacks, add to low priority queue */ mreq->state = BUS_ARB_WAIT; List_Insert(MREQ_TO_LIST(mreq), LIST_ATREAR(WB_QUEUE(mreq->machnum))); Arbitrate(mreq->machnum); return;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -