1 // VisualBoyAdvance - Nintendo Gameboy/GameboyAdvance (TM) emulator.
2 // Copyright (C) 1999-2003 Forgotten
3 // Copyright (C) 2005 Forgotten and the VBA development team
4
5 // This program is free software; you can redistribute it and/or modify
6 // it under the terms of the GNU General Public License as published by
7 // the Free Software Foundation; either version 2, or(at your option)
8 // any later version.
9 //
10 // This program is distributed in the hope that it will be useful,
11 // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 // GNU General Public License for more details.
14 //
15 // You should have received a copy of the GNU General Public License
16 // along with this program; if not, write to the Free Software Foundation,
17 // Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
18
19 #include "GBA.h"
20 #include "eeprom.h"
21
22 #define EEPROM_IDLE 0
23 #define EEPROM_READADDRESS 1
24 #define EEPROM_READDATA 2
25 #define EEPROM_READDATA2 3
26 #define EEPROM_WRITEDATA 4
27
28 extern uint8_t libretro_save_buf[0x20000 + 0x2000];
29 extern bool use_mednafen_save_method;
30 extern int cpuDmaCount;
31
32 static int eepromMode = EEPROM_IDLE;
33 static int eepromByte = 0;
34 static int eepromBits = 0;
35 static int eepromAddress = 0;
36 static uint8 *eepromData = libretro_save_buf + 0x20000;
37 static uint8 eepromBuffer[16];
38 static bool eepromInUse = false;
39 static int eepromSize = 512;
40 #include "../state.h"
41
EEPROM_StateAction(StateMem * sm,int load,int data_only)42 int EEPROM_StateAction(StateMem *sm, int load, int data_only)
43 {
44 const bool prev_eepromInUse = eepromInUse;
45 const int prev_eepromSize = eepromSize;
46
47 SFORMAT eepromSaveData[] =
48 {
49 SFVAR(eepromMode),
50 SFVAR(eepromByte),
51 SFVAR(eepromBits),
52 SFVAR(eepromAddress),
53 SFVAR(eepromInUse),
54 SFVAR(eepromSize),
55 SFARRAYN(eepromData, 0x2000, "eepromData"),
56 SFARRAYN(eepromBuffer, 16, "eepromBuffer"),
57 SFEND
58 };
59 int ret = MDFNSS_StateAction(sm, load, data_only, eepromSaveData, "EEPR", false);
60
61 if(load)
62 {
63 if(eepromSize != 512 && eepromSize != 0x2000)
64 eepromSize = 0x2000;
65
66 if(prev_eepromSize > eepromSize)
67 eepromSize = prev_eepromSize;
68
69 eepromInUse |= prev_eepromInUse;
70
71 //printf("InUse: %d\n", eepromInUse);
72 }
73
74 return(ret);
75 }
76
EEPROM_SaveFile(const char * filename)77 bool EEPROM_SaveFile(const char *filename)
78 {
79 if(eepromInUse)
80 {
81 if(!MDFN_DumpToFile(filename, 0, eepromData, eepromSize))
82 return(0);
83 }
84
85 return(1);
86 }
87
EEPROM_LoadFile(const char * filename)88 bool EEPROM_LoadFile(const char *filename)
89 {
90 FILE *fp = fopen(filename, "rb");
91
92 if(fp)
93 {
94 long size;
95
96 fseek(fp, 0, SEEK_END);
97 size = ftell(fp);
98 fseek(fp, 0, SEEK_SET);
99
100 if(size == 512 || size == 0x2000)
101 {
102 if((long)fread(eepromData, 1, size, fp) == size)
103 {
104 eepromInUse = true;
105 eepromSize = size;
106 fclose(fp);
107 return(1);
108 }
109 }
110 fclose(fp);
111 }
112
113 return(0);
114 }
115
116
eepromInit(void)117 void eepromInit(void)
118 {
119 memset(eepromData, 0xFF, 0x2000);
120 memset(eepromBuffer, 0, sizeof(eepromBuffer));
121 eepromMode = EEPROM_IDLE;
122 eepromByte = 0;
123 eepromBits = 0;
124 eepromAddress = 0;
125 eepromInUse = false;
126 eepromSize = 512;
127 }
128
EEPROM_Reset(void)129 void EEPROM_Reset(void)
130 {
131 eepromMode = EEPROM_IDLE;
132 eepromByte = 0;
133 eepromBits = 0;
134 eepromAddress = 0;
135 }
136
eepromRead(uint32)137 int eepromRead(uint32 /* address */)
138 {
139 switch(eepromMode) {
140 case EEPROM_IDLE:
141 case EEPROM_READADDRESS:
142 case EEPROM_WRITEDATA:
143 return 1;
144 case EEPROM_READDATA:
145 {
146 eepromBits++;
147 if(eepromBits == 4) {
148 eepromMode = EEPROM_READDATA2;
149 eepromBits = 0;
150 eepromByte = 0;
151 }
152 return 0;
153 }
154 case EEPROM_READDATA2:
155 {
156 int data = 0;
157 int address = eepromAddress << 3;
158 int mask = 1 << (7 - (eepromBits & 7));
159 data = (eepromData[(address + eepromByte) & 0x1FFF] & mask) ? 1 : 0;
160 eepromBits++;
161 if((eepromBits & 7) == 0)
162 eepromByte++;
163 if(eepromBits == 0x40)
164 eepromMode = EEPROM_IDLE;
165 return data;
166 }
167 default:
168 return 0;
169 }
170 return 1;
171 }
172
eepromWrite(uint32,uint8 value)173 void eepromWrite(uint32 /* address */, uint8 value)
174 {
175 if(cpuDmaCount == 0)
176 return;
177 int bit = value & 1;
178 switch(eepromMode) {
179 case EEPROM_IDLE:
180 eepromByte = 0;
181 eepromBits = 1;
182 eepromBuffer[eepromByte & 0xF] = bit;
183 eepromMode = EEPROM_READADDRESS;
184 break;
185 case EEPROM_READADDRESS:
186 eepromBuffer[eepromByte & 0xF] <<= 1;
187 eepromBuffer[eepromByte & 0xF] |= bit;
188 eepromBits++;
189 if((eepromBits & 7) == 0) {
190 eepromByte++;
191 }
192 if(cpuDmaCount == 0x11 || cpuDmaCount == 0x51) {
193 if(eepromBits == 0x11) {
194 eepromSize = 0x2000;
195 eepromAddress = ((eepromBuffer[0] & 0x3F) << 8) |
196 ((eepromBuffer[1] & 0xFF));
197 if(!(eepromBuffer[0] & 0x40)) {
198 eepromBuffer[0] = bit;
199 eepromBits = 1;
200 eepromByte = 0;
201 eepromMode = EEPROM_WRITEDATA;
202 } else {
203 eepromMode = EEPROM_READDATA;
204 eepromByte = 0;
205 eepromBits = 0;
206 }
207 }
208 } else {
209 if(eepromBits == 9) {
210 eepromAddress = (eepromBuffer[0] & 0x3F);
211 if(!(eepromBuffer[0] & 0x40)) {
212 eepromBuffer[0] = bit;
213 eepromBits = 1;
214 eepromByte = 0;
215 eepromMode = EEPROM_WRITEDATA;
216 } else {
217 eepromMode = EEPROM_READDATA;
218 eepromByte = 0;
219 eepromBits = 0;
220 }
221 }
222 }
223 break;
224 case EEPROM_READDATA:
225 case EEPROM_READDATA2:
226 // should we reset here?
227 eepromMode = EEPROM_IDLE;
228 break;
229 case EEPROM_WRITEDATA:
230 eepromBuffer[eepromByte & 0xF] <<= 1;
231 eepromBuffer[eepromByte & 0xF] |= bit;
232 eepromBits++;
233 if((eepromBits & 7) == 0) {
234 eepromByte++;
235 }
236 if(eepromBits == 0x40) {
237 eepromInUse = true;
238 // write data;
239 for(int i = 0; i < 8; i++) {
240 eepromData[((eepromAddress << 3) + i) & 0x1FFF] = eepromBuffer[i];
241 }
242 } else if(eepromBits == 0x41) {
243 eepromMode = EEPROM_IDLE;
244 eepromByte = 0;
245 eepromBits = 0;
246 }
247 break;
248 }
249 }
250