/** * **************************************************************************** * 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.functionalUnit; import archimulator.common.Named; import archimulator.core.AbstractBasicCore; import archimulator.core.ReorderBufferEntry; import java.util.EnumMap; import java.util.EnumSet; /** * Functional unit pool. * * @author Min Cai */ public class FunctionalUnitPool implements Named { private EnumMap<FunctionalUnitType, FunctionalUnitDescriptor> descriptors; private EnumMap<FunctionalUnitOperationType, FunctionalUnitType> functionalUnitOperationToFunctionalUnitMap; private AbstractBasicCore core; private EnumMap<FunctionalUnitType, Long> numStallsOnNoFreeFunctionalUnit; private EnumMap<FunctionalUnitOperationType, Long> numStallsOnAcquireFailedOnNoFreeFunctionalUnit; /** * Create a functional unit pool. * * @param core the core */ public FunctionalUnitPool(AbstractBasicCore core) { this.core = core; this.descriptors = new EnumMap<>(FunctionalUnitType.class); this.functionalUnitOperationToFunctionalUnitMap = new EnumMap<>(FunctionalUnitOperationType.class); this.addFunctionalUnitDescriptor(FunctionalUnitType.INTEGER_ALU, 8) .addFunctionalUnitOperation(FunctionalUnitOperationType.INT_ALU, 2, 1); this.addFunctionalUnitDescriptor(FunctionalUnitType.INTEGER_MULTIPLY_DIVIDE, 2) .addFunctionalUnitOperation(FunctionalUnitOperationType.INT_MULTIPLY, 3, 1) .addFunctionalUnitOperation(FunctionalUnitOperationType.INT_DIVIDE, 20, 19); this.addFunctionalUnitDescriptor(FunctionalUnitType.FLOAT_ADD, 8) .addFunctionalUnitOperation(FunctionalUnitOperationType.FLOAT_ADD, 4, 1) .addFunctionalUnitOperation(FunctionalUnitOperationType.FLOAT_COMPARE, 4, 1) .addFunctionalUnitOperation(FunctionalUnitOperationType.FLOAT_CONVERT, 4, 1); this.addFunctionalUnitDescriptor(FunctionalUnitType.FLOAT_MULTIPLY_DIVIDE, 2) .addFunctionalUnitOperation(FunctionalUnitOperationType.FLOAT_MULTIPLY, 8, 1) .addFunctionalUnitOperation(FunctionalUnitOperationType.FLOAT_DIVIDE, 40, 20) .addFunctionalUnitOperation(FunctionalUnitOperationType.FLOAT_SQRT, 80, 40); this.addFunctionalUnitDescriptor(FunctionalUnitType.MEMORY_PORT, 4) .addFunctionalUnitOperation(FunctionalUnitOperationType.READ_PORT, 1, 1) .addFunctionalUnitOperation(FunctionalUnitOperationType.WRITE_PORT, 1, 1); this.numStallsOnNoFreeFunctionalUnit = new EnumMap<>(FunctionalUnitType.class); EnumSet<FunctionalUnitType> fuTypes = EnumSet.allOf(FunctionalUnitType.class); for (FunctionalUnitType fuTye : fuTypes) { this.numStallsOnNoFreeFunctionalUnit.put(fuTye, 0L); } this.numStallsOnAcquireFailedOnNoFreeFunctionalUnit = new EnumMap<>(FunctionalUnitOperationType.class); EnumSet<FunctionalUnitOperationType> fuOperationTypes = EnumSet.allOf(FunctionalUnitOperationType.class); for (FunctionalUnitOperationType fuOperationType : fuOperationTypes) { this.numStallsOnAcquireFailedOnNoFreeFunctionalUnit.put(fuOperationType, 0L); } } /** * Add a functional unit descriptor. * * @param type the functional unit type * @param quantity the quantity * @return the newly added functional unit descriptor */ private FunctionalUnitDescriptor addFunctionalUnitDescriptor(FunctionalUnitType type, int quantity) { FunctionalUnitDescriptor desc = new FunctionalUnitDescriptor(this, type, quantity); this.descriptors.put(type, desc); return desc; } /** * Acquire. * * @param reorderBufferEntry the reorder buffer entry * @param onCompletedCallback the callback action performed when the operation is completed * @return a value indicating whether the acquiring succeeds or not */ public boolean acquire(final ReorderBufferEntry reorderBufferEntry, final Runnable onCompletedCallback) { FunctionalUnitOperationType functionalUnitOperationType = reorderBufferEntry.getDynamicInstruction().getStaticInstruction().getMnemonic().getFunctionalUnitOperationType(); FunctionalUnitType functionalUnitType = this.functionalUnitOperationToFunctionalUnitMap.get(functionalUnitOperationType); FunctionalUnitOperation functionalUnitOperation = this.descriptors.get(functionalUnitType).getOperations().get(functionalUnitOperationType); final FunctionalUnitDescriptor functionalUnitDescriptor = this.descriptors.get(functionalUnitType); if (functionalUnitDescriptor.isFull()) { this.numStallsOnAcquireFailedOnNoFreeFunctionalUnit.put( functionalUnitOperationType, this.numStallsOnAcquireFailedOnNoFreeFunctionalUnit.get(functionalUnitOperationType) + 1 ); return false; } this.core.getCycleAccurateEventQueue() .schedule(this, () -> functionalUnitDescriptor.setNumFree(functionalUnitDescriptor.getNumFree() + 1), functionalUnitOperation.getIssueLatency()) .schedule(this, () -> { if (!reorderBufferEntry.isSquashed()) { onCompletedCallback.run(); } }, functionalUnitOperation.getOperationLatency()); functionalUnitDescriptor.setNumFree(functionalUnitDescriptor.getNumFree() - 1); return true; } /** * Release all functional unit descriptors. */ public void releaseAll() { this.descriptors.values().forEach(FunctionalUnitDescriptor::releaseAll); } /** * Update statistics per cycle. */ public void updatePerCycleStats() { FunctionalUnitPool.this.numStallsOnNoFreeFunctionalUnit.keySet().stream().filter(fuType -> this.descriptors.get(fuType).isFull()).forEach(fuType -> { this.numStallsOnNoFreeFunctionalUnit.put(fuType, this.numStallsOnNoFreeFunctionalUnit.get(fuType) + 1); }); } /** * Get the map of descriptors. * * @return the map of descriptors */ public EnumMap<FunctionalUnitType, FunctionalUnitDescriptor> getDescriptors() { return descriptors; } /** * Get the map of functional unit operation types to functional unit types. * * @return the map of functional unit operation types to functional unit types */ public EnumMap<FunctionalUnitOperationType, FunctionalUnitType> getFunctionalUnitOperationToFunctionalUnitMap() { return functionalUnitOperationToFunctionalUnitMap; } /** * Get the map of the numbers of stalls when there is no free functional unit for a specific functional unit type. * * @return the map of the numbers of stalls when there is no free functional unit for a specific functional unit type */ public EnumMap<FunctionalUnitType, Long> getNumStallsOnNoFreeFunctionalUnit() { return numStallsOnNoFreeFunctionalUnit; } /** * Get the map of the numbers of stalls on acquiring failed when there is no free functional unit for a specific functional unit type. * * @return the map of the numbers of stalls on acquiring failed when there is no free functional unit for a specific functional unit type */ public EnumMap<FunctionalUnitOperationType, Long> getNumStallsOnAcquireFailedOnNoFreeFunctionalUnit() { return numStallsOnAcquireFailedOnNoFreeFunctionalUnit; } @Override public String getName() { return core.getName() + "/functionalUnitPool"; } }