Pobtastic / Skoolkit / Finding Routines

Created Fri, 21 Feb 2025 23:28:50 +0000 Modified Wed, 20 Aug 2025 22:05:19 +0000
531 Words 3 min

Dashboard

The first routine to be called from the “real” entrypoint is $8FC3:

c $84D0 Game Entry Point
@ $84D0 label=GameEntryPoint
...
  $84EC,$03 Call #R$8FC3.

Which is an odd looking routine, everyone does things slightly differently so this isn’t a hard-and-fast rule … but, noting that this happens a LOT:

CALL $8F8E

And as it’s referencing an address in the screen buffer, this suggests this is drawing something (or writing it), and given the game has only just loaded, it’s likely going to be part of the title screen.

c$8FC3 LD DE,$9030   ; #REGde=#R$9030.
 $8FC6 LD HL,$5080   ; #REGhl=#N$5080.
 $8FC9 LD BC,$2145   ; #REGbc=#N$2145.
 $8FCC CALL $8F8E    ; Call #R$8F8E.

Looking at $9030, this doesn’t look like code at all - it gives the appearance of being UDG reference data:

; Data block at 9030
b$9030 DEFB $7C,$7E,$7E,$7E,$7E,$7E,$7E,$7E
 $9038 DEFB $7E,$7E,$7E,$24,$7E,$7E,$7E,$7E
 $9040 DEFB $7E,$7E,$7E,$7E,$7E,$24,$7E,$7E
 $9048 DEFB $7E,$7E,$7E,$7E,$7E,$7E,$7E,$7B
 $9050 DEFB $7C,$20,$5E,$5C,$20,$4C,$49,$56
 $9058 DEFB $45,$53,$20,$7B,$3C,$3E,$20,$49
 $9060 DEFB $54,$45,$4D,$53,$20,$7B,$26,$28
 $9068 DEFB $20,$54,$49,$4D,$45,$20,$20,$7B
 $9070 DEFB $7C,$20,$5F,$5D,$20,$20,$20,$20
 $9078 DEFB $20,$20,$20,$7B,$3D,$3F,$20,$20
 $9080 DEFB $20,$20,$20,$20,$20,$7B,$27,$29
 $9088 DEFB $20,$20,$20,$3A,$20,$20,$20,$7B
 $9090 DEFB $7C,$7D,$7D,$7D,$7D,$7D,$7D,$7D
 $9098 DEFB $7D,$7D,$7D,$2A,$7D,$7D,$7D,$7D
 $90A0 DEFB $7D,$7D,$7D,$7D,$7D,$2A,$7D,$7D
 $90A8 DEFB $7D,$7D,$7D,$7D,$7D,$7D,$7D,$7B

So, given that the custom font begins at: $EBE0:

$EBE0 + ($7C * $08) = $EFC0
$EBE0 + ($7D * $08) = $EFC8
$EBE0 + ($7E * $08) = $EFD0

Which relate to:

Reference Address Font UDG
$7C $EFC0 Custom Font $EFC0
$7D $EFC8 Custom Font $EFC8
$7E $EFD0 Custom Font $EFD0

We don’t have to manually go through each one, or even disassemble the whole thing to find out what it does. Skoolkit helpfully allows us to run the code and see what happens:

N $8FC3 #PUSHS #UDGTABLE {
.   #SIM(start=$8FC3,stop=$902F)#SCR$02{$00,$140,$200,$40}(dashboard)
. } UDGTABLE# #POPS

Just watch out that #SIM is simulating running the code, so it is actively changing the screen buffer RAM in the current snapshot. This would then change any other screenshots after this point except, I’m using the #PUSHS (PUSH Snapshot) and #POPS (POP Snapshot) commands to keep the current snapshot clean.

The resulting image from the code is:

Dashboard

Some Things To Note:

  • #PUSHS/ #POPS: Given we’re writing over the snapshot, we’re changing it. These commands push the snapshot onto the stack, and pop it back off again
  • #SIM allows us to simulate the routine, given the start and stop points
  • #UDGTABLE creates a table which won’t render in ASM mode (as images can only be shown when using HTML
  • #SCR takes a screenshot of the screen buffer (named dashboard.png in this instance)

Populated Dashboard

Now we’re aware of what this function is for, when we see this:

 $84EC CALL $8FC3    ; Call #R$8FC3.
 $84EF CALL $90AA    ; Call #R$90AA.

We now know this is the dashboard routine, plus after checking - the following routine populates the dashboard stats. Hence, we can make another screenshot:

N $90B0 #PUSHS #UDGTABLE {
.   #SIM(start=$84EC,stop=$84F2)#SCR$02{$00,$140,$200,$40}(dashboard-populated)
. } UDGTABLE# #POPS

Populated Dashboard

And now we can start to label where the “Lives”/ “Items”/ “Time” values are stored in memory. Which is which can be gained by either guessing for now or altering the #SIM command to stop earlier in order to check which value is drawn first … second … third. Then we can determine which is which, as it’ll be based on which section it appears in.