801 lines
28 KiB
Java
Executable File
801 lines
28 KiB
Java
Executable File
/*****************************************************************************
|
|
Tejas Simulator
|
|
------------------------------------------------------------------------------------------------------------
|
|
|
|
Copyright [2010] [Indian Institute of Technology, Delhi]
|
|
Licensed under the Apache License, Version 2.0 (the "License");
|
|
you may not use this file except in compliance with the License.
|
|
You may obtain a copy of the License at
|
|
|
|
http://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
Unless required by applicable law or agreed to in writing, software
|
|
distributed under the License is distributed on an "AS IS" BASIS,
|
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
See the License for the specific language governing permissions and
|
|
limitations under the License.
|
|
------------------------------------------------------------------------------------------------------------
|
|
|
|
Contributors: Prathmesh Kallurkar
|
|
*****************************************************************************/
|
|
|
|
package emulatorinterface.translator.x86.objparser;
|
|
|
|
import emulatorinterface.DynamicInstructionBuffer;
|
|
import emulatorinterface.EmulatorPacketList;
|
|
import emulatorinterface.communication.Encoding;
|
|
import emulatorinterface.communication.Packet;
|
|
import emulatorinterface.translator.InvalidInstructionException;
|
|
import emulatorinterface.translator.qemuTranslationCache.TranslatedInstructionCache;
|
|
import emulatorinterface.translator.visaHandler.DynamicInstructionHandler;
|
|
import emulatorinterface.translator.visaHandler.VisaHandlerSelector;
|
|
import emulatorinterface.translator.x86.instruction.InstructionClass;
|
|
import emulatorinterface.translator.x86.instruction.InstructionClassTable;
|
|
import emulatorinterface.translator.x86.instruction.X86StaticInstructionHandler;
|
|
import emulatorinterface.translator.x86.operand.OperandTranslator;
|
|
import emulatorinterface.translator.x86.registers.Registers;
|
|
import emulatorinterface.translator.x86.registers.TempRegisterNum;
|
|
import generic.GenericCircularQueue;
|
|
import generic.Instruction;
|
|
import generic.InstructionList;
|
|
import generic.InstructionTable;
|
|
import generic.Operand;
|
|
import generic.OperationType;
|
|
import generic.Statistics;
|
|
import java.io.BufferedReader;
|
|
import java.io.IOException;
|
|
import java.io.InputStreamReader;
|
|
import java.util.StringTokenizer;
|
|
import java.util.regex.Matcher;
|
|
import java.util.regex.Pattern;
|
|
import config.EmulatorConfig;
|
|
import config.EmulatorType;
|
|
import main.CustomObjectPool;
|
|
import main.Main;
|
|
import misc.Error;
|
|
import misc.Numbers;
|
|
|
|
/**
|
|
* Objparser class contains methods to parse a static executable file and to
|
|
* determine the information of dynamic instructions. The x86 assembly code
|
|
* generated by objdump utility is first parsed to obtain operation, source
|
|
* operands and destination operand. The x86 CISC operations are broken down
|
|
* into corresponding simpler micro-operations which follow load-store
|
|
* architecture. We store the linear address of the instruction and the
|
|
* corresponding micro-operations in a hash-table for faster access to
|
|
* instruction information later on..
|
|
*
|
|
* @author prathmesh
|
|
*/
|
|
public class ObjParser
|
|
{
|
|
private static InstructionTable ciscIPtoRiscIP = null;
|
|
private static InstructionList staticMicroOpList = null;
|
|
private static InstructionList threadMicroOpsList[] = null;
|
|
|
|
public static void initializeThreadMicroOpsList(int maxApplicationThreads) {
|
|
threadMicroOpsList = new InstructionList[maxApplicationThreads];
|
|
|
|
for(int i=0; i<maxApplicationThreads; i++) {
|
|
threadMicroOpsList[i] = new InstructionList(10000);
|
|
}
|
|
}
|
|
|
|
private static DynamicInstructionBuffer[] staticDynamicInstructionBuffers;
|
|
public static void initializeDynamicInstructionBuffer(int maxApplicationThreads) {
|
|
staticDynamicInstructionBuffers = new DynamicInstructionBuffer[maxApplicationThreads];
|
|
|
|
for(int i=0; i<maxApplicationThreads; i++) {
|
|
staticDynamicInstructionBuffers[i] = new DynamicInstructionBuffer();
|
|
}
|
|
}
|
|
|
|
private static Instruction staticLoadMicroOp, staticStoreMicroOp, staticBranchMicroOp;
|
|
public static void initializeControlMicroOps() {
|
|
// Load from immediate memory location to a MSR(load_reg)
|
|
Operand loadLocation = Operand.getMemoryOperand(Operand.getImmediateOperand(), null);
|
|
Operand loadRegister = Operand.getIntegerRegister(Registers.encodeRegister("load_reg"));
|
|
staticLoadMicroOp = Instruction.getLoadInstruction(loadLocation, loadRegister);
|
|
|
|
// Store from MSR(load_reg) to immediate memory location
|
|
Operand storeLocation = Operand.getMemoryOperand(Operand.getImmediateOperand(), null);
|
|
Operand storeRegister = Operand.getIntegerRegister(Registers.encodeRegister("store_reg"));
|
|
staticStoreMicroOp = Instruction.getStoreInstruction(storeLocation, storeRegister);
|
|
|
|
// Branch address
|
|
Operand branchAddress = Operand.getImmediateOperand();
|
|
staticBranchMicroOp = Instruction.getBranchInstruction(branchAddress, Registers.getEFlagsRegister());
|
|
}
|
|
|
|
/**
|
|
* This method translates a static instruction to dynamic instruction.
|
|
* It takes as arguments - instructionTable, instructionPointer and dynamic
|
|
* Instruction information
|
|
*/
|
|
|
|
/**
|
|
* This method parses the object file, and creates a hash-table from the
|
|
* static instructions.
|
|
* @param executableFile
|
|
* @return
|
|
*/
|
|
public static void buildStaticInstructionTable(String executableFile)
|
|
{
|
|
BufferedReader input;
|
|
|
|
long noOfLines = noOfLines(executableFile);
|
|
if(noOfLines==0) {
|
|
misc.Error.showErrorAndExit("error in reading the output of objdump on " + executableFile);
|
|
}
|
|
|
|
// Read the assembly code from the program using object-dump utility
|
|
input = readObjDumpOutput(executableFile);
|
|
|
|
// Create a new hash table
|
|
ciscIPtoRiscIP = new InstructionTable((int)noOfLines);
|
|
|
|
System.out.println("The executable has " + noOfLines + " assembly lines");
|
|
|
|
String line;
|
|
long instructionPointer;
|
|
String instructionPrefix;
|
|
String operation;
|
|
String operand1, operand2, operand3;
|
|
|
|
staticMicroOpList = new InstructionList((int)noOfLines*3);
|
|
|
|
int microOpsIndex = 0;
|
|
|
|
long handled = 0, notHandled = 0;
|
|
|
|
// Read from the obj-dump output
|
|
while ((line = readNextLineOfObjDump(input)) != null)
|
|
{
|
|
// System.out.println("Number of lines = " + (handled+notHandled) +
|
|
// " and size of array-list = " + staticMicroOpList.getListSize());
|
|
|
|
if (!(isContainingObjDumpAssemblyCode(line))) {
|
|
continue;
|
|
}
|
|
|
|
String assemblyCodeTokens[] = tokenizeObjDumpAssemblyCode(line);
|
|
|
|
// read the assembly code tokens
|
|
instructionPointer = Numbers.hexToLong(assemblyCodeTokens[0]);
|
|
|
|
instructionPrefix = assemblyCodeTokens[1];
|
|
operation = assemblyCodeTokens[2];
|
|
operand1 = assemblyCodeTokens[3];
|
|
operand2 = assemblyCodeTokens[4];
|
|
operand3 = assemblyCodeTokens[5];
|
|
|
|
// Riscify current instruction
|
|
int microOpsIndexBefore = microOpsIndex;
|
|
int numRicscInsn = riscifyInstruction( instructionPointer,
|
|
instructionPrefix, operation,
|
|
operand1, operand2, operand3,
|
|
staticMicroOpList);
|
|
microOpsIndex += numRicscInsn;
|
|
|
|
if(microOpsIndexBefore==microOpsIndex) {
|
|
notHandled++;
|
|
} else {
|
|
handled++;
|
|
}
|
|
|
|
// add instruction's index into the hash-table
|
|
ciscIPtoRiscIP.addInstruction(instructionPointer, microOpsIndexBefore);
|
|
}
|
|
|
|
System.out.println("Total number of assembly lines = " + (handled + notHandled));
|
|
System.out.println("Total number of micro-operations = " + staticMicroOpList.length());
|
|
|
|
// close the buffered reader
|
|
try {input.close();}
|
|
catch (IOException ioe) {Error.showErrorAndExit("\n\tError in closing the buffered reader !!");}
|
|
|
|
Statistics.setStaticCoverage(((double)handled/(double)(handled+notHandled))*(double)100);
|
|
}
|
|
|
|
private static int riscifyInstruction(
|
|
long instructionPointer, String instructionPrefix, String operation,
|
|
String operand1Str, String operand2Str, String operand3Str,
|
|
InstructionList instructionList)
|
|
{
|
|
// if(instructionPointer==4363909) {
|
|
// System.err.println("ip=" + instructionPointer + "\tprefix=" + instructionPrefix +
|
|
// "\top=" + operation + "\top1=" + operand1Str + "\top2=" + operand2Str + "\top3=" + operand3Str);
|
|
// }
|
|
|
|
int microOpsIndexBefore = instructionList.length();
|
|
Operand operand1 = null, operand2 = null, operand3 = null;
|
|
|
|
|
|
// System.out.println("instructionList size before = " + microOpsIndexBefore);
|
|
|
|
try
|
|
{
|
|
//Determine the instruction class for this instruction
|
|
InstructionClass instructionClass;
|
|
instructionClass = InstructionClassTable.getInstructionClass(operation);
|
|
|
|
// Obtain a handler for this instruction
|
|
X86StaticInstructionHandler handler;
|
|
handler = InstructionClassTable.getInstructionClassHandler(instructionClass);
|
|
|
|
// Handle the instruction
|
|
if(handler!=null) {
|
|
// Simplify the operands
|
|
|
|
TempRegisterNum tempRegisterNum = new TempRegisterNum();
|
|
|
|
operand1 = OperandTranslator.simplifyOperand(operand1Str, instructionList, tempRegisterNum, instructionPrefix);
|
|
operand2 = OperandTranslator.simplifyOperand(operand2Str, instructionList, tempRegisterNum, instructionPrefix);
|
|
operand3 = OperandTranslator.simplifyOperand(operand3Str, instructionList, tempRegisterNum, instructionPrefix);
|
|
|
|
handler.handle(instructionPointer, operand1, operand2, operand3, instructionList, tempRegisterNum);
|
|
|
|
//now set the ip of all converted instructions to instructionPointer
|
|
for(int i=microOpsIndexBefore; i<instructionList.length(); i++)
|
|
{
|
|
instructionList.setCISCProgramCounter(i, instructionPointer);
|
|
}
|
|
} else {
|
|
throw new InvalidInstructionException("", false);
|
|
}
|
|
} catch(Exception inInstrEx) {
|
|
/*
|
|
* microOps created for this instruction are not valid
|
|
* since the translation of the instruction did not
|
|
* complete its execution.
|
|
*/
|
|
|
|
while(instructionList.getListSize() != microOpsIndexBefore) {
|
|
instructionList.removeLastInstr(operand1, operand2, operand3);
|
|
}
|
|
}
|
|
|
|
return (instructionList.length()-microOpsIndexBefore);
|
|
}
|
|
|
|
private static Matcher instructionPrefixMatcher;
|
|
public static void createInstructionPrefixMatcher()
|
|
{
|
|
Pattern p = Pattern.compile("rep|repe|repne|repz|repnz|lock|o16");
|
|
instructionPrefixMatcher = p.matcher("");
|
|
}
|
|
|
|
//return true if the string is a valid instruction prefix
|
|
private static boolean isInstructionPrefix(String string)
|
|
{
|
|
if(instructionPrefixMatcher==null) {
|
|
createInstructionPrefixMatcher();
|
|
}
|
|
|
|
if(instructionPrefixMatcher.reset(string).matches()) {
|
|
return true;
|
|
} else {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
// runs obj-dump utility on the executable file to obtain the assembly code.
|
|
// The obj-dump output is then returned using a buffered reader.
|
|
public static BufferedReader readObjDumpOutput(String executableFileName) {
|
|
BufferedReader input = null;
|
|
|
|
try {
|
|
// Generate the command for obj-dump with required command line
|
|
// arguments
|
|
String command[] = { "objdump", "--disassemble", "-Mintel",
|
|
"--prefix-addresses", executableFileName };
|
|
Process p = Runtime.getRuntime().exec(command);
|
|
|
|
// read the output of the process in a buffered reader
|
|
input = new BufferedReader(
|
|
new InputStreamReader(p.getInputStream()));
|
|
} catch (IOException ioe) {
|
|
Error
|
|
.showErrorAndExit("\n\tError in running objdump on the executable file !!");
|
|
}
|
|
|
|
return input;
|
|
}
|
|
|
|
// Counts number of lines in a file.
|
|
public static int noOfLines(String executableFileName) {
|
|
int numLines = 0;
|
|
BufferedReader input = null;
|
|
|
|
try {
|
|
// Generate the command for obj-dump with required command line
|
|
// arguments
|
|
String command[] = { "objdump", "--disassemble", "-Mintel",
|
|
"--prefix-addresses", executableFileName };
|
|
Process p = Runtime.getRuntime().exec(command);
|
|
// read the output of the process in a buffered reader
|
|
input = new BufferedReader(
|
|
new InputStreamReader(p.getInputStream()));
|
|
|
|
while((input.readLine())!=null) {
|
|
numLines++;
|
|
}
|
|
} catch (IOException ioe) {
|
|
Error
|
|
.showErrorAndExit("\n\tError in running objdump on the executable file !!");
|
|
}
|
|
|
|
return numLines;
|
|
}
|
|
|
|
// reads the next line of buffered reader "input"
|
|
public static String readNextLineOfObjDump(BufferedReader input)
|
|
{
|
|
try
|
|
{
|
|
return (input.readLine());
|
|
}
|
|
catch (IOException ioe)
|
|
{
|
|
Error.showErrorAndExit("\n\tError in reading from the buffered reader containing assembly code !!");
|
|
}
|
|
|
|
// we would never reach this statement
|
|
return null;
|
|
}
|
|
|
|
private static Matcher objdumpAssemblyCodeMatcher;
|
|
public static void createObjdumpAssemblyCodeMatcher()
|
|
{
|
|
Pattern p = Pattern.compile("[0-9a-fA-F]+ <.*> [a-zA-Z]+.*");
|
|
objdumpAssemblyCodeMatcher = p.matcher("");
|
|
}
|
|
|
|
// checks if the passed line of objdump output matches the output for an
|
|
// assembly code.
|
|
public static boolean isContainingObjDumpAssemblyCode(String line)
|
|
{
|
|
if(objdumpAssemblyCodeMatcher==null) {
|
|
createObjdumpAssemblyCodeMatcher();
|
|
}
|
|
|
|
// A valid assembly code line has following pattern
|
|
// linear-address <referrence-address> opcode (operands)
|
|
return objdumpAssemblyCodeMatcher.reset(line).matches();
|
|
}
|
|
|
|
// for a line of assembly code, this would return the
|
|
// linear address, operation, operand1,operand2, operand3
|
|
public static String[] tokenizeObjDumpAssemblyCode(String line)
|
|
{
|
|
String linearAddress;
|
|
String instructionPrefix;
|
|
String operation;
|
|
String operand1, operand2, operand3;
|
|
String operands;
|
|
|
|
// remove the suffix part of string
|
|
if(line.indexOf("#")!=-1) {
|
|
line = line.substring(0, line.indexOf("#"));
|
|
}
|
|
|
|
// remove the part of string enclosed in <...>
|
|
//uselessCommentMatcher.reset(line).replaceAll(, "");
|
|
|
|
// Initialise all operands to null
|
|
operands = operand1 = operand2 = operand3 = null;
|
|
|
|
// Tokenize the line
|
|
StringTokenizer lineTokenizer = new StringTokenizer(line);
|
|
|
|
// Read the tokens into required variables
|
|
linearAddress = lineTokenizer.nextToken();
|
|
lineTokenizer.nextToken(); // skip the referred address
|
|
|
|
// Determine the instruction prefix and operation
|
|
String tempToken = lineTokenizer.nextToken();
|
|
if(isInstructionPrefix(tempToken)) {
|
|
instructionPrefix = tempToken;
|
|
operation = lineTokenizer.nextToken();
|
|
} else {
|
|
instructionPrefix = null;
|
|
operation = tempToken;
|
|
}
|
|
|
|
if (lineTokenizer.hasMoreTokens())
|
|
operands = lineTokenizer.nextToken();
|
|
|
|
// If the operation has tokens, then break it further.
|
|
if (operands != null) {
|
|
// First join all the operand tokens
|
|
while (lineTokenizer.hasMoreTokens())
|
|
operands = operands + " " + lineTokenizer.nextToken();
|
|
|
|
StringTokenizer operandTokenizer = new StringTokenizer(operands,
|
|
",", false);
|
|
|
|
if (operandTokenizer.hasMoreTokens())
|
|
operand1 = operandTokenizer.nextToken();
|
|
if (operandTokenizer.hasMoreTokens())
|
|
operand2 = operandTokenizer.nextToken();
|
|
if (operandTokenizer.hasMoreTokens())
|
|
operand3 = operandTokenizer.nextToken();
|
|
}
|
|
|
|
return new String[] { linearAddress, instructionPrefix, operation, operand1, operand2,
|
|
operand3 };
|
|
}
|
|
|
|
// for a line of assembly code, this would return the
|
|
// linear address, operation, operand1,operand2, operand3
|
|
private static String[] tokenizeQemuAssemblyCodeSS(String line)
|
|
{
|
|
String instructionPrefix;
|
|
String operation;
|
|
String operand1, operand2, operand3;
|
|
String operands;
|
|
|
|
// Initialise all operands to null
|
|
instructionPrefix = operation = null;
|
|
operands = operand1 = operand2 = operand3 = null;
|
|
|
|
// Tokenize the line
|
|
StringTokenizer lineTokenizer = new StringTokenizer(line);
|
|
|
|
// Read the tokens into required variables
|
|
String str = lineTokenizer.nextToken().trim();
|
|
if(isInstructionPrefix(str)==true) {
|
|
instructionPrefix = str;
|
|
operation = lineTokenizer.nextToken().trim();
|
|
} else {
|
|
instructionPrefix = null;
|
|
operation = str;
|
|
}
|
|
|
|
if (lineTokenizer.hasMoreTokens()) {
|
|
operands = lineTokenizer.nextToken();
|
|
|
|
// First join all the operand tokens
|
|
while (lineTokenizer.hasMoreTokens()) {
|
|
operands = operands + " " + lineTokenizer.nextToken();
|
|
}
|
|
|
|
StringTokenizer operandTokenizer = new StringTokenizer(operands,
|
|
",", false);
|
|
|
|
if (operandTokenizer.hasMoreTokens()) {
|
|
operand1 = operandTokenizer.nextToken().trim();
|
|
}
|
|
|
|
if (operandTokenizer.hasMoreTokens()) {
|
|
operand2 = operandTokenizer.nextToken().trim();
|
|
}
|
|
|
|
if (operandTokenizer.hasMoreTokens()) {
|
|
operand3 = operandTokenizer.nextToken().trim();
|
|
}
|
|
}
|
|
|
|
return new String[] { instructionPrefix, operation, operand1, operand2, operand3 };
|
|
}
|
|
|
|
// return index of null character for a byte array
|
|
private static int len(byte[] asmBytes) {
|
|
int i=0;
|
|
for(;asmBytes[i]!=0 && i<asmBytes.length;i++);
|
|
return i;
|
|
}
|
|
|
|
// searches character ch in asmByes. If not-found return -1, else return index of ch
|
|
private static int indexOf(byte[] asmBytes, char ch, int offset, int len) {
|
|
for(int i=offset; i<len(asmBytes); i++) {
|
|
if(asmBytes[i]==ch) {
|
|
return i;
|
|
}
|
|
}
|
|
|
|
return -1;
|
|
}
|
|
|
|
private static String concatenateStringArray(String[] strArray) {
|
|
String concatenatedString = new String(strArray[0] + strArray[1] + strArray[2] + strArray[3]);
|
|
return concatenatedString;
|
|
}
|
|
// for a line of assembly code, this would return the
|
|
// linear address, operation, operand1,operand2, operand3
|
|
private static String[] tokenizeQemuAssemblyCode(byte[] asmBytes) {
|
|
|
|
String assemblyTokens[] = new String[5];
|
|
|
|
// System.out.println("assembly = " + new String(asmBytes));
|
|
|
|
int previousPointer, currentPointer;
|
|
previousPointer = currentPointer = 0;
|
|
|
|
// -------------- instructionPrefix and operation ----------------------------------
|
|
currentPointer = indexOf(asmBytes, ' ', previousPointer, 64);
|
|
|
|
if(currentPointer==-1) {
|
|
assemblyTokens[0] = null;
|
|
assemblyTokens[1] = new String(asmBytes, 0, len(asmBytes)); // only operation field is present
|
|
assemblyTokens[2] = assemblyTokens[3] = assemblyTokens[4] = null;
|
|
return assemblyTokens;
|
|
}
|
|
|
|
String str = new String(asmBytes, previousPointer, (currentPointer-previousPointer));
|
|
currentPointer++; previousPointer = currentPointer;
|
|
|
|
if(isInstructionPrefix(str)) {
|
|
assemblyTokens[0] = str;
|
|
currentPointer = indexOf(asmBytes, ' ', previousPointer, 64);
|
|
|
|
if(currentPointer==-1) {
|
|
assemblyTokens[1] = new String(asmBytes, previousPointer, len(asmBytes)-previousPointer); // only operation field is present
|
|
assemblyTokens[2] = assemblyTokens[3] = assemblyTokens[4] = null;
|
|
return assemblyTokens;
|
|
}
|
|
else {
|
|
assemblyTokens[1] = new String(asmBytes, previousPointer, (currentPointer-previousPointer));
|
|
currentPointer++; previousPointer = currentPointer;
|
|
}
|
|
} else {
|
|
assemblyTokens[0] = null;
|
|
assemblyTokens[1] = str;
|
|
}
|
|
|
|
// --------------------- operand1, operand2, operand3 --------------------------------
|
|
if(previousPointer==len(asmBytes)) {
|
|
assemblyTokens[2] = assemblyTokens[3] = assemblyTokens[4] = null;
|
|
return assemblyTokens;
|
|
}
|
|
|
|
currentPointer = indexOf(asmBytes, ',', previousPointer, 64);
|
|
if(currentPointer==-1) {
|
|
assemblyTokens[3] = assemblyTokens[4] = null;
|
|
assemblyTokens[2] = new String(asmBytes, previousPointer, len(asmBytes)-previousPointer);
|
|
return assemblyTokens;
|
|
} else {
|
|
assemblyTokens[2] = new String(asmBytes, previousPointer, (currentPointer-previousPointer));
|
|
currentPointer+=2; previousPointer=currentPointer;
|
|
|
|
if(previousPointer==len(asmBytes)) {
|
|
assemblyTokens[3] = assemblyTokens[4] = null;
|
|
} else {
|
|
currentPointer = indexOf(asmBytes, ',', previousPointer, 64);
|
|
|
|
if(currentPointer==-1) {
|
|
assemblyTokens[4] = null;
|
|
assemblyTokens[3] = new String(asmBytes, previousPointer, len(asmBytes)-previousPointer);
|
|
return assemblyTokens;
|
|
} else {
|
|
assemblyTokens[3] = new String(asmBytes, previousPointer, (currentPointer-previousPointer));
|
|
currentPointer++; previousPointer=currentPointer;
|
|
|
|
assemblyTokens[4] = new String(asmBytes, previousPointer, len(asmBytes)-previousPointer);
|
|
return assemblyTokens;
|
|
}
|
|
}
|
|
}
|
|
|
|
return assemblyTokens;
|
|
}
|
|
|
|
private static boolean removeInstructionFromTail(GenericCircularQueue<Instruction> inputToPipeline, long instructionPointer, int previousSize) {
|
|
|
|
if(inputToPipeline.size()<previousSize) {
|
|
misc.Error.showErrorAndExit("This is not possible !!!");
|
|
}
|
|
|
|
while(inputToPipeline.size()>previousSize) {
|
|
Instruction ins = inputToPipeline.pop();
|
|
CustomObjectPool.getInstructionPool().returnObject(ins);
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
/*
|
|
* This function fuses the statically translated micro-ops with the information received from the emulator.
|
|
* New micro-ops are added to the circular buffer(argument). Finally it returns the number of CISC instructions it could
|
|
* translate.
|
|
*/
|
|
public static void fuseInstruction(
|
|
int tidApp, long startInstructionPointer,
|
|
EmulatorPacketList arrayListPacket, GenericCircularQueue<Instruction> inputToPipeline)
|
|
{
|
|
int prevLengthOfInputToPipeLine = inputToPipeline.size();
|
|
|
|
//System.out.println("ip = " + startInstructionPointer + "\t" + Long.toHexString(startInstructionPointer));
|
|
|
|
// Create a dynamic instruction buffer for all control packets
|
|
DynamicInstructionBuffer dynamicInstructionBuffer = staticDynamicInstructionBuffers[tidApp];
|
|
dynamicInstructionBuffer.configurePackets(arrayListPacket);
|
|
|
|
InstructionList assemblyPacketList = null;
|
|
|
|
int numCISC = 1;
|
|
int microOpIndex = -1;
|
|
boolean lockPrefix = false;
|
|
|
|
boolean removedFromTail = false;
|
|
// Riscify the assembly packets
|
|
if(EmulatorConfig.emulatorType==EmulatorType.none) {
|
|
assemblyPacketList = threadMicroOpsList[tidApp];
|
|
threadMicroOpsList[tidApp].clear();
|
|
|
|
//This is a bug(at least in case of caching): assemblyPacketList = threadMicroOpsList[tidApp];
|
|
Packet p = arrayListPacket.get(0);
|
|
|
|
if(p.value==Encoding.ASSEMBLY) {
|
|
byte asmBytes[] = CustomObjectPool.getCustomAsmCharPool().dequeue(tidApp);
|
|
String assemblyTokens[] = tokenizeQemuAssemblyCode(asmBytes);
|
|
String asmText = concatenateStringArray(assemblyTokens);
|
|
|
|
//check if present in translated-instruction cache
|
|
if(TranslatedInstructionCache.isPresent(asmText)) {
|
|
assemblyPacketList = TranslatedInstructionCache.getInstructionList(asmText);
|
|
|
|
for(int j=0; j<assemblyPacketList.length(); j++) {
|
|
assemblyPacketList.setCISCProgramCounter(j, p.ip);
|
|
}
|
|
|
|
} else {
|
|
// System.out.println(i + " : " + assemblyLine);
|
|
long instructionPointer = p.ip;
|
|
String instructionPrefix, operation, operand1, operand2, operand3;
|
|
instructionPrefix = assemblyTokens[0]; operation = assemblyTokens[1];
|
|
operand1 = assemblyTokens[2]; operand2 = assemblyTokens[3]; operand3 = assemblyTokens[4];
|
|
|
|
riscifyInstruction( instructionPointer,
|
|
instructionPrefix, operation,
|
|
operand1, operand2, operand3,
|
|
assemblyPacketList);
|
|
|
|
//Add to translated-instruction cache
|
|
TranslatedInstructionCache.add(asmText, assemblyPacketList);
|
|
}
|
|
} else {
|
|
return;
|
|
//misc.Error.showErrorAndExit("First packet to fuse instruction must be assembly packet !!");
|
|
}
|
|
|
|
microOpIndex = 0;
|
|
|
|
} else if (EmulatorConfig.emulatorType==EmulatorType.pin) {
|
|
assemblyPacketList = staticMicroOpList;
|
|
|
|
microOpIndex = ciscIPtoRiscIP.getMicroOpIndex(startInstructionPointer);
|
|
|
|
if(microOpIndex < -1)
|
|
{
|
|
//lock prefix
|
|
microOpIndex *= -1;
|
|
lockPrefix = true;
|
|
}
|
|
|
|
if((microOpIndex==-1) ||
|
|
(lockPrefix == false && assemblyPacketList.get(microOpIndex).getCISCProgramCounter()!=startInstructionPointer))
|
|
{
|
|
// Don't worry. even if the micro-op index is incorrect, it will be caught in the main
|
|
// translate loop
|
|
microOpIndex = 0;
|
|
|
|
// dynamicInstructionBuffer.clearBuffer();
|
|
//System.out.println("static -- " + microOpIndex);
|
|
//return 0;
|
|
}
|
|
}
|
|
|
|
Instruction staticMicroOp, dynamicMicroOp;
|
|
DynamicInstructionHandler dynamicInstructionHandler;
|
|
|
|
// main translate loop.
|
|
while(true)
|
|
{
|
|
staticMicroOp = assemblyPacketList.get(microOpIndex);
|
|
if(staticMicroOp==null ||
|
|
(lockPrefix == false
|
|
&& staticMicroOp.getCISCProgramCounter() != startInstructionPointer)) {
|
|
break;
|
|
}
|
|
|
|
dynamicInstructionHandler = VisaHandlerSelector.selectHandler(staticMicroOp.getOperationType());
|
|
dynamicMicroOp = getDynamicMicroOp(staticMicroOp);
|
|
if(lockPrefix == true)
|
|
{
|
|
dynamicMicroOp.setCISCProgramCounter(startInstructionPointer);
|
|
}
|
|
microOpIndex = dynamicInstructionHandler.handle(microOpIndex, dynamicMicroOp, dynamicInstructionBuffer);
|
|
|
|
if(microOpIndex==-1) {
|
|
//System.out.println("dynamic");
|
|
// I was unable to fuse certain micro-ops of this instruction.
|
|
// So, I must remove any previously
|
|
// computed micro-ops from the buffer
|
|
CustomObjectPool.getInstructionPool().returnObject(dynamicMicroOp);
|
|
removeInstructionFromTail(inputToPipeline, staticMicroOp.getCISCProgramCounter(), prevLengthOfInputToPipeLine);
|
|
removedFromTail = true;
|
|
numCISC = 0;
|
|
break;
|
|
} else {
|
|
inputToPipeline.enqueue(dynamicMicroOp); //append microOp
|
|
}
|
|
}
|
|
|
|
if((removedFromTail == true )&& inputToPipeline.size()!=prevLengthOfInputToPipeLine) {
|
|
System.err.println("\ncurrentSize = " + inputToPipeline.size());
|
|
System.err.println("previousSize = " + prevLengthOfInputToPipeLine);
|
|
misc.Error.showErrorAndExit("");
|
|
}
|
|
|
|
// If we have failed to read any information from dynamicInstructionBuffer before, then read it now.
|
|
if(dynamicInstructionBuffer.missedInformation()) {
|
|
//This instruction could not be translated. However, if there are some
|
|
//load/store/branch operations in this instruction, they must be pushed
|
|
//to pipeline.
|
|
flushDynamicInformationPackets(startInstructionPointer, dynamicInstructionBuffer, inputToPipeline);
|
|
}
|
|
|
|
/* clear the dynamicInstructionBuffer */
|
|
// dynamicInstructionBuffer.clearBuffer();
|
|
//System.out.println(inputToPipeline);
|
|
//return numCISC;
|
|
}
|
|
|
|
//Some instructions are not translated by the translator. However, if there are some
|
|
//load/store/branch operations in this instruction, they must be pushed
|
|
//to pipeline.
|
|
private static void flushDynamicInformationPackets(
|
|
long instructionPointer,
|
|
DynamicInstructionBuffer dynamicInstructionBuffer,
|
|
GenericCircularQueue<Instruction> inputToPipeline)
|
|
{
|
|
Instruction dynamicMicroOp;
|
|
DynamicInstructionHandler dynamicInstructionHandler;
|
|
|
|
// load information
|
|
for(int i=dynamicInstructionBuffer.getMemReadCount(); i<dynamicInstructionBuffer.getMemReadSize(); i++)
|
|
{
|
|
dynamicMicroOp = CustomObjectPool.getInstructionPool().borrowObject();
|
|
dynamicMicroOp.copy(staticLoadMicroOp);
|
|
dynamicInstructionHandler = VisaHandlerSelector.selectHandler(dynamicMicroOp.getOperationType());
|
|
dynamicInstructionHandler.handle(0, dynamicMicroOp, dynamicInstructionBuffer);
|
|
inputToPipeline.enqueue(dynamicMicroOp);
|
|
}
|
|
|
|
// store information
|
|
for(int i=dynamicInstructionBuffer.getMemWriteCount(); i<dynamicInstructionBuffer.getMemWriteSize(); i++)
|
|
{
|
|
dynamicMicroOp = CustomObjectPool.getInstructionPool().borrowObject();
|
|
dynamicMicroOp.copy(staticStoreMicroOp);
|
|
dynamicInstructionHandler = VisaHandlerSelector.selectHandler(dynamicMicroOp.getOperationType());
|
|
dynamicInstructionHandler.handle(0, dynamicMicroOp, dynamicInstructionBuffer);
|
|
inputToPipeline.enqueue(dynamicMicroOp);
|
|
}
|
|
|
|
// branch information. This must be performed strictly after memory operations.
|
|
if(dynamicInstructionBuffer.isBranchInformationReadNeeded())
|
|
{
|
|
dynamicMicroOp = CustomObjectPool.getInstructionPool().borrowObject();
|
|
dynamicMicroOp.copy(staticBranchMicroOp);
|
|
dynamicInstructionHandler = VisaHandlerSelector.selectHandler(dynamicMicroOp.getOperationType());
|
|
dynamicInstructionHandler.handle(0, dynamicMicroOp, dynamicInstructionBuffer);
|
|
inputToPipeline.enqueue(dynamicMicroOp);
|
|
}
|
|
}
|
|
|
|
private static Instruction getDynamicMicroOp(Instruction staticMicroOp) {
|
|
|
|
Instruction dynamicMicroOp = null;
|
|
|
|
if(EmulatorConfig.emulatorType==EmulatorType.pin) {
|
|
dynamicMicroOp = CustomObjectPool.getInstructionPool().borrowObject();
|
|
dynamicMicroOp.copy(staticMicroOp);
|
|
} else if(EmulatorConfig.emulatorType==EmulatorType.none) {
|
|
// This will ensure that the packet is returned to instruction pool
|
|
dynamicMicroOp = staticMicroOp;
|
|
}
|
|
|
|
return dynamicMicroOp;
|
|
}
|
|
} |