When a function is decompiled in the middle of a function, and that function
has a jump point prior to the function's entry point, we need to add a
fake virtual instruction that jumps back to the start of the function.
The virtual instruction needs to be the last instruction in the
ordered instruction set.
We previously accomplished that by adding an instruction at the
location of the function entrypiont minus one. However, this was
failing in cases where a system would cause an interrupt right on
the virtual address. Emulators would then save the virtual
instruction's address to the stack, and jump back into that address
once RTI occurs.
This fails because the virtual address can't be decompiled, because
legit code doesn't exist at that address.
To fix this, I updated the `SubAddressOrder` property to allow for negative
values. This allows the loopback instruction to be on the correct CPUAddress
while still being ordered as expected.
Also ensured that virtual addresses do not get labels, as they are not
actually valid jump targets.
When tracing a function, previously we were throwing an exception
if we encountered an invalid / unknown op code. This is needed because
we don't know how many bytes the instruction contains and thus can't
accurately predict where the next instruction would be.
However, some roms (like super mario bros) use an always taken
branch instruction to save bytes instead of a jump. In this case
the next byte after the branch is an invalid op code that will never
actually be hit.
So this change makes it so that invalid operations act as an end
of function markers, but throw a warning in the console. That
allows unconditional/always branches to work, and for games that
actually use these unofficial op codes they are able to get hints
in the debug window.
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.
Since the entry point for analysis could be in the middle of a loop,
we need to guarantee that a jump is dedicated to the entrypoint, so
that an instruction that comes before the "entrypoint" will redirect
back to the entrypoint after execution