/* This file is part of jpcsp. Jpcsp 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. Jpcsp 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 Jpcsp. If not, see <http://www.gnu.org/licenses/>. */ package jpcsp.Allegrex.compiler.nativeCode; import java.util.LinkedList; import java.util.List; import jpcsp.Memory; import jpcsp.Allegrex.compiler.CodeInstruction; /** * @author gid15 * */ public class NativeCodeSequence { protected String name; protected NativeOpcodeInfo[] opcodes = new NativeOpcodeInfo[0]; private Class<INativeCodeSequence> nativeCodeSequenceClass; private ParameterInfo[] parameters = new ParameterInfo[0]; private int branchInstruction = -1; private boolean isReturning = false; private boolean wholeCodeBlock = false; private String methodName = "call"; private List<CodeInstruction> beforeCodeInstructions; private boolean isHook = false; private boolean isMethodReturning = false; private static class NativeOpcodeInfo { private int opcode; private int mask; private int notMask; private String label; private int maskedOpcode; public NativeOpcodeInfo(int opcode, int mask, String label) { this.opcode = opcode; this.mask = mask; this.label = label; maskedOpcode = opcode & mask; notMask = ~mask; } public boolean isMatching(int opcode) { return (opcode & mask) == maskedOpcode; } public int getOpcode() { return opcode; } public String getLabel() { return label; } public int getMask() { return mask; } public int getNotMask() { return notMask; } } private static class ParameterInfo { private int value; private boolean isLabelIndex; public ParameterInfo(int value, boolean isLabelIndex) { this.value = value; this.isLabelIndex = isLabelIndex; } public int getValue() { return value; } public int getValue(int address, NativeOpcodeInfo[] opcodes) { if (isLabelIndex && value >= 0 && value < opcodes.length) { int labelAddress = address + (value << 2); int targetOpcode = Memory.getInstance().read32(labelAddress); NativeOpcodeInfo opcode = opcodes[value]; return targetOpcode & opcode.getNotMask(); } return value; } } public NativeCodeSequence(String name, Class<INativeCodeSequence> nativeCodeSequenceClass) { this.name = name; this.nativeCodeSequenceClass = nativeCodeSequenceClass; } public String getName() { return name; } public void setName(String name) { this.name = name; } public void addOpcode(int opcode, int mask, String label) { NativeOpcodeInfo[] newOpcodes = new NativeOpcodeInfo[opcodes.length + 1]; System.arraycopy(opcodes, 0, newOpcodes, 0, opcodes.length); opcodes = newOpcodes; opcodes[opcodes.length - 1] = new NativeOpcodeInfo(opcode, mask, label); } public int getFirstOpcode() { return opcodes[0].getOpcode(); } public int getFirstOpcodeMask() { return opcodes[0].getMask(); } public int getNumOpcodes() { return opcodes.length; } public Class<INativeCodeSequence> getNativeCodeSequenceClass() { return nativeCodeSequenceClass; } public void setNativeCodeSequenceClass(Class<INativeCodeSequence> nativeCodeSequenceClass) { this.nativeCodeSequenceClass = nativeCodeSequenceClass; } public int getLabelIndex(String label) { int value = -1; if (label == null) { return value; } for (int i = 0; i < opcodes.length; i++) { if (label.equalsIgnoreCase(opcodes[i].getLabel())) { value = i; break; } } return value; } public boolean isMatching(int opcodeIndex, int opcode) { return opcodes[opcodeIndex].isMatching(opcode); } public void setParameter(int parameter, int value, boolean isLabelIndex) { if (parameter >= parameters.length) { ParameterInfo[] newParameters = new ParameterInfo[parameter + 1]; System.arraycopy(parameters, 0, newParameters, 0, parameters.length); for (int i = parameters.length; i < parameter; i++) { newParameters[i] = null; } parameters = newParameters; } parameters[parameter] = new ParameterInfo(value, isLabelIndex); } public int getParameterValue(int parameter, int address) { if (parameter >= parameters.length) { return 0; } ParameterInfo parameterInfo = parameters[parameter]; if (address == 0) { return parameterInfo.getValue(); } return parameterInfo.getValue(address, opcodes); } public int getNumberParameters() { return parameters.length; } public int getBranchInstruction() { return branchInstruction; } public void setBranchInstruction(int branchInstruction) { this.branchInstruction = branchInstruction; } public boolean hasBranchInstruction() { return branchInstruction >= 0; } @Override public String toString() { StringBuilder result = new StringBuilder(); result.append(name); result.append("["); for (int i = 0; opcodes != null && i < opcodes.length; i++) { if (i > 0) { result.append(","); } result.append(String.format("%08X", opcodes[i].getOpcode())); } result.append("]"); result.append("("); for (int i = 0; i < getNumberParameters(); i++) { if (i > 0) { result.append(","); } result.append(getParameterValue(i, 0)); } result.append(")"); return result.toString(); } public boolean isReturning() { return isReturning; } public void setReturning(boolean isReturning) { this.isReturning = isReturning; } public boolean isWholeCodeBlock() { return wholeCodeBlock; } public void setWholeCodeBlock(boolean wholeCodeBlock) { this.wholeCodeBlock = wholeCodeBlock; } public String getMethodName() { return methodName; } public void setMethodName(String methodName) { this.methodName = methodName; } public List<CodeInstruction> getBeforeCodeInstructions() { return beforeCodeInstructions; } public void addBeforeCodeInstruction(CodeInstruction codeInstruction) { if (beforeCodeInstructions == null) { beforeCodeInstructions = new LinkedList<CodeInstruction>(); } beforeCodeInstructions.add(codeInstruction); } public boolean isHook() { return isHook; } public void setHook(boolean isHook) { this.isHook = isHook; } public boolean isMethodReturning() { return isMethodReturning; } public void setMethodReturning(boolean isMethodReturning) { this.isMethodReturning = isMethodReturning; } }