New SRAM Tutorial

Discussion in 'Tutorials' started by Iso Kilo, Feb 23, 2020.

Tags:
  1. Iso Kilo

    Iso Kilo Sonic 1 Beta Researcher Member

    Joined:
    Oct 9, 2017
    Messages:
    208
    Location:
    Small Town in BC, Canada
    Credits to @AkumaYin for optimizing InitSRAM

    Over the past few days, I've been learning how to work with SRAM (Save RAM), and I think I've gotten it down.
    For those who don't know, SRAM is used for saving data once the Mega Drive is turned off. Sonic 3 uses it to store 6 entries that contain: Your selected character, your current zone, your Chaos Emeralds. And with Sonic 3 and Knuckles, you get 2 more save slots, and your lives and continues are saved.
    Implementing and using SRAM is surprisingly easy. And only requires a few steps.

    Initialization
    First your project needs to be able to actually use SRAM. There's a part of the header that determines this information.
    Code:
    SRAM_Support
        dc.l    $20202020    ; Null SRAM
    
    Start_of_SRAM
        dc.l    $20202020    ; Start of SRAM memory space
    
    End_of_SRAM
        dc.l    $20202020    ; End of SRAM memory space
    As is, the SRAM is using a null value and is therefore inactive. To make it active you'll need to change the contents of SRAM support. The format is pretty simple: "RA",XX,$20. XX is based on the type of SRAM you want. Here are your options:

    • $A0 - No saving, 16-bit addresses
    • $B0 - No saving, even 8-bit addresses
    • $B8 - No saving, odd 8-bit addresses
    • $E0 - Saving, 16-bit addresses
    • $F0 - Saving, even 8-bit addresses
    • $F8 - Saving, odd 8-bit addresses
    You'd most likely want to use $F8 (Saving with odd 8-bit addresses) so here's what that would look like:
    Code:
    SRAM_Support
        dc.b    "RA",$F8,$20
    You can then choose your space for SRAM memory. Starting from $200001 to $20FFFF.
    The header is now set up to allow for SRAM. From here on out you can do whatever you please. But I still need to go over a few things.
    If you were to attempt and load SRAM data that doesn't exist, you'd most likely get a crash. This can be prevented with a routine to check if SRAM exists.
    Code:
    InitSRAM:
            move.b  #1,($A130F1).l    ; Enable SRAM writing
            lea ($200001).l,a0      ; Load SRAM memory into a0 (Change the last digit to 0 if you're using even SRAM)
            movep.l 0(a0),d0        ; Get the existing string at the start of SRAM
            move.l  #"SRAM",d1        ; Write the string "SRAM" to d1
            cmp.l   d0,d1            ; Was it already in SRAM?
            beq.s   @Continue           ; If so, skip
            movep.l d1,0(a0)        ; Write string "SRAM"
            ; Here is where you initialize values like lives or level. If you're using 8 bit values, you can only use every other byte.
            ; Example - 8(a0) => $A(a0)
     
    @Continue:
            move.b    #0,($A130F1).l    ; Disable SRAM writing
    I recommend you place this before the main game loop routine.


    Using SRAM
    Everything is ready to be used. How you use it is up to you, here are just some notes.
    • You must enable and disable SRAM writing mode before and after you do SRAM writing, but only if your ROM is larger than 2 MB, otherwise it's always active.
    • You have to lea the SRAM memory into an address register when using 8-bit SRAM and long word values.
    • You must use movep to move memory into SRAM when using 8-bit SRAM and long word values.
    • You cannot directly move values into SRAM, you'd have to do it via a register when using 8-bit SRAM and long word values.
    • You can just directly use move.b into the SRAM memory you want when using byte values.
    If you have suggestions, fixes, additions, or even some cool results, let me know. (Seriously, I got very little feedback on this, and it concerns me because I know I'm not perfect at SRAM yet). Other than that, enjoy saving!
     
    Last edited: Feb 29, 2020