Skip to content
Merged
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
6 changes: 4 additions & 2 deletions NESDecompiler.Core/Decompilation/DecompiledFunction.cs
Original file line number Diff line number Diff line change
Expand Up @@ -39,11 +39,13 @@ public 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();
}
Expand Down
13 changes: 7 additions & 6 deletions NESDecompiler.Core/Decompilation/FunctionDecompiler.cs
Original file line number Diff line number Diff line change
Expand Up @@ -27,10 +27,10 @@ public static DecompiledFunction Decompile(ushort functionAddress, IReadOnlyList
// 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);
}
Expand All @@ -44,6 +44,9 @@ public static DecompiledFunction Decompile(ushort functionAddress, IReadOnlyList
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);
Expand Down Expand Up @@ -109,9 +112,7 @@ private static DisassembledInstruction GetNextInstruction(ushort address, IReadO
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);
}

Expand Down
8 changes: 8 additions & 0 deletions NESDecompiler.Core/Disassembly/Disassembler.cs
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,14 @@ public class DisassembledInstruction
/// </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>
Expand Down
Loading