FF4 SNES SRM Checksum - Printable Version +- FF6 Hacking (https://www.ff6hacking.com/forums) +-- Forum: Discussion Forums (https://www.ff6hacking.com/forums/forum-5.html) +--- Forum: Magitek Research Facility (https://www.ff6hacking.com/forums/forum-9.html) +---- Forum: Other Rom Hacking (https://www.ff6hacking.com/forums/forum-64.html) +---- Thread: FF4 SNES SRM Checksum (/thread-3411.html) Pages:
1
2
|
RE: FF4 SNES SRM Checksum - stonerbot613 - 02-13-2017 I wrote a quick MATLAB script (code below) that generates the correct checksum based on your comments and from the assembly you sent. It mostly works save for that pesky initial checksum value. The initial value at address $41 unfortunately does not seem to be 0, and further, it seems to depend on either the save slot or some combination of information contained within. Luckily the initial value is always a fairly low number (> -100 or so signed... ~>65460 if unsigned). Also, the same initial value for slot 0 on one file isn't necessarily the same initial value for slot 0 on another file. Is there something from your ROM assembly source that specifies what goes into address $41? It's got to be deterministic and probably calculated during some part of the save routine. I forgot how much I disliked assembly code (and all the direct, indirect, absolute, immediate, etc. addressing schemes)! If I had some easy way of getting the disassembly from the ROM and being able to debug it, I could look into it as well at some point. What sort of debugging/disassembly setup are you using? *** MATLAB script follows in case anybody else would like to use it *** % Open the FF2 SNES SRM save file fid = fopen('FF4_in_use.srm', 'r'); % User selects which save slot to use (0, 1, 2, or 3) slot_offset = 0; % Position file pointer at correct byte offset in file fseek(fid, (slot_offset*2048), 'bof'); % Read 2kB save slot data. Cast as 8-bit Unsigned Integer bytes = fread(fid, 2048, 'uint8=>uint8'); % Store off checksum in file checksum = (uint32(bytes(2045))*256) + uint32(bytes(2046)); % Apply starting offset (LDA $41) - Seems to be based on slot number? if(slot_offset == 0) D8acc = intmax('uint16') - 81; end if(slot_offset == 1) D8acc = intmax('uint16') - 22; end if (slot_offset == 2) D8acc = intmax('uint16') - 71; end if (slot_offset == 3) D8acc = intmax('uint16') - 72; end % Compute 16-bit data values and accumulate. Loop 0x7fa times % NUMber of ELements in BYTES - 6 = 0x7fa for i=1numel(bytes)-6) % Handle initial word 0x00bb if(i==1) a = 0; b = bytes(i); c = uint32(uint32(a)*256) + uint32(b); % Handle other words 0xaabb else a = bytes(i-1); b = bytes(i); c = uint32(uint32(a)*256) + uint32(b); end % Look at sanity check hex value of 0xaabb d = dec2hex(c, 4); % Accumulate running checksum D8acc = uint32(D8acc) + uint32©; end while (D8acc >= 65536) D8acc = D8acc - 65536; carry = 1; end % Get final calculated checksum and compare to save slot checksum E8acc = dec2hex(D8acc, 4); checksum_hex = dec2hex(checksum, 4); if (E8acc == checksum_hex) disp('CHECKSUMS MATCH'); else disp('CHECKSUMS DO NOT MATCH'); end fclose(fid); RE: FF4 SNES SRM Checksum - m06 - 02-13-2017 The disassembly I posted before was made by me. I posted the full notes I have but if anyone has any FFIV disassembly I would be happy to get a copy. I use bsnes+ for breakpoints, geiger's disassembler is also awesome but I'm using Mac Os X. I have a home made disassembler for auto generating the assembly code. I took a look at $41, it is reset in two places at least: Code: $15c9ce when the game starts, I think this is where the RAM is cleared. I don't know what it does but I'm suspecting it's a high byte of $40, $40 is being reset all the time in the entry routine. I think it serves as some sort of deep game timer. I think $41 (and maybe $40 aswell) is stored in the SRAM somewhere since the value is variable. Maybe next to the game timer? This is all a lot of guesswork at the moment for me, I'll try to look into this later on. Rough disassembly of the entry point for FFIV: Code: 008000 20 2C 80 JSR $802C @assasin: Sounds right, different way to compute the same checksum. Your math impresses me. RE: FF4 SNES SRM Checksum - assassin - 02-13-2017 argh, guess i was a bit off.. i forgot that the bottom half's sums can carry into the top half, and then the top half's into the bottom half via Carry Flag. RE: FF4 SNES SRM Checksum - stonerbot613 - 02-13-2017 Looks like I'm not able to find any type of magic offset stored in the SRAM file. I've tried looping through both all 8-bit words and all 16-bit words as the initial value with no repeatable luck. I get a few matches in various places but nothing that is consistent from one slot to the next or one file to the next. I just found Geiger's debugger. Is there a way to set a trigger (breakpoint) on when the user selects to save a file? Or do you absolutely have to know the address that you want to break at? Is there also a traceback feature? I saw the "Trace From" option, but again it seems to imply that you need to know starting and ending address points. RE: FF4 SNES SRM Checksum - m06 - 02-13-2017 I think you can break when addresses get read or written (aswell as executed). SRAM should be at $700000 so a breakpoint for write in that range should give you the save routine. For a SNES memory map see this link: https://en.wikibooks.org/wiki/Super_NES_Programming/SNES_memory_map#LoROM I found the checksum routine by having a read breakpoint for $7007FE. I think the whole save slot is copied as a big chunk from WRAM though so I'm guessing $41 would be shadowed into the save slot? Then again you said you tested the whole SRAM file, so it's probably not there, I'm confused to how this might work. Save routine is a good starting point though, good idea. RE: FF4 SNES SRM Checksum - stonerbot613 - 02-13-2017 Aha! I got the debugger working and quickly figured out my goofs. 1) I had neglected to increment the 16-bit accumulated value when there was a carry. (I knew the C in ADC wasn't there for kicks!) 2) I was incorrectly adding a word at the beginning of the data block. After tweaking my code, it works every time. The best part? That mysterious initial value? It's 0. No need to investigate all of that $41 business. Interestingly, my disassembly addresses were slightly off from what yours were. Maybe that's down to a tool difference? Thank you so much for the quick debugging/breakpoint how-to. It saved the day! RE: FF4 SNES SRM Checksum - m06 - 02-13-2017 Awesome to hear! Thanks for asking an interesting question and being an avid hacker yourself. On this forum we love to answer questions. The disassembly difference could be the tool, could also be that I used a japanese ROM. In retrospect that was stupid of me and I should note the version of the ROM when posting disassemblies. Sadly my emulators don't display that information conveniently, I can say my ROM had CRC32: CAA15E97 for anyone curious to compare. @assassin: At least you pointed out the importance of the carry flag that turned out to be the problem. Either you knew what was up or the cosmos has it's ways. I'm a happy hacker now RE: FF4 SNES SRM Checksum - assassin - 02-13-2017 glad it's working, and that i could stumble into helping.. but why would they add in Var $41 instead of just a 0000h constant? all to save 1 byte? does the variable (along with $42) get zeroed right before the game save/load or checksum functions? or are you going off of never seeing it receive another value? in the latter case, it is a lot harder to prove a negative. FF6, in comparison, has an always-zero value (at least when running in Bank C3, the main menus), presumably to save space on loads, but it's at a more intuitive address $0000. RE: FF4 SNES SRM Checksum - m06 - 03-01-2017 I made a python script for this if anyone wants: https://github.com/mogue/SNES-SRM-Checksum-Fix/blob/master/FF4_SRM_checksum_fix.py The repository also includes FF5 and FF6 SRM fixing. @ assassin: I'm not sure how to prove the value stays zero, it's zeroed when the menu opens. FF5 checksum uses a similar initial RAM value that gets zeroed when the menu opens but is located elsewhere. All my testing suggest these values stay zero. RE: FF4 SNES SRM Checksum - Grandirus - 04-27-2017 (03-01-2017, 01:37 PM)m06 Wrote: I made a python script for this if anyone wants: Hi. There is some way to wrote this as Visual Basic 6 language? I'm trying to make and SRM Editor. Already made a Save State Editor, but now, I'm entering in SRM files. Have done one for "Zelda, A Link To The Past" SRM, and another to "Phantasy Star IV". Any help will be welcome. EDIT: Success with FF5 code. Do some google searchs about python, and now I have some code to test with FF5 SRM Files. Now, I'm stuck in FF4 code. My code do close results with the checksum (checksum is C443, my result is C4C4) I'm continue to find out where this diference enter in the final result. EDIT 2: I figured out how to made it work in VB6 code. Now I'm going to FF6 checksum quest, hahahahaha. EDIT 3: Got it to FF6 too. All working fine. Now, I will made the convertions, from Save State editors to SRAM editors. EDIT 4: Thanks to m06 scripts, I figured out how to make and VB6 function to fix checksums for FF4, FF5 and FF6. FF4 and FF5 worked fine, with game config options (can change window colors and other options in the editor). FF6 wil take some time to update the current project that I have. Well, thanks m06. |