beardypig/ghidra-emotionengine

VU decompilation seems unsound

Opened this issue · 2 comments

Below I will attempt to argue that the current approach to decompiling VU code is detrimental and the P-Code implementation of all VU instructions should be replaced with pcodeop stubs (maybe, see below). Overall I don't find what the decompiler emits currently to be useful, although I admit that my workflow may be different to the workflow of others. As such, I want anyone who's worked with VU code in the past to weigh in below. I want to get as many opinions as I can to get more of a representative sample.

In micro mode:

  • A common mechanism for passing data between the EE core and a VU0 microprogram is to pass the data in the vf registers (e.g. the R&C games do this). This breaks data flow analysis since the value of registers being worked with will change in a way that is not predictable from the perspective of either the code running on the EE core or the VU0 microprogram. For example, a spin loop could be constructed on the EE core that waits for data on VU0 (or vice versa) by repeatedly checking the value of a specific register. This primarily seems to be a problem with instructions that transfer data between the EE core and VU0, so I suspect replacing these with pcodeop stubs would do the trick.

  • Tangentially related: Usually when I'm reversing micromode-related code on the EE core it's more convenient to extract the relevant microprogram into a seperate file. I think this means that treating VU0 as a separate processor in Ghidra would be more convenient that setting a context register. This seems like it would be a nice feature.

In macro mode:

  • Data flow analysis here seems like a much more reasonable goal, although when I see VU code, I always just drop to reading the assembly, and I don't see how anything else is really practical. As such, the main thing the decompiler could do to help me is tell me whether VU code exists. Currently, lots of VU code seems to decompile to nothing, and instructions that decompile more correctly result in long code output that is indistinguishable to regular MIPS code output, so if every instruction generated pcodeop stubs this would be helpful. Maybe this could be done optionally via a context register. I don't like having to set lots of random context registers manually, although if it's once per file I suppose that's okay. If anyone's aware of a more appropriate configuration mechanism please tell me about it.

On a side note, a lot of the MMI instructions have a similar issue in that the p-code as written produces a lot of unnecessary branches for things like clamping. I think in this case the solution could be to replace clamp operations with pcodeop stubs as well.

I've been using a modified version of ghidra-emotionengine that removes support for micromode, and replaces the implementation of all VU instructions with pcodeop stubs (basically it reverts a bunch of stuff to how it was in PR#23). I expect this would not be a good solution for merging into master as it removes some features, although I find this quite useful. It seems to be more correct and it's certainly closer to what the original code would have looked like.

I suppose the main counterargument to all of this would be that we have the disassembly, so this is at most a minor inconvenience. This is also why it took so long to file this issue, it's not exactly a deal breaker for reversing VU code. Still, my position is that correctness should be favored in this case. I don't see the point of doing all this fancy analysis if there's no guarantee that the result of said analysis is correct.

I agree. It is quite broken and I'm not even sure why I submitted it along with the rest of the vu stuff.

I always confuse myself with the vu modes. The vu instructions mixed in on the EE side are working correctly right?

Now I think about it I can't think of an example where pure VU macro instructions on the EE core-side decompile to nothing when there is not a microprogram involved. I was probably thinking of cases where they were trying to transfer data to/from a microprogram, in which case it is broken on the EE core-side and VU macro instructions typically aren't involved (but lqc2/sqc2/qmtc/qmfc/ctc2 are).

As to whether the code for the macro instructions is technically correct I'm not sure. There's a lot of output with p-code op business that I'm not sure about.