Docs › Cross-referencing

Cross-referencing

Per-Game Notes

Per-Game Notes

The three community disassemblies (s1disasm, s2disasm, skdisasm) are independent projects with different structures, conventions, and quirks. This page covers the specifics that matter when cross-referencing each game.


Sonic 1 (s1disasm)

Repository: https://github.com/sonicretro/s1disasm

Disassembly Structure

The main source file is sonic.asm (unlike S2’s s2.asm). Constants are in Constants.asm.

Object code lives in separate files in _incObj/, named with a hex ID prefix:

_incObj/1F Crabmeat.asm
_incObj/22 Buzz Bomber.asm
_incObj/3D Boss - Green Hill (part 1).asm

Related animation and mapping files:

_anim/Crabmeat.asm      -- animation scripts
_maps/Crabmeat.asm      -- sprite mappings

This is different from S2, where all object code is inline in s2.asm.

Label Prefixes

S1 uses shorter, different prefixes than S2:

S1S2 equivalentMeaning
Nem_ArtNem_Nemesis-compressed art
Kos_ArtKos_Kosinski-compressed art
Unc_ArtUnc_Uncompressed art
Map_MapUnc_Sprite mappings
Ani_(inline)Animation scripts
Blk16_(16x16 dir)16x16 block mappings
Blk256_(128x128 dir)256x256 metatile mappings
DPLC_(inline)Dynamic Pattern Load Cues

When using RomOffsetFinder with --game s1, use S1 prefixes (Nem_, not ArtNem_).

Sprite Mapping Format

S1 uses a 5-byte per piece format. S2 and S3K use 6 bytes:

FieldS1S2/S3K
Y offset1 byte (signed)1 byte (signed)
Size1 byte1 byte
Pattern2 bytes2 bytes
X offset1 byte (signed)2 bytes (signed word)

The single-byte X offset limits S1 sprite pieces to -128..+127 pixels from center.

Level Data

S1 uses 256x256 pixel metatiles (S2/S3K use 128x128). This means:

  • Level layouts reference different-sized chunks.
  • Block mapping files are in map256/ (not mappings/128x128/).
  • 16x16 block mappings are in map16/ (not mappings/16x16/).
  • Level layouts are uncompressed binary files in levels/.

Object Field Names

S1 uses different field names from S2 for the same offsets:

S1 fieldS2 fieldOffsetDescription
obIDid0x00Object ID
obXx_pos0x08X position
obYy_pos0x0CY position
obVelXx_vel0x10X velocity
obVelYy_vel0x12Y velocity
obFramemapping_frame0x1ACurrent frame
obRoutineroutine0x24Routine number
obSubtypesubtype0x28Subtype
obColTypecollision_flags0x20Collision type

ROM Address Verification

Critical caveat: Addresses derived from s1disasm labels do not always match the compiled ROM binary. The disassembly source uses labels that resolve to different offsets depending on assembly options and ROM revision.

Always verify addresses by searching the actual ROM binary for known data patterns, or use RomOffsetFinder --game s1 verify to cross-check.

SMPS Audio

S1 uses a different SMPS driver configuration from S2:

  • Different base note mapping.
  • Different PSG envelope tables.
  • Different FM operator order.
  • PC-relative pointers in music data.

The engine captures these differences in Sonic1SmpsConstants and the S1-specific SmpsSequencerConfig.


Sonic 2 (s2disasm)

Repository: https://github.com/sonicretro/s2disasm

Disassembly Structure

The main source file is s2.asm. Constants are in s2.constants.asm.

Object code is inline in s2.asm, not in separate files. Search for Obj__: labels to find object entry points.

Art, mappings, and level data are organised into subdirectories:

art/nemesis/     -- Nemesis-compressed sprite art
art/kosinski/    -- Kosinski-compressed level tiles
art/enigma/      -- Enigma-compressed mappings
art/palettes/    -- Uncompressed palette files
collision/       -- Collision height arrays
level/           -- Level layouts (Kosinski-compressed)
mappings/sprite/ -- Sprite frame mappings
mappings/16x16/  -- Block definitions
mappings/128x128/ -- Chunk definitions
sound/           -- SMPS music and SFX data

Resource Overlays

Some zones share base resources with overlays applied on top. HTZ is the primary example:

ResourceBaseOverlayByte offset
PatternsEHZ_HTZ.binHTZ_Supp.bin0x3F80
BlocksEHZ.binHTZ.bin0x0980
ChunksEHZ_HTZ.bin(shared)

The overlay is written at the specified offset after decompressing the base data. The engine handles this in the level loading pipeline.

REV00 vs REV01

The engine targets REV01. Some differences from REV00:

  • Object code may have bug fixes or behavior changes.
  • ROM addresses may shift due to code size differences.
  • Some animation scripts have rev02even alignment directives.

Using REV00 ROMs will cause address mismatches and incorrect behavior.

SMPS Audio

S2 uses OVERFLOW2 tempo mode (overflow = tick, higher tempo value = faster). S3K uses OVERFLOW mode (overflow = skip, higher tempo value = slower). These are opposite behaviors for the same overflow mechanism.


Sonic 3 & Knuckles (skdisasm)

Repository: https://github.com/sonicretro/skdisasm

Disassembly Structure

S3K has the most complex disassembly. The main source file is sonic3k.asm, but there is also s3.asm for Sonic 3-specific data. Some labels (like Map_Sonic) are defined in both files with different addresses.

Always verify addresses against the machine code, not just the disasm labels. The sonic3k.asm definition is authoritative for the S3K combined ROM.

Combined 1P+2P Tables

S3K’s Map_Sonic and PLC_Sonic are combined tables with 502 entries (251 for 1P + 251 for 2P). The first word of each table is 0x03EC (502 x 2 = 1004).

Entries 0-250 are 1P frame offsets. Entries 251-501 are 2P frame offsets.

The 2P sub-table at entry 251 starts at offset 0x01F6 from the combined table. This creates a “table within a table” where the 2P entries also function as a standalone 251-entry table. This can be misleading — the combined table start address is the correct one to use.

When parsing these tables, trim to the first half (size / 2) to get only the 1P data.

Level Loading

S3K uses LevelLoadBlock with 24-byte entries (S2 uses a 12-byte MainLoadBlock). Each entry contains pointers to the zone’s art, chunks, blocks, collision, and other data.

SolidIndexes Pointer Format

SolidIndexes entries are 32-bit values with two flag bits:

  • Bit 31: Non-interleaved flag (set = S3K zones, clear = S&K zones).
  • Bit 0: +1 offset baked into some entries.

To decode: collisionBase = rawPtr & 0x7FFFFFFE (strip both flags). Then:

  • Non-interleaved (bit 31 set): primary data at base, secondary at base + 0x600.
  • Interleaved (bit 31 clear): primary and secondary alternate bytes in a 0xC00 block.

Compression

S3K uses KosinskiM (Kosinski Moduled) for many resources, in addition to standard Kosinski and Nemesis. KosinskiM wraps standard Kosinski with a module header that allows streaming decompression. In the engine, this is CompressionType.KOSINSKI_MODULED.

Z80 Sound Driver

S3K’s Z80 driver is significantly different from S1/S2:

  • Music bank list: 1-byte entries (not 2-byte words). Each byte is a Z80 bank number; romBank = bankByte << 15.
  • DAC bank list: Also 1-byte entries with the same shift.
  • Driver loading: The Kosinski-compressed driver at Z80_DRIVER_ADDR decompresses to only ~4459 bytes. A separate Kosinski block at Z80_ADDITIONAL_DATA_ADDR is loaded to Z80 RAM 0x1300. Together they form the complete driver.
  • DAC drum entries: 5-byte descriptors (rate, length, pointer) using the DACExtract.c case 0x19 format, not MMPR/case 0x06.
  • DPCM encoding: S3K uses DPCM (Differential PCM) for some samples, requiring a dedicated decoder.

Tempo Mode

S3K uses OVERFLOW tempo: when the tempo counter overflows, the sequencer skips a tick (delay). This means a higher tempo value produces slower music. S2 uses OVERFLOW2: overflow means tick. They are opposites.

Palette Mutations

S3K has per-frame palette color writes in resize/event routines that do not go through the normal palette cycle system. These are specific colors written directly during level events (e.g., during the AIZ fire transition).


Summary of Key Differences

FeatureS1S2S3K
Object filesSeparate (_incObj/)Inline (s2.asm)Inline (sonic3k.asm)
Art label prefixNem_ArtNem_ArtNem_ / ArtKos_
Mapping format5 bytes/piece6 bytes/piece6 bytes/piece
Metatile size256x256128x128128x128
Level compressionUncompressedKosinskiKosinskiM
Tempo modeOVERFLOW2OVERFLOW
ROM scannerNoNoYes (Sonic3kRomScanner)
RomOffsetFinder flag--game s1(default)--game s3k