/**
* ****************************************************************************
* 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.directory.*;
import archimulator.uncore.coherence.msi.state.DirectoryControllerState;
import archimulator.util.fsm.FiniteStateMachineFactory;
import java.util.List;
import java.util.function.Consumer;
import java.util.stream.Collectors;
import static ch.lambdaj.Lambda.*;
import static org.hamcrest.Matchers.not;
/**
* Directory controller finite state machine factory.
*
* @author Min Cai
*/
public class DirectoryControllerFiniteStateMachineFactory extends FiniteStateMachineFactory<DirectoryControllerState, DirectoryControllerEventType, DirectoryControllerFiniteStateMachine> {
/**
* Create a directory controller finite state machine factory.
*/
private DirectoryControllerFiniteStateMachineFactory() {
Consumer<DirectoryControllerFiniteStateMachine> actionWhenStateChanged = fsm -> {
if (fsm.getPreviousState() != fsm.getState() && fsm.getState().isStable()) {
Runnable onCompletedCallback = fsm.getOnCompletedCallback();
if (onCompletedCallback != null) {
fsm.setOnCompletedCallback(null);
onCompletedCallback.run();
}
}
if (fsm.getPreviousState() != fsm.getState()) {
List<Runnable> stalledEventsToProcess = fsm.getStalledEvents().stream().collect(Collectors.toList());
fsm.getStalledEvents().clear();
stalledEventsToProcess.forEach(Runnable::run);
}
};
this.inState(DirectoryControllerState.I)
.setOnCompletedCallback(actionWhenStateChanged)
.onCondition(DirectoryControllerEventType.GETS, (fsm, sender, eventType, params) -> {
GetSEvent event = (GetSEvent) params;
fsm.getDirectoryController().incrementNumPendingMemoryAccesses();
fsm.getDirectoryController().transfer(fsm.getDirectoryController().getNext(), 8, () -> {
fsm.getDirectoryController().getNext().memReadRequestReceive(fsm.getDirectoryController(), event.getTag(), () -> fsm.getDirectoryController().getCycleAccurateEventQueue().schedule(fsm.getDirectoryController(), () -> {
fsm.getDirectoryController().decrementNumPendingMemoryAccesses();
DataFromMemEvent dataFromMemEvent = new DataFromMemEvent(fsm.getDirectoryController(), event, event.getRequester(), event.getTag(), event.getAccess());
fsm.fireTransition(fsm.getDirectoryController().getNext() + "." + String.format("0x%08x", event.getTag()), dataFromMemEvent);
}, fsm.getDirectoryController().getHitLatency()));
});
fsm.fireServiceNonblockingRequestEvent(event.getAccess(), event.getTag(), false);
fsm.getLine().setAccess(event.getAccess());
fsm.getLine().setTag(event.getTag());
}, DirectoryControllerState.IS_D)
.onCondition(DirectoryControllerEventType.GETM, (fsm, sender, eventType, params) -> {
GetMEvent event = (GetMEvent) params;
fsm.getDirectoryController().incrementNumPendingMemoryAccesses();
fsm.getDirectoryController().transfer(fsm.getDirectoryController().getNext(), 8, () -> {
fsm.getDirectoryController().getNext().memReadRequestReceive(fsm.getDirectoryController(), event.getTag(), () -> fsm.getDirectoryController().getCycleAccurateEventQueue().schedule(fsm.getDirectoryController(), () -> {
fsm.getDirectoryController().decrementNumPendingMemoryAccesses();
DataFromMemEvent dataFromMemEvent = new DataFromMemEvent(fsm.getDirectoryController(), event, event.getRequester(), event.getTag(), event.getAccess());
fsm.fireTransition(fsm.getDirectoryController().getNext() + "." + String.format("0x%08x", event.getTag()), dataFromMemEvent);
}, fsm.getDirectoryController().getHitLatency()));
});
fsm.fireServiceNonblockingRequestEvent(event.getAccess(), event.getTag(), false);
fsm.getLine().setAccess(event.getAccess());
fsm.getLine().setTag(event.getTag());
}, DirectoryControllerState.IM_D);
this.inState(DirectoryControllerState.IS_D)
.setOnCompletedCallback(actionWhenStateChanged)
.onCondition(DirectoryControllerEventType.GETS, (fsm, sender, eventType, params) -> {
GetSEvent event = (GetSEvent) params;
fsm.stall(event.getOnStalledCallback());
fsm.fireNonblockingRequestHitToTransientTagEvent(event.getAccess(), event.getTag());
}, DirectoryControllerState.IS_D)
.onCondition(DirectoryControllerEventType.GETM, (fsm, sender, eventType, params) -> {
GetMEvent event = (GetMEvent) params;
fsm.stall(event.getOnStalledCallback());
fsm.fireNonblockingRequestHitToTransientTagEvent(event.getAccess(), event.getTag());
}, DirectoryControllerState.IS_D)
.onCondition(DirectoryControllerEventType.REPLACEMENT, (fsm, sender, eventType, params) -> {
ReplacementEvent event = (ReplacementEvent) params;
fsm.stall(event.getOnStalledCallback());
}, DirectoryControllerState.IS_D)
.onCondition(DirectoryControllerEventType.PUTS_NOT_LAST, (fsm, sender, eventType, params) -> {
PutSNotLastEvent event = (PutSNotLastEvent) params;
fsm.stall(sender, event);
}, DirectoryControllerState.IS_D)
.onCondition(DirectoryControllerEventType.PUTS_LAST, (fsm, sender, eventType, params) -> {
PutSLastEvent event = (PutSLastEvent) params;
fsm.stall(sender, event);
}, DirectoryControllerState.IS_D)
.onCondition(DirectoryControllerEventType.PUTM_AND_DATA_FROM_NONOWNER, (fsm, sender, eventType, params) -> {
PutMAndDataFromNonOwnerEvent event = (PutMAndDataFromNonOwnerEvent) params;
fsm.stall(sender, event);
}, DirectoryControllerState.IS_D)
.onCondition(DirectoryControllerEventType.DATA_FROM_MEM, (fsm, sender, eventType, params) -> {
DataFromMemEvent event = (DataFromMemEvent) params;
fsm.sendDataToRequester(event, event.getRequester(), event.getTag(), 0);
fsm.addRequesterToSharers(event.getRequester());
fsm.fireCacheLineInsertEvent(event.getAccess(), event.getTag(), fsm.getVictimTag());
fsm.setEvicterTag(CacheLine.INVALID_TAG);
fsm.setVictimTag(CacheLine.INVALID_TAG);
fsm.getDirectoryController().getCache().getReplacementPolicy().handleInsertionOnMiss(event.getAccess(), fsm.getSet(), fsm.getWay());
}, DirectoryControllerState.S);
this.inState(DirectoryControllerState.IM_D)
.setOnCompletedCallback(actionWhenStateChanged)
.onCondition(DirectoryControllerEventType.GETS, (fsm, sender, eventType, params) -> {
GetSEvent event = (GetSEvent) params;
fsm.stall(event.getOnStalledCallback());
fsm.fireNonblockingRequestHitToTransientTagEvent(event.getAccess(), event.getTag());
}, DirectoryControllerState.IM_D)
.onCondition(DirectoryControllerEventType.GETM, (fsm, sender, eventType, params) -> {
GetMEvent event = (GetMEvent) params;
fsm.stall(event.getOnStalledCallback());
fsm.fireNonblockingRequestHitToTransientTagEvent(event.getAccess(), event.getTag());
}, DirectoryControllerState.IM_D)
.onCondition(DirectoryControllerEventType.REPLACEMENT, (fsm, sender, eventType, params) -> {
ReplacementEvent event = (ReplacementEvent) params;
fsm.stall(event.getOnStalledCallback());
}, DirectoryControllerState.IM_D)
.onCondition(DirectoryControllerEventType.PUTS_NOT_LAST, (fsm, sender, eventType, params) -> {
PutSNotLastEvent event = (PutSNotLastEvent) params;
fsm.stall(sender, event);
}, DirectoryControllerState.IM_D)
.onCondition(DirectoryControllerEventType.PUTS_LAST, (fsm, sender, eventType, params) -> {
PutSLastEvent event = (PutSLastEvent) params;
fsm.stall(sender, event);
}, DirectoryControllerState.IM_D)
.onCondition(DirectoryControllerEventType.PUTM_AND_DATA_FROM_NONOWNER, (fsm, sender, eventType, params) -> {
PutMAndDataFromNonOwnerEvent event = (PutMAndDataFromNonOwnerEvent) params;
fsm.stall(sender, event);
}, DirectoryControllerState.IM_D)
.onCondition(DirectoryControllerEventType.DATA_FROM_MEM, (fsm, sender, eventType, params) -> {
DataFromMemEvent event = (DataFromMemEvent) params;
fsm.sendDataToRequester(event, event.getRequester(), event.getTag(), 0);
fsm.setOwnerToRequester(event.getRequester());
fsm.fireCacheLineInsertEvent(event.getAccess(), event.getTag(), fsm.getVictimTag());
fsm.setEvicterTag(CacheLine.INVALID_TAG);
fsm.setVictimTag(CacheLine.INVALID_TAG);
fsm.getDirectoryController().getCache().getReplacementPolicy().handleInsertionOnMiss(event.getAccess(), fsm.getSet(), fsm.getWay());
}, DirectoryControllerState.M);
this.inState(DirectoryControllerState.S)
.setOnCompletedCallback(actionWhenStateChanged)
.onCondition(DirectoryControllerEventType.GETS, (fsm, sender, eventType, params) -> {
GetSEvent event = (GetSEvent) params;
fsm.sendDataToRequester(event, event.getRequester(), event.getTag(), 0);
fsm.addRequesterToSharers(event.getRequester());
fsm.hit(event.getAccess(), event.getTag(), event.getSet(), event.getWay());
}, DirectoryControllerState.S)
.onCondition(DirectoryControllerEventType.GETM, (fsm, sender, eventType, params) -> {
GetMEvent event = (GetMEvent) params;
fsm.sendDataToRequester(event, event.getRequester(), event.getTag(), select(fsm.getDirectoryEntry().getSharers(), having(on(CacheController.class), not(event.getRequester()))).size());
fsm.sendInvToSharers(event, event.getRequester(), event.getTag());
fsm.clearSharers();
fsm.setOwnerToRequester(event.getRequester());
fsm.hit(event.getAccess(), event.getTag(), event.getSet(), event.getWay());
}, DirectoryControllerState.M)
.onCondition(DirectoryControllerEventType.REPLACEMENT, (fsm, sender, eventType, params) -> {
ReplacementEvent event = (ReplacementEvent) params;
fsm.setNumRecallAcks(fsm.getDirectoryEntry().getSharers().size());
fsm.sendRecallToSharers(event, fsm.getLine().getTag());
fsm.clearSharers();
fsm.setOnCompletedCallback(event.getOnCompletedCallback());
fsm.fireReplacementEvent(event.getAccess(), event.getTag());
fsm.setEvicterTag(event.getTag());
fsm.setVictimTag(fsm.getLine().getTag());
fsm.getDirectoryController().incrementNumEvictions();
}, DirectoryControllerState.SI_A)
.onCondition(DirectoryControllerEventType.PUTS_NOT_LAST, (fsm, sender, eventType, params) -> {
PutSNotLastEvent event = (PutSNotLastEvent) params;
fsm.removeRequesterFromSharers(event.getRequester());
fsm.sendPutAckToReq(event, event.getRequester(), event.getTag());
}, DirectoryControllerState.S)
.onCondition(DirectoryControllerEventType.PUTS_LAST, (fsm, sender, eventType, params) -> {
PutSLastEvent event = (PutSLastEvent) params;
fsm.removeRequesterFromSharers(event.getRequester());
fsm.sendPutAckToReq(event, event.getRequester(), event.getTag());
fsm.firePutSOrPutMAndDataFromOwnerEvent(event.getAccess(), event.getTag());
fsm.getLine().setAccess(null);
fsm.getLine().setTag(CacheLine.INVALID_TAG);
}, DirectoryControllerState.I)
.onCondition(DirectoryControllerEventType.PUTM_AND_DATA_FROM_NONOWNER, (fsm, sender, eventType, params) -> {
PutMAndDataFromNonOwnerEvent event = (PutMAndDataFromNonOwnerEvent) params;
fsm.removeRequesterFromSharers(event.getRequester());
fsm.sendPutAckToReq(event, event.getRequester(), event.getTag());
}, DirectoryControllerState.S);
this.inState(DirectoryControllerState.M)
.setOnCompletedCallback(actionWhenStateChanged)
.onCondition(DirectoryControllerEventType.GETS, (fsm, sender, eventType, params) -> {
GetSEvent event = (GetSEvent) params;
fsm.sendFwdGetSToOwner(event, event.getRequester(), event.getTag());
fsm.addRequesterAndOwnerToSharers(event.getRequester());
fsm.clearOwner();
fsm.hit(event.getAccess(), event.getTag(), event.getSet(), event.getWay());
}, DirectoryControllerState.S_D)
.onCondition(DirectoryControllerEventType.GETM, (fsm, sender, eventType, params) -> {
GetMEvent event = (GetMEvent) params;
fsm.sendFwdGetMToOwner(event, event.getRequester(), event.getTag());
fsm.setOwnerToRequester(event.getRequester());
fsm.hit(event.getAccess(), event.getTag(), event.getSet(), event.getWay());
}, DirectoryControllerState.M)
.onCondition(DirectoryControllerEventType.REPLACEMENT, (fsm, sender, eventType, params) -> {
ReplacementEvent event = (ReplacementEvent) params;
fsm.setNumRecallAcks(1);
fsm.sendRecallToOwner(event, fsm.getLine().getTag());
fsm.clearOwner();
fsm.setOnCompletedCallback(event.getOnCompletedCallback());
fsm.fireReplacementEvent(event.getAccess(), event.getTag());
fsm.setEvicterTag(event.getTag());
fsm.setVictimTag(fsm.getLine().getTag());
fsm.getDirectoryController().incrementNumEvictions();
}, DirectoryControllerState.MI_A)
.onCondition(DirectoryControllerEventType.PUTS_NOT_LAST, (fsm, sender, eventType, params) -> {
PutSNotLastEvent event = (PutSNotLastEvent) params;
fsm.sendPutAckToReq(event, event.getRequester(), event.getTag());
}, DirectoryControllerState.M)
.onCondition(DirectoryControllerEventType.PUTS_LAST, (fsm, sender, eventType, params) -> {
PutSLastEvent event = (PutSLastEvent) params;
fsm.sendPutAckToReq(event, event.getRequester(), event.getTag());
}, DirectoryControllerState.M)
.onCondition(DirectoryControllerEventType.PUTM_AND_DATA_FROM_OWNER, (fsm, sender, eventType, params) -> {
PutMAndDataFromOwnerEvent event = (PutMAndDataFromOwnerEvent) params;
fsm.copyDataToMem(event.getTag());
fsm.clearOwner();
fsm.sendPutAckToReq(event, event.getRequester(), event.getTag());
fsm.firePutSOrPutMAndDataFromOwnerEvent(event.getAccess(), event.getTag());
fsm.getLine().setAccess(null);
fsm.getLine().setTag(CacheLine.INVALID_TAG);
}, DirectoryControllerState.I)
.onCondition(DirectoryControllerEventType.PUTM_AND_DATA_FROM_NONOWNER, (fsm, sender, eventType, params) -> {
PutMAndDataFromNonOwnerEvent event = (PutMAndDataFromNonOwnerEvent) params;
fsm.sendPutAckToReq(event, event.getRequester(), event.getTag());
}, DirectoryControllerState.M);
this.inState(DirectoryControllerState.S_D)
.setOnCompletedCallback(actionWhenStateChanged)
.onCondition(DirectoryControllerEventType.GETS, (fsm, sender, eventType, params) -> {
GetSEvent event = (GetSEvent) params;
fsm.stall(event.getOnStalledCallback());
}, DirectoryControllerState.S_D)
.onCondition(DirectoryControllerEventType.GETM, (fsm, sender, eventType, params) -> {
GetMEvent event = (GetMEvent) params;
fsm.stall(event.getOnStalledCallback());
}, DirectoryControllerState.S_D)
.onCondition(DirectoryControllerEventType.REPLACEMENT, (fsm, sender, eventType, params) -> {
ReplacementEvent event = (ReplacementEvent) params;
fsm.stall(event.getOnStalledCallback());
}, DirectoryControllerState.S_D)
.onCondition(DirectoryControllerEventType.PUTS_NOT_LAST, (fsm, sender, eventType, params) -> {
PutSNotLastEvent event = (PutSNotLastEvent) params;
fsm.removeRequesterFromSharers(event.getRequester());
fsm.sendPutAckToReq(event, event.getRequester(), event.getTag());
}, DirectoryControllerState.S_D)
.onCondition(DirectoryControllerEventType.PUTS_LAST, (fsm, sender, eventType, params) -> {
PutSLastEvent event = (PutSLastEvent) params;
fsm.removeRequesterFromSharers(event.getRequester());
fsm.sendPutAckToReq(event, event.getRequester(), event.getTag());
}, DirectoryControllerState.S_D)
.onCondition(DirectoryControllerEventType.PUTM_AND_DATA_FROM_NONOWNER, (fsm, sender, eventType, params) -> {
PutMAndDataFromNonOwnerEvent event = (PutMAndDataFromNonOwnerEvent) params;
fsm.removeRequesterFromSharers(event.getRequester());
fsm.sendPutAckToReq(event, event.getRequester(), event.getTag());
}, DirectoryControllerState.S_D)
.onCondition(DirectoryControllerEventType.DATA, (fsm, sender, eventType, params) -> {
DataEvent event = (DataEvent) params;
fsm.copyDataToMem(event.getTag());
}, DirectoryControllerState.S);
this.inState(DirectoryControllerState.MI_A)
.setOnCompletedCallback(actionWhenStateChanged)
.onCondition(DirectoryControllerEventType.GETS, (fsm, sender, eventType, params) -> {
GetSEvent event = (GetSEvent) params;
fsm.stall(event.getOnStalledCallback());
}, DirectoryControllerState.MI_A)
.onCondition(DirectoryControllerEventType.GETM, (fsm, sender, eventType, params) -> {
GetMEvent event = (GetMEvent) params;
fsm.stall(event.getOnStalledCallback());
}, DirectoryControllerState.MI_A)
.onCondition(DirectoryControllerEventType.REPLACEMENT, (fsm, sender, eventType, params) -> {
ReplacementEvent event = (ReplacementEvent) params;
fsm.stall(event.getOnStalledCallback());
}, DirectoryControllerState.MI_A)
.onCondition(DirectoryControllerEventType.RECALL_ACK, (fsm, sender, eventType, params) -> fsm.decrementRecallAcks(), DirectoryControllerState.MI_A)
.onCondition(DirectoryControllerEventType.LAST_RECALL_ACK, (fsm, sender, eventType, params) -> {
LastRecallAckEvent event = (LastRecallAckEvent) params;
fsm.copyDataToMem(event.getTag());
fsm.getLine().setAccess(null);
fsm.getLine().setTag(CacheLine.INVALID_TAG);
}, DirectoryControllerState.I)
.onCondition(DirectoryControllerEventType.PUTS_NOT_LAST, (fsm, sender, eventType, params) -> {
PutSNotLastEvent event = (PutSNotLastEvent) params;
fsm.sendPutAckToReq(event, event.getRequester(), event.getTag());
}, DirectoryControllerState.MI_A)
.onCondition(DirectoryControllerEventType.PUTS_LAST, (fsm, sender, eventType, params) -> {
PutSLastEvent event = (PutSLastEvent) params;
fsm.sendPutAckToReq(event, event.getRequester(), event.getTag());
}, DirectoryControllerState.MI_A)
.onCondition(DirectoryControllerEventType.PUTM_AND_DATA_FROM_NONOWNER, (fsm, sender, eventType, params) -> {
PutMAndDataFromNonOwnerEvent event = (PutMAndDataFromNonOwnerEvent) params;
fsm.sendPutAckToReq(event, event.getRequester(), event.getTag());
}, DirectoryControllerState.MI_A);
this.inState(DirectoryControllerState.SI_A)
.setOnCompletedCallback(actionWhenStateChanged)
.onCondition(DirectoryControllerEventType.GETS, (fsm, sender, eventType, params) -> {
GetSEvent event = (GetSEvent) params;
fsm.stall(event.getOnStalledCallback());
}, DirectoryControllerState.SI_A)
.onCondition(DirectoryControllerEventType.GETM, (fsm, sender, eventType, params) -> {
GetMEvent event = (GetMEvent) params;
fsm.stall(event.getOnStalledCallback());
}, DirectoryControllerState.SI_A)
.onCondition(DirectoryControllerEventType.REPLACEMENT, (fsm, sender, eventType, params) -> {
ReplacementEvent event = (ReplacementEvent) params;
fsm.stall(event.getOnStalledCallback());
}, DirectoryControllerState.SI_A)
.onCondition(DirectoryControllerEventType.RECALL_ACK, (fsm, sender, eventType, params) -> fsm.decrementRecallAcks(), DirectoryControllerState.SI_A)
.onCondition(DirectoryControllerEventType.LAST_RECALL_ACK, (fsm, sender, eventType, params) -> {
fsm.getLine().setAccess(null);
fsm.getLine().setTag(CacheLine.INVALID_TAG);
}, DirectoryControllerState.I)
.onCondition(DirectoryControllerEventType.PUTS_NOT_LAST, (fsm, sender, eventType, params) -> {
PutSNotLastEvent event = (PutSNotLastEvent) params;
fsm.sendPutAckToReq(event, event.getRequester(), event.getTag());
}, DirectoryControllerState.SI_A)
.onCondition(DirectoryControllerEventType.PUTS_LAST, (fsm, sender, eventType, params) -> {
PutSLastEvent event = (PutSLastEvent) params;
fsm.sendPutAckToReq(event, event.getRequester(), event.getTag());
}, DirectoryControllerState.SI_A)
.onCondition(DirectoryControllerEventType.PUTM_AND_DATA_FROM_NONOWNER, (fsm, sender, eventType, params) -> {
PutMAndDataFromNonOwnerEvent event = (PutMAndDataFromNonOwnerEvent) params;
fsm.sendPutAckToReq(event, event.getRequester(), event.getTag());
}, DirectoryControllerState.SI_A);
}
private static DirectoryControllerFiniteStateMachineFactory singleton;
/**
* Get the directory controller finite state machine factory singleton.
*
* @return the directory controller finite state machine factory singleton
*/
public static DirectoryControllerFiniteStateMachineFactory getSingleton() {
if (singleton == null) {
singleton = new DirectoryControllerFiniteStateMachineFactory();
}
return singleton;
}
}