In this article I want to disassemble the internal device of the legendary game Sonic the Hedgehog for the Sega Mega Drive, as well as ways to modify it or, as they say, hacking. This game has about a hundred hacks , including really worthy work (such as Pana Der Hejhog or Sonic Remastered ), and strange and even creepy (like An Ordinary Sonic ROM Hack ). To understand how to create them, you need to figure out how to write in the assembler language Motorola 68K (usually games for consoles of those times were written in assembler), where to get the disassembled version of the game and what architecture has its engine.

The disassembly of ROM files for Sega is done using the commercial disassembler and IDA Pro debugger . Then there is a painstaking process of marking, structuring and combing the raw assembler code using the debugger (and ingenuity). This process requires a good understanding of the technical features of the Sega Mega Drive platform and games for it.
Fortunately, GitHub already has disassembled and tagged versions of all the games in the Sonic the Hedgehog series, created by enthusiasts with the support of Sonic Retro . The source code of the very first game in the series is best marked and structured. This version of the code is in the repository sonicretro / s1disasm and it will be parsed in the article.
Immersion in the internal structure of the toy will begin with theory.

Sega Mega Drive ( Sega Genesis) 32- Motorola MC68000 ( Motorola 68K) Zilog Z80 ( Z80 ). (RAM) – 64K. ( ) – 320x224 .
Motorola 68K . , . Motorola 68K Apple Macintosh.
Mega Drive Yamaha YM7101 80 . ; Sega Mega Drive " Sega Mega Drive: Video Display Processor".
AS. 82 . : ResearchGate Intel Core i7 338 .
32- : D0
–D7
. . A0
–A7
. - . A7 SP
.
. .l
(long) 32- . .w
(word) .b
(byte) 16- 8- .
Motorola 68K.
move
– .
:
move.l #48, d4
– 48 d4
.move.w d5, d6
– 16 d5
d6
.move.w #$12FF, obStatus(a0)
– 12FF , obStatus
, a0
.
, #
. #$
.
:
move.l #5, (a0)
– 5 , a0
.move.l (a1), d2
– , a1
, d2
.
(a*
).
add
– .sub
– .mulu
– ; muls
– .divu
– ; divs
– .
:
add.b #$08, d0
– 08 d0
.sub.w (v_screenposx).w, d1
– d1
v_screenposx
( 16- ).mulu.w #10, d0
– d0
10 ( d0
).divs.w #$68, d2
– d2
68 ( d2
).
jmp
, bra
– .jsr
, bsr
– , rts
– ( call
ret
x86).
:
jmp .foo
nop
.foo:
SubRoutine:
nop
rts
bsr SubRoutine
68K CCR
(Condition Code Register). cmp
, tst
btst
() , beq
, bne
, bge
, ble
.
cmp
– .tst
– .btst
– .beq
/bne
– , / .bge
/ble
– , / .
:
cmp.w #32,d0
bge.s .foo
btst #0,d0
bne.s .foo
Motorola 68K ( ) , .
s1disasm Python-, . Sonic the Hedgehog "Kosinski compression", ( ).
, , git- AS
(git checkout AS
) :
./build.py
ROM- s1built.bin
. Sega Mega Drive. macOS, , OpenEmu.
– sonic.asm
. : Zilog Z80 (WaitForZ80
), (VDPSetupGame
) . GameInit
MainGameLoop
, .
, Variables.asm
. RAM, .
v_gamemode
. :
- 00 – "Sega",
- 01 – ,
- 08 – ,
- 0C – ,
- 10 – special stage,
- 14 – "Continue",
- 18 – ,
- 1C – ,
- 8C – .
move.b #id_Sega,(v_gamemode).w
GameInit
v_gamemode
, . id_Sega
id_Title
./build.py
, , "Sega" , .
v_gamemode
, . , id_Title
GM_Title
, id_Level
– GM_Level
.
, Variables.asm
. v_sonspeedmax
, v_sonspeedacc
v_sonspeeddec
.
, Sonic_Main
, : , , :
move.w #$600,(v_sonspeedmax).w
move.w #$C,(v_sonspeedacc).w
move.w #$80,(v_sonspeeddec).w
, 256. , 0xC / 256 = 0.046875, – 0x80 / 256 = 0.5 ( ).
Mega Drive Sega 315‑5313 (Video Display Processor, VDP). VDP , vdp_data_port
vdp_control_port
. VDPSetupGame
, VDPSetupArray
. , , . , GM_Level
. VDP Sega Retro.
Low Color ( Mode Register 1 ):
Video Display Processor – background ( B) foreground ( A), , . 8x8 . ; – 4x4 . , 32x32 .
(LoadTilesAsYouMove
, DrawChunks
) (BuildSprites
) , :
, LoadTilesAsYouMove
. Sonic the Hedgehog 64x32 512x256 .
foreground- Green Hill Zone, GIF-, 5 : , , . , . , 3D- . Sonic the Hedgehog.
8192 RAM . v_objspace
. , . : , , , , , . DisplaySprite
.

64 . , , Constants.asm
. a0
. , :
ObX(a0)
, ObY(a0)
– .ObVelX(a0)
, ObVelX(a1)
– 1/256 .obHeight(a0)
, obWidth(a0)
– .obSubtype(a0)
– (: ).obStatus(a0)
– .obRoutine(a0)
– .
, X , Y, .
ExecuteObjects
. , . Object Pointers.asm
. _incObj
.
, (, , , "" ). , , obRoutine
.
SpeedToPos
. , .
: no-ring challenge
, : no-ring challenge. . , ( ).
"" – Ring_Main
(bra
) :
Ring_Main:
bra.w Ring_Delete
lea (v_objstate).w,a2
moveq #0,d0
move.b obRespawnNo(a0),d0
. "" 26 Monitor.asm
. obSubtype
1 . , 6. cmp
beq
, :
Mon_Main:
cmp.b #6,obSubtype(a0)
beq DeleteObject
addq.b #2,obRoutine(a0)
move.b #$E,obHeight(a0)
, ROM' , . GitHub. , - , .
:
, . Sonic the Hedgehog 3 – .
Sonic the Hedgehog 3
, , Sonic Retro. , , , 64 , . . 0.1875 , . , 0.75.
, , , , , "" .
"", 25 & 37 Rings.asm
. :
Ring_Index:
ptr_Ring_Main: dc.w Ring_Main-Ring_Index
ptr_Ring_Animate: dc.w Ring_Animate-Ring_Index
ptr_Ring_Collect: dc.w Ring_Collect-Ring_Index
ptr_Ring_Sparkle: dc.w Ring_Sparkle-Ring_Index
ptr_Ring_Delete: dc.w Ring_Delete-Ring_Index
: Main
– ; Animate
– ; Collect
– ; Sparkle
– ; Delete
– . , , ptr_Ring_Animate
.
obStatus
. , . obStatus
( ) . bset
, , – btst
.
Ring_Animate
, , , 64 :
Ring_Animate:
tst.b (v_shield).w
beq.s .animate
.dist_from_sonic:
move.w (v_player+obX).w,d0
sub.w obX(a0),d0
move.w (v_player+obY).w,d1
sub.w obY(a0),d1
.check_magnetised:
btst #0,obStatus(a0)
bne.s .attract
.check_near_x:
cmp.w #64,d0
bge.s .animate
cmp.w #-64,d0
ble.s .animate
.check_near_y:
cmp.w #64,d1
bge.s .animate
cmp.w #-64,d1
ble.s .animate
bset #0,obStatus(a0)
.attract:
.animate:
, , . :
if sign(obVelX) == sign(distX):
, ( Motorola 68K) , 0 , 1 – . "" – XOR (eor
Motorola 68K).
, ( ) , (0.1875 0.75) 256 ( 48 192 ).
:
.attract:
move.w #48,d4
move.w obVelX(a0),d3
eor.w d0, d3
btst #$F,d3
beq.s .x_towards
move.w #192,d4
.x_towards:
cmp.w #0,d0
bge.s .attract_x
neg d4
.attract_x:
add.w d4,obVelX(a0)
move.w #48,d4
move.w obVelY(a0),d3
eor.w d1,d3
btst #$F,d3
beq.s .y_towards
move.w #192,d4
.y_towards:
cmp.w #0,d1
bge.s .attract_y
neg d4
.attract_y:
add.w d4,obVelY(a0)
.animate:
, , SpeedToPos
:
.animate:
jsr (SpeedToPos).l
ROM , — — Sonic 3 Sonic 1!
GitHub , .
. (SonED2, Chaos), , . / Motorola 68K EASy68K, , Sega.
, , . , - , , .