Trapping LDR's in page zero

Discuss development specific to the Pi version of ADFFS
Post Reply
JonAbbott
Posts: 2938
Joined: Thu Apr 11, 2013 12:13 pm
Location: Essex
Contact:

Trapping LDR's in page zero

Post by JonAbbott »

Just had a thought on how to implement this by changing the JIT core. This should remove the need to manually fix up IRQ/IRQ1v exit instructions past RO3.11:
  • Exit the JIT if the next instruction is an LDR that would ordinarily be copied (coded)
  • If the current instruction is an LDR that needs copying, interpret the instruction and pass to the page_zero_abort handler if the read address is below &4000 (coded)
  • Add read abort handling to page_zero_abort (coded)
  • Allow page_zero_abort to return to the JIT (coded)
  • For &18 set Rd to B x (&EAxxxxxx) where x points to a MOV PC, R14 instruction below 32mb and then skip the instruction (coded)
  • For &100 set Rd to an address of a MOV PC, R14 instruction below 32mb and then skip the instruction (coded)
  • All other addresses can return to the JIT without skipping the instruction (coded)
  • Remove code in abort_handler that restores IRQv and IRQ1v (coded)
  • Remove code in page_zero_abort that checks for IRQ1v being released (coded)
  • Remove code in page_zero_abort that checks for fixups when IRQv and IRQ1v are written too (coded)
This may need some jiggery pokery to implement as the JIT stacks R0-R7 and would need to store all registers in the abort handlers register dump to both interpret and handle any subsequent read abort.
JonAbbott
Posts: 2938
Joined: Thu Apr 11, 2013 12:13 pm
Location: Essex
Contact:

Re: Trapping LDR's in page zero

Post by JonAbbott »

Whilst testing this today, it's highlighted an interesting question - what to do about bugs in games?

The second game I tested (Fire & Ice) tries to read from a variable it's yet to define and ends up reading from page zero. This is a problem because the JIT reports any read from a page zero address it can't handle. I've either got to turn this check off, fix the bugs in the games or handle every page zero address.

Handling every page zero address is a massive amount of work and may not even be possible where values can't be obtained legally in RO5. Fixing bugs is time consuming and not guaranteed to get every bug without play testing. Turning off the check runs the risk of returning an invalid value where they've changed or moved across RISCOS versions
JonAbbott
Posts: 2938
Joined: Thu Apr 11, 2013 12:13 pm
Location: Essex
Contact:

Re: Trapping LDR's in page zero

Post by JonAbbott »

JonAbbott wrote:what to do about bugs in games?
See this post for details on games that inadvertently access page zero due to bugs.
JonAbbott
Posts: 2938
Joined: Thu Apr 11, 2013 12:13 pm
Location: Essex
Contact:

Re: Trapping LDR's in page zero

Post by JonAbbott »

JonAbbott wrote:Rotor
I've fixed the bug in Rotor

It tries to write a string to screen, but the string pointer is 0 the first time the game is loaded. I've put a check for zero and it now exits the function if it's not set.
morb
Posts: 8
Joined: Wed Jan 28, 2015 11:57 pm

Re: Trapping LDR's in page zero

Post by morb »

JonAbbott wrote:Whilst testing this today, it's highlighted an interesting question - what to do about bugs in games?

The second game I tested (Fire & Ice) tries to read from a variable it's yet to define and ends up reading from page zero. This is a problem because the JIT reports any read from a page zero address it can't handle. I've either got to turn this check off, fix the bugs in the games or handle every page zero address.

Handling every page zero address is a massive amount of work and may not even be possible where values can't be obtained legally in RO5. Fixing bugs is time consuming and not guaranteed to get every bug without play testing. Turning off the check runs the risk of returning an invalid value where they've changed or moved across RISCOS versions
Can you work in a runtime configuration flag which switches this read check on / off? Obviously not ideal, but at least it puts the more risky behaviour under the user's control.
JonAbbott
Posts: 2938
Joined: Thu Apr 11, 2013 12:13 pm
Location: Essex
Contact:

Re: Trapping LDR's in page zero

Post by JonAbbott »

morb wrote:Can you work in a runtime configuration flag which switches this read check on / off? Obviously not ideal, but at least it puts the more risky behaviour under the user's control.
I'm considering adding a command to turn the check off, but leave it on by default. Although I can fix the bugs, there's no guarantee I'll get them all from limited play testing and more are bound to come up in the future in other games.

I'm surprised some of these games don't crash on Arcs, as very often they're writing to memory based on the variable read - which clearly is rubbish as it's come from page zero. Luck I guess.
JonAbbott
Posts: 2938
Joined: Thu Apr 11, 2013 12:13 pm
Location: Essex
Contact:

Re: Trapping LDR's in page zero

Post by JonAbbott »

I'm almost done with testing all the known working games on StrongARM. This method of LDR detection seems to be working reliably with no noticeable performance impact. I'll move onto testing on the Pi next week.

One thing it has highlighted is that I should probably merge all the instruction decoders into one routine and implement post-indexed updating of registers (eg LDR Rd, [Rn], #4 should increase Rn by 4) in some of the existing abort handlers (IOC and MEMC don't currently increase Rn for example).

This is the only fully interpreted instruction handler in ADFFS, up to now it's only performed post abort instruction fix-ups to correct for changes in the way ARM handles aborts. Provided the LDR is reading memory outside of page zero, the instruction is copied and if it's within page zero it remains interpreted. These instructions tend to be during the setup phase of the game, so there's no performance impact.
JonAbbott
Posts: 2938
Joined: Thu Apr 11, 2013 12:13 pm
Location: Essex
Contact:

Re: Trapping LDR's in page zero

Post by JonAbbott »

This looks like a bigger issue than I first thought, around a third of known working games read from unset variables.

They could be down to the C compiler used, or simply missed bugs in the original code. Trying to fix them all is going to be an uphill struggle, so I'm now considering turning the check off and returning 0 for any read ADFFS doesn't know how to handle. Where games have obvious issues, I'll have to turn the check back on during testing and add support for any addresses the games are trying to read on purpose.

I know a few Krysalis titles that I've yet to add support for do read from page zero, there's also a few obvious ones I can add:

18 - IRQ Hardware Vector (coded)
100 - IRQ1V (coded)
114 - MEMC_CR_SoftCopy
5B4 - MouseX
5B8 - MouseY
9B2 - VULACopy (ignored - Oh, No! More Lemmings)
AE8 - EnvString
10C0 - ScreenStart
1178 - DisplayStart
117C - DriverBankAddr
1180 - DisplayBankAddr
1228 - VIDCClockSpeed
1474 - HSWRSoftCopy
1478 - HSWRSoftCopy
1584 - VIDCControlCopy
JonAbbott
Posts: 2938
Joined: Thu Apr 11, 2013 12:13 pm
Location: Essex
Contact:

Re: Trapping LDR's in page zero

Post by JonAbbott »

I've spent the day fixing the bugs in the games detailed above. I'm having trouble getting Heimdall to error, so will come back to that.

Of course, there's no guarantee there aren't more bugs so I'll have to deal with them as people report them once it's released.
JonAbbott
Posts: 2938
Joined: Thu Apr 11, 2013 12:13 pm
Location: Essex
Contact:

Re: Trapping LDR's in page zero

Post by JonAbbott »

Another day finding bugs in games, Conqueror's taken a few hours to track down. Turns out it was hardcoded to support only support three sound voices. WaveSynth is normally mapped as voice 1, making Conqueror's last sound voice 4 ... which consequently overflows into the code.

It doesn't crash on most machines due to pure luck, the values it writes become valid instructions that only execute if the Z flag is set.
Post Reply