don't click here

ASM Sonic CD (1993) Disassembly by Devon (and Other Things)

Discussion in 'Engineering & Reverse Engineering' started by Alex Field, Jun 9, 2022.

  1. Devon

    Devon

    I'm a loser, baby, so why don't you kill me? Tech Member
    1,248
    1,419
    93
    your mom
    Okay, so the problem lied with how IDA 6.8 interpreted branching instructions compared to IDA 7.7. 6.8 actually just refers to those instructions as "db", "b", "bra", or "bsr", but IDA 7.7 actually uses the full instruction names, with the size. IDA 7.7 also expands the addresses that are stored as words into 24 bits instead of 32 bits, like in earlier versions.

    I have pushed another update, and have confirmed it to work in both 6.8 and 7.7 now.
     
  2. OrionNavattan

    OrionNavattan

    Tech Member
    166
    164
    43
    Oregon
    Script is working correctly now in IDA 7.6. Thank you :>
     
  3. OrionNavattan

    OrionNavattan

    Tech Member
    166
    164
    43
    Oregon
    The script has some sort of issue with the animal objects in R33C and R33D: it hangs when it reaches those objects in the files. (Removing the lines that makes it analyze the animal object allows the script to finish the rest of the file successfully.)
     
    Last edited: May 15, 2023
  4. Devon

    Devon

    I'm a loser, baby, so why don't you kill me? Tech Member
    1,248
    1,419
    93
    your mom
    @OrionNavattan
    I have tracked down the issue. Turns out there's an animation used by the exit barrier in the CCZ boss in which it doesn't have a flag at the end of the data. As a result, it kept continuing to erroneously parse the animation past the end of it, which busted the area where the animal object was at, preventing it from being properly disassembled.
    Code (Text):
    1. Ani_20EA86:dc.w @Ani_20EA86_0-*
    2. @Ani_20EA86_0:dc.b 0
    3.         dc.b 0, 1, 2, 3, 4, 5, 6, 7, 7

    [​IMG]
    The reason this animation is like this is because the object itself manually checks which frame it's on before stopping it, meaning the flag isn't really needed.

    I have modified the script that takes this into account. Do let me know if you find any other issues with it running.
     
    Last edited: May 15, 2023
    • Like Like x 3
    • Informative Informative x 1
    • List
  5. OrionNavattan

    OrionNavattan

    Tech Member
    166
    164
    43
    Oregon
    Obviously whoever programmed that didn't know about the animation script flags that could take care of stopping it. But then again, given the baffling and idiotic code I've glimpsed elsewhere (subroutines consisting of ONE LINE?) and the overall impression that the developers were unfamiliar with the engine, and in some cases even the standard libraries, I guess I shouldn't be surprised.

    Anyhow, added the fix to my script (I've modified it to use labels matching Hivebrain's S1 disasm), and it works now. There is one other issue I might as well report:in some but not all MMDs, it doesn't delete the raw chunk data, leaving it all dc.b'ed in the exported ASM after the script-generated incbin. I personally haven't consider this to be too significant of an issue since I'm mainly after the code, but I suspect others might not think the same.
     
  6. Devon

    Devon

    I'm a loser, baby, so why don't you kill me? Tech Member
    1,248
    1,419
    93
    your mom
    Could you tell me which MMDs do that?
     
  7. OrionNavattan

    OrionNavattan

    Tech Member
    166
    164
    43
    Oregon
    Well, as it turns out, the problem is not with your script, but rather some sort of mistake I made while modifying it to output different labels. (Curiously, it only seems to affect PPZ Acts 1 and 2, though I haven't gotten anywhere near close to trying all the MMDs.) I'm going to leave it be, since it doesn't really impact what I'm doing, and I can just fall back to the unmodified script if I need to look at the data store area. (And there may be a better way to replace the labels by using a script in my editor.)

    That said, I have found a couple of bugs in the unmodified script:
    R11C generates following error: 23B89E: can't rename byte as 'Art_Flower' because the name is already used in the program.

    R11D generates following error: 3A8F2: can't rename byte as 'Art_Flower' because the name is already used in the program.

    R31A: generates following errors:
    20B4B4: can't rename byte as '@Ani_20B4AA_1' because this byte can't have a name (it is a tail byte).
    20B4B7: can't rename byte as '@Ani_20B4AA_2' because this byte can't have a name (it is a tail byte).

    Raw data is left at Art_TitleCardText, unk_2358CA, and unk_235A7A.

    For EVERY MMD, the final bit of ChkObjOnScrWidth:
    Code (ASM):
    1.  
    2. .OffScreen:
    3.    moveq   #1,d0               ; Mark as offscreen
    4.    rts
    5.  
    is not disassembled at all, instead being rendered as
    Code (ASM):
    1.  
    2. dword_20xxxx:
    3.    dc.l $70014E75
    4.  
     
  8. Devon

    Devon

    I'm a loser, baby, so why don't you kill me? Tech Member
    1,248
    1,419
    93
    your mom
    @OrionNavattan Fixed R11C and R11D (accidentally left in a definition for Art_Flower that was found inside the padding data made up of leftover garbage data). Fixed the animation in R31A (was another case of animations without ending flags). unk_2358CA and unk_235A7A were also animations for the Kama-Kama badnik that were left uncaught. Put in a quick fix for that by catching it from the Kama-Kama object code. The issue with ChkObjOnScrWidth was with UpdateObjects referencing the object table 4 bytes before the start of it (so that ID 1 actually points to the first actual object entry). Got that fixed.

    The raw data at Art_TitleCardText is actually unused data AFTER the title card text graphics. I'm gonna leave it as is for now, because I'm actually running short on free time (I travel out of the country tomorrow), but just keep that in mind.

    I went ahead and also made it parse the debug table for any uncaught mappings data as well. Hopefully that works okay.

    Download
     
  9. BenoitRen

    BenoitRen

    Tech Member
    409
    183
    43
    I'm curious what the code for a random number looks like in the Mega CD version, because the PC port has the following weird implementation:
    Code (Text):
    1.  
    2. int random()
    3. {
    4.   int_union lD0;
    5.   int_union lD1;
    6.   unsigned short w;
    7.   lD0.l = ranum;
    8.   if (ranum == 0) {
    9.     lD0.l = 10861 | 13914;
    10.   }
    11.   lD1 = lD0;
    12.   if (lD0.l < 0) {
    13.     lD0.l = lD0.l << 2;
    14.     lD0.l |= -32768;
    15.   }
    16.   else {
    17.     lD0.l = lD0.l << 2;
    18.   }
    19.   lD0.l += lD1.l;
    20.   if (lD0.l < 0) {
    21.     lD0.l = lD0.l << 3;
    22.     lD0.l |= -32768;
    23.   }
    24.   else {
    25.     lD0.l = lD0.l << 3;
    26.   }
    27.   lD0.l += lD1.l;
    28.   lD1.w.l += lD0.w.l;
    29.   w = lD0.w.h;
    30.   lD0.w.h = lD0.w.l;
    31.   lD0.w.l = w;
    32.   lD1.w.l += lD0.w.l;
    33.   lD0.w.l = lD1.w.l;
    34.   w = lD0.w.h;
    35.   lD0.w.h = lD0.w.l;
    36.   lD0.w.l = w;
    37.   ranum = lD0.l;
    38.   return lD1.l;
    39. }
     
  10. OrionNavattan

    OrionNavattan

    Tech Member
    166
    164
    43
    Oregon
    The Mega CD version uses the same psuedorandom number routine as Sonic 1, 2 and 3K (it even uses the same initial seed), although curiously, every instance of it except for the one in the Time Warp Cutscene MMD take the precaution to avoid trashing d1.

    Code (ASM):
    1.  
    2. ; Modified from my Sonic 2 disasm, but this what nearly every instance of
    3. ; this subroutine in Sonic CD looks like.
    4. RandomNumber:
    5.        move.l   d1,-(sp)            
    6.        move.l   (v_random).w,d1
    7.        bne.s   .scramble               ; if d1 is not 0, branch
    8.        move.l   #$2A6D365A,d1               ; if d1 is 0, use this seed number
    9.  
    10.    .scramble:
    11.        ; set the high word of d0 to be the high word of the RNG
    12.        ; and multiply the RNG by 41        
    13.        move.l   d1,d0
    14.        asl.l   #2,d1
    15.        add.l   d0,d1
    16.        asl.l   #3,d1
    17.        add.l   d0,d1
    18.      
    19.        ; add the low word of the RNG to the high word of the RNG
    20.        ; and set the low word of d0 to be the result
    21.        move.w   d1,d0
    22.        swap   d1
    23.        add.w   d1,d0
    24.        move.w   d0,d1
    25.        swap   d1
    26.      
    27.        move.l   d1,(v_random).w
    28.        move.l   (sp)+,d1
    29.  
     
  11. Devon

    Devon

    I'm a loser, baby, so why don't you kill me? Tech Member
    1,248
    1,419
    93
    your mom
    As a side note with the routine, it seems to just be a stock Sega RNG function, because I've seen it in other games.
     
  12. BenoitRen

    BenoitRen

    Tech Member
    409
    183
    43
    I see the C version does the same thing, but adds separate logic for negative numbers. Fascinating!
     
  13. Brainulator

    Brainulator

    Regular garden-variety member Member
    I'm curious: which ones?
     
  14. Devon

    Devon

    I'm a loser, baby, so why don't you kill me? Tech Member
    1,248
    1,419
    93
    your mom
    Minor update to the IDA script. Debug item index count reading was a little bugged.