/**
* ****************************************************************************
* 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.core;
import archimulator.core.functionalUnit.FunctionalUnitOperationType;
import archimulator.isa.StaticInstructionType;
import archimulator.os.ContextState;
import archimulator.util.Reference;
import archimulator.util.RoundRobinScheduler;
import java.util.Iterator;
import java.util.List;
/**
* Basic core.
*
* @author Min Cai
*/
public class BasicCore extends AbstractBasicCore {
private RoundRobinScheduler<Thread> registerRenameScheduler;
private RoundRobinScheduler<Thread> dispatchScheduler;
/**
* Create a basic core.
*
* @param processor the parent processor
* @param num the number of the core
*/
public BasicCore(Processor processor, int num) {
super(processor, num);
this.registerRenameScheduler = new RoundRobinScheduler<>(
this.threads,
thread -> {
if (thread.getContext() == null) {
return false;
} else if (thread.getDecodeBuffer().isEmpty()) {
thread.incrementNumRegisterRenameStallsOnDecodeBufferIsEmpty();
return false;
} else if (thread.getReorderBuffer().isFull()) {
thread.incrementNumRegisterRenameStallsOnReorderBufferIsFull();
return false;
} else {
return true;
}
},
Thread::registerRenameOne,
getExperiment().getConfig().getDecodeWidth()
);
this.dispatchScheduler = new RoundRobinScheduler<>(
this.threads,
thread -> thread.getContext() != null,
Thread::dispatchOne,
getExperiment().getConfig().getDecodeWidth()
);
}
@Override
protected void fetch() {
this.threads.stream().filter(
thread -> thread.getContext() != null && thread.getContext().getState() == ContextState.RUNNING
).forEach(Thread::fetch);
}
@Override
protected void registerRename() {
this.registerRenameScheduler.consumeNext();
}
@Override
protected void dispatch() {
this.dispatchScheduler.consumeNext();
}
@Override
protected void wakeUp() {
this.wakeUp(this.waitingInstructionQueue, this.readyInstructionQueue);
this.wakeUp(this.waitingStoreQueue, this.readyStoreQueue);
}
/**
* Wake up.
*
* @param waitingQueue the waiting queue
* @param readyQueue the ready queue
*/
private void wakeUp(List<AbstractReorderBufferEntry> waitingQueue, List<AbstractReorderBufferEntry> readyQueue) {
waitingQueue.stream().filter(AbstractReorderBufferEntry::isAllOperandReady).forEach(readyQueue::add);
waitingQueue.removeIf(AbstractReorderBufferEntry::isAllOperandReady);
}
@Override
protected void issue() {
Reference<Integer> quant = new Reference<>(getExperiment().getConfig().getIssueWidth());
this.issueInstructionQueue(quant);
this.issueLoadQueue(quant);
this.issueStoreQueue(quant);
}
/**
* Issue the instruction queue.
*
* @param quant the quant
*/
private void issueInstructionQueue(Reference<Integer> quant) {
for (Iterator<AbstractReorderBufferEntry> it = this.readyInstructionQueue.iterator(); quant.get() > 0 && it.hasNext(); ) {
final ReorderBufferEntry reorderBufferEntry = (ReorderBufferEntry) it.next();
if (reorderBufferEntry.getDynamicInstruction().getStaticInstruction().getMnemonic().getFunctionalUnitOperationType() != FunctionalUnitOperationType.NONE) {
if (this.functionalUnitPool.acquire(reorderBufferEntry, reorderBufferEntry::signalCompleted)) {
reorderBufferEntry.setIssued();
} else {
reorderBufferEntry.getThread().incrementNumSelectionStallsOnNoFreeFunctionalUnit();
continue;
}
} else {
reorderBufferEntry.setIssued();
reorderBufferEntry.setCompleted();
reorderBufferEntry.writeBack();
}
it.remove();
quant.set(quant.get() - 1);
}
}
/**
* Issue the load queue.
*
* @param quant the quant
*/
private void issueLoadQueue(Reference<Integer> quant) {
for (Iterator<AbstractReorderBufferEntry> it = this.readyLoadQueue.iterator(); quant.get() > 0 && it.hasNext(); ) {
final LoadStoreQueueEntry loadStoreQueueEntry = (LoadStoreQueueEntry) it.next();
boolean hitInLoadStoreQueue = loadStoreQueueEntry.getThread().getLoadStoreQueue().getEntries().stream().anyMatch(
loadStoreQueueEntryFound
-> loadStoreQueueEntryFound.getDynamicInstruction().getStaticInstruction().getMnemonic().getType() == StaticInstructionType.STORE
&& loadStoreQueueEntryFound.getEffectiveAddress() == loadStoreQueueEntry.getEffectiveAddress()
);
if (hitInLoadStoreQueue) {
loadStoreQueueEntry.setIssued();
loadStoreQueueEntry.signalCompleted();
} else {
if (!this.canLoad(loadStoreQueueEntry.getThread(), loadStoreQueueEntry.getEffectiveAddress())) {
loadStoreQueueEntry.getThread().incrementNumSelectionStallsOnCanNotLoad();
break;
}
this.load(
loadStoreQueueEntry.getDynamicInstruction(),
loadStoreQueueEntry.getEffectiveAddress(),
loadStoreQueueEntry.getDynamicInstruction().getPc(),
loadStoreQueueEntry::signalCompleted
);
loadStoreQueueEntry.setIssued();
}
it.remove();
quant.set(quant.get() - 1);
}
}
/**
* Issue the store queue.
*
* @param quant the store queue
*/
private void issueStoreQueue(Reference<Integer> quant) {
for (Iterator<AbstractReorderBufferEntry> it = this.readyStoreQueue.iterator(); quant.get() > 0 && it.hasNext(); ) {
final LoadStoreQueueEntry loadStoreQueueEntry = (LoadStoreQueueEntry) it.next();
if (!this.canStore(loadStoreQueueEntry.getThread(), loadStoreQueueEntry.getEffectiveAddress())) {
loadStoreQueueEntry.getThread().incrementNumSelectionStallsOnCanNotStore();
break;
}
this.store(loadStoreQueueEntry.getDynamicInstruction(), loadStoreQueueEntry.getEffectiveAddress(), loadStoreQueueEntry.getDynamicInstruction().getPc(), () -> {
// loadStoreQueueEntry.signalCompleted(); //TODO: should we need to wait for store to complete?
});
loadStoreQueueEntry.setIssued();
loadStoreQueueEntry.signalCompleted(); //TODO: should we need to wait for store to complete?
it.remove();
quant.set(quant.get() - 1);
}
}
@Override
protected void writeBack() {
for (AbstractReorderBufferEntry reorderBufferEntry : this.oooEventQueue) {
reorderBufferEntry.setCompleted();
reorderBufferEntry.writeBack();
}
this.oooEventQueue.clear();
}
@Override
protected void refreshLoadStoreQueue() {
this.threads.stream().filter(thread -> thread.getContext() != null).forEach(Thread::refreshLoadStoreQueue);
}
@Override
protected void commit() {
this.threads.stream().filter(thread -> thread.getContext() != null).forEach(Thread::commit);
}
}