Hacking classic Sonic the Hedgehog for Sega

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.


Sonic hacks


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- : D0D7. . A0A7. - . 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, d1d1 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  ;     .foo
nop       ;    (nop)   
.foo:     ;  .foo

SubRoutine:  ;   SubRoutine
nop
rts          ;   

bsr SubRoutine  ;   SubRoutine


68K CCR (Condition Code Register). cmp, tst btst () , beq, bne, bge, ble .


  • cmp –  .
  • tst – .
  • btst – .
  • beq/bne – , / .
  • bge/ble – , / .

:


cmp.w   #32,d0  ;  d0  32
bge.s   .foo    ;  d0 > 32,    .foo

btst    #0,d0  ;   ()  d0  
bne.s   .foo   ;     ,    .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  ; Sonic's top speed
move.w  #$C,(v_sonspeedacc).w    ; Sonic's acceleration
move.w  #$80,(v_sonspeeddec).w   ; Sonic's deceleration

, 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.


Marble Zone, GIF-, 1 :


8192 RAM . v_objspace. , . : , , , , , . DisplaySprite.


Sonic game objects


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:  ; Routine 0
    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:   ; Routine 0
    cmp.b   #6,obSubtype(a0)  ;   ?
    beq     DeleteObject      ;  ,  

    addq.b  #2,obRoutine(a0)
    move.b  #$E,obHeight(a0)
    ; ...

, ROM' , . GitHub. , - , .


:


, . Sonic the Hedgehog 3 – .


GIF-, , 1 :

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: ; Routine 2
    tst.b   (v_shield).w  ;    ?
    beq.s   .animate      ;  , 

.dist_from_sonic:
    ;    
    move.w  (v_player+obX).w,d0  ;     X  d0
    sub.w   obX(a0),d0           ; d0 =   X
    move.w  (v_player+obY).w,d1  ;     Y  d1
    sub.w   obY(a0),d1           ; d1 =   Y

.check_magnetised:
    ; ,        
    btst    #0,obStatus(a0)  ;   obStatus  0?
    bne.s   .attract         ;   =>  ,   .attract

.check_near_x:
    ;    ,  
    cmp.w   #64,d0    ;   X > 64?
    bge.s   .animate  ;  , 
    cmp.w   #-64,d0   ;   X < -64?
    ble.s   .animate  ;  , 

.check_near_y:
    cmp.w   #64,d1    ;   Y > 64?
    bge.s   .animate  ;  , 
    cmp.w   #-64,d1   ;   Y < -64?
    ble.s   .animate  ;  , 

    ;    64x64,   
    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:
    ;     X
    move.w #48,d4          ;   d4  48
    move.w  obVelX(a0),d3  ;     X  d3
    eor.w   d0, d3         ;      
    btst    #$F,d3         ;  15-   1 ( )...
    beq.s   .x_towards     ;   x_towards
    move.w #192,d4         ;   ,   d4  192

.x_towards:
    ;    ,    (neg)   (d4)
    cmp.w   #0,d0
    bge.s   .attract_x
    neg d4

.attract_x:
    ;     X    X
    add.w   d4,obVelX(a0)

    ;      Y:
    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!


GIF- , 3.5 :

GitHub , .



. (SonED2, Chaos), , . / Motorola 68K EASy68K, , Sega.


, , . , - , , .




All Articles