/*
This file is part of JOP, the Java Optimized Processor
see <http://www.jopdesign.com/>
Copyright (C) 2011, Benedikt Huber (benedikt@vmars.tuwien.ac.at)
This program 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.
This program 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.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.jopdesign.wcet.jop;
import org.apache.bcel.Constants;
import org.apache.bcel.generic.Instruction;
import org.apache.bcel.generic.InvokeInstruction;
import org.apache.bcel.generic.Type;
import com.jopdesign.common.MethodInfo;
import com.jopdesign.common.code.ControlFlowGraph;
import com.jopdesign.common.config.OptionGroup;
import com.jopdesign.common.processormodel.JOPConfig;
import com.jopdesign.timing.MethodCacheTiming;
import com.jopdesign.wcet.WCETProcessorModel;
import com.jopdesign.wcet.WCETTool;
/**
* Purpose: Base class for method cache implementations
*
*/
public abstract class MethodCacheImplementation implements MethodCache {
public static MethodCache getCacheModel(WCETTool p, MethodCacheTiming timing) {
OptionGroup options = JOPConfig.getOptions(p.getConfig());
switch (options.getOption(JOPConfig.CACHE_IMPL)) {
case NO_METHOD_CACHE:
return new NoMethodCache();
case LRU_CACHE:
return BlockCache.fromConfig(p, timing, true);
case FIFO_CACHE:
return BlockCache.fromConfig(p, timing, false);
case LRU_VARBLOCK_CACHE:
return VarBlockCache.fromConfig(p, timing, true);
case FIFO_VARBLOCK_CACHE:
return VarBlockCache.fromConfig(p, timing, false);
default:
throw new AssertionError("Non-exhaustive match on enum: CACHE_IMPL: " +
options.getOption(JOPConfig.CACHE_IMPL));
}
}
protected WCETTool project;
protected MethodCacheTiming timing;
protected int cacheSizeWords;
public MethodCacheImplementation(WCETTool p, MethodCacheTiming timing, int cacheSizeWords) {
this.project = p;
this.timing = timing;
this.cacheSizeWords = cacheSizeWords;
}
@Override
public long getSizeInWords() {
return cacheSizeWords;
}
@Override
public int requiredNumberOfBlocks(MethodInfo mi) {
return requiredNumberOfBlocks(project.getSizeInWords(mi));
}
public long getMaxMissCost(ControlFlowGraph cfg) {
long invokeCost = getMissPenalty(cfg.getNumberOfWords(), true);
if (!cfg.isLeafMethod()) return Math.max(invokeCost, getMissOnReturnCost(cfg));
else return invokeCost;
}
/**
* Get miss penalty for invoking the given method
*/
public long getMissOnInvokeCost(ControlFlowGraph cfg) {
return this.getMissPenalty(cfg.getNumberOfWords(), true);
}
/**
* Get miss penalty for returning to the given method
*/
public long getMissOnReturnCost(ControlFlowGraph cfg) {
return getMissPenalty(cfg.getNumberOfWords(), false);
}
/**
* Get an upper bound for the miss cost involved in invoking a method of length
* <pre>invokedBytes</pre> and returning to a method of length <pre>invokerBytes</pre>
*
* @param proc
* @param invoker
* @param invoked
* @return the maximal cache miss penalty for the invoke/return
*/
public long getInvokeReturnMissCost(WCETProcessorModel proc, ControlFlowGraph invoker, ControlFlowGraph invoked) {
return getMissPenalty(invoked.getNumberOfWords(), true) +
getMissPenalty(invoker.getNumberOfWords(), false);
}
/**
* @param words number of words to load
* @param loadOnInvoke whether this is an invoke or return instruction
* @return the maximum miss penalty for loading {@code words} words from method cache
*/
public long getMissPenalty(int words) {
return Math.max( getMissPenalty(words,true), getMissPenalty(words,false));
}
/**
* Compute the delay (in cycles) caused by a method cache miss
* @param invokeSite the invoke site
* @param words size of the loaded method in words
* @param isInvokeInstruction whether the load happens on invoke (cheaper on JOP)
* @return maximum difference between a hit and a miss, in cycles
*/
public long getMissPenalty(int words, boolean loadOnInvoke) {
return timing.getMethodCacheMissPenalty(words, loadOnInvoke);
}
/**
* @param invokeeWords number of words to load
* @param invokeInstruction the invoke instruction
* @return the maximum miss penalty for loading {@code words} words from method cache during {@code invokeInstruction}
*/
public long getMissPenaltyOnInvoke(int invokeeWords, Instruction invokeInstruction) {
return timing.getMethodCacheMissPenalty(invokeeWords, invokeInstruction.getOpcode());
}
/**
* @param invokerWords number of words to load
* @param invokeeRef reference to the invoked method
* @return
*/
@Override
public long getMissPenaltyOnReturn(int invokerWords, Type returnType) {
short opcode;
switch(returnType.getType()) {
case Constants.T_BOOLEAN :
case Constants.T_BYTE :
case Constants.T_CHAR :
case Constants.T_SHORT :
case Constants.T_INT : opcode = Constants.IRETURN; break;
case Constants.T_DOUBLE : opcode = Constants.DRETURN; break;
case Constants.T_FLOAT : opcode = Constants.FRETURN; break;
case Constants.T_LONG : opcode = Constants.LRETURN; break;
case Constants.T_ARRAY :
case Constants.T_REFERENCE : opcode = Constants.IRETURN; break;
case Constants.T_VOID: opcode = Constants.RETURN; break;
default: return getMissPenalty(invokerWords, false);
}
return timing.getMethodCacheMissPenalty(invokerWords, opcode);
}
}