about summary refs log tree commit diff stats
path: root/gba/source/libSave.c
diff options
context:
space:
mode:
Diffstat (limited to 'gba/source/libSave.c')
-rw-r--r--gba/source/libSave.c677
1 files changed, 677 insertions, 0 deletions
diff --git a/gba/source/libSave.c b/gba/source/libSave.c new file mode 100644 index 0000000..1ae8162 --- /dev/null +++ b/gba/source/libSave.c
@@ -0,0 +1,677 @@
1/*
2 libSave
3 Cartridge backup memory save routines. To use, call the required
4 routine with a pointer to an appropriately sized array of data to
5 be read from or written to the cartridge.
6 Data types are from wintermute's gba_types.h libgba library.
7*/
8
9#include <stdio.h>
10#include <stdlib.h>
11#include <string.h>
12//---------------------------------------------------------------------------------
13#ifndef _gba_types_h_
14#define _gba_types_h_
15//---------------------------------------------------------------------------------
16
17//---------------------------------------------------------------------------------
18// Data types
19//---------------------------------------------------------------------------------
20/** Unsigned 8 bit value
21
22*/
23typedef unsigned char u8;
24/** Unsigned 16 bit value
25
26*/
27typedef unsigned short int u16;
28/** Unsigned 32 bit value
29
30*/
31typedef unsigned int u32;
32
33/** signed 8 bit value
34
35*/
36typedef signed char s8;
37/** Signed 16 bit value
38
39*/
40typedef signed short int s16;
41/** Signed 32 bit value
42
43*/
44typedef signed int s32;
45
46/** Unsigned volatile 8 bit value
47
48*/
49typedef volatile u8 vu8;
50/** Unsigned volatile 16 bit value
51
52*/
53typedef volatile u16 vu16;
54/** Unsigned volatile 32 bit value
55
56*/
57typedef volatile u32 vu32;
58
59/** Unsigned volatile 8 bit value
60
61*/
62typedef volatile s8 vs8;
63/** Signed volatile 16 bit value
64
65*/
66typedef volatile s16 vs16;
67/** Signed volatile 32 bit value
68
69*/
70typedef volatile s32 vs32;
71
72#ifndef __cplusplus
73/** C++ compatible bool for C
74
75*/
76typedef enum { false, true } bool;
77#endif
78
79//---------------------------------------------------------------------------------
80#endif // data types
81//---------------------------------------------------------------------------------
82
83
84#define EEPROM_ADDRESS (volatile u16*)0xDFFFF00
85#define SRAM_ADDRESS (volatile u16*)0x0E000000
86#define FLASH_1M_ADDRESS (volatile u16*)0x09FE0000
87#define REG_EEPROM (*(volatile u16*)0xDFFFF00)
88#define REG_DM3SAD (*(volatile u32*)0x40000D4)
89#define REG_DM3DAD (*(volatile u32*)0x40000D8)
90#define REG_DM3CNT (*(volatile u32*)0x40000DC)
91
92
93//-----------------------------------------------------------------------
94// Common EEPROM Routines
95//-----------------------------------------------------------------------
96
97void EEPROM_SendPacket( u16* packet, int size )
98{
99 REG_DM3SAD = (u32)packet;
100 REG_DM3DAD = (u32)EEPROM_ADDRESS;
101 REG_DM3CNT = 0x80000000 + size;
102}
103
104void EEPROM_ReceivePacket( u16* packet, int size )
105{
106 REG_DM3SAD = (u32)EEPROM_ADDRESS;
107 REG_DM3DAD = (u32)packet;
108 REG_DM3CNT = 0x80000000 + size;
109}
110
111//-----------------------------------------------------------------------
112// Routines for 512B EEPROM
113//-----------------------------------------------------------------------
114
115void EEPROM_Read_512B( volatile u8 offset, u8* dest ) // dest must point to 8 bytes
116{
117 u16 packet[68];
118 u8* out_pos;
119 u16* in_pos;
120 u8 out_byte;
121 int byte, bit;
122
123 memset( packet, 0, 68*2 );
124
125 // Read request
126 packet[0] = 1;
127 packet[1] = 1;
128
129 // 6 bits eeprom address (MSB first)
130 packet[2] = (offset>>5)&1;
131 packet[3] = (offset>>4)&1;
132 packet[4] = (offset>>3)&1;
133 packet[5] = (offset>>2)&1;
134 packet[6] = (offset>>1)&1;
135 packet[7] = (offset)&1;
136
137 // End of request
138 packet[8] = 0;
139
140 // Do transfers
141 EEPROM_SendPacket( packet, 9 );
142 memset( packet, 0, 68*2 );
143 EEPROM_ReceivePacket( packet, 68 );
144
145 // Extract data
146 in_pos = &packet[4];
147 out_pos = dest;
148 for( byte = 7; byte >= 0; --byte )
149 {
150 out_byte = 0;
151 for( bit = 7; bit >= 0; --bit )
152 {
153// out_byte += (*in_pos++)<<bit;
154 out_byte += ((*in_pos++)&1)<<bit;
155 }
156 *out_pos++ = out_byte ;
157 }
158}
159
160void EEPROM_Write_512B( volatile u8 offset, u8* source ) // source must point to 8 bytes
161{
162 u16 packet[73];
163 u8* in_pos;
164 u16* out_pos;
165 u8 in_byte;
166 int byte, bit;
167
168 memset( packet, 0, 73*2 );
169
170 // Write request
171 packet[0] = 1;
172 packet[1] = 0;
173
174 // 6 bits eeprom address (MSB first)
175 packet[2] = (offset>>5)&1;
176 packet[3] = (offset>>4)&1;
177 packet[4] = (offset>>3)&1;
178 packet[5] = (offset>>2)&1;
179 packet[6] = (offset>>1)&1;
180 packet[7] = (offset)&1;
181
182 // Extract data
183 in_pos = source;
184 out_pos = &packet[8];
185 for( byte = 7; byte >= 0; --byte )
186 {
187 in_byte = *in_pos++;
188 for( bit = 7; bit >= 0; --bit )
189 {
190 *out_pos++ = in_byte>>bit;
191 }
192 }
193
194 // End of request
195 packet[72] = 0;
196
197 // Do transfers
198 EEPROM_SendPacket( packet, 73 );
199
200 // Wait for EEPROM to finish (should timeout after 10 ms)
201 while( (REG_EEPROM & 1) == 0 );
202}
203
204//---------------------------------------------------------------------------------
205void GetSave_EEPROM_512B(u8* data)
206//---------------------------------------------------------------------------------
207{
208 volatile u8 x;
209 u32 sleep;
210
211 // Set up waitstates for EEPROM access etc.
212 *(volatile unsigned short *)0x04000204 = 0x4317;
213
214 for (x=0;x<64;++x){
215 EEPROM_Read_512B(x,&data[x*8]);
216 for(sleep=0;sleep<512000;sleep++);
217 }
218}
219
220//---------------------------------------------------------------------------------
221void PutSave_EEPROM_512B(u8* data)
222//---------------------------------------------------------------------------------
223{
224 volatile u8 x;
225 u32 sleep;
226
227 // Set up waitstates for EEPROM access etc.
228 *(volatile unsigned short *)0x04000204 = 0x4317;
229
230 for (x=0;x<64;x++){
231 EEPROM_Write_512B(x,&data[x*8]);
232 for(sleep=0;sleep<512000;sleep++);
233 }
234}
235//-----------------------------------------------------------------------
236// Routines for 8KB EEPROM
237//-----------------------------------------------------------------------
238
239void EEPROM_Read_8KB( volatile u16 offset, u8* dest ) // dest must point to 8 bytes
240{
241 u16 packet[68];
242 u8* out_pos;
243 u16* in_pos;
244 u8 out_byte;
245 int byte, bit;
246
247 memset( packet, 0, 68*2 );
248
249 // Read request
250 packet[0] = 1;
251 packet[1] = 1;
252
253 // 14 bits eeprom address (MSB first)
254 packet[2] = (offset>>13)&1;
255 packet[3] = (offset>>12)&1;
256 packet[4] = (offset>>11)&1;
257 packet[5] = (offset>>10)&1;
258 packet[6] = (offset>>9)&1;
259 packet[7] = (offset>>8)&1;
260 packet[8] = (offset>>7)&1;
261 packet[9] = (offset>>6)&1;
262 packet[10] = (offset>>5)&1;
263 packet[11] = (offset>>4)&1;
264 packet[12] = (offset>>3)&1;
265 packet[13] = (offset>>2)&1;
266 packet[14] = (offset>>1)&1;
267 packet[15] = (offset)&1;
268
269 // End of request
270 packet[16] = 0;
271
272 // Do transfers
273 EEPROM_SendPacket( packet, 17 );
274 memset( packet, 0, 68*2 );
275 EEPROM_ReceivePacket( packet, 68 );
276
277 // Extract data
278 in_pos = &packet[4];
279 out_pos = dest;
280 for( byte = 7; byte >= 0; --byte )
281 {
282 out_byte = 0;
283 for( bit = 7; bit >= 0; --bit )
284 {
285// out_byte += (*in_pos++)<<bit;
286 out_byte += ((*in_pos++)&1)<<bit;
287 }
288 *out_pos++ = out_byte;
289 }
290
291}
292
293void EEPROM_Write_8KB( volatile u16 offset, u8* source ) // source must point to 8 bytes
294{
295 u16 packet[81];
296 u8* in_pos;
297 u16* out_pos;
298 u8 in_byte;
299 int byte, bit;
300
301 memset( packet, 0, 81*2 );
302
303 // Write request
304 packet[0] = 1;
305 packet[1] = 0;
306
307 // 14 bits eeprom address (MSB first)
308 packet[2] = (offset>>13)&1;
309 packet[3] = (offset>>12)&1;
310 packet[4] = (offset>>11)&1;
311 packet[5] = (offset>>10)&1;
312 packet[6] = (offset>>9)&1;
313 packet[7] = (offset>>8)&1;
314 packet[8] = (offset>>7)&1;
315 packet[9] = (offset>>6)&1;
316 packet[10] = (offset>>5)&1;
317 packet[11] = (offset>>4)&1;
318 packet[12] = (offset>>3)&1;
319 packet[13] = (offset>>2)&1;
320 packet[14] = (offset>>1)&1;
321 packet[15] = (offset)&1;
322
323 // Extract data
324 in_pos = source;
325 out_pos = &packet[16];
326 for( byte = 7; byte >= 0; --byte )
327 {
328 in_byte = *in_pos++;
329 for( bit = 7; bit >= 0; --bit )
330 {
331 *out_pos++ = (in_byte>>bit)&1;
332 }
333 }
334
335 // End of request
336 packet[80] = 0;
337
338 // Do transfers
339 EEPROM_SendPacket( packet, 81 );
340
341 // Wait for EEPROM to finish (should timeout after 10 ms)
342 while( (REG_EEPROM & 1) == 0 );
343}
344
345//---------------------------------------------------------------------------------
346void GetSave_EEPROM_8KB(u8* data)
347//---------------------------------------------------------------------------------
348{
349 volatile u16 x;
350 u32 sleep;
351
352 // Set up waitstates for EEPROM access etc.
353 *(volatile unsigned short *)0x04000204 = 0x4317;
354
355 for (x=0;x<1024;x++){
356 EEPROM_Read_8KB(x,&data[x*8]);
357 for(sleep=0;sleep<512000;sleep++);
358 }
359
360}
361
362//---------------------------------------------------------------------------------
363void PutSave_EEPROM_8KB(u8* data)
364//---------------------------------------------------------------------------------
365{
366 volatile u16 x;
367 u32 sleep;
368
369 // Set up waitstates for EEPROM access etc.
370 *(volatile unsigned short *)0x04000204 = 0x4317;
371
372 for (x=0;x<1024;x++){
373 EEPROM_Write_8KB(x,&data[x*8]);
374 for(sleep=0;sleep<512000;sleep++);
375 }
376}
377
378//---------------------------------------------------------------------------------
379void GetSave_SRAM_32KB(u8* data)
380//---------------------------------------------------------------------------------
381{
382 volatile u8 *sram= (u8*) 0x0E000000;
383 volatile u16 x;
384
385 for (x = 0; x < 0x8000; ++x)
386 {
387 data[x] = sram[x];
388 }
389
390}
391
392//---------------------------------------------------------------------------------
393void PutSave_SRAM_32KB(u8* data)
394//---------------------------------------------------------------------------------
395{
396 volatile u8 *sram= (u8*) 0x0E000000;
397 volatile u16 x;
398
399 for (x = 0; x < 0x8000; ++x)
400 {
401 sram[x] = data[x];
402 }
403}
404
405//---------------------------------------------------------------------------------
406void GetSave_FLASH_64KB(u8* data)
407//---------------------------------------------------------------------------------
408{
409 volatile u8 *sram= (u8*) 0x0E000000;
410 volatile u32 x;
411
412 for (x = 0; x < 0x10000; ++x)
413 {
414 data[x] = sram[x];
415 }
416}
417
418//---------------------------------------------------------------------------------
419void PutSave_FLASH_64KB(u8* foo)
420//---------------------------------------------------------------------------------
421{
422 volatile u8 *fctrl0 = (u8*) 0xE005555;
423 volatile u8 *fctrl1 = (u8*) 0xE002AAA;
424 volatile u8 *fctrl2 = (u8*) 0xE000000;
425
426 //init flash
427 *fctrl0 = 0xAA;
428 *fctrl1 = 0x55;
429 *fctrl0 = 0x90;
430 *fctrl2 = 0xF0;
431
432 //erase chip
433 *fctrl0 = 0xAA;
434 *fctrl1 = 0x55;
435 *fctrl0 = 0x80;
436 *fctrl0 = 0xAA;
437 *fctrl1 = 0x55;
438 *fctrl0 = 0x10;
439
440 //wait for erase done
441 u8 val1;
442 u8 val2;
443 val1 = *fctrl2;
444 val2 = *fctrl2;
445 while (val1 != val2) {
446 val1 = *fctrl2;
447 val2 = *fctrl2;
448 }
449 val1 = *fctrl2;
450 val2 = *fctrl2;
451 while (val1 != val2) {
452 val1 = *fctrl2;
453 val2 = *fctrl2;
454 }
455
456 volatile u8 *data = fctrl2;
457 u32 i;
458 //write data
459 for (i=0; i<65536; i++) {
460 *fctrl0 = 0xAA;
461 *fctrl1 = 0x55;
462 *fctrl0 = 0xA0;
463 data [i] = foo [ i ];
464 val1 = data [ i ];
465 val2 = data [ i ];
466
467 while (val1 != val2) {
468 val1 = data [ i ];
469 val2 = data [ i ];
470 }
471 val1 = data [ i ];
472 val2 = data [ i ];
473 while (val1 != val2) {
474 val1 = data [ i ];
475 val2 = data [ i ];
476 }
477 val1 = data [ i ];
478 val2 = data [ i ];
479 while (val1 != val2) {
480 val1 = data [ i ];
481 val2 = data [ i ];
482 }
483 }
484}
485
486//---------------------------------------------------------------------------------
487void GetSave_FLASH_128KB(u8* data)
488//---------------------------------------------------------------------------------
489{
490 const u32 size = 0x10000;
491
492 volatile u8 *fctrl0 = (u8*) 0xE005555;
493 volatile u8 *fctrl1 = (u8*) 0xE002AAA;
494 volatile u8 *fctrl2 = (u8*) 0xE000000;
495 volatile u32 i;
496 volatile u8 *sram= (u8*) 0x0E000000;
497
498 //init flash
499 *fctrl0 = 0xAA;
500 *fctrl1 = 0x55;
501 *fctrl0 = 0x90;
502 *fctrl2 = 0xF0;
503
504 // read first bank
505 *fctrl0 = 0xAA;
506 *fctrl1 = 0x55;
507 *fctrl0 = 0xB0;
508 *fctrl2 = 0x00;
509
510 for (i=0; i<size; i++){
511 data[i] = sram[i];
512 }
513
514 // read second bank
515 *fctrl0 = 0xAA;
516 *fctrl1 = 0x55;
517 *fctrl0 = 0xB0;
518 *fctrl2 = 0x01;
519
520 for (i=0; i<size; i++){
521 data[i + size] = sram[i];
522 }
523
524}
525
526//---------------------------------------------------------------------------------
527void PutSave_FLASH_128KB(u8* foo)
528//---------------------------------------------------------------------------------
529{
530 volatile u8 *fctrl0 = (u8*) 0xE005555;
531 volatile u8 *fctrl1 = (u8*) 0xE002AAA;
532 volatile u8 *fctrl2 = (u8*) 0xE000000;
533
534 u8 val1;
535 u8 val2;
536
537 //init flash
538 *fctrl0 = 0xAA;
539 *fctrl1 = 0x55;
540 *fctrl0 = 0x90;
541 *fctrl2 = 0xF0;
542
543 //erase chip
544 *fctrl0 = 0xAA;
545 *fctrl1 = 0x55;
546 *fctrl0 = 0x80;
547 *fctrl0 = 0xAA;
548 *fctrl1 = 0x55;
549 *fctrl0 = 0x10;
550
551 //wait for erase done
552 val1 = *fctrl2;
553 val2 = *fctrl2;
554 while (val1 != val2) {
555 val1 = *fctrl2;
556 val2 = *fctrl2;
557 }
558 val1 = *fctrl2;
559 val2 = *fctrl2;
560 while (val1 != val2) {
561 val1 = *fctrl2;
562 val2 = *fctrl2;
563 }
564
565 volatile u8 *data = fctrl2;
566 volatile u32 i;
567 // change to bank 0
568 *fctrl0 = 0xAA;
569 *fctrl1 = 0x55;
570 *fctrl0 = 0xB0;
571 *fctrl2 = 0x00;
572
573 //write data
574 for (i=0; i<65536; i++) {
575 *fctrl0 = 0xAA;
576 *fctrl1 = 0x55;
577 *fctrl0 = 0xA0;
578 data [i] = foo [ i ];
579 val1 = data [ i ];
580 val2 = data [ i ];
581
582 while (val1 != val2) {
583 val1 = data [ i ];
584 val2 = data [ i ];
585 }
586 val1 = data [ i ];
587 val2 = data [ i ];
588 while (val1 != val2) {
589 val1 = data [ i ];
590 val2 = data [ i ];
591 }
592 val1 = data [ i ];
593 val2 = data [ i ];
594 while (val1 != val2) {
595 val1 = data [ i ];
596 val2 = data [ i ];
597 }
598 }
599
600 // Change to bank 1
601 *fctrl0 = 0xAA;
602 *fctrl1 = 0x55;
603 *fctrl0 = 0xB0;
604 *fctrl2 = 0x01;
605
606 //write data
607 for (i=0; i<65536; i++) {
608 *fctrl0 = 0xAA;
609 *fctrl1 = 0x55;
610 *fctrl0 = 0xA0;
611 data [i] = foo [ i + 0x10000];
612 val1 = data [ i ];
613 val2 = data [ i ];
614
615 while (val1 != val2) {
616 val1 = data [ i ];
617 val2 = data [ i ];
618 }
619 val1 = data [ i ];
620 val2 = data [ i ];
621 while (val1 != val2) {
622 val1 = data [ i ];
623 val2 = data [ i ];
624 }
625 val1 = data [ i ];
626 val2 = data [ i ];
627 while (val1 != val2) {
628 val1 = data [ i ];
629 val2 = data [ i ];
630 }
631 }
632
633}
634
635//---------------------------------------------------------------------------------
636u32 SaveSize(u8* data, s32 gamesize)
637//---------------------------------------------------------------------------------
638{
639 if(gamesize < 0)
640 return 0;
641
642 u32 *pak= ((u32*)0x08000000);
643 s32 x;
644 s32 size = gamesize/4;
645
646
647 for (x=size-1;x>=0;x--){
648 switch (pak[x]) {
649 case 0x53414C46:
650 if (pak[x+1] == 0x5F4D3148){
651 return 0x20000; // FLASH_128KB
652 } else if ((pak[x+1] & 0x0000FFFF) == 0x00005F48){
653 return 0x10000; // FLASH_64KB
654 } else if (pak[x+1] == 0x32313548){
655 return 0x10000; // FLASH_64KB
656 }
657 break;
658 case 0x52504545:
659 if ((pak[x+1] & 0x00FFFFFF) == 0x005F4D4F){
660 GetSave_EEPROM_8KB(data);
661 if (memcmp(data,data+0x200,8) != 0 ||
662 memcmp(data,data+0x400,8) != 0 ||
663 memcmp(data,data+0x600,8) != 0){
664 return 0x2000; //EEPROM_8KB
665 }
666 return 0x200; // EEPROM_512B
667 }
668 break;
669 case 0x4D415253:
670 if ((pak[x+1] & 0x000000FF) == 0x0000005F){
671 return 0x8000; // SRAM_32KB
672 }
673 }
674 }
675 return 0;
676}
677