about summary refs log tree commit diff stats
diff options
context:
space:
mode:
authorFIX94 <fix94.1@gmail.com>2016-04-08 23:10:13 +0200
committerFIX94 <fix94.1@gmail.com>2016-04-08 23:10:13 +0200
commit2fdb5e638e023408697be8950e776e8f8ffd2590 (patch)
treeed9d04ded678e3e8af685221a8409d508455d918
parent95b6910184d576e64ace469b9845b96b5a1d9f2d (diff)
downloadgen3uploader-2fdb5e638e023408697be8950e776e8f8ffd2590.tar.gz
gen3uploader-2fdb5e638e023408697be8950e776e8f8ffd2590.tar.bz2
gen3uploader-2fdb5e638e023408697be8950e776e8f8ffd2590.zip
added experimental save support (only tested with EEPROM)
-rw-r--r--gba/source/libSave.c677
-rw-r--r--gba/source/libSave.h27
-rw-r--r--gba/source/main.c134
-rw-r--r--source/main.c231
4 files changed, 998 insertions, 71 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
diff --git a/gba/source/libSave.h b/gba/source/libSave.h new file mode 100644 index 0000000..5ecf822 --- /dev/null +++ b/gba/source/libSave.h
@@ -0,0 +1,27 @@
1
2
3//---------------------------------------------------------------------------------
4#ifdef __cplusplus
5extern "C" {
6#endif
7//---------------------------------------------------------------------------------
8
9void GetSave_EEPROM_512B(u8* data);
10void PutSave_EEPROM_512B(u8* data);
11void GetSave_EEPROM_8KB(u8* data);
12void PutSave_EEPROM_8KB(u8* data);
13void GetSave_SRAM_32KB(u8* data);
14void PutSave_SRAM_32KB(u8* data);
15void GetSave_FLASH_64KB(u8* data);
16void PutSave_FLASH_64KB(u8* foo);
17void GetSave_FLASH_128KB(u8* data);
18void PutSave_FLASH_128KB(u8* foo);
19
20u32 SaveSize(u8* data, s32 gamesize);
21
22
23//---------------------------------------------------------------------------------
24#ifdef __cplusplus
25} // extern "C"
26#endif
27//---------------------------------------------------------------------------------
diff --git a/gba/source/main.c b/gba/source/main.c index 9d05189..567165a 100644 --- a/gba/source/main.c +++ b/gba/source/main.c
@@ -7,12 +7,15 @@
7#include <gba_sio.h> 7#include <gba_sio.h>
8#include <stdio.h> 8#include <stdio.h>
9#include <stdlib.h> 9#include <stdlib.h>
10#include "libSave.h"
10 11
11u32 getGameSize(void) 12u8 save_data[0x20000] __attribute__ ((section (".sbss")));
13
14s32 getGameSize(void)
12{ 15{
13 if(*(vu32*)(0x08000004) != 0x51AEFF24) 16 if(*(vu32*)(0x08000004) != 0x51AEFF24)
14 return 0; 17 return -1;
15 u32 i; 18 s32 i;
16 for(i = (1<<20); i < (1<<25); i<<=1) 19 for(i = (1<<20); i < (1<<25); i<<=1)
17 { 20 {
18 vu16 *rompos = (vu16*)(0x08000000+i); 21 vu16 *rompos = (vu16*)(0x08000000+i);
@@ -30,6 +33,8 @@ u32 getGameSize(void)
30 } 33 }
31 return i; 34 return i;
32} 35}
36#define JOY_WRITE 2
37#define JOY_READ 4
33//--------------------------------------------------------------------------------- 38//---------------------------------------------------------------------------------
34// Program entry point 39// Program entry point
35//--------------------------------------------------------------------------------- 40//---------------------------------------------------------------------------------
@@ -49,43 +54,132 @@ int main(void) {
49 u32 i; 54 u32 i;
50 iprintf("\x1b[9;10HROM Dumper\n"); 55 iprintf("\x1b[9;10HROM Dumper\n");
51 iprintf("\x1b[10;5HPlease look at the TV\n"); 56 iprintf("\x1b[10;5HPlease look at the TV\n");
52 REG_HS_CTRL |= 6; 57 REG_HS_CTRL |= (JOY_WRITE|JOY_READ);
58 u32 prevIrqMask = REG_IME;
53 while (1) { 59 while (1) {
54 if((REG_HS_CTRL&4)) 60 if((REG_HS_CTRL&JOY_READ))
55 { 61 {
56 REG_HS_CTRL |= 4; 62 irqDisable(IRQ_VBLANK);
57 u32 gamesize = getGameSize(); 63 REG_IME = 0;
64 REG_HS_CTRL |= (JOY_WRITE|JOY_READ);
65 s32 gamesize = getGameSize();
66 u32 savesize = SaveSize(save_data,gamesize);
58 REG_JOYTR = gamesize; 67 REG_JOYTR = gamesize;
59 while((REG_HS_CTRL&4) == 0) ; 68 //wait for a cmd receive for safety
60 REG_HS_CTRL |= 4; 69 while((REG_HS_CTRL&JOY_WRITE) == 0) ;
61 if(gamesize == 0) 70 REG_HS_CTRL |= (JOY_WRITE|JOY_READ);
71 REG_JOYTR = savesize;
72 //wait for a cmd receive for safety
73 while((REG_HS_CTRL&JOY_WRITE) == 0) ;
74 REG_HS_CTRL |= (JOY_WRITE|JOY_READ);
75 if(gamesize == -1)
62 { 76 {
63 REG_JOYTR = 0; 77 REG_JOYTR = 0;
78 REG_IME = prevIrqMask;
79 irqEnable(IRQ_VBLANK);
64 continue; //nothing to read 80 continue; //nothing to read
65 } 81 }
66 //game in, send header 82 //game in, send header
67 for(i = 0; i < 0xC0; i+=4) 83 for(i = 0; i < 0xC0; i+=4)
68 { 84 {
69 REG_JOYTR = *(vu32*)(0x08000000+i); 85 REG_JOYTR = *(vu32*)(0x08000000+i);
70 while((REG_HS_CTRL&4) == 0) ; 86 while((REG_HS_CTRL&JOY_READ) == 0) ;
71 REG_HS_CTRL |= 4; 87 REG_HS_CTRL |= (JOY_WRITE|JOY_READ);
72 } 88 }
89 REG_JOYTR = 0;
73 //wait for other side to choose 90 //wait for other side to choose
74 while((REG_HS_CTRL&2) == 0) ; 91 while((REG_HS_CTRL&JOY_WRITE) == 0) ;
75 REG_HS_CTRL |= 2; 92 REG_HS_CTRL |= (JOY_WRITE|JOY_READ);
76 if(REG_JOYRE == 0) 93 u32 choseval = REG_JOYRE;
94 if(choseval == 0)
77 { 95 {
78 REG_JOYTR = 0; 96 REG_JOYTR = 0;
97 REG_IME = prevIrqMask;
98 irqEnable(IRQ_VBLANK);
79 continue; //nothing to read 99 continue; //nothing to read
80 } 100 }
81 //dump the game 101 else if(choseval == 1)
82 for(i = 0; i < gamesize; i+=4)
83 { 102 {
84 REG_JOYTR = *(vu32*)(0x08000000+i); 103 //dump the game
85 while((REG_HS_CTRL&4) == 0) ; 104 for(i = 0; i < gamesize; i+=4)
86 REG_HS_CTRL |= 4; 105 {
106 REG_JOYTR = *(vu32*)(0x08000000+i);
107 while((REG_HS_CTRL&JOY_READ) == 0) ;
108 REG_HS_CTRL |= (JOY_WRITE|JOY_READ);
109 }
110 }
111 else if(choseval == 2)
112 {
113 //backup save
114 switch (savesize){
115 case 0x200:
116 GetSave_EEPROM_512B(save_data);
117 break;
118 case 0x2000:
119 GetSave_EEPROM_8KB(save_data);
120 break;
121 case 0x8000:
122 GetSave_SRAM_32KB(save_data);
123 break;
124 case 0x10000:
125 GetSave_FLASH_64KB(save_data);
126 break;
127 case 0x20000:
128 GetSave_FLASH_128KB(save_data);
129 break;
130 default:
131 break;
132 }
133 REG_JOYTR = savesize;
134 //wait for a cmd receive for safety
135 while((REG_HS_CTRL&JOY_WRITE) == 0) ;
136 REG_HS_CTRL |= (JOY_WRITE|JOY_READ);
137 //send the save
138 for(i = 0; i < savesize; i+=4)
139 {
140 REG_JOYTR = *(vu32*)(save_data+i);
141 while((REG_HS_CTRL&JOY_READ) == 0) ;
142 REG_HS_CTRL |= (JOY_WRITE|JOY_READ);
143 }
144 }
145 else if(choseval == 3)
146 {
147 REG_JOYTR = savesize;
148 //receive the save
149 for(i = 0; i < savesize; i+=4)
150 {
151 while((REG_HS_CTRL&JOY_WRITE) == 0) ;
152 REG_HS_CTRL |= (JOY_WRITE|JOY_READ);
153 *(vu32*)(save_data+i) = REG_JOYRE;
154 }
155 //write it
156 switch (savesize){
157 case 0x200:
158 PutSave_EEPROM_512B(save_data);
159 break;
160 case 0x2000:
161 PutSave_EEPROM_8KB(save_data);
162 break;
163 case 0x8000:
164 PutSave_SRAM_32KB(save_data);
165 break;
166 case 0x10000:
167 PutSave_FLASH_64KB(save_data);
168 break;
169 case 0x20000:
170 PutSave_FLASH_128KB(save_data);
171 break;
172 default:
173 break;
174 }
175 REG_JOYTR = 0;
176 //wait for a cmd receive for safety
177 while((REG_HS_CTRL&JOY_WRITE) == 0) ;
178 REG_HS_CTRL |= (JOY_WRITE|JOY_READ);
87 } 179 }
88 REG_JOYTR = 0; 180 REG_JOYTR = 0;
181 REG_IME = prevIrqMask;
182 irqEnable(IRQ_VBLANK);
89 } 183 }
90 Halt(); 184 Halt();
91 } 185 }
diff --git a/source/main.c b/source/main.c index afe3423..ee23263 100644 --- a/source/main.c +++ b/source/main.c
@@ -23,7 +23,8 @@ void printmain()
23{ 23{
24 printf("\x1b[2J"); 24 printf("\x1b[2J");
25 printf("\x1b[37m"); 25 printf("\x1b[37m");
26 printf("GBA Link Cable Dumper v1.0 by FIX94\n"); 26 printf("GBA Link Cable Dumper v1.1 by FIX94\n");
27 printf("Save Support based on SendSave by Chishm\n");
27} 28}
28 29
29u8 *resbuf,*cmdbuf; 30u8 *resbuf,*cmdbuf;
@@ -299,9 +300,17 @@ int main(int argc, char *argv[])
299 { 300 {
300 if(recvsafe() == 0) //ready 301 if(recvsafe() == 0) //ready
301 { 302 {
302 sleep(1); //gba rom prepare 303 printf("Waiting for GBA\n");
303 u32 gbasize = __builtin_bswap32(recvsafe()); 304 VIDEO_WaitVSync();
304 if(gbasize == 0) 305 int gbasize = 0;
306 while(gbasize == 0)
307 gbasize = __builtin_bswap32(recvsafe());
308 sendsafe(0); //got gbasize
309 usleep(5000); //wait for it to set next val
310 u32 savesize = __builtin_bswap32(recvsafe());
311 sendsafe(0); //got savesize
312 usleep(5000); //wait for it to set next val
313 if(gbasize == -1)
305 { 314 {
306 printf("ERROR: No (Valid) GBA Card inserted!\n"); 315 printf("ERROR: No (Valid) GBA Card inserted!\n");
307 VIDEO_WaitVSync(); 316 VIDEO_WaitVSync();
@@ -309,29 +318,36 @@ int main(int argc, char *argv[])
309 sleep(2); 318 sleep(2);
310 continue; 319 continue;
311 } 320 }
321 //get rom header
312 for(i = 0; i < 0xC0; i+=4) 322 for(i = 0; i < 0xC0; i+=4)
313 *(vu32*)(testdump+i) = recvfast(); 323 *(vu32*)(testdump+i) = recvfast();
324 //print out all the info from the game
314 printf("Game Name: %.12s\n",(char*)(testdump+0xA0)); 325 printf("Game Name: %.12s\n",(char*)(testdump+0xA0));
315 printf("Game ID: %.4s\n",(char*)(testdump+0xAC)); 326 printf("Game ID: %.4s\n",(char*)(testdump+0xAC));
316 printf("Company ID: %.2s\n",(char*)(testdump+0xB0)); 327 printf("Company ID: %.2s\n",(char*)(testdump+0xB0));
317 printf("ROM Size: %02.02f MB\n \n",((float)(gbasize/1024))/1024.f); 328 printf("ROM Size: %02.02f MB\n",((float)(gbasize/1024))/1024.f);
329 if(savesize > 0)
330 printf("Save Size: %02.02f KB\n \n",((float)(savesize))/1024.f);
331 else
332 printf("No Save File\n \n");
333 //generate file paths
318 char gamename[64]; 334 char gamename[64];
319 sprintf(gamename,"/dumps/%.12s [%.4s%.2s].gba", 335 sprintf(gamename,"/dumps/%.12s [%.4s%.2s].gba",
320 (char*)(testdump+0xA0),(char*)(testdump+0xAC),(char*)(testdump+0xB0)); 336 (char*)(testdump+0xA0),(char*)(testdump+0xAC),(char*)(testdump+0xB0));
321 FILE *f = fopen(gamename,"rb"); 337 char savename[64];
322 if(f) 338 sprintf(savename,"/dumps/%.12s [%.4s%.2s].sav",
339 (char*)(testdump+0xA0),(char*)(testdump+0xAC),(char*)(testdump+0xB0));
340 //let the user choose the option
341 printf("Press A to dump this game, it will take about %i minutes.\n",gbasize/1024/1024*3/2);
342 printf("Press B if you want to cancel dumping this game.\n");
343 if(savesize > 0)
323 { 344 {
324 fclose(f); 345 printf("Press Y to backup this save file.\n");
325 sendsafe(0); 346 printf("Press X to restore this save file.\n\n");
326 printf("ERROR: Game already dumped! Please insert another game.\n");
327 VIDEO_WaitVSync();
328 VIDEO_WaitVSync();
329 sleep(2);
330 continue;
331 } 347 }
332 printf("Press A to dump this game, it will take about %i minutes.\n",gbasize/1024/1024*3/2); 348 else
333 printf("Press B if you want to cancel dumping this game.\n\n"); 349 printf("\n");
334 int dumping = 0; 350 int command = 0;
335 while(1) 351 while(1)
336 { 352 {
337 PAD_ScanPads(); 353 PAD_ScanPads();
@@ -341,56 +357,169 @@ int main(int argc, char *argv[])
341 endproc(); 357 endproc();
342 else if(btns&PAD_BUTTON_A) 358 else if(btns&PAD_BUTTON_A)
343 { 359 {
344 dumping = 1; 360 command = 1;
345 break; 361 break;
346 } 362 }
347 else if(btns&PAD_BUTTON_B) 363 else if(btns&PAD_BUTTON_B)
348 break; 364 break;
365 else if(savesize > 0)
366 {
367 if(btns&PAD_BUTTON_Y)
368 {
369 command = 2;
370 break;
371 }
372 else if(btns&PAD_BUTTON_X)
373 {
374 command = 3;
375 break;
376 }
377 }
349 } 378 }
350 sendsafe(dumping); 379 if(command == 1)
351 if(dumping == 0)
352 continue;
353 //create base file with size
354 printf("Creating file...\n");
355 int fd = open(gamename, O_WRONLY|O_CREAT);
356 if(fd >= 0)
357 { 380 {
358 ftruncate(fd, gbasize); 381 FILE *f = fopen(gamename,"rb");
359 close(fd); 382 if(f)
383 {
384 fclose(f);
385 command = 0;
386 printf("ERROR: Game already dumped!\n");
387 VIDEO_WaitVSync();
388 sleep(2);
389 }
360 } 390 }
361 f = fopen(gamename,"wb"); 391 else if(command == 2)
362 if(!f)
363 { 392 {
364 printf("ERROR: Could not create file! Exit...\n"); 393 FILE *f = fopen(savename,"rb");
365 VIDEO_WaitVSync(); 394 if(f)
366 VIDEO_WaitVSync(); 395 {
367 sleep(5); 396 fclose(f);
368 exit(0); 397 command = 0;
398 printf("ERROR: Save already backed up!\n");
399 VIDEO_WaitVSync();
400 sleep(2);
401 }
369 } 402 }
370 printf("Dumping...\n"); 403 else if(command == 3)
371 u32 bytes_read = 0;
372 while(gbasize > 0)
373 { 404 {
374 int toread = (gbasize > 0x400000 ? 0x400000 : gbasize); 405 size_t readsize = 0;
375 int j; 406 FILE *f = fopen(savename,"rb");
376 for(j = 0; j < toread; j+=4) 407 if(f)
377 { 408 {
378 *(vu32*)(testdump+j) = recvfast(); 409 fseek(f,0,SEEK_END);
379 bytes_read+=4; 410 readsize = ftell(f);
380 if((bytes_read&0xFFFF) == 0) 411 if(readsize != savesize)
381 { 412 {
382 printf("\r%02.02f MB done",(float)(bytes_read/1024)/1024.f); 413 command = 0;
414 printf("ERROR: Save has the wrong size, aborting restore!\n");
383 VIDEO_WaitVSync(); 415 VIDEO_WaitVSync();
416 sleep(2);
417 }
418 else
419 {
420 rewind(f);
421 fread(testdump,readsize,1,f);
422 }
423 fclose(f);
424 }
425 else
426 {
427 command = 0;
428 printf("ERROR: No Save to restore!\n");
429 VIDEO_WaitVSync();
430 sleep(2);
431 }
432 }
433 sendsafe(command);
434 usleep(5000); //wait for it to set next val
435 if(command == 0)
436 continue;
437 else if(command == 1)
438 {
439 //create base file with size
440 printf("Creating file...\n");
441 int fd = open(gamename, O_WRONLY|O_CREAT);
442 if(fd >= 0)
443 {
444 ftruncate(fd, gbasize);
445 close(fd);
446 }
447 FILE *f = fopen(gamename,"wb");
448 if(!f)
449 {
450 printf("ERROR: Could not create file! Exit...\n");
451 VIDEO_WaitVSync();
452 VIDEO_WaitVSync();
453 sleep(5);
454 exit(0);
455 }
456 printf("Dumping...\n");
457 u32 bytes_read = 0;
458 while(gbasize > 0)
459 {
460 int toread = (gbasize > 0x400000 ? 0x400000 : gbasize);
461 int j;
462 for(j = 0; j < toread; j+=4)
463 {
464 *(vu32*)(testdump+j) = recvfast();
465 bytes_read+=4;
466 if((bytes_read&0xFFFF) == 0)
467 {
468 printf("\r%02.02f MB done",(float)(bytes_read/1024)/1024.f);
469 VIDEO_WaitVSync();
470 }
384 } 471 }
385 //printf("%02x%02x%02x%02x",resbuf[0],resbuf[1],resbuf[2],resbuf[3]); 472 fwrite(testdump,toread,1,f);
473 gbasize -= toread;
474 }
475 printf("\nClosing file\n");
476 fclose(f);
477 printf("Game dumped!\n");
478 sleep(5);
479 }
480 else if(command == 2)
481 {
482 FILE *f = fopen(savename,"wb");
483 if(!f)
484 {
485 printf("ERROR: Could not create file! Exit...\n");
486 VIDEO_WaitVSync();
487 VIDEO_WaitVSync();
488 sleep(5);
489 exit(0);
386 } 490 }
387 fwrite(testdump,toread,1,f); 491 printf("Waiting for GBA\n");
388 gbasize -= toread; 492 VIDEO_WaitVSync();
493 u32 readval = 0;
494 while(readval != savesize)
495 readval = __builtin_bswap32(recvsafe());
496 sendsafe(0); //got savesize
497 usleep(5000); //wait for it to set next val
498 printf("Receiving...\n");
499 for(i = 0; i < savesize; i+=4)
500 *(vu32*)(testdump+i) = recvsafe();
501 printf("Writing save...\n");
502 fwrite(testdump,savesize,1,f);
503 fclose(f);
504 printf("Save backed up!\n");
505 sleep(5);
506 }
507 else if(command == 3)
508 {
509 printf("Sending save\n");
510 VIDEO_WaitVSync();
511 u32 readval = 0;
512 while(readval != savesize)
513 readval = __builtin_bswap32(recvsafe());
514 for(i = 0; i < savesize; i+=4)
515 sendsafe(__builtin_bswap32(*(vu32*)(testdump+i)));
516 printf("Waiting for GBA\n");
517 while(recvsafe() != 0)
518 VIDEO_WaitVSync();
519 printf("Save restored!\n");
520 sendsafe(0);
521 sleep(5);
389 } 522 }
390 printf("\nClosing file\n");
391 fclose(f);
392 printf("Game dumped!\n");
393 sleep(5);
394 } 523 }
395 } 524 }
396 } 525 }