about summary refs log tree commit diff stats
diff options
context:
space:
mode:
authorKelly Rauchenberger <fefferburbia@gmail.com>2017-07-11 16:37:21 -0400
committerKelly Rauchenberger <fefferburbia@gmail.com>2017-07-11 16:37:21 -0400
commit57afb4058710a978bd7b07a368125d04378c62f1 (patch)
tree7a06f1679f0612c58d5a209a013261ff5ad6cb82
parent004575f7cec14946c1936aceca6efee38b7f8a74 (diff)
downloadgen3uploader-57afb4058710a978bd7b07a368125d04378c62f1.tar.gz
gen3uploader-57afb4058710a978bd7b07a368125d04378c62f1.tar.bz2
gen3uploader-57afb4058710a978bd7b07a368125d04378c62f1.zip
started tweaking with stuff
-rw-r--r--.gitignore7
-rw-r--r--build.bat2
-rwxr-xr-xbuild.sh11
-rw-r--r--gba/Makefile12
-rw-r--r--gba/gba_pkjb.ld296
-rw-r--r--gba/gba_pkjb.specs8
-rw-r--r--gba/source/gamedata.c534
-rw-r--r--gba/source/gamedata.h22
-rw-r--r--gba/source/link.c41
-rw-r--r--gba/source/link.h12
-rw-r--r--gba/source/main.c592
-rw-r--r--gba/source/saveblocks.h343
-rw-r--r--gba/source/savestructs.h793
-rw-r--r--gba/start/pkjb_crt0.s102
-rw-r--r--source/link.c16
-rw-r--r--source/link.h8
-rw-r--r--source/main.c1287
17 files changed, 3415 insertions, 671 deletions
diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..ac7cf98 --- /dev/null +++ b/.gitignore
@@ -0,0 +1,7 @@
1*.elf
2build
3data
4*.dol
5tags
6*.o
7*.d
diff --git a/build.bat b/build.bat index aece78f..c962421 100644 --- a/build.bat +++ b/build.bat
@@ -7,4 +7,4 @@ make -f Makefile.gc clean
7make -f Makefile.gc 7make -f Makefile.gc
8make -f Makefile.wii clean 8make -f Makefile.wii clean
9make -f Makefile.wii 9make -f Makefile.wii
10pause \ No newline at end of file 10pause
diff --git a/build.sh b/build.sh new file mode 100755 index 0000000..b521d27 --- /dev/null +++ b/build.sh
@@ -0,0 +1,11 @@
1#!/bin/bash
2cd gba
3make clean
4make
5cd ..
6mkdir data
7mv -f gba/gba_pkjb.gba data/gba_mb.gba
8make -f Makefile.gc clean
9make -f Makefile.gc
10make -f Makefile.wii clean
11make -f Makefile.wii
diff --git a/gba/Makefile b/gba/Makefile index 99dfbb6..e417104 100644 --- a/gba/Makefile +++ b/gba/Makefile
@@ -7,6 +7,10 @@ ifeq ($(strip $(DEVKITARM)),)
7$(error "Please set DEVKITARM in your environment. export DEVKITARM=<path to>devkitARM) 7$(error "Please set DEVKITARM in your environment. export DEVKITARM=<path to>devkitARM)
8endif 8endif
9 9
10%_pkjb.elf:
11 @echo linking pkjb
12 $(LD) -specs=../gba_pkjb.specs $(LDFLAGS) $(OFILES) $(LIBPATHS) $(LIBS) -o $@
13
10include $(DEVKITARM)/gba_rules 14include $(DEVKITARM)/gba_rules
11 15
12#--------------------------------------------------------------------------------- 16#---------------------------------------------------------------------------------
@@ -16,7 +20,7 @@ include $(DEVKITARM)/gba_rules
16# DATA is a list of directories containing data files 20# DATA is a list of directories containing data files
17# INCLUDES is a list of directories containing header files 21# INCLUDES is a list of directories containing header files
18#--------------------------------------------------------------------------------- 22#---------------------------------------------------------------------------------
19TARGET := $(shell basename $(CURDIR))_mb 23TARGET := $(shell basename $(CURDIR))_pkjb
20BUILD := build 24BUILD := build
21SOURCES := source 25SOURCES := source
22DATA := 26DATA :=
@@ -29,6 +33,7 @@ INCLUDES :=
29ARCH := -mthumb -mthumb-interwork 33ARCH := -mthumb -mthumb-interwork
30 34
31CFLAGS := -g -Wall -O3\ 35CFLAGS := -g -Wall -O3\
36 -Wno-multichar\
32 -mcpu=arm7tdmi -mtune=arm7tdmi\ 37 -mcpu=arm7tdmi -mtune=arm7tdmi\
33 -fomit-frame-pointer\ 38 -fomit-frame-pointer\
34 -ffast-math \ 39 -ffast-math \
@@ -38,8 +43,8 @@ CFLAGS += $(INCLUDE)
38 43
39CXXFLAGS := $(CFLAGS) -fno-rtti -fno-exceptions 44CXXFLAGS := $(CFLAGS) -fno-rtti -fno-exceptions
40 45
41ASFLAGS := $(ARCH) 46ASFLAGS := -g $(ARCH)
42LDFLAGS = -g $(ARCH) -Wl,-Map,$(notdir $@).map 47LDFLAGS = $(ARCH) -Wl,-Map,$(notdir $@).map
43 48
44#--------------------------------------------------------------------------------- 49#---------------------------------------------------------------------------------
45# any extra libraries we wish to link with the project 50# any extra libraries we wish to link with the project
@@ -109,6 +114,7 @@ export LIBPATHS := $(foreach dir,$(LIBDIRS),-L$(dir)/lib)
109#--------------------------------------------------------------------------------- 114#---------------------------------------------------------------------------------
110$(BUILD): 115$(BUILD):
111 @[ -d $@ ] || mkdir -p $@ 116 @[ -d $@ ] || mkdir -p $@
117 $(CC) -MMD -MP -MF start/pkjb_crt0.d -x assembler-with-cpp $(ASFLAGS) -c start/pkjb_crt0.s -o start/pkjb_crt0.o $(ERROR_FILTER)
112 @make --no-print-directory -C $(BUILD) -f $(CURDIR)/Makefile 118 @make --no-print-directory -C $(BUILD) -f $(CURDIR)/Makefile
113 119
114all : $(BUILD) 120all : $(BUILD)
diff --git a/gba/gba_pkjb.ld b/gba/gba_pkjb.ld new file mode 100644 index 0000000..102cb42 --- /dev/null +++ b/gba/gba_pkjb.ld
@@ -0,0 +1,296 @@
1/* Linker Script Original v1.3 by Jeff Frohwein */
2/* v1.0 - Original release */
3/* v1.1 - Added proper .data section support */
4/* v1.2 - Added support for c++ & iwram overlays */
5/* - Major contributions by Jason Wilkins. */
6/* v1.3 - .ewram section now can be used when */
7/* compiling for MULTIBOOT mode. This fixes */
8/* malloc() in DevKitAdvance which depends */
9/* on __eheap_start instead of end to define*/
10/* the starting location of heap space. */
11/* External global variable __gba_iwram_heap*/
12/* support added to allow labels end, _end, */
13/* & __end__ to point to end of iwram or */
14/* the end of ewram. */
15/* Additions by WinterMute */
16/* v1.4 - .sbss section added for unitialised */
17/* data in ewram */
18/* v1.5 - padding section added to stop EZF */
19/* stripping important data */
20/* v1.6 - added memory sections */
21
22/* This file is released into the public domain */
23/* for commercial or non-commercial use with no */
24/* restrictions placed upon it. */
25
26/* NOTE!!!: This linker script defines the RAM & */
27/* ROM start addresses. In order for it to work */
28/* properly, remove -Ttext and -Tbss linker */
29/* options from your makefile if they are */
30/* present. */
31
32/* You can use the following to view section */
33/* addresses in your .elf file: */
34/* objdump -h file.elf */
35/* Please note that empty sections may incorrectly*/
36/* list the lma address as the vma address for */
37/* some versions of objdump. */
38
39OUTPUT_FORMAT("elf32-littlearm", "elf32-bigarm", "elf32-littlearm")
40OUTPUT_ARCH(arm)
41ENTRY(_start)
42
43MEMORY {
44
45 rom : ORIGIN = 0x08000000, LENGTH = 32M
46 iwram : ORIGIN = 0x03000000, LENGTH = 32K
47 ewram : ORIGIN = 0x02000000, LENGTH = 256K
48}
49
50
51
52__text_start = ORIGIN(ewram);
53__eheap_end = ORIGIN(ewram) + LENGTH(ewram);
54__iwram_start = ORIGIN(iwram);
55__iwram_top = ORIGIN(iwram) + LENGTH(iwram);;
56
57__sp_irq = __iwram_top - 0x060;
58__sp_usr = __sp_irq - 0x0a0;
59__irq_flags = 0x03007ff8;
60
61SECTIONS
62{
63 . = __text_start;
64 .init :
65 {
66 KEEP (*(.init))
67 . = ALIGN(4);
68 } >ewram =0xff
69
70 .plt :
71 {
72 *(.plt)
73 . = ALIGN(4); /* REQUIRED. LD is flaky without it. */
74 } >ewram
75
76 .text ALIGN (4):
77 {
78 *(EXCLUDE_FILE (*.iwram*) .text)
79 *(.text .stub .text.* .gnu.linkonce.t.*)
80 KEEP (*(.text.*personality*))
81 /* .gnu.warning sections are handled specially by elf32.em. */
82 *(.gnu.warning)
83 *(.glue_7t) *(.glue_7) *(.vfp11_veneer)
84 . = ALIGN(4); /* REQUIRED. LD is flaky without it. */
85 } >ewram = 0xff
86
87 __text_end = .;
88 .fini :
89 {
90 KEEP (*(.fini))
91 . = ALIGN(4); /* REQUIRED. LD is flaky without it. */
92 } >ewram =0
93
94 .rodata :
95 {
96 *(.rodata)
97 *all.rodata*(*)
98 *(.roda)
99 *(.rodata.*)
100 *(.gnu.linkonce.r*)
101 SORT(CONSTRUCTORS)
102 . = ALIGN(4); /* REQUIRED. LD is flaky without it. */
103 } >ewram = 0xff
104
105 .ARM.extab : { *(.ARM.extab* .gnu.linkonce.armextab.*) } >ewram
106 __exidx_start = .;
107 .ARM.exidx : { *(.ARM.exidx* .gnu.linkonce.armexidx.*) } >ewram
108 __exidx_end = .;
109 /* Ensure the __preinit_array_start label is properly aligned. We
110 could instead move the label definition inside the section, but
111 the linker would then create the section even if it turns out to
112 be empty, which isn't pretty. */
113 . = ALIGN(32 / 8);
114 PROVIDE (__preinit_array_start = .);
115 .preinit_array : { KEEP (*(.preinit_array)) } >ewram = 0xff
116 PROVIDE (__preinit_array_end = .);
117 PROVIDE (__init_array_start = .);
118 .init_array : { KEEP (*(.init_array)) } >ewram = 0xff
119 PROVIDE (__init_array_end = .);
120 PROVIDE (__fini_array_start = .);
121 .fini_array : { KEEP (*(.fini_array)) } >ewram = 0xff
122 PROVIDE (__fini_array_end = .);
123 .ctors :
124 {
125 /* gcc uses crtbegin.o to find the start of the constructors, so
126 we make sure it is first. Because this is a wildcard, it
127 doesn't matter if the user does not actually link against
128 crtbegin.o; the linker won't look for a file to match a
129 wildcard. The wildcard also means that it doesn't matter which
130 directory crtbegin.o is in. */
131 KEEP (*crtbegin.o(.ctors))
132 KEEP (*(EXCLUDE_FILE (*crtend.o) .ctors))
133 KEEP (*(SORT(.ctors.*)))
134 KEEP (*(.ctors))
135 . = ALIGN(4); /* REQUIRED. LD is flaky without it. */
136 } >ewram = 0
137
138 .dtors :
139 {
140 KEEP (*crtbegin.o(.dtors))
141 KEEP (*(EXCLUDE_FILE (*crtend.o) .dtors))
142 KEEP (*(SORT(.dtors.*)))
143 KEEP (*(.dtors))
144 . = ALIGN(4); /* REQUIRED. LD is flaky without it. */
145 } >ewram = 0
146
147 .jcr : { KEEP (*(.jcr)) } >ewram
148 .eh_frame :
149 {
150 KEEP (*(.eh_frame))
151 . = ALIGN(4); /* REQUIRED. LD is flaky without it. */
152 } >ewram = 0
153
154 .gcc_except_table :
155 {
156 *(.gcc_except_table)
157 . = ALIGN(4); /* REQUIRED. LD is flaky without it. */
158 } >ewram = 0
159
160 __iwram_lma = .;
161
162 .iwram __iwram_start : AT (__iwram_lma)
163 {
164 __iwram_start__ = ABSOLUTE(.) ;
165 *(.iwram)
166 *iwram.*(.text)
167 . = ALIGN(4); /* REQUIRED. LD is flaky without it. */
168 __iwram_end__ = ABSOLUTE(.) ;
169 } >iwram = 0xff
170
171 __data_lma = __iwram_lma + SIZEOF(.iwram) ;
172
173 .bss ALIGN(4) (NOLOAD):
174 {
175 __bss_start__ = ABSOLUTE(.);
176 *(.dynbss)
177 *(.gnu.linkonce.b*)
178 *(.bss*)
179 *(COMMON)
180 . = ALIGN(4); /* REQUIRED. LD is flaky without it. */
181 __bss_end__ = ABSOLUTE(.) ;
182 }
183
184 .data ALIGN(4) : AT (__data_lma)
185 {
186 __data_start__ = ABSOLUTE(.);
187 *(.data)
188 *(.data.*)
189 *(.gnu.linkonce.d*)
190 CONSTRUCTORS
191 . = ALIGN(4); /* REQUIRED. LD is flaky without it. */
192 __data_end__ = ABSOLUTE(.);
193 } >iwram = 0xff
194
195 __iwram_overlay_lma = __data_lma + SIZEOF(.data);
196
197 PROVIDE (edata = .);
198 __iwram_overlay_start = . ;
199
200 OVERLAY ALIGN(4) : NOCROSSREFS AT (__iwram_overlay_lma)
201 {
202 .iwram0 { *(.iwram0) . = ALIGN(4);}
203 .iwram1 { *(.iwram1) . = ALIGN(4);}
204 .iwram2 { *(.iwram2) . = ALIGN(4);}
205 .iwram3 { *(.iwram3) . = ALIGN(4);}
206 .iwram4 { *(.iwram4) . = ALIGN(4);}
207 .iwram5 { *(.iwram5) . = ALIGN(4);}
208 .iwram6 { *(.iwram6) . = ALIGN(4);}
209 .iwram7 { *(.iwram7) . = ALIGN(4);}
210 .iwram8 { *(.iwram8) . = ALIGN(4);}
211 .iwram9 { *(.iwram9) . = ALIGN(4);}
212 } >iwram = 0xff
213
214 __ewram_lma = LOADADDR(.iwram0) + SIZEOF(.iwram0)+SIZEOF(.iwram1)+SIZEOF(.iwram2)+SIZEOF(.iwram3)+SIZEOF(.iwram4)+SIZEOF(.iwram5)+SIZEOF(.iwram6)+SIZEOF(.iwram7)+SIZEOF(.iwram8)+SIZEOF(.iwram9);
215
216 __iwram_overlay_end = __ewram_lma ;
217
218 /* v1.3 */
219 __ewram_start = __ewram_lma ;
220
221 .ewram __ewram_start : AT (__ewram_lma)
222 {
223 *(.ewram)
224 . = ALIGN(4); /* REQUIRED. LD is flaky without it. */
225 __ewram_end = ABSOLUTE(.);
226 } >ewram = 0xff
227
228 __ewram_overlay_lma = __ewram_lma + SIZEOF(.ewram);
229
230 .sbss ALIGN(4)(NOLOAD):
231 {
232 __sbss_start__ = ABSOLUTE(.);
233 *(.sbss)
234 . = ALIGN(4);
235 __sbss_end__ = ABSOLUTE(.);
236 __end__ = ABSOLUTE(.);
237 __eheap_start = ABSOLUTE(.);
238 }
239
240 OVERLAY ALIGN(4): NOCROSSREFS AT (__ewram_overlay_lma)
241 {
242 .ewram0 { *(.ewram0) . = ALIGN(4);}
243 .ewram1 { *(.ewram1) . = ALIGN(4);}
244 .ewram2 { *(.ewram2) . = ALIGN(4);}
245 .ewram3 { *(.ewram3) . = ALIGN(4);}
246 .ewram4 { *(.ewram4) . = ALIGN(4);}
247 .ewram5 { *(.ewram5) . = ALIGN(4);}
248 .ewram6 { *(.ewram6) . = ALIGN(4);}
249 .ewram7 { *(.ewram7) . = ALIGN(4);}
250 .ewram8 { *(.ewram8) . = ALIGN(4);}
251 .ewram9 { *(.ewram9) . = ALIGN(4);}
252 } >ewram = 0xff
253 __ewram_overlay_end = ABSOLUTE(.);
254
255 __eheap_start = __ewram_overlay_end ;
256
257 _end = __ewram_overlay_end;
258 __end__ = __ewram_overlay_end;
259 __rom_end__ = __ewram_overlay_end;
260
261 /* Stabs debugging sections. */
262 .stab 0 : { *(.stab) }
263 .stabstr 0 : { *(.stabstr) }
264 .stab.excl 0 : { *(.stab.excl) }
265 .stab.exclstr 0 : { *(.stab.exclstr) }
266 .stab.index 0 : { *(.stab.index) }
267 .stab.indexstr 0 : { *(.stab.indexstr) }
268 .comment 0 : { *(.comment) }
269 /* DWARF debug sections.
270 Symbols in the DWARF debugging sections are relative to the beginning
271 of the section so we begin them at 0. */
272 /* DWARF 1 */
273 .debug 0 : { *(.debug) }
274 .line 0 : { *(.line) }
275 /* GNU DWARF 1 extensions */
276 .debug_srcinfo 0 : { *(.debug_srcinfo) }
277 .debug_sfnames 0 : { *(.debug_sfnames) }
278 /* DWARF 1.1 and DWARF 2 */
279 .debug_aranges 0 : { *(.debug_aranges) }
280 .debug_pubnames 0 : { *(.debug_pubnames) }
281 /* DWARF 2 */
282 .debug_info 0 : { *(.debug_info) }
283 .debug_abbrev 0 : { *(.debug_abbrev) }
284 .debug_line 0 : { *(.debug_line) }
285 .debug_frame 0 : { *(.debug_frame) }
286 .debug_str 0 : { *(.debug_str) }
287 .debug_loc 0 : { *(.debug_loc) }
288 .debug_macinfo 0 : { *(.debug_macinfo) }
289 /* SGI/MIPS DWARF 2 extensions */
290 .debug_weaknames 0 : { *(.debug_weaknames) }
291 .debug_funcnames 0 : { *(.debug_funcnames) }
292 .debug_typenames 0 : { *(.debug_typenames) }
293 .debug_varnames 0 : { *(.debug_varnames) }
294 .stack 0x80000 : { _stack = .; *(.stack) }
295 /* These must appear regardless of . */
296}
diff --git a/gba/gba_pkjb.specs b/gba/gba_pkjb.specs new file mode 100644 index 0000000..7c9027b --- /dev/null +++ b/gba/gba_pkjb.specs
@@ -0,0 +1,8 @@
1%rename link old_link
2
3*link:
4-T ../gba_pkjb.ld%s %(old_link) --gc-sections
5
6*startfile:
7../start/pkjb_crt0%O%s crti%O%s crtbegin%O%s
8
diff --git a/gba/source/gamedata.c b/gba/source/gamedata.c new file mode 100644 index 0000000..19d5100 --- /dev/null +++ b/gba/source/gamedata.c
@@ -0,0 +1,534 @@
1/*
2 * Pokemon Gen III Data Extractor by hatkirby 2017.
3 *
4 * This software may be modified and distributed under the terms
5 * of the MIT license. See the LICENSE file for details.
6 *
7 */
8#include "gamedata.h"
9
10void decryptSaveStructures(
11 pSaveBlock1 SaveBlock1,
12 pSaveBlock2 SaveBlock2,
13 pSaveBlock3 SaveBlock3)
14{
15 if (GAME_RS)
16 {
17 // R/S doesn't have save crypto.
18 return;
19 }
20
21 u8* sb1raw = (u8*)SaveBlock1;
22 u8* sb2raw = (u8*)SaveBlock2;
23 //u8* sb3raw = (u8*)SaveBlock3; // unused
24
25 u32* xor_key_ptr = (u32*)(&sb2raw[( GAME_EM ? 0xA8 : 0xF20 )]);
26
27 u32 xor_key = *xor_key_ptr;
28 u16 xor_key16 = (u16)xor_key;
29 if (!xor_key)
30 {
31 // xor key is zero, nothing needs to be done.
32 return;
33 }
34
35 u32* ptr_to_xor;
36 u32 save_offset;
37 int i;
38 u32* bag_pocket_offsets;
39 u32* bag_pocket_counts;
40 if (GAME_FRLG)
41 {
42 // loop over and decrypt various things
43 save_offset = 0x3D38 + 4;
44 for (i = 3; i >= 0; i--)
45 {
46 ptr_to_xor = (u32*)(&sb1raw[save_offset]);
47 *ptr_to_xor ^= xor_key;
48 save_offset += 12;
49 }
50
51 for (i = 0; i <= 0x3f; i++)
52 {
53 save_offset = 0x1200 + (i*sizeof(u32));
54 ptr_to_xor = (u32*)(&sb1raw[save_offset]);
55 *ptr_to_xor ^= xor_key;
56 }
57
58 // loop over each of the bag pockets and decrypt decrypt decrypt
59 bag_pocket_offsets = (u32[5]) { 0x310, 0x388, 0x430, 0x464, 0x54C };
60 bag_pocket_counts = (u32[5]) { 42, 30, 13, 58, 43 };
61
62 for (i = 0; i < 5; i++)
63 {
64 for (int bag_i = 0; bag_i < bag_pocket_counts[i]; bag_i++)
65 {
66 save_offset = bag_pocket_offsets[i] + (sizeof(u32) * bag_i) + 2;
67 *(u16*)(&sb1raw[save_offset]) ^= xor_key16;
68 }
69 }
70
71 // decrypt some more stuff
72 save_offset = 0xaf8;
73 ptr_to_xor = (u32*)(&sb1raw[save_offset]);
74 *ptr_to_xor ^= xor_key;
75
76 save_offset = 0x290;
77 ptr_to_xor = (u32*)(&sb1raw[save_offset]);
78 *ptr_to_xor ^= xor_key;
79
80 save_offset = 0x294;
81 *(u16*)(&sb1raw[save_offset]) ^= xor_key16;
82 } else {
83 // Emerald
84
85 // loop over and decrypt various things
86 for (i = 0; i <= 0x3f; i++)
87 {
88 save_offset = 0x159c + (i*sizeof(u32));
89 ptr_to_xor = (u32*)(&sb1raw[save_offset]);
90 *ptr_to_xor ^= xor_key;
91 }
92
93 // loop over each of the bag pockets and decrypt decrypt decrypt
94 bag_pocket_offsets = (u32[5]) { 0x560, 0x5D8, 0x650, 0x690, 0x790 };
95 bag_pocket_counts = (u32[5]) { 30, 30, 16, 64, 46 };
96
97 for (i = 0; i < 5; i++)
98 {
99 for (int bag_i = 0; bag_i < bag_pocket_counts[i]; bag_i++)
100 {
101 save_offset = bag_pocket_offsets[i] + (sizeof(u32) * bag_i) + 2;
102 *(u16*)(&sb1raw[save_offset]) ^= xor_key16;
103 }
104 }
105
106 // decrypt some more stuff
107 save_offset = 0x1F4;
108 ptr_to_xor = (u32*)(&sb1raw[save_offset]);
109 *ptr_to_xor ^= xor_key;
110
111 save_offset = 0x490;
112 ptr_to_xor = (u32*)(&sb1raw[save_offset]);
113 *ptr_to_xor ^= xor_key;
114
115 save_offset = 0x494;
116 *(u16*)(&sb1raw[save_offset]) ^= xor_key16;
117 }
118
119 *xor_key_ptr = 0;
120}
121
122bool initSaveData(
123 pSaveBlock1* SaveBlock1,
124 pSaveBlock2* SaveBlock2,
125 pSaveBlock3* SaveBlock3)
126{
127 // check the ROM code, make sure this game is supported.
128 u8* ROM = (u8*) 0x8000000;
129
130 u32 gamecode = (*(u32*)(&ROM[0xAC]));
131
132 void(*loadsave)(char a1);
133 //void(*mainloop)();
134 //void(*load_pokemon)();
135 pSaveBlock1 gSaveBlock1;
136 pSaveBlock2 gSaveBlock2;
137 pSaveBlock3 gSaveBlock3;
138 //u32 titlemid = 0;
139
140 // get the address of the save loading function.
141 switch (gamecode)
142 {
143 // --- R/S ---
144 case 'DVXA': // Ruby German
145 case 'DPXA': // Sapphire German
146 {
147 // TODO: detect debug ROM?
148 gSaveBlock1 = (pSaveBlock1) 0x2025734;
149 gSaveBlock2 = (pSaveBlock2) 0x2024EA4;
150 gSaveBlock3 = (pSaveBlock3) 0x20300A0;
151 loadsave = (void(*)(char)) 0x8126249; // same for v1.0 + v1.1
152 //mainloop = (void(*)()) 0x80003D9;
153 //load_pokemon = (void(*)()) 0x8047da9;
154
155 break;
156 }
157
158 case 'FVXA': // Ruby French
159 case 'FPXA': // Sapphire French
160 {
161 gSaveBlock1 = (pSaveBlock1) 0x2025734;
162 gSaveBlock2 = (pSaveBlock2) 0x2024EA4;
163 gSaveBlock3 = (pSaveBlock3) 0x20300A0;
164 loadsave = (void(*)(char)) 0x8126351; // same for v1.0 + v1.1
165 //mainloop = (void(*)()) 0x80003D9;
166 //load_pokemon = (void(*)()) 0x8047e95;
167
168 break;
169 }
170
171 case 'IVXA': // Ruby Italian
172 case 'IPXA': // Sapphire Italian
173 {
174 gSaveBlock1 = (pSaveBlock1) 0x2025734;
175 gSaveBlock2 = (pSaveBlock2) 0x2024EA4;
176 gSaveBlock3 = (pSaveBlock3) 0x20300A0;
177 loadsave = (void(*)(char)) 0x8126249; // same for v1.0 + v1.1
178 //mainloop = (void(*)()) 0x80003D9;
179 //load_pokemon = (void(*)()) 0x8047dbd;
180
181 break;
182 }
183
184 case 'SVXA': // Ruby Spanish
185 case 'SPXA': // Sapphire Spanish
186 {
187 gSaveBlock1 = (pSaveBlock1) 0x2025734;
188 gSaveBlock2 = (pSaveBlock2) 0x2024EA4;
189 gSaveBlock3 = (pSaveBlock3) 0x20300A0;
190 loadsave = (void(*)(char)) 0x8126349; // same for v1.0 + v1.1
191 //mainloop = (void(*)()) 0x80003D9;
192 //load_pokemon = (void(*)()) 0x8047ea5;
193
194 break;
195 }
196
197 case 'EVXA': // Ruby English
198 case 'EPXA': // Sapphire English
199 {
200 gSaveBlock1 = (pSaveBlock1) 0x2025734;
201 gSaveBlock2 = (pSaveBlock2) 0x2024EA4;
202 gSaveBlock3 = (pSaveBlock3) 0x20300A0;
203 //mainloop = (void(*)()) 0x80002A5;
204
205 // version number
206 switch (ROM[0xBC])
207 {
208 case 0:
209 {
210 loadsave = (void(*)(char)) 0x8125EC9;
211 //load_pokemon = (void(*)()) 0x8047a85;
212
213 break;
214 }
215
216 case 1:
217 case 2:
218 {
219 loadsave = (void(*)(char)) 0x8125EE9;
220 //load_pokemon = (void(*)()) 0x8047aa5;
221
222 break;
223 }
224
225 default:
226 {
227 return false; // unsupported version
228 }
229 }
230
231 break;
232 }
233
234 case 'JVXA': // Ruby Japanese
235 case 'JPXA': // Sapphire Japanese
236 {
237 gSaveBlock1 = (pSaveBlock1) 0x2025494;
238 gSaveBlock2 = (pSaveBlock2) 0x2024C04;
239 gSaveBlock3 = (pSaveBlock3) 0x202FDBC;
240 loadsave = (void(*)(char)) 0x8120d05; // same for v1.0 + v1.1
241 //mainloop = (void(*)()) 0x80002A9;
242 //load_pokemon = (void(*)()) 0x8044d55;
243
244 break;
245 }
246
247 /// --- FR/LG ---
248 // In FR/LG, the function that initialises the save-block pointers to default does not set up saveblock3.
249 // Which will need to be set up before loading the save if we want boxed Pokémon to not disappear.
250 // Oh, and loadsave() offset is different between FR and LG...
251
252 case 'DRPB': // FireRed German
253 case 'DGPB': // LeafGreen German
254 {
255 gSaveBlock1 = (pSaveBlock1) 0x202552C;
256 gSaveBlock2 = (pSaveBlock2) 0x2024588;
257 gSaveBlock3 = (pSaveBlock3) 0x2029314;
258 *(pSaveBlock3*)(0x3004f60) = gSaveBlock3;
259 loadsave = (void(*)(char)) ( GAME_FR ? 0x80da721 : 0x80da6f5 );
260 //mainloop = (void(*)()) 0x8000425;
261 //titlemid = 0x80791df;
262 //load_pokemon = (void(*)()) 0x804c251;
263
264 break;
265 }
266
267 case 'FRPB': // FireRed French
268 case 'FGPB': // LeafGreen French
269 {
270 gSaveBlock1 = (pSaveBlock1) 0x202552C;
271 gSaveBlock2 = (pSaveBlock2) 0x2024588;
272 gSaveBlock3 = (pSaveBlock3) 0x2029314;
273 *(pSaveBlock3*)(0x3004f60) = gSaveBlock3;
274 loadsave = (void(*)(char)) ( GAME_FR ? 0x80da7e1 : 0x80da7b5 );
275 //mainloop = (void(*)()) 0x8000417;
276 //titlemid = 0x807929f;
277 //load_pokemon = (void(*)()) 0x804c311;
278
279 break;
280 }
281
282 case 'IRPB': // FireRed Italian
283 case 'IGPB': // LeafGreen Italian
284 {
285 gSaveBlock1 = (pSaveBlock1) 0x202552C;
286 gSaveBlock2 = (pSaveBlock2) 0x2024588;
287 gSaveBlock3 = (pSaveBlock3) 0x2029314;
288 *(pSaveBlock3*)(0x3004f60) = gSaveBlock3;
289 loadsave = (void(*)(char)) ( GAME_FR ? 0x80da721 : 0x80da6f5 );
290 //mainloop = (void(*)()) 0x8000425;
291 //titlemid = 0x80791cb;
292 //load_pokemon = (void(*)()) 0x804c23d;
293
294 break;
295 }
296
297 case 'SRPB': // FireRed Spanish
298 case 'SGPB': // LeafGreen Spanish
299 {
300 gSaveBlock1 = (pSaveBlock1) 0x202552C;
301 gSaveBlock2 = (pSaveBlock2) 0x2024588;
302 gSaveBlock3 = (pSaveBlock3) 0x2029314;
303 *(pSaveBlock3*)(0x3004f60) = gSaveBlock3;
304 loadsave = (void(*)(char)) ( GAME_FR ? 0x80da809 : 0x80da7dd );
305 //mainloop = (void(*)()) 0x8000417;
306 //titlemid = 0x80792b3;
307 //load_pokemon = (void(*)()) 0x804c325;
308
309 break;
310 }
311
312 case 'ERPB': // FireRed English
313 case 'EGPB': // LeafGreen English
314 {
315 gSaveBlock1 = (pSaveBlock1) 0x202552C;
316 gSaveBlock2 = (pSaveBlock2) 0x2024588;
317 gSaveBlock3 = (pSaveBlock3) 0x2029314;
318 *(pSaveBlock3*)(0x3005010) = gSaveBlock3;
319
320 // version number
321 switch (ROM[0xBC])
322 {
323 case 0:
324 {
325 loadsave = (void(*)(char)) ( GAME_FR ? 0x80da4fd : 0x80da4d1 );
326 //mainloop = (void(*)()) 0x800041b;
327 //titlemid = 0x807927b;
328 //load_pokemon = (void(*)()) 0x804c231;
329
330 break;
331 }
332
333 case 1:
334 {
335 loadsave = (void(*)(char)) ( GAME_FR ? 0x80da511 : 0x80da4e5 );
336 //mainloop = (void(*)()) 0x8000429;
337 //titlemid = 0x807928f;
338 //load_pokemon = (void(*)()) 0x804c245;
339
340 break;
341 }
342
343 default:
344 {
345 return false; // unsupported version
346 }
347 }
348
349 break;
350 }
351
352 case 'JRPB': // FireRed Japanese
353 case 'JGPB': // LeafGreen Japanese
354 {
355 gSaveBlock1 = (pSaveBlock1) 0x202548C;
356 gSaveBlock2 = (pSaveBlock2) 0x20244E8;
357 gSaveBlock3 = (pSaveBlock3) 0x202924C;
358 *(pSaveBlock3*)(0x3005050) = gSaveBlock3;
359
360 // version number
361 switch (ROM[0xBC])
362 {
363 case 0:
364 {
365 loadsave = (void(*)(char)) ( GAME_FR ? 0x80db4e5 : 0x80db4b9 );
366 //mainloop = (void(*)()) 0x800041b;
367 //titlemid = 0x8078a0f;
368 //load_pokemon = (void(*)()) 0x804b9e9;
369
370 break;
371 }
372
373 case 1:
374 {
375 if ((gamecode << 8) == 'GPB\x00')
376 {
377 // LeafGreen v1.1 Japanese is undumped.
378 // Therefore, it is unsupported.
379 // I will make guesses at the offsets in the comments, but I will not actually implement them until LeafGreen v1.1 is dumped.
380
381 return false;
382 }
383
384 loadsave = (void(*)(char)) 0x80db529; // potential LG1.1 address: 0x80db4fd
385 //mainloop = (void(*)()) 0x8000417;
386 //titlemid = 0x8078987;
387 //load_pokemon = (void(*)()) 0x804b9c5;
388
389 break;
390 }
391
392 default:
393 {
394 return false; // unsupported version
395 }
396 }
397
398 break;
399 }
400
401 /// --- Emerald ---
402 // In Emerald, the saveblock pointer that isn't set up is saveblock1 (in FR/LG it was saveblock3).
403 // The initial save loading code after the copyright screen is also updated, now it sets up ASLR/crypto here before loading the save.
404
405 case 'DEPB': // Emerald German
406 {
407 gSaveBlock1 = (pSaveBlock1) 0x2025A00;
408 gSaveBlock2 = (pSaveBlock2) 0x2024A54;
409 gSaveBlock3 = (pSaveBlock3) 0x2029808;
410 *(pSaveBlock1*)(0x3005d8c) = gSaveBlock1;
411 loadsave = (void(*)(char)) 0x8153075;
412 //mainloop = (void(*)()) 0x800042b;
413 //titlemid = 0x816fdb5;
414 //load_pokemon = (void(*)()) 0x8076dd5;
415
416 break;
417 }
418
419 case 'FEPB': // Emerald French
420 {
421 gSaveBlock1 = (pSaveBlock1) 0x2025A00;
422 gSaveBlock2 = (pSaveBlock2) 0x2024A54;
423 gSaveBlock3 = (pSaveBlock3) 0x2029808;
424 *(pSaveBlock1*)(0x3005d8c) = gSaveBlock1;
425 loadsave = (void(*)(char)) 0x815319d;
426 //mainloop = (void(*)()) 0x800042b;
427 //titlemid = 0x816fedd;
428 //load_pokemon = (void(*)()) 0x8076dd1;
429
430 break;
431 }
432
433 case 'IEPB': // Emerald Italian
434 {
435 gSaveBlock1 = (pSaveBlock1) 0x2025A00;
436 gSaveBlock2 = (pSaveBlock2) 0x2024A54;
437 gSaveBlock3 = (pSaveBlock3) 0x2029808;
438 *(pSaveBlock1*)(0x3005d8c) = gSaveBlock1;
439 loadsave = (void(*)(char)) 0x8153065;
440 //mainloop = (void(*)()) 0x800042b;
441 //titlemid = 0x816fda5;
442 //load_pokemon = (void(*)()) 0x8076dd5;
443
444 break;
445 }
446
447 case 'SEPB': // Emerald Spanish
448 {
449 gSaveBlock1 = (pSaveBlock1) 0x2025A00;
450 gSaveBlock2 = (pSaveBlock2) 0x2024A54;
451 gSaveBlock3 = (pSaveBlock3) 0x2029808;
452 *(pSaveBlock1*)(0x3005d8c) = gSaveBlock1;
453 loadsave = (void(*)(char)) 0x8153175;
454 //mainloop = (void(*)()) 0x800042b;
455 //titlemid = 0x816feb5;
456 //load_pokemon = (void(*)()) 0x8076dd1;
457
458 break;
459 }
460
461 case 'EEPB': // Emerald English
462 {
463 gSaveBlock1 = (pSaveBlock1) 0x2025A00;
464 gSaveBlock2 = (pSaveBlock2) 0x2024A54;
465 gSaveBlock3 = (pSaveBlock3) 0x2029808;
466 *(pSaveBlock1*)(0x3005d8c) = gSaveBlock1;
467 loadsave = (void(*)(char)) 0x81534d1;
468 //mainloop = (void(*)()) 0x800042b;
469 //titlemid = 0x817014d;
470 //load_pokemon = (void(*)()) 0x8076dd5;
471
472 break;
473 }
474
475 case 'JEPB': // Emerald Japanese
476 {
477 gSaveBlock1 = (pSaveBlock1) 0x20256A4;
478 gSaveBlock2 = (pSaveBlock2) 0x20246F8;
479 gSaveBlock3 = (pSaveBlock3) 0x20294AC;
480 *(pSaveBlock1*)(0x3005aec) = gSaveBlock1;
481 loadsave = (void(*)(char)) 0x815340d;
482 //mainloop = (void(*)()) 0x800042b;
483 //titlemid = 0x816ff45;
484 //load_pokemon = (void(*)()) 0x80767dd;
485
486 break;
487 }
488
489 default:
490 {
491 return false; // this game isn't supported
492 }
493 }
494
495 loadsave(0);
496
497 // now the save is loaded, we can do what we want with the loaded blocks.
498 // first, we're going to want to decrypt the parts that are crypted, if applicable.
499 decryptSaveStructures(gSaveBlock1,gSaveBlock2,gSaveBlock3);
500
501 *SaveBlock1 = gSaveBlock1;
502 *SaveBlock2 = gSaveBlock2;
503 *SaveBlock3 = gSaveBlock3;
504
505 /*
506 // time to call the payload.
507 payload(gSaveBlock1,gSaveBlock2,gSaveBlock3);
508 // Now, we better call the function that sets the pokemon-related stuff from the structure elements of the loaded save again.
509 // Just in case the payload did something with that.
510 load_pokemon();
511 // In FR/LG/Emerald, just returning to the game is unwise.
512 // The game reloads the savefile.
513 // In FR/LG, this is done at the title screen after setting ASLR/saveblock-crypto up. (probably because at initial save-load, SaveBlock3 ptr isn't set up lol)
514 // So, better bypass the title screen and get the game to return directly to the Continue/New Game screen.
515 // In Emerald, the save reload happens after the Continue option was chosen, so we have no choice but to bypass everything and get the game to go straight to the overworld.
516 // Easiest way to do this is to call into the middle of the function we want, using an ASM wrapper to set up the stack.
517 // Here goes...
518 if (titlemid) {
519 // Function reserves an extra 4 bytes of stack space in FireRed/LeafGreen, and none in Emerald.
520 call_into_middle_of_titlescreen_func(titlemid,(GAME_EM ? 0 : 4));
521 }
522 // Now we've done what we want, time to return to the game.
523 // Can't just return, the game will reload the save.
524 // So let's just call the main-loop directly ;)
525 // turn the sound back on before we head back to the game
526 *(vu16 *)(REG_BASE + 0x84) = 0x8f;
527 // re-enable interrupts
528 REG_IME = 1;
529 mainloop();
530 // Anything past here will not be executed.
531 return 0;
532 */
533 return true;
534}
diff --git a/gba/source/gamedata.h b/gba/source/gamedata.h new file mode 100644 index 0000000..99dfa8e --- /dev/null +++ b/gba/source/gamedata.h
@@ -0,0 +1,22 @@
1#ifndef _GAMEDATA_H_
2#define _GAMEDATA_H_
3
4#include <gba.h>
5#include "saveblocks.h"
6
7#define GAME_RUBY (((*(u32*)(0x80000AC)) << 8) == 'VXA\x00')
8#define GAME_SAPP (((*(u32*)(0x80000AC)) << 8) == 'PXA\x00')
9#define GAME_RS ((GAME_RUBY) || (GAME_SAPP))
10#define GAME_FR (((*(u32*)(0x80000AC)) << 8) == 'RPB\x00')
11#define GAME_LG (((*(u32*)(0x80000AC)) << 8) == 'GPB\x00')
12#define GAME_FRLG ((GAME_FR) || (GAME_LG))
13#define GAME_EM (((*(u32*)(0x80000AC)) << 8) == 'EPB\x00')
14
15#define LANG_JAPAN ((*(u8*)(0x80000AF)) == 'J')
16
17bool initSaveData(
18 pSaveBlock1* SaveBlock1,
19 pSaveBlock2* SaveBlock2,
20 pSaveBlock3* SaveBlock3);
21
22#endif
diff --git a/gba/source/link.c b/gba/source/link.c new file mode 100644 index 0000000..e695622 --- /dev/null +++ b/gba/source/link.c
@@ -0,0 +1,41 @@
1#include "link.h"
2
3#define JOY_WRITE 2
4#define JOY_READ 4
5#define JOY_RW 6
6
7void waitForWriteAccess()
8{
9 //while ((REG_HS_CTRL & JOY_READ) == 0);
10 while ((REG_HS_CTRL & JOY_WRITE) == 0);
11 REG_HS_CTRL |= JOY_RW;
12}
13
14void waitForAck()
15{
16 while ((REG_HS_CTRL & JOY_WRITE) == 0);
17 REG_HS_CTRL |= JOY_RW;
18 REG_JOYTR = 0;
19 while ((REG_HS_CTRL & JOY_WRITE) == 0);
20 REG_HS_CTRL |= JOY_RW;
21}
22
23void sendS32(s32 val)
24{
25 REG_JOYTR = val;
26 //waitForWriteAccess();
27}
28
29void sendU32(u32 val)
30{
31 REG_JOYTR = val;
32 //waitForWriteAccess();
33}
34
35u32 recieveU32()
36{
37 while ((REG_HS_CTRL & JOY_WRITE) == 0);
38 REG_HS_CTRL |= JOY_RW;
39 return REG_JOYRE;
40}
41
diff --git a/gba/source/link.h b/gba/source/link.h new file mode 100644 index 0000000..f18b38a --- /dev/null +++ b/gba/source/link.h
@@ -0,0 +1,12 @@
1#ifndef _LINK_H_
2#define _LINK_H_
3
4#include <gba.h>
5
6void waitForWriteAccess();
7void waitForAck();
8void sendS32(s32 val);
9void sendU32(u32 val);
10u32 recieveU32();
11
12#endif
diff --git a/gba/source/main.c b/gba/source/main.c index ee94c35..104866a 100644 --- a/gba/source/main.c +++ b/gba/source/main.c
@@ -8,6 +8,8 @@
8#include <stdio.h> 8#include <stdio.h>
9#include <stdlib.h> 9#include <stdlib.h>
10#include "libSave.h" 10#include "libSave.h"
11#include "gamedata.h"
12#include "link.h"
11 13
12#define REG_WAITCNT *(vu16 *)(REG_BASE + 0x204) 14#define REG_WAITCNT *(vu16 *)(REG_BASE + 0x204)
13#define JOY_WRITE 2 15#define JOY_WRITE 2
@@ -18,224 +20,398 @@ u8 save_data[0x20000] __attribute__ ((section (".sbss")));
18 20
19s32 getGameSize(void) 21s32 getGameSize(void)
20{ 22{
21 if(*(vu32*)(0x08000004) != 0x51AEFF24) 23 if(*(vu32*)(0x08000004) != 0x51AEFF24)
22 return -1; 24 return -1;
23 s32 i; 25 s32 i;
24 for(i = (1<<20); i < (1<<25); i<<=1) 26 for(i = (1<<20); i < (1<<25); i<<=1)
27 {
28 vu16 *rompos = (vu16*)(0x08000000+i);
29 int j;
30 bool romend = true;
31 for(j = 0; j < 0x1000; j++)
32 {
33 if(rompos[j] != j)
34 {
35 romend = false;
36 break;
37 }
38 }
39 if(romend) break;
40 }
41 return i;
42}
43
44
45// === (from tonc_memdef.h) ===========================================
46
47// --- REG_DISPCNT defines ---
48#define DCNT_MODE0 0x0000
49#define DCNT_MODE1 0x0001
50#define DCNT_MODE2 0x0002
51#define DCNT_MODE3 0x0003
52#define DCNT_MODE4 0x0004
53#define DCNT_MODE5 0x0005
54// layers
55#define DCNT_BG0 0x0100
56#define DCNT_BG1 0x0200
57#define DCNT_BG2 0x0400
58#define DCNT_BG3 0x0800
59#define DCNT_OBJ 0x1000
60typedef u16 COLOR;
61#define MEM_VRAM 0x06000000
62#define SCREEN_WIDTH 240
63#define vid_mem ((u16*)MEM_VRAM)
64static inline void m3_plot(int x, int y, COLOR clr)
65{ vid_mem[y*SCREEN_WIDTH+x]= clr; }
66static inline COLOR RGB15(u32 red, u32 green, u32 blue)
67{ return red | (green<<5) | (blue<<10); }
68void plot_sqr(int x, int y, COLOR clr)
69{
70 /*for (int j=0;j<8; j++)
25 { 71 {
26 vu16 *rompos = (vu16*)(0x08000000+i); 72 for (int i=0;i<8; i++)
27 int j;
28 bool romend = true;
29 for(j = 0; j < 0x1000; j++)
30 { 73 {
31 if(rompos[j] != j) 74 vid_mem[(y*8+j+32)*SCREEN_WIDTH+x*8+i+32] = clr;
32 {
33 romend = false;
34 break;
35 }
36 } 75 }
37 if(romend) break;
38 } 76 }
39 return i; 77 vid_mem[(y*8+1+32)*SCREEN_WIDTH+x*8+1+32] = RGB15(31,31,31);*/
78}
79void m3_fill(COLOR clr)
80{
81 /*int ii;
82 u32 *dst= (u32*)vid_mem;
83 u32 wd= (clr<<16) | clr;
84
85 for(ii=0; ii<SCREEN_WIDTH/4; ii++)
86 *dst++= wd;*/
40} 87}
41 88
42//--------------------------------------------------------------------------------- 89//---------------------------------------------------------------------------------
43// Program entry point 90// Program entry point
44//--------------------------------------------------------------------------------- 91//---------------------------------------------------------------------------------
45int main(void) { 92int main(void)
46//--------------------------------------------------------------------------------- 93{
94 //REG_IME = 0;
95 //REG_DISPCNT= DCNT_MODE3 | DCNT_BG2;
96 m3_fill(RGB15(31,31,31));
97 plot_sqr( 4, 4, RGB15(31, 0, 0) ); // or CLR_RED
47 98
48 // the vblank interrupt must be enabled for VBlankIntrWait() to work 99
49 // since the default dispatcher handles the bios flags no vblank handler 100
50 // is required 101 //*(vu16 *)(REG_BASE + 0x84) = 0x8f;
51 irqInit(); 102 //REG_IME = 1;
52 irqEnable(IRQ_VBLANK); 103 // the vblank interrupt must be enabled for VBlankIntrWait() to work
53 104 // since the default dispatcher handles the bios flags no vblank handler
54 consoleDemoInit(); 105 // is required
55 REG_JOYTR = 0; 106 //irqInit();
56 // ansi escape sequence to set print co-ordinates 107 //irqEnable(IRQ_VBLANK);
57 // /x1b[line;columnH 108
58 u32 i; 109 //consoleDemoInit();
59 iprintf("\x1b[9;2HGBA Link Cable Dumper v1.6\n"); 110 //REG_JOYTR = 0;
60 iprintf("\x1b[10;4HPlease look at the TV\n"); 111
61 // disable this, needs power 112 // ansi escape sequence to set print co-ordinates
62 SNDSTAT = 0; 113 // /x1b[line;columnH
63 SNDBIAS = 0; 114 //u32 i;
64 // Set up waitstates for EEPROM access etc. 115 //iprintf("\x1b[9;2HPokemon Gen III Data Extractor\n");
65 REG_WAITCNT = 0x0317; 116 //iprintf("\x1b[10;4HPlease look at the TV\n");
66 //clear out previous messages 117
67 REG_HS_CTRL |= JOY_RW; 118 // disable this, needs power
68 while (1) { 119 //SNDSTAT = 0;
69 if(REG_HS_CTRL&JOY_READ) 120 //SNDBIAS = 0;
70 { 121
71 REG_HS_CTRL |= JOY_RW; 122 // Set up waitstates for EEPROM access etc.
72 s32 gamesize = getGameSize(); 123 //REG_WAITCNT = 0x0317;
73 u32 savesize = SaveSize(save_data,gamesize); 124
74 REG_JOYTR = gamesize; 125 //clear out previous messages
75 //wait for a cmd receive for safety 126 REG_HS_CTRL |= JOY_RW;
76 while((REG_HS_CTRL&JOY_WRITE) == 0) ; 127 sendU32(0);
77 REG_HS_CTRL |= JOY_RW; 128 plot_sqr( 4, 5, RGB15( 0,31, 0) ); // or CLR_LIME
78 REG_JOYTR = savesize; 129 while (1)
79 //wait for a cmd receive for safety 130 {
80 while((REG_HS_CTRL&JOY_WRITE) == 0) ; 131 waitForWriteAccess();
81 REG_HS_CTRL |= JOY_RW; 132 //while (recieveU32() != 0);
82 if(gamesize == -1) 133 //waitForAck();
83 { 134 plot_sqr( 4, 6, RGB15( 0, 0,31) ); // or CLR_BLUE
84 REG_JOYTR = 0; 135 // Send game size to acknowledge that an actual cart is inserted.
85 continue; //nothing to read 136 //s32 gamesize = getGameSize();
86 } 137 //sendS32(gamesize);
87 //game in, send header 138 //waitForAck();
88 for(i = 0; i < 0xC0; i+=4) 139
89 { 140 // If the game size is illegal, start over.
90 REG_JOYTR = *(vu32*)(0x08000000+i); 141 //if (gamesize == -1)
91 while((REG_HS_CTRL&JOY_READ) == 0) ; 142 //{
92 REG_HS_CTRL |= JOY_RW; 143 // sendS32(0);
93 } 144 //
94 REG_JOYTR = 0; 145 // continue;
95 //wait for other side to choose 146 //}
96 while((REG_HS_CTRL&JOY_WRITE) == 0) ; 147
97 REG_HS_CTRL |= JOY_RW; 148 // Identify the inserted game.
98 u32 choseval = REG_JOYRE; 149 if (GAME_RUBY)
99 if(choseval == 0) 150 {
100 { 151 sendS32(1);
101 REG_JOYTR = 0; 152 } else if (GAME_SAPP)
102 continue; //nothing to read 153 {
103 } 154 sendS32(2);
104 else if(choseval == 1) 155 } else if (GAME_FR)
105 { 156 {
106 //disable interrupts 157 sendS32(3);
107 u32 prevIrqMask = REG_IME; 158 } else if (GAME_LG)
108 REG_IME = 0; 159 {
109 //dump the game 160 sendS32(4);
110 for(i = 0; i < gamesize; i+=4) 161 } else if (GAME_EM)
111 { 162 {
112 REG_JOYTR = *(vu32*)(0x08000000+i); 163 sendS32(5);
113 while((REG_HS_CTRL&JOY_READ) == 0) ; 164 } else {
114 REG_HS_CTRL |= JOY_RW; 165 sendS32(-1);
115 } 166 waitForAck();
116 //restore interrupts 167
117 REG_IME = prevIrqMask; 168 sendS32(0);
118 } 169
119 else if(choseval == 2) 170 continue;
120 { 171 }
121 //disable interrupts 172 plot_sqr( 5, 4, RGB15( 31, 0,31) );
122 u32 prevIrqMask = REG_IME; 173 waitForAck();
123 REG_IME = 0; 174 plot_sqr( 5, 5, RGB15( 16, 16,16) );
124 //backup save 175 // Get access to save data.
125 switch (savesize){ 176 pSaveBlock1 SaveBlock1;
126 case 0x200: 177 pSaveBlock2 SaveBlock2;
127 GetSave_EEPROM_512B(save_data); 178 pSaveBlock3 SaveBlock3;
128 break; 179 if (!initSaveData(&SaveBlock1, &SaveBlock2, &SaveBlock3))
129 case 0x2000: 180 {
130 GetSave_EEPROM_8KB(save_data); 181 // Unsupported game version.
131 break; 182 //iprintf("Unsupported game version\n");
132 case 0x8000: 183 sendS32(-1);
133 GetSave_SRAM_32KB(save_data); 184 waitForAck();
134 break; 185
135 case 0x10000: 186 sendS32(0);
136 GetSave_FLASH_64KB(save_data); 187
137 break; 188 continue;
138 case 0x20000: 189 }
139 GetSave_FLASH_128KB(save_data); 190 plot_sqr( 5, 6, RGB15( 0, 31,16) );
140 break; 191 sendS32(1);
141 default: 192 waitForAck();
142 break; 193 /*
143 } 194 // Send trainer name.
144 //restore interrupts 195 u8* trainerName;
145 REG_IME = prevIrqMask; 196
146 //say gc side we read it 197 if (GAME_RS)
147 REG_JOYTR = savesize; 198 {
148 //wait for a cmd receive for safety 199 trainerName = SaveBlock2->rs.playerName;
149 while((REG_HS_CTRL&JOY_WRITE) == 0) ; 200 } else if (GAME_FRLG)
150 REG_HS_CTRL |= JOY_RW; 201 {
151 //send the save 202 trainerName = SaveBlock2->frlg.playerName;
152 for(i = 0; i < savesize; i+=4) 203 } else if (GAME_EM)
153 { 204 {
154 REG_JOYTR = *(vu32*)(save_data+i); 205 trainerName = SaveBlock2->e.playerName;
155 while((REG_HS_CTRL&JOY_READ) == 0) ; 206 }
156 REG_HS_CTRL |= JOY_RW; 207 iprintf("%d\n", trainerName[0]);
157 } 208 iprintf("%d\n", trainerName[1]);
158 } 209 iprintf("%d\n", trainerName[2]);
159 else if(choseval == 3 || choseval == 4) 210 iprintf("%d\n", trainerName[3]);
160 { 211 iprintf("%d\n", trainerName[4]);
161 REG_JOYTR = savesize; 212 iprintf("%d\n", trainerName[5]);
162 if(choseval == 3) 213 iprintf("%d\n", trainerName[6]);
163 { 214 iprintf("%d\n", trainerName[7]);
164 //receive the save 215
165 for(i = 0; i < savesize; i+=4) 216 u32 tn1 =
166 { 217 (trainerName[0] << 24)
167 while((REG_HS_CTRL&JOY_WRITE) == 0) ; 218 | (trainerName[1] << 16)
168 REG_HS_CTRL |= JOY_RW; 219 | (trainerName[2] << 8)
169 *(vu32*)(save_data+i) = REG_JOYRE; 220 | (trainerName[3]);
170 } 221
171 } 222 u32 tn2 =
172 else 223 (trainerName[4] << 24)
173 { 224 | (trainerName[5] << 16)
174 //clear the save 225 | (trainerName[6] << 8)
175 for(i = 0; i < savesize; i+=4) 226 | (trainerName[7]);
176 *(vu32*)(save_data+i) = 0; 227
177 } 228 sendU32(tn1);
178 //disable interrupts 229 waitForAck();
179 u32 prevIrqMask = REG_IME; 230
180 REG_IME = 0; 231 sendU32(tn2);
181 //write it 232 waitForAck();
182 switch (savesize){ 233*/
183 case 0x200: 234 // Send trainer ID.
184 PutSave_EEPROM_512B(save_data); 235 u8* trainerId = 0;
185 break; 236
186 case 0x2000: 237 if (GAME_RS)
187 PutSave_EEPROM_8KB(save_data); 238 {
188 break; 239 trainerId = SaveBlock2->rs.playerTrainerId;
189 case 0x8000: 240 } else if (GAME_FRLG)
190 PutSave_SRAM_32KB(save_data); 241 {
191 break; 242 trainerId = SaveBlock2->frlg.playerTrainerId;
192 case 0x10000: 243 } else if (GAME_EM)
193 PutSave_FLASH_64KB(save_data); 244 {
194 break; 245 trainerId = SaveBlock2->e.playerTrainerId;
195 case 0x20000: 246 }
196 PutSave_FLASH_128KB(save_data); 247
197 break; 248 u32 tti =
198 default: 249 (trainerId[2] << 8)
199 break; 250 | (trainerId[3]);
200 } 251
201 //restore interrupts 252 sendU32(tti);
202 REG_IME = prevIrqMask; 253 waitForAck();
203 //say gc side we're done 254
204 REG_JOYTR = 0; 255 // Restart, because we're just testing.
205 //wait for a cmd receive for safety 256 sendS32(0);
206 while((REG_HS_CTRL&JOY_WRITE) == 0) ; 257 //continue;
207 REG_HS_CTRL |= JOY_RW; 258 break;
208 } 259
209 REG_JOYTR = 0; 260/*
210 } 261
211 else if(REG_HS_CTRL&JOY_WRITE) 262
212 { 263 //game in, send header
213 REG_HS_CTRL |= JOY_RW; 264 for(i = 0; i < 0xC0; i+=4)
214 u32 choseval = REG_JOYRE; 265 {
215 if(choseval == 5) 266 REG_JOYTR = *(vu32*)(0x08000000+i);
216 { 267 while((REG_HS_CTRL&JOY_READ) == 0) ;
217 //disable interrupts 268 REG_HS_CTRL |= JOY_RW;
218 u32 prevIrqMask = REG_IME; 269 }
219 REG_IME = 0; 270 REG_JOYTR = 0;
220 //dump BIOS 271 //wait for other side to choose
221 for (i = 0; i < 0x4000; i+=4) 272 while((REG_HS_CTRL&JOY_WRITE) == 0) ;
222 { 273 REG_HS_CTRL |= JOY_RW;
223 // the lower bits are inaccurate, so just get it four times :) 274 u32 choseval = REG_JOYRE;
224 u32 a = MidiKey2Freq((WaveData *)(i-4), 180-12, 0) * 2; 275 if(choseval == 0)
225 u32 b = MidiKey2Freq((WaveData *)(i-3), 180-12, 0) * 2; 276 {
226 u32 c = MidiKey2Freq((WaveData *)(i-2), 180-12, 0) * 2; 277 REG_JOYTR = 0;
227 u32 d = MidiKey2Freq((WaveData *)(i-1), 180-12, 0) * 2; 278 continue; //nothing to read
228 REG_JOYTR = ((a>>24<<24) | (d>>24<<16) | (c>>24<<8) | (b>>24)); 279 }
229 while((REG_HS_CTRL&JOY_READ) == 0) ; 280 else if(choseval == 1)
230 REG_HS_CTRL |= JOY_RW; 281 {
231 } 282 //disable interrupts
232 //restore interrupts 283 u32 prevIrqMask = REG_IME;
233 REG_IME = prevIrqMask; 284 REG_IME = 0;
234 } 285 //dump the game
235 REG_JOYTR = 0; 286 for(i = 0; i < gamesize; i+=4)
236 } 287 {
237 Halt(); 288 REG_JOYTR = *(vu32*)(0x08000000+i);
238 } 289 while((REG_HS_CTRL&JOY_READ) == 0) ;
290 REG_HS_CTRL |= JOY_RW;
291 }
292 //restore interrupts
293 REG_IME = prevIrqMask;
294 }
295 else if(choseval == 2)
296 {
297 //disable interrupts
298 u32 prevIrqMask = REG_IME;
299 REG_IME = 0;
300 //backup save
301 switch (savesize){
302 case 0x200:
303 GetSave_EEPROM_512B(save_data);
304 break;
305 case 0x2000:
306 GetSave_EEPROM_8KB(save_data);
307 break;
308 case 0x8000:
309 GetSave_SRAM_32KB(save_data);
310 break;
311 case 0x10000:
312 GetSave_FLASH_64KB(save_data);
313 break;
314 case 0x20000:
315 GetSave_FLASH_128KB(save_data);
316 break;
317 default:
318 break;
319 }
320 //restore interrupts
321 REG_IME = prevIrqMask;
322 //say gc side we read it
323 REG_JOYTR = savesize;
324 //wait for a cmd receive for safety
325 while((REG_HS_CTRL&JOY_WRITE) == 0) ;
326 REG_HS_CTRL |= JOY_RW;
327 //send the save
328 for(i = 0; i < savesize; i+=4)
329 {
330 REG_JOYTR = *(vu32*)(save_data+i);
331 while((REG_HS_CTRL&JOY_READ) == 0) ;
332 REG_HS_CTRL |= JOY_RW;
333 }
334 }
335 else if(choseval == 3 || choseval == 4)
336 {
337 REG_JOYTR = savesize;
338 if(choseval == 3)
339 {
340 //receive the save
341 for(i = 0; i < savesize; i+=4)
342 {
343 while((REG_HS_CTRL&JOY_WRITE) == 0) ;
344 REG_HS_CTRL |= JOY_RW;
345 *(vu32*)(save_data+i) = REG_JOYRE;
346 }
347 }
348 else
349 {
350 //clear the save
351 for(i = 0; i < savesize; i+=4)
352 *(vu32*)(save_data+i) = 0;
353 }
354 //disable interrupts
355 u32 prevIrqMask = REG_IME;
356 REG_IME = 0;
357 //write it
358 switch (savesize){
359 case 0x200:
360 PutSave_EEPROM_512B(save_data);
361 break;
362 case 0x2000:
363 PutSave_EEPROM_8KB(save_data);
364 break;
365 case 0x8000:
366 PutSave_SRAM_32KB(save_data);
367 break;
368 case 0x10000:
369 PutSave_FLASH_64KB(save_data);
370 break;
371 case 0x20000:
372 PutSave_FLASH_128KB(save_data);
373 break;
374 default:
375 break;
376 }
377 //restore interrupts
378 REG_IME = prevIrqMask;
379 //say gc side we're done
380 REG_JOYTR = 0;
381 //wait for a cmd receive for safety
382 while((REG_HS_CTRL&JOY_WRITE) == 0) ;
383 REG_HS_CTRL |= JOY_RW;
384 }
385 REG_JOYTR = 0;
386 }
387 } else if(REG_HS_CTRL&JOY_WRITE)
388 {
389 REG_HS_CTRL |= JOY_RW;
390 u32 choseval = REG_JOYRE;
391 if(choseval == 5)
392 {
393 //disable interrupts
394 u32 prevIrqMask = REG_IME;
395 REG_IME = 0;
396 //dump BIOS
397 for (i = 0; i < 0x4000; i+=4)
398 {
399 // the lower bits are inaccurate, so just get it four times :)
400 u32 a = MidiKey2Freq((WaveData *)(i-4), 180-12, 0) * 2;
401 u32 b = MidiKey2Freq((WaveData *)(i-3), 180-12, 0) * 2;
402 u32 c = MidiKey2Freq((WaveData *)(i-2), 180-12, 0) * 2;
403 u32 d = MidiKey2Freq((WaveData *)(i-1), 180-12, 0) * 2;
404 REG_JOYTR = ((a>>24<<24) | (d>>24<<16) | (c>>24<<8) | (b>>24));
405 while((REG_HS_CTRL&JOY_READ) == 0) ;
406 REG_HS_CTRL |= JOY_RW;
407 }
408 //restore interrupts
409 REG_IME = prevIrqMask;
410 }
411 REG_JOYTR = 0;
412 }*/
413 Halt();
414 }
239} 415}
240 416
241 417
diff --git a/gba/source/saveblocks.h b/gba/source/saveblocks.h new file mode 100644 index 0000000..cf0a5c3 --- /dev/null +++ b/gba/source/saveblocks.h
@@ -0,0 +1,343 @@
1/*
2 * Example Gen3-multiboot payload by slipstream/RoL 2017.
3 *
4 * This software may be modified and distributed under the terms
5 * of the MIT license. See the LICENSE file for details.
6 *
7 * saveblocks.h: describes saveblock structures for all of Gen 3 (yay!)
8 */
9
10// Most of the structures come from pokeruby, FR/LG changes come from my own research / the firered IDB on pokecommunity
11#include "savestructs.h"
12
13typedef struct
14{
15 /*0x00*/ struct Coords16 pos;
16 /*0x04*/ struct WarpData location;
17 /*0x0C*/ struct WarpData warp[4];
18 /*0x2C*/ u16 battleMusic;
19 /*0x2E*/ u8 weather;
20 /*0x2F*/ u8 filler_2F;
21 /*0x30*/ u8 flashUsed;
22 /*0x32*/ u16 mapDataId;
23 /*0x34*/ u16 mapView[0x100];
24 /*0x234*/ u8 playerPartyCount;
25 /*0x238*/ struct Pokemon playerParty[6];
26 /*0x490*/ u32 money;
27 /*0x494*/ u16 coins;
28 /*0x496*/ u16 registeredItem; // registered for use with SELECT button
29 /*0x498*/ struct ItemSlot pcItems[50];
30 /*0x560*/ struct ItemSlot bagPocket_Items[20];
31 /*0x5B0*/ struct ItemSlot bagPocket_KeyItems[20];
32 /*0x600*/ struct ItemSlot bagPocket_PokeBalls[16];
33 /*0x640*/ struct ItemSlot bagPocket_TMHM[64];
34 /*0x740*/ struct ItemSlot bagPocket_Berries[46];
35 /*0x7F8*/ struct Pokeblock pokeblocks[40];
36 /*0x938*/ u8 unk938[52]; // pokedex related
37 /*0x96C*/ u16 berryBlenderRecords[3];
38 /*0x972*/ u8 filler_972[0x6];
39 /*0x978*/ u16 trainerRematchStepCounter;
40 /*0x97A*/ u8 trainerRematches[100];
41 /*0x9E0*/ struct MapObject mapObjects[16];
42 /*0xC20*/ struct MapObjectTemplate mapObjectTemplates[64];
43 /*0x1220*/ u8 flags[0x120];
44 /*0x1340*/ u16 vars[0x100];
45 /*0x1540*/ u32 gameStats[50];
46 /*0x1608*/ struct BerryTree berryTrees[128];
47 /*0x1A08*/ struct SecretBaseRecord secretBases[20];
48 /*0x2688*/ u8 playerRoomDecor[12];
49 /*0x2694*/ u8 playerRoomDecorPos[12];
50 /*0x26A0*/ u8 decorDesk[10];
51 /*0x26AA*/ u8 decorChair[10];
52 /*0x26B4*/ u8 decorPlant[10];
53 /*0x26BE*/ u8 decorOrnament[30];
54 /*0x26DC*/ u8 decorMat[30];
55 /*0x26FA*/ u8 decorPoster[10];
56 /*0x2704*/ u8 decorDoll[40];
57 /*0x272C*/ u8 decorCushion[10];
58 /*0x2736*/ u8 padding_2736[2];
59 /*0x2738*/ TVShow tvShows[24];
60 /*0x2A98*/ u8 filler_2A98[0x64];
61 /*0x2AFC*/ u16 outbreakPokemonSpecies;
62 /*0x2AFE*/ u8 outbreakLocationMapNum;
63 /*0x2AFF*/ u8 outbreakLocationMapGroup;
64 /*0x2B00*/ u8 outbreakPokemonLevel;
65 /*0x2B01*/ u8 outbreakUnk1;
66 /*0x2B02*/ u16 outbreakUnk2;
67 /*0x2B04*/ u16 outbreakPokemonMoves[4];
68 /*0x2B0C*/ u8 outbreakUnk4;
69 /*0x2B0D*/ u8 outbreakPokemonProbability;
70 /*0x2B0E*/ u16 outbreakUnk5;
71 /*0x2B10*/ u8 filler_2B0E[0xC];
72 /*0x2B1C*/ u16 unk2B1C[4];
73 /*0x2B24*/ u8 filler_2B24[0x28];
74 /*0x2B4C*/ struct MailStruct mail[16];
75 /*0x2D8C*/ u8 filler_2D8C[0x8];
76 /*0x2D94*/ OldMan oldMan;
77 /*0x2DC0*/ u8 unk_2DC0[0x14];
78 /*0x2DD4*/ struct EasyChatPair easyChatPairs[5]; //Dewford trend [0] and some other stuff
79 /*0x2DFC*/ u8 filler_2DFC[0x100];
80 /*0x2EFC*/ struct SB1_2EFC_Struct sb1_2EFC_struct[5];
81 /*0x2F9C*/ u8 filler_2F9C[0xA0];
82 /*0x303C*/ u8 filler_303C[0x38];
83 /*0x3074*/ u8 filler_3074[0x42];
84 /*0x30B6*/ u8 filler_30B6;
85 /*0x30B7*/ u8 filler_30B7[0x59];
86 /*0x3110*/ u8 giftRibbons[7];
87 /*0x3117*/ u8 filler_311B[0x2D];
88 /*0x3144*/ struct Roamer roamer;
89 /*0x3158*/ u8 filler_3158[0x8];
90 /*0x3160*/ struct EnigmaBerry enigmaBerry; // this is actually offset by 0x98 ...
91 /*0x3690*/ struct RamScript ramScript;
92 /*0x3A7C*/ u8 filler_3A7C[0x10];
93 /*0x3A8C*/ u8 unk3A8C[52]; //pokedex related
94} SaveBlock1_RS;
95
96typedef struct // Don't rely on the commented offsets, they'll be wrong due to elements removed in FR/LG...
97{
98 /*0x00*/ struct Coords16 pos;
99 /*0x04*/ struct WarpData location;
100 /*0x0C*/ struct WarpData warp[4];
101 /*0x2C*/ u16 battleMusic;
102 /*0x2E*/ u8 weather;
103 /*0x2F*/ u8 filler_2F;
104 /*0x30*/ u8 flashUsed;
105 /*0x32*/ u16 mapDataId;
106// /*0x34*/ u16 mapView[0x100]; // Not in fr/lg
107 /*0x234*/ u8 playerPartyCount;
108 /*0x238*/ struct Pokemon playerParty[6];
109 /*0x490*/ u32 money;
110 /*0x494*/ u16 coins;
111 /*0x496*/ u16 registeredItem; // registered for use with SELECT button
112 /*0x498*/ struct ItemSlot pcItems[30];
113 /*0x560*/ struct ItemSlot bagPocket_Items[42];
114 /*0x5B0*/ struct ItemSlot bagPocket_KeyItems[30];
115 /*0x600*/ struct ItemSlot bagPocket_PokeBalls[13];
116 /*0x640*/ struct ItemSlot bagPocket_TMHM[58];
117 /*0x740*/ struct ItemSlot bagPocket_Berries[43];
118// /*0x7F8*/ struct Pokeblock pokeblocks[40]; // Not in fr/lg
119 /*0x938*/ u8 unk938[52]; // pokedex related
120 /*0x96C*/ u8 unk_62C[12];
121 /*0x972*/ u8 filler_972[0x6];
122 /*0x97A*/ u8 unk_63E[98];
123 /*0x9E0*/ struct MapObject mapObjects[16];
124 /*0xC20*/ struct MapObjectTemplate mapObjectTemplates[64];
125 /*0x1220*/ u8 flags[0x120];
126 /*0x1340*/ u16 vars[0x100];
127 /*0x1540*/ u32 gameStats[64]; // encrypted with saveblock2 xor-key
128 struct QuestStory questlog[4];
129 u8 messages[12][4];
130 struct NPCState npc_states[0x10];
131 u8 unk_2f10[112];
132 struct DaycarePokemon daycare[2];
133 u8 unk_3098[56];
134 struct Roamer roamer;
135 u8 unk_30e4[8];
136 /*0x3160*/ struct EnigmaBerryFRLGE enigmaBerry;
137 u8 unk_3120[0x1C0]; // 4 bytes of CRC16, then 444 bytes of unknown. Mystery Gift related.
138 u8 unk_32E0[0x150]; // 4 bytes of CRC16, then 332 bytes of unknown. Mystery Gift related. "mevent_buffer_1"
139 u8 unk_3430[0x150]; // 4 bytes of CRC16, then 332 bytes of unknown. Mystery Gift related. "mevent_buffer_2"
140 u8 unk_368C[0x9C]; // padding? doesn't seem to be actually used
141 struct RamScript ramScript;
142 u8 unk_3A07[17];
143 u8 pokemon_flags_2[52];
144 u8 rivalName[8];
145 u8 unk_3a54[128];
146 u8 words[21][10];
147 u8 unk_3ba6[570];
148} __attribute__((aligned(1))) SaveBlock1_FRLG;
149
150typedef struct // Don't rely on the commented offsets, they'll be wrong due to elements changed/added in Emerald...
151{
152 /*0x00*/ struct Coords16 pos;
153 /*0x04*/ struct WarpData location;
154 /*0x0C*/ struct WarpData warp[4];
155 /*0x2C*/ u16 battleMusic;
156 /*0x2E*/ u8 weather;
157 /*0x2F*/ u8 filler_2F;
158 /*0x30*/ u8 flashUsed;
159 /*0x32*/ u16 mapDataId;
160 /*0x34*/ u16 mapView[0x100];
161 /*0x234*/ u8 playerPartyCount;
162 /*0x238*/ struct Pokemon playerParty[6];
163 /*0x490*/ u32 money;
164 /*0x494*/ u16 coins;
165 /*0x496*/ u16 registeredItem; // registered for use with SELECT button
166 /*0x498*/ struct ItemSlot pcItems[50];
167 /*0x560*/ struct ItemSlot bagPocket_Items[30];
168 /*0x5D8*/ struct ItemSlot bagPocket_KeyItems[30];
169 /*0x650*/ struct ItemSlot bagPocket_PokeBalls[16];
170 /*0x690*/ struct ItemSlot bagPocket_TMHM[64];
171 /*0x790*/ struct ItemSlot bagPocket_Berries[46];
172 /*0x7F8*/ struct Pokeblock pokeblocks[40]; // every offset is shifted by 0x50 from here on thanks to changed bag-counts
173 /*0x938*/ u8 unk938[52]; // pokedex related
174 /*0x96C*/ u16 berryBlenderRecords[3];
175 /*0x972*/ u8 filler_972[0x6];
176 /*0x978*/ u16 trainerRematchStepCounter;
177 /*0x97A*/ u8 trainerRematches[100];
178 /*0x9E0*/ struct MapObject mapObjects[16];
179 /*0xC20*/ struct MapObjectTemplate mapObjectTemplates[64];
180 /*0x1220*/ u8 flags[0x12C];
181 /*0x1340*/ u16 vars[0x100]; // offsets shifted by 0x5C from here on thanks to added flags
182 /*0x1540*/ u32 gameStats[64]; // encrypted with saveblock2 xor-key
183 /*0x1608*/ struct BerryTree berryTrees[128]; // offsets shifted by 0x94 from here on thanks to added 14 gamestats
184 /*0x1A08*/ struct SecretBaseRecord secretBases[20];
185 /*0x2688*/ u8 playerRoomDecor[12];
186 /*0x2694*/ u8 playerRoomDecorPos[12];
187 /*0x26A0*/ u8 decorDesk[10];
188 /*0x26AA*/ u8 decorChair[10];
189 /*0x26B4*/ u8 decorPlant[10];
190 /*0x26BE*/ u8 decorOrnament[30];
191 /*0x26DC*/ u8 decorMat[30];
192 /*0x26FA*/ u8 decorPoster[10];
193 /*0x2704*/ u8 decorDoll[40];
194 /*0x272C*/ u8 decorCushion[10];
195 // /*0x2736*/ u8 padding_2736[2];
196 /*0x2738*/ TVShow tvShows[24];
197 /*0x2A98*/ u8 filler_2A98[0x64];
198 /*0x2AFC*/ u16 outbreakPokemonSpecies; // offset by 0x94
199 /*0x2AFE*/ u8 outbreakLocationMapNum;
200 /*0x2AFF*/ u8 outbreakLocationMapGroup;
201 /*0x2B00*/ u8 outbreakPokemonLevel;
202 /*0x2B01*/ u8 outbreakUnk1;
203 /*0x2B02*/ u16 outbreakUnk2;
204 /*0x2B04*/ u16 outbreakPokemonMoves[4];
205 /*0x2B0C*/ u8 outbreakUnk4;
206 /*0x2B0D*/ u8 outbreakPokemonProbability;
207 /*0x2B0E*/ u16 outbreakUnk5;
208 /*0x2B10*/ u8 filler_2B0E[0xC];
209 /*0x2B1C*/ u16 unk2B1C[4];
210 /*0x2B24*/ u8 filler_2B24[0x28];
211 /*0x2B4C*/ struct MailStruct mail[16]; // offset by 0x94
212 /*0x2D8C*/ u8 filler_2D8C[0x8];
213 /*0x2D94*/ OldMan oldMan;
214 /*0x2DC0*/ u8 unk_2DC0[0x14];
215 /*0x2DD4*/ struct EasyChatPair easyChatPairs[5]; //Dewford trend [0] and some other stuff
216 // /*0x2DFC*/ u8 filler_2DFC[0x100];
217 /*0x2EFC*/ struct SB1_2EFC_Struct sb1_2EFC_struct[12];
218 u8 unk_3010[0x198]; // no idea if any of this is actually used.
219 /*0x3110*/ u8 giftRibbons[7];
220 /*0x3117*/ u8 filler_311B[0x2D];
221 /*0x3144*/ struct Roamer roamer;
222 /*0x3158*/ u8 filler_3158[0x8];
223 /*0x3160*/ struct EnigmaBerryFRLGE enigmaBerry;
224 u8 unk_322C[0x1C0]; // 4 bytes of CRC16, then 444 bytes of unknown. Mystery Gift related.
225 u8 unk_33EC[0x150]; // 4 bytes of CRC16, then 332 bytes of unknown. Mystery Gift related. "mevent_buffer_1"
226 u8 unk_353C[0x150]; // 4 bytes of CRC16, then 332 bytes of unknown. Mystery Gift related. "mevent_buffer_2"
227 u8 unk_368C[0x9C]; // padding? doesn't seem to be actually used
228 /*0x3690*/ struct RamScript ramScript;
229 /*0x3A7C*/ u8 filler_3A7C[0x10];
230 /*0x3A8C*/ u8 unk3A8C[52]; //pokedex related
231} SaveBlock1_E;
232
233// ---
234
235struct SaveBlock2_Sub
236{
237 /*0x0000, 0x00A8*/ u8 filler_000[0x4AE];
238 /*0x04AE, 0x0556*/ u8 var_4AE;
239 /*0x04AF, 0x0557*/ u8 var_4AF;
240 /*0x04B0, 0x0558*/ u16 var_4B0;
241 /*0x04B2, 0x055A*/ u16 var_4B2;
242 /*0x04B4, 0x055C*/ u16 var_4B4;
243 /*0x04B6, 0x055E*/ u16 var_4B6;
244 /*0x04B8, 0x0560*/ u8 filler_4B8[0x10];
245 /*0x04C8, 0x0570*/ u16 var_4C8;
246 /*0x04CA, 0x0572*/ u16 var_4CA;
247 /*0x04CC, 0x0574*/ u8 filler_4CC[0x31C];
248};
249
250typedef struct
251{
252 /*0x00*/ u8 playerName[8];
253 /*0x08*/ u8 playerGender; // MALE, FEMALE
254 /*0x09*/ u8 specialSaveWarp;
255 /*0x0A*/ u8 playerTrainerId[4];
256 /*0x0E*/ u16 playTimeHours;
257 /*0x10*/ u8 playTimeMinutes;
258 /*0x11*/ u8 playTimeSeconds;
259 /*0x12*/ u8 playTimeVBlanks;
260 /*0x13*/ u8 optionsButtonMode; // OPTIONS_BUTTON_MODE_[NORMAL/LR/L_EQUALS_A]
261 /*0x14*/ u16 optionsTextSpeed:3; // OPTIONS_TEXT_SPEED_[SLOW/MID/FAST]
262 u16 optionsWindowFrameType:5; // Specifies one of the 20 decorative borders for text boxes
263 u16 optionsSound:1; // OPTIONS_SOUND_[MONO/STEREO]
264 u16 optionsBattleStyle:1; // OPTIONS_BATTLE_STYLE_[SHIFT/SET]
265 u16 optionsBattleSceneOff:1; // whether battle animations are disabled
266 u16 regionMapZoom:1; // whether the map is zoomed in
267 /*0x18*/ struct Pokedex pokedex;
268 /*0x90*/ u8 filler_90[0x8];
269 /*0x98*/ struct Time localTimeOffset;
270 /*0xA0*/ struct Time lastBerryTreeUpdate;
271 /*0xA8*/ struct SaveBlock2_Sub filler_A8;
272} SaveBlock2_RS;
273
274typedef struct
275{
276 /*0x00*/ u8 playerName[8];
277 /*0x08*/ u8 playerGender; // MALE, FEMALE
278 /*0x09*/ u8 specialSaveWarp;
279 /*0x0A*/ u8 playerTrainerId[4];
280 /*0x0E*/ u16 playTimeHours;
281 /*0x10*/ u8 playTimeMinutes;
282 /*0x11*/ u8 playTimeSeconds;
283 /*0x12*/ u8 playTimeVBlanks;
284 /*0x13*/ u8 optionsButtonMode; // OPTIONS_BUTTON_MODE_[NORMAL/LR/L_EQUALS_A]
285 /*0x14*/ u16 optionsTextSpeed:3; // OPTIONS_TEXT_SPEED_[SLOW/MID/FAST]
286 u16 optionsWindowFrameType:5; // Specifies one of the 20 decorative borders for text boxes
287 u16 optionsSound:1; // OPTIONS_SOUND_[MONO/STEREO]
288 u16 optionsBattleStyle:1; // OPTIONS_BATTLE_STYLE_[SHIFT/SET]
289 u16 optionsBattleSceneOff:1; // whether battle animations are disabled
290 u16 regionMapZoom:1; // whether the map is zoomed in
291 /*0x18*/ struct Pokedex pokedex;
292 /*0x90*/ u8 filler_90[0x8];
293 /*0x98*/ struct Time localTimeOffset;
294 /*0xA0*/ struct Time lastBerryTreeUpdate;
295 /*0xA8*/ struct SaveBlock2_Sub filler_A8;
296 /*0x890*/ u8 unk_890[8];
297 /*0x898*/ u8 mapdata[0x258];
298 /*0xaf0*/ u16 field_af0;
299 /*0xaf2*/ u16 field_af2;
300 /*0xaf4*/ u16 field_af4;
301 /*0xaf6*/ u16 field_af6;
302 /*0xaf8*/ u8 unk_af8[0x428];
303 /*0xf20*/ u32 xor_key;
304} SaveBlock2_FRLG;
305
306typedef struct
307{
308 /*0x00*/ u8 playerName[8];
309 /*0x08*/ u8 playerGender; // MALE, FEMALE
310 /*0x09*/ u8 specialSaveWarp;
311 /*0x0A*/ u8 playerTrainerId[4];
312 /*0x0E*/ u16 playTimeHours;
313 /*0x10*/ u8 playTimeMinutes;
314 /*0x11*/ u8 playTimeSeconds;
315 /*0x12*/ u8 playTimeVBlanks;
316 /*0x13*/ u8 optionsButtonMode; // OPTIONS_BUTTON_MODE_[NORMAL/LR/L_EQUALS_A]
317 /*0x14*/ u16 optionsTextSpeed:3; // OPTIONS_TEXT_SPEED_[SLOW/MID/FAST]
318 u16 optionsWindowFrameType:5; // Specifies one of the 20 decorative borders for text boxes
319 u16 optionsSound:1; // OPTIONS_SOUND_[MONO/STEREO]
320 u16 optionsBattleStyle:1; // OPTIONS_BATTLE_STYLE_[SHIFT/SET]
321 u16 optionsBattleSceneOff:1; // whether battle animations are disabled
322 u16 regionMapZoom:1; // whether the map is zoomed in
323 /*0x18*/ struct Pokedex pokedex;
324 /*0x90*/ u8 filler_90[0x8];
325 /*0x98*/ struct Time localTimeOffset;
326 /*0xA0*/ struct Time lastBerryTreeUpdate;
327 /*0xA8*/ u32 xor_key;
328 /*0xAC*/ struct SaveBlock2_Sub filler_A8;
329} SaveBlock2_E;
330
331typedef union {
332 SaveBlock1_RS rs;
333 SaveBlock1_FRLG frlg;
334 SaveBlock1_E e;
335} SaveBlock1, *pSaveBlock1;
336
337typedef union {
338 SaveBlock2_RS rs;
339 SaveBlock2_FRLG frlg;
340 SaveBlock2_E e;
341} SaveBlock2, *pSaveBlock2;
342
343typedef struct PokemonStorage SaveBlock3, *pSaveBlock3; \ No newline at end of file
diff --git a/gba/source/savestructs.h b/gba/source/savestructs.h new file mode 100644 index 0000000..2bf4d4d --- /dev/null +++ b/gba/source/savestructs.h
@@ -0,0 +1,793 @@
1/*
2 * Example Gen3-multiboot payload by slipstream/RoL 2017.
3 *
4 * This software may be modified and distributed under the terms
5 * of the MIT license. See the LICENSE file for details.
6 *
7 * saveblocks.h: describes structures used by saveblocks for all of Gen 3
8 */
9
10// Most of the structures come from pokeruby, FR/LG changes come from my own research / the firered IDB on pokecommunity
11
12#define POKEMON_NAME_LENGTH 10
13#define OT_NAME_LENGTH 7
14#define TILE_SIZE_4BPP 32
15
16struct Coords16
17{
18 s16 x;
19 s16 y;
20};
21
22struct UCoords16
23{
24 u16 x;
25 u16 y;
26};
27
28struct SecretBaseRecord
29{
30 u8 sbr_field_0; // ID?
31 u8 sbr_field_1_0:4;
32 u8 gender:1;
33 u8 sbr_field_1_5:1;
34 u8 sbr_field_2[7]; // 0xFF bytes?
35 u8 trainerId[4]; // byte 0 is used for determining trainer class
36 u16 sbr_field_e;
37 u8 sbr_field_10;
38 u8 sbr_field_11;
39 u8 decorations[16];
40 u8 sbr_field_22[16];
41 u32 partyPersonality[6];
42 u16 partyMoves[6 * 4];
43 u16 partySpecies[6];
44 u16 partyHeldItems[6];
45 u8 partyLevels[6];
46 u8 partyEVs[6];
47};
48
49typedef void (*TilesetCB)(void);
50
51struct Tileset
52{
53 u8 isCompressed;
54 u8 isSecondary;
55 void *tiles;
56 void *palettes;
57 void *metatiles;
58 void *metatileAttributes;
59 TilesetCB callback;
60};
61
62struct MapData
63{
64 s32 width;
65 s32 height;
66 u16 *border;
67 u16 *map;
68 struct Tileset *primaryTileset;
69 struct Tileset *secondaryTileset;
70};
71
72struct MapObjectTemplate
73{
74 /*0x00*/ u8 localId;
75 /*0x01*/ u8 graphicsId;
76 /*0x02*/ u8 unk2;
77 /*0x04*/ s16 x;
78 /*0x06*/ s16 y;
79 /*0x08*/ u8 elevation;
80 /*0x09*/ u8 movementType;
81 /*0x0A*/ u8 unkA_0:4;
82 u8 unkA_4:4;
83 ///*0x0B*/ u8 fillerB[1];
84 /*0x0C*/ u16 unkC;
85 /*0x0E*/ u16 unkE;
86 /*0x10*/ u8 *script;
87 /*0x14*/ u16 flagId;
88 /*0x16*/ u8 filler_16[2];
89}; /*size = 0x18*/
90
91struct WarpEvent
92{
93 s16 x, y;
94 s8 warpId;
95 u8 mapGroup;
96 u8 mapNum;
97 u8 unk7;
98};
99
100struct CoordEvent
101{
102 s16 x, y;
103 u8 unk4;
104 u8 filler_5;
105 u16 trigger;
106 u16 index;
107 u8 filler_A[0x2];
108 u8 *script;
109};
110
111struct BgEvent
112{
113 s16 x, y;
114 u8 unk4;
115 u8 kind;
116 s16 filler_6;
117 u8 *script;
118};
119
120struct MapEvents
121{
122 u8 mapObjectCount;
123 u8 warpCount;
124 u8 coordEventCount;
125 u8 bgEventCount;
126
127 struct MapObjectTemplate *mapObjects;
128 struct WarpEvent *warps;
129 struct CoordEvent *coordEvents;
130 struct BgEvent *bgEvents;
131};
132
133struct MapConnection
134{
135 u8 direction;
136 u32 offset;
137 u8 mapGroup;
138 u8 mapNum;
139};
140
141struct MapConnections
142{
143 s32 count;
144 struct MapConnection *connections;
145};
146
147struct MapHeader
148{
149 struct MapData *mapData;
150 struct MapEvents *events;
151 u8 *mapScripts;
152 struct MapConnections *connections;
153 u16 music;
154 u16 mapDataId;
155 u8 name;
156 u8 cave;
157 u8 weather;
158 /* 0x17 */ u8 mapType;
159 u8 filler_18;
160 u8 escapeRope;
161 u8 flags;
162 u8 battleType;
163};
164
165struct MapObject
166{
167 /*0x00*/ u32 active:1;
168 u32 mapobj_bit_1:1;
169 u32 mapobj_bit_2:1;
170 u32 mapobj_bit_3:1;
171 u32 mapobj_bit_4:1;
172 u32 mapobj_bit_5:1;
173 u32 mapobj_bit_6:1;
174 u32 mapobj_bit_7:1;
175 /*0x01*/ u32 mapobj_bit_8:1;
176 u32 mapobj_bit_9:1;
177 u32 mapobj_bit_10:1;
178 u32 mapobj_bit_11:1;
179 u32 mapobj_bit_12:1;
180 u32 mapobj_bit_13:1;
181 u32 mapobj_bit_14:1;
182 u32 mapobj_bit_15:1;
183 /*0x02*/ u32 mapobj_bit_16:1;
184 u32 mapobj_bit_17:1;
185 u32 mapobj_bit_18:1;
186 u32 mapobj_bit_19:1;
187 u32 mapobj_bit_20:1;
188 u32 mapobj_bit_21:1;
189 u32 mapobj_bit_22:1;
190 u32 mapobj_bit_23:1;
191 /*0x03*/ u32 mapobj_bit_24:1;
192 u32 mapobj_bit_25:1;
193 u32 mapobj_bit_26:1;
194 u32 mapobj_bit_27:1;
195 u32 mapobj_bit_28:1;
196 u32 mapobj_bit_29:1;
197 u32 mapobj_bit_30:1;
198 u32 mapobj_bit_31:1;
199 /*0x04*/ u8 spriteId;
200 /*0x05*/ u8 graphicsId;
201 /*0x06*/ u8 animPattern;
202 /*0x07*/ u8 trainerType;
203 /*0x08*/ u8 localId;
204 /*0x09*/ u8 mapNum;
205 /*0x0A*/ u8 mapGroup;
206 /*0x0B*/ u8 mapobj_unk_0B_0:4;
207 u8 elevation:4;
208 /*0x0C*/ struct Coords16 coords1;
209 /*0x10*/ struct Coords16 coords2;
210 /*0x14*/ struct Coords16 coords3;
211 /*0x18*/ u8 mapobj_unk_18:4; //current direction?
212 /*0x18*/ u8 placeholder18:4;
213 /*0x19*/ u8 mapobj_unk_19;
214 /*0x1A*/ u8 mapobj_unk_1A;
215 /*0x1B*/ u8 mapobj_unk_1B;
216 /*0x1C*/ u8 mapobj_unk_1C;
217 /*0x1D*/ u8 trainerRange_berryTreeId;
218 /*0x1E*/ u8 mapobj_unk_1E;
219 /*0x1F*/ u8 mapobj_unk_1F;
220 /*0x20*/ u8 mapobj_unk_20;
221 /*0x21*/ u8 mapobj_unk_21;
222 /*0x22*/ u8 animId;
223 /*size = 0x24*/
224};
225
226struct Berry
227{
228 const u8 name[7];
229 u8 firmness;
230 u16 size;
231 u8 maxYield;
232 u8 minYield;
233 const u8 *description1;
234 const u8 *description2;
235 u8 stageDuration;
236 u8 spicy;
237 u8 dry;
238 u8 sweet;
239 u8 bitter;
240 u8 sour;
241 u8 smoothness;
242};
243
244struct EnigmaBerry
245{
246 struct Berry berry;
247 u8 pic[(6 * 6) * TILE_SIZE_4BPP];
248 u16 palette[16];
249 u8 description1[45];
250 u8 description2[45];
251 u8 itemEffect[18];
252 u8 holdEffect;
253 u8 holdEffectParam;
254 u32 checksum;
255};
256
257struct BattleEnigmaBerry
258{
259 u8 name[7];
260 u8 holdEffect;
261 u8 itemEffect[18];
262 u8 holdEffectParam;
263};
264
265struct EnigmaBerryFRLGE {
266 struct Berry berry; // 0x00
267 u8 itemEffect[18]; // 0x1C
268 u8 holdEffect; // 0x2E
269 u8 holdEffectParam; // 0x2F
270 u32 checksum; // 0x30
271};
272
273struct __attribute__((aligned(4))) BerryTree
274{
275 u8 berry;
276 u8 stage:7;
277 u8 growthSparkle:1;
278 u16 secondsUntilNextStage;
279 u8 berryYield;
280 u8 regrowthCount:4;
281 u8 watered1:1;
282 u8 watered2:1;
283 u8 watered3:1;
284 u8 watered4:1;
285};
286
287struct PokemonSubstruct0
288{
289 u16 species;
290 u16 heldItem;
291 u32 experience;
292 u8 ppBonuses;
293 u8 friendship;
294};
295
296struct PokemonSubstruct1
297{
298 u16 moves[4];
299 u8 pp[4];
300};
301
302struct PokemonSubstruct2
303{
304 u8 hpEV;
305 u8 attackEV;
306 u8 defenseEV;
307 u8 speedEV;
308 u8 spAttackEV;
309 u8 spDefenseEV;
310 u8 cool;
311 u8 beauty;
312 u8 cute;
313 u8 smart;
314 u8 tough;
315 u8 sheen;
316};
317
318struct PokemonSubstruct3
319{
320 /* 0x00 */ u8 pokerus;
321 /* 0x01 */ u8 metLocation;
322
323 /* 0x02 */ u16 metLevel:7;
324 /* 0x02 */ u16 metGame:4;
325 /* 0x03 */ u16 pokeball:4;
326 /* 0x03 */ u16 otGender:1;
327
328 /* 0x04 */ u32 hpIV:5;
329 /* 0x04 */ u32 attackIV:5;
330 /* 0x05 */ u32 defenseIV:5;
331 /* 0x05 */ u32 speedIV:5;
332 /* 0x05 */ u32 spAttackIV:5;
333 /* 0x06 */ u32 spDefenseIV:5;
334 /* 0x07 */ u32 isEgg:1;
335 /* 0x07 */ u32 altAbility:1;
336
337 /* 0x08 */ u32 coolRibbon:3;
338 /* 0x08 */ u32 beautyRibbon:3;
339 /* 0x08 */ u32 cuteRibbon:3;
340 /* 0x09 */ u32 smartRibbon:3;
341 /* 0x09 */ u32 toughRibbon:3;
342 /* 0x09 */ u32 championRibbon:1;
343 /* 0x0A */ u32 winningRibbon:1;
344 /* 0x0A */ u32 victoryRibbon:1;
345 /* 0x0A */ u32 artistRibbon:1;
346 /* 0x0A */ u32 effortRibbon:1;
347 /* 0x0A */ u32 giftRibbon1:1;
348 /* 0x0A */ u32 giftRibbon2:1;
349 /* 0x0A */ u32 giftRibbon3:1;
350 /* 0x0A */ u32 giftRibbon4:1;
351 /* 0x0B */ u32 giftRibbon5:1;
352 /* 0x0B */ u32 giftRibbon6:1;
353 /* 0x0B */ u32 giftRibbon7:1;
354 /* 0x0B */ u32 fatefulEncounter:5; // unused in Ruby/Sapphire, but the high bit must be set for Mew/Deoxys to obey in FR/LG/Emerald
355};
356
357union PokemonSubstruct
358{
359 struct PokemonSubstruct0 type0;
360 struct PokemonSubstruct1 type1;
361 struct PokemonSubstruct2 type2;
362 struct PokemonSubstruct3 type3;
363 u16 raw[6];
364};
365
366struct BoxPokemon
367{
368 u32 personality;
369 u32 otId;
370 u8 nickname[POKEMON_NAME_LENGTH];
371 u8 language;
372 u8 isBadEgg:1;
373 u8 hasSpecies:1;
374 u8 isEgg:1;
375 u8 unused:5;
376 u8 otName[OT_NAME_LENGTH];
377 u8 markings;
378 u16 checksum;
379 u16 unknown;
380
381 union
382 {
383 u32 raw[12];
384 union PokemonSubstruct substructs[4];
385 } secure;
386};
387
388struct Pokemon
389{
390 struct BoxPokemon box;
391 u32 status;
392 u8 level;
393 u8 pokerus;
394 u16 hp;
395 u16 maxHP;
396 u16 attack;
397 u16 defense;
398 u16 speed;
399 u16 spAttack;
400 u16 spDefense;
401};
402
403struct UnknownPokemonStruct
404{
405 u16 species;
406 u16 heldItem;
407 u16 moves[4];
408 u8 level;
409 u8 ppBonuses;
410 u8 hpEV;
411 u8 attackEV;
412 u8 defenseEV;
413 u8 speedEV;
414 u8 spAttackEV;
415 u8 spDefenseEV;
416 u32 otId;
417 u32 hpIV:5;
418 u32 attackIV:5;
419 u32 defenseIV:5;
420 u32 speedIV:5;
421 u32 spAttackIV:5;
422 u32 spDefenseIV:5;
423 u32 gap:1;
424 u32 altAbility:1;
425 u32 personality;
426 u8 nickname[POKEMON_NAME_LENGTH + 1];
427 u8 friendship;
428};
429
430struct BattlePokemon
431{
432 /* 0x00 */ u16 species;
433 /* 0x02 */ u16 attack;
434 /* 0x04 */ u16 defense;
435 /* 0x06 */ u16 speed;
436 /* 0x08 */ u16 spAttack;
437 /* 0x0A */ u16 spDefense;
438 /* 0x0C */ u16 moves[4];
439 /* 0x14 */ u32 hpIV:5;
440 /* 0x14 */ u32 attackIV:5;
441 /* 0x15 */ u32 defenseIV:5;
442 /* 0x15 */ u32 speedIV:5;
443 /* 0x16 */ u32 spAttackIV:5;
444 /* 0x17 */ u32 spDefenseIV:5;
445 /* 0x17 */ u32 isEgg:1;
446 /* 0x17 */ u32 altAbility:1;
447 /* 0x18 */ s8 statStages[8];
448 /* 0x20 */ u8 ability;
449 /* 0x21 */ u8 type1;
450 /* 0x22 */ u8 type2;
451 /* 0x23 */ u8 unknown;
452 /* 0x24 */ u8 pp[4];
453 /* 0x28 */ u16 hp;
454 /* 0x2A */ u8 level;
455 /* 0x2B */ u8 friendship;
456 /* 0x2C */ u16 maxHP;
457 /* 0x2E */ u16 item;
458 /* 0x30 */ u8 nickname[POKEMON_NAME_LENGTH + 1];
459 /* 0x3B */ u8 ppBonuses;
460 /* 0x3C */ u8 otName[8];
461 /* 0x44 */ u32 experience;
462 /* 0x48 */ u32 personality;
463 /* 0x4C */ u32 status1;
464 /* 0x50 */ u32 status2;
465 /* 0x54 */ u32 otId;
466};
467
468struct BaseStats
469{
470 /* 0x00 */ u8 baseHP;
471 /* 0x01 */ u8 baseAttack;
472 /* 0x02 */ u8 baseDefense;
473 /* 0x03 */ u8 baseSpeed;
474 /* 0x04 */ u8 baseSpAttack;
475 /* 0x05 */ u8 baseSpDefense;
476 /* 0x06 */ u8 type1;
477 /* 0x07 */ u8 type2;
478 /* 0x08 */ u8 catchRate;
479 /* 0x09 */ u8 expYield;
480 /* 0x0A */ u16 evYield_HP:2;
481 /* 0x0A */ u16 evYield_Attack:2;
482 /* 0x0A */ u16 evYield_Defense:2;
483 /* 0x0A */ u16 evYield_Speed:2;
484 /* 0x0B */ u16 evYield_SpAttack:2;
485 /* 0x0B */ u16 evYield_SpDefense:2;
486 /* 0x0C */ u16 item1;
487 /* 0x0E */ u16 item2;
488 /* 0x10 */ u8 genderRatio;
489 /* 0x11 */ u8 eggCycles;
490 /* 0x12 */ u8 friendship;
491 /* 0x13 */ u8 growthRate;
492 /* 0x14 */ u8 eggGroup1;
493 /* 0x15 */ u8 eggGroup2;
494 /* 0x16 */ u8 ability1;
495 /* 0x17 */ u8 ability2;
496 /* 0x18 */ u8 safariZoneFleeRate;
497 /* 0x19 */ u8 bodyColor;
498};
499
500struct BattleMove
501{
502 u8 effect;
503 u8 power;
504 u8 type;
505 u8 accuracy;
506 u8 pp;
507 u8 secondaryEffectChance;
508 u8 target;
509 u8 priority;
510 u32 flags;
511};
512
513struct PokemonStorage
514{
515 /* 0x00 */ u8 currentBox;
516 /* 0x01 */ struct BoxPokemon boxes[14][30];
517 u8 boxNames[14][9];
518 u8 boxBackground[14];
519};
520
521struct WarpData
522{
523 s8 mapGroup;
524 s8 mapNum;
525 s8 warpId;
526 s16 x, y;
527};
528
529struct ItemSlot
530{
531 u16 itemId;
532 u16 quantity;
533};
534
535struct __attribute__((aligned(2))) Pokeblock
536{
537 u8 color;
538 u8 spicy;
539 u8 dry;
540 u8 sweet;
541 u8 bitter;
542 u8 sour;
543 u8 feel;
544};
545
546struct Roamer
547{
548 /*0x00*/ u32 ivs;
549 /*0x04*/ u32 personality;
550 /*0x08*/ u16 species;
551 /*0x0A*/ u16 hp;
552 /*0x0C*/ u8 level;
553 /*0x0D*/ u8 status;
554 /*0x0E*/ u8 cool;
555 /*0x0F*/ u8 beauty;
556 /*0x10*/ u8 cute;
557 /*0x11*/ u8 smart;
558 /*0x12*/ u8 tough;
559 /*0x13*/ u8 active;
560};
561
562struct RamScriptData
563{
564 u8 magic;
565 u8 mapGroup;
566 u8 mapNum;
567 u8 objectId;
568 u8 script[995];
569} __attribute__((aligned(1),packed));
570
571struct RamScript
572{
573 u32 checksum;
574 struct RamScriptData data;
575} __attribute__((aligned(1),packed));
576
577struct SB1_2EFC_Struct
578{
579 u8 unknown[0x20];
580};
581
582struct EasyChatPair
583{
584 u16 unk0_0:7;
585 u16 unk0_7:7;
586 u16 unk1_6:1;
587 u16 unk2;
588 u16 words[2];
589}; /*size = 0x8*/
590
591struct TVShowCommon {
592 /*0x00*/ u8 var00;
593 /*0x01*/ u8 var01;
594};
595
596struct TVShowFanClubLetter {
597 /*0x00*/ u8 var00;
598 /*0x01*/ u8 var01;
599 /*0x02*/ u16 species;
600 u8 pad04[12];
601 /*0x10*/ u8 playerName[8];
602 /*0x18*/ u8 var18;
603};
604
605struct TVShowRecentHappenings {
606 /*0x00*/ u8 var00;
607 /*0x01*/ u8 var01;
608 /*0x02*/ u16 var02;
609 u8 pad04[12];
610 /*0x10*/ u8 var10[8];
611 /*0x18*/ u8 var18;
612 u8 pad19[10];
613};
614
615struct TVShowFanclubOpinions {
616 /*0x00*/ u8 var00;
617 /*0x01*/ u8 var01;
618 /*0x02*/ u16 var02;
619 /*0x04*/ u8 var04A:4;
620 u8 var04B:4;
621 /*0x04*/ u8 var05[8];
622 /*0x0D*/ u8 var0D;
623 /*0x0E*/ u8 var0E;
624 /*0x0F*/ u8 var0F;
625 /*0x10*/ u8 var10[8];
626};
627
628struct TVShowNameRaterShow {
629 /*0x00*/ u8 var00;
630 /*0x01*/ u8 var01;
631 /*0x02*/ u16 species;
632 /*0x04*/ u8 pokemonName[11];
633 /*0x0F*/ u8 trainerName[11];
634 /*0x1A*/ u8 random;
635 /*0x1B*/ u8 random2;
636 /*0x1C*/ u16 var1C;
637 /*0x1E*/ u8 language;
638 /*0x1F*/ u8 var1F;
639};
640
641struct TVShowMassOutbreak {
642 /*0x00*/ u8 var00;
643 /*0x01*/ u8 var01;
644 /*0x02*/ u8 var02;
645 /*0x03*/ u8 var03;
646 /*0x04*/ u16 moves[4];
647 /*0x0C*/ u16 species;
648 /*0x0E*/ u16 var0E;
649 /*0x10*/ u8 locationMapNum;
650 /*0x11*/ u8 locationMapGroup;
651 /*0x12*/ u8 var12;
652 /*0x13*/ u8 probability;
653 /*0x14*/ u8 level;
654 /*0x15*/ u8 var15;
655 /*0x16*/ u16 var16;
656 /*0x18*/ u8 var18;
657 u8 pad19[11];
658};
659
660typedef union TVShow {
661 struct TVShowCommon common;
662 struct TVShowFanClubLetter fanclubLetter;
663 struct TVShowRecentHappenings recentHappenings;
664 struct TVShowFanclubOpinions fanclubOpinions;
665 struct TVShowNameRaterShow nameRaterShow;
666 struct TVShowMassOutbreak massOutbreak;
667} TVShow;
668
669struct __attribute__((aligned(4))) MailStruct
670{
671 /*0x00*/ u16 words[9];
672 /*0x12*/ u8 playerName[8];
673 /*0x1A*/ u8 trainerId[4];
674 /*0x1E*/ u16 species;
675 /*0x20*/ u16 itemId;
676};
677
678struct UnkMauvilleOldManStruct
679{
680 u8 unk_2D94;
681 u8 unk_2D95;
682 /*0x2D96*/ u16 mauvilleOldMan_ecArray[6];
683 /*0x2DA2*/ u16 mauvilleOldMan_ecArray2[6];
684 /*0x2DAE*/ u8 playerName[8];
685 /*0x2DB6*/ u8 filler_2DB6[0x3];
686 /*0x2DB9*/ u8 playerTrainerId[4];
687 u8 unk_2DBD;
688 /* size = 0x2C */
689};
690
691struct UnkMauvilleOldManStruct2
692{
693 u8 filler0;
694 u8 unk1;
695 u8 unk2;
696 u16 mauvilleOldMan_ecArray[10];
697 u16 mauvilleOldMan_ecArray2[6];
698 u8 fillerF[0x2];
699 /* size = 0x2C */
700};
701
702typedef union OldMan {
703 struct UnkMauvilleOldManStruct oldMan1;
704 struct UnkMauvilleOldManStruct2 oldMan2;
705} OldMan;
706
707struct QuestStoryNPC {
708 u16 bitfield;
709 u8 direction;
710 u8 height;
711 u8 type_id;
712 u8 running_behaviour_or_picture_id;
713 u8 is_trainer;
714 u8 local_id;
715 u8 local_mapnumber;
716 u8 local_mapbank;
717 u16 x;
718 u16 y;
719 u8 sight_distance;
720 u8 role_from;
721 u8 unknown_decrement_on_step;
722 u8 unk_11;
723 u16 padding_12;
724};
725
726struct QuestStory {
727 u8 active;
728 u8 bank;
729 u8 map;
730 u8 warpId;
731 u16 x;
732 u16 y;
733 struct QuestStoryNPC npc[0x10];
734 u8 unk_148[0x51f];
735};
736
737struct NPCState {
738 u8 bitfield;
739 u8 obj_anim_and_vis_control;
740 u8 unk_2;
741 u8 unk_3;
742 u8 oamid;
743 u8 type_id;
744 u8 running_behaviour_or_picture_id;
745 u8 is_trainer;
746 u8 local_id;
747 u8 local_mapnumber;
748 u8 local_mapbank;
749 u8 height;
750 struct Coords16 stay_around;
751 struct Coords16 to;
752 struct Coords16 from;
753 u8 direction;
754 u8 movement_area;
755 u8 objid_surfing;
756 u8 objid_1B;
757 u8 idx_movement_behaviour;
758 u8 sight_distance;
759 u8 role_to;
760 u8 role_from;
761 u8 unk_20;
762 u8 unknown_decrement_on_step;
763 u8 unk_22;
764 u8 unk_23;
765};
766
767struct DaycarePokemon {
768 struct BoxPokemon pokemon;
769 u8 unk_50[56];
770 u32 steps;
771};
772
773
774struct Time
775{
776 /*0x00*/ s16 days;
777 /*0x02*/ s8 hours;
778 /*0x03*/ s8 minutes;
779 /*0x04*/ s8 seconds;
780};
781
782struct Pokedex
783{
784 /*0x00*/ u8 order;
785 /*0x01*/ u8 unknown1;
786 /*0x02*/ u8 nationalMagic; // must equal 0xDA in order to have National mode
787 /*0x03*/ u8 unknown2;
788 /*0x04*/ u32 unownPersonality; // set when you first see Unown
789 /*0x08*/ u32 spindaPersonality; // set when you first see Spinda
790 /*0x0C*/ u32 unknown3;
791 /*0x10*/ u8 owned[52];
792 /*0x44*/ u8 seen[52];
793}; \ No newline at end of file
diff --git a/gba/start/pkjb_crt0.s b/gba/start/pkjb_crt0.s new file mode 100644 index 0000000..0d9d657 --- /dev/null +++ b/gba/start/pkjb_crt0.s
@@ -0,0 +1,102 @@
1 .section ".init"
2 .global _start
3 .align
4 .arm
5@---------------------------------------------------------------------------------
6_start:
7@---------------------------------------------------------------------------------
8 b rom_header_end
9
10 .fill 156,1,0 @ Nintendo Logo Character Data (8000004h)
11 .fill 16,1,0 @ Game Title
12 .byte 0x30,0x31 @ Maker Code (80000B0h)
13 .byte 0x96 @ Fixed Value (80000B2h)
14 .byte 0x00 @ Main Unit Code (80000B3h)
15 .byte 0x00 @ Device Type (80000B4h)
16 .fill 7,1,0 @ unused
17 .byte 0x00 @ Software Version No (80000BCh)
18 .byte 0xf0 @ Complement Check (80000BDh)
19 .byte 0x00,0x00 @ Checksum (80000BEh)
20
21@---------------------------------------------------------------------------------
22rom_header_end:
23@---------------------------------------------------------------------------------
24 b start_vector @ This branch must be here for proper
25 @ positioning of the following header.
26
27 .GLOBAL __boot_method, __slave_number
28@---------------------------------------------------------------------------------
29__boot_method:
30@---------------------------------------------------------------------------------
31 .byte 0 @ boot method (0=ROM boot, 3=Multiplay boot)
32@---------------------------------------------------------------------------------
33__slave_number:
34@---------------------------------------------------------------------------------
35 .byte 0 @ slave # (1=slave#1, 2=slave#2, 3=slave#3)
36
37 .byte 0 @ reserved
38 .byte 0 @ reserved
39 .word 0 @ reserved
40 .word 0 @ reserved
41 .word 0 @ reserved
42 .word 0 @ reserved
43 .word 0 @ reserved
44 .word 0 @ reserved
45
46 .fill 4096,1,0 @ 4kb of filler so no useful code gets overwritten when flash bytes get copied over the top.
47 .global start_vector
48 .align
49@---------------------------------------------------------------------------------
50start_vector:
51@---------------------------------------------------------------------------------
52
53@---------------------------------------------------------------------------------
54@ Enter Thumb mode
55@---------------------------------------------------------------------------------
56 add r0, pc, #1
57 bx r0
58
59 .thumb
60@ Turn off sound
61 ldr r1, =0x4000084
62 eor r0, r0, r0
63 strh r0, [r1]
64
65@---------------------------------------------------------------------------------
66@ set heap end
67@---------------------------------------------------------------------------------
68 ldr r1, =fake_heap_end
69 ldr r0, =__eheap_end
70 str r0, [r1]
71@---------------------------------------------------------------------------------
72@ global constructors
73@---------------------------------------------------------------------------------
74 ldr r3, =__libc_init_array
75 push {lr}
76 bl _blx_r3_stub
77@---------------------------------------------------------------------------------
78@ Jump to user code
79@---------------------------------------------------------------------------------
80 mov r0, #0 @ int argc
81 mov r1, #0 @ char *argv[]
82 ldr r3, =main
83 bl _blx_r3_stub
84@; If we're here, turn the sound back on before we return
85 ldr r1, =0x4000084
86 mov r0, #0x8F
87 strh r0, [r1]
88@; Also turn interrupts back on
89 ldr r1, =0x4000208
90 mov r0, #1
91 str r0, [r1]
92 pop {pc}
93
94@---------------------------------------------------------------------------------
95_blx_r3_stub:
96@---------------------------------------------------------------------------------
97 bx r3
98
99 .align
100 .pool
101 .end
102
diff --git a/source/link.c b/source/link.c new file mode 100644 index 0000000..7229191 --- /dev/null +++ b/source/link.c
@@ -0,0 +1,16 @@
1#include "link.h"
2
3u32 waitForButtons(u32 mask)
4{
5 for (;;)
6 {
7 PAD_ScanPads();
8 VIDEO_WaitVSync();
9
10 u32 btns = PAD_ButtonsDown(0);
11 if (btns & mask)
12 {
13 return btns;
14 }
15 }
16}
diff --git a/source/link.h b/source/link.h new file mode 100644 index 0000000..4e536b4 --- /dev/null +++ b/source/link.h
@@ -0,0 +1,8 @@
1#ifndef _LINK_H_
2#define _LINK_H_
3
4#include <gccore.h>
5
6u32 waitForButtons(u32 mask);
7
8#endif
diff --git a/source/main.c b/source/main.c index 7fd5683..79fd2fc 100644 --- a/source/main.c +++ b/source/main.c
@@ -1,4 +1,5 @@
1/* 1/*
2 * Copyright (C) 2017 hatkirby
2 * Copyright (C) 2016 FIX94 3 * Copyright (C) 2016 FIX94
3 * 4 *
4 * This software may be modified and distributed under the terms 5 * This software may be modified and distributed under the terms
@@ -15,6 +16,7 @@
15#include <fcntl.h> 16#include <fcntl.h>
16#include <dirent.h> 17#include <dirent.h>
17#include <fat.h> 18#include <fat.h>
19#include "link.h"
18 20
19//from my tests 50us seems to be the lowest 21//from my tests 50us seems to be the lowest
20//safe si transfer delay in between calls 22//safe si transfer delay in between calls
@@ -25,11 +27,12 @@ extern u32 gba_mb_gba_size;
25 27
26void printmain() 28void printmain()
27{ 29{
28 printf("\x1b[2J"); 30 printf("\x1b[2J");
29 printf("\x1b[37m"); 31 printf("\x1b[37m");
30 printf("GBA Link Cable Dumper v1.6 by FIX94\n"); 32 printf("Pokemon Gen III Data Extractor by hatkirby\n");
31 printf("Save Support based on SendSave by Chishm\n"); 33 printf("Based on GBA Link Cable Dumper v1.6 by FIX94\n");
32 printf("GBA BIOS Dumper by Dark Fader\n \n"); 34 printf("Save Support based on SendSave by Chishm\n");
35 printf("Save Structure based on gba-gen3multiboot by slipstream/RoL\n");
33} 36}
34 37
35u8 *resbuf,*cmdbuf; 38u8 *resbuf,*cmdbuf;
@@ -37,520 +40,886 @@ u8 *resbuf,*cmdbuf;
37volatile u32 transval = 0; 40volatile u32 transval = 0;
38void transcb(s32 chan, u32 ret) 41void transcb(s32 chan, u32 ret)
39{ 42{
40 transval = 1; 43 transval = 1;
41} 44}
42 45
43volatile u32 resval = 0; 46volatile u32 resval = 0;
44void acb(s32 res, u32 val) 47void acb(s32 res, u32 val)
45{ 48{
46 resval = val; 49 resval = val;
47} 50}
48 51/*
49unsigned int docrc(u32 crc, u32 val) 52unsigned int docrc(u32 crc, u32 val)
50{ 53{
51 int i; 54 int i;
52 for(i = 0; i < 0x20; i++) 55 for (i = 0; i < 0x20; i++)
53 { 56 {
54 if((crc^val)&1) 57 if ((crc ^ val) & 1)
55 { 58 {
56 crc>>=1; 59 crc>>=1;
57 crc^=0xa1c1; 60 crc^=0xa1c1;
58 } 61 } else {
59 else 62 crc>>=1;
60 crc>>=1; 63 }
61 val>>=1; 64
65 val>>=1;
66 }
67
68 return crc;
69}*/
70unsigned int docrc(u32 crc,u32 val) {
71 u32 result;
72
73 result = val ^ crc;
74 for (int i = 0; i < 0x20; i++) {
75 if (result & 1) {
76 result >>= 1;
77 result ^= 0xA1C1;
78 } else result >>= 1;
62 } 79 }
63 return crc; 80 return result;
64} 81}
65 82
66void endproc()
67{
68 printf("Start pressed, exit\n");
69 VIDEO_WaitVSync();
70 VIDEO_WaitVSync();
71 exit(0);
72}
73void fixFName(char *str) 83void fixFName(char *str)
74{ 84{
75 u8 i = 0; 85 u8 i = 0;
76 for(i = 0; i < strlen(str); ++i) 86 for (i = 0; i < strlen(str); ++i)
77 { 87 {
78 if(str[i] < 0x20 || str[i] > 0x7F) 88 if (str[i] < 0x20 || str[i] > 0x7F)
79 str[i] = '_'; 89 {
80 else switch(str[i]) 90 str[i] = '_';
81 { 91 } else {
82 case '\\': 92 switch (str[i])
83 case '/': 93 {
84 case ':': 94 case '\\':
85 case '*': 95 case '/':
86 case '?': 96 case ':':
87 case '\"': 97 case '*':
88 case '<': 98 case '?':
89 case '>': 99 case '\"':
90 case '|': 100 case '<':
91 str[i] = '_'; 101 case '>':
92 break; 102 case '|':
93 default: 103 str[i] = '_';
94 break; 104 break;
95 } 105 default:
96 } 106 break;
107 }
108 }
109 }
97} 110}
111
98unsigned int calckey(unsigned int size) 112unsigned int calckey(unsigned int size)
99{ 113{
100 unsigned int ret = 0; 114 unsigned int ret = 0;
101 size=(size-0x200) >> 3; 115 size= (size - 0x200) >> 3;
102 int res1 = (size&0x3F80) << 1; 116 int res1 = (size & 0x3F80) << 1;
103 res1 |= (size&0x4000) << 2; 117 res1 |= (size & 0x4000) << 2;
104 res1 |= (size&0x7F); 118 res1 |= (size & 0x7F);
105 res1 |= 0x380000; 119 res1 |= 0x380000;
106 int res2 = res1; 120 int res2 = res1;
107 res1 = res2 >> 0x10; 121 res1 = res2 >> 0x10;
108 int res3 = res2 >> 8; 122 int res3 = res2 >> 8;
109 res3 += res1; 123 res3 += res1;
110 res3 += res2; 124 res3 += res2;
111 res3 <<= 24; 125 res3 <<= 24;
112 res3 |= res2; 126 res3 |= res2;
113 res3 |= 0x80808080; 127 res3 |= 0x80808080;
114 128
115 if((res3&0x200) == 0) 129 if ((res3 & 0x200) == 0)
116 { 130 {
117 ret |= (((res3)&0xFF)^0x4B)<<24; 131 ret |= (((res3) & 0xFF) ^ 0x4B) << 24;
118 ret |= (((res3>>8)&0xFF)^0x61)<<16; 132 ret |= (((res3>>8) & 0xFF) ^ 0x61) << 16;
119 ret |= (((res3>>16)&0xFF)^0x77)<<8; 133 ret |= (((res3>>16) & 0xFF) ^ 0x77) << 8;
120 ret |= (((res3>>24)&0xFF)^0x61); 134 ret |= (((res3>>24) & 0xFF) ^ 0x61);
121 } 135 } else {
122 else 136 ret |= (((res3) & 0xFF) ^ 0x73) << 24;
123 { 137 ret |= (((res3>>8) & 0xFF) ^ 0x65) << 16;
124 ret |= (((res3)&0xFF)^0x73)<<24; 138 ret |= (((res3>>16) & 0xFF) ^ 0x64) << 8;
125 ret |= (((res3>>8)&0xFF)^0x65)<<16; 139 ret |= (((res3>>24) & 0xFF) ^ 0x6F);
126 ret |= (((res3>>16)&0xFF)^0x64)<<8; 140 }
127 ret |= (((res3>>24)&0xFF)^0x6F); 141
128 } 142 return ret;
129 return ret;
130} 143}
144
131void doreset() 145void doreset()
132{ 146{
133 cmdbuf[0] = 0xFF; //reset 147 cmdbuf[0] = 0xFF; //reset
134 transval = 0; 148 transval = 0;
135 SI_Transfer(1,cmdbuf,1,resbuf,3,transcb,SI_TRANS_DELAY); 149 SI_Transfer(1, cmdbuf, 1, resbuf, 3, transcb, SI_TRANS_DELAY);
136 while(transval == 0) ; 150
151 while (transval == 0);
137} 152}
153
138void getstatus() 154void getstatus()
139{ 155{
140 cmdbuf[0] = 0; //status 156 cmdbuf[0] = 0; //status
141 transval = 0; 157 transval = 0;
142 SI_Transfer(1,cmdbuf,1,resbuf,3,transcb,SI_TRANS_DELAY); 158 SI_Transfer(1, cmdbuf, 1, resbuf, 3, transcb, SI_TRANS_DELAY);
143 while(transval == 0) ; 159
160 while (transval == 0);
161}
162
163void endproc()
164{
165 doreset();
166 printf("Start pressed, exit\n");
167 VIDEO_WaitVSync();
168 VIDEO_WaitVSync();
169 exit(0);
170}
171
172void fsleep(int i)
173{
174 sleep(i);
175 /*PAD_ScanPads();
176 if (PAD_ButtonsDown(0) & PAD_BUTTON_START)
177 {
178 getstatus();
179 endproc();
180 }*/
144} 181}
182
145u32 recv() 183u32 recv()
146{ 184{
147 memset(resbuf,0,32); 185 memset(resbuf,0,32);
148 cmdbuf[0]=0x14; //read 186 cmdbuf[0]=0x14; //read
149 transval = 0; 187 transval = 0;
150 SI_Transfer(1,cmdbuf,1,resbuf,5,transcb,SI_TRANS_DELAY); 188 SI_Transfer(1, cmdbuf, 1, resbuf, 5, transcb, SI_TRANS_DELAY);
151 while(transval == 0) ; 189
152 return *(vu32*)resbuf; 190 while (transval == 0);
191 printf("%08lx\n", *(vu32*)resbuf);
192 return *(vu32*)resbuf;
153} 193}
194
154void send(u32 msg) 195void send(u32 msg)
155{ 196{
156 cmdbuf[0]=0x15;cmdbuf[1]=(msg>>0)&0xFF;cmdbuf[2]=(msg>>8)&0xFF; 197 cmdbuf[0] = 0x15;
157 cmdbuf[3]=(msg>>16)&0xFF;cmdbuf[4]=(msg>>24)&0xFF; 198 cmdbuf[1] = (msg >> 0) & 0xFF;
158 transval = 0; 199 cmdbuf[2] = (msg >> 8) & 0xFF;
159 resbuf[0] = 0; 200 cmdbuf[3] = (msg >> 16) & 0xFF;
160 SI_Transfer(1,cmdbuf,5,resbuf,1,transcb,SI_TRANS_DELAY); 201 cmdbuf[4] = (msg >> 24) & 0xFF;
161 while(transval == 0) ; 202
203 transval = 0;
204 resbuf[0] = 0;
205 SI_Transfer(1, cmdbuf, 5, resbuf, 1, transcb, SI_TRANS_DELAY);
206
207 while (transval == 0);
162} 208}
209
163bool dirExists(const char *path) 210bool dirExists(const char *path)
164{ 211{
165 DIR *dir; 212 DIR *dir = opendir(path);
166 dir = opendir(path); 213 if (dir)
167 if(dir) 214 {
168 { 215 closedir(dir);
169 closedir(dir); 216
170 return true; 217 return true;
171 } 218 }
172 return false; 219
220 return false;
173} 221}
222
174void createFile(const char *path, size_t size) 223void createFile(const char *path, size_t size)
175{ 224{
176 int fd = open(path, O_WRONLY|O_CREAT); 225 int fd = open(path, O_WRONLY | O_CREAT);
177 if(fd >= 0) 226 if (fd >= 0)
178 { 227 {
179 ftruncate(fd, size); 228 ftruncate(fd, size);
180 close(fd); 229 close(fd);
181 } 230 }
182} 231}
232
183void warnError(char *msg) 233void warnError(char *msg)
184{ 234{
185 puts(msg); 235 puts(msg);
186 VIDEO_WaitVSync(); 236 VIDEO_WaitVSync();
187 VIDEO_WaitVSync(); 237 VIDEO_WaitVSync();
188 sleep(2); 238 sleep(2);
189} 239}
240
190void fatalError(char *msg) 241void fatalError(char *msg)
191{ 242{
192 puts(msg); 243 puts(msg);
193 VIDEO_WaitVSync(); 244 VIDEO_WaitVSync();
194 VIDEO_WaitVSync(); 245 VIDEO_WaitVSync();
195 sleep(5); 246 sleep(5);
196 exit(0); 247 exit(0);
197} 248}
198int main(int argc, char *argv[]) 249
199{ 250u32 genKeyA() {
200 void *xfb = NULL; 251 u32 retries = 0;
201 GXRModeObj *rmode = NULL; 252 while (true) {
202 VIDEO_Init(); 253 u32 key = 0;
203 rmode = VIDEO_GetPreferredMode(NULL); 254 if (retries > 32) {
204 xfb = MEM_K0_TO_K1(SYS_AllocateFramebuffer(rmode)); 255 key = 0xDD654321;
205 VIDEO_Configure(rmode); 256 } else {
206 VIDEO_SetNextFramebuffer(xfb); 257 key = (rand() & 0x00ffffff) | 0xDD000000;
207 VIDEO_SetBlack(FALSE); 258 }
208 VIDEO_Flush(); 259 u32 unk = (key % 2 != 0);
209 VIDEO_WaitVSync(); 260 u32 v12 = key;
210 if(rmode->viTVMode&VI_NON_INTERLACE) VIDEO_WaitVSync(); 261 for (u32 v13 = 1; v13 < 32; v13++) {
211 int x = 24, y = 32, w, h; 262 v12 >>= 1;
212 w = rmode->fbWidth - (32); 263 unk += (v12 % 2 != 0);
213 h = rmode->xfbHeight - (48); 264 }
214 CON_InitEx(rmode, x, y, w, h); 265 if ((unk >= 10 && unk <= 24)) {
215 VIDEO_ClearFrameBuffer(rmode, xfb, COLOR_BLACK); 266 if (retries > 4) printf("KeyA retries = %ld",retries);
216 PAD_Init(); 267 printf("KeyA = 0x%08lx\n",key);
217 cmdbuf = memalign(32,32); 268 return key;
218 resbuf = memalign(32,32); 269 }
219 u8 *testdump = memalign(32,0x400000); 270 retries++;
220 if(!testdump) return 0;
221 if(!fatInitDefault())
222 {
223 printmain();
224 fatalError("ERROR: No usable device found to write dumped files to!");
225 } 271 }
226 mkdir("/dumps", S_IREAD | S_IWRITE); 272}
227 if(!dirExists("/dumps")) 273
228 { 274u32 checkKeyB(u32 KeyBRaw) {
229 printmain(); 275 if ((KeyBRaw & 0xFF) != 0xEE) {
230 fatalError("ERROR: Could not create dumps folder, make sure you have a supported device connected!"); 276 printf("Invalid KeyB - lowest 8 bits should be 0xEE, actually 0x%02x\n",((u8)(KeyBRaw)));
277 return 0;
231 } 278 }
232 int i; 279 u32 KeyB = KeyBRaw & 0xffffff00;
233 while(1) 280 u32 val = KeyB;
234 { 281 u32 unk = (val < 0);
235 printmain(); 282 for (u32 i = 1; i < 24; i++) {
236 printf("Waiting for a GBA in port 2...\n"); 283 val <<= 1;
237 resval = 0; 284 unk += (val < 0);
238 285 }
239 SI_GetTypeAsync(1,acb); 286 if (unk > 14) {
240 while(1) 287 printf("Invalid KeyB - high 24 bits bad: 0x%08lx\n",KeyB);
241 { 288 return 0;
242 if(resval) 289 }
243 { 290 printf("Valid KeyB: 0x%08lx\n",KeyB);
244 if(resval == 0x80 || resval & 8) 291 return KeyB;
245 { 292}
246 resval = 0; 293
247 SI_GetTypeAsync(1,acb); 294u32 deriveKeyC(u32 keyCderive, u32 kcrc) {
248 } 295 u32 keyc = 0;
249 else if(resval) 296 u32 keyCi = 0;
250 break; 297 do {
251 } 298 u32 v5 = 0x1000000 * keyCi - 1;
252 PAD_ScanPads(); 299 u32 keyCattempt = docrc(kcrc,v5);
253 VIDEO_WaitVSync(); 300 //printf("i = %d; keyCderive = %08x; keyCattempt = %08x\n",keyCi,keyCderive,keyCattempt);
254 if(PAD_ButtonsHeld(0)) 301 if (keyCderive == keyCattempt) {
255 endproc(); 302 keyc = v5;
303 printf("Found keyC: %08lx\n",keyc);
304 return keyc;
256 } 305 }
257 if(resval & SI_GBA) 306 keyCi++;
307 } while (keyCi < 256);
308 return keyc;
309}
310
311int main(int argc, char *argv[])
312{
313 void *xfb = NULL;
314 GXRModeObj *rmode = NULL;
315 VIDEO_Init();
316 rmode = VIDEO_GetPreferredMode(NULL);
317 xfb = MEM_K0_TO_K1(SYS_AllocateFramebuffer(rmode));
318 VIDEO_Configure(rmode);
319 VIDEO_SetNextFramebuffer(xfb);
320 VIDEO_SetBlack(FALSE);
321 VIDEO_Flush();
322 VIDEO_WaitVSync();
323 if(rmode->viTVMode&VI_NON_INTERLACE) VIDEO_WaitVSync();
324 int x = 24, y = 32, w, h;
325 w = rmode->fbWidth - (32);
326 h = rmode->xfbHeight - (48);
327 CON_InitEx(rmode, x, y, w, h);
328 VIDEO_ClearFrameBuffer(rmode, xfb, COLOR_BLACK);
329 PAD_Init();
330 cmdbuf = memalign(32,32);
331 resbuf = memalign(32,32);
332 u8 *testdump = memalign(32,0x400000);
333 if(!testdump) return 0;
334
335 /*if (!fatInitDefault())
336 {
337 printmain();
338 fatalError("ERROR: No usable device found to write dumped files to!");
339 }
340
341 mkdir("/dumps", S_IREAD | S_IWRITE);
342 if (!dirExists("/dumps"))
343 {
344 printmain();
345 fatalError("ERROR: Could not create dumps folder, make sure you have a supported device connected!");
346 }*/
347
348 int i;
349 while(1)
350 {
351 printmain();
352
353 printf("Press A to begin, press Start to quit.\n");
354 if (waitForButtons(PAD_BUTTON_A | PAD_BUTTON_START) & PAD_BUTTON_START)
258 { 355 {
259 printf("GBA Found! Waiting on BIOS\n"); 356 endproc();
357 }
358
359 printf("Waiting for a GBA in port 2...\n");
360 resval = 0;
361
362 SI_GetTypeAsync(1,acb);
363 while(1)
364 {
365 if (resval)
366 {
367 if (resval == 0x80 || resval & 8)
368 {
369 resval = 0;
370 SI_GetTypeAsync(1,acb);
371 } else if (resval)
372 {
373 break;
374 }
375 }
376
377 PAD_ScanPads();
378 VIDEO_WaitVSync();
379 if (PAD_ButtonsHeld(0) & PAD_BUTTON_START)
380 {
381 getstatus();
382 endproc();
383 }
384 }
385
386 if (resval & SI_GBA)
387 {
388 printf("GBA Found! Waiting on BIOS\n");
260 resbuf[2]=0; 389 resbuf[2]=0;
261 while(!(resbuf[2]&0x10)) 390 //u32 oldresult = 0;
391 //u32 newresult = 0;
392 // wait for the BIOS to hand over to the game
393 do {
394 doreset();
395
396 } while (!(resbuf[1] > 4));
397 printf("BIOS handed over to game, waiting on game\n");
398 do
262 { 399 {
263 doreset(); 400 doreset();
264 getstatus(); 401 } while((resbuf[0] != 0) || !(resbuf[2]&0x10));
265 } 402 // receive the game-code from GBA side.
266 printf("Ready, sending dumper\n"); 403 u32 gamecode = recv();
404 printf("Ready, sending multiboot ROM\n");
267 unsigned int sendsize = ((gba_mb_gba_size+7)&~7); 405 unsigned int sendsize = ((gba_mb_gba_size+7)&~7);
268 unsigned int ourkey = calckey(sendsize); 406 // generate KeyA
407 unsigned int ourkey = genKeyA();
269 //printf("Our Key: %08x\n", ourkey); 408 //printf("Our Key: %08x\n", ourkey);
270 //get current sessionkey 409 printf("Sending game code that we got: 0x%08lx\n",__builtin_bswap32(gamecode));
271 u32 sessionkeyraw = recv(); 410 // send the game code back, then KeyA.
272 u32 sessionkey = __builtin_bswap32(sessionkeyraw^0x7365646F); 411 send(__builtin_bswap32(gamecode));
273 //send over our own key 412 send(ourkey);
274 send(__builtin_bswap32(ourkey)); 413 // get KeyB from GBA, check it to make sure its valid, then xor with KeyA to derive the initial CRC value and the sessionkey.
275 unsigned int fcrc = 0x15a0; 414 u32 sessionkeyraw = 0;
276 //send over gba header 415 do {
277 for(i = 0; i < 0xC0; i+=4) 416 sessionkeyraw = recv();
278 send(__builtin_bswap32(*(vu32*)(gba_mb_gba+i))); 417 } while (sessionkeyraw == gamecode);
279 //printf("Header done! Sending ROM...\n"); 418 sessionkeyraw = checkKeyB(__builtin_bswap32(sessionkeyraw));
280 for(i = 0xC0; i < sendsize; i+=4) 419 if (sessionkeyraw == 0)
281 { 420 {
282 u32 enc = ((gba_mb_gba[i+3]<<24)|(gba_mb_gba[i+2]<<16)|(gba_mb_gba[i+1]<<8)|(gba_mb_gba[i])); 421 warnError("Cannot continue.\n");
283 fcrc=docrc(fcrc,enc); 422
423 continue;
424 }
425
426 u32 sessionkey = sessionkeyraw ^ ourkey;
427 u32 kcrc = sessionkey;
428 printf("start kCRC=%08lx\n",kcrc);
429 sessionkey = (sessionkey*0x6177614b)+1;
430 // send hacked up send-size in uint32s
431 u32 hackedupsize = (sendsize >> 3) - 1;
432 printf("Sending hacked up size 0x%08lx\n",hackedupsize);
433 send(hackedupsize);
434 //unsigned int fcrc = 0x00bb;
435 // send over multiboot binary header, in the clear until the end of the nintendo logo.
436 // GBA checks this, if nintendo logo does not match the one in currently inserted cart's ROM, it will not accept any more data.
437 for(i = 0; i < 0xA0; i+=4) {
438 vu32 rom_dword = *(vu32*)(gba_mb_gba+i);
439 send(__builtin_bswap32(rom_dword));
440 }
441 printf("\n");
442 printf("Header done! Sending ROM...\n");
443 // Add each uint32 of the multiboot image to the checksum, encrypt the uint32 with the session key, increment the session key, send the encrypted uint32.
444 for(i = 0xA0; i < sendsize; i+=4)
445 {
446 u32 dec = (
447 (((gba_mb_gba[i+3]) << 24) & 0xff000000) |
448 (((gba_mb_gba[i+2]) << 16) & 0x00ff0000) |
449 (((gba_mb_gba[i+1]) << 8) & 0x0000ff00) |
450 (((gba_mb_gba[i]) << 0) & 0x000000ff)
451 );
452 u32 enc = (dec - kcrc) ^ sessionkey;
453 kcrc=docrc(kcrc,dec);
284 sessionkey = (sessionkey*0x6177614B)+1; 454 sessionkey = (sessionkey*0x6177614B)+1;
285 enc^=sessionkey; 455 //enc^=((~(i+(0x20<<20)))+1);
286 enc^=((~(i+(0x20<<20)))+1); 456 //enc^=0x6f646573;//0x20796220;
287 enc^=0x20796220;
288 send(enc); 457 send(enc);
289 } 458 }
290 fcrc |= (sendsize<<16); 459 //fcrc |= (sendsize<<16);
291 //printf("ROM done! CRC: %08x\n", fcrc); 460 printf("ROM done! CRC: %08lx\n", kcrc);
292 //send over CRC
293 sessionkey = (sessionkey*0x6177614B)+1;
294 fcrc^=sessionkey;
295 fcrc^=((~(i+(0x20<<20)))+1);
296 fcrc^=0x20796220;
297 send(fcrc);
298 //get crc back (unused) 461 //get crc back (unused)
299 recv(); 462 // Get KeyC derivation material from GBA (eventually)
300 printf("Done!\n"); 463 u32 keyCderive = 0;
301 sleep(2); 464 do {
302 //hm 465 keyCderive = recv();
303 while(1) 466 } while (keyCderive <= 0xfeffffff);
304 { 467 keyCderive = __builtin_bswap32(keyCderive);
305 printmain(); 468 keyCderive >>= 8;
306 printf("Press A once you have a GBA Game inserted.\n"); 469 printf("KeyC derivation material: %08lx\n",keyCderive);
307 printf("Press Y to backup the GBA BIOS.\n \n"); 470
308 PAD_ScanPads(); 471 // (try to) find the KeyC, using the checksum of the multiboot image, and the derivation material that GBA sent to us
309 VIDEO_WaitVSync(); 472
310 u32 btns = PAD_ButtonsDown(0); 473 u32 keyc = deriveKeyC(keyCderive,kcrc);
311 if(btns&PAD_BUTTON_START) 474 if (keyc == 0)
312 endproc();
313 else if(btns&PAD_BUTTON_A)
314 { 475 {
315 if(recv() == 0) //ready 476 printf("Could not find keyC - kcrc=0x%08lx\n",kcrc);
316 { 477 warnError("Cannot continue.\n");
317 printf("Waiting for GBA\n"); 478 continue;
318 VIDEO_WaitVSync(); 479 }
319 int gbasize = 0; 480
320 while(gbasize == 0) 481 // derive the boot key from the found KeyC, and send to GBA. if this is not correct, GBA will not jump to the multiboot image it was sent.
321 gbasize = __builtin_bswap32(recv()); 482 u32 bootkey = docrc(0xBB,keyc) | 0xbb000000;
322 send(0); //got gbasize 483 printf("BootKey = 0x%08lx\n",bootkey);
323 u32 savesize = __builtin_bswap32(recv()); 484 send(bootkey);
324 send(0); //got savesize 485 /*
325 if(gbasize == -1) 486 printf("GBA Found! Waiting on BIOS...\n");
326 { 487
327 warnError("ERROR: No (Valid) GBA Card inserted!\n"); 488 resbuf[2]=0;
328 continue; 489 while (!(resbuf[2] & 0x10))
329 } 490 {
330 //get rom header 491 doreset();
331 for(i = 0; i < 0xC0; i+=4) 492 getstatus();
332 *(vu32*)(testdump+i) = recv(); 493 }
333 //print out all the info from the game 494
334 printf("Game Name: %.12s\n",(char*)(testdump+0xA0)); 495 printf("Ready, sending extractor.\n");
335 printf("Game ID: %.4s\n",(char*)(testdump+0xAC)); 496
336 printf("Company ID: %.2s\n",(char*)(testdump+0xB0)); 497 unsigned int sendsize = ((gba_mb_gba_size + 7) & ~7);
337 printf("ROM Size: %02.02f MB\n",((float)(gbasize/1024))/1024.f); 498 unsigned int ourkey = calckey(sendsize);
338 if(savesize > 0) 499
339 printf("Save Size: %02.02f KB\n \n",((float)(savesize))/1024.f); 500 //get current sessionkey
340 else 501 u32 sessionkeyraw = recv();
341 printf("No Save File\n \n"); 502 u32 sessionkey = __builtin_bswap32(sessionkeyraw ^ 0x7365646F);
342 //generate file paths 503
343 char gamename[64]; 504 //send over our own key
344 sprintf(gamename,"/dumps/%.12s [%.4s%.2s].gba", 505 send(__builtin_bswap32(ourkey));
345 (char*)(testdump+0xA0),(char*)(testdump+0xAC),(char*)(testdump+0xB0)); 506 unsigned int fcrc = 0x15a0;
346 fixFName(gamename+7); //fix name behind "/dumps/" 507
347 char savename[64]; 508 //send over gba header
348 sprintf(savename,"/dumps/%.12s [%.4s%.2s].sav", 509 for(i = 0; i < 0xC0; i+=4)
349 (char*)(testdump+0xA0),(char*)(testdump+0xAC),(char*)(testdump+0xB0)); 510 {
350 fixFName(savename+7); //fix name behind "/dumps/" 511 send(__builtin_bswap32(*(vu32*)(gba_mb_gba+i)));
351 //let the user choose the option 512 }
352 printf("Press A to dump this game, it will take about %i minutes.\n",gbasize/1024/1024*3/2); 513
353 printf("Press B if you want to cancel dumping this game.\n"); 514 for (i = 0xC0; i < sendsize; i+=4)
354 if(savesize > 0) 515 {
355 { 516 u32 enc = (
356 printf("Press Y to backup this save file.\n"); 517 (gba_mb_gba[i+3] << 24)
357 printf("Press X to restore this save file.\n"); 518 | (gba_mb_gba[i+2] << 16)
358 printf("Press Z to clear the save file on the GBA Cartridge.\n\n"); 519 | (gba_mb_gba[i+1] << 8)
359 } 520 | (gba_mb_gba[i]));
360 else 521
361 printf("\n"); 522 fcrc = docrc(fcrc,enc);
362 int command = 0; 523 sessionkey = (sessionkey * 0x6177614B) + 1;
363 while(1) 524 enc ^= sessionkey;
364 { 525 enc ^= ((~(i + (0x20 << 20))) + 1);
365 PAD_ScanPads(); 526 enc ^= 0x20796220;
366 VIDEO_WaitVSync(); 527
367 u32 btns = PAD_ButtonsDown(0); 528 send(enc);
368 if(btns&PAD_BUTTON_START) 529 }
369 endproc(); 530
370 else if(btns&PAD_BUTTON_A) 531 fcrc |= (sendsize<<16);
371 { 532
372 command = 1; 533 //send over CRC
373 break; 534 sessionkey = (sessionkey * 0x6177614B) + 1;
374 } 535 fcrc ^= sessionkey;
375 else if(btns&PAD_BUTTON_B) 536 fcrc ^= ((~(i + (0x20 << 20))) + 1);
376 break; 537 fcrc ^= 0x20796220;
377 else if(savesize > 0) 538
378 { 539 send(fcrc);
379 if(btns&PAD_BUTTON_Y) 540
380 { 541 //get crc back (unused)
381 command = 2; 542 recv();
382 break; 543 printf("Done!\n");
383 } 544 sleep(2);
384 else if(btns&PAD_BUTTON_X) 545
385 { 546 //hm
386 command = 3; 547 while (1)
387 break; 548 {
388 } 549 printmain();
389 else if(btns&PAD_TRIGGER_Z) 550 printf("Press A once you have a GBA Game inserted.\n \n");
390 { 551
391 command = 4; 552 PAD_ScanPads();
392 break; 553 VIDEO_WaitVSync();
393 } 554 u32 btns = PAD_ButtonsDown(0);
394 } 555 if (btns & PAD_BUTTON_START)
395 } 556 {
396 if(command == 1) 557 endproc();
397 { 558 } else if (btns & PAD_BUTTON_A)
398 FILE *f = fopen(gamename,"rb"); 559 {*/
399 if(f) 560 sleep(1);
400 { 561 //recv();
401 fclose(f); 562
402 command = 0; 563 //if (recv() == 0) //ready
403 warnError("ERROR: Game already dumped!\n"); 564 {
404 } 565
405 } 566 printf("Waiting for GBA...\n");
406 else if(command == 2) 567 while (recv() != 0) {fsleep(1);};
407 { 568 send(0);
408 FILE *f = fopen(savename,"rb"); 569
409 if(f) 570 VIDEO_WaitVSync();
410 { 571
411 fclose(f); 572 /*int gbasize = 0;
412 command = 0; 573 while(gbasize == 0)
413 warnError("ERROR: Save already backed up!\n"); 574 {
414 } 575 gbasize = __builtin_bswap32(recv());
415 } 576 }
416 else if(command == 3) 577
417 { 578 send(0); //got gbasize
418 size_t readsize = 0; 579 while (recv()!=0) {sleep(1);};
419 FILE *f = fopen(savename,"rb"); 580
420 if(f) 581 //u32 savesize = __builtin_bswap32(recv());
421 { 582 //send(0); //got savesize
422 fseek(f,0,SEEK_END); 583
423 readsize = ftell(f); 584 if (gbasize == -1)
424 if(readsize != savesize) 585 {
425 { 586 warnError("ERROR: No (Valid) GBA Card inserted!\n");
426 command = 0; 587
427 warnError("ERROR: Save has the wrong size, aborting restore!\n"); 588 continue;
428 } 589 }*/
429 else 590
430 { 591 // Get game
431 rewind(f); 592 // -1 - unsupported game
432 fread(testdump,readsize,1,f); 593 // 1 - Ruby
433 } 594 // 2 - Sapphire
434 fclose(f); 595 // 3 - FireRed
435 } 596 // 4 - LeafGreen
436 else 597 // 5 - Emerald
437 { 598 u32 gameId = 0;
438 command = 0; 599 while (gameId == 0)
439 warnError("ERROR: No Save to restore!\n");
440 }
441 }
442 send(command);
443 //let gba prepare
444 sleep(1);
445 if(command == 0)
446 continue;
447 else if(command == 1)
448 { 600 {
449 //create base file with size 601 gameId = __builtin_bswap32(recv());
450 printf("Preparing file...\n"); 602 fsleep(1);
451 createFile(gamename,gbasize);
452 FILE *f = fopen(gamename,"wb");
453 if(!f)
454 fatalError("ERROR: Could not create file! Exit...");
455 printf("Dumping...\n");
456 u32 bytes_read = 0;
457 while(gbasize > 0)
458 {
459 int toread = (gbasize > 0x400000 ? 0x400000 : gbasize);
460 int j;
461 for(j = 0; j < toread; j+=4)
462 {
463 *(vu32*)(testdump+j) = recv();
464 bytes_read+=4;
465 if((bytes_read&0xFFFF) == 0)
466 printf("\r%02.02f MB done",(float)(bytes_read/1024)/1024.f);
467 }
468 fwrite(testdump,toread,1,f);
469 gbasize -= toread;
470 }
471 printf("\nClosing file\n");
472 fclose(f);
473 printf("Game dumped!\n");
474 sleep(5);
475 } 603 }
476 else if(command == 2) 604
605 send(0);
606 while (recv()!=0) {fsleep(1);};
607 //sleep(1);
608
609 if (gameId == -1)
610 {
611 warnError("ERROR: Unsupported GBA game inserted!\n");
612
613 continue;
614 }
615
616 printf("\nPokemon ");
617 switch (gameId)
618 {
619 case 1: printf("Ruby"); break;
620 case 2: printf("Sapphire"); break;
621 case 3: printf("FireRed"); break;
622 case 4: printf("LeafGreen"); break;
623 case 5: printf("Emerald"); break;
624 }
625
626 printf("\n");
627 VIDEO_WaitVSync();
628
629 u32 isValid = 0;
630 while (isValid == 0)
477 { 631 {
478 //create base file with size 632 isValid = __builtin_bswap32(recv());
479 printf("Preparing file...\n"); 633 fsleep(1);
480 createFile(savename,savesize);
481 FILE *f = fopen(savename,"wb");
482 if(!f)
483 fatalError("ERROR: Could not create file! Exit...");
484 printf("Waiting for GBA\n");
485 VIDEO_WaitVSync();
486 u32 readval = 0;
487 while(readval != savesize)
488 readval = __builtin_bswap32(recv());
489 send(0); //got savesize
490 printf("Receiving...\n");
491 for(i = 0; i < savesize; i+=4)
492 *(vu32*)(testdump+i) = recv();
493 printf("Writing save...\n");
494 fwrite(testdump,savesize,1,f);
495 fclose(f);
496 printf("Save backed up!\n");
497 sleep(5);
498 } 634 }
499 else if(command == 3 || command == 4) 635
636 if (isValid == -1)
637 {
638 //send(0);
639
640 warnError("ERROR: Unsupported game version inserted!\n");
641
642 continue;
643 }
644
645 send(0);
646 while (recv()!=0) {fsleep(1);};
647 //sleep(1);
648 /*
649 // Get trainer name
650 u8 trainerName[8];
651
652 u32 tnd = recv();
653 send(0);
654 trainerName[0] = (tnd & 0xFF000000);
655 trainerName[1] = (tnd & 0x00FF0000) >> 8;
656 trainerName[2] = (tnd & 0x0000FF00) >> 16;
657 trainerName[3] = (tnd & 0x000000FF) >> 24;
658
659 tnd = recv();
660 send(0);
661 trainerName[4] = (tnd & 0xFF000000);
662 trainerName[5] = (tnd & 0x00FF0000) >> 8;
663 trainerName[6] = (tnd & 0x0000FF00) >> 16;
664 trainerName[7] = (tnd & 0x000000FF) >> 24;
665
666 printf("Trainer: %s", (char*) trainerName);
667*/
668 // Get trainer ID
669 u32 trainerId = 0;
670 while (trainerId == 0)
500 { 671 {
501 u32 readval = 0; 672 trainerId = __builtin_bswap32(recv());
502 while(readval != savesize) 673 fsleep(1);
503 readval = __builtin_bswap32(recv());
504 if(command == 3)
505 {
506 printf("Sending save\n");
507 VIDEO_WaitVSync();
508 for(i = 0; i < savesize; i+=4)
509 send(__builtin_bswap32(*(vu32*)(testdump+i)));
510 }
511 printf("Waiting for GBA\n");
512 while(recv() != 0)
513 VIDEO_WaitVSync();
514 printf(command == 3 ? "Save restored!\n" : "Save cleared!\n");
515 send(0);
516 sleep(5);
517 } 674 }
518 } 675 send(0);
519 } 676 while (recv()!=0) {fsleep(1);};
520 else if(btns&PAD_BUTTON_Y) 677 //sleep(1);
521 { 678
522 const char *biosname = "/dumps/gba_bios.bin"; 679 printf(" (%ld)\n", trainerId);
523 FILE *f = fopen(biosname,"rb"); 680
524 if(f) 681 //continue;
525 { 682
526 fclose(f); 683 // Wait for confirmation.
527 warnError("ERROR: BIOS already backed up!\n"); 684 printf("Press A to import the data from this game.\n");
528 } 685 printf("Press B to cancel.\n");
529 else 686 VIDEO_WaitVSync();
530 { 687
531 //create base file with size 688 if (waitForButtons(PAD_BUTTON_A | PAD_BUTTON_B) & PAD_BUTTON_B)
532 printf("Preparing file...\n"); 689 {
533 createFile(biosname,0x4000); 690 continue;
534 f = fopen(biosname,"wb"); 691 }
535 if(!f) 692
536 fatalError("ERROR: Could not create file! Exit..."); 693
537 //send over bios dump command 694
538 send(5); 695
539 //the gba might still be in a loop itself 696/*
540 sleep(1); 697 //get rom header
541 //lets go! 698 for(i = 0; i < 0xC0; i+=4)
542 printf("Dumping...\n"); 699 *(vu32*)(testdump+i) = recv();
543 for(i = 0; i < 0x4000; i+=4) 700 //print out all the info from the game
544 *(vu32*)(testdump+i) = recv(); 701 printf("Game Name: %.12s\n",(char*)(testdump+0xA0));
545 fwrite(testdump,0x4000,1,f); 702 printf("Game ID: %.4s\n",(char*)(testdump+0xAC));
546 printf("Closing file\n"); 703 printf("Company ID: %.2s\n",(char*)(testdump+0xB0));
547 fclose(f); 704 printf("ROM Size: %02.02f MB\n",((float)(gbasize/1024))/1024.f);
548 printf("BIOS dumped!\n"); 705 if(savesize > 0)
549 sleep(5); 706 printf("Save Size: %02.02f KB\n \n",((float)(savesize))/1024.f);
550 } 707 else
551 } 708 printf("No Save File\n \n");
552 } 709 //generate file paths
553 } 710 char gamename[64];
554 } 711 sprintf(gamename,"/dumps/%.12s [%.4s%.2s].gba",
555 return 0; 712 (char*)(testdump+0xA0),(char*)(testdump+0xAC),(char*)(testdump+0xB0));
713 fixFName(gamename+7); //fix name behind "/dumps/"
714 char savename[64];
715 sprintf(savename,"/dumps/%.12s [%.4s%.2s].sav",
716 (char*)(testdump+0xA0),(char*)(testdump+0xAC),(char*)(testdump+0xB0));
717 fixFName(savename+7); //fix name behind "/dumps/"
718 //let the user choose the option
719 printf("Press A to dump this game, it will take about %i minutes.\n",gbasize/1024/1024*3/2);
720 printf("Press B if you want to cancel dumping this game.\n");
721 if(savesize > 0)
722 {
723 printf("Press Y to backup this save file.\n");
724 printf("Press X to restore this save file.\n");
725 printf("Press Z to clear the save file on the GBA Cartridge.\n\n");
726 }
727 else
728 printf("\n");
729
730 int command = 0;
731 while(1)
732 {
733 PAD_ScanPads();
734 VIDEO_WaitVSync();
735 u32 btns = PAD_ButtonsDown(0);
736 if(btns&PAD_BUTTON_START)
737 endproc();
738 else if(btns&PAD_BUTTON_A)
739 {
740 command = 1;
741 break;
742 }
743 else if(btns&PAD_BUTTON_B)
744 break;
745 else if(savesize > 0)
746 {
747 if(btns&PAD_BUTTON_Y)
748 {
749 command = 2;
750 break;
751 }
752 else if(btns&PAD_BUTTON_X)
753 {
754 command = 3;
755 break;
756 }
757 else if(btns&PAD_TRIGGER_Z)
758 {
759 command = 4;
760 break;
761 }
762 }
763 }
764 if(command == 1)
765 {
766 FILE *f = fopen(gamename,"rb");
767 if(f)
768 {
769 fclose(f);
770 command = 0;
771 warnError("ERROR: Game already dumped!\n");
772 }
773 }
774 else if(command == 2)
775 {
776 FILE *f = fopen(savename,"rb");
777 if(f)
778 {
779 fclose(f);
780 command = 0;
781 warnError("ERROR: Save already backed up!\n");
782 }
783 }
784 else if(command == 3)
785 {
786 size_t readsize = 0;
787 FILE *f = fopen(savename,"rb");
788 if(f)
789 {
790 fseek(f,0,SEEK_END);
791 readsize = ftell(f);
792 if(readsize != savesize)
793 {
794 command = 0;
795 warnError("ERROR: Save has the wrong size, aborting restore!\n");
796 }
797 else
798 {
799 rewind(f);
800 fread(testdump,readsize,1,f);
801 }
802 fclose(f);
803 }
804 else
805 {
806 command = 0;
807 warnError("ERROR: No Save to restore!\n");
808 }
809 }
810 send(command);
811 //let gba prepare
812 sleep(1);
813 if(command == 0)
814 continue;
815 else if(command == 1)
816 {
817 //create base file with size
818 printf("Preparing file...\n");
819 createFile(gamename,gbasize);
820 FILE *f = fopen(gamename,"wb");
821 if(!f)
822 fatalError("ERROR: Could not create file! Exit...");
823 printf("Dumping...\n");
824 u32 bytes_read = 0;
825 while(gbasize > 0)
826 {
827 int toread = (gbasize > 0x400000 ? 0x400000 : gbasize);
828 int j;
829 for(j = 0; j < toread; j+=4)
830 {
831 *(vu32*)(testdump+j) = recv();
832 bytes_read+=4;
833 if((bytes_read&0xFFFF) == 0)
834 printf("\r%02.02f MB done",(float)(bytes_read/1024)/1024.f);
835 }
836 fwrite(testdump,toread,1,f);
837 gbasize -= toread;
838 }
839 printf("\nClosing file\n");
840 fclose(f);
841 printf("Game dumped!\n");
842 sleep(5);
843 }
844 else if(command == 2)
845 {
846 //create base file with size
847 printf("Preparing file...\n");
848 createFile(savename,savesize);
849 FILE *f = fopen(savename,"wb");
850 if(!f)
851 fatalError("ERROR: Could not create file! Exit...");
852 printf("Waiting for GBA\n");
853 VIDEO_WaitVSync();
854 u32 readval = 0;
855 while(readval != savesize)
856 readval = __builtin_bswap32(recv());
857 send(0); //got savesize
858 printf("Receiving...\n");
859 for(i = 0; i < savesize; i+=4)
860 *(vu32*)(testdump+i) = recv();
861 printf("Writing save...\n");
862 fwrite(testdump,savesize,1,f);
863 fclose(f);
864 printf("Save backed up!\n");
865 sleep(5);
866 }
867 else if(command == 3 || command == 4)
868 {
869 u32 readval = 0;
870 while(readval != savesize)
871 readval = __builtin_bswap32(recv());
872 if(command == 3)
873 {
874 printf("Sending save\n");
875 VIDEO_WaitVSync();
876 for(i = 0; i < savesize; i+=4)
877 send(__builtin_bswap32(*(vu32*)(testdump+i)));
878 }
879 printf("Waiting for GBA\n");
880 while(recv() != 0)
881 VIDEO_WaitVSync();
882 printf(command == 3 ? "Save restored!\n" : "Save cleared!\n");
883 send(0);
884 sleep(5);
885 }*/
886 }
887 }
888 /*else if(btns&PAD_BUTTON_Y)
889 {
890 const char *biosname = "/dumps/gba_bios.bin";
891 FILE *f = fopen(biosname,"rb");
892 if(f)
893 {
894 fclose(f);
895 warnError("ERROR: BIOS already backed up!\n");
896 }
897 else
898 {
899 //create base file with size
900 printf("Preparing file...\n");
901 createFile(biosname,0x4000);
902 f = fopen(biosname,"wb");
903 if(!f)
904 fatalError("ERROR: Could not create file! Exit...");
905 //send over bios dump command
906 send(5);
907 //the gba might still be in a loop itself
908 sleep(1);
909 //lets go!
910 printf("Dumping...\n");
911 for(i = 0; i < 0x4000; i+=4)
912 *(vu32*)(testdump+i) = recv();
913 fwrite(testdump,0x4000,1,f);
914 printf("Closing file\n");
915 fclose(f);
916 printf("BIOS dumped!\n");
917 sleep(5);
918 }
919 }*/
920// }
921 // }
922// }
923 }
924 return 0;
556} 925}