don't click here

SRAM Support in Sonic 1?

Discussion in 'Engineering & Reverse Engineering' started by theocas, Apr 19, 2010.

Thread Status:
Not open for further replies.
  1. theocas

    theocas

    Tech Member
    346
    0
    16
    I know that this is possible since I modified the Header of my ROM to this:
    Code (ASM):
    1.  
    2. SRAMSupport:    dc.l $5241E020  ; change to $5241E020 to create SRAM
    3.         dc.l $20202020      ; SRAM start
    4.         dc.l $202020C0      ; SRAM end
    5.  
    I tried doing this in the Lamppost Save routine:
    Code (ASM):
    1.  
    2. ; and now to the SRAM:
    3.         move.b  $28(a0),($20202020).w       ; lamppost number
    4.         move.b  ($FFFFFE30).w,($20202021).w
    5.         move.w  8(a0),($20202022).w     ; x-position
    6.         move.w  $C(a0),($20202023).w        ; y-position
    7.         move.w  ($FFFFFE20).w,($20202026).w     ; rings
    8.         move.b  ($FFFFFE1B).w,($20202040).w     ; lives
    9.         move.l  ($FFFFFE22).w,($2020204F).w     ; time
    10.         move.b  ($FFFFF742).w,($20202055).w     ; routine counter for dynamic level mod
    11.         move.w  ($FFFFF72E).w,($20202065).w     ; lower y-boundary of level
    12.         move.w  ($FFFFF700).w,($20202067).w     ; screen x-position
    13.         move.w  ($FFFFF704).w,($20202069).w     ; screen y-position
    14.         move.w  ($FFFFF708).w,($2020206A).w     ; bg position
    15.         move.w  ($FFFFF70C).w,($2020206C).w     ; bg position
    16.         move.w  ($FFFFF710).w,($2020206E).w     ; bg position
    17.         move.w  ($FFFFF714).w,($20202070).w     ; bg position
    18.         move.w  ($FFFFF718).w,($20202072).w     ; bg position
    19.         move.w  ($FFFFF71C).w,($20202074).w     ; bg position
    20.         move.w  ($FFFFF648).w,($20202076).w     ; water height
    21.         move.b  ($FFFFF64D).w,($20202078).w     ; rountine counter for water
    22.         move.b  ($FFFFF64E).w,($20202080).w     ; water direction
    23.  
    But get an Invalid Value error (Just what I expected) I think this is the right approach, but I haven't looked at a Sonic 3 disasembly to see how S3 did it( I can't find a S3 disasembly) Can anyone give me some pointers or explain how Sonic 3 saves data to it's SRAM from ASM? Sorry if I am asking all the obvious questions, but Thanks for any help!
     
  2. Hanoch

    Hanoch

    Also known as TheKnock, Birashot Member
    491
    0
    0
    Israel
    everything
    20202020 Isn't a valid sram start/end, you need to change it to 200000 for Sram start and 2003FF for sram end.
     
  3. Selbi

    Selbi

    The Euphonic Mess Member
    1,497
    48
    28
    Northern Germany
    Sonic ERaZor
    From what I can tell by lookind at it (even though I don't know how SRAM works):
    The lines with a -> are moving either a word or a longword to an odd value (RAM address ending with 1, 3, 5, 7, 9, B, D or F). Don't ask me why, but this doesn't work. You need to find an even address (RAM address ending with 0, 2, 4, 6, 8, A, C or E).

    But, as already mentioned, I'm not sure if this works at all.
     
  4. theocas

    theocas

    Tech Member
    346
    0
    16
    Thanks, I will try that out.
    Selbi: I will change all odd RAM adresses to even ones and see how it works.
     
  5. MarkeyJester

    MarkeyJester

    Original, No substitute Resident Jester
    2,202
    432
    63
    Japan
    The thing is, I've been told that they need to be odd addresses, and you cannot hold code on the even addresses, of course I don't think that's 100% true, though games that use SRam all seem to move only a byte of data to it, but in odd addresses too, so I would asume it would be safe to keep it on an odd address and not to move words or long-words of data too and from it. I set it this way for BroTro, and it's been tested with special carts on HW that allow SRam support, and apparently it all works fine, so I would asume so.
     
  6. Chilly Willy

    Chilly Willy

    Tech Member
    751
    11
    18
    Doom 32X
    Save ram on the Genesis MUST be on odd addresses only. 0x200001, 0x200003, 0x200005, etc. This is because the 68000 uses a word bus, and the save ram only sits on the odd byte leaving the even byte unsupported. The 68000 has a special command for transferring data to/from peripherals or memory that only sits on one byte of the word - MOVEP (move peripheral).

    The 68000 cannot read/write words or longs to odd addresses (you get an odd address exception if you do). MOVEP instead breaks word and long read/writes into bytes, and does each byte of the word/long to addresses two bytes apart. For example

    move.w #0x1234,d0
    lea 0x200000,a0
    movep.w d0,1(a0)

    stores 0x12 into 0x200001, and 0x34 into 0x200003. movep.l works the same way, but doing longs as four bytes. So when reading/writing sram, you either need to do everything yourself as byte moves to/from odd addresses starting at 0x200001, or use movep instructions for words and longs.

    Note that movep only allows for the Dn,d16(Am) and d16(An),Dm addressing modes.
     
  7. theocas

    theocas

    Tech Member
    346
    0
    16
    OK, you lost me there. So what I need to do is replace all the MOVE.P and all MOVE.W instructions with MOVEP or do I have to copy all data into another address and then do a MOVEP?
     
  8. SegaLoco

    SegaLoco

    W)(at did you say? Banned
    Not to get off topic a bit, but something that has always bugged me is that, the SRAM section in the header really isn't just a random value. You could also write:

    Code (Text):
    1. ExRAMSupport:    dc.b    'RA', %11111000, %00100000
    2. ExRAMAddr:    dc.l    $00200000, $002003FF
    The general form for this section is
    Code (Text):
    1. ExRAMSupport:    dc.b    'RA', %1x1yz000, %00100000
    2. ExRAMAddr:    dc.l    StartAddr, EndAddr
    where x = 1 for backup ram, x = 0 for external work ram.

    yz = 10 for even addressed SRAM, and yz = 11 for odd addressed SRAM, as ChillyWilly there was saying.

    (If you all like memorizing that number, fine by me, I personally think this is easier :v: )

    Edit: Oh, for no ExRAM do

    Code (Text):
    1. ExRAMSupport:    dc.b    '  ', %00100000, %00100000
    2. ExRAMAddr:    dc.l    $20202020, $20202020
     
  9. Tweaker

    Tweaker

    Banned
    12,387
    2
    0
    When you reference SRAM addresses, you have to use .l instead of .w after the parentheses. So:
    Code (ASM):
    1. move.b  ($FFFFF64E).w,($20202080).w     ; water direction
    Should be:
    Code (ASM):
    1. move.b  ($FFFFF64E).w,($20202080).l     ; water direction
    Hope this helps.
     
  10. theocas

    theocas

    Tech Member
    346
    0
    16
    I have convertet the Lamppost code to this:
    Code (ASM):
    1.  
    2. Obj79_StoreInfo:            ; XREF: Obj79_HitLamp
    3.         move.b  $28(a0),($200000).l         ; lamppost number
    4.         move.b  ($FFFFFE30).w,($200002).l
    5.         move.b  8(a0),($200008).l       ; x-position
    6.         move.w  $C(a0),($20000B).l      ; y-position
    7.         move.w  ($FFFFFE20).w,($20000F).l   ; rings
    8.         move.b  ($FFFFFE1B).w,($200014).l   ; lives
    9.         move.l  ($FFFFFE22).w,($200018).l   ; time
    10.         move.b  ($FFFFF742).w,($20001B).l   ; routine counter for dynamic level mod
    11.         move.w  ($FFFFF72E).w,($20001F).l   ; lower y-boundary of level
    12.         move.w  ($FFFFF700).w,($200024).l   ; screen x-position
    13.         move.w  ($FFFFF704).w,($200028).l   ; screen y-position
    14.         move.w  ($FFFFF708).w,($20002B).l   ; bg position
    15.         move.w  ($FFFFF70C).w,($20002F).l   ; bg position
    16.         move.w  ($FFFFF710).w,($200034).l   ; bg position
    17.         move.w  ($FFFFF714).w,($200038).l   ; bg position
    18.         move.w  ($FFFFF718).w,($20003B).l   ; bg position
    19.         move.w  ($FFFFF71C).w,($20003F).l   ; bg position
    20.         move.w  ($FFFFF648).w,($200044).l   ; water height
    21.         move.b  ($FFFFF64D).w,($200048).l   ; rountine counter for water
    22.         move.b  ($FFFFF64E).w,($20004B).l   ; water direction
    23.         rts
    24.        
    25. Obj79_LoadInfo:             ; XREF: LevelSizeLoad
    26.                
    27.                         move.b  $28(a0),($200000).l         ; lamppost number
    28.         move.b  ($200002).l,($FFFFFE30).w
    29.         move.b  ($200008).l,($FFFFD008).w       ; x-position
    30.         move.w  ($20000B).l,($FFFFD00C).w       ; y-position
    31.         move.w  ($20000F).l,($FFFFFE20).w   ; rings
    32.         move.b  ($200014).l,($FFFFFE1B).w   ; lives
    33.         move.l  ($200018).l,($FFFFFE22).w   ; time
    34.         move.b  ($20001B).l,($FFFFF742).w   ; routine counter for dynamic level mod
    35.         move.w  ($20001F).l,($FFFFF72E).w   ; lower y-boundary of level
    36.         move.w  ($200024).l,($FFFFF700).w   ; screen x-position
    37.         move.w  ($200028).l,($FFFFF704).w   ; screen y-position
    38.         move.w  ($20002B).l,($FFFFF708).w   ; bg position
    39.         move.w  ($20002F).l,($FFFFF70C).w   ; bg position
    40.         move.w  ($200034).l,($FFFFF710).w   ; bg position
    41.         move.w  ($200038).l,($FFFFF714).w   ; bg position
    42.         move.w  ($20003B).l,($FFFFF718).w   ; bg position
    43.         move.w  ($20003F).l,($FFFFF71C).w   ; bg position
    44.         move.w  ($200044).l,($FFFFF648).w   ; water height
    45.         move.b  ($200048).l,($FFFFF64D).w   ; rountine counter for water
    46.         move.b  ($20004B).l,($FFFFF64E).w   ; water direction
    47.  
    But once I pass a lamp post and die, I just get put back at the beginning of the Level. Am I just using the wrong adresses, or is my header off:
    Code (ASM):
    1.  
    2. ExRAMSupport:   dc.b    'RA', %111000, %00100000
    3. ExRAMAddr:      dc.l    $200000, $200000
    4.  
     
  11. Tweaker

    Tweaker

    Banned
    12,387
    2
    0
    Well... erm, yeah. You're not specifying a range—you're just putting the start there twice. If you've used all the bytes you're going to, then I suggest making $200100 the end or something like that.
     
  12. theocas

    theocas

    Tech Member
    346
    0
    16
    I did that and I still get the same result as before. Something is telling me the data is not being written to SRAM...
     
  13. Chilly Willy

    Chilly Willy

    Tech Member
    751
    11
    18
    Doom 32X
    move.b can stay move.b
    move.w -> movep.w
    move.l -> movep.l

    Remember that sram is every other byte, so a byte takes two bytes of space, a word takes four bytes of space, and a long takes eight bytes.

    So, more like this

    Code (Text):
    1. Obj79_StoreInfo:        ; XREF: Obj79_HitLamp
    2.         move.b    #1,($A130F1).l; enable save ram
    3.         lea        ($200001).l,a1    ; base of sram
    4.         move.b    $28(a0),0(a1)     ; lamppost number
    5.         move.b    ($FFFFFE30).w,2(a1)
    6.         move.b    8(a0),4(a1)    ; x-position
    7.         move.w    $C(a0),d0    ; y-position
    8.         movep.w    d0,6(a1)
    9.         move.w    ($FFFFFE20).w,d0 ; rings
    10.         movep.w    d0,10(a1)
    11.         move.b    ($FFFFFE1B).w,14(a1) ; lives
    12.         move.l    ($FFFFFE22).w,d0 ; time
    13.         movep.l    d0,16(a1)
    14.         move.b    ($FFFFF742).w,24(a1) ; routine counter for dynamic level mod
    15.         move.w    ($FFFFF72E).w,d0 ; lower y-boundary of level
    16.         movep.w    d0,26(a1)
    17.         move.w    ($FFFFF700).w,d0 ; screen x-position
    18.         movep.w    d0,30(a1)
    19.         move.w    ($FFFFF704).w,d0 ; screen y-position
    20.         movep.w    d0,34(a1)
    21.         move.w    ($FFFFF708).w,d0 ; bg position
    22.         movep.w    d0,38(a1)
    23.         move.w    ($FFFFF70C).w,d0 ; bg position
    24.         movep.w    d0,42(a1)
    25.         move.w    ($FFFFF710).w,d0 ; bg position
    26.         movep.w    d0,46(a1)
    27.         move.w    ($FFFFF714).w,d0 ; bg position
    28.         movep.w    d0,50(a1)
    29.         move.w    ($FFFFF718).w,d0 ; bg position
    30.         movep.w    d0,54(a1)
    31.         move.w    ($FFFFF71C).w,d0 ; bg position
    32.         movep.w    d0,58(a1)
    33.         move.w    ($FFFFF648).w,d0 ; water height
    34.         movep.w    d0,62(a1)
    35.         move.b    ($FFFFF64D).w,66(a1) ; rountine counter for water
    36.         move.b    ($FFFFF64E).w,68(a1) ; water direction
    37.         move.b    #0,($A130F1).l; disable save ram
    38.         rts
    The load from sram is the same, but the moves are the other direction. And the header should be like this

    Code (Text):
    1. ExRAMSupport:
    2.         dc.b    'RA'    ; external ram
    3.         dc.b    $F8    ; don't clear + odd bytes
    4.         dc.b    $20    ; sram
    5. ExRAMAddr:
    6.         dc.l    $200001, $203FFF; start, end
    $200001 to $203FFF is 16KB of space, but only every other byte is used, so it's 8KB of sram. Assuming you intend this for an emulator or flash cart, 8KB of flash is nothing. Note in the save routine that only a little of that is used. Ideally, instead of setting a1 to $200001 in the save routine, you'd pass in a value so you could do multiple save states. $200001 -> first save, $200101 -> second save, $200201 -> third save, etc.
     
  14. SegaLoco

    SegaLoco

    W)(at did you say? Banned
    You aren't writing that quite right. For odd addressed SRAM you want:
    Code (Text):
    1. ExRamSupport: dc.b 'RA', %11111000, %00100000
    2. ExRamBounds: dc.l $00200000, $00203FFF
    Edit: Dang, ChillyWilly beat me to it, albeit I prefer my binary version, there is no difference...
     
  15. theocas

    theocas

    Tech Member
    346
    0
    16
    I have replaced the Save Routine with this, but I still get the same behavior for some reason. I simply switched the numbers in the movep and move.b instructions to the SRAM. Here is what I have in the save routine:

    Code (ASM):
    1.  
    2.                 move.b    #1,($A130F1).l; enable save ram
    3.                 lea        ($200001).l,a1    ; base of sram        
    4.                 move.b    0(a1),$28(a0)     ; lamppost number        
    5.                 move.b    ($FFFFFE30).w,2(a1)        
    6.                 move.b    4(a1),8(a0)    ; x-position        
    7.                 move.w    $C(a0),d0    ; y-position        
    8.                 movep.w    6(a1),d0            
    9.                 move.w    ($FFFFFE20).w,d0 ; rings        
    10.                 movep.w    10(a1),d0            
    11.                 move.b    ($FFFFFE1B).w,14(a1) ; lives        
    12.                 move.l    ($FFFFFE22).w,d0 ; time        
    13.                 movep.l    16(a1),d0            
    14.                 move.b    ($FFFFF742).w,24(a1) ; routine counter for dynamic level mod        
    15.                 move.w    ($FFFFF72E).w,d0 ; lower y-boundary of level        
    16.                 movep.w    26(a1),d0        
    17.                 move.w    ($FFFFF700).w,d0 ; screen x-position        
    18.                 movep.w    30(a1),d0        
    19.                 move.w    ($FFFFF704).w,d0 ; screen y-position        
    20.                 movep.w    34(a1),d0        
    21.                 move.w    ($FFFFF708).w,d0 ; bg position        
    22.                 movep.w    38(a1),d0        
    23.                 move.w    ($FFFFF70C).w,d0 ; bg position        
    24.                 movep.w    42(a1),d0        
    25.                 move.w    ($FFFFF710).w,d0 ; bg position        
    26.                 movep.w    46(a1),d0        
    27.                 move.w    ($FFFFF714).w,d0 ; bg position        
    28.                 movep.w    50(a1),d0        
    29.                 move.w    ($FFFFF718).w,d0 ; bg position        
    30.                 movep.w    54(a1),d0        
    31.                 move.w    ($FFFFF71C).w,d0 ; bg position        
    32.                 movep.w    58(a1),d0        
    33.                 move.w    ($FFFFF648).w,d0 ; water height        
    34.                 movep.w    62(a1),d0        
    35.                 move.b    66(a1),($FFFFF64D).w ; rountine counter for water        
    36.                 move.b    68(a1),($FFFFF64E).w ; water direction        
    37.                 move.b    #0,($A130F1).l; disable save ram        
    38.                 rts
    39.  
    And yes, my initial idea was to have 4 different save slots.
     
  16. Chilly Willy

    Chilly Willy

    Tech Member
    751
    11
    18
    Doom 32X
    You need to swap the word and long moves around as well.

    Code (Text):
    1.                 move.b    #1,($A130F1).l; enable save ram
    2.                 lea        ($200001).l,a1   ; base of sram        
    3.                 move.b    0(a1),$28(a0)    ; lamppost number        
    4.                 move.b    ($FFFFFE30).w,2(a1)        
    5.                 move.b    4(a1),8(a0)   ; x-position        
    6.                 movep.w    6(a1),d0            
    7.                 move.w    d0,$C(a0)   ; y-position        
    8.                 movep.w    10(a1),d0            
    9.                 move.w    d0,($FFFFFE20).w; rings        
    10.                 move.b    ($FFFFFE1B).w,14(a1); lives        
    11.                 movep.l    16(a1),d0            
    12.                 move.l    d0,($FFFFFE22).w; time        
    13.                 move.b    ($FFFFF742).w,24(a1); routine counter for dynamic level mod        
    14.                 movep.w    26(a1),d0        
    15.                 move.w    d0,($FFFFF72E).w; lower y-boundary of level        
    16.                 movep.w    30(a1),d0        
    17.                 move.w    d0,($FFFFF700).w; screen x-position        
    18.                 movep.w    34(a1),d0        
    19.                 move.w    d0,($FFFFF704).w; screen y-position        
    20.                 movep.w    38(a1),d0        
    21.                 move.w    d0,($FFFFF708).w; bg position        
    22.                 movep.w    42(a1),d0        
    23.                 move.w    d0,($FFFFF70C).w; bg position        
    24.                 movep.w    46(a1),d0        
    25.                 move.w    d0,($FFFFF710).w; bg position        
    26.                 movep.w    50(a1),d0        
    27.                 move.w    d0,($FFFFF714).w; bg position        
    28.                 movep.w    54(a1),d0        
    29.                 move.w    d0,($FFFFF718).w; bg position        
    30.                 movep.w    58(a1),d0        
    31.                 move.w    d0,($FFFFF71C).w; bg position        
    32.                 movep.w    62(a1),d0        
    33.                 move.w    d0,($FFFFF648).w; water height        
    34.                 move.b    66(a1),($FFFFF64D).w; rountine counter for water        
    35.                 move.b    68(a1),($FFFFF64E).w; water direction        
    36.                 move.b    #0,($A130F1).l; disable save ram        
    37.                 rts
     
  17. theocas

    theocas

    Tech Member
    346
    0
    16
    My emulator is still not even writing an SRAM file. I have uploaded the rom here: Link. I have the lamp post's save and read routine set to read/write to the SRAM. My header seems to be fine too:
    Code (ASM):
    1.  
    2. ExRAMSupport:  
    3.                 dc.b    'RA'    ; external ram        
    4.                 dc.b    $F8    ; don't clear + odd bytes        
    5.                 dc.b    $20    ; sram
    6. ExRAMAddr:        
    7.                 dc.l    $200001, $203FFF; start, end
    8.  
    Can someone please test if they get the same result, because right now I'm thinking my emulator is not working...

    EDIT: I have checked the ROM on Kega Fusion on Mac OS X as well, but I get the same result as Gens/GX on Windows7
     
  18. Chilly Willy

    Chilly Willy

    Tech Member
    751
    11
    18
    Doom 32X
    When I run this on KEGA in Ubuntu, I get an s1built.srm file in the ".Kega Fusion" directory where all the srm files are. It has these contents:

    ff02 ff00 ff19 ff03 ff73 ff00 ff09 ff00 ff00 ff01
    ff24 ff2f ff00 ff03 ff70 ff18 ffd6 ff03 ff13 ff09
    ff50 ff00 ff0e ff0c ff6b ff00 ff0e ff00 ff00 ff00
    ff00 ff00 ff00 ff00 ff00

    That data appears to be consistent with the code. It's not clear under what circumstances the data will be saved or restored. Does it save when you hit a lamppost? How do you restore?
     
  19. theocas

    theocas

    Tech Member
    346
    0
    16
    The data should be saved when a lamp post is activated and restored when you die after hitting a lamp post. My initial idea was to first get something like this working, and then convert it to have 4 different save slots. But like I said again, I just can not get it to work on both of my machines.
     
  20. Chilly Willy

    Chilly Willy

    Tech Member
    751
    11
    18
    Doom 32X
    Well, either you're missing something on the save, or you aren't restoring in the proper place. It IS saving the data - the srm file is proof of that. So it's just a matter of making sure you are saving everything you need, and then restoring at the proper place.

    EDIT: I did notice something... some moves weren't turned around in the restore

    Code (Text):
    1.                 move.b    #1,($A130F1).l; enable save ram
    2.                 lea        ($200001).l,a1  ; base of sram        
    3.                 move.b    0(a1),$28(a0)   ; lamppost number        
    4.                 move.b    ($FFFFFE30).w,2(a1)        
    5.                 move.b    4(a1),8(a0)  ; x-position        
    6.                 movep.w    6(a1),d0            
    7.                 move.w    d0,$C(a0)  ; y-position        
    8.                 movep.w    10(a1),d0            
    9.                 move.w    d0,($FFFFFE20).w; rings        
    10. ;                move.b    ($FFFFFE1B).w,14(a1); lives        *****************************************************
    11.                  move.b    14(a1),($FFFFFE1B).w; lives        
    12.                 movep.l    16(a1),d0            
    13.                 move.l    d0,($FFFFFE22).w; time        
    14. ;                move.b    ($FFFFF742).w,24(a1); routine counter for dynamic level mod        *************************************************
    15.                 move.b    24(a1),($FFFFF742).w; routine counter for dynamic level mod        
    16.                 movep.w    26(a1),d0        
    17.                 move.w    d0,($FFFFF72E).w; lower y-boundary of level        
    18.                 movep.w    30(a1),d0        
    19.                 move.w    d0,($FFFFF700).w; screen x-position        
    20.                 movep.w    34(a1),d0        
    21.                 move.w    d0,($FFFFF704).w; screen y-position        
    22.                 movep.w    38(a1),d0        
    23.                 move.w    d0,($FFFFF708).w; bg position        
    24.                 movep.w    42(a1),d0        
    25.                 move.w    d0,($FFFFF70C).w; bg position        
    26.                 movep.w    46(a1),d0        
    27.                 move.w    d0,($FFFFF710).w; bg position        
    28.                 movep.w    50(a1),d0        
    29.                 move.w    d0,($FFFFF714).w; bg position        
    30.                 movep.w    54(a1),d0        
    31.                 move.w    d0,($FFFFF718).w; bg position        
    32.                 movep.w    58(a1),d0        
    33.                 move.w    d0,($FFFFF71C).w; bg position        
    34.                 movep.w    62(a1),d0        
    35.                 move.w    d0,($FFFFF648).w; water height        
    36.                 move.b    66(a1),($FFFFF64D).w; rountine counter for water        
    37.                 move.b    68(a1),($FFFFF64E).w; water direction        
    38.                 move.b    #0,($A130F1).l; disable save ram        
    39.                 rts
     
Thread Status:
Not open for further replies.