User:Kmeisthax/Findings/2011/6/10/v67 Patch Notes
Cleared Tile Fix
The Cleared Tile Glitch happens when the VWF core draws tiles. It will always draw one extra tile most of the time. In normal operation (i.e. drawing to successive tiles) this is fine, but if things are drawn in reverse order then some tiles may be cleared. Let's fix that.
If you're wondering, here's the current state of the VWF:
ROM:0002F9C1 ; --------------------------------------------------------------------------- ROM:0002F9C1 nop ROM:0002F9C2 nop ROM:0002F9C3 nop ROM:0002F9C4 nop ROM:0002F9C5 nop ROM:0002F9C6 nop ROM:0002F9C7 nop ROM:0002F9C8 nop ROM:0002F9C9 nop ROM:0002F9CA nop ROM:0002F9CB nop ROM:0002F9CC nop ROM:0002F9CD nop ROM:0002F9CE nop ROM:0002F9CF nop ROM:0002F9D0 nop ROM:0002F9D1 nop ROM:0002F9D2 nop ROM:0002F9D3 ld b, 8 ROM:0002F9D5 ld a, $CF ; '-' ROM:0002F9D7 ld [WRAM_VWF_CompositingArea0], a ROM:0002F9DA ld a, $D0 ; '-' ROM:0002F9DC ld [WRAM_VWF_CompositingArea1], a ROM:0002F9DF push bc ROM:0002F9E0 push de ROM:0002F9E1 push hl ROM:0002F9E2 di ROM:0002F9E3 ld a, [WRAM_VWF_CompositingArea0] ROM:0002F9E6 ld h, a ROM:0002F9E7 ld a, [WRAM_VWF_CompositingArea1] ROM:0002F9EA ld l, a ROM:0002F9EB ld b, [hl] ROM:0002F9EC inc hl ROM:0002F9ED ld c, [hl] ROM:0002F9EE dec hl ROM:0002F9EF ld a, [de] ROM:0002F9F0 ld d, a ROM:0002F9F1 ld e, 0 ROM:0002F9F3 ld a, [WRAM_VWF_OldTileMode] ROM:0002F9F6 cp 2 ROM:0002F9F8 jr z, loc_FA00 ROM:0002F9FA cp 1 ROM:0002F9FC jr z, loc_FA01+1 ROM:0002F9FE jr loc_FA01+2 ROM:0002FA00 ; --------------------------------------------------------------------------- ROM:0002FA00 ld c, 0 ROM:0002FA02 ld b, c ROM:0002FA03 ld a, [WRAM_VWF_LetterShift] ROM:0002FA06 or a ROM:0002FA07 jr z, loc_FA10 ROM:0002FA09 srl d ROM:0002FA0B rr e ROM:0002FA0D dec a ROM:0002FA0E jr nz, loc_FA07+2 ROM:0002FA10 ld a, d ROM:0002FA11 or b ROM:0002FA12 ld b, a ROM:0002FA13 ld c, e ROM:0002FA14 ld [hl], b ROM:0002FA15 inc hl ROM:0002FA16 ld [hl], c ROM:0002FA17 inc hl ROM:0002FA18 ld a, h ROM:0002FA19 ld [WRAM_VWF_CompositingArea0], a ROM:0002FA1C ld a, l ROM:0002FA1D ld [WRAM_VWF_CompositingArea1], a ROM:0002FA20 pop hl ROM:0002FA21 ld d, h ROM:0002FA22 ld e, l ROM:0002FA23 ld a, [byte_FF41] ROM:0002FA25 and 2 ROM:0002FA27 jr nz, loc_FA21+2 ROM:0002FA29 ld a, b ROM:0002FA2A ldi [hl], a ROM:0002FA2B ldi [hl], a ROM:0002FA2C push hl ROM:0002FA2D ld hl, $10 ROM:0002FA30 add hl, de ROM:0002FA31 ld a, [byte_FF41] ROM:0002FA33 and 2 ROM:0002FA35 jr nz, loc_FA30+1 ROM:0002FA37 ld a, c ROM:0002FA38 ldi [hl], a ROM:0002FA39 ldi [hl], a ROM:0002FA3A ei ROM:0002FA3B pop hl ROM:0002FA3C pop de ROM:0002FA3D pop bc ROM:0002FA3E inc de ROM:0002FA3F dec b ROM:0002FA40 jr nz, loc_F9DF ROM:0002FA42 ld a, 0 ROM:0002FA44 ld [WRAM_VWF_OldTileMode], a ROM:0002FA47 ld b, $7B ; '{' ROM:0002FA49 ld a, [WRAM_VWF_CurrentLetter] ROM:0002FA4C ld c, a ROM:0002FA4D ld a, [bc] ROM:0002FA4E inc a ROM:0002FA4F ld b, a ROM:0002FA50 ld a, [WRAM_VWF_LetterShift] ROM:0002FA53 add a, b ROM:0002FA54 bit 3, a ROM:0002FA56 jr z, loc_FA6D ROM:0002FA58 sub 8 ROM:0002FA5A push af ROM:0002FA5B ld a, 1 ROM:0002FA5D ld [WRAM_VWF_OldTileMode], a ROM:0002FA60 ld a, [WRAM_VWF_MainScriptHack] ROM:0002FA63 cp 1 ROM:0002FA65 jr nz, unk_FA6C ROM:0002FA67 ld a, 0 ROM:0002FA69 ld [WRAM_VWF_MainScriptHack], a ROM:0002FA6C pop af ROM:0002FA6D ld [WRAM_VWF_LetterShift], a ROM:0002FA70 ret ROM:0002FA70 ; --------------------------------------------------------------------------- ROM:0002FA71 db 0 ROM:0002FA72 db 0 ROM:0002FA73 db 0 ROM:0002FA74 db 0 ROM:0002FA75 db 0 ROM:0002FA76 db 0 ROM:0002FA77 db 0 ROM:0002FA78 db 0 ROM:0002FA79 db 0 ROM:0002FA7A db 0 ROM:0002FA7B db 0 ROM:0002FA7C db 0 ROM:0002FA7D db 0 ROM:0002FA7E db 0 ROM:0002FA7F db 0 ROM:0002FA80 db 0 ROM:0002FA81 db 0 ROM:0002FA82 db 0 ROM:0002FA83 db 0 ROM:0002FA84 db 0 ROM:0002FA85 db 0 ROM:0002FA86 db 0 ROM:0002FA87 db 0
Yowza! That's a lotta NOPs. We need to insert some advice such that we can determine if the second tile needs to be written to or not. It's simple enough...
ROM:0002F9D3 ld b, 8 06 08 ROM:0002F9D5 ld a, $CF ; '-' 3E CF ROM:0002F9D7 ld [WRAM_VWF_CompositingArea0], a EA C3 C7 ROM:0002F9DA ld a, $D0 ; '-' 3E D0 ROM:0002F9DC ld [WRAM_VWF_CompositingArea1], a EA C4 C7 ;that should be a hint as to where this code goes push hl E5 push bc C5 ld a, [WRAM_VWF_CurrentLetter] FA C1 C7 ld h, $7B 26 7B ld l, a 6F xor a AF ld b, [hl] 46 ld a, [WRAM_VWF_LetterShift] FA C2 C7 add a, b 80 bit 3, a CB 5F jr nz, ClearTile2 20 03 xor a AF jr nextSec 18 02 .ClearTile2: ld a, 1 3E 01 .nextSec: pop bc C1 pop hl E1 ROM:0002F9DF push bc C5 ROM:0002F9E0 push de D5 ROM:0002F9E1 push hl E5 push af F5 ROM:0002F9E2 di F3
Now, by moving back the start of the function we should be able to insert our advice without having to increase any relative jumps. Okay, just one, but only by one byte to fit our new push af... well at least so far. We will have to move back the entry point by 41(dec) bytes from 2F9E2, so it now starts at 2F9B9. That's not enough space. So our second solution is to move the whole routine forward 8 bytes, which we can do because we have 8 bytes to spare. This is a safe operation because the whole routine is composed of relative jumps, and thus position-independant.
Of course, remember to alter the VWF advice routine to call the VWF code. The VWF advice routine is at 2CE2C and the particular call is at 2CE53...
ROM:0002CE2C add a, a ROM:0002CE2D jr nc, 2CE30 ROM:0002CE2F inc b ROM:0002CE30 sla a ROM:0002CE32 rl b ROM:0002CE34 sla a ROM:0002CE36 rl b ROM:0002CE38 ld c, a ROM:0002CE39 ld hl, $5229 ROM:0002CE3C add hl, bc ROM:0002CE3D ld d, h ROM:0002CE3E ld e, l ROM:0002CE3F pop hl ROM:0002CE40 ld a, [WRAM_TextStyle] ROM:0002CE43 cp 0 ROM:0002CE45 jr z, loc_CE53 ROM:0002CE47 cp 1 ROM:0002CE49 jr z, loc_CE65 ROM:0002CE4B cp 2 ROM:0002CE4D jr z, loc_CE79 ROM:0002CE4F cp 3 ROM:0002CE51 jr z, loc_CE8C ROM:0002CE53 call 2F9C1 ; ALTER OPERAND TO BE THIS ROM:0002CE56 jr 2CE64
(This is, partially, a reverting of a change done in the previous patch, since now I know what to do with all that space..)
We now need to gate the second tile drawing code so that it won't touch the second tile if A=0. This is what the tile drawing code currently looks like in v65...
ROM:0002FA20 pop hl ROM:0002FA21 ld d, h ROM:0002FA22 ld e, l ROM:0002FA23 ld a, [byte_FF41] ROM:0002FA25 and 2 ROM:0002FA27 jr nz, loc_FA21+2 ROM:0002FA29 ld a, b ROM:0002FA2A ldi [hl], a ROM:0002FA2B ldi [hl], a ROM:0002FA2C push hl ROM:0002FA2D ld hl, $10 ROM:0002FA30 add hl, de ROM:0002FA31 ld a, [byte_FF41] ROM:0002FA33 and 2 ROM:0002FA35 jr nz, loc_FA30+1 ROM:0002FA37 ld a, c ROM:0002FA38 ldi [hl], a ROM:0002FA39 ldi [hl], a ROM:0002FA3A ei ROM:0002FA3B pop hl ROM:0002FA3C pop de ROM:0002FA3D pop bc ROM:0002FA3E inc de ROM:0002FA3F dec b ROM:0002FA40 jr nz, loc_F9DF
(A word of warning: These rom addresses should be summed with 8 if you're looking through the post-patch code because of my routine moving.)
Extra code needs to be inserted. Keep in mind however that we have a limit of 17 bytes before we need to pointcut a jump into some advice.
pop af F1 ROM:0002FA20 pop hl E1 ROM:0002FA21 ld d, h 54 ROM:0002FA22 ld e, l 5D push af F5 ROM:0002FA23 ld a, [byte_FF41] F0 41 ROM:0002FA25 and 2 E6 02 ROM:0002FA27 jr nz, loc_FA21+2 20 ?? ROM:0002FA29 ld a, b 78 ROM:0002FA2A ldi [hl], a 22 ROM:0002FA2B ldi [hl], a 22 pop af F1 ROM:0002FA2C push hl E5 push af F5 or a B7 jr z, .NoSecondTile 28 ?? ROM:0002FA2D ld hl, $10 21 10 00 ROM:0002FA30 add hl, de 19 ROM:0002FA31 ld a, [byte_FF41] F0 41 ROM:0002FA33 and 2 E6 02 ROM:0002FA35 jr nz, loc_FA30+1 20 ?? ROM:0002FA37 ld a, c 79 ROM:0002FA38 ldi [hl], a 22 ROM:0002FA39 ldi [hl], a 22 .NoSecondTile: ROM:0002FA3A ei FB pop af F1 ROM:0002FA3B pop hl ROM:0002FA3C pop de ROM:0002FA3D pop bc ROM:0002FA3E inc de ROM:0002FA3F dec b ROM:0002FA40 jr nz, loc_F9DF 20 94
Oh wow! Only 8 bytes... Let's insert the code and see what happens. It works! Easy patch... NOT! Inserting all those bytes and keeping everything sane was a pain, and really I did it in stages to catch errors before they accumulated.