don't click here

Sonic & Knuckles Collection C port

Discussion in 'Engineering & Reverse Engineering' started by BenoitRen, Jan 11, 2024.

  1. BenoitRen

    BenoitRen

    Tech Member
    392
    178
    43
    Some time after starting my Sonic CD decompilation, I read Clownacy's Everything That I Know About Sonic the Hedgehog's Source Code post. It mentioned the presence of a symbol list in Sonic & Knuckles Collection, but didn't delve further. Digging further, I found an old Sonic Retro thread by LOst (that for some reason I can't find again) that dumped the entire list, and then I found MainMemory's Sonic & Knuckles Collection labels, where she figured out part of the debug info format. Apparently she also has a GitHub repo for a disassembly, but aside from IDA files and some modding tools there doesn't seem to be anything there.

    In late august last year, I decided to take a look myself. Instead of ripping my CD, I downloaded a copy of the trial version. Yes, the trial version also contains the debug info. I'm not sure if it contains the same amount, but it was enough to get started.

    First is a long symbol list. Like MainMemory's post explains, these are Pascal style strings, where each string is prepended by a byte that mentions its length. After this list is some kind of index, because between the bytes you can find addresses that point to code in the executable. Each address is also followed by an number that increases with each entry. However, after 0x45, the format seems to change, and that seems to be where the excavation stopped.

    However, I've figured it out.

    You see, after entry 0x45 it starts documenting the local labels. Each entry first points to the location of the label, and then has sub-entries that are pairs of addresses and numbers. The address points to the location of the local labels, while the number points to the symbol list, with identifier 0x50 pointing to the 80th item, for example. This way, it can reuse labels, as some, like @@100 and @@ret, are used more than once.

    I decided to come back to this later and try my hand at a decompilation. That time was last weekend.

    At first I was intimidated by all those unknown memory locations in the code. Then I remembered that Sonic Jam, which was also the result of automatic 68000 assembly conversion, assigned specific parts of memory to the 68000's registers. I cross-referenced with the Sonic 3 & Knuckles disassembly, and sure enough, it's also the case here. Thanks to info on Sonic 3 Unlocked I was also able to find the actwk array that holds the 110 sprite status objects.

    All right, so what do I have so far?


    I don't know how far I'll get with this, as there's only so much time I can devote to multiple projects, x86 assembly isn't as nice to read as MIPS assembly, and the amount of debug info is far from being the treasure trove that Sonic CD's PS2 port is, but I figured I could at least try. So far I already noticed one inconsistency with the Mega Drive game's disassembly when it comes to data.

    29/02/2024 EDIT: I've extracted all 15213+ ASM labels with their memory address! Attached them as labels.txt. The file can be imported into Ghidra using the ImportSymbolsScript.py script.

    12/03/2024 EDIT: There's a Git repository now. I've also added three labels to labels.txt that had gone missing for some reason.
     

    Attached Files:

    Last edited: Mar 12, 2024
  2. Clownacy

    Clownacy

    Tech Member
    1,059
    602
    93
    Here's a link to that thread. I love the work you've been doing with the decompilations, by the way!
     
  3. MainMemory

    MainMemory

    Kate the Wolf Tech Member
    4,741
    338
    63
    SonLVL
    I've been poking around at these kinds of things for a long while, but I always held off on fully committing to a decompilation because ultimately the game's code is 99% just the 68000 ASM fed into a machine that spit out equivalent x86 ASM with no thought to optimization, unlike Sonic CD or Sonic 3D Blast which were properly converted to C. The labels are cool, but without a ton of manual cleanup what you're getting out of this is probably going to look worse than if someone just decompiled the MD version directly.

    I do still hold a moderate interest in making mods for this version, as unoptimized code aside, it still is the original game running natively on PC, and there's a lot of good that could come from properly utilizing that. Also, I believe the trial version uses the same EXE as the full version, and can be changed into such with an INI flag. I can't promise that I'll be jumping in to decompile it, but if you have any questions about the game, feel free to ask me. I'm fairly certain there's an IDB importer for Ghidra that would let you use all the things I found previously.
     
  4. BenoitRen

    BenoitRen

    Tech Member
    392
    178
    43
    The debug info covers the memory range 0x006ebcb8 to 0x00820771. But functions in the 0x40xxxxxx to 0x42xxxxxx range are often called. Do you have any idea what those are?
     
  5. MainMemory

    MainMemory

    Kate the Wolf Tech Member
    4,741
    338
    63
    SonLVL
    Here's everything I have from the region not covered by the debug info, using names mainly taken from the S&K disasm on GitHub. Note that the game's code is largely in the same order as the MD version with some PC-specific additions and some extra code from S3A where appropriate.
    Code (Text):
    1.  
    2. GetDSoundInfo   00404390  
    3. AllocateRAMAndVRAM   004043B0  
    4. DrawSprites   00404564  
    5. ConvertSpriteTable   004049EB  
    6. ConvertSpriteTable_P2   00404B1A  
    7. ReadSaveFile   00404E0C  
    8. WriteSaveFile   00404ECE  
    9. VInt   004050C0  
    10. VInt_12_Main   00405201  
    11. VInt_4_Main   00405237  
    12. VInt_14_Main   00405284  
    13. VInt_2_Main   004052B0  
    14. VInt_16_Main   004052DC  
    15. VInt_1A_Main   00405312  
    16. VInt_1C_Main   0040535F  
    17. VInt_1E_Main   0040539F  
    18. VInt_8_A_C_E_Main   004053E9  
    19. ConvertPalette   00405536  
    20. ConvertPalette2   004056F7  
    21. ConvertSpriteTable_Call   00405A23  
    22. Poll_Controllers   00405A45  
    23. SpecialVInt_Function   00405A91  
    24. DrawGraphics   00405B76  
    25. CopyPalette   0040699E  
    26. CopyPalette2   004069D0  
    27. InitDirectSound   004097BC  
    28. CreateSoundBuffer   00409A27  
    29. PlaySoundFlags   00409EBF  
    30. StopSound   00409F33  
    31. PlaySound   00409F9F  
    32. SetSoundPosition   0040A0EF  
    33. LoadSounds   0040A25F  
    34. unknown_libname_25   0040A4DD  
    35. GetSoundPlaying   0040A4F8  
    36. StopAllSounds   0040A563  
    37. PlaySoundRegister   0040A98E  
    38. LoadAndPlaySong   0040AEA5  
    39. ReloadAndPlaySong   0040AEE7  
    40. InitializeMidiInterface   0040B5BB  
    41. LoadSong   0040B5EB  
    42. PlaySong   0040B62E  
    43. StopSong   0040B65B  
    44. PauseMusic   0040B69E  
    45. ResumeMusic   0040B6CB  
    46. SetMusicSpeed   0040B6F8  
    47. SpeedUpMusic   0040B72B  
    48. Change_Music_Tempo   0040B75A  
    49. ReadFileInt   0040B800  
    50. GetSoundBuffer   0040B8B0  
    51. IsDSoundInit   0040B8E0  
    52. TitleSonic_LoadFrames   0040B900  
    53. Poll_JoysticksAndKeyboard   0040BCDB  
    54. Poll_Controller1   0040C3D2  
    55. Poll_Controller2   0040C4D0  
    56. ReadFileWrapper   0040EAC8  
    57. PixelConvTable   0040F5AC  
    58. DebugStartup   0040FF14  
    59. SKAloneStartup   0040FF54  
    60. S3orS3KStartup   0040FF63  
    61. BlueSpheresStartup   0040FF72  
    62. Test_Checksum   0040FFB6  
    63. Test_Checksum_removed   0040FFB7  
    64. SonicAndKnucklesStartup   00410095  
    65. GameLoop   004100CF  
    66. GameModes   00410130  
    67. JumpToSegaScreen   00410184  
    68. DetectPAL   004101ED  
    69. Kosinski_Decomp_2   0041028C  
    70. Kosinski_Decomp   0041034B  
    71. Queue_Kos   00410365  
    72. Process_Kos_Queue   0041037A  
    73. Plane_Map_To_VRAM   00410384  
    74. Copy_Data_To_VRAM   00410426  
    75. Enigma_Decomp   00410456  
    76. Eni_Decomp_00   00410683  
    77. Eni_Decomp_01   004106C3  
    78. Eni_Decomp_100   004106F6  
    79. Eni_Decomp_101   0041072E  
    80. Eni_Decomp_110   00410776  
    81. Eni_Decomp_111   004107BE  
    82. Eni_Decomp_Index   00410805  
    83. Nemesis_Decomp   00410CE8  
    84. Nemesis_Decomp2   00410D43  
    85. Sega_Screen   00411443  
    86. Load_PLC   0041144B  
    87. Load_PLC_Raw   0041149C  
    88. Process_PLC1   004114A9  
    89. Queue_Kos_Module   004114AA  
    90. Process_Kos_Module_Queue   00411510  
    91. DrawSprite_NoFlipNoPriority   00411698  
    92. DrawSprite_XFlipNoPriority   0041177C  
    93. DrawSprite_YFlipNoPriority   0041186D  
    94. DrawSprite_XYFlipNoPriority   00411957  
    95. CheckSpriteMask   00411A50  
    96. DrawSpriteMasked_NoFlip   00411ADD  
    97. DrawSpriteMasked_XFlip   00411BD6  
    98. DrawSpriteMasked_YFlip   00411CE0  
    99. DrawSpriteMasked_XYFlip   00411DE3  
    100. DrawSprite_NoFlip   00411EF4  
    101. DrawSprite_XFlip   00411FD5  
    102. DrawSprite_YFlip   004120C3  
    103. DrawSprite_XYFlip   004121AA  
    104. Render_HUD   004122AC  
    105. UpdateHUD   004125BD  
    106. HUD_LoadZero   00412944  
    107. DrawThreeDigitNumber   00412DA7  
    108. DrawSixDigitNumber   00412DBD  
    109. DrawSingleDigitNumber   00413363  
    110. DrawTwoDigitNumber   00413379  
    111. HUD_Lives   004139B8  
    112. LevelSelect_S2Options   00415104  
    113. Obj_Titlecard   00416412  
    114. SpecialStage_Results   00417946  
    115. Init_Controllers   0041A6FC  
    116. Init_VDP   0041A6FE  
    117. Clear_DisplayData   0041A75C  
    118. SndDrvInit   0041A81A  
    119. Play_Sound   0041A81B  
    120. Play_Sound_2   0041A82D  
    121. Paused_Debug_Controls   0041A834  
    122. Level   0041A838  
    123. LevelLoop   0041B142  
    124. Level_NotLRZ   0041B1B2  
    125. Level_NotEnding   0041B1E3  
    126. DemoMode   0041B1FA  
    127. SpawnLevelMainSprites   0041B557  
    128. SpawnLevelMainSprites_SpawnPlayers   0041BA7E  
    129. Handle_Onscreen_Water_Height   0041BD97  
    130. HCZ_WaterTunnels   0041C40D  
    131. HCZ1_WaterTunLocs   0041C6E0  
    132. HCZ2_WaterTunLocs   0041C7B4  
    133. GetDemoPtr   0041D422  
    134. Demo_PlayRecord   0041D4DA  
    135. LoadSolids   0041D697  
    136. LoadLevelLoadBlock   0041DA83  
    137. CheckLevelForWater   0041DB98  
    138. LoadWaterPalette   0041DD39  
    139. LevelMusic_Playlist   0041DF65  
    140. Offs_PLC   0041DF98  
    141. PLC_00   0041E090  
    142. PLC_01   0041E0AA  
    143. PLC_02   0041E0C4  
    144. PLC_05   0041E0E8  
    145. PLC_07   0041E116  
    146. Init_SpriteTable   0041E61C  
    147. Process_Sprites   0041E760  
    148. MoveSprite   0041E85B  
    149. MoveSprite2   0041E8F6  
    150. MoveSprite_TestGravity   0041E979  
    151. MoveSprite_TestGravity2   0041EA30  
    152. Delete_Current_Sprite   0041EACF  
    153. Draw_Sprite   0041EB34  
    154. Animate_Sprite   0041EBC7  
    155. Render_Sprites   0041F0B6  
    156. Render_Sprites_CompetitionMode   00420A46  
    157. Sprite_OnScreen_Test   00421B44  
    158. TouchResponse   00421F59  
    159. HurtCharacter   00422B67  
    160. Kill_Character   00422D84  
    161. Add_Object_To_Collision_Response_List   00422F11  
    162. HyperAttackTouchResponse   004232EC  
    163. nullsub_110   0042363D  
    164. nullsub_109   00423AC9  
    165. AnPal_Pachinko   00424946  
    166. Pal_FadeFromBlack   00426210  
    167. Animate_Palette   004264F7  
    168. Pal_FadeToBlack   0042653F  
    169. Pal_ToWhite   00426A53  
    170. LoadPalette   00426C05  
    171. LoadPalette_Immediate   00426CD1  
    172. GetSine   00426FDE  
    173. Load_Sprites   0042A860  
    174. Create_New_Sprite   0042B8B8  
    175. Create_New_Sprite3   0042B8CF  
    176. Create_New_Sprite_Int   0042B8FF  
    177. Obj_Air_CountDown   0042BD04  
    178. Player_ResetAirTimer   0042C8F3  
    179. Obj_Invincibility   0042CB7F  
    180. Obj_188E8   0042CF01  
    181. Map_Invincibility   0042D3E8  
    182. Obj_DashDust   0042D43C  
    183. Obj_SuperSonicKnux_Stars   0042E1DA  
    184. Obj_HyperSonic_Stars   0042E614  
    185. Obj_Insta_Shield   0042EA10  
    186. Obj_Fire_Shield   0042EC14  
    187. Obj_Lightning_Shield   0042EEBB  
    188. Obj_Bubble_Shield   0042F3DA  
    189. Obj_SuperTails_Birds   0042FF46  
    190. Obj_HyperSonicKnux_Trail   004308C8  
    191. Get_LevelSizeStart   00430A6C  
    192. LevelSizes   00430B8A  
    193. DeformBgLayer   004310A7  
    194. j_LevelSetup   00431B36  
    195. LoadLevelLoadBlock2   00431B3B  
    196. Load_Level   00431D18  
    197. LevelLoadBlock   00431DC8  
    198. Obj_Sonic2P   00433450  
    199. Obj_Sonic   00434009  
    200. Sonic_Index   004340CA  
    201. Sonic_Init   004340D8  
    202. Sonic_Control   0043428D  
    203. Sonic_Modes   00434488  
    204. Sonic_Display   00434490  
    205. Sonic_RecordPos   00434703  
    206. Reset_Player_Position_Array   004348E9  
    207. Sonic_Water   00434A0A  
    208. Sonic_MdNormal   00434CA3  
    209. Call_Player_AnglePos   00434D72  
    210. Sonic_MdAir   00434E05  
    211. Sonic_MdRoll   00434E50  
    212. Sonic_MdJump   00434F22  
    213. Sonic_Move   00434F6D  
    214. Sonic_RollSpeed   00435D45  
    215. Sonic_ChgJumpDir   00436186  
    216. Player_LevelBound   00436400  
    217. SonicKnux_Roll   0043656C  
    218. Sonic_Jump   004366C1  
    219. Sonic_JumpHeight   004369B6  
    220. Sonic_HyperDash_Velocities   00436EA7  
    221. Tails_Super   00436ECF  
    222. SonicKnux_SuperHyper   00436EDE  
    223. SonicKnux_Spindash   00437033  
    224. Player_SlopeResist   00437531  
    225. Player_RollRepel   00437639  
    226. Player_SlopeRepel   00437719  
    227. Player_JumpAngle   00437836  
    228. SonicKnux_DoLevelCollision   0043795B  
    229. Player_TouchFloor_Check_Spindash   0043809E  
    230. Player_TouchFloor   004380BA  
    231. BubbleShield_Bounce   004382B7  
    232. Animate_Sonic   00438BAF  
    233. AniSonic   00439B76  
    234. Sonic_Load_PLC   00439D88  
    235. Sonic_Load_PLC2   00439D9D  
    236. Tails_Carry_LoadPLC   00439F69  
    237. SonicKnuckles2P_Load_PLC   0043A8B4  
    238. Obj_Tails2P   0043AA88  
    239. Obj_Tails   0043B7A6  
    240. Tails_Display   0043BD3E  
    241. TailsCPU_Control   0043BFB1  
    242. Tails_Catch_Up_Flying   0043C203  
    243. Tails_FlySwim_Unknown   0043C47C  
    244. Tails_Water   0043E0FB  
    245. Animate_Tails   00441510  
    246. Tails_Tail_Load_PLC   00441E98  
    247. Tails_Load_PLC   00441F61  
    248. Tails2P_Tail_Load_PLC   00442B0C  
    249. Tails2P_Load_PLC   00442BD4  
    250. Obj_Tails_Tail   00442D87  
    251. AniTails_Tail   00442F9C  
    252. Obj_Tails2P_Tail   00443000  
    253. Ani_Tails2P_Tail   004431DC  
    254. Obj_MGZ2_BossTransition   004431F4  
    255. Obj_Knuckles   004435CC  
    256. Draw_LRZ_Special_Rock_Sprites   004485D0  
    257. Animate_Tiles   00448AD0  
    258. Animate_Init   0044CE15  
    259. Load_Rings   0044D020  
    260. Render_Rings   0044DA9C  
    261. Sprite_Listing3   0044F0E8  
    262. Sprite_ListingK   0044F4E8  
    263. Do_ResizeEvents   0044F7CC  
    264. LevelResizeArray   0044F94F  
    265. AIZ1_Resize   0044F9AF  
    266. AIZ2_Resize   0044FCE8  
    267. AIZ2_SonicResize1   0044FD60  
    268. AIZ2_SonicResize2   0044FDBD  
    269. AIZ2_SonicResize3   0044FE53  
    270. AIZ2_SonicResize4   0044FE80  
    271. AIZ2_SonicResize5   0044FF03  
    272. AIZ2_SonicResize6   0044FF3E  
    273. AIZ2_SonicResize7   0044FF79  
    274. AIZ2_SonicResizeEnd   0044FF98  
    275. AIZ2_KnuxResize1   0044FF99  
    276. AIZ2_KnuxResize2   0044FFF6  
    277. AIZ2_KnuxResize3   00450096  
    278. AIZ2_KnuxResize4   004500B9  
    279. AIZ2_KnuxResize5   00450137  
    280. AIZ2_KnuxResizeEnd   0045016B  
    281. CalcRoomOverHead   00450A88  
    282. CheckRightWallDist   00451522  
    283. CheckLeftWallDist   00452006  
    284. DebugMode   00452264  
    285. DebugOffs   00452A6B  
    286. Debug_AIZ1   00452ACB  
    287. Debug_AIZ2   00452C29  
    288. Debug_HCZ   00452DE7  
    289. Debug_MGZ   00453071  
    290. Debug_CNZ   00453223  
    291. Debug_FBZ1   004533D5  
    292. Debug_FBZ2   00453623  
    293. Debug_ICZ1   00453865  
    294. Debug_ICZ2   004539FF  
    295. Debug_LBZ1   00453BA5  
    296. Debug_LBZ2   00453D57  
    297. Debug_MHZ   00453F39  
    298. Debug_SOZ1   004540D3  
    299. Debug_SOZ2   00454279  
    300. Debug_LRZ1   00454437  
    301. Debug_LRZ2   00454601  
    302. Debug_SSZ   004547CB  
    303. Debug_DEZ1   004548D5  
    304. Debug_DEZ2   00454A4B  
    305. Debug_DDZ   00454B9D  
    306. Debug_DEZBoss   00454C2F  
    307. Debug_Ending   00454C91  
    308. Debug_ALZ   00454CF3  
    309. Debug_BPZ   00454DCD  
    310. Debug_DPZ   00454ECB  
    311. Debug_CGZ   00454FC9  
    312. Debug_EMZ   004550BB  
    313. Debug_Pachinko_Special   004551C5  
    314. Debug_HPZ   00455233  
    315. Debug_Gumball_Special   004552AD  
    316. Player_AnglePos   00455310  
    317. Obj_PathSwap   0045712C  
    318. ArtUnc_Tails   00459FDC  
    319. ArtUnc_Tails_Tail   0047051C  
    320. ArtUnc_Sonic2P   0047167C  
    321. ArtUnc_Tails2P   0047473C  
    322. ArtUnc_Tails2P_Tail   004774DC  
    323. ArtUnc_Knuckles2P   00477A5C  
    324. ArtUnc_Invincibility   0047ED80  
    325. MapEni_S3TitleSonic1   00485700  
    326. MapEni_S3TitleSonic2   004857BC  
    327. MapEni_S3TitleSonic3   00485880  
    328. MapEni_S3TitleSonic4   00485944  
    329. MapEni_S3TitleSonic5   00485A08  
    330. MapEni_S3TitleSonic6   00485ACC  
    331. MapEni_S3TitleSonic7   00485B94  
    332. MapEni_S3TitleSonic8   00485C94  
    333. MapEni_S3TitleSonic9   00485D80  
    334. MapEni_S3TitleSonicA   00485E50  
    335. MapEni_S3TitleSonicB   00485F14  
    336. MapEni_S3TitleSonicC   00485FB4  
    337. MapEni_S3TitleSonicD   00486084  
    338. MapEni_S3TitleBg   00486180  
    339. ArtNem_Title_S3Banner   004862DC  
    340. ArtKos_S3TitleSonic1   00486D98  
    341. ArtKos_S3TitleSonic8   00487CF8  
    342. ArtKos_S3TitleSonic9   0048A358  
    343. ArtKos_S3TitleSonicA   0048C658  
    344. ArtKos_S3TitleSonicB   0048DB38  
    345. ArtKos_S3TitleSonicC   0048EE58  
    346. ArtKos_S3TitleSonicD   00490038  
    347. ArtUnc_AirCountDown   004966D8  
    348. Map_Sonic2P   00498BCC  
    349. Map_Tails2P   00498E78  
    350. Map_Tails2P_Tail   00499036  
    351. Map_Knuckles2P   0049923C  
    352. ArtNem_Title_SonicSprites   00499554  
    353. PalKos_Pachinko   004DB190  
    354. ArtKos_SaveScreen   004DE00E  
    355. ArtKos_SaveScreenSKZone   004E05FC  
    356. ArtKos_SaveScreenPortrait   004E264C  
    357. ArtKosM_MHZEndBoss   004ED9D8  
    358. ArtNem_SonicLifeIcon   0050E10C  
    359. ArtNem_TailsLifeIcon   0050E224  
    360. ArtNem_KnucklesLifeIcon   0050E310  
    361. ArtNem_Monitors   0050E508  
    362. ArtNem_Explosion   0050F8F4  
    363. ArtNem_SpikesSprings   00510234  
    364. ArtNem_Ring   00510524  
    365. ArtNem_EnemyPts   00510760  
    366. ArtNem_BlueFlicky   00510C0C  
    367. ArtNem_SignpostStub   00532CDC  
    368. ArtUnc_HCZWaterSplash2   00542F24  
    369. ArtUnc_HCZWaterSplash   005436A4  
    370. Pal_SaveMenuBG   0054DE0E  
    371. MapEni_S3MenuBG   0054DE4E  
    372. ArtKos_S3MenuBG   0054E050  
    373. MapEni_SaveScreen_Layout   00552BCC  
    374. ArtKos_SaveScreenMisc   00552F56  
    375. FBZ_16x16_Kos   005542F8  
    376. ArtKosM_FBZ   00554F38  
    377. FBZ_128x128_Kos   0055739A  
    378. ArtUnc_Sonic   005A3AAC  
    379. Knuckles_Art   005C3B8C  
    380. ArtUnc_Sonic_Extra   005E3B0C  
    381. ArtUnc_Tails_Extra   005E77AC  
    382. Map_Sonic   005EA0CC  
    383. Map_SuperSonic   005EA2C2  
    384. PLC_Sonic   005EBC2E  
    385. PLC_SuperSonic   005EBE24  
    386. Map_Tails   005EC964  
    387. PLC_Tails   005EDB36  
    388. Map_Knuckles   005EE382  
    389. PLC_Knuckles   005EF7B6  
    390. AIZ1_16x16_Primary_Kos   005F06DC  
    391. AIZ1_16x16_Secondary_Kos   005F08DC  
    392. AIZ1_8x8_Primary_KosM   005F25FC  
    393. AIZ1_8x8_Secondary_KosM   005F340E  
    394. AIZ1_128x128_Kos   005F8BD2  
    395. AIZ2_16x16_Primary_Kos   005FCFE4  
    396. AIZ2_16x16_Secondary_Kos   005FD884  
    397. AIZ2_8x8_Primary_KosM   005FE564  
    398. AIZ2_8x8_Secondary_KosM   00600716  
    399. AIZ2_128x128_Kos   0060217A  
    400. HCZ_16x16_Primary_Kos   0060618A  
    401. HCZ_8x8_Primary_KosM   006065FA  
    402. HCZ_128x128_Primary_Kos   0060723C  
    403. HCZ1_16x16_Secondary_Kos   0060757C  
    404. HCZ1_8x8_Secondary_KosM   00607E0C  
    405. HCZ1_128x128_Secondary_Kos   0060A05E  
    406. HCZ2_16x16_Secondary_Kos   0060C10E  
    407. HCZ2_8x8_Secondary_KosM   0060C9FE  
    408. HCZ2_128x128_Secondary_Kos   0060E880  
    409. MGZ_16x16_Primary_Kos   00610500  
    410. MGZ_8x8_Primary_KosM   00610E50  
    411. MGZ_128x128_Primary_Kos   006133F2  
    412. MGZ1_16x16_Secondary_Kos   006156F2  
    413. MGZ1_8x8_Secondary_KosM   00615A02  
    414. MGZ1_128x128_Secondary_Kos   006163E4  
    415. MGZ2_16x16_Secondary_Kos   00616C64  
    416. MGZ2_8x8_Secondary_KosM   006170C4  
    417. MGZ2_128x128_Secondary_Kos   00618156  
    418. CNZ_16x16_Kos   00619BC6  
    419. CNZ_8x8_KosM   0061AC06  
    420. CNZ_128x128_Kos   0061DE28  
    421. AngleArray   0064CEB4  
    422. HeightMaps   0064CFB4  
    423. HeightMapsRot   0064DFB4  
    424. SolidIndexes   0064EFB4  
    425. Solid_AIZ1   0064F074  
    426. Solid_AIZ2   0064F674  
    427. Solid_HCZ1   0064FC74  
    428. Solid_HCZ2   00650274  
    429. Solid_MGZ1   00650874  
    430. Solid_MGZ2   00650E74  
    431. Solid_CNZ   00651474  
    432. Solid_FBZ   00651A74  
    433. Solid_ICZ1   00652074  
    434. Solid_ICZ2   00652674  
    435. Solid_LBZ1   00652C74  
    436. Solid_LBZ2   00653274  
    437. Solid_MHZ   00653874  
    438. Solid_SOZ   00654474  
    439. Solid_LRZ1   00654A74  
    440. Solid_LRZ2   00655074  
    441. Solid_SSZ1   00655674  
    442. Solid_SSZ2   00655C74  
    443. Solid_DEZ   00656274  
    444. Solid_DDZ   00656874  
    445. Solid_ALZ   00656E74  
    446. Solid_BPZ   00657474  
    447. Solid_DPZ   00657A74  
    448. Solid_CGZ   00658074  
    449. Solid_EMZ   00658674  
    450. Solid_Gumball_Special   00658C74  
    451. Solid_Pachinko_Special   00659274  
    452. Solid_Slots_Special   00659874  
    453. Solid_LRZ3   00659E74  
    454. Solid_HPZ   0065A474  
    455. LevelPtrs   0065AA74  
    456. Layout_AIZ1   0065AB34  
    457. Layout_AIZ2   0065B380  
    458. Layout_HCZ1   0065C0E6  
    459. Layout_HCZ2   0065CC0E  
    460. Layout_MGZ1   0065DAB6  
    461. Layout_MGZ2   0065E746  
    462. Layout_CNZ1   0065F4F6  
    463. Layout_CNZ2   006600C0  
    464. Layout_FBZ1   0066104E  
    465. Layout_FBZ2   00661DF6  
    466. Layout_ICZ1   00662D84  
    467. Layout_ICZ2   00663D4C  
    468. Layout_LBZ1   00664B9C  
    469. Layout_LBZ2   00665B48  
    470. Layout_MHZ1   00666A70  
    471. Layout_MHZ2   006677A4  
    472. Layout_SOZ1   00668414  
    473. Layout_SOZ2   00669280  
    474. Layout_LRZ1   0066A098  
    475. Layout_LRZ2   0066AEC0  
    476. Layout_SSZ1   0066BC48  
    477. Layout_SSZ2   0066C8B8  
    478. Layout_DEZ1   0066CA34  
    479. Layout_DEZ2   0066DA02  
    480. Layout_DDZ   0066E890  
    481. Layout_ALZ   0066E99C  
    482. Layout_BPZ   0066EB68  
    483. Layout_DPZ   0066ECBC  
    484. Layout_CGZ   0066EDB4  
    485. Layout_EMZ   0066EEAC  
    486. Layout_Gumball_Special   0066EFA4  
    487. Layout_Pachinko_Special   0066F05C  
    488. Layout_Slots_Special   0066F244  
    489. Layout_LRZBoss   0066F3E6  
    490. Layout_HPZ   0066F69E  
    491. Layout_DEZBoss   0066FCC6  
    492. PalPoint   006704A6  
    493. Pal_SonicTails   006707B6  
    494. Pal_Knuckles   00670876  
    495. Pal_AIZIntro   00670896  
    496. Pal_AIZ   006708F6  
    497. Pal_AIZFire   00670956  
    498. Pal_AIZBoss   006709B6  
    499. Pal_AIZ_Water   00670A16  
    500. Pal_AIZ2_Water   00670A96  
    501. Pal_HCZ1   00670B16  
    502. Pal_HCZ2   00670B76  
    503. Pal_HCZ1_Water   00670BD6  
    504. Pal_HCZ2_Water   00670C56  
    505. Pal_MGZ   00670CD6  
    506. Pal_CNZ   00670D36  
    507. Pal_CNZ_Dark   00670D96  
    508. Pal_FBZ1   00670E16  
    509. Pal_FBZ2   00670E76  
    510. Pal_ICZ1   00670ED6  
    511. Pal_ICZ2   00670F36  
    512. Pal_ICZ2_Water   00670F96  
    513. Pal_LBZ1   00671016  
    514. Pal_LBZ2   00671076  
    515. Pal_LBZ_Water   006710D6  
    516. Pal_LBZ_DeathEgg   00671156  
    517. Pal_MHZ1   006711B6  
    518. Pal_MHZ2   00671216  
    519. Pal_SOZ1   00671276  
    520. Pal_SOZ2   006712D6  
    521. Pal_SOZ_Dark1   00671336  
    522. Pal_SOZ_Dark2   00671396  
    523. Pal_LRZ1   006713F6  
    524. Pal_LRZ2   00671456  
    525. Pal_SSZ1   006714B6  
    526. Pal_SSZ2   00671516  
    527. Pal_DEZ1   00671636  
    528. Pal_DEZ2   00671696  
    529. Pal_DDZ   006716F6  
    530. Pal_ALZ   00671756  
    531. Pal_BPZ   006717B6  
    532. Pal_DPZ   00671816  
    533. Pal_CGZ   00671876  
    534. Pal_EMZ   006718D6  
    535. Pal_Gumball_Special   00671936  
    536. Pal_Pachinko_Special   00671996  
    537. Pal_Slot_Special   006719F6  
    538. Pal_LRZBoss   00671A56  
    539. Pal_HPZ   00671AB6  
    540. Pal_HPZ_Line3   00671AD6  
    541. Pal_DEZBoss   00671B16  
    542. ArtNem_S22POptions   006916DE  
    543. ArtKos_BigSEGA   006937AC  
    544. ArtKos_TitleScreenBG   00693B2C  
    545. ArtKos_Title_699610   00699610  
    546. ArtKos_Title_69A4F0   0069A4F0  
    547. ArtKos_69AB70   0069AB70  
    548. ArtNem_Title_ANDKnuckles   0069D5A4  
    549. SpecialStage   0069DDD4  
    550. SSLayoutOffs_RAM   0069E3DF  
    551. LoadSpecialStageMap   0069E3FF  
    552. Rotate_SSPal   0069EC3F  
    553. Update_SSMap   0069ED2E  
    554. SS_Pal_Map_Ptrs   0069EF32  
    555. Draw_SSNum   0069F2DA  
    556. Draw_SSSprites   006A1439  
    557. Draw_SSSprite_Normal   006A1E6F  
    558. Draw_SSSprite_FlyAway   006A1FB8  
    559. Animate_SSRings   006A2819  
    560. BlueSpheresTitle   006A4398  
    561. aNoWayNoWayNoWa   006A4787  
    562. aGetBlueSpheres   006A47B3  
    563. aGm000010090   006A487B  
    564. aGm000040490   006A4888  
    565. BlueSpheresResults   006A716E  
    566. aCongratulation   006A77E6  
    567. aPerfect   006A77F8  
    568. Obj_Sonic_RotatingSlotBonus   006A9460  
    569. LevelSetup   006AC52C  
    570. ScreenEvents   006AC6DD  
    571. Offs_ScreenEvents   006AC7E0  
    572. VInt_DrawLevel   006ACAE0  
    573. VInt_DrawLevel_2   006ACB0B  
    574. VInt_DrawLevel_Done   006ACC1F  
    575. VInt_VRAMWrite   006ACC20  
    576. VInt_VRAMWrite_Col   006ACC53  
    577. SpecialVInt_VRAMWrite   006ACC9B  
    578. SpecialVInt_VRAMRead   006ACCCE  
    579. SpecialVInt_LBZ2WindowCopy   006ACD01  
    580. SpecialVInt_LBZ2ScrollAClear   006ACE0B  
    581. SpecialVInt_LBZ2ScrollAClear2   006ACE85  
    582. SpecialVInt_LBZ2WindowClear   006ACEFD  
    583. Setup_TileRowDraw   006AD96B  
    584. Refresh_PlaneFull   006ADFAB  
    585. DrawTilesAsYouMove   006AE347  
    586. DrawBGAsYouMove   006AE3A9  
    587. PlainDeformation   006AEF73  
    588. ApplyDeformation   006AF1EC  
    589. Reset_TileOffsetPositionActual   006AFF3E  
    590. Reset_TileOffsetPositionEff   006AFFA1  
    591. ShakeScreen_BG   006B0355  
    592. AIZ_TreeReveal   006B08D0  
    593. AIZ_TreeRevealArray   006B0952  
    594. AIZ1_IntroDeform   006B09C2  
    595. AIZ1_IntroDeformArray   006B12C4  
    596. AIZ1_ScreenInit   006B1BD4  
    597. AIZ1_ScreenEvent   006B1BE9  
    598. AIZ1SE_ChangeChunk2   006B1DF0  
    599. AIZ1SE_ChangeChunk3   006B1E1E  
    600. AIZ1SE_ChangeChunk4   006B1E4C  
    601. Adjust_AIZ1Chunks   006B1F29  
    602. AIZ1_BackgroundInit   006B215E  
    603. AIZ1_BackgroundEvent   006B2221  
    604. AIZ2_ScreenInit   006B2BF2  
    605. AIZ2_ScreenEvent   006B2C07  
    606. AIZ2_BackgroundInit   006B2F42  
    607. AIZ2_BackgroundEvent   006B2FA3  
    608. FBZ1_ScreenInit   006BA9D4  
    609. FBZ1_ScreenEvent   006BAB4E  
    610. FBZ1_BackgroundInit   006BC75A  
    611. FBZ1_BackgroundEvent   006BC899  
    612. FBZ2_ScreenInit   006BD544  
    613. FBZ2_ScreenEvent   006BD609  
    614. FBZ2_BackgroundInit   006BDCED  
    615. FBZ2_BackgroundEvent   006BDDF5  
    616. j_DrawTilesAsYouMove   006C2FF5  
    617. ICZ1_ScreenInit   006C4416  
    618. ICZ1_ScreenEvent   006C44C3  
    619. ICZ1_BackgroundInit   006C4567  
    620. ICZ1_BackgroundEvent   006C466F  
    621. ICZ2_ScreenInit   006C53D5  
    622. ICZ2_ScreenEvent   006C53E3  
    623. ICZ2_BackgroundInit   006C53EA  
    624. ICZ2_BackgroundEvent   006C54BA  
    625. CNZ1_ScreenInit   006CBFD8  
    626. CNZ1_ScreenEvent   006CBFE6  
    627. CNZ1_BackgroundInit   006CC46C  
    628. CNZ1_BackgroundEvent   006CC4A3  
    629. CNZ2_ScreenInit   006CD3C5  
    630. CNZ2_ScreenEvent   006CD3D3  
    631. CNZ2_BackgroundInit   006CD5DD  
    632. CNZ2_BackgroundEvent   006CD61E  
    633. LBZ1_ScreenInit   006CE60D  
    634. LBZ1_ScreenEvent   006CE7E5  
    635. LBZ1_BackgroundInit   006CF1A7  
    636. LBZ1_BackgroundEvent   006CF2C1  
    637. LBZ2_ScreenInit   006CF5E2  
    638. LBZ2_ScreenEvent   006CF625  
    639. LBZ2_BackgroundInit   006CF96B  
    640. LBZ2_BackgroundEvent   006CF9F5  
    641. MGZ1_ScreenInit   006D30E4  
    642. MGZ1_ScreenEvent   006D30FA  
    643. MGZ1_BackgroundInit   006D312A  
    644. MGZ1_BackgroundEvent   006D315F  
    645. MGZ2_ScreenInit   006D34C7  
    646. MGZ2_ScreenEvent   006D34F3  
    647. MGZ2_BackgroundInit   006D4596  
    648. MGZ2_BackgroundEvent   006D46F3  
    649. HCZ1_ScreenInit   006D5010  
    650. HCZ1_ScreenEvent   006D5026  
    651. HCZ1_BackgroundInit   006D502D  
    652. HCZ1_BackgroundEvent   006D50AD  
    653. HCZ1BGE_Normal   006D50D1  
    654. HCZ1BGE_DoTransition   006D51E6  
    655. HCZ2_ScreenInit   006D5CD7  
    656. HCZ2_ScreenEvent   006D5CE5  
    657. HCZ2_BackgroundInit   006D5D0E  
    658. HCZ2_BackgroundEvent   006D5DA1  
    659. Pachinko_ScreenInit   006D63A8  
    660. Pachinko_ScreenEvent   006D63B2  
    661. Pachinko_BackgroundInit   006D63B7  
    662. Pachinko_BackgroundEvent   006D63CD  
    663. Pachinko_BGScroll   006D63DE  
    664. Competition_Menu   006D6499  
    665. Competition_LevelSelect   006D6C13  
    666. Competition_PlayerSelect   006D7CB9  
    667. Competition_Results   006D889D  
    668. TimeAttack_Records   006D94A2  
    669. KosArt_To_VDP   006D9DF4  
    670. Set_Lives_and_Continues   006DA1B4  
    671. Title_Screen   006DBFE2  
    672. S3K_Title_Screen   006DBFF0  
    673. Pal_Title   006DCE75  
    674. Pal_TitleSonic1   006DCEE5  
    675. Pal_TitleSonicD   006DD085  
    676. Obj_TitleBanner   006DD105  
    677. Obj_TitleANDKnuckles   006DD408  
    678. Obj_TitleCopyright   006DD578  
    679. Obj_TitleSelection   006DD5F1  
    680. Obj_TitleSonicFinger   006DD736  
    681. Obj_TitleSonicWink   006DD804  
    682. Obj_TitleTailsPlane   006DD8C0  
    683. S3_Level_Select_Code_Dummy   006DDA20  
    684. S3_Level_Select_Code   006DDA21  
    685. LSelect3CodeDat   006DDACB  
    686. ArtNem_TitleScreenText   006DDB68  
    687. SK_Alone_Title_Screen   006DDE88  
    688. ArtNem_TitleScreen1997   006E0340  
    689. SRAM_Load   006E04C8  
    690. SaveGame   006E0980  
    691. SaveScreen   006E0D1D  
    692. Pal_Save_Chars   006E1B43  
    693. Pal_Save_Emeralds   006E1B65  
    694. Map_SaveScreen   006E1ED9  
    695. ObjDat_SaveScreen   006E2209  
    696. ArtKos_SaveScreenS3Zone   006E3D00  
    697. S3_Alone_Title_Screen   006E62E0  
    698. Iterate_Sonic_TitleFrame   006E6C59  
    699. TitleSonic_LoadFrame   006E6DAD  
    700. ObjDat_SaveScreen_S3   006EA783  
    701.  
     
  6. Brainulator

    Brainulator

    Regular garden-variety member Member
    Looking at sprite_status.h:
    • Any reason why sproffset is called pattern and patbase is called mapping?
    • Shouldn't mstno be a short/char union as in Sonic CD? Same goes for direc (which is split into direc1 and direc2) as well as xposi and yposi (which are words that should be treated as int/short/char unions).
    • Isn't $2A cddat and $2C-$2D userflag?
    In addition, I'm pretty sure that several symbols missing from the EXE's debug info can be found in Gems Collection Sonic CD as well as Sonic 2 Nick Arcade.

    That said, I very much appreciate this. Thank you for doing this!
     
  7. BenoitRen

    BenoitRen

    Tech Member
    392
    178
    43
    To name the sprite_status struct's members, I cross-referenced Sonic the Hedgehog's SST, your post on how Sonic CD's SST compares to it, and Sonic 3's SST. It's very likely I made some mistakes. :)

    I'm guessing I chose "pattern" because the description on the wiki lead me to think that was what it represented. But looking more closely, you're right; it's the same thing as "sproffset" in Sonic CD.

    It looks like for "mapping" I didn't cross-reference at all, because the position and description is the same in both the original game, Sonic CD, and Sonic 3. It should indeed be "patbase".

    I'm trying to avoid unions as it leads to code that is dependent on the CPU's endianness. That's why I split them up. If I find that solution isn't workable, I'll join them again, but unions are a last resort.

    The reason I made actfree start at 0x2A is because it seems to essentially be the start of data specific to the type of object. I guess it would be more accurate to assign cddat and userflag. But what about 0x2B? It seems to also be a status bitfield. Do I name that cddat2?

    Having decompiled a large chunk of Sonic CD definitely helps. Yesterday I happened to find our good friend random() and its associated global variable ranum, seemingly unchanged. But I want to be careful with this, as who knows what changed on the way to Sonic 3 while passing through Sonic 2.

    I haven't looked at the symbols found in Sonic 2 Nick Arcade yet, because they seemed to map to an older build. But I'm open to suggestions on how they could be of use.

    Thanks for your corrections!
     
  8. Brainulator

    Brainulator

    Regular garden-variety member Member
    First of all, you're welcome.

    As for cddat2, I guess with your avoidance of unions in mind, uh... sure, why not.

    For Sonic 2 Nick Arcade, I would imagine that there would at least be parallels for, going off of these lists: bgmset, soundset, dmactrset, mapdevr, random, sinset, atan, ringgetsub, speedset, speedset2, actionsub, frameout, patchg, spatsetsub, actwkchk, actwkchk2, colichg, efectwrt, efecttbl, score, edit, mapinittbl, divdevtbl, scddirtbl1, scddirtbl2, scdtbl, asettbl, and their associated labels (there's also frameoutchk and frameoutchkd, which aren't listed in that post). random was not changed between Sonic 2 and 3, though Sonic & Knuckles changed the default seed value for whatever reason.
     
  9. BenoitRen

    BenoitRen

    Tech Member
    392
    178
    43
    Someone correct me if I'm wrong, but it looks like what the disassembly calls Create_New_Sprite3 has an off-by-one error.

    It takes the address of the first reserved SST (0xCAE2), then subtracts the address of the current SST, and divides it by 0x40. That in itself is already odd, because the size of an SST is 0x4A. It then uses a lookup table to get a loop counter.

    If the loop counter is negative, which it would only be if the current SST is the first reserved SST, it returns. If not, it loops until it either finds a free SST or if the loop counter becomes negative.

    The lookup table's first values are -1, 0, and 1.

    Let's suppose that the current SST is the last dynamic SST, right before the first reserved SST. The calculation would be:
    Code (Text):
    1. (0xCAE2 - 0xCA98) / 0x40
    The result being 1. So it would retrieve 0 from the lookup table. It's not negative, so it enters the loop.

    The first thing that happens in the loop is to advance to the next SST. But this would be the first reserved SST! If it's free at any point, and the range of dynamic SSTs is full, it could be claimed by mistake!

    I've ported this to C as follows:
    Code (Text):
    1. void Create_New_Sprite3(sprite_status* pActwk, sprite_status** ppNewActwk) {
    2.   *ppNewActwk = pActwk;
    3.  
    4.   // Off by one error. The reserved range's first slot might be overwritten.
    5.   for (int slots = (&actwk[93] - pActwk) - 1; slots >= 0; --slots) {
    6.     ++*ppNewActwk;
    7.     if ((*ppNewActwk)->r_ptr == 0) return true;
    8.   }
    9.  
    10.   return false;
    11. }
    There also seems to be a problem when the current SST is the first dynamic SST, based on a comment in the disassembly and the lookup table.

    Thoughts?
     
    Last edited: Jan 16, 2024
  10. BenoitRen

    BenoitRen

    Tech Member
    392
    178
    43
    I need some help figuring out some mysterious stack use.

    In the function chk_framein, at one point it copies the current stack value into EAX and pops the stack. Then it assigns EAX to an int starting at byte 52 (0x34) of the sprite status object.
    Code (Text):
    1. POP        EAX
    2. MOV        EDI,dword ptr [68k_a0]
    3. MOV        dword ptr [EDI + 0x34],EAX
    At the bottom of the function this value is retrieved again and assigned to the sprite status object's routine pointer.
    Code (Text):
    1. MOV        EDI,dword ptr [68k_a0]
    2. MOV        EAX,dword ptr [EDI + 0x34]
    3. EDI,dword ptr [68k_a0]
    4. MOV        dword ptr [EDI],EAX
    After some searching I found the equivalent code in the Mega Drive version's disassembly, Obj_WaitOffscreen. This is the equivalent code:
    Code (Text):
    1. move.l   (sp)+,$34(a0)
    The equivalent of the bottom part:
    Code (Text):
    1. move.l   $34(a0),(a0)
    My question is: where is the value on the stack coming from? I've ran multiple searches. The Kosinski decompression manipulates the stack, but it doesn't seem to be related. All other stack manipulations are reverted before the end of the function in which they are found.
     
  11. MarkeyJester

    MarkeyJester

    Original, No substitute Resident Jester
    2,200
    430
    63
    Japan
    It'll be the return address of the caller.

    It's a way of setting the object's next routine to run, without using an instruction that needs that address as an immediate value. If you used move to set the address, you'd have to store a long-word address. But because the next routine is literally next to the jmp/jp instruction, they can swapped out a jmp/jp for a jsr/call, and abuse the fact that these instruction will push that same routine address onto the stack, and because the subroutine is reusable, you save 6 bytes for every call.

    There are other minor benefits such as program flow, but space is definitely a key factor, memory cost money.
     
    • Agree Agree x 1
    • Informative Informative x 1
    • List
  12. Brainulator

    Brainulator

    Regular garden-variety member Member
    It should be noted that the Buggernaut, Blaster, and Technosqueek badniks, as well as the ICZ path-following platforms, actually have code that refers to their pointers after they are on-screen.
     
  13. BenoitRen

    BenoitRen

    Tech Member
    392
    178
    43
    While I did port some code to C, these days I'm mostly doing research before beginning the porting in earnest. So I figured I'd talk some more about the labels, which have been extracted before, but never talked about.

    But before that, I want to talk about the internal zone IDs. Outside of a section on Sonic 3 cheat codes and a TCRF page about Sonic & Knuckles content in Sonic 3, these don't seem to be documented anywhere.

    00 - Angel Island Zone
    01 - Hydro City Zone
    02 - Marble Garden Zone
    03 - Carnival Night Zone
    04 - Flying Battery Zone
    05 - Ice Cap Zone
    06 - Launch Base Zone
    07 - Mushroom Hill Zone
    08 - Sandopolis Zone
    09 - Lava Reef Zone
    0A - Sky Sanctuary Zone
    0B - Death Egg Zone
    0C - Doomsday Zone

    Note that it starts at 00, not 01. I already knew that Flying Battery was supposed to be the fifth zone, but its ID is 04, not 05.

    With that out of the way, let's take a look at some of the labels.

    gost08: The ghost enemy from Sandopolis Zone, called Hyudoro. The same section also contains the code related to their capsule prison, labelled obox08.

    iwa09: Iwamodoki, a rock enemy from Lava Reef Zone.

    rolldai: I've often seen things called "dai" in Sonic source code, but I have no idea what it means. Is this a rolling spike, or something?

    caos09: This seems to refer to the Hidden Palace that you access through a big ring. I know this because the same section also refers to a light_piller (light pillar), which is how you make your entrance, and schaos, which refers to the Super Chaos Emeralds.

    shel03: A shell in Carnival Night Zone? That must be Shell Star, known in English as Clamer.

    bs00b0: Angel Island Zone's end boss, the Flame Mobile.

    nozu05: Something in Ice Cap Zone. A nozzle? Related labels are nozu05_igas, nozu05_ice, and ice_break. This seems to be what's termed as a "freeze gun", which spews gas that freezes Sonic if he touches it.

    fish01: A fish in Hydro City Zone. A related label is dec_ring, which means that it decreases rings. That must be Kapu-Kapu, known in English as Mega Chopper.

    nuckle: Knuckles, of course. The regular labels always misspell his name, while local labels spell it correctly. At least there's some consistency.

    That's all for now. Let me know if this interests you, and I'll write more soon.
     
  14. saxman

    saxman

    Oldbie Tech Member
    Oh gosh, that's primitive stuff! If it's not documented anywhere, then I'm honestly surprised. Here it is documented going all the way back to the old Sonic 3K Hacking Guide from the early 2000s:

    upload_2024-2-10_14-38-41.png

    Although, it looks like I messed up the IDs somewhere, because Doomsday isn't 0D.

    By the way, look forward to seeing more of your decompilation work.
     
  15. Brainulator

    Brainulator

    Regular garden-variety member Member
    I see that you listed Hidden Palace in between Lava Reef and Sky Sanctuary, rather than waaaaay at the end of the list.
    rolldai is the barrels in Carnival Night Zone, including the Barrel of Doom. rolldai2 is the Hydrocity version. I've actually decided to take a crack at lining up the labels myself, and reached something very interesting...

    MainMemory has said multiple times before, including in this very thread, that Sonic & Knuckles Collection was machine-translated from 68000 assembly to x86 assembly, without attempting to optimize the results. Something I noticed, though, is that I think there might be some portions of the code that were optimized to some extent. For example, let's look at two functions, which, in the current version of skdisasm, are called CreateChild1_Normal and CreateChild7_Normal2:
    Code (Text):
    1. CreateChild1_Normal:
    2.         moveq    #0,d2                ; Includes positional offset data
    3.         move.w    (a2)+,d6
    4.  
    5. .loop:
    6.         jsr    (AllocateObjectAfterCurrent).l
    7.         bne.s    .end
    8.         move.w    a0,parent3(a1)            ; Parent RAM address into $46
    9.         move.l    mappings(a0),mappings(a1)
    10.         move.w    art_tile(a0),art_tile(a1)    ; Mappings and VRAM offset copied from parent object
    11.         move.l    (a2)+,(a1)            ; Object address
    12.         move.b    d2,subtype(a1)            ; Index of child object (done sequentially for each object)
    13.         move.w    x_pos(a0),d0
    14.         move.b    (a2)+,d1            ; X Positional offset
    15.         move.b    d1,child_dx(a1)            ; $42 has the X offset
    16.         ext.w    d1
    17.         add.w    d1,d0
    18.         move.w    d0,x_pos(a1)            ; Apply offset to new position
    19.         move.w    y_pos(a0),d0
    20.         move.b    (a2)+,d1            ; Same as above for Y
    21.         move.b    d1,child_dy(a1)            ; $43 has the Y offset
    22.         ext.w    d1
    23.         add.w    d1,d0
    24.         move.w    d0,y_pos(a1)            ; Apply offset
    25.         addq.w    #2,d2                ; Add 2 to index
    26.         dbf    d6,.loop            ; Loop
    27.         moveq    #0,d0
    28.  
    29. .end:
    30.         rts
    Code (Text):
    1.  
    2. CreateChild7_Normal2:
    3.         moveq    #0,d2                ; Same as child routine 1, but does not limit children to object slots after the parent
    4.         move.w    (a2)+,d6
    5.  
    6. .loop:
    7.         jsr    (AllocateObject).l
    8.         bne.s    .end
    9.         move.w    a0,parent3(a1)
    10.         move.l    mappings(a0),mappings(a1)
    11.         move.w    art_tile(a0),art_tile(a1)
    12.         move.l    (a2)+,(a1)
    13.         move.b    d2,subtype(a1)
    14.         move.w    x_pos(a0),d0
    15.         move.b    (a2)+,d1
    16.         move.b    d1,child_dx(a1)
    17.         ext.w    d1
    18.         add.w    d1,d0
    19.         move.w    d0,x_pos(a1)
    20.         move.w    y_pos(a0),d0
    21.         move.b    (a2)+,d1
    22.         move.b    d1,child_dy(a1)
    23.         ext.w    d1
    24.         add.w    d1,d0
    25.         move.w    d0,y_pos(a1)
    26.         addq.w    #2,d2
    27.         dbf    d6,.loop
    28.         moveq    #0,d0
    29.  
    30. .end:
    31.         rts
    32.  

    You can see that the two functions, in the Mega Drive version of Sonic & Knuckles, are identical save for which function is called to check where in RAM to spawn the child object. As such, any input data will be identical between the two. You'd think that these would be the same in PC version, right?

    Note that I haven't seen any direct attestation of this label, I'm just making an educated guess. Also, this was copied and cleaned up from Ghidra, leaving in the address and binary data so you can see that some of the instructions were assembled differently.
    Code (Text):
    1.  
    2. set_act00
    3.           7584ac 55                                     PUSH                 EBP
    4.           7584ad 33 c9                                  XOR                  ECX,ECX
    5.           7584af 8b 2d cc 47 85 00                      MOV                  EBP,dword ptr [68k_a2]
    6.           7584b5 66 8b 55 00                            MOV                  DX,word ptr [EBP]
    7.           7584b9 83 c5 02                               ADD                  EBP,0x2
    8.           7584bc 66 42                                  INC                  DX
    9. @@loop0
    10.           7584be e8 0c 34 cd ff                         CALL                 actwkchk2
    11.           7584c3 75 59                                  JNZ                  @@ret
    12.           7584c5 8b 35 c0 47 85 00                      MOV                  ESI,dword ptr [68k_a0]
    13.           7584cb 8b 3d c8 47 85 00                      MOV                  EDI,dword ptr [68k_a1]
    14.           7584d1 66 89 77 46                            MOV                  word ptr [EDI + oya_adr],SI
    15.           7584d5 8b 46 0c                               MOV                  EAX,dword ptr [ESI + patbase]
    16.           7584d8 89 47 0c                               MOV                  dword ptr [EDI + patbase],EAX
    17.           7584db 66 8b 46 0a                            MOV                  AX,word ptr [ESI + sproffset]
    18.           7584df 66 89 47 0a                            MOV                  word ptr [EDI + sproffset],AX
    19.           7584e3 8b 45 00                               MOV                  EAX,dword ptr [EBP]
    20.           7584e6 83 c5 04                               ADD                  EBP,0x4
    21.           7584e9 89 07                                  MOV                  dword ptr [EDI],EAX
    22.           7584eb 88 4f 2c                               MOV                  byte ptr [EDI + userflag],CL
    23.           7584ee 66 8b 46 10                            MOV                  AX,word ptr [ESI + xposi]
    24.           7584f2 66 0f be 5d 00                         MOVSX                BX,byte ptr [EBP]
    25.           7584f7 45                                     INC                  EBP
    26.           7584f8 88 5f 42                               MOV                  byte ptr [EDI + 0x42],BL
    27.           7584fb 66 03 c3                               ADD                  AX,BX
    28.           7584fe 66 89 47 10                            MOV                  word ptr [EDI + xposi],AX
    29.           758502 66 8b 46 14                            MOV                  AX,word ptr [ESI + yposi]
    30.           758506 66 0f be 5d 00                         MOVSX                BX,byte ptr [EBP]
    31.           75850b 45                                     INC                  EBP
    32.           75850c 88 5f 43                               MOV                  byte ptr [EDI + 0x43],BL
    33.           75850f 66 03 c3                               ADD                  AX,BX
    34.           758512 66 89 47 14                            MOV                  word ptr [EDI + yposi],AX
    35.           758516 66 83 c1 02                            ADD                  CX,0x2
    36.           75851a 66 4a                                  DEC                  DX
    37.           75851c 75 a0                                  JNZ                  @@loop0
    38. @@ret
    39.           75851e 5d                                     POP                  EBP
    40.           75851f c3                                     RET
    41.  
    This, too, was copied and cleaned up from Ghidra, leaving in the address and binary data so you can see that some of the instructions were assembled differently.
    Code (Text):
    1.  
    2. set_act06
    3.           6ecd70 33 c0                                  XOR                  EAX,EAX
    4.           6ecd72 a3 ac 49 85 00                         MOV                  [68k_d2],EAX
    5.           6ecd77 8b 3d cc 47 85 00                      MOV                  EDI,dword ptr [68k_a2]
    6.           6ecd7d 66 8b 07                               MOV                  AX,word ptr [EDI]
    7.           6ecd80 83 c7 02                               ADD                  EDI,0x2
    8.           6ecd83 89 3d cc 47 85 00                      MOV                  dword ptr [68k_a2],EDI
    9.           6ecd89 66 a3 bc 49 85 00                      MOV                  [68k_d6],AX
    10. @@loop0
    11.           6ecd8f e8 24 eb d3 ff                         CALL                 actwkchk
    12.           6ecd94 0f 85 5a 01 00 00                      JNZ                  @@ret
    13.           6ecd9a 66 a1 c0 47 85 00                      MOV                  AX,[68k_a0]
    14.           6ecda0 8b 3d c8 47 85 00                      MOV                  EDI,dword ptr [68k_a1]
    15.           6ecda6 66 89 47 46                            MOV                  word ptr [EDI + oya_adr],AX
    16.           6ecdaa 8b 3d c0 47 85 00                      MOV                  EDI,dword ptr [68k_a0]
    17.           6ecdb0 8b 47 0c                               MOV                  EAX,dword ptr [EDI + patbase]
    18.           6ecdb3 8b 3d c8 47 85 00                      MOV                  EDI,dword ptr [68k_a1]
    19.           6ecdb9 89 47 0c                               MOV                  dword ptr [EDI + patbase],EAX
    20.           6ecdbc 8b 3d c0 47 85 00                      MOV                  EDI,dword ptr [68k_a0]
    21.           6ecdc2 66 8b 47 0a                            MOV                  AX,word ptr [EDI + sproffset]
    22.           6ecdc6 8b 3d c8 47 85 00                      MOV                  EDI,dword ptr [68k_a1]
    23.           6ecdcc 66 89 47 0a                            MOV                  word ptr [EDI + sproffset],AX
    24.           6ecdd0 8b 3d cc 47 85 00                      MOV                  EDI,dword ptr [68k_a2]
    25.           6ecdd6 8b 07                                  MOV                  EAX,dword ptr [EDI]
    26.           6ecdd8 83 c7 04                               ADD                  EDI,0x4
    27.           6ecddb 89 3d cc 47 85 00                      MOV                  dword ptr [68k_a2],EDI
    28.           6ecde1 8b 3d c8 47 85 00                      MOV                  EDI,dword ptr [68k_a1]
    29.           6ecde7 89 07                                  MOV                  dword ptr [EDI],EAX
    30.           6ecde9 a0 ac 49 85 00                         MOV                  AL,[68k_d2]
    31.           6ecdee 8b 3d c8 47 85 00                      MOV                  EDI,dword ptr [68k_a1]
    32.           6ecdf4 88 47 2c                               MOV                  byte ptr [EDI + userflag],AL
    33.           6ecdf7 8b 3d c0 47 85 00                      MOV                  EDI,dword ptr [68k_a0]
    34.           6ecdfd 66 8b 47 10                            MOV                  AX,word ptr [EDI + xposi]
    35.           6ece01 66 a3 a4 49 85 00                      MOV                  [68k_d0],AX
    36.           6ece07 8b 3d cc 47 85 00                      MOV                  EDI,dword ptr [68k_a2]
    37.           6ece0d 8a 07                                  MOV                  AL,byte ptr [EDI]
    38.           6ece0f 47                                     INC                  EDI
    39.           6ece10 89 3d cc 47 85 00                      MOV                  dword ptr [68k_a2],EDI
    40.           6ece16 a2 a8 49 85 00                         MOV                  [68k_d1],AL
    41.           6ece1b a0 a8 49 85 00                         MOV                  AL,[68k_d1]
    42.           6ece20 8b 3d c8 47 85 00                      MOV                  EDI,dword ptr [68k_a1]
    43.           6ece26 88 47 42                               MOV                  byte ptr [EDI + 0x42],AL
    44.           6ece29 a0 a8 49 85 00                         MOV                  AL,[68k_d1]
    45.           6ece2e 66 98                                  CBW
    46.           6ece30 66 a3 a8 49 85 00                      MOV                  [68k_d1],AX
    47.           6ece36 66 8b 1d a8 49 85 00                   MOV                  BX,word ptr [68k_d1]
    48.           6ece3d 66 a1 a4 49 85 00                      MOV                  AX,[68k_d0]
    49.           6ece43 66 03 c3                               ADD                  AX,BX
    50.           6ece46 66 a3 a4 49 85 00                      MOV                  [68k_d0],AX
    51.           6ece4c 66 a1 a4 49 85 00                      MOV                  AX,[68k_d0]
    52.           6ece52 8b 3d c8 47 85 00                      MOV                  EDI,dword ptr [68k_a1]
    53.           6ece58 66 89 47 10                            MOV                  word ptr [EDI + xposi],AX
    54.           6ece5c 8b 3d c0 47 85 00                      MOV                  EDI,dword ptr [68k_a0]
    55.           6ece62 66 8b 47 14                            MOV                  AX,word ptr [EDI + yposi]
    56.           6ece66 66 a3 a4 49 85 00                      MOV                  [68k_d0],AX
    57.           6ece6c 8b 3d cc 47 85 00                      MOV                  EDI,dword ptr [68k_a2]
    58.           6ece72 8a 07                                  MOV                  AL,byte ptr [EDI]
    59.           6ece74 47                                     INC                  EDI
    60.           6ece75 89 3d cc 47 85 00                      MOV                  dword ptr [68k_a2],EDI
    61.           6ece7b a2 a8 49 85 00                         MOV                  [68k_d1],AL
    62.           6ece80 a0 a8 49 85 00                         MOV                  AL,[68k_d1]
    63.           6ece85 8b 3d c8 47 85 00                      MOV                  EDI,dword ptr [68k_a1]
    64.           6ece8b 88 47 43                               MOV                  byte ptr [EDI + 0x43],AL
    65.           6ece8e a0 a8 49 85 00                         MOV                  AL,[68k_d1]
    66.           6ece93 66 98                                  CBW
    67.           6ece95 66 a3 a8 49 85 00                      MOV                  [68k_d1],AX
    68.           6ece9b 66 8b 1d a8 49 85 00                   MOV                  BX,word ptr [68k_d1]
    69.           6ecea2 66 a1 a4 49 85 00                      MOV                  AX,[68k_d0]
    70.           6ecea8 66 03 c3                               ADD                  AX,BX
    71.           6eceab 66 a3 a4 49 85 00                      MOV                  [68k_d0],AX
    72.           6eceb1 66 a1 a4 49 85 00                      MOV                  AX,[68k_d0]
    73.           6eceb7 8b 3d c8 47 85 00                      MOV                  EDI,dword ptr [68k_a1]
    74.           6ecebd 66 89 47 14                            MOV                  word ptr [EDI + yposi],AX
    75.           6ecec1 66 a1 ac 49 85 00                      MOV                  AX,[68k_d2]
    76.           6ecec7 66 05 02 00                            ADD                  AX,0x2
    77.           6ececb 66 a3 ac 49 85 00                      MOV                  [68k_d2],AX
    78.           6eced1 9c                                     PUSHFD
    79.           6eced2 66 a1 bc 49 85 00                      MOV                  AX,[68k_d6]
    80.           6eced8 66 48                                  DEC                  AX
    81.           6eceda 66 a3 bc 49 85 00                      MOV                  [68k_d6],AX
    82.           6ecee0 66 3d ff ff                            CMP                  AX,0xffff
    83.           6ecee4 74 06                                  JZ                   @@DBCA0059
    84.           6ecee6 9d                                     POPFD
    85.           6ecee7 e9 a3 fe ff ff                         JMP                  @@loop0
    86. @@DBCA0059
    87.           6eceec 9d                                     POPFD
    88. @@DBCC0059
    89.           6eceed 33 c0                                  XOR                  EAX,EAX
    90.           6eceef a3 a4 49 85 00                         MOV                  [68k_d0],EAX
    91. @@ret
    92.           6ecef4 c3                                     RET
    93.  

    So while the first subroutine seems to have been cleaned up somewhat, the seventh (or second, in this post) was not, resulting in things like 68K register simulation rather than using the x86 registers, as well as writing from writing from memory to a register... and then immediately writing from the same memory address to the same register. The optimized code does not have any debug symbol data... I wonder if the debug data was meant to indicate what code had yet to be cleaned up.
     
    • Like Like x 1
    • Informative Informative x 1
    • List
  16. BenoitRen

    BenoitRen

    Tech Member
    392
    178
    43
    Maybe I didn't use the correct search terms, but I only found a list on Sonic Retro where it was explained how to make an Action Replay code for Sonic 3.

    Hidden Palace seems to be part of Lava Reef Zone.
    Ah, I see! So a "dai" is a barrel, then?
    What exactly do you mean by debug symbol data? Is it something else than the labels? Because CreateChild7_Normal2 does fall within the range that there are labels for. But I can't tell you which it is yet, because I haven't gotten that far yet (I'm at the 74xxxx range).
     
  17. Brainulator

    Brainulator

    Regular garden-variety member Member
    Kind of. LRZ3 and HPZ are acts 1 and 2 of zone $16.
    "dai" seems to be a platform. Compare certain labels found in Sonic 2 Nick Arcade.
    I meant the labels, yes. CreateChild1_Normal is not within the range of the labels.
     
    • Informative Informative x 1
    • List
  18. BenoitRen

    BenoitRen

    Tech Member
    392
    178
    43
    I got the function name wrong. I meant CreateChild1_Normal, at address 0x007584ac. The debug info covers the range 0x006ebcb8 to 0x00820771.

    I'm attaching an export of my labelling work so far so no one else has to do it. It can be imported using the ImportSymbolsScript.py script included with Ghidra.

    EDIT: Export is obsolete. Find the last version in the first post.
     
    Last edited: Feb 29, 2024
  19. It's been a lifetime since I was studying computer science, but isn't this the norm? I remember one of my textbooks back in the day went so far as having the first chapter "Chapter 0" to really drive the point home.
     
    • Agree Agree x 5
    • Like Like x 1
    • List
  20. MainMemory

    MainMemory

    Kate the Wolf Tech Member
    4,741
    338
    63
    SonLVL
    These "cleaned up" functions were likely rewritten in C, with the debug data only covering the ASM parts, while the C portion was covered by a standard PDB file (which wasn't shipped with the game).
     
    • Like Like x 2
    • Informative Informative x 1
    • List