diff --git a/build.gradle b/build.gradle index 2ad1d73..cb53ab6 100644 --- a/build.gradle +++ b/build.gradle @@ -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 + diff --git a/src/main/java/spice86/generator/FunctionGenerator.java b/src/main/java/spice86/generator/FunctionGenerator.java index 28e3ac4..d8e3f42 100644 --- a/src/main/java/spice86/generator/FunctionGenerator.java +++ b/src/main/java/spice86/generator/FunctionGenerator.java @@ -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 diff --git a/src/main/java/spice86/generator/ProgramGenerator.java b/src/main/java/spice86/generator/ProgramGenerator.java index c383fc9..6bea0aa 100644 --- a/src/main/java/spice86/generator/ProgramGenerator.java +++ b/src/main/java/spice86/generator/ProgramGenerator.java @@ -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() { @@ -83,13 +86,15 @@ private String generateClassDeclaration() { private String generateConstructor() { String res = - "public GeneratedOverrides(Dictionary functionInformations, Machine machine, ushort entrySegment = " + "public GeneratedOverrides(Configuration configuration,\n" + + " IDictionary 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; @@ -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 } } diff --git a/src/main/java/spice86/generator/instructiongenerator/InstructionGenerator.java b/src/main/java/spice86/generator/instructiongenerator/InstructionGenerator.java index 3a8d849..91f5307 100644 --- a/src/main/java/spice86/generator/instructiongenerator/InstructionGenerator.java +++ b/src/main/java/spice86/generator/instructiongenerator/InstructionGenerator.java @@ -170,6 +170,11 @@ 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 + ")"); } @@ -177,6 +182,11 @@ private String generateAssignmentWith2ParametersOnlyOneOperand(String operation, 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 + ")"); } @@ -202,7 +212,14 @@ 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; } @@ -210,6 +227,12 @@ private String generateNoAssignmentWith2Parameters(String operation, String[] pa 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 + ");"; } @@ -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); } @@ -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); } @@ -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) { @@ -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]); @@ -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)); @@ -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)); @@ -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 = @@ -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) { @@ -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(); @@ -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); @@ -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();"; diff --git a/src/main/java/spice86/generator/instructiongenerator/PushGenerator.java b/src/main/java/spice86/generator/instructiongenerator/PushGenerator.java index 3f04680..5582fc1 100644 --- a/src/main/java/spice86/generator/instructiongenerator/PushGenerator.java +++ b/src/main/java/spice86/generator/instructiongenerator/PushGenerator.java @@ -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) { diff --git a/src/main/java/spice86/generator/parsing/ParsedInstructionBuilder.java b/src/main/java/spice86/generator/parsing/ParsedInstructionBuilder.java index 1520ef2..d6fb146 100644 --- a/src/main/java/spice86/generator/parsing/ParsedInstructionBuilder.java +++ b/src/main/java/spice86/generator/parsing/ParsedInstructionBuilder.java @@ -223,8 +223,8 @@ private Set completePossibleValues(ParsedInstruction parsedInstruction, private boolean isParameterModified(ParsedInstruction parsedInstruction, Map> 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(); diff --git a/src/main/java/spice86/importer/FunctionCreator.java b/src/main/java/spice86/importer/FunctionCreator.java index 4e297d2..0423ec0 100644 --- a/src/main/java/spice86/importer/FunctionCreator.java +++ b/src/main/java/spice86/importer/FunctionCreator.java @@ -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(); } }