about summary refs log tree commit diff stats
path: root/gba/source
diff options
context:
space:
mode:
authorslipstream/RoL <l33twax@yahoo.com>2017-02-19 01:19:35 +0000
committerslipstream/RoL <l33twax@yahoo.com>2017-02-19 01:19:35 +0000
commitd4e309bb19b74c4b21ca19952c9b1cdd067c667a (patch)
tree36d4e67a43ab746135a18de3eef4edb09867b568 /gba/source
parent004575f7cec14946c1936aceca6efee38b7f8a74 (diff)
downloadgen3uploader-d4e309bb19b74c4b21ca19952c9b1cdd067c667a.tar.gz
gen3uploader-d4e309bb19b74c4b21ca19952c9b1cdd067c667a.tar.bz2
gen3uploader-d4e309bb19b74c4b21ca19952c9b1cdd067c667a.zip
Initial commit of the fork
Forking gba-link-cable-dumper to gba-gen3multiboot
Diffstat (limited to 'gba/source')
-rw-r--r--gba/source/main.c262
1 files changed, 33 insertions, 229 deletions
diff --git a/gba/source/main.c b/gba/source/main.c index ee94c35..ce6969b 100644 --- a/gba/source/main.c +++ b/gba/source/main.c
@@ -1,241 +1,45 @@
1/* 1/*
2 * Copyright (C) 2016 FIX94 2 * Example Gen3-multiboot payload by slipstream/RoL 2017.
3 * Supports only English Ruby, v1.0-1.2.
3 * 4 *
4 * This software may be modified and distributed under the terms 5 * This software may be modified and distributed under the terms
5 * of the MIT license. See the LICENSE file for details. 6 * of the MIT license. See the LICENSE file for details.
6 */ 7 */
7#include <gba.h> 8#include <gba.h>
8#include <stdio.h>
9#include <stdlib.h>
10#include "libSave.h"
11 9
12#define REG_WAITCNT *(vu16 *)(REG_BASE + 0x204)
13#define JOY_WRITE 2
14#define JOY_READ 4
15#define JOY_RW 6
16
17u8 save_data[0x20000] __attribute__ ((section (".sbss")));
18
19s32 getGameSize(void)
20{
21 if(*(vu32*)(0x08000004) != 0x51AEFF24)
22 return -1;
23 s32 i;
24 for(i = (1<<20); i < (1<<25); i<<=1)
25 {
26 vu16 *rompos = (vu16*)(0x08000000+i);
27 int j;
28 bool romend = true;
29 for(j = 0; j < 0x1000; j++)
30 {
31 if(rompos[j] != j)
32 {
33 romend = false;
34 break;
35 }
36 }
37 if(romend) break;
38 }
39 return i;
40}
41
42//---------------------------------------------------------------------------------
43// Program entry point
44//---------------------------------------------------------------------------------
45int main(void) { 10int main(void) {
46//--------------------------------------------------------------------------------- 11 // check the ROM code, make sure this game is supported.
47 12 char* ROM = 0x8000000;
48 // the vblank interrupt must be enabled for VBlankIntrWait() to work 13
49 // since the default dispatcher handles the bios flags no vblank handler 14 if ((*(u32*)(&ROM[0xAC])) != 'EVXA') return 0; // Pokémon Ruby english, nothing else supported!
50 // is required 15
51 irqInit(); 16 void(*loadsave)(char a1);
52 irqEnable(IRQ_VBLANK); 17 // get the address of the save loading function.
53 18 switch (ROM[0xBC]) { // version number
54 consoleDemoInit(); 19 case 0:
55 REG_JOYTR = 0; 20 loadsave = 0x8125EC9;
56 // ansi escape sequence to set print co-ordinates 21 break;
57 // /x1b[line;columnH 22 case 1:
58 u32 i; 23 case 2:
59 iprintf("\x1b[9;2HGBA Link Cable Dumper v1.6\n"); 24 loadsave = 0x8125EE9;
60 iprintf("\x1b[10;4HPlease look at the TV\n"); 25 break;
61 // disable this, needs power 26 default:
62 SNDSTAT = 0; 27 return 0; //bail out
63 SNDBIAS = 0;
64 // Set up waitstates for EEPROM access etc.
65 REG_WAITCNT = 0x0317;
66 //clear out previous messages
67 REG_HS_CTRL |= JOY_RW;
68 while (1) {
69 if(REG_HS_CTRL&JOY_READ)
70 {
71 REG_HS_CTRL |= JOY_RW;
72 s32 gamesize = getGameSize();
73 u32 savesize = SaveSize(save_data,gamesize);
74 REG_JOYTR = gamesize;
75 //wait for a cmd receive for safety
76 while((REG_HS_CTRL&JOY_WRITE) == 0) ;
77 REG_HS_CTRL |= JOY_RW;
78 REG_JOYTR = savesize;
79 //wait for a cmd receive for safety
80 while((REG_HS_CTRL&JOY_WRITE) == 0) ;
81 REG_HS_CTRL |= JOY_RW;
82 if(gamesize == -1)
83 {
84 REG_JOYTR = 0;
85 continue; //nothing to read
86 }
87 //game in, send header
88 for(i = 0; i < 0xC0; i+=4)
89 {
90 REG_JOYTR = *(vu32*)(0x08000000+i);
91 while((REG_HS_CTRL&JOY_READ) == 0) ;
92 REG_HS_CTRL |= JOY_RW;
93 }
94 REG_JOYTR = 0;
95 //wait for other side to choose
96 while((REG_HS_CTRL&JOY_WRITE) == 0) ;
97 REG_HS_CTRL |= JOY_RW;
98 u32 choseval = REG_JOYRE;
99 if(choseval == 0)
100 {
101 REG_JOYTR = 0;
102 continue; //nothing to read
103 }
104 else if(choseval == 1)
105 {
106 //disable interrupts
107 u32 prevIrqMask = REG_IME;
108 REG_IME = 0;
109 //dump the game
110 for(i = 0; i < gamesize; i+=4)
111 {
112 REG_JOYTR = *(vu32*)(0x08000000+i);
113 while((REG_HS_CTRL&JOY_READ) == 0) ;
114 REG_HS_CTRL |= JOY_RW;
115 }
116 //restore interrupts
117 REG_IME = prevIrqMask;
118 }
119 else if(choseval == 2)
120 {
121 //disable interrupts
122 u32 prevIrqMask = REG_IME;
123 REG_IME = 0;
124 //backup save
125 switch (savesize){
126 case 0x200:
127 GetSave_EEPROM_512B(save_data);
128 break;
129 case 0x2000:
130 GetSave_EEPROM_8KB(save_data);
131 break;
132 case 0x8000:
133 GetSave_SRAM_32KB(save_data);
134 break;
135 case 0x10000:
136 GetSave_FLASH_64KB(save_data);
137 break;
138 case 0x20000:
139 GetSave_FLASH_128KB(save_data);
140 break;
141 default:
142 break;
143 }
144 //restore interrupts
145 REG_IME = prevIrqMask;
146 //say gc side we read it
147 REG_JOYTR = savesize;
148 //wait for a cmd receive for safety
149 while((REG_HS_CTRL&JOY_WRITE) == 0) ;
150 REG_HS_CTRL |= JOY_RW;
151 //send the save
152 for(i = 0; i < savesize; i+=4)
153 {
154 REG_JOYTR = *(vu32*)(save_data+i);
155 while((REG_HS_CTRL&JOY_READ) == 0) ;
156 REG_HS_CTRL |= JOY_RW;
157 }
158 }
159 else if(choseval == 3 || choseval == 4)
160 {
161 REG_JOYTR = savesize;
162 if(choseval == 3)
163 {
164 //receive the save
165 for(i = 0; i < savesize; i+=4)
166 {
167 while((REG_HS_CTRL&JOY_WRITE) == 0) ;
168 REG_HS_CTRL |= JOY_RW;
169 *(vu32*)(save_data+i) = REG_JOYRE;
170 }
171 }
172 else
173 {
174 //clear the save
175 for(i = 0; i < savesize; i+=4)
176 *(vu32*)(save_data+i) = 0;
177 }
178 //disable interrupts
179 u32 prevIrqMask = REG_IME;
180 REG_IME = 0;
181 //write it
182 switch (savesize){
183 case 0x200:
184 PutSave_EEPROM_512B(save_data);
185 break;
186 case 0x2000:
187 PutSave_EEPROM_8KB(save_data);
188 break;
189 case 0x8000:
190 PutSave_SRAM_32KB(save_data);
191 break;
192 case 0x10000:
193 PutSave_FLASH_64KB(save_data);
194 break;
195 case 0x20000:
196 PutSave_FLASH_128KB(save_data);
197 break;
198 default:
199 break;
200 }
201 //restore interrupts
202 REG_IME = prevIrqMask;
203 //say gc side we're done
204 REG_JOYTR = 0;
205 //wait for a cmd receive for safety
206 while((REG_HS_CTRL&JOY_WRITE) == 0) ;
207 REG_HS_CTRL |= JOY_RW;
208 }
209 REG_JOYTR = 0;
210 }
211 else if(REG_HS_CTRL&JOY_WRITE)
212 {
213 REG_HS_CTRL |= JOY_RW;
214 u32 choseval = REG_JOYRE;
215 if(choseval == 5)
216 {
217 //disable interrupts
218 u32 prevIrqMask = REG_IME;
219 REG_IME = 0;
220 //dump BIOS
221 for (i = 0; i < 0x4000; i+=4)
222 {
223 // the lower bits are inaccurate, so just get it four times :)
224 u32 a = MidiKey2Freq((WaveData *)(i-4), 180-12, 0) * 2;
225 u32 b = MidiKey2Freq((WaveData *)(i-3), 180-12, 0) * 2;
226 u32 c = MidiKey2Freq((WaveData *)(i-2), 180-12, 0) * 2;
227 u32 d = MidiKey2Freq((WaveData *)(i-1), 180-12, 0) * 2;
228 REG_JOYTR = ((a>>24<<24) | (d>>24<<16) | (c>>24<<8) | (b>>24));
229 while((REG_HS_CTRL&JOY_READ) == 0) ;
230 REG_HS_CTRL |= JOY_RW;
231 }
232 //restore interrupts
233 REG_IME = prevIrqMask;
234 }
235 REG_JOYTR = 0;
236 }
237 Halt();
238 } 28 }
29 loadsave(0);
30 // now the save is loaded, we can do what we want with the loaded blocks.
31 // here as a small PoC, changing first letter of player name to 'z'.
32 u8* gSaveBlock2 = 0x2024EA4;
33 gSaveBlock2[0] = 0xee; // 'z'
34 // Now we've done what we want, time to return to the game.
35 // Can't just return, the game will reload the save.
36 // So let's just call the main-loop directly ;)
37 void(*mainloop)() = 0x80002A5;
38 // turn the sound back on before we head back to the game
39 *(vu16 *)(REG_BASE + 0x84) = 0x8f;
40 mainloop();
41 // Anything past here will not be executed.
42 return 0;
239} 43}
240 44
241 45