-
Notifications
You must be signed in to change notification settings - Fork 0
/
sram-doc.txt
939 lines (707 loc) · 29.7 KB
/
sram-doc.txt
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
-------------------------------------------------------------------------------
| Super Metroid SRAM Document 1.0
| by John David Ratliff
|
| The most recent version of this guide can always be found at
| http://games.technoplaza.net/smse/sram-doc.txt
|
| Copyright (C) 2005 emuWorks (http://games.technoplaza.net/)
| Permission is granted to copy, distribute and/or modify this document
| under the terms of the GNU Free Documentation License, Version 1.2
| or any later version published by the Free Software Foundation;
| with no Invariant Sections, no Front-Cover Texts, and no Back-Cover
| Texts. A copy of the license can be found at
| http://www.gnu.org/licenses/fdl.html
-------------------------------------------------------------------------------
-------------------------------------------------------------------------------
| Table of Contents
-------------------------------------------------------------------------------
- 1.0 Introduction
- 2.0 Copyright Notice
- 3.0 Revision History
- 4.0 The Super Metroid SRAM
- 4.1 SRAM Basics
- 4.2 SRAM Offsets
- 4.3 The Sanity Algorithm
- 4.4 Checksum Repair Program (sanity.c)
- 5.0 smse - The Super Metroid SRAM Editor
- 6.0 Credits & Acknowledgements
- 7.0 Contact Information
-------------------------------------------------------------------------------
| 1.0 Introduction
-------------------------------------------------------------------------------
This document is a guide to the SRAM format used by Super Metroid for the
Super Nintendo and Super Famicom. It is not a walkthrough or guide to
anything else about the game or any other topic.
Save RAM, abbreviated SRAM, was used in nearly all Nintendo games to save
progress in the cartridge prior to the advent of memory cards and built-in
hard drives that came with third-generation (and later) systems such as the
Playstation and X-Box. SRAM is a special segment of memory which is preserved
using a battery built into the cartridge, and enables games to keep a limited
area of memory from being erased when the console (SNES) was turned off.
SRAM was reliable so long as the battery lasted, and the batteries were
generally guaranteed for 5 years from the date of cartridge production, and
often outlasted their guarantee period. Many Nintendo and Super Nintendo
cartridges with SRAM still have working batteries, and many others are now
dead.
Why have I spent two paragraphs talking about SRAM? Because it was the
storage medium used to save game progress for Super Metroid. All three games,
along with some other information was stored in a block of memory 0x2000
bytes long. (Note: all numbers prefixed with 0x are in the hexadecimal
system)
This document is a guide to what is stored in the SRAM and where. It is
useful only if you wish to alter the SRAM in some way. See section 5.0 for
a program that helps edit Super Metroid SRAM files.
Why would you want to edit the SRAM file? To edit your games; either to cheat
or to try things out. For example, say you wanted to try a new way of
beating Draygon, but didn't have any save games. Rather than play all the
way through to Draygon, you might just start a game, get past the space
colony, save the game on Zebes and edit the SRAM to put you near Draygon
with whatever equipment you might need to try your new method. Of course,
cheating is probably the more popular use for SRAM editing.
-------------------------------------------------------------------------------
| 2.0 Copyright Notice
-------------------------------------------------------------------------------
This document is Copyright (C) 2005 emuWorks (http://games.technoplaza.net/)
Permission is granted to copy, distribute and/or modify this document
under the terms of the GNU Free Documentation License, Version 1.2
or any later version published by the Free Software Foundation;
with no Invariant Sections, no Front-Cover Texts, and no Back-Cover
Texts. A copy of the license can be found at
http://www.gnu.org/licenses/fdl.html
Basically, it is free documentation in much the same way software under the
GNU General Public License is free software. You can modify it, redistribute
it, sell it, publish it, etc.
-------------------------------------------------------------------------------
| 3.0 Revision History
-------------------------------------------------------------------------------
Version 1.0 - Saturday, October 15, 2005
- First Public Release
-------------------------------------------------------------------------------
| 4.0 The Super Metroid SRAM
-------------------------------------------------------------------------------
This section details the SRAM format used by Super Metroid.
-------------------------------------------------------------------------------
| 4.1 SRAM Basics
-------------------------------------------------------------------------------
As was discused in section 1.0, Super Metroid used an SRAM of 0x2000 bytes
to store game progress.
Each game occupied 0x65C bytes of the SAM for a total of 0x1314 bytes.
There are 8 bytes of meta-data kept on each game for a total of 0x18 bytes,
bringing us to a total of 0x132C bytes. The remaining 0xCD4 bytes are
largely unused. There are a few game properties that are stored in the
SRAM, but these are not documented here (nor do I know any of them).
Because the SRAM is simply a block of RAM, it can lose its value if there
is no power. The battery in the cartridge feeds power to the memory when
the console is off, but if the battery dies, the SRAM will cease to
function. Because the battery must eventually die, nearly every game that
used SRAM added a sanity algorithm to confirm that the SRAM was still in
working order. Data within the SRAM acts to confirm that the remainder of
the SRAM data is valid. 8 bytes of SRAM data for each game are reserved for
this purpose. They are the checksum (2 bytes), the checksum compliment
(2 bytes), the redundant checksum (2 bytes), and the redundant checksum
compliment (2 bytes). The sanity algorithm will be discussed in detail in
section 4.4.
The SRAM is largely composed of game data, the majority of which is of
little importance for most purposes. There are only around 300 bits of
really important data. These include the majority of Samus' progress,
including her current and max energy and reserve energy, her current and
max inventory (missiles, super missiles, and power bombs), which bosses
have been defeated, the save point, the area maps Samus has downloaded,
the game time, the controller and game configuration, which items Samus
has found (morphing ball, screw attack, ice beam, etc.), which missile,
super missile, and power bomb packs Samus has found, which energy and
reserve tanks Samus has found, and which doors Samus has opened. The
majority of the remaining data in the SRAM corresponds to Samus' personal
map for each area, which is a listing of all the rooms Samus has entered in
each area. The specifics of this personal map data are of little interest
to me, and so are undocumented (and unknown).
The data documented here is generally edited in a single bit of the SRAM.
The next section will present a listing of all the known offsets and
which bit within the offset is used.
The three games, which are 0x65C bytes in length begin at offset 0x10 in
the SRAM. SRAM offset 0x10 is the start of Game A. 0x66C is the start of
Game B, and 0xCC8 is the start of Game C. The offset data in the next
section is all relative to the start of each game. So offset 0x60 in game 1
is really 0x70 from the start of the SRAM, 0x6CC in game 2, and 0xD28 in
game 3.
-------------------------------------------------------------------------------
| 4.2 SRAM Offsets
-------------------------------------------------------------------------------
These offsets will be presented in no special order other than similar things
will be grouped together.
---------------------------------------------------------------------------
The energy and reserve energy are words (2 bytes). Words are special in the
SRAM because they must be stored in little endian format. If you don't know
what the is, you can google for it if you're interested.
Here is what it means for our purposes. It means you need to take the value
you want, convert it to hex, and reverse the bytes. For example, 1499, the
max energy is 0x5DB in hex. This word becomes the two bytes, 0x5 and 0xDB.
If you want to change the current energy to 1499, you need to put 0xDB in
offset 0x20 and 0x5 in offset 0x21. This looks backwards to us, but is
the way the 65c816 processor (used in the Super Nintendo/Famicom) reads
numbers.
---------------------------------------------------------------------------
Energy - Max energy is 1499 (0x5DB)
0x20 (Current)
0x22 (Max)
Reserve Energy - Max reserve energy is 400 (0x190)
0x34 (Current)
0x32 (Max)
---------------------------------------------------------------------------
Missiles - Max missiles is 230 (0xE6)
0x24 (Current)
0x26 (Max)
Super Missiles - Max super missiles is 50 (0x32)
0x28 (Current)
0x2A (Max)
Power Bombs - Max power bombs is 50 (0x32)
0x2C (Current)
0x2E (Max)
---------------------------------------------------------------------------
The next group of offsets detail Samus' equipment (morphing ball, screw
attack, ice beam, etc). The first offset is whether the item has been
taken, and therefore will not appear in the game. The second one is whether
Samus has the item in her inventory or not. The third one is whether the
item is equipped or not.
The grappling beam and the X-Ray scope are special in that you must have
them in the inventory and be equipped for Samus to be able to use them. If
they are not equipped, they won't show up or be selectable.
These offsets, as well as almost all others, are specified in the format
offset:bit where the offset is the byte location from the start of the
game data and the bit is the bit number within the byte, from 0-7 starting
at the rightmost bit. For example, if you had a byte with the following
bit pattern: 10010110, then bit 0 is off and bit 7 is on.
---------------------------------------------------------------------------
Morphing Ball
0xB3:2, 0x2:2, 0x0:2
Bombs
0xB0:7, 0x3:4, 0x1:4
Spring Ball
0xC2:6, 0x2:1, 0x0:1
High Jump Boots
0xB6:5, 0x3:0, 0x1:0
Varia Suit
0xB6:0, 0x2:0, 0x0:0
Gravity Suit
0xC0:7, 0x2:5, 0x0:5
Speed Booster
0xB8:2, 0x3:5, 0x1:5
Space Jump
0xC3:2, 0x3:1, 0x1:1
Screw Attack
0xB9:7, 0x2:3, 0x0:3
Charge Beam
0xB2:7, 0x7:4, 0x5:4
Ice Beam
0xB6:2, 0x6:1, 0x4:1
Wave Beam
0xB8:4, 0x6:0, 0x4:0
Spazer
0xB5:2, 0x6:2, 0x4:2
Plasma Beam
0xC1:7, 0x6:3, 0x4:3
Grappling Beam
0xB7:4, 0x3:6, 0x1:6
X-Ray Scope
0xB4:6, 0x3:7, 0x1:7
---------------------------------------------------------------------------
The next set of bits list the bosses and mini-bosses in the game. For the
four major bosses (Kraid, Phantoon, Draygon, and Ridley), the first bit
is whether they have been defeated, and the second is whether their statue
has been broken in the Tourian Elevator room.
---------------------------------------------------------------------------
Silver Torizo
0x68:2
Spore Spawn
0x69:1
Kraid
0x69:0, 0x61:1
Phantoon
0x6B:0, 0x60:6
Botwoon
0x6C:1
Draygon
0x6C:0, 0x61:0
Crocomire
0x6A:1
Golden Torizo
0x6A:2
Ridley
0x6A:0, 0x60:7
---------------------------------------------------------------------------
The metroid rooms determine if one of the four rooms in Tourian with
metroids has been cleared or not. If the room is cleared, there will not
be metroids in it if you go back into that room.
---------------------------------------------------------------------------
Metroid Rooms
0x62:0
0x62:1
0x62:2
0x62:3
---------------------------------------------------------------------------
The Zebetites byte is a little confusing. First, only three bits are used,
and five values: 000, 001, 010, 011, and 100. Each value represents the
number of destroyed Zebetites, 0-4. You cannot specify an individual
Zebetite to destroy, only the total number destroyed.
To change the number, pick the zebetite number you want, left shift it by
3 and bitwise OR it into the offset byte. You must bitwise OR because there
are other bits in the same byte used for other purposes.
---------------------------------------------------------------------------
Zebetites
0x60
---------------------------------------------------------------------------
The next three bits are miscellaneous useful things I found.
Tourian Elevator: Whether the elevator to Tourian is present or not
Maridia Glass Tube Broken: Whether the glass tube is broken or not
Rescued Animals: Whether Samus rescued the Animals during her escape or not
---------------------------------------------------------------------------
Tourian Elevator
0x61:2
Maridia Glass Tube Broken
0x61:3
Rescued Animals
0x61:7
---------------------------------------------------------------------------
The missile packs, super missile packs, power bomb packs, energy tanks, and
reserve tanks determine whether the particular item has been taken or not.
These may be used in the item percent calculation at the end, but I haven't
tested this.
I do not know which bit corresponds to which item.
---------------------------------------------------------------------------
Crateria Missile Packs (8)
0xB0:1, 0xB0:2, 0xB0:3, 0xB0:4
0xB0:6, 0xB1:1, 0xB1:2, 0xB1:4
Brinstar Missile Packs (12)
0xB1:7, 0xB2:2, 0xB2:3, 0xB2:5
0xB2:6, 0xB3:1, 0xB3:4, 0xB4:2
0xB4:4, 0xB4:5, 0xB5:1, 0xB5:4
Norfair Missile Packs (15)
0xB6:1, 0xB6:3, 0xB6:6, 0xB6:7
0xB7:2, 0xB7:3, 0xB7:6, 0xB7:7
0xB8:0, 0xB8:1, 0xB8:3, 0xB8:6
0xB9:1, 0xB9:2, 0xB9:5
Wrecked Ship Missile Packs (3)
0xC0:0, 0xC0:2, 0xC0:3
Maridia Missile Packs (8)
0xC1:0, 0xC1:3, 0xC1:5, 0xC1:6
0xC2:0, 0xC2:2, 0xC2:4, 0xC2:7
Crateria Super Missile Packs (1)
0xB1:3
Brinstar Super Missile Packs (3)
0xB1:6, 0xB2:0, 0xB3:7
Norfair Super Missile Packs (1)
0xB8:7
Wrecked Ship Super Missile Packs (2)
0xC0:5, 0xC0:6
Maridia Super Missile Packs (3)
0xC1:1, 0xC1:4, 0xC2:5
Crateria Power Bomb Packs (1)
0xB0:0
Brinstar Power Bomb Packs (5)
0xB1:5, 0xB3:0, 0xB3:3, 0xB4:7,
0xB5:0
Norfair Power Bomb Packs (3)
0xB7:1, 0xB9:3, 0xB9:4
Maridia Power Bomb Packs (1)
0xC2:3
Crateria Energy Tanks (2)
0xB0:5, 0xB1:0
Brinstar Energy Tanks (5)
0xB3:5, 0xB3:6, 0xB4:1, 0xB4:3, 0xB5:3
Norfair Energy Tanks (4)
0xB6:4, 0xB7:0, 0xB9:6, 0xBA:0
Wrecked Ship Energy Tanks (1)
0xC0:4
Maridia Energy Tanks (2)
0xC1:2, 0xC3:0
Brinstar Reserve Tank
0xB2:1
Norfair Reserve Tank
0xB7:5
Wrecked Ship Reserve Tank
0xC0:1
Maridia Reserve Tank
0xC2:1
---------------------------------------------------------------------------
The door bits determine whether a door has been opened or not. I know some
doors, while others are unknown. I have put comments by all the doors I
know.
---------------------------------------------------------------------------
Crateria Red Doors (3)
0xF0:5 (Crateria Map)
0xF3:5 (Bombs)
0xF3:6 (Tourian Elevator)
Brinstar Red Doors (10)
0xF3:7
0xF4:0 (Brinstar Map)
0xF4:1
0xF4:2
0xF4:3
0xF4:6 (Brinstar Reserve Tank)
0xF5:2 (Spore Spawn)
0xF5:3
0xF6:2
0xF7:2 (X-Ray Scope)
Norfair Red Doors (7)
0xF9:2
0xF9:5 (High Jump Boots)
0xFA:1
0xFA:2
0xFA:5 (Speed Booster)
0xFA:6
0xFA:7 (Wave Beam)
Wrecked Ship Red Doors (1)
0x101:3 (Reserve Tank)
Maridia Red Doors (8)
0x101:4
0x101:5
0x101:6
0x102:0 (Maridia Map)
0x102:2
0x102:6
0x103:0
Tourian Red Doors (2)
0x104:7
0x105:1 (Mother Brain)
Crateria Green Doors (2)
0xF0:0
0xF1:4 (Wrecked Ship)
Brinstar Green Doors (10)
0xF5:1
0xF5:6 (Spore Spawn Exit)
0xF6:3
0xF6:4
0xF6:5
0xF7:0
0xF7:3
0xF7:5
0xF7:7 (Spazer)
0xF8:4
Norfair Green Doors (6)
0xF9:1
0xF9:3 (Ice Beam)
0xF9:6
0xFA:3
0xFA:4 (Speed Booster)
0xFB:7
Wrecked Ship Green Doors (1)
0x100:4
Maridia Green Doors (4)
0x101:7
0x102:4
0x102:5
0x103:2 (Draygon)
Crateria Yellow Doors (6)
0xF0:1
0xF1:5
0xF1:6
0xF1:7
0xF2:0
0xF2:3
Brinstar Yellow Doors (4)
0xF5:0
0xF6:0
0xF7:1 (X-Ray Scope)
0xF7:4
Norfair Yellow Doors (3)
0xF9:4 (Norfair Map)
0xFB:0
0xFB:6
Crateria Metal Doors (1)
0xF3:3 (Bombs Exit)
Brinstar Metal Doors (16)
0xF3:1 (Old Tourian Right)
0xF3:2 (Old Tourian Left)
0xF4:5 (Brinstar Map Exit)
0xF5:4
0xF5:5
0xF5:7
0xF6:1
0xF6:6
0xF6:7
0xF7:6
0xF8:0
0xF8:1
0xF8:2 (Mini-Kraid Right)
0xF8:3 (Mini-Kraid Left)
0xF8:6 (Varia Suit)
0xF8:7 (Kraid Exit)
Norfair Metal Doors (6)
0xF9:7 (Crocomire Exit)
0xFA:0 (High Jump Boots Exit)
0xFB:1 (Screw Attack)
0xFB:2 (Ridley Exit)
0xFB:3 (Ridley Left)
0xFC:0 (Gold Space Pirates)
Wrecked Ship Metal Doors (5)
0x100:3
0x100:6 (Phantoon Exit)
0x101:0
0x101:1
0x101:2
Maridia Metal Doors (7)
0x102:1 (Plasma Exit)
0x102:3 (Plasma)
0x102:7
0x103:4
0x103:5 (Botwoon Exit)
0x103:6 (Draygon Exit)
0x103:7 (Space Jump)
Tourian Metal Doors (5)
0x104:0
0x104:1
0x104:2
0x104:3
0x104:5 (Dust Chozo - Point of No Return)
Brinstar Eye Door (Kraid)
0xF8:5
Norfair Eye Door (Ridley)
0xFB:4
Wrecked Ship Eye Door (Phantoon)
0x100:5
Maridia Eye Door (Draygon)
0x103:3
Tourian Eye Door
0x105:0
---------------------------------------------------------------------------
The six area maps are simple. A value of 0 means you don't have the area
map, and a value of 0xFF means you do.
---------------------------------------------------------------------------
Crateria Map
0x148
Brinstar Map
0x149
Norfair Map
0x14A
Wrecked Ship Map
0x14B
Maridia Map
0x14C
Tourian Map
0x14D
---------------------------------------------------------------------------
The save point is slightly, but not overly complicated. The first offset
determines which area you are in. 0 = Crateria, 1 = Brinstar, 2 = Norfair,
3 = Wrecked Ship, 4 = Maridia, and 5 = Tourian. The second offset
determines which save point within the area you are at starting at.
There are 2 save points in Crateria, 5 in Brinstar, 6 in Norfair, 1 in the
Wrecked Ship, 4 in Maridia, and 2 in Tourian.
---------------------------------------------------------------------------
Save Spot
0x158 (Area)
0x156 (Point)
---------------------------------------------------------------------------
Game time determines how much time the game has been played for. The max
game time is 99 hours and 59 minutes, after which the game stops tracking
your time.
---------------------------------------------------------------------------
Game Time
0x3E (Hours)
0x3C (Minutes)
Shot Button
0x10
---------------------------------------------------------------------------
The controller configuration is slightly complicated. Each button is a
word (2 bytes), but you don't need to worry about converting to little
ending here, because each button value is simple.
A = 0x80, 0
B = 0, 0x80
X = 0x40, 0
Y = 0, 0x40
L = 0x20, 0
R = 0x10, 0
Select = 0, 0x20
Don't duplicate any buttons and remember that Angle Up/Down can only be
assigned to R/L. If you change this, the game will simply ignore it.
---------------------------------------------------------------------------
Jump Button
0x12
Dash Button
0x14
Item Cancel Button
0x16
Item Select Button
0x18
Angle Down Button
0x1A
Angle Up Button
0x1C
---------------------------------------------------------------------------
These last three bits are the other part of the game configuration. They
are pretty straightforward.
---------------------------------------------------------------------------
Language (English or Japanese)
0x40:0
Moon Walk (Off or On)
0x42:0
Icon Cancel (Manual or Automatic)
0x48:0
-------------------------------------------------------------------------------
| 4.3 The Sanity Algorithm
-------------------------------------------------------------------------------
The sanity algorithm, used to ensure the SRAM is still valid is not very
complex, but hard to calculate by hand. If you want to edit the SRAM, but
don't want to do sanity algorithm math, you can either use smse (see section
5.0) or edit the SRAM by hand and use my checksum repair program (see section
4.4) to fix the sanity values for you.
The sanity values are comprised of eight bytes. A primary checksum (2 bytes),
a checksum compliment (the checksum XOR 0xFF -- 2 bytes), and redundant
copies of each of these two values for a total of 8 bytes.
The game requires at least one checksum and one checksum compliment to be
correct for it to consider a game to be valid. If both checksums or both
compliments are invalid, the game is considered invalid and is not playable.
To calculate the checksum, you will need two counter variables. I will call
them low and high. Set the low and high counter to 0 initially. Now, take the
SRAM data for a single game and do the following:
1. For the current byte, add it to the high counter. If the counter exceeds
255, subtract 255 from the high counter and increment the low counter by
1.
2. Take the next byte and add it to the low counter. If the counter exceeds
255, subtract 255 from the low counter. Do NOT increment the high
counter.
Continue until you have added all the bytes (half to the high counter, and
half to the low counter). When you are done, you should have two bytes, the
high counter and the low counter. The high counter is the high byte of the
checksum word, and the low counter is the low byte of the checksum word.
For the compliment, simply take the XOR of 0xFF with each byte of the
checksum. The high and low byte XOR values becomes the compliment value.
The redundant values are simply copies of the checksum and the compliment.
The values should be put in the SRAM at the following offsets (these are from
the start of the SRAM).
0x0, 0x1 Checksum High/Low Bytes Game 1
0x8, 0x9 Compliment High/Low Bytes Game 1
0x1FF0, 0x1FF1 Checksum High/Low Bytes Game 1
0x1FF8, 0x1FF9 Compliment High/Low Bytes Game 1
Game 2 and 3 are the bytes following game 1.
-------------------------------------------------------------------------------
| 4.4 Checksum Repair Program (sanity.c)
-------------------------------------------------------------------------------
This is a small program in ANSI C that can be used to repair sanity values in
a Super Metroid SRAM file.
There are a couple minor problems with this program. First, no file
validation is performed. Any file with at least 0x2000 bytes will be
accepted and overwritten. Be carewhat what arguments you pass to this
program. Second, invalid games are fixed. This means games that were blank
will become valid games that are unplayable. Just be aware of this when you
start Super Metroid in Snes9x or ZSNES (or whatever SNES emulator you use).
If you see a game where Samus has 0 energy, the game is useless. Samus will
die as soon as the game begins.
This program is standard ANSI C and should compile on any operating system
with an ANSI C compiler. I have put a windows binary up at
http://games.technoplaza.net/smse/history/sanity.zip
To run the program, simply type ./sanity [SRAM file]. If you want to compile
the program and have gcc, you can do "gcc sanity.c -o sanity"
I don't think there are any bugs, but I tested it all of one time, so who
knows. Write me a letter if it doesn't work or compile or something.
/*
* Super Metroid SRAM Checksum Repair Program
* Copyright (C) 2005 emuWorks
* http://games.technoplaza.net/
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include <stdio.h>
void sanitize(char *sram) {
int game, i;
short high, low;
unsigned char value;
unsigned char hb, lb, hc, lc;
char *ptr;
for (game = 0; game < 3; ++game) {
ptr = (sram + 0x10 + (0x65C * game));
high = 0;
low = 0;
for (i = 0; i < 0x65C; ++i) {
value = ptr[i];
if ((high += value) > 0xFF) {
high &= 0xFF;
++low;
}
value = ptr[++i];
if ((low += value) > 0xFF) {
low &= 0xFF;
}
}
hb = (unsigned char)high;
lb = (unsigned char)low;
hc = (hb ^ 0xFF);
lc = (lb ^ 0xFF);
sram[game * 2] = hb;
sram[game * 2 + 1] = lb;
sram[8 + game * 2] = hc;
sram[8 + game * 2 + 1] = lc;
sram[0x1FF0 + game * 2] = hb;
sram[0x1FF0 + game * 2 + 1] = lb;
sram[0x1FF8 + game * 2] = hc;
sram[0x1FF8 + game * 2 + 1] = lc;
}
}
int main(int argc, char **argv) {
FILE *f;
char sram[0x2000];
if (argc != 2) {
fprintf(stderr, "syntax: sanity [Super Metroid SRAM File]\n");
return -1;
}
if ((f = fopen(argv[1], "rb")) == NULL) {
fprintf(stderr,
"error: unable to open Super Metroid SRAM file for reading\n");
return -1;
}
if (fread(sram, 0x2000, 1, f) != 1) {
fprintf(stderr, "error: invalid SRAM file\n");
return -1;
}
fclose(f);
sanitize(sram);
if ((f = fopen(argv[1], "wb")) == NULL) {
fprintf(stderr,
"error: unable to open Super Metroid SRAM file for writing\n");
return -1;
}
if (fwrite(sram, 0x2000, 1, f) != 1) {
fprintf(stderr, "error: unable to write SRAM data\n");
return -1;
}
fclose(f);
printf("successfully fixed sanity data in file: [%s]\n", argv[1]);
return 0;
}
-------------------------------------------------------------------------------
| 5.0 smse - The Super Metroid SRAM Editor
-------------------------------------------------------------------------------
If you really want to edit the SRAM, I recommend a program called 'smse', the
Super Metroid SRAM Editor. Not surprisingly, I wrote it.
It will edit any of the offsets I have outlined in this document an will
keep fix the sanity values for you so you don't need to. It's far simpler
than trying to edit by hand, unless you need to edit parts of the SRAM I
haven't documented.
If you want to try it out, head over to http://games.technoplaza.net/smse/.
It's free software under the GNU GPL, tested in Windows, Linux, and Mac OS X,
and is likely to run on almost any unix that support GTK+.
-------------------------------------------------------------------------------
| 6.0 Credits & Acknowledgements
-------------------------------------------------------------------------------
I want to thank phonymike for discovering and documenting the checksum
algorithm used by Super Metroid. In addition, I want to thank him for the
many offsets he discovered and documented in his original Metroid 3 editor.
-------------------------------------------------------------------------------
| 7.0 Contact Information
-------------------------------------------------------------------------------
The author (John Ratliff) can be contacted at
webmaster [AT] technoplaza [DOT] net. Replace as necessary.
I can also be reached via an online feedback form at
http://www.technoplaza.net/feedback.php