Load 16x16 Blocks From ROM Instead of RAM (Sonic 1, GitHub)

Discussion in 'Tutorials' started by Filter, Dec 22, 2022.

  1. Filter

    Filter Active Member Member

    Joined:
    Jul 28, 2021
    Messages:
    27
    Location:
    Canada
    EDIT(2): Fixed a mistype.

    EDIT: Newer, much cleaner method has been added to replace the old one.

    So quite recently I was looking at the tutorial for making chunks in Sonic 1 load from ROM instead of RAM, which was smart but it was only made for Green Hill Zone and nowhere else. So I came up with an idea that branched from there, what if we loaded blocks without RAM and instead loaded them from ROM? Well, let's dive in.

    How Much RAM Gets Freed
    Considering that in Sonic 1 blocks are normally loaded from LevelHeaders and then decompressed from Enigma, the estimated RAM you will be freeing is shown below.
    Code:
    v_16x16 RAM Usage = $1FFF
    Code:
    v_16x16 RAM Usage (after the guide has been followed) = 4
    Yeah, that's a lot of RAM freed. There's enough RAM there to import a lot of things into your hacks.

    Installation
    So first we want to decompress the blocks, firstly go ahead and grab FW-KENSC and once that's done installing then go into the folder labelled map16 and select all files in there. Now right click and decompress all the files from Enigma (if you aren't using Enigma in your hack, then use the compression you used to decompress it). Once that is complete, you should be left with *.unc files left in the folder and you can go ahead and delete the other files. Remember to go into your main assembly file (sonic.asm) and fix the pointers to the contents in map16 to point to the uncompressed ones.

    Now that the blocks are uncompressed, it's time to make them load! But first, we need to make sure they aren't being decompressed because since they don't have a compression, it's just gonna execute garbage code. So go to LevelDataLoad and change this:
    Code:
            movea.l    (a2)+,a0
            lea    (v_16x16).w,a1    ; RAM address for 16x16 mappings
            move.w    #0,d0
            bsr.w    EniDec
    To this:
    Code:
            move.l    (a2)+,(v_16x16).w
    There, that should do it. Now what this does is that it moves the blocks to a RAM address, although you might think this takes up the same amount of RAM, but it only takes up 4 bytes.

    Here's the part where we actually load the blocks, go to GetBlockData and change this:
    Code:
            lea    (v_16x16).w,a1
    With this:
    Code:
            movea.l    (v_16x16).w,a1
    Instead of doing what the compressed data does and makes it lea to a1, we are gonna move it into a1 using longword (4 bytes).

    We're almost done here, but you might have noticed that the title screen loads it's blocks as a complete mess! To fix this, go to Tit_LoadText and replace this:
    Code:
            lea    (v_16x16).w,a1
            lea    (Blk16_GHZ).l,a0 ; load    GHZ 16x16 mappings
            move.w    #0,d0
            bsr.w    EniDec
    With this:
    Code:
            move.l    #Blk16_GHZ,(v_16x16).w
    There we go! You have just freed a lot of RAM, perhaps now with all that free RAM you could port a few things, like Kosinski Moduled, or anything you really want to have in your hacks. Hopefully you find this tutorial useful, no credit is required but it would be appreciated if used.
     
    Last edited: Mar 13, 2023
    ProjectFM, MrLordSith and DeltaW like this.
  2. Devon

    Devon La mer va embrassé moi et délivré moi lakay. Member

    Joined:
    Aug 26, 2013
    Messages:
    1,412
    Location:
    your mom
    Your guide has a flaw in it that prevents it from working 100%, and it has to do with this tidbit of code:
    Code:
            move.w  (v_zone).w,d0
            lsl.w   #2,d0 ; change this to lsr.w   #6,d0 if using 128x128 chunks
            move.l    BlockList(pc,d0.w),a1
    "BlockList" only has 1 entry per zone, and yet, you are using both the zone and act IDs to calculate the index of it by reading a word. As a result, Green Hill Act 2 ($0001) will load Labyrinth's blocks, and zone past Green Hill will try to load a pointer past the table (i.e. Labyrinth Act 1's zone/act ID is $0100, which is not valid for the table). To fix that, you need to change the first line to
    Code:
            moveq    #0,d0
            move.b    (v_zone).w,d0
    Which will clear d0 to prevent trash data from messing with it, and then just loading the zone ID. Also, for REV01, make sure that this is placed under GetBlockData_2 instead, or it'll get skipped whenever GetBlockData_2 gets called instead.

    Make sure you test beyond Green Hill Act 1 for stuff like this.
     
    ProjectFM likes this.
  3. Filter

    Filter Active Member Member

    Joined:
    Jul 28, 2021
    Messages:
    27
    Location:
    Canada
    Thanks, oddly enough this problem never occurred for me, even with the code the way it was. Anyways, thanks for doing this.
     
  4. JGamer2151

    JGamer2151 Well-Known Member/Lurker Member

    Joined:
    Dec 1, 2020
    Messages:
    100
    I do like the fact that you can now load 16x16 blocks for every level in ROM; I just wish that the same can be done for the 256x256/128x128 chunks as well, as the chunks for all levels can also be loaded into ROM alongside with the blocks (assuming you have enough ROM space). If only the chunks guide on the Retro SCHG How-to page can be updated to expand to all levels as opposed to just GHZ (the guide only uses GHZ as an example of how to use uncompressed chunks, as I think the guide expects those with enough care can adapt the code for GHZ to other levels)…

    Aside from that, this guide would also benefit Sonic 2, and Sonic 3K as well, since the blocks can also be uncompressed and put into ROM, eventually freeing up more RAM, especially for Sonic 3K. The only issues with this are within the disassemblies made for those games, which could have made porting this guide for use with those games a bit tedious. However, with enough patience, it can be done.
     
    Last edited: Dec 23, 2022
  5. Devon

    Devon La mer va embrassé moi et délivré moi lakay. Member

    Joined:
    Aug 26, 2013
    Messages:
    1,412
    Location:
    your mom
    That... doesn't make any sense. It should have broke in stages past Green Hill Act 1.

    GHZ2:
    [​IMG]

    MZ1:
    [​IMG]

    LZ1:
    [​IMG]
     
  6. NaylenFresh

    NaylenFresh rawr..... Member

    Joined:
    Sep 30, 2022
    Messages:
    95
    Location:
    England
    those are some interesting + weird results
     
  7. TheInvisibleSun

    TheInvisibleSun Visible Member

    Joined:
    Jul 2, 2013
    Messages:
    424
    Location:
    Western New York, USA
    I think it's good practice to post a built rom incorporating the completed tutorial for situations like this, in case there's a misunderstanding
     
  8. Filter

    Filter Active Member Member

    Joined:
    Jul 28, 2021
    Messages:
    27
    Location:
    Canada
    Edit: Added some better pointers for those using certain versions of Project 128.

    Time for a quick update!

    For those who are surprisingly still using the old school Hivebrain 2005 disassembly, you're in luck because I still have experience with it and now you can apply this to your hacks.

    Since the blocks are already in a folder that are uncompressed, this makes it a hell of a lot easier. So in sonic1.asm, find all instances of map16 and change them to map16_u, this will direct them to the uncompressed blocks folder.

    Now go to MainLoadBlockLoad, and change this:
    Code:
            movea.l    (a2)+,a0
            lea    ($FFFFB000).w,a1 ; RAM address for 16x16 mappings
            move.w    #0,d0
            bsr.w    EniDec
    To this:
    Code:
            move.l    (a2)+,($FFFFB000).w
    There, now it's pointing directly to the ram instead of decompressing it.

    Next, find sub_6BD6 (For some Project 128 users, that's loc_712C) and change this:
    Code:
            lea    ($FFFFB000).w,a1
    To this:
    Code:
            movea.l    ($FFFFB000).w,a1
    That should fix all levels, but you'll notice the title screen is a mess, let's fix that!

    Find Title_LoadText, and replace this:
    Code:
            lea    ($FFFFB000).w,a1
            lea    (Blk16_GHZ).l,a0 ; load    GHZ 16x16 mappings
            move.w    #0,d0
            bsr.w    EniDec
    With this:
    Code:
            move.l    #Blk16_GHZ,($FFFFB000).w ; load    GHZ 16x16 mappings
    There we go! That's all you need to do, enjoy using blocks loaded from ROM instead of RAM!

    There's also an example ROM that will be included in this post of what the results should be like. If you run into any problems let me know and I'll be happy to help debug your issues and get this working in your hacks. No credit is required for this by the way, feel free to use it without credit!
     

    Attached Files:

    Last edited: Jun 3, 2023
    ProjectFM, JGamer2151 and Hame like this.