rlm@1
|
1 #include <cstdio>
|
rlm@1
|
2 #include <cstring>
|
rlm@1
|
3
|
rlm@1
|
4 #include "Flash.h"
|
rlm@1
|
5 #include "GBA.h"
|
rlm@1
|
6 #include "GBAGlobals.h"
|
rlm@1
|
7 #include "Sram.h"
|
rlm@1
|
8 #include "../common/System.h"
|
rlm@1
|
9 #include "../common/Util.h"
|
rlm@1
|
10
|
rlm@1
|
11 #define FLASH_READ_ARRAY 0
|
rlm@1
|
12 #define FLASH_CMD_1 1
|
rlm@1
|
13 #define FLASH_CMD_2 2
|
rlm@1
|
14 #define FLASH_AUTOSELECT 3
|
rlm@1
|
15 #define FLASH_CMD_3 4
|
rlm@1
|
16 #define FLASH_CMD_4 5
|
rlm@1
|
17 #define FLASH_CMD_5 6
|
rlm@1
|
18 #define FLASH_ERASE_COMPLETE 7
|
rlm@1
|
19 #define FLASH_PROGRAM 8
|
rlm@1
|
20 #define FLASH_SETBANK 9
|
rlm@1
|
21
|
rlm@1
|
22 u8 flashSaveMemory[0x20000 + 4];
|
rlm@1
|
23 int32 flashState = FLASH_READ_ARRAY;
|
rlm@1
|
24 int32 flashReadState = FLASH_READ_ARRAY;
|
rlm@1
|
25 int32 flashSize = 0x10000;
|
rlm@1
|
26 int32 flashDeviceID = 0x1b;
|
rlm@1
|
27 int32 flashManufacturerID = 0x32;
|
rlm@1
|
28 int32 flashBank = 0;
|
rlm@1
|
29
|
rlm@1
|
30 static variable_desc flashSaveData[] = {
|
rlm@1
|
31 { &flashState, sizeof(int32) },
|
rlm@1
|
32 { &flashReadState, sizeof(int32) },
|
rlm@1
|
33 { &flashSaveMemory[0], 0x10000 },
|
rlm@1
|
34 { NULL, 0 }
|
rlm@1
|
35 };
|
rlm@1
|
36
|
rlm@1
|
37 static variable_desc flashSaveData2[] = {
|
rlm@1
|
38 { &flashState, sizeof(int32) },
|
rlm@1
|
39 { &flashReadState, sizeof(int32) },
|
rlm@1
|
40 { &flashSize, sizeof(int32) },
|
rlm@1
|
41 { &flashSaveMemory[0], 0x20000 },
|
rlm@1
|
42 { NULL, 0 }
|
rlm@1
|
43 };
|
rlm@1
|
44
|
rlm@1
|
45 static variable_desc flashSaveData3[] = {
|
rlm@1
|
46 { &flashState, sizeof(int32) },
|
rlm@1
|
47 { &flashReadState, sizeof(int32) },
|
rlm@1
|
48 { &flashSize, sizeof(int32) },
|
rlm@1
|
49 { &flashBank, sizeof(int32) },
|
rlm@1
|
50 { &flashSaveMemory[0], 0x20000 },
|
rlm@1
|
51 { NULL, 0 }
|
rlm@1
|
52 };
|
rlm@1
|
53
|
rlm@1
|
54 void flashReset()
|
rlm@1
|
55 {
|
rlm@1
|
56 flashState = FLASH_READ_ARRAY;
|
rlm@1
|
57 flashReadState = FLASH_READ_ARRAY;
|
rlm@1
|
58 flashBank = 0;
|
rlm@1
|
59 }
|
rlm@1
|
60
|
rlm@1
|
61 void flashErase()
|
rlm@1
|
62 {
|
rlm@1
|
63 memset(flashSaveMemory, 0, 0x20000*sizeof(u8));
|
rlm@1
|
64 flashState = FLASH_READ_ARRAY;
|
rlm@1
|
65 flashReadState = FLASH_READ_ARRAY;
|
rlm@1
|
66 flashSize = 0x10000;
|
rlm@1
|
67 flashDeviceID = 0x1b;
|
rlm@1
|
68 flashManufacturerID = 0x32;
|
rlm@1
|
69 flashBank = 0;
|
rlm@1
|
70 }
|
rlm@1
|
71
|
rlm@1
|
72 void flashSaveGame(gzFile gzFile)
|
rlm@1
|
73 {
|
rlm@1
|
74 utilWriteData(gzFile, flashSaveData3);
|
rlm@1
|
75 }
|
rlm@1
|
76
|
rlm@1
|
77 void flashReadGame(gzFile gzFile, int version)
|
rlm@1
|
78 {
|
rlm@1
|
79 if (version < SAVE_GAME_VERSION_5)
|
rlm@1
|
80 utilReadData(gzFile, flashSaveData);
|
rlm@1
|
81 else if (version < SAVE_GAME_VERSION_7)
|
rlm@1
|
82 {
|
rlm@1
|
83 utilReadData(gzFile, flashSaveData2);
|
rlm@1
|
84 flashBank = 0;
|
rlm@1
|
85 flashSetSize(flashSize);
|
rlm@1
|
86 }
|
rlm@1
|
87 else
|
rlm@1
|
88 {
|
rlm@1
|
89 utilReadData(gzFile, flashSaveData3);
|
rlm@1
|
90 }
|
rlm@1
|
91 }
|
rlm@1
|
92
|
rlm@1
|
93 void flashSetSize(int size)
|
rlm@1
|
94 {
|
rlm@1
|
95 // log("Setting flash size to %d\n", size);
|
rlm@1
|
96 flashSize = size;
|
rlm@1
|
97 if (size == 0x10000)
|
rlm@1
|
98 {
|
rlm@1
|
99 flashDeviceID = 0x1b;
|
rlm@1
|
100 flashManufacturerID = 0x32;
|
rlm@1
|
101 }
|
rlm@1
|
102 else
|
rlm@1
|
103 {
|
rlm@1
|
104 flashDeviceID = 0x13; //0x09;
|
rlm@1
|
105 flashManufacturerID = 0x62; //0xc2;
|
rlm@1
|
106 }
|
rlm@1
|
107 }
|
rlm@1
|
108
|
rlm@1
|
109 u8 flashRead(u32 address)
|
rlm@1
|
110 {
|
rlm@1
|
111 // log("Reading %08x from %08x\n", address, reg[15].I);
|
rlm@1
|
112 // log("Current read state is %d\n", flashReadState);
|
rlm@1
|
113 address &= 0xFFFF;
|
rlm@1
|
114
|
rlm@1
|
115 switch (flashReadState)
|
rlm@1
|
116 {
|
rlm@1
|
117 case FLASH_READ_ARRAY:
|
rlm@1
|
118 return flashSaveMemory[(flashBank << 16) + address];
|
rlm@1
|
119 case FLASH_AUTOSELECT:
|
rlm@1
|
120 switch (address & 0xFF)
|
rlm@1
|
121 {
|
rlm@1
|
122 case 0:
|
rlm@1
|
123 // manufacturer ID
|
rlm@1
|
124 return u8(flashManufacturerID);
|
rlm@1
|
125 case 1:
|
rlm@1
|
126 // device ID
|
rlm@1
|
127 return u8(flashDeviceID);
|
rlm@1
|
128 }
|
rlm@1
|
129 break;
|
rlm@1
|
130 case FLASH_ERASE_COMPLETE:
|
rlm@1
|
131 flashState = FLASH_READ_ARRAY;
|
rlm@1
|
132 flashReadState = FLASH_READ_ARRAY;
|
rlm@1
|
133 return 0xFF;
|
rlm@1
|
134 }
|
rlm@1
|
135 ;
|
rlm@1
|
136 return 0;
|
rlm@1
|
137 }
|
rlm@1
|
138
|
rlm@1
|
139 void flashSaveDecide(u32 address, u8 byte)
|
rlm@1
|
140 {
|
rlm@1
|
141 // log("Deciding save type %08x\n", address);
|
rlm@1
|
142 if (address == 0x0e005555)
|
rlm@1
|
143 {
|
rlm@1
|
144 saveType = 2;
|
rlm@1
|
145 cpuSaveGameFunc = flashWrite;
|
rlm@1
|
146 }
|
rlm@1
|
147 else
|
rlm@1
|
148 {
|
rlm@1
|
149 saveType = 1;
|
rlm@1
|
150 cpuSaveGameFunc = sramWrite;
|
rlm@1
|
151 }
|
rlm@1
|
152
|
rlm@1
|
153 (*cpuSaveGameFunc)(address, byte);
|
rlm@1
|
154 }
|
rlm@1
|
155
|
rlm@1
|
156 void flashWrite(u32 address, u8 byte)
|
rlm@1
|
157 {
|
rlm@1
|
158 // log("Writing %02x at %08x\n", byte, address);
|
rlm@1
|
159 // log("Current state is %d\n", flashState);
|
rlm@1
|
160 address &= 0xFFFF;
|
rlm@1
|
161 switch (flashState)
|
rlm@1
|
162 {
|
rlm@1
|
163 case FLASH_READ_ARRAY:
|
rlm@1
|
164 if (address == 0x5555 && byte == 0xAA)
|
rlm@1
|
165 flashState = FLASH_CMD_1;
|
rlm@1
|
166 break;
|
rlm@1
|
167 case FLASH_CMD_1:
|
rlm@1
|
168 if (address == 0x2AAA && byte == 0x55)
|
rlm@1
|
169 flashState = FLASH_CMD_2;
|
rlm@1
|
170 else
|
rlm@1
|
171 flashState = FLASH_READ_ARRAY;
|
rlm@1
|
172 break;
|
rlm@1
|
173 case FLASH_CMD_2:
|
rlm@1
|
174 if (address == 0x5555)
|
rlm@1
|
175 {
|
rlm@1
|
176 if (byte == 0x90)
|
rlm@1
|
177 {
|
rlm@1
|
178 flashState = FLASH_AUTOSELECT;
|
rlm@1
|
179 flashReadState = FLASH_AUTOSELECT;
|
rlm@1
|
180 }
|
rlm@1
|
181 else if (byte == 0x80)
|
rlm@1
|
182 {
|
rlm@1
|
183 flashState = FLASH_CMD_3;
|
rlm@1
|
184 }
|
rlm@1
|
185 else if (byte == 0xF0)
|
rlm@1
|
186 {
|
rlm@1
|
187 flashState = FLASH_READ_ARRAY;
|
rlm@1
|
188 flashReadState = FLASH_READ_ARRAY;
|
rlm@1
|
189 }
|
rlm@1
|
190 else if (byte == 0xA0)
|
rlm@1
|
191 {
|
rlm@1
|
192 flashState = FLASH_PROGRAM;
|
rlm@1
|
193 }
|
rlm@1
|
194 else if (byte == 0xB0 && flashSize == 0x20000)
|
rlm@1
|
195 {
|
rlm@1
|
196 flashState = FLASH_SETBANK;
|
rlm@1
|
197 }
|
rlm@1
|
198 else
|
rlm@1
|
199 {
|
rlm@1
|
200 flashState = FLASH_READ_ARRAY;
|
rlm@1
|
201 flashReadState = FLASH_READ_ARRAY;
|
rlm@1
|
202 }
|
rlm@1
|
203 }
|
rlm@1
|
204 else
|
rlm@1
|
205 {
|
rlm@1
|
206 flashState = FLASH_READ_ARRAY;
|
rlm@1
|
207 flashReadState = FLASH_READ_ARRAY;
|
rlm@1
|
208 }
|
rlm@1
|
209 break;
|
rlm@1
|
210 case FLASH_CMD_3:
|
rlm@1
|
211 if (address == 0x5555 && byte == 0xAA)
|
rlm@1
|
212 {
|
rlm@1
|
213 flashState = FLASH_CMD_4;
|
rlm@1
|
214 }
|
rlm@1
|
215 else
|
rlm@1
|
216 {
|
rlm@1
|
217 flashState = FLASH_READ_ARRAY;
|
rlm@1
|
218 flashReadState = FLASH_READ_ARRAY;
|
rlm@1
|
219 }
|
rlm@1
|
220 break;
|
rlm@1
|
221 case FLASH_CMD_4:
|
rlm@1
|
222 if (address == 0x2AAA && byte == 0x55)
|
rlm@1
|
223 {
|
rlm@1
|
224 flashState = FLASH_CMD_5;
|
rlm@1
|
225 }
|
rlm@1
|
226 else
|
rlm@1
|
227 {
|
rlm@1
|
228 flashState = FLASH_READ_ARRAY;
|
rlm@1
|
229 flashReadState = FLASH_READ_ARRAY;
|
rlm@1
|
230 }
|
rlm@1
|
231 break;
|
rlm@1
|
232 case FLASH_CMD_5:
|
rlm@1
|
233 if (byte == 0x30)
|
rlm@1
|
234 {
|
rlm@1
|
235 // SECTOR ERASE
|
rlm@1
|
236 memset(&flashSaveMemory[(flashBank << 16) + (address & 0xF000)],
|
rlm@1
|
237 0,
|
rlm@1
|
238 0x1000);
|
rlm@1
|
239 systemSaveUpdateCounter = SYSTEM_SAVE_UPDATED;
|
rlm@1
|
240 flashReadState = FLASH_ERASE_COMPLETE;
|
rlm@1
|
241 }
|
rlm@1
|
242 else if (byte == 0x10)
|
rlm@1
|
243 {
|
rlm@1
|
244 // CHIP ERASE
|
rlm@1
|
245 memset(flashSaveMemory, 0, flashSize);
|
rlm@1
|
246 systemSaveUpdateCounter = SYSTEM_SAVE_UPDATED;
|
rlm@1
|
247 flashReadState = FLASH_ERASE_COMPLETE;
|
rlm@1
|
248 }
|
rlm@1
|
249 else
|
rlm@1
|
250 {
|
rlm@1
|
251 flashState = FLASH_READ_ARRAY;
|
rlm@1
|
252 flashReadState = FLASH_READ_ARRAY;
|
rlm@1
|
253 }
|
rlm@1
|
254 break;
|
rlm@1
|
255 case FLASH_AUTOSELECT:
|
rlm@1
|
256 if (byte == 0xF0)
|
rlm@1
|
257 {
|
rlm@1
|
258 flashState = FLASH_READ_ARRAY;
|
rlm@1
|
259 flashReadState = FLASH_READ_ARRAY;
|
rlm@1
|
260 }
|
rlm@1
|
261 else if (address == 0x5555 && byte == 0xAA)
|
rlm@1
|
262 flashState = FLASH_CMD_1;
|
rlm@1
|
263 else
|
rlm@1
|
264 {
|
rlm@1
|
265 flashState = FLASH_READ_ARRAY;
|
rlm@1
|
266 flashReadState = FLASH_READ_ARRAY;
|
rlm@1
|
267 }
|
rlm@1
|
268 break;
|
rlm@1
|
269 case FLASH_PROGRAM:
|
rlm@1
|
270 flashSaveMemory[(flashBank<<16)+address] = byte;
|
rlm@1
|
271 systemSaveUpdateCounter = SYSTEM_SAVE_UPDATED;
|
rlm@1
|
272 flashState = FLASH_READ_ARRAY;
|
rlm@1
|
273 flashReadState = FLASH_READ_ARRAY;
|
rlm@1
|
274 break;
|
rlm@1
|
275 case FLASH_SETBANK:
|
rlm@1
|
276 if (address == 0)
|
rlm@1
|
277 {
|
rlm@1
|
278 flashBank = (byte & 1);
|
rlm@1
|
279 }
|
rlm@1
|
280 flashState = FLASH_READ_ARRAY;
|
rlm@1
|
281 flashReadState = FLASH_READ_ARRAY;
|
rlm@1
|
282 break;
|
rlm@1
|
283 }
|
rlm@1
|
284 }
|
rlm@1
|
285
|