Wednesday, October 4, 2017

Lock-on Technology: how much can be reused?

Much like Sonic & Knuckles, the Sonic 3 cartridge contains a 16 megabit ROM. As such, when the two are locked on to one another, they take up the entirety of the Mega Drive's ROM address space, as illustrated by the following diagram:

0x000000
0x200000
0x400000
Sonic & Knuckles
Main ROM
Sonic 3
Main ROM

As we saw last time, when Sonic & Knuckles detects the Sonic 3 ROM header in the lock-on slot, it starts up a mode in which it can reference content from the Sonic 3 ROM. However, 99% of the code executed still comes from the Sonic & Knuckles ROM, so you're effectively still playing Sonic & Knuckles, just a version which is allowed to access stuff in the Sonic 3 cartridge.

It bears repeating: regardless of whether you're playing Sonic 3 & Knuckles or standalone Sonic & Knuckles, the same exact code is executing, which means the game plays exactly the same. The only difference is whether the code is allowed to reach into the Sonic 3 ROM or not.

So, how exactly does the Sonic & Knuckles code manage to use content from the Sonic 3 ROM?

The developers had a powerful ally on their side: hindsight. By the time Sonic & Knuckles entered full production, Sonic 3 was already a done deal. The ROM was finalized, printed into game cartridges and being sold around the world. S&K can take full advantage of the fact that everything in the Sonic 3 ROM is in a known location.

All the developers had to do was take a pointer to a particular asset in the Sonic 3 source code, add $200000 to it, and that's where Sonic & Knuckles would find it once the cartridges were locked on.
EndOfROM:
    if Sonic3_Complete=0
        org $200000
        include "Lockon S3/LockOn Pointers.asm"
    else
        include "Lockon S3/LockOn Data.asm"
    endif
The current disassembly has two build modes, depending on the value of the Sonic3_Complete flag. When the flag is on, the LockOn Data.asm file includes all the assets from the Sonic 3 ROM which are referenced by Sonic & Knuckles, similarly to the setup the developers used until the 0517 prototype:
AIZ1_16x16_Primary_Kos:     binclude "Levels/AIZ/Blocks/Act 1 Primary.bin"
    even
AIZ1_16x16_Secondary_Kos:   binclude "Levels/AIZ/Blocks/Act 1 Secondary.bin"
    even
AIZ1_16x16_MainLevel_Kos:   binclude "Levels/AIZ/Blocks/Act 1 Main Level.bin"
    even
AIZ1_8x8_Primary_KosM:      binclude "Levels/AIZ/Tiles/Act 1 Primary.bin"
    even
AIZ1_8x8_Secondary_KosM:    binclude "Levels/AIZ/Tiles/Act 1 Secondary.bin"
    even
AIZ1_8x8_MainLevel_KosM:    binclude "Levels/AIZ/Tiles/Act 1 Main Level.bin"
    even
AIZ1_128x128_Kos:           binclude "Levels/AIZ/Chunks/Act 1.bin"
    even
When the flag is off, the LockOn Pointers.asm file replaces all the Sonic 3 assets with their location in the final Sonic 3 ROM. This is analogous to the setup used from the 0525 prototype all the way through the final:
AIZ1_16x16_Primary_Kos:     ds.b  $200
AIZ1_16x16_Secondary_Kos:   ds.b  $C40
AIZ1_16x16_MainLevel_Kos:   ds.b $10E0
AIZ1_8x8_Primary_KosM:      ds.b  $E12
AIZ1_8x8_Secondary_KosM:    ds.b $2FD2
AIZ1_8x8_MainLevel_KosM:    ds.b $27F2
AIZ1_128x128_Kos:           ds.b $3990
AIZ1_8x8_Flames_KosM:       ds.b  $A82

Alright, next. What can we reuse from the Sonic 3 ROM?

Obviously, as we just saw, data can be referenced, so long as it doesn't contain pointers to other ROM locations. Data containing ROM pointers suffers the same fate as the 68000 vector table before it: all the pointers now refer to random location in the Sonic & Knuckles ROM rather than their intended location in the Sonic 3 ROM.

This is exactly the case with the level load block: all the underlying data can be reused, but the level load block itself is unusable and is thus completely reconstructed in the Sonic & Knuckles ROM.
LevelLoadBlock:
    dc.l AIZ1_8x8_Primary_KosM+$B000000
    dc.l AIZ1_8x8_Secondary_KosM+$B000000
    dc.l AIZ1_16x16_Primary_Kos+$A000000
    dc.l AIZ1_16x16_Secondary_Kos+$A000000
    dc.l AIZ1_128x128_Kos
    dc.l AIZ1_128x128_Kos
; ---------------------------------------------------------------------------
    dc.l AIZ2_8x8_Primary_KosM+$C000000
    dc.l AIZ2_8x8_Secondary_KosM+$C000000
    dc.l AIZ2_16x16_Primary_Kos+$B000000
    dc.l AIZ2_16x16_Secondary_Kos+$B000000
    dc.l AIZ2_128x128_Kos
    dc.l AIZ2_128x128_Kos
; ---------------------------------------------------------------------------
    ...

What about code?

Object code is mostly unusable, due to the frequent use of hard ROM pointers in the initialization of their SSTs, such as the code pointer and the mappings pointer.
    move.l  #loc_24090,(a0)             ; unusable
    move.l  #Map_Spikes,$C(a0)          ; unusable
The next concern are jumps. Short jumps using the Bcc, BRA or BSR instructions are fine, because they're assembled into a branch opcode with a relative displacement. The displacement is always applied to the program counter's current value, so the branch target is always the same regardless of the address the ROM was rebased to.
    bne.s   Obj_MonitorFallUpsideDown   ; OK
    bsr.w   MoveSprite                  ; OK
Finally, long jumps using the JMP or JSR instructions are fine, so long as they use the PC-relative syntax. Jumps using the effective address syntax are assembled as hard pointers to their destination addresses, and are therefore unusable due to the reasons outlined above.
    jsr     Refresh_PlaneTileDeform(pc) ; OK
    jmp     (AIZ1_ApplyDeformWater).l   ; unusable
In practice, the only code Sonic & Knuckles reuses from Sonic 3 is screen and background event code pertaining to the Sonic 3 stages. This code is present in the Screen Events.asm file, which is only included when the Sonic3_Complete build flag is on.

That file actually contains several routines related to the rendering of background planes, which then appear duplicated in the Sonic & Knuckles source code; they are identified by their "S3_" prefix. These routines might seem like pointless redundancy, but that line of reasoning is a sunk cost fallacy: in practice, the routines are on the Sonic 3 cartridge, which the customer already paid for!

3 comments:

  1. I assume graphics and music can be reused?

    ReplyDelete
  2. Oh, so that's why the disassembly is missing Sonic 3 alone data.

    Wait, so how was Sega able to use Sonic 3 objects in Sonic 3 & knuckles?

    ReplyDelete