Mag truck

Technical discussion for those interested in Supermodel development and Model 3 reverse engineering. Prospective contributors welcome.
Forum rules
Keep it classy!

  • No ROM requests or links.
  • Do not ask to be a play tester.
  • Do not ask about release dates.
  • No drama!

Mag truck

Postby Ian » Sun Dec 12, 2021 4:29 pm

This is probably the most broken game currently in supermodel, well the attract sequence is anyway. If you leave it long enough eventually it stops rendering 3d all together. But what is happening exactly?
Well from what I can see the entire matrix stack gets filled with NaNs. So that means the model matrix (the matrix that sets the position for the model in the scene) is just filled with NaNs instead of float values.

Image

The NaNs also show up in the viewport data as broken light angles. Just the x/y/z angle is broken, the other parameters seem fine.

Image

Nan values also leak into some of the ram models. (Models generated on the CPU and uploaded to the GPU).

Image

So what is happening? I have a few theories.
Perhaps we have incomplete NaN emulation. Maybe there is some CPU mode which handles these numbers differently?
Other ideas are, maybe the game is reading the time, and if it hasn't been incremented between frames it gives a 0, which causes a divide by zero error.
Perhaps there is something the GPU is not returning in the stat packet, such as the frame number or some clock value, which should be incremented every frame, and this is causing a divide by zero error.
Maybe bad ROM ?
Ian
 
Posts: 2044
Joined: Tue Feb 23, 2016 9:23 am

Re: Mag truck

Postby Ian » Sun Dec 19, 2021 7:29 am

Just a small update. I put a breakpoint here, and caught the number / zero condition.
It seems to happen just once per frame, and if I override the denominator then the model matrices are no longer garbage, viewport light parameters look correct etc, although it still renders a black screen. Not sure what the proper float value should be. So I don't think this is some timing issue, or some kind of data transfer problem.

Image

I think the CPU is reading some value from maybe the 3d h/w or something, which shouldn't be zero, but it is. If we can find out what this value is I think we can fix it.
Ian
 
Posts: 2044
Joined: Tue Feb 23, 2016 9:23 am

Re: Mag truck

Postby Bart » Mon Dec 20, 2021 1:28 pm

If we could narrow it down to a particular division instruction (there might be a few), it should be possible to home in on what is being read from where to load that register.
User avatar
Bart
Site Admin
 
Posts: 3086
Joined: Thu Sep 01, 2011 2:13 pm
Location: Reno, Nevada

Re: Mag truck

Postby Bart » Mon Dec 20, 2021 1:31 pm

Also, I don't think it's the case with MagTruck, but there are actually 4 IRQs associated with the video hardware and we only understand one of them. I was never able to figure out what the others do. I don't recall any game that relies on them but I wonder if my memory is off and MagTruck does something with those IRQs.

I'm rushing to get an AR game for Snapchat out but that should be done this week and I'll try to spend Christmas day looking into some of the various things that have come up lately. What better way to pass the time than with my old friend Model 3 :D
User avatar
Bart
Site Admin
 
Posts: 3086
Joined: Thu Sep 01, 2011 2:13 pm
Location: Reno, Nevada

Re: Mag truck

Postby Ian » Mon Dec 20, 2021 2:25 pm

The divide by zero really happens once per frame in the part that's broken. Just let the attract sequence run until the screen turns black. If you put a breakpoint the same as in my screenshot above you can catch it and prevent the nans propagating

Of course if you don't catch and handle this value it seems to get multiplied all over the place.

My guess was it's some sort of time difference value. If you are doing any sort of animation or interpolation of light angles you need the difference in time in order to work out the correct incrementation value.

I was messing about with the real3d registers. Just guessing really. One of the values it returns is the time the hw took to process the frame. But I'm pretty sure the game is not using this value.

Time difference between irqs sounds like an avenue worth exploring:)

Snapchat has AR games?? :)
Ian
 
Posts: 2044
Joined: Tue Feb 23, 2016 9:23 am

Re: Mag truck

Postby Bart » Mon Dec 20, 2021 3:11 pm

Ian wrote:The divide by zero really happens once per frame in the part that's broken. Just let the attract sequence run until the screen turns black. If you put a breakpoint the same as in my screenshot above you can catch it and prevent the nans propagating

Of course if you don't catch and handle this value it seems to get multiplied all over the place.

My guess was it's some sort of time difference value. If you are doing any sort of animation or interpolation of light angles you need the difference in time in order to work out the correct incrementation value.

I was messing about with the real3d registers. Just guessing really. One of the values it returns is the time the hw took to process the frame. But I'm pretty sure the game is not using this value.

Time difference between irqs sounds like an avenue worth exploring:)


I think I've seen games computing time deltas based on some of these other IRQs but I've never found one that then uses those values. I think they were just standard stub IRQ handlers that were never really employed. And I thought MagTruck was that way too but I can check again. I should have a disassembly of it somewhere.

Snapchat has AR games?? :)


Yeah, surprisingly! What began as just a "face filter" platform, Lens Studio, is surprisingly full-featured and now supports world mesh reconstruction even on non-Lidar phones. It uses JavaScript as its scripting language and even includes a physics engine now that I suspect is based on PhysX, just like Unity's. Not a fan of the app, personally, but Snap has been funding AR developers building on both the phone and their experimental Spectacles AR glasses. They're definitely pursuing a consumer AR device and are essentially outsourcing their prototyping to the broader community, which is an interesting approach.
User avatar
Bart
Site Admin
 
Posts: 3086
Joined: Thu Sep 01, 2011 2:13 pm
Location: Reno, Nevada

Re: Mag truck

Postby gm_matthew » Fri Dec 24, 2021 7:35 pm

I've found out where the division by zero is happening: at 0x1a660 the game reads two vectors (one at 0x24f424, the other at 0x24f430), subtracts one from the other, and passes the result to the subroutine at 0x1466c4. This subroutine calculates the magnitude of the passed vector based on the x and z values, and then performs some division by this magnitude. The problem is that the two stored vectors have identical x and z values, so when one is subtracted from the other both x=0 and z=0, which results in the calculated magnitude being zero and hence division by zero!

During the bit of the attract sequence where the 3D stops working altogether, the code at 0x19e60 writes to the vector at 0x24f424 and 0x1a168 writes to the vector at 0x24f430. Presumably the error we're looking for must be somewhere in the calculation of these vectors... that's as far as I've got.
gm_matthew
 
Posts: 224
Joined: Fri Oct 07, 2011 7:29 am
Location: Bristol, UK

Re: Mag truck

Postby Bart » Sat Dec 25, 2021 10:04 pm

gm_matthew wrote:I've found out where the division by zero is happening: at 0x1a660 the game reads two vectors (one at 0x24f424, the other at 0x24f430), subtracts one from the other, and passes the result to the subroutine at 0x1466c4. This subroutine calculates the magnitude of the passed vector based on the x and z values, and then performs some division by this magnitude. The problem is that the two stored vectors have identical x and z values, so when one is subtracted from the other both x=0 and z=0, which results in the calculated magnitude being zero and hence division by zero!

During the bit of the attract sequence where the 3D stops working altogether, the code at 0x19e60 writes to the vector at 0x24f424 and 0x1a168 writes to the vector at 0x24f430. Presumably the error we're looking for must be somewhere in the calculation of these vectors... that's as far as I've got.


That's helpful! I'm going to take a look at it more tomorrow. The value that is written to 0x24f424 is read from 0x7fcea0. This address is assembled as an offset from the address in register r31, which is probably a global pointer generated by the compiler for accessing global variables. You can see that this particular variable is accessed in a several places throughout the code by searching the disassembly for "r31,0xA8". E.g.:

Code: Select all
0x00019E50: 0x395F00A8   addi   r10,r31,0xA8  ; r10 = 0x7fcea0, r31 = 0x7fcdf8
User avatar
Bart
Site Admin
 
Posts: 3086
Joined: Thu Sep 01, 2011 2:13 pm
Location: Reno, Nevada

Re: Mag truck

Postby gm_matthew » Sun Dec 26, 2021 6:11 am

Bart wrote:That's helpful! I'm going to take a look at it more tomorrow. The value that is written to 0x24f424 is read from 0x7fcea0. This address is assembled as an offset from the address in register r31, which is probably a global pointer generated by the compiler for accessing global variables. You can see that this particular variable is accessed in a several places throughout the code by searching the disassembly for "r31,0xA8". E.g.:

Code: Select all
0x00019E50: 0x395F00A8   addi   r10,r31,0xA8  ; r10 = 0x7fcea0, r31 = 0x7fcdf8


Except there's this bit at the beginning of the subroutine:

Code: Select all
0x00019C5C: 0x7C3F0B78  or  r31,r1,r1


So in this subroutine r31 is used for accessing local variables on the stack, not global variables.

Code: Select all
0x00019DDC: 0x381F00A8  addi    r0,r31,0xA8

0x00019E2C: 0x7C030378  or  r3,r0,r0

0x00019E40: 0x4BFFB315  bl  0x00015154


The address of this local variable is passed to the subroutine at 0x15144, which seems to create a vector based on the following steps:

    create identity matrix
    add pitch transformation
    add roll transformation
    apply transformation to vector (0.0, 0.0, f1)
    translate vector by vector pointed to by r4 (copied from vector at 0x227670 before subroutine is called)

The result is stored in the local variable at r31+0xa8, which is then written to 0x24f424 as we've established.

I recently discovered the existence of Ghidra which is like IDA Pro but is free and open source; it even attempts to decompile PowerPC code into C-like code! It's not perfect, but it's been proving very useful in understanding what is happening during subroutines that I would have had to decompile manually before. Even so, I'm really struggling to find exactly what is causing the vectors to end up with identical x and z values...
gm_matthew
 
Posts: 224
Joined: Fri Oct 07, 2011 7:29 am
Location: Bristol, UK

Re: Mag truck

Postby Bart » Sun Dec 26, 2021 1:33 pm

gm_matthew wrote:So in this subroutine r31 is used for accessing local variables on the stack, not global variables.


Ah, you are correct!

    create identity matrix
    add pitch transformation
    add roll transformation
    apply transformation to vector (0.0, 0.0, f1)
    translate vector by vector pointed to by r4 (copied from vector at 0x227670 before subroutine is called)


This is interesting. So it's just trying to compute some sort of look direction or something. When it constructs the pitch and roll transform, is it creating standard rotation matrices? If so, it must be computing these from pitch and roll angles. Do we know what those angles are? That is, are they zero or some non-zero value?

Whatever is computing those angles is probably not updating the angles as expected. This could be something that is influenced by a timing parameter. However, I just tried firing IRQs 0x08, 0x04, and 0x01 at different times and it doesn't change the situation here. That doesn't rule out a timing dependency because it could be reading e.g., a Real3D or tilegen status register (or something else entirely) and computing timing based on when that changes.

I wonder if I could intercept each time the time base registers are read and check if any subsequent calculation yields a 0 (usually TBR reads are followed by some arithmetic to compute a deltaTime). I fear that there will be a zillion of these to search through, though. I'll take a look in a moment...
User avatar
Bart
Site Admin
 
Posts: 3086
Joined: Thu Sep 01, 2011 2:13 pm
Location: Reno, Nevada

Next

Return to The Dark Room

Who is online

Users browsing this forum: No registered users and 1 guest