Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 1 addition & 2 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -41,5 +41,4 @@ else {
throw new GradleException("GHIDRA_INSTALL_DIR is not defined!")
}
//----------------------END "DO NOT MODIFY" SECTION-------------------------------
sourceCompatibility = JavaVersion.VERSION_14
targetCompatibility = JavaVersion.VERSION_14

10 changes: 9 additions & 1 deletion src/main/java/spice86/generator/FunctionGenerator.java
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,15 @@ private String generateGotoFromOutsideAndInstructionSkip(SegmentedAddress firstI
continue;
}
String caseString = " case " + Utils.toHexWith0X(target.toPhysical() - parsedProgram.getCs1Physical()) + ":";
String gotoTarget = JumpCallTranslator.getLabelToAddress(target, false);

// Use the actual instruction address for the label name if possible
SegmentedAddress labelAddress = target;
ParsedInstruction targetInstruction = parsedProgram.getInstructionAtSegmentedAddress(target);
if (targetInstruction != null) {
labelAddress = targetInstruction.getInstructionSegmentedAddress();
}

String gotoTarget = JumpCallTranslator.getLabelToAddress(labelAddress, false);
String jumpSourceAddresses = getJumpSourceAddressesToString(target);
res.append(
caseString + " goto " + gotoTarget + ";break; // Target of external jump from " + jumpSourceAddresses
Expand Down
15 changes: 10 additions & 5 deletions src/main/java/spice86/generator/ProgramGenerator.java
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,10 @@ private String generateNamespace() {
}

private String generateImports() {
return "";
return "using Spice86.Core.CLI;\n"
+ "using Spice86.Core.Emulator.CPU.InstructionsImpl;\n"
+ "using Spice86.Shared.Emulator.Memory;\n"
+ "using Spice86.Shared.Interfaces;\n\n";
}

private String generateClassDeclaration() {
Expand All @@ -83,13 +86,15 @@ private String generateClassDeclaration() {

private String generateConstructor() {
String res =
"public GeneratedOverrides(Dictionary<SegmentedAddress, FunctionInformation> functionInformations, Machine machine, ushort entrySegment = "
"public GeneratedOverrides(Configuration configuration,\n"
+ " IDictionary<SegmentedAddress, FunctionInformation> functionInformations,\n"
+ " Machine machine, ILoggerService loggerService, ushort entrySegment = "
+ Utils.toHexWith0X(parsedProgram.getCs1Physical() / 0x10)
+ ") : base(functionInformations, machine) {\n";
+ ")\n"
+ " : base(functionInformations, machine, loggerService, configuration) {\n";
res += Utils.indent(generateSegmentConstructorAssignment(), 2);
res += '\n';
res += " DefineGeneratedCodeOverrides();\n";
res += " DetectCodeRewrites();\n";
res += " SetProvidedInterruptHandlersAsOverridden();\n";
res += "}\n\n";
return res;
Expand Down Expand Up @@ -176,6 +181,6 @@ private String generateCodeRewriteDetector() {
}

private String defineExecutableArea(int rangeStart, int rangeEnd) {
return " DefineExecutableArea(" + Utils.toHexWith0X(rangeStart) + ", " + Utils.toHexWith0X(rangeEnd) + ");\n";
return ""; // removed
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -170,13 +170,23 @@ private String generateAssignmentWith1Parameter(String operation, String nativeO
if (canUseNativeOperation()) {
return dest + nativeOperation + ";";
}
String className = operation.substring(0, operation.lastIndexOf('.'));
if ("Alu".equals(className)) {
String methodName = operation.substring(operation.lastIndexOf('.') + 1);
return parameterTranslator.generateAssignment(dest, className + bits + "." + methodName + "(" + dest + ")");
}
return parameterTranslator.generateAssignment(dest, operation + bits + "(" + dest + ")");
}

private String generateAssignmentWith2ParametersOnlyOneOperand(String operation, String[] parameters,
Integer bits) {
String dest = parameterTranslator.toSpice86Value(parameters[0], bits);
String operand = parameterTranslator.toSpice86Value(parameters[1], bits);
String className = operation.substring(0, operation.lastIndexOf('.'));
if ("Alu".equals(className)) {
String methodName = operation.substring(operation.lastIndexOf('.') + 1);
return parameterTranslator.generateAssignment(dest, className + bits + "." + methodName + "(" + operand + ")");
}
return parameterTranslator.generateAssignment(dest, operation + bits + "(" + operand + ")");
}

Expand All @@ -202,14 +212,27 @@ private String generateAssignmentWith2Parameters(String operation, String native
}
res += "// " + resNativeOperation + '\n';
}
res += parameterTranslator.generateAssignment(dest, operation + bitsParameter1 + "(" + dest + ", " + operand + ")");
// Extract class and method name from "Class.Method" to generate "Class{bits}.Method"
String className = operation.substring(0, operation.lastIndexOf('.'));
if ("Alu".equals(className)) {
String methodName = operation.substring(operation.lastIndexOf('.') + 1);
res += parameterTranslator.generateAssignment(dest, className + bitsParameter1 + "." + methodName + "(" + dest + ", " + operand + ")");
} else {
res += parameterTranslator.generateAssignment(dest, operation + bitsParameter1 + "(" + dest + ", " + operand + ")");
}
return res;
}

private String generateNoAssignmentWith2Parameters(String operation, String[] parameters) {
Integer bitsParameter1 = parsedInstruction.getParameter1BitLength();
String dest = parameterTranslator.toSpice86Value(parameters[0], bitsParameter1);
String operand = signExtendParameter2IfNeeded(parameters);
// Extract class and method name from "Class.Method" to generate "Class{bits}.Method"
String className = operation.substring(0, operation.lastIndexOf('.'));
if ("Alu".equals(className)) {
String methodName = operation.substring(operation.lastIndexOf('.') + 1);
return className + bitsParameter1 + "." + methodName + "(" + dest + ", " + operand + ");";
}
return operation + bitsParameter1 + "(" + dest + ", " + operand + ");";
}

Expand Down Expand Up @@ -255,7 +278,7 @@ private String generateOuts(String[] parameters, int bits) {
private String generateScas(String[] parameters, int bits) {
String param1 = getAXOrAL(bits);
String param2 = getDestination(parameters, bits);
String operation = "Alu.Sub" + bits + "(" + param1 + ", " + param2 + ");";
String operation = "Alu" + bits + ".Sub(" + param1 + ", " + param2 + ");";
return generateStringOperation(operation, false, true, bits);
}

Expand All @@ -276,7 +299,7 @@ private String generateLods(String[] parameters, int bits) {
private String generateCmps(String[] parameters, int bits) {
String param1 = getSource(parameters, bits);
String param2 = getDestination(parameters, bits);
String operation = "Alu.Sub" + bits + "(" + param1 + ", " + param2 + ");";
String operation = "Alu" + bits + ".Sub(" + param1 + ", " + param2 + ");";
return generateStringOperation(operation, true, true, bits);
}

Expand Down Expand Up @@ -331,7 +354,7 @@ private String generateNot(String[] parameters, Integer bits) {

private String generateNeg(String[] parameters, Integer bits) {
String parameter = parameterTranslator.toSpice86Value(parameters[0], bits);
return parameterTranslator.generateAssignment(parameter, "Alu.Sub" + bits + "(0, " + parameter + ")");
return parameterTranslator.generateAssignment(parameter, "Alu" + bits + ".Sub(0, " + parameter + ")");
}

private String generateLXS(String segmentRegister, String[] parameters) {
Expand Down Expand Up @@ -383,8 +406,12 @@ private String generateIMul(String[] parameters, Integer bits) {
String destination = parameterTranslator.toSpice86Value(parameters[0], bits);
String operand1 = parameterTranslator.toSpice86Value(parameters[1], bits);
String operand2 = parameterTranslator.toSpice86Value(parameters[2], bits);
return parameterTranslator.generateAssignment(destination,
parameterTranslator.castToUnsignedInt("Alu.Imul" + bits + "(" + operand1 + ", " + operand2 + ")", bits));
String signedType = parameterTranslator.toSignedType(bits);
String cast = "(" + signedType + ")";
String aluCall = "Alu" + bits + ".Imul(" + cast + operand1 + ", " + cast + operand2 + ")";
String assignment = parameterTranslator.generateAssignment(destination,
parameterTranslator.castToUnsignedInt(aluCall, bits));
return "unchecked {\n" + Utils.indent(assignment, 2) + "\n}";
}
// Regular grp3 imul
return generateGrp3ImulMul(true, bits, "Imul", parameters[0]);
Expand All @@ -399,7 +426,7 @@ private String generateGrp3ImulMul(boolean signed, int bits, String aluOperation
int resBits = bits * 2;
String resType = signed ? parameterTranslator.toSignedType(resBits) : parameterTranslator.toUnsignedType(resBits);
String operation = parameterTranslator.generateAssignmentWithType(resType, tempVar,
"Alu." + aluOperation + bits + "(" + opSignCast + opRes1 + ", " + opSignCast + op2
"Alu" + bits + "." + aluOperation + "(" + opSignCast + opRes1 + ", " + opSignCast + op2
+ ")");
String operationAssignment1 =
parameterTranslator.generateAssignment(opRes1, parameterTranslator.castToUnsignedInt(tempVar, bits));
Expand All @@ -412,7 +439,7 @@ private String generateGrp3IdivDiv(boolean signed, int bits, String aluOperation
int op1Bits = bits * 2;
String op1Type = signed ? parameterTranslator.toSignedType(op1Bits) : parameterTranslator.toUnsignedType(op1Bits);
String op1Var = parameterTranslator.generateTempVar("op1" + aluOperation);
String op1Cast = signed ? "(" + op1Type + ")" : "";
String op1Cast = "(" + op1Type + ")";
String op1Assignment =
parameterTranslator.generateAssignmentWithType(op1Type, op1Var, op1Cast + generateDivIdviOp1(bits));

Expand All @@ -426,7 +453,7 @@ private String generateGrp3IdivDiv(boolean signed, int bits, String aluOperation
String operationResultType = op2Type + "?";
String operationResultVar = parameterTranslator.generateTempVar("res" + aluOperation);
String operationAssignment = parameterTranslator.generateAssignmentWithType(operationResultType, operationResultVar,
"Alu." + aluOperation + bits + "(" + op1Var + ", " + op2Var
"Alu" + bits + "." + aluOperation + "(" + op1Var + ", " + op2Var
+ ")");

String nullCheckAssignment =
Expand Down Expand Up @@ -485,7 +512,7 @@ private String generateDiv(String[] parameters, Integer bits) {
}

private String generateIDiv(String[] parameters, Integer bits) {
return generateGrp3IdivDiv(true, bits, "IDiv", parameters[0]);
return generateGrp3IdivDiv(true, bits, "Idiv", parameters[0]);
}

private String generateLea(String[] parameters) {
Expand Down Expand Up @@ -534,6 +561,16 @@ private String convertInstructionWithoutPrefix(String mnemonic, String[] params)
return "// " + instuctionAsm + " (" + address + ")\n" + instruction;
}

/* BCD Instructions Helper */
private String generateBcdInstruction(String method, String[] params, Integer bits) {
String param = parameterTranslator.toSpice86Value(params[0], bits);
return "new Instructions8(Cpu.State, Cpu, Memory, new(Memory, Cpu, Cpu.State))." + method + "(" + param + ");";
}

private String generateBcdInstructionNoParam(String method) {
return "new Instructions8(Cpu.State, Cpu, Memory, new(Memory, Cpu, Cpu.State))." + method + "();";
}

private String generateModifiedInstructionWarning() {
// Writes a comment in case of autogenerated code with the instruction bytes that were modified and the addresses of the instructions that did the change
int instructionAddress = parsedInstruction.getInstructionSegmentedAddress().toPhysical();
Expand Down Expand Up @@ -674,10 +711,10 @@ private String convertInstructionWithoutPrefixAndComment(String mnemonic, String
log.info("Params are " + String.join(",", params));
Integer parameter1Bits = parsedInstruction.getParameter1BitLength();
return switch (mnemonic) {
case "AAA" -> "Cpu.Aaa();";
case "AAD" -> "Cpu.Aad(" + parameterTranslator.toSpice86Value(params[0], parameter1Bits) + ");";
case "AAM" -> "Cpu.Aam(" + parameterTranslator.toSpice86Value(params[0], parameter1Bits) + ");";
case "AAS" -> "Cpu.Aas();";
case "AAA" -> generateBcdInstructionNoParam("Aaa");
case "AAD" -> generateBcdInstruction("Aad", params, parameter1Bits);
case "AAM" -> generateBcdInstruction("Aam", params, parameter1Bits);
case "AAS" -> generateBcdInstructionNoParam("Aas");
case "ADC" -> generateAssignmentWith2Parameters("Alu.Adc", null, params);
case "ADD" -> generateAssignmentWith2Parameters("Alu.Add", "+", params);
case "AND" -> generateAssignmentWith2Parameters("Alu.And", "&", params);
Expand All @@ -692,8 +729,8 @@ private String convertInstructionWithoutPrefixAndComment(String mnemonic, String
case "CMPSB" -> generateCmps(params, 8);
case "CMPSW" -> generateCmps(params, 16);
case "CWD" -> generateCwd();
case "DAS" -> "Cpu.Das();";
case "DAA" -> "Cpu.Daa();";
case "DAS" -> generateBcdInstructionNoParam("Das");
case "DAA" -> generateBcdInstructionNoParam("Daa");
case "DEC" -> generateDec(params, parameter1Bits);
case "DIV" -> generateDiv(params, parameter1Bits);
case "HLT" -> "return Hlt();";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,10 +31,12 @@ public String generatePushAll(Integer bits) {

public String generatePush(String[] ghidraParams, Integer bits) {
String expression = parameterTranslator.toSpice86Value(ghidraParams[0], bits);
int pushBits = bits;
if (parsedInstruction.getParameter1BitLength() == 8) {
expression = parameterTranslator.signExtendByteToUInt(expression, parsedInstruction.getInstructionBitLength());
pushBits = parsedInstruction.getInstructionBitLength();
expression = parameterTranslator.signExtendByteToUInt(expression, pushBits);
}
return generatePushToExpression(expression, bits);
return generatePushToExpression(expression, pushBits);
}

public String generatePushFlags(Integer bits) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -223,8 +223,8 @@ private Set<Integer> completePossibleValues(ParsedInstruction parsedInstruction,
private boolean isParameterModified(ParsedInstruction parsedInstruction,
Map<Integer, Set<Integer>> possibleInstructionByteValues, Integer parameter,
Integer parameterBitLength, Integer parameterOffset) {
if (parameter == null) {
// No parameter, nothing to check
if (parameter == null || parameterBitLength == null) {
// No parameter or unknown bit length, nothing to check
return false;
}
int physicalAddress = parsedInstruction.instructionSegmentedAddress.toPhysical();
Expand Down
25 changes: 20 additions & 5 deletions src/main/java/spice86/importer/FunctionCreator.java
Original file line number Diff line number Diff line change
Expand Up @@ -52,25 +52,40 @@ public void createFunctionWithDefinedBody(String name, Address entryPoint, Addre
}

public void createOrUpdateFunction(String name, Address entryPoint) {
if (!program.getMemory().contains(entryPoint)) {
log.warning("Address " + entryPoint + " is not in memory. Skipping function creation for " + name);
return;
}
if (!program.getMemory().getBlock(entryPoint).isInitialized()) {
log.warning("Address " + entryPoint + " is in uninitialized memory. Skipping function creation for " + name);
return;
}
boolean existing = program.getListing().getFunctionAt(entryPoint) != null;
if (existing) {
log.info("Re-creating function at address " + entryPoint + " with name " + name);
} else {
log.info("Creating function at address " + entryPoint + " with name " + name);
}
if (!runCreateFunctionCommand(entryPoint, name, existing)) {
throw new RuntimeException("Failed to create function at " + entryPoint);
String error = runCreateFunctionCommand(entryPoint, name, existing);
if (error != null) {
log.error("Failed to create function at " + entryPoint + ": " + error + ". Skipping.");
return;
}
markFunctionAsReturning(entryPoint);
}

private void markFunctionAsReturning(Address entryPoint) {
Function function = program.getListing().getFunctionAt(entryPoint);
function.setNoReturn(false);
if (function != null) {
function.setNoReturn(false);
}
}

private boolean runCreateFunctionCommand(Address entryPoint, String name, boolean recreate) {
private String runCreateFunctionCommand(Address entryPoint, String name, boolean recreate) {
CreateFunctionCmd cmd = new CreateFunctionCmd(name, entryPoint, null, SourceType.USER_DEFINED, false, recreate);
return cmd.applyTo(program, taskMonitor);
if (cmd.applyTo(program, taskMonitor)) {
return null;
}
return cmd.getStatusMsg();
}
}