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