mirror of
https://github.com/ApfelTeeSaft/NESDecompiler.git
synced 2026-08-26 19:33:30 +00:00
Merge pull request #10 from KallDrexx/support_virtual_instructions
Allow for sub address instructions. When a wrap around scenario is detected during single function tracing, if the address prior to the "entry point" is a single byte, then we do not have any space to add the required jump call. This fixes that by adding the concept of sub address instructions. This allows adding instructions at runtime that get sorted correctly against the real instructions from the ROM. This not only solves the wrapping issue, but also allows for adding hooks at runtime.
This commit is contained in:
@@ -39,11 +39,13 @@ public class DecompiledFunction
|
||||
// the first instruction.
|
||||
var initialInstructions = instructions
|
||||
.Where(x => x.CPUAddress >= address)
|
||||
.OrderBy(x => x.CPUAddress);
|
||||
.OrderBy(x => x.CPUAddress)
|
||||
.ThenBy(x => x.SubAddressOrder);
|
||||
|
||||
var trailingInstructions = instructions
|
||||
.Where(x => x.CPUAddress < address)
|
||||
.OrderBy(x => x.CPUAddress);
|
||||
.OrderBy(x => x.CPUAddress)
|
||||
.ThenBy(x => x.SubAddressOrder); // real instructions before virtual ones
|
||||
|
||||
OrderedInstructions = initialInstructions.Concat(trailingInstructions).ToArray();
|
||||
}
|
||||
|
||||
@@ -27,10 +27,10 @@ public static class FunctionDecompiler
|
||||
// the function entrance. This usually happens when there is a jump/branch to right before the
|
||||
// entrypoint, usually due to decompiling in the middle of a loop. To fix this, we need to add
|
||||
// a jump back to the function entrypoint
|
||||
if (functionAddress == 0x00 || seenInstructions.Contains((ushort)(functionAddress - 1)))
|
||||
if (functionAddress == 0x00)
|
||||
{
|
||||
var message = $"Function 0x{functionAddress:X4} wraps around, but there's not enough " +
|
||||
$"space to add a jump back to the entrypoint";
|
||||
const string message = "Wrap around instruction detected for a function at 0000, but that " +
|
||||
"doesn't make sense";
|
||||
|
||||
throw new InvalidOperationException(message);
|
||||
}
|
||||
@@ -44,6 +44,9 @@ public static class FunctionDecompiler
|
||||
CPUAddress = (ushort)(nextAddress - 1),
|
||||
Bytes = [0x4C, (byte)addressLow, (byte)addressHigh],
|
||||
TargetAddress = functionAddress,
|
||||
|
||||
// Make sure they appear after any instruction that already occupies that address
|
||||
SubAddressOrder = 1,
|
||||
};
|
||||
|
||||
instructions.Add(jumpInstruction);
|
||||
@@ -109,9 +112,7 @@ public static class FunctionDecompiler
|
||||
var info = InstructionSet.GetInstruction(bytes[0]);
|
||||
if (!info.IsValid)
|
||||
{
|
||||
var message = $"Attempted to get instruction at address 0x{address:X4}, but byte 0x{bytes[0]:X4} " +
|
||||
$"is not a valid/known opcode";
|
||||
|
||||
var message = $"Opcode 0x{bytes[0]:X2} at address 0x{address:X4} is not a known instruction";
|
||||
throw new InvalidOperationException(message);
|
||||
}
|
||||
|
||||
|
||||
@@ -72,6 +72,14 @@ namespace NESDecompiler.Core.Disassembly
|
||||
/// </summary>
|
||||
public bool IsJump => Info.Mnemonic == "JMP" || Info.Mnemonic == "JSR";
|
||||
|
||||
/// <summary>
|
||||
/// Determines the order of this instruction within a single address space. This is mostly
|
||||
/// needed in the cases that additional instructions are needed to be added in the same
|
||||
/// address location at runtime. Can be used to add runtime hooks or to work around
|
||||
/// decompilation issues. Should be 0 for all native instructions from a ROM.
|
||||
/// </summary>
|
||||
public byte SubAddressOrder { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Returns a string representation of this instruction
|
||||
/// </summary>
|
||||
|
||||
Reference in New Issue
Block a user