User:Kmeisthax/Findings/2011/6/6/v60 Patch Notes

From Wikifang, a definitive guide to Telefang, Dino Device and Bugsite
Jump to navigation Jump to search

(If you're wondering, "advice" means "code placed into empty ROM space" and "pointcut" means "jumps to advice injected into live function". The terms are taken from aspect oriented programming but unlike AOP we're monkey patching it ourselves)

ROM B:7E29 VWF fix hack

First, to make our advice execute, we need to insert this pointcut...

   jp [ADDR_OF_PATCH] = 3 bytes displaced
    = C3 7C 00

The beginning of the function looks like this

   push HL = 1 byte
   ld B,0 = 2 bytes

So our advice looks like this:

   ld [C7C1],A == EA C1 C7
   push HL = E5
   ld B,0 = 06 00
   jp [ADDR_OF_OLD_CODE + 3] = C3 ?? ??
      [7E2C] = C3 2C 7E
  

The old code lives at 7E29, we finish our advice at 7E2C

Finally, where to insert our advice... ROM B:7C00 looks empty. It's right after the glyph tables, so we'll insert code here. 0x9 bytes are written.

ALSO, there's unused HOME BANK SPACE!!! 0x77 to 0x100 are unused even though it's perfectly valid to do so.

WRAM C7C5 is 1 when we need to write to another tile. Currently the "Denjuu Name Renderer" in HOME blindly increments the tile pointer, which is wrong behavior. Let's insert advice to fix this!

The offending lines are in HOME 3AA3...

   3aa3: pop HL
   3aa4: ld BC, $10
   3aa7: add HL, BC
   3aa8: <other stuffs...>

I would like to add the following effect.

   ld A, [C7C5]
   cp 1
   jp z, [ADDR_WHERE_WE_INCREMENT_HL] = [3AA7]
   jp [ADDR_WHERE_WE_DONT_INCREMENT_HL] = [3AA8]

Like before our pointcut takes 3 bytes, so we need to also move 3 bytes of instructions into the advice, like so...

   ;originally 3AA4
   ld BC, $10   = 01 10 00
   ld A, [C7C5] = FA C5 C7
   cp 1         = FE 01
   jp z, [3AA7] = CA A7 3A
   jp [3AA8]    = C3 A8 3A

We now must decide where to store the advice. Let's use the empty space in 0x77. This goes from 0x77 to 0x85 using 0xE precious bytes from the HOME padding area.

Then edit our pointcut...

   3AA4: jp [0077] = C3 77 00

It should be done.

BUT WAIT THERE'S MORE!

VWF state isn't being set properly. We're getting garbage bytes on the next thing to use the VWF! In the VWF state there's a byte called OldTileMode (WRAM C7C5). It's 0 when the current tile still has room for another glyph, 1 when we need a new VRAM tile, and 2 when we start up a new line of text! When we're done with the current line we need to set Mode 2 and set the "VWFLetterShift" (WRAM C7C2) to 0.

CALL NOW, AND WE'LL TRIPLE THE ORDER AND SEND YOU THREE D-SHOTS, FOR ONLY $19.95!

Okay, so now we need to attach ourselves to the end of the loop. It looks like this:

   3AB2: dec b
   3AB3: jp nz, DrawStringToScreen
   3AB6: ret

We can replace the absolute jump conditional with a regular absolute jump into more advice that looks like this:

   jp nz, DrawStringToScreen
   ld A, 2
   ld [C7C5], A
   ld A, 0
   ld [C7C2], A
   ret

The original ret on the original function is now useless. Our advice returns for it. So then let's look at what this advice codes as...

   C2 95 3A
   3E 02
   EA C5 C7
   3E 00
   EA C2 C7
   C9

We'll place our advice right after the last advice in that free HOME area. That place is getting a little crouded... 0x85 stores the start of our advice and it goes on to 0x92 for a total of another 0xE bytes. So that's a total of 0x1C bytes of advice code.

And our pointcut just becomes...

   3AB3: jp 0085 = C3 85 00

BUT I'M NOT DONE YET!

There's another way to bail out of this routine if we encounter E0 in the string. This time, since we have a useless RET byte before it I might as well also move the bailout code up one byte. This particular bailout lives at HOME 3AB7 and is only referenced by 3A9B...

   3A99: cp $E0
   3A9B: jp z, loc_3AB7
   3AB7: pop hl
         pop de
         pop bc
         ret

Even after moving 3AB7 back I still need 3 bytes for a jump. So POP BC gets to piggyback on my advice.

Here's what our advice should look like:

   pop bc = C1
   jp 88 = C3 88 00

Our advice will live at 0x93, so we could technically make that a jr instead:

   pop bc = C1
   jr PC-0C = 18 F2

A marvelous three byte routine! And finally, let's make our pointcut...

   3A99: cp $E0
   3A9B: jp z, loc_3AB6
   3AB6: pop hl
         pop de
         jp 0x93 = C3 93 00