don't click here

Some changes/fixes for Sonic 1

Discussion in 'Engineering & Reverse Engineering' started by RetroKoH, Sep 4, 2012.

  1. Kilo

    Kilo

    Starting new projects every week Tech Member
    1,231
    1,177
    93
    Canada
    Changes with the weather
    Getting Started With V30 Mode for PAL
    This targets the Hivebrain 2005 disassembly, but if you're a smart cookie you can port it to other disasms and games. :)
    So as most know, the PAL Mega Drive has the capacity to have a taller resolution, rather than being stuck with 28 tiles vertically, you can have 30 tiles vertically. Unfortunately, the Sonic games don't take advantage of it. I'll show you how to change that, and how to adjust level rendering for it.
    Head on down to VDPSetupGame, in which we'll see:
    Code (Text):
    1.         move.w    (VDPSetupArray+2).l,d0
    2.         move.w    d0,($FFFFF60C).w
    This caches a 'default' setup for VDP register mode 2, for future use.
    Let's look at mode 2's flags:
    Code (Text):
    1. 0|DISP|VINT|DMA|V30|1|0|0
    We've got flags to enable the display, vertical interrupts, DMA operations, and our target V30 mode in bit 3.
    So between the 2 lines above, insert this to enable it:
    Code (Text):
    1.         btst    #6,($FFFFFFF8).w    ; Is this a PAL console?
    2.         beq.s    @UseV28                ; If not, skip
    3.         bset    #3,d0
    4.  
    5. @UseV28:
    Scrolling isn't equipped for this extra height, though, so we have to fix it.
    The first step to doing this is correcting the DMAs that send the horizontal scroll buffer to VRAM at V-Int (And note this will add on an extra $20 bytes being used by the horizontal scroll buffer, $CC00, but if you read the wiki then you should've been keeping this area free anyway in the event of an overflow). The line we're looking at in particular is this:
    Code (Text):
    1. move.l    #$940193C0,(a5)
    This is 2 VDP registers being set mashed into 1. It sets the length of the DMA operation that it needs to do. Right now it's 940193C0 or $1C0, which in decimal is 448, the Mega Drive's regular vertical resolution times 2 for the foreground and background planes. What we need to do is obvious, a quick PAL check, and if it passes, make the length longer, to $1E0 to be precise. So underneath the above line (of which there are 5 instances of) insert:
    Code (Text):
    1.         btst    #6,($FFFFFFF8).w    ; Is this a PAL console?
    2.         beq.s    @V28                ; If not, skip
    3.         move.w    #$93E0,(a5)            ; We only need to re-set the lower byte, we already set the upper byte and it doesn't need to be chaged.
    4.  
    5. @V28:
    So now our lower 16 pixels scroll with the screen. Next, we have to fix vertical tile reloading, since it starts from Y -1 on a grid of 16x16 blocks. But now that we've extended the screen, we can see that -1 block. So to fix this, we need to tinker with LoadTilesAsYouMove a bit.
    Now there's quite a bit we need to change, and adding checks all over the place would not be the smartest thing to do, seeing as tile redrawing is one of the more computationally intense parts of the engine. So let's instead create 2 variables, one for the screen's vertical resolution, and another for the starting Y position in which we'll be drawing:
    Code (Text):
    1. screenheight = $FFFFFFC4
    2. yblockstart = $FFFFFFC6
    You're welcome to change the exact RAM location, as long as you have 4 words. Though, I'd suggest keeping it in an area that doesn't get reset upon level end. We'll head back to VDPSetupGame, and under the label place:
    Code (Text):
    1.         move.w    #224,(screenheight).w
    2.         move.w    #-16,(yblockstart).w
    And underneath our PAL check before the @UseV28 label insert:
    Code (Text):
    1.         move.w    #240,(screenheight).w
    2.         move.w    #0,(yblockstart).w
    Alright, now we can go about changing the redraw code itself. We go to LoadTilesAsYouMove
    We're going to be modifying each instance of
    Code (Text):
    1.         moveq    #-$10,d4
    and
    Code (Text):
    1.         move.w    #$E0,d4
    Replacing them with
    Code (Text):
    1.         move.w    (yblockstart).w,d4
    and
    Code (Text):
    1.         move.w    (screenheight).w,d4
    Respectively.
    Our final step is modifying the deformation routines. While we now take more data from the horizontal scroll buffer to DMA into VRAM, we're currently not writing anything to those extra $20 bytes in the buffer. So we have to go through each zone's deform routine, do a PAL check, and extend the dbf loop by 16.
    Generally, each zone uses d1 as it's counter, so we can drop this before each loop:
    Code (Text):
    1.         btst    #6,($FFFFFFF8).w    ; Is this a PAL console?
    2.         beq.s    @V28                ; If not, skip.
    3.         addi.b    #16,d1                ; Scroll an extra 16 pixels.
    4.  
    5. @V28:
    Note for GHZ, you'll want to place this before loc_6384.
    Star Light Zone's a bit more complicated, and I unfortunately don't have the time to sort it out right now, so if someone would like to tackle that below me, be my guest. But by now you should have:
    blastem_20241226_121348.png

    This concludes my end of getting you started with V30 mode. There's still a lot that needs to be done to fully utilize V30. Parallax is a little broken, CRAM dots appear at line 224 when water takes up the full screen, everything in general is about 8 pixels too high. But I leave that up to you to figure out, and I hope to see some hacks with V30 support down the road.
     
  2. Something that was brought up on the Hacking Contest Discord server while I was implementing this. The game is programmed to waste a ton of cycles when in PAL mode, which they suggested was done to stall the extra scanlines if it was still displaying in 320x224. Is this true? If not, what is it meant to do?
     
  3. vladikcomper

    vladikcomper

    Tech Member
    215
    195
    43
    Sonic Warped
    This cycle waster is there to merely hide CRAM dots, because in V28 mode (224-pixel vertical resolution) there are visible borders on PAL. Due to a hardware bug, VDP outputs wrong pixels whenever you transfer palettes to CRAM (it displays colors currently transferred instead of actual underlying pixels) and Sonic games transfer palettes at the very beginning of VBlank.

    You don't really need this in V30 mode (240-pixel vertical resolution) because vertical interrupt occurs on line 240 instead of 224 in this case (and the whole point of that operation is to wait until line 240). For instance, I completely removed cycle waster in my own hacks the implemented 240p display (like Sonic 1 Blastless and Sonic 1: 50Hz=60Hz) and there were no visible dots on real hardware.

    And to be completely fair, there are smarter ways to hide CRAM dots in PAL even if you don't use V30 mode. Instead of wasting CPU cycles because you wanted to delay a palette transfer, you can just do other transfers first like sprites, HSRAM; this should waste enough time already or reduce time wasted at the very least (but this obviously requires more careful timing and you should be careful with lag frames which avoid any updates generally).
     
    • Like Like x 2
    • Agree Agree x 1
    • List
  4. MarkeyJester

    MarkeyJester

    Original, No substitute Resident Jester
    2,254
    516
    93
    Japan
    As a bit of a side note, it doesn't just hide the colour dots, it hides the backdrop colour change on the bottom boarder too, which would show one frame ahead than intended:

    upload_2024-12-30_19-5-50.png

    ...which is surprisingly noticeable, especially in video motion, and especially during fade sequences.
     
    • Like Like x 3
    • Agree Agree x 1
    • Informative Informative x 1
    • List