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