/**
* ****************************************************************************
* Copyright (c) 2010-2016 by Min Cai (min.cai.china@gmail.com).
* <p>
* This file is part of the Archimulator multicore architectural simulator.
* <p>
* Archimulator is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
* <p>
* Archimulator is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* <p>
* You should have received a copy of the GNU General Public License
* along with Archimulator. If not, see <http://www.gnu.org/licenses/>.
* ****************************************************************************
*/
package archimulator.uncore.coherence.msi.fsm;
import archimulator.uncore.cache.CacheLine;
import archimulator.uncore.coherence.msi.controller.CacheController;
import archimulator.uncore.coherence.msi.event.cache.*;
import archimulator.uncore.coherence.msi.state.CacheControllerState;
import archimulator.util.fsm.FiniteStateMachineFactory;
import java.util.ArrayList;
import java.util.List;
import java.util.function.Consumer;
/**
* L1 cache controller finite state machine factory.
*
* @author Min Cai
*/
public class CacheControllerFiniteStateMachineFactory extends FiniteStateMachineFactory<CacheControllerState, CacheControllerEventType, CacheControllerFiniteStateMachine> {
/**
* Create an L1 cache controller finite state machine factory.
*/
private CacheControllerFiniteStateMachineFactory() {
Consumer<CacheControllerFiniteStateMachine> actionWhenStateChanged = fsm -> {
if (fsm.getPreviousState() != fsm.getState()) {
if (fsm.getState().isStable()) {
Runnable onCompletedCallback = fsm.getOnCompletedCallback();
if (onCompletedCallback != null) {
fsm.setOnCompletedCallback(null);
onCompletedCallback.run();
}
}
List<Runnable> stalledEventsToProcess = new ArrayList<>();
stalledEventsToProcess.addAll(fsm.getStalledEvents());
fsm.getStalledEvents().clear();
stalledEventsToProcess.forEach(Runnable::run);
}
};
this.inState(CacheControllerState.I)
.setOnCompletedCallback(actionWhenStateChanged)
.onCondition(CacheControllerEventType.LOAD, (fsm, sender, eventType, params) -> {
LoadEvent event = (LoadEvent) params;
fsm.sendGetSToDir(event, event.getTag());
fsm.fireServiceNonblockingRequestEvent(event.getAccess(), event.getTag(), false);
fsm.getLine().setAccess(event.getAccess());
fsm.getLine().setTag(event.getTag());
fsm.setOnCompletedCallback(() -> {
fsm.getCacheController().getCache().getReplacementPolicy().handleInsertionOnMiss(event.getAccess(), fsm.getSet(), fsm.getWay());
event.getOnCompletedCallback().run();
});
}, CacheControllerState.IS_D)
.onCondition(CacheControllerEventType.STORE, (fsm, sender, eventType, params) -> {
StoreEvent event = (StoreEvent) params;
fsm.sendGetMToDir(event, event.getTag());
fsm.fireServiceNonblockingRequestEvent(event.getAccess(), event.getTag(), false);
fsm.getLine().setAccess(event.getAccess());
fsm.getLine().setTag(event.getTag());
fsm.setOnCompletedCallback(() -> {
fsm.getCacheController().getCache().getReplacementPolicy().handleInsertionOnMiss(event.getAccess(), fsm.getSet(), fsm.getWay());
event.getOnCompletedCallback().run();
});
}, CacheControllerState.IM_AD);
this.inState(CacheControllerState.IS_D)
.setOnCompletedCallback(actionWhenStateChanged)
.onCondition(CacheControllerEventType.LOAD, (fsm, sender, eventType, params) -> {
LoadEvent event = (LoadEvent) params;
fsm.stall(event.getOnStalledCallback());
fsm.fireNonblockingRequestHitToTransientTagEvent(event.getAccess(), event.getTag());
}, CacheControllerState.IS_D)
.onCondition(CacheControllerEventType.STORE, (fsm, sender, eventType, params) -> {
StoreEvent event = (StoreEvent) params;
fsm.stall(event.getOnStalledCallback());
fsm.fireNonblockingRequestHitToTransientTagEvent(event.getAccess(), event.getTag());
}, CacheControllerState.IS_D)
.onCondition(CacheControllerEventType.REPLACEMENT, (fsm, sender, eventType, params) -> {
ReplacementEvent event = (ReplacementEvent) params;
event.getOnStalledCallback().run();
}, CacheControllerState.IS_D)
.onCondition(CacheControllerEventType.INV, (fsm, sender, eventType, params) -> {
InvEvent event = (InvEvent) params;
fsm.stall(sender, event);
}, CacheControllerState.IS_D)
.onCondition(CacheControllerEventType.DATA_FROM_DIR_ACKS_EQ_0, (fsm, sender, eventType, params) -> {
}, CacheControllerState.S)
.onCondition(CacheControllerEventType.DATA_FROM_OWNER, (fsm, sender, eventType, params) -> {
}, CacheControllerState.S);
this.inState(CacheControllerState.IM_AD)
.setOnCompletedCallback(actionWhenStateChanged)
.onCondition(CacheControllerEventType.LOAD, (fsm, sender, eventType, params) -> {
LoadEvent event = (LoadEvent) params;
fsm.stall(event.getOnStalledCallback());
fsm.fireNonblockingRequestHitToTransientTagEvent(event.getAccess(), event.getTag());
}, CacheControllerState.IM_AD)
.onCondition(CacheControllerEventType.STORE, (fsm, sender, eventType, params) -> {
StoreEvent event = (StoreEvent) params;
fsm.stall(event.getOnStalledCallback());
fsm.fireNonblockingRequestHitToTransientTagEvent(event.getAccess(), event.getTag());
}, CacheControllerState.IM_AD)
.onCondition(CacheControllerEventType.REPLACEMENT, (fsm, sender, eventType, params) -> {
ReplacementEvent event = (ReplacementEvent) params;
event.getOnStalledCallback().run();
}, CacheControllerState.IM_AD)
.onCondition(CacheControllerEventType.FWD_GETS, (fsm, sender, eventType, params) -> {
FwdGetSEvent event = (FwdGetSEvent) params;
fsm.stall(sender, event);
}, CacheControllerState.IM_AD)
.onCondition(CacheControllerEventType.FWD_GETM, (fsm, sender, eventType, params) -> {
FwdGetMEvent event = (FwdGetMEvent) params;
fsm.stall(sender, event);
}, CacheControllerState.IM_AD)
.onCondition(CacheControllerEventType.DATA_FROM_DIR_ACKS_EQ_0, (fsm, sender, eventType, params) -> {
}, CacheControllerState.M)
.onCondition(CacheControllerEventType.DATA_FROM_DIR_ACKS_GT_0, (fsm, sender, eventType, params) -> {
}, CacheControllerState.IM_A)
.onCondition(CacheControllerEventType.DATA_FROM_OWNER, (fsm, sender, eventType, params) -> {
}, CacheControllerState.M)
.onCondition(CacheControllerEventType.INV_ACK, (fsm, sender, eventType, params) -> fsm.decrementInvAcks(), CacheControllerState.IM_AD);
this.inState(CacheControllerState.IM_A)
.setOnCompletedCallback(actionWhenStateChanged)
.onCondition(CacheControllerEventType.LOAD, (fsm, sender, eventType, params) -> {
LoadEvent event = (LoadEvent) params;
fsm.stall(event.getOnStalledCallback());
fsm.fireNonblockingRequestHitToTransientTagEvent(event.getAccess(), event.getTag());
}, CacheControllerState.IM_A)
.onCondition(CacheControllerEventType.STORE, (fsm, sender, eventType, params) -> {
StoreEvent event = (StoreEvent) params;
fsm.stall(event.getOnStalledCallback());
fsm.fireNonblockingRequestHitToTransientTagEvent(event.getAccess(), event.getTag());
}, CacheControllerState.IM_A)
.onCondition(CacheControllerEventType.REPLACEMENT, (fsm, sender, eventType, params) -> {
ReplacementEvent event = (ReplacementEvent) params;
event.getOnStalledCallback().run();
}, CacheControllerState.IM_A)
.onCondition(CacheControllerEventType.FWD_GETS, (fsm, sender, eventType, params) -> {
FwdGetSEvent event = (FwdGetSEvent) params;
fsm.stall(sender, event);
}, CacheControllerState.IM_A)
.onCondition(CacheControllerEventType.FWD_GETM, (fsm, sender, eventType, params) -> {
FwdGetMEvent event = (FwdGetMEvent) params;
fsm.stall(sender, event);
}, CacheControllerState.IM_A)
.onCondition(CacheControllerEventType.RECALL, (fsm, sender, eventType, params) -> {
RecallEvent event = (RecallEvent) params;
fsm.stall(sender, event);
}, CacheControllerState.IM_A)
.onCondition(CacheControllerEventType.INV_ACK, (fsm, sender, eventType, params) -> fsm.decrementInvAcks(), CacheControllerState.IM_A)
.onCondition(CacheControllerEventType.LAST_INV_ACK, (fsm, sender, eventType, params) -> {
}, CacheControllerState.M);
this.inState(CacheControllerState.S)
.setOnCompletedCallback(actionWhenStateChanged)
.onCondition(CacheControllerEventType.LOAD, (fsm, sender, eventType, params) -> {
LoadEvent event = (LoadEvent) params;
fsm.hit(event.getAccess(), event.getTag(), event.getSet(), event.getWay());
fsm.getCacheController().getCycleAccurateEventQueue().schedule(fsm.getCacheController(), event.getOnCompletedCallback(), 0);
}, CacheControllerState.S)
.onCondition(CacheControllerEventType.STORE, (fsm, sender, eventType, params) -> {
StoreEvent event = (StoreEvent) params;
fsm.sendGetMToDir(event, event.getTag());
fsm.setOnCompletedCallback(event.getOnCompletedCallback());
fsm.fireServiceNonblockingRequestEvent(event.getAccess(), event.getTag(), true);
}, CacheControllerState.SM_AD)
.onCondition(CacheControllerEventType.REPLACEMENT, (fsm, sender, eventType, params) -> {
ReplacementEvent event = (ReplacementEvent) params;
fsm.sendPutSToDir(event, fsm.getLine().getTag());
fsm.setOnCompletedCallback(event.getOnCompletedCallback());
fsm.fireReplacementEvent(event.getAccess(), event.getTag());
fsm.getCacheController().incrementNumEvictions();
}, CacheControllerState.SI_A)
.onCondition(CacheControllerEventType.INV, (fsm, sender, eventType, params) -> {
InvEvent event = (InvEvent) params;
CacheController req = event.getRequester();
fsm.sendInvAckToRequester(event, req, event.getTag());
fsm.getLine().setAccess(null);
fsm.getLine().setTag(CacheLine.INVALID_TAG);
}, CacheControllerState.I)
.onCondition(CacheControllerEventType.RECALL, (fsm, sender, eventType, params) -> {
RecallEvent event = (RecallEvent) params;
fsm.sendRecallAckToDir(event, event.getTag(), 8);
fsm.getLine().setAccess(null);
fsm.getLine().setTag(CacheLine.INVALID_TAG);
}, CacheControllerState.I);
this.inState(CacheControllerState.SM_AD)
.setOnCompletedCallback(actionWhenStateChanged)
.onCondition(CacheControllerEventType.LOAD, (fsm, sender, eventType, params) -> {
LoadEvent event = (LoadEvent) params;
fsm.hit(event.getAccess(), event.getTag(), event.getSet(), event.getWay());
fsm.getCacheController().getCycleAccurateEventQueue().schedule(fsm.getCacheController(), event.getOnCompletedCallback(), 0);
}, CacheControllerState.SM_AD)
.onCondition(CacheControllerEventType.STORE, (fsm, sender, eventType, params) -> {
StoreEvent event = (StoreEvent) params;
fsm.stall(event.getOnStalledCallback());
}, CacheControllerState.SM_AD)
.onCondition(CacheControllerEventType.REPLACEMENT, (fsm, sender, eventType, params) -> {
ReplacementEvent event = (ReplacementEvent) params;
event.getOnStalledCallback().run();
}, CacheControllerState.SM_AD)
.onCondition(CacheControllerEventType.FWD_GETS, (fsm, sender, eventType, params) -> {
FwdGetSEvent event = (FwdGetSEvent) params;
fsm.stall(sender, event);
}, CacheControllerState.SM_AD)
.onCondition(CacheControllerEventType.FWD_GETM, (fsm, sender, eventType, params) -> {
FwdGetMEvent event = (FwdGetMEvent) params;
fsm.stall(sender, event);
}, CacheControllerState.SM_AD)
.onCondition(CacheControllerEventType.INV, (fsm, sender, eventType, params) -> {
InvEvent event = (InvEvent) params;
CacheController req = event.getRequester();
fsm.sendInvAckToRequester(event, req, event.getTag());
}, CacheControllerState.IM_AD)
.onCondition(CacheControllerEventType.RECALL, (fsm, sender, eventType, params) -> {
RecallEvent event = (RecallEvent) params;
fsm.sendRecallAckToDir(event, event.getTag(), 8);
}, CacheControllerState.IM_AD)
.onCondition(CacheControllerEventType.DATA_FROM_DIR_ACKS_EQ_0, (fsm, sender, eventType, params) -> {
}, CacheControllerState.M)
.onCondition(CacheControllerEventType.DATA_FROM_DIR_ACKS_GT_0, (fsm, sender, eventType, params) -> {
}, CacheControllerState.SM_A)
.onCondition(CacheControllerEventType.DATA_FROM_OWNER, (fsm, sender, eventType, params) -> {
}, CacheControllerState.M)
.onCondition(CacheControllerEventType.INV_ACK, (fsm, sender, eventType, params) -> fsm.decrementInvAcks(), CacheControllerState.SM_AD);
this.inState(CacheControllerState.SM_A)
.setOnCompletedCallback(actionWhenStateChanged)
.onCondition(CacheControllerEventType.LOAD, (fsm, sender, eventType, params) -> {
LoadEvent event = (LoadEvent) params;
fsm.hit(event.getAccess(), event.getTag(), event.getSet(), event.getWay());
fsm.getCacheController().getCycleAccurateEventQueue().schedule(fsm.getCacheController(), event.getOnCompletedCallback(), 0);
}, CacheControllerState.SM_A)
.onCondition(CacheControllerEventType.STORE, (fsm, sender, eventType, params) -> {
StoreEvent event = (StoreEvent) params;
fsm.stall(event.getOnStalledCallback());
}, CacheControllerState.SM_A)
.onCondition(CacheControllerEventType.REPLACEMENT, (fsm, sender, eventType, params) -> {
ReplacementEvent event = (ReplacementEvent) params;
event.getOnStalledCallback().run();
}, CacheControllerState.SM_A)
.onCondition(CacheControllerEventType.FWD_GETS, (fsm, sender, eventType, params) -> {
FwdGetSEvent event = (FwdGetSEvent) params;
fsm.stall(sender, event);
}, CacheControllerState.SM_A)
.onCondition(CacheControllerEventType.FWD_GETM, (fsm, sender, eventType, params) -> {
FwdGetMEvent event = (FwdGetMEvent) params;
fsm.stall(sender, event);
}, CacheControllerState.SM_A)
.onCondition(CacheControllerEventType.INV_ACK, (fsm, sender, eventType, params) -> fsm.decrementInvAcks(), CacheControllerState.SM_A)
.onCondition(CacheControllerEventType.LAST_INV_ACK, (fsm, sender, eventType, params) -> {
}, CacheControllerState.M)
.onCondition(CacheControllerEventType.RECALL, (fsm, sender, eventType, params) -> {
RecallEvent event = (RecallEvent) params;
fsm.stall(sender, event);
}, CacheControllerState.SM_A);
this.inState(CacheControllerState.M)
.setOnCompletedCallback(actionWhenStateChanged)
.onCondition(CacheControllerEventType.LOAD, (fsm, sender, eventType, params) -> {
LoadEvent event = (LoadEvent) params;
fsm.hit(event.getAccess(), event.getTag(), event.getSet(), event.getWay());
fsm.getCacheController().getCycleAccurateEventQueue().schedule(fsm.getCacheController(), event.getOnCompletedCallback(), 0);
}, CacheControllerState.M)
.onCondition(CacheControllerEventType.STORE, (fsm, sender, eventType, params) -> {
StoreEvent event = (StoreEvent) params;
fsm.hit(event.getAccess(), event.getTag(), event.getSet(), event.getWay());
fsm.getCacheController().getCycleAccurateEventQueue().schedule(fsm.getCacheController(), event.getOnCompletedCallback(), 0);
}, CacheControllerState.M)
.onCondition(CacheControllerEventType.REPLACEMENT, (fsm, sender, eventType, params) -> {
ReplacementEvent event = (ReplacementEvent) params;
fsm.sendPutMAndDataToDir(event, fsm.getLine().getTag());
fsm.setOnCompletedCallback(event.getOnCompletedCallback());
fsm.fireReplacementEvent(event.getAccess(), event.getTag());
fsm.getCacheController().incrementNumEvictions();
}, CacheControllerState.MI_A)
.onCondition(CacheControllerEventType.FWD_GETS, (fsm, sender, eventType, params) -> {
FwdGetSEvent event = (FwdGetSEvent) params;
fsm.sendDataToRequesterAndDir(event, event.getRequester(), event.getTag());
}, CacheControllerState.S)
.onCondition(CacheControllerEventType.FWD_GETM, (fsm, sender, eventType, params) -> {
FwdGetMEvent event = (FwdGetMEvent) params;
fsm.sendDataToRequester(event, event.getRequester(), event.getTag());
fsm.getLine().setAccess(null);
fsm.getLine().setTag(CacheLine.INVALID_TAG);
}, CacheControllerState.I)
.onCondition(CacheControllerEventType.RECALL, (fsm, sender, eventType, params) -> {
RecallEvent event = (RecallEvent) params;
fsm.sendRecallAckToDir(event, event.getTag(), fsm.getCacheController().getCache().getLineSize() + 8);
fsm.getLine().setAccess(null);
fsm.getLine().setTag(CacheLine.INVALID_TAG);
}, CacheControllerState.I);
this.inState(CacheControllerState.MI_A)
.setOnCompletedCallback(actionWhenStateChanged)
.onCondition(CacheControllerEventType.LOAD, (fsm, sender, eventType, params) -> {
LoadEvent event = (LoadEvent) params;
fsm.stall(event.getOnStalledCallback());
}, CacheControllerState.MI_A)
.onCondition(CacheControllerEventType.STORE, (fsm, sender, eventType, params) -> {
StoreEvent event = (StoreEvent) params;
fsm.stall(event.getOnStalledCallback());
}, CacheControllerState.MI_A)
.onCondition(CacheControllerEventType.REPLACEMENT, (fsm, sender, eventType, params) -> {
ReplacementEvent event = (ReplacementEvent) params;
event.getOnStalledCallback().run();
}, CacheControllerState.MI_A)
.onCondition(CacheControllerEventType.RECALL, (fsm, sender, eventType, params) -> {
RecallEvent event = (RecallEvent) params;
fsm.sendRecallAckToDir(event, event.getTag(), 8);
}, CacheControllerState.II_A)
.onCondition(CacheControllerEventType.FWD_GETS, (fsm, sender, eventType, params) -> {
FwdGetSEvent event = (FwdGetSEvent) params;
fsm.sendDataToRequesterAndDir(event, event.getRequester(), event.getTag());
}, CacheControllerState.SI_A)
.onCondition(CacheControllerEventType.FWD_GETM, (fsm, sender, eventType, params) -> {
FwdGetMEvent event = (FwdGetMEvent) params;
fsm.sendDataToRequester(event, event.getRequester(), event.getTag());
}, CacheControllerState.II_A)
.onCondition(CacheControllerEventType.PUT_ACK, (fsm, sender, eventType, params) -> {
fsm.getLine().setAccess(null);
fsm.getLine().setTag(CacheLine.INVALID_TAG);
}, CacheControllerState.I);
this.inState(CacheControllerState.SI_A)
.setOnCompletedCallback(actionWhenStateChanged)
.onCondition(CacheControllerEventType.LOAD, (fsm, sender, eventType, params) -> {
LoadEvent event = (LoadEvent) params;
fsm.stall(event.getOnStalledCallback());
}, CacheControllerState.SI_A)
.onCondition(CacheControllerEventType.STORE, (fsm, sender, eventType, params) -> {
StoreEvent event = (StoreEvent) params;
fsm.stall(event.getOnStalledCallback());
}, CacheControllerState.SI_A)
.onCondition(CacheControllerEventType.REPLACEMENT, (fsm, sender, eventType, params) -> {
ReplacementEvent event = (ReplacementEvent) params;
event.getOnStalledCallback().run();
}, CacheControllerState.SI_A)
.onCondition(CacheControllerEventType.INV, (fsm, sender, eventType, params) -> {
InvEvent event = (InvEvent) params;
fsm.sendInvAckToRequester(event, event.getRequester(), event.getTag());
}, CacheControllerState.II_A)
.onCondition(CacheControllerEventType.RECALL, (fsm, sender, eventType, params) -> {
RecallEvent event = (RecallEvent) params;
fsm.sendRecallAckToDir(event, event.getTag(), 8);
}, CacheControllerState.II_A)
.onCondition(CacheControllerEventType.PUT_ACK, (fsm, sender, eventType, params) -> {
fsm.getLine().setAccess(null);
fsm.getLine().setTag(CacheLine.INVALID_TAG);
}, CacheControllerState.I);
this.inState(CacheControllerState.II_A)
.setOnCompletedCallback(actionWhenStateChanged)
.onCondition(CacheControllerEventType.LOAD, (fsm, sender, eventType, params) -> {
LoadEvent event = (LoadEvent) params;
fsm.stall(event.getOnStalledCallback());
}, CacheControllerState.II_A)
.onCondition(CacheControllerEventType.STORE, (fsm, sender, eventType, params) -> {
StoreEvent event = (StoreEvent) params;
fsm.stall(event.getOnStalledCallback());
}, CacheControllerState.II_A)
.onCondition(CacheControllerEventType.REPLACEMENT, (fsm, sender, eventType, params) -> {
ReplacementEvent event = (ReplacementEvent) params;
event.getOnStalledCallback().run();
}, CacheControllerState.II_A)
.onCondition(CacheControllerEventType.PUT_ACK, (fsm, sender, eventType, params) -> {
fsm.getLine().setAccess(null);
fsm.getLine().setTag(CacheLine.INVALID_TAG);
}, CacheControllerState.I);
}
private static CacheControllerFiniteStateMachineFactory singleton;
/**
* Get the L1 cache controller finite state machine factory singleton.
*
* @return the L1 cache controller finite state machine factory singleton
*/
public static CacheControllerFiniteStateMachineFactory getSingleton() {
if (singleton == null) {
singleton = new CacheControllerFiniteStateMachineFactory();
}
return singleton;
}
}