/** * **************************************************************************** * 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.bpred; import java.util.ArrayList; import java.util.List; /** * Branch target buffer. * * @author Min Cai */ public class BranchTargetBuffer { private List<List<BranchTargetBufferEntry>> entries; /** * Create a branch target buffer. * * @param numSets the number of sets * @param associativity associativity */ public BranchTargetBuffer(int numSets, int associativity) { this.entries = new ArrayList<>(); for (int i = 0; i < numSets; i++) { List<BranchTargetBufferEntry> entriesPerSet = new ArrayList<>(); for (int j = 0; j < associativity; j++) { entriesPerSet.add(new BranchTargetBufferEntry()); } this.entries.add(entriesPerSet); } } /** * Lookup the branch target buffer entry for the specified branch address. * * @param branchAddress the branch address * @return the branch target buffer entry matching the specified branch address */ public BranchTargetBufferEntry lookup(int branchAddress) { int set = this.getSet(branchAddress); for (BranchTargetBufferEntry branchTargetBufferEntry : this.entries.get(set)) { if (branchTargetBufferEntry.getSource() == branchAddress) { return branchTargetBufferEntry; } } return null; } /** * Update. * * @param branchAddress the branch address * @param branchTarget the branch target * @param taken a value indicating whether the branch is taken or not * @return the branch target buffer entry matching the specified branch address */ public BranchTargetBufferEntry update(int branchAddress, int branchTarget, boolean taken) { if (!taken) { return null; } int set = this.getSet(branchAddress); if (this.entries.get(set).size() == 1) { return this.entries.get(set).get(0); } BranchTargetBufferEntry entryFound = null; for (BranchTargetBufferEntry entry : this.entries.get(set)) { if (entry.getSource() == branchAddress) { entryFound = entry; break; } } if (entryFound == null) { entryFound = this.entries.get(set).get(this.entries.get(set).size() - 1); //LRU entryFound.setSource(branchAddress); } entryFound.setTarget(branchTarget); this.entries.get(set).remove(entryFound); this.entries.get(set).add(0, entryFound); //MRU return entryFound; } /** * Get the set index for the specified branch address * * @param branchAddress the branch address * @return the set index for the specified branch address */ private int getSet(int branchAddress) { return branchAddress >> BranchPredictor.BRANCH_SHIFT & (this.entries.size() - 1); } }