don't click here

Basic Questions & Answers thread

Discussion in 'Engineering & Reverse Engineering' started by Tweaker, May 29, 2008.

  1. flamewing

    flamewing

    Emerald Hunter Tech Member
    1,161
    68
    28
    France
    Sonic Classic Heroes; Sonic 2 Special Stage Editor; Sonic 3&K Heroes (on hold)
    Here, this should help (using constants from sonic3k.constants.asm when applicable):
    [68k]mainspr_childsprites = $16 ; amount of child sprites
    sub2_x_pos = $18 ;x_vel
    sub2_y_pos = $1A ;y_vel
    sub2_mapframe = $1D
    sub3_x_pos = $1E ;y_radius
    sub3_y_pos = $20 ;anim
    sub3_mapframe = $23 ;anim_frame

    Obj_HCZWaterSplash:
    tst.b subtype(a0)
    beq.s .watersplash
    move.l #Map_HCZWaterSplash2,mappings(a0)
    move.w #$36E,art_tile(a0)
    tst.b (Current_act).w
    beq.s .act1
    move.w #$344,art_tile(a0)

    .act1:
    ori.b #4,render_flags(a0) ; Use on-screen coordinates
    move.w #$300,priority(a0)
    move.b #$A0,width_pixels(a0)
    move.b #$80,height_pixels(a0)
    move.b #-1,objoff_31(a0)
    move.b #0,status(a0)
    bset #6,render_flags(a0) ; Make it a multi-sprite
    move.w #2,mainspr_childsprites(a0)
    lea sub2_x_pos(a0),a2
    move.w x_pos(a0),(a2)+ ; Position of 1st child, X...
    move.w y_pos(a0),(a2)+ ; ... and Y
    move.w #5,(a2)+ ; Mapping frame of 1st child
    move.w x_pos(a0),(a2)+ ; Position of 2nd child, X...
    move.w y_pos(a0),(a2)+ ; ... and Y
    move.w #$505,(a2)+ ; Mapping frames of main srite and 2nd child
    move.l #Obj_HCZWaterWalk,(a0)
    bra.w Obj_HCZWaterWalk
    ; ---------------------------------------------------------------------------
    .watersplash:
    move.l #Map_HCZWaterSplash,mappings(a0)
    move.w #$43B2,art_tile(a0)
    ori.b #4,render_flags(a0) ; Use on-screen coordinates
    move.w #$300,priority(a0)
    move.b #$28,width_pixels(a0)
    move.b #$20,height_pixels(a0)
    move.b #-1,objoff_30(a0)
    move.l #Obj_HCZWaterSplash_Main,(a0)

    Obj_HCZWaterSplash_Main:
    subq.b #1,anim_frame_timer(a0)
    bpl.s .timer_going
    move.b #7,anim_frame_timer(a0)
    addq.b #1,mapping_frame(a0)
    andi.b #3,mapping_frame(a0)

    .timer_going:
    tst.b render_flags(a0)
    bpl.s .chk_gone
    moveq #0,d1
    move.b mapping_frame(a0),d1
    cmp.b objoff_30(a0),d1
    beq.s .chk_gone
    move.b d1,objoff_30(a0)
    lsl.w #8,d1
    move.w d1,d0
    add.w d0,d0
    add.w d0,d1
    addi.l #ArtUnc_HCZWaterSplash,d1
    move.w #$7640,d2
    move.w #$180,d3
    jsr (Add_To_DMA_Queue).l

    .chk_gone:
    jmp (Sprite_OnScreen_Test).l
    ; ---------------------------------------------------------------------------
    ;loc_384B2
    Obj_HCZWaterWalk:
    move.w (Player_1+x_pos).w,x_pos(a0)
    move.w (Water_level).w,y_pos(a0)
    bsr.s Check_Water_Walk
    tst.b status(a0)
    beq.s .chk_art_dma
    move.b (Level_frame_counter+1).w,d0
    addq.b #2,d0
    andi.b #$F,d0
    bne.s .skip_snd
    moveq #$DB,d0
    jsr (Play_Sound_2).l

    .skip_snd:
    subq.b #1,anim_frame_timer(a0)
    bpl.s .chk_art_dma
    move.b #2,anim_frame_timer(a0)
    addq.b #1,objoff_30(a0)
    cmpi.b #5,objoff_30(a0)
    bcs.s .chk_art_dma
    move.b #0,objoff_30(a0)

    .chk_art_dma:
    moveq #0,d1
    move.b objoff_30(a0),d1
    cmp.b objoff_31(a0),d1
    beq.s .chk_gone
    move.b d1,objoff_31(a0)
    lsl.w #7,d1
    move.w d1,d0
    add.w d0,d0
    add.w d0,d1
    addi.l #ArtUnc_HCZWaterSplash2,d1
    move.w #$6DC0,d2
    tst.b (Current_act).w
    beq.s .got_vram_dest
    move.w #$6880,d2

    .got_vram_dest:
    move.w #$C0,d3
    jsr (Add_To_DMA_Queue).l

    .chk_gone:
    jmp (Sprite_OnScreen_Test).l

    ; =============== S U B R O U T I N E =======================================

    ;sub_38534
    Check_Water_Walk:
    lea (Player_1).w,a1
    lea sub2_x_pos(a0),a2
    moveq #3,d6
    move.w (Ctrl_1_logical).w,d5
    bsr.s Check_Water_Walk_1P
    bclr #0,render_flags(a0)
    btst #0,status(a1)
    beq.s .noflip
    bset #0,render_flags(a0)

    .noflip:
    lea (Player_2).w,a1
    lea sub3_x_pos(a0),a2
    moveq #4,d6
    move.w (Ctrl_2_logical).w,d5
    bsr.s Check_Water_Walk_1P
    move.b render_flags(a0),d0
    add.b status(a1),d0
    andi.b #1,d0
    beq.s .done
    move.b #5,sub2_mapframe-sub2_x_pos(a2)

    .done:
    rts
    ; End of function Check_Water_Walk


    ; =============== S U B R O U T I N E =======================================

    ;sub_3857E
    Check_Water_Walk_1P:
    btst d6,status(a0) ; Supporting player already?
    bne.s .already_walking_on_water ; Branch if yes
    tst.w y_vel(a1) ; Moving on Y?
    bne.s .no_water_walk ; Branch if yes
    moveq #0,d1
    move.b y_radius(a1),d1
    add.w y_pos(a1),d1
    addq.w #1,d1
    cmp.w (Water_level).w,d1 ; At the top of water?
    bne.s .no_water_walk ; Branch if not
    move.w x_vel(a1),d0
    bpl.s .pos_vx
    neg.w d0

    .pos_vx:
    cmpi.w #$700,d0 ; Moving faster than $700 subpixels/frame?
    bcs.s .no_water_walk ; Branch if not
    bset d6,status(a0) ; Start supporting player
    move.w x_pos(a1),(a2)
    move.w (Water_level).w,sub2_y_pos-sub2_x_pos(a2)
    move.b #0,sub2_mapframe-sub2_x_pos(a2)
    bclr #0,status(a1)
    tst.w x_vel(a1)
    bpl.s .no_water_walk
    bset #0,status(a1)

    .no_water_walk:
    rts
    ; ---------------------------------------------------------------------------
    .already_walking_on_water:
    move.w d5,d0
    andi.w #$70,d0 ; Pressing jump buttons?
    bne.s .do_jump ; Then jump!
    move.w (Water_level).w,d0
    moveq #0,d1
    move.b y_radius(a1),d1
    sub.w d1,d0
    subq.w #1,d0
    cmp.w y_pos(a1),d0 ; Not touching the top of the water?
    bhi.s .fall_through ; Branch if not (UNSIGNED comparison)
    move.w x_vel(a1),d1
    bpl.s .got_abs_vx
    neg.w d1

    .got_abs_vx:
    cmpi.w #$700,d1 ; Moving faster than $700 subpixels/frame?
    bcs.s .fall_through ; Branch if not
    move.w d0,y_pos(a1) ; Move to top of water
    move.w #0,y_vel(a1) ; Stop moving on Y
    move.w x_pos(a1),(a2)
    move.w (Water_level).w,sub2_y_pos-sub2_x_pos(a2)
    btst #1,status(a1)
    beq.s .done
    andi.w #$C00,d5 ; Holding left or right?
    bne.s .done ; Branch if yes
    move.w #$C,d1 ; Natural deceleration
    move.w x_vel(a1),d0 ; Not moving (redundant check)?
    beq.s .fall_through ; Branch if yes (never)
    bmi.s .going_left ; Branch if going left
    sub.w d1,d0 ; Decelerate
    bcc.s .set_vx
    move.w #0,d0 ; Clamp to 0

    .set_vx:
    move.w d0,x_vel(a1)
    bra.s .done
    ; ---------------------------------------------------------------------------
    .going_left:
    add.w d1,d0 ; Decelerate
    bcc.s .set_vx_2
    move.w #0,d0 ; Clamp to 0

    .set_vx_2:
    move.w d0,x_vel(a1)
    bra.s .done
    ; ---------------------------------------------------------------------------
    .fall_through:
    bclr d6,status(a0) ; Stop supporting player
    move.b #5,sub2_mapframe-sub2_x_pos(a2)

    .done:
    rts
    ; ---------------------------------------------------------------------------
    .do_jump:
    bclr d6,status(a0) ; Stop supporting player
    move.b #5,sub2_mapframe-sub2_x_pos(a2)
    move.w #-$680,y_vel(a1)
    bset #1,status(a1)
    move.b #1,jumping(a1)
    move.b #$E,y_radius(a1)
    move.b #7,x_radius(a1)
    move.b #2,anim(a1)
    bset #2,status(a1)
    rts
    ; End of function Check_Water_Walk_1P
    ; ---------------------------------------------------------------------------[/68k]


    Anyway: you need to have 0 y speed and be moving at 7 pixels/frame or more in order to be able to walk on water.

    But lets see your "fix": $FFFFB19E = $FFFFB172 + subtype. Setting it to nonzero generates a simple water splash, while it being zero is a water walking object. Your second fix works, but you have a permanently used, essentially useless object now. A better fix would be to delete the object after the initial subtype check, or even better: not create it to begin with.

    Edit: ufff... the visual editor has become useless due to the rampage of size=2 tags...

    Edit2: Added quote due to page break.
     
  2. Hitaxas

    Hitaxas

    Retro 80's themed Twitch streamer ( on hiatus) Member
    I was just doing what I did for testing purposes. Now that you've posted the code in that form, its much easier to understand. Thanks. :)

    I might be doing something with it at some point.
     
  3. Caverns 4

    Caverns 4

    Member
    346
    0
    16
    Sonic: Retold
    Okay, what I have here is not a question, as much as a complaint about the way the HG disassembly of Sonic 2 is, and a few really stupid things; Primarily regarding Hidden Palace leftovers being horribly mislabeled. It wouldn't take but a few minute to fix, and no one has done it with the fresh disassembles.

    To begin with, only SOME of Hidden Palaces leftover art tiles are at the bottom of the constants files. Because a bunch of crap is mislabeled. I'll start here:

    Code (Text):
    1. ArtTile_ArtNem_HPZOrb               = $0536
    Gee, that sure does look a lot like this...

    Code (Text):
    1. ArtTile_ArtNem_MtzLavaBubble        = $0536
    Oh, wait, that's because it's the SAME THING. ArtTile_ArtNem_HPZOrb and ArtTile_ArtNem_HPZ_Unk are backwards, that is to say, ArtTile_ArtNem_HPZOrb should be $035A. ArtTile_ArtNem_HPZ_Unk shouldn't even exist, because it's an error in itself - HPZOrb aand HPZUnk art used in Object 71, but what's called HPZUnk is actually HPZOrb! And the other art tile, which is currently called HPZOrb is actually ArtTile_ArtNem_MtzLavaBubble, being named incorrectly and thereby duplicated.This also means big confusion for people who don't know this nuace, and the last thing we need is the disassembly being confusing on top of Sonic 2 itself being tricky dicky.

    Now, there's more:
    Code (Text):
    1.     zoneOffsetTableEntry.w Animated_OOZ
    For zone $08, OOZ's animated code is referenced. Because OOZ's PLC is loaded in HPZ, this LOOKS like it makes sense, but it is infact, more misnomenclature, because if you look at the animated pointer for OOZ, you see this:

    Code (Text):
    1.     zoneOffsetTableEntry.w Animated_OOZ2
    OOZ2? That can't make sense, right? You're right it doesn't... Animated_OOZ2 is the REAL Animated_OOZ, and the first Animated_OOZ should be Animated_HPZ. But the problems don't end here either, lets look at the actual routine:

    Code (Text):
    1. ; word_4009C: Animated_HPZ:
    2. OOZ:    zoneanimstart
    3.     ; Pulsing ball from OOZ
    4.     zoneanimdecl 8, ArtUnc_OOZPulseBall, tiles_to_bytes(ArtTile_ArtUnc_OOZPulseBall_2), 6, 8
    5.     dc.b   0
    6.     dc.b   0
    7.     dc.b   8
    8.     dc.b $10
    9.     dc.b $10
    10.     dc.b   8
    11.     ; Pulsing ball from OOZ
    12.     zoneanimdecl 8, ArtUnc_OOZPulseBall, tiles_to_bytes(ArtTile_ArtUnc_OOZPulseBall_3), 6, 8
    13.     dc.b   8
    14.     dc.b $10
    15.     dc.b $10
    16.     dc.b   8
    17.     dc.b   0
    18.     dc.b   0
    19.     ; Pulsing ball from OOZ
    20.     zoneanimdecl 8, ArtUnc_OOZPulseBall, tiles_to_bytes(ArtTile_ArtUnc_OOZPulseBall_4), 6, 8
    21.     dc.b $10
    22.     dc.b   8
    23.     dc.b   0
    24.     dc.b   0
    25.     dc.b   8
    26.     dc.b $10
    27.  
    28.     zoneanimend
    ArtTile_ArtUnc_OOZPulseBall_2,3, and 4 are ALL misnamed. These belong to Hidden Palace Zone itself. And another thing:

    The art pointer to ArtUnc_OOZPulseBall is technically correct... But that's only so because the art for HPZ's orbs was removed. The label however, was probably not removed in the original code. It would make more sense to change the routine to point to ArtUnc_HPZPulseBall for the art, and have it as an empty label, likeso:

    Code (Text):
    1. ; Removed art
    2. ; the pulsing orb from HPZ was here in earlier builds, but since the art is gone, it's now just another pointer to ArtUnc_OOZPulseBall
    3. ArtUnc_HPZPulseBall:
    4. ;---------------------------------------------------------------------------------------
    5. ; Uncompressed art
    6. ; Pulsing ball in OOZ   ; ArtUnc_4BF7E:
    7. ArtUnc_OOZPulseBall:    BINCLUDE    "art/uncompressed/Pulsing ball (OOZ).bin"
    Having explained this, there is finally, one more thing that I can remember that bugs me:

    Code (Text):
    1.     levartptrs PLCID_Hpz1,  PLCID_Hpz2,     PalID_HPZ,  BM16_OOZ,   BM16_OOZ,  BM16_OOZ ;   8 ; HPZ  ; HIDDEN PALACE ZONE (UNUSED)
    Three pointers to BM16_OOZ? Well, of course. The first part of any level that is stored in the ROM is the 16x16 tiles. But again, should there not be empty pointers? Like this?

    Code (Text):
    1.  
    2. BM16_HPZ:
    3. ArtKos_HPZ:
    4. BM128_HPZ:
    5. ; OOZ 16x16 block mappings (Kosinski compression) ;The HPZ labels above are all blank, so they just point to this.
    6. BM16_OOZ:   BINCLUDE    "mappings/16x16/OOZ.bin"
    7. ;-----------------------------------------------------------------------------------
    All the labels were obviously still there in the final game, because they all end up pointing to one place, while other zone's that were removed early in development such as Wood Zone are like this:
    Code (Text):
    1. PalID_WZ,   ArtKos_EHZ, BM16_EHZ, BM128_EHZ ;   2 ; LEV2 ; LEVEL 2 (UNUSED)
    It can't be just me bothered by all these details right? Sure, some of these are minor and don't affect the bit-perfect status of the built ROM, but that's no excuse to not try to make the SCHG disassemblies as clear as sensibly possible! If I knew how to commit changes to the disassemblies through the correct means myself, I already would have, but I'm getting sick of these details getting overlooked, especially since some of them are pretty big deals.

    Also, APM_HPZ doesn't use the art tiles fore the background orbs like it should, that's an oversight in my opinion as well.
     
  4. Hitaxas

    Hitaxas

    Retro 80's themed Twitch streamer ( on hiatus) Member
    I'm curious about this little bit of the Obj_HCZWaterWalk object (referring to the version Flamewing posted):

    Code (ASM):
    1. .set_vx:
    2.         move.w    d0,x_vel(a1)       ; move d0 (0) into xvel of player
    3.         bra.s    .done
    4. ; ---------------------------------------------------------------------------
    5. .going_left:
    6.         add.w    d1,d0            ; Decelerate
    7.         bcc.s    .set_vx_2
    8.         move.w    #0,d0            ; Clamp to 0
    9.  
    10. .set_vx_2:
    11.         move.w    d0,x_vel(a1)     ; move d0 (0) into xvel
    12.         bra.s    .done
    13. ; ---------------------------------------------------------------------------
    14. .fall_through:  ; as it says, makes player fall in water
    15.         bclr    d6,status(a0)    ; Stop supporting player, clear object status 3 (onobject)
    16.         move.b    #5,sub2_mapframe-sub2_x_pos(a2)
    17.  
    18. .done:
    19.         rts
    20. ; ---------------------------------------------------------------------------
    At .set_vx and .set_vx_2, is the branch to .done necessary? Couldn't you just replace the branches with an rts and call it a day? Or does it really not matter since the branch is so short?

    Not that I see it as a big deal, just wondering why it was done the way it was.
     
  5. flamewing

    flamewing

    Emerald Hunter Tech Member
    1,161
    68
    28
    France
    Sonic Classic Heroes; Sonic 2 Special Stage Editor; Sonic 3&K Heroes (on hold)
    Two words: "pull request".

    Seriously: if instead of complaining about these errors you had spent this time writing a pull request and submitting it on Github, it might have been merged already. But you chose to complain instead of being proactive, go figure.

    Now, the clue-by-4: people (of which hackers are a subset) aren't omniscient, and contrary to what seem to be your expectations, they have lives outside of hacking (or analyzing disassemblies, as is the case here). The people that have contributed with analysis generally do not obsessively go over every line until it is perfect; they do some basic analysis aiming for coverage, reach possibly wrong conclusions and move on to other areas of the code. Eventually, they (or someone else) perform a more in-depth analysis of some of those areas (based on free time and/or necessity), notice the mistakes and contributes a correction. And this is a good thing: there are 95724 lines in asm files for the S2 disassembly at present; if the people that analysed were aiming for perfection at first try, the disassembly would be perfect in the first half, and nonexistant on the second half. Or some other appropriate fraction.

    So: complain less; make more pull requests.

    Yes, you can replace them with an rts; and yiu would gain 10 cycles on that code path. I can only guess why they didn't.
     
  6. Caverns 4

    Caverns 4

    Member
    346
    0
    16
    Sonic: Retold
    As I said in the post, I had no idea how to have a change made officially, since I honestly don't know anything about Github. With that said, bring the details of that to someone's attention were the best way I knew of at the time to makes my statements noticed.

    Of course, I wondered why your response had so much ill emotion it, so I looked at what I aside again in the first place.

    After rereading my post, I can see how did sound like I was being critical (albeit unintentionally), so let me clarify; I did not mean to insult or put down those who worked on the original disassembly, nor did I intend to come off as demanding. I simply knew about a few issues that I wanted to see addressed. And I don't expect everything to be perfect, we all make mistakes. So for coming off as an asshole like I did, I apologize.

    I'll look into it and try this pull request thing tomorrow.
     
  7. Clownacy

    Clownacy

    Tech Member
    1,093
    666
    93
    Hey, I thought I already fixed that like a month ago!

    EDIT: Hello from the 10th of June

    Now, if you're gonna be like that, I should also tell you that this is a non-issue now. You were right, there were some hardcoded RAM addresses. It looks like it was looked over during the equating process because a search-and-replace wouldn't cover these instances.
     
  8. flamewing

    flamewing

    Emerald Hunter Tech Member
    1,161
    68
    28
    France
    Sonic Classic Heroes; Sonic 2 Special Stage Editor; Sonic 3&K Heroes (on hold)
    Regarding pull requests: the first post of this pinned thread has links that explain everything.
     
  9. Caverns 4

    Caverns 4

    Member
    346
    0
    16
    Sonic: Retold
    Most of the time, the first thing I do is update my stuff. Stupid me, I didn't actually think to check for an update before I said anything (since my last update was a while back), obviously. Lesson learned.

    Thank you both of you.
     
  10. RetroKoH

    RetroKoH

    Member
    1,707
    74
    28
    S1Fixed: A successor to ReadySonic
    Open question to all who use sprite editors, what DPLC editing related functions would you like to see in a Sprite Editor?
     
  11. FireRat

    FireRat

    Nah. Fuck it. Banned
    48
    10
    8
    Chile
    Mobius Evolution 2
    I'm answering here to avoid keeping off-topic in the other post...

    Although this isn't completely DPLC-related, would it be possible to do some simple VRAM emulation, allowing multiple files to be loaded? Not only would help to decide whether or not to use DPLC under certain circumstances (you know, DPLC's main cons are the lag it takes to draw or their ROM space),but it would come really handful in situations like this:

    [​IMG]
     
  12. RetroKoH

    RetroKoH

    Member
    1,707
    74
    28
    S1Fixed: A successor to ReadySonic
    Well, I'm not 100 sure what you mean exactly by VRAM emulation... Or what you'd want that to entail... But Triad can load VRAM dumps directly, AND can load other tile sets into the current tileset being viewed.

    Unless you're talking about a simulator/VRAM sandbox to test out your PLCs and stuff like that, seeing if you can make them all fit... Really you can essentially do that in the sprite editor but if enough people want a REAL VRAM simulation testing tool I can implement a stand-alone one.
     
  13. MainMemory

    MainMemory

    Kate the Wolf Tech Member
    4,785
    365
    63
    SonLVL
    What he wants is like how SonLVL loads art for objects, with multiple files loaded at various locations within a virtual VRAM space, like the 1up monitor and DEZ Eggman in Sonic 2 that have art broken into pieces.
     
  14. RetroKoH

    RetroKoH

    Member
    1,707
    74
    28
    S1Fixed: A successor to ReadySonic
    Gotcha! I think the current features in the Sprite editor SHOULD satisfy this request. But do try it out when it's ready and I'll tweak it and improve it.
     
  15. AkumaYin

    AkumaYin

    Member
    286
    6
    18
    Okay, so I've been using SMPS2ASM with a Sonic 1 disassembly to make music ports lately, and I'm trying to do Angel Island Act 1. I've fixed up the PSG and DAC, but this is a song that uses Sonic 3's UVB. So, I copy-pasta'd it from the Clone Driver v2 to the end of the song, but it still sounds totally messed up. Is there something I need to do to remove its dependency on the UVB and make it actually read from its own instrument table?
     
  16. Clownacy

    Clownacy

    Tech Member
    1,093
    666
    93
    Did you make the song actually point to the copy of the UVB at the end of the song? It shouldn't be messed up if you did as you said. At least, I don't think it should.

    To answer your question: There is no dependency outside of SMPS2ASM's smpsHeaderVoiceUVB. Switch that to a smpsHeaderVoice and you should be good to go. The only thing that differs a UVB song from a normal song is the goofy voice pointer. Once you put the UVB at the song's end and changed the pointer, you should be good to go, but it is awfully inefficient; it'd be worth trying to remove the unused voices. Look for the Voice Change commands (smpsSetvoice), and note the numbered IDs listed by them. Those are the IDs of the voices from the UVB that you want to keep. Once you have all the IDs noted, go through the UVB and copy the voices whose IDs matches those of the commands to the end of your song. After that, begin changing the Voice Change commands to match the new list of voices.

    I want to say that backporting the Clone V2 to S1 is easy, but you've really got to know what you're doing. It requires a lot of code restoration, and even the relocating of the flag sound slots. Boo...

    EDIT: Quoted due to page break
     
  17. redquebec

    redquebec

    Member
    39
    0
    6
    A basic question, but interesting. How far could we trust the ROM Headers? I recently tried to organize a lot of beta roms, and I try to rely on the date included in the rom headers. It seems correct, building up chronologically.

    Is it true for released Genesis games? Here are the info from the last official No-Intro romset, the date in header, and the release date:
    Sonic The Hedgehog Apr-91 4M 23-Jun-91
    Sonic The Hedgehog 2 Sep-92 8M 21-Nov-92
    Sonic The Hedgehog 3 Nov-93 16M 02-Feb-94
    Sonic & Knuckles Jun-94 16M 18-Oct-94

    If the infos are correct, that means they were ready to deliver way ahead their sales. Does that seemed correct? Was Sonic 3 really completed by November 1993? How are the build date generated at first? At compile time or was it a manual entry?
     
  18. OKei

    OKei

    OKeijiDragon Member
    1,511
    71
    28
    There would always be that large gap of time between the game actually finalized and the game actually reaching store shelfs, especially in the 8-bit and 16-bit eras. Game cartridges always had to take a lot of time and money to assemble and manufacture before being shipped to retailers. Normally, game carts would take up to two or three months to manufacture (depending on the amount of units the game publisher had ordered), and so developers had to finish a game before the deadline line given by publisher to be sent the master ROM to Nintendo or Sega to produce the carts. For high profile, mass-produced games as those four Sonic titles, those dates seem just about right. I'm no expert so I could be totally wrong though. + - But I don't think so. =)  

    I've never seen those ROM header completion dates before though, and I didn't know there could be dates attached to cartridge-based ROMs in their headers (I too would like to know how these dates are generated). The Sonic 2 date does ring a bell as the last known proto for that game was dated September 24, 1992. And come to think of it, S&K's last known proto was dated June 19, 1994 too.
     
  19. Clownacy

    Clownacy

    Tech Member
    1,093
    666
    93
    A while ago I read somewhere that multiplying a register by a multiple of 2 is best left to add, instead of a bit-shift, but only with words or longwords. So 'add.w d0,d0' is faster than 'lsl.w #1,d0'. Is there any truth to this?
     
  20. FraGag

    FraGag

    Tech Member
    The answer to this is in the M68000 User's Manual, which lists (in sections 7 to 9) the number of clock periods each instruction takes to execute. We shall look at section 8, because as far as I know, the processor in the MD/Genesis operates in 16-bit mode.

    We can see, for example, that ADD.W <ea>,Dn takes 4 clock periods, including 1 read cycle*, plus the effective address calculation time (table 8-4, page 8-4). The effective address calculation times are listed in table 8-1 (page 8-2). The calculation time for Dn is 0 clock periods, so it has no additional cost over the instruction's base execution time. Therefore, add.w d0,d0 simply takes 4 clock periods to execute.

    We can also see that LSL.W to a register takes 6+2n clock periods (where n is the shift count), including 1 read cycle*. Therefore, lsl.w #1,d0 takes 8 clock periods to execute, which is more than add.w d0,d0 takes.

    Likewise, it's faster to perform 2 adds than to LSL by 2: 2 add.w d0,d0 instructions take 8 clock periods to execute, while one lsl.w #2,d0 instruction takes 10 clock periods to execute. If we want to shift by 3, then it's equivalent: 3 adds takes 12 clock periods, and lsl.w #3,d0 also takes 12 clock periods. Shifting by more than 3 is faster with LSL than with a sequence of adds.

    * At the very start of section 8, the manual states:
    I don't know if the memory cycle on the MD/Genesis is in fact 4 clock periods, but in general, you'll want to minimize the number of reads and writes if you can. :)