]> Shamusworld >> Repos - virtualjaguar/blob - src/eeprom.cpp
2fb896e44b6d229e4745ff6fa272544fcca89276
[virtualjaguar] / src / eeprom.cpp
1 //
2 // Jaguar EEPROM handler
3 //
4 // by Cal2
5 // GCC/SDL port by Niels Wagenaar (Linux/WIN32) and Caz (BeOS)
6 // Cleanups/enhancements by James Hammons
7 // (C) 2010 Underground Software
8 //
9 // JLH = James Hammons <jlhamm@acm.org>
10 //
11 // Who  When        What
12 // ---  ----------  -------------------------------------------------------------
13 // JLH  01/16/2010  Created this log ;-)
14 //
15
16 #include "eeprom.h"
17
18 #include <stdlib.h>
19 #include <string.h>                                                             // For memset
20 #include "jaguar.h"
21 #include "log.h"
22 #include "settings.h"
23
24 //#define eeprom_LOG
25
26 static uint16_t eeprom_ram[64];
27 static uint16_t cdromEEPROM[64];
28
29 //
30 // Private function prototypes
31 //
32
33 static void EEPROMSave(void);
34 static void eeprom_set_di(uint32_t state);
35 static void eeprom_set_cs(uint32_t state);
36 static uint32_t eeprom_get_do(void);
37 void ReadEEPROMFromFile(FILE * file, uint16_t * ram);
38 void WriteEEPROMToFile(FILE * file, uint16_t * ram);
39
40
41 enum { EE_STATE_START = 1, EE_STATE_OP_A, EE_STATE_OP_B, EE_STATE_0, EE_STATE_1,
42         EE_STATE_2, EE_STATE_3, EE_STATE_0_0, EE_READ_ADDRESS, EE_STATE_0_0_0,
43         EE_STATE_0_0_1, EE_STATE_0_0_2, EE_STATE_0_0_3, EE_STATE_0_0_1_0, EE_READ_DATA,
44         EE_STATE_BUSY, EE_STATE_1_0, EE_STATE_1_1, EE_STATE_2_0, EE_STATE_3_0 };
45
46 // Local global variables
47
48 static uint16_t jerry_ee_state = EE_STATE_START;
49 static uint16_t jerry_ee_op = 0;
50 static uint16_t jerry_ee_rstate = 0;
51 static uint16_t jerry_ee_address_data = 0;
52 static uint16_t jerry_ee_address_cnt = 6;
53 static uint16_t jerry_ee_data = 0;
54 static uint16_t jerry_ee_data_cnt = 16;
55 static uint16_t jerry_writes_enabled = 0;
56 static uint16_t jerry_ee_direct_jump = 0;
57
58 static char eeprom_filename[MAX_PATH];
59 static char cdromEEPROMFilename[MAX_PATH];
60 static bool haveEEPROM = false;
61 static bool haveCDROMEEPROM = false;
62
63
64 void EepromInit(void)
65 {
66         // Handle regular cartridge EEPROM
67         sprintf(eeprom_filename, "%s%08X.eeprom", vjs.EEPROMPath, (unsigned int)jaguarMainROMCRC32);
68         sprintf(cdromEEPROMFilename, "%scdrom.eeprom", vjs.EEPROMPath);
69         FILE * fp = fopen(eeprom_filename, "rb");
70
71         if (fp)
72         {
73                 ReadEEPROMFromFile(fp, eeprom_ram);
74                 fclose(fp);
75                 WriteLog("EEPROM: Loaded from %s\n", eeprom_filename);
76                 haveEEPROM = true;
77         }
78         else
79                 WriteLog("EEPROM: Could not open file \"%s\"!\n", eeprom_filename);
80
81         // Handle JagCD EEPROM
82         fp = fopen(cdromEEPROMFilename, "rb");
83
84         if (fp)
85         {
86                 ReadEEPROMFromFile(fp, cdromEEPROM);
87                 fclose(fp);
88                 WriteLog("EEPROM: Loaded from cdrom.eeprom\n");
89                 haveCDROMEEPROM = true;
90         }
91         else
92                 WriteLog("EEPROM: Could not open file \"%s\"!\n", cdromEEPROMFilename);
93 }
94
95
96 void EepromReset(void)
97 {
98         if (!haveEEPROM)
99                 memset(eeprom_ram, 0xFF, 64 * sizeof(uint16_t));
100
101         if (!haveCDROMEEPROM)
102                 memset(cdromEEPROM, 0xFF, 64 * sizeof(uint16_t));
103 }
104
105
106 void EepromDone(void)
107 {
108         WriteLog("EEPROM: Done.\n");
109 }
110
111
112 static void EEPROMSave(void)
113 {
114         // Write out regular cartridge EEPROM data
115         FILE * fp = fopen(eeprom_filename, "wb");
116
117         if (fp)
118         {
119                 WriteEEPROMToFile(fp, eeprom_ram);
120                 fclose(fp);
121         }
122         else
123                 WriteLog("EEPROM: Could not create file \"%s!\"\n", eeprom_filename);
124
125         // Write out JagCD EEPROM data
126         fp = fopen(cdromEEPROMFilename, "wb");
127
128         if (fp)
129         {
130                 WriteEEPROMToFile(fp, cdromEEPROM);
131                 fclose(fp);
132         }
133         else
134                 WriteLog("EEPROM: Could not create file \"%s!\"\n", cdromEEPROMFilename);
135 }
136
137
138 //
139 // Read/write EEPROM files to disk in an endian safe manner
140 //
141 void ReadEEPROMFromFile(FILE * file, uint16_t * ram)
142 {
143         uint8_t buffer[128];
144         fread(buffer, 1, 128, file);
145
146         for(int i=0; i<64; i++)
147                 ram[i] = (buffer[(i * 2) + 0] << 8) | buffer[(i * 2) + 1];
148 }
149
150
151 void WriteEEPROMToFile(FILE * file, uint16_t * ram)
152 {
153         uint8_t buffer[128];
154
155         for(int i=0; i<64; i++)
156         {
157                 buffer[(i * 2) + 0] = ram[i] >> 8;
158                 buffer[(i * 2) + 1] = ram[i] & 0xFF;
159         }
160
161         fwrite(buffer, 1, 128, file);
162 }
163
164
165 uint8_t EepromReadByte(uint32_t offset)
166 {
167         switch (offset)
168         {
169         case 0xF14001:
170                 return eeprom_get_do();
171         case 0xF14801:
172                 break;
173         case 0xF15001:
174                 eeprom_set_cs(1);
175                 break;
176 //      default: WriteLog("EEPROM: unmapped 0x%.8x\n", offset); break;
177         }
178
179         return 0x00;
180 }
181
182
183 uint16_t EepromReadWord(uint32_t offset)
184 {
185         return ((uint16_t)EepromReadByte(offset + 0) << 8) | EepromReadByte(offset + 1);
186 }
187
188
189 void EepromWriteByte(uint32_t offset, uint8_t data)
190 {
191         switch (offset)
192         {
193         case 0xF14001:
194                 break;
195         case 0xF14801:
196                 eeprom_set_di(data & 0x01);
197                 break;
198         case 0xF15001:
199                 eeprom_set_cs(1);
200                 break;
201 //      default: WriteLog("eeprom: unmapped 0x%.8x\n",offset); break;
202         }
203 }
204
205
206 void EepromWriteWord(uint32_t offset, uint16_t data)
207 {
208         EepromWriteByte(offset + 0, (data >> 8) & 0xFF);
209         EepromWriteByte(offset + 1, data & 0xFF);
210 }
211
212
213 /*
214 ;
215 ;   Commands specific to the National Semiconductor NM93C14
216 ;
217 ;
218 ;  9-bit commands..
219 ;                        876543210
220 eEWDS   equ     %100000000              ;Erase/Write disable (default)
221 eWRAL   equ     %100010000              ;Writes all registers
222 eERAL   equ     %100100000              ;Erase all registers
223 eEWEN   equ     %100110000              ;Erase/write Enable
224 eWRITE  equ     %101000000              ;Write selected register
225 eREAD   equ     %110000000              ;read from EEPROM
226 eERASE  equ     %111000000              ;Erase selected register
227 */
228
229
230 static void eeprom_set_di(uint32_t data)
231 {
232 //      WriteLog("eeprom: di=%i\n",data);
233 //      WriteLog("eeprom: state %i\n",jerry_ee_state);
234         switch (jerry_ee_state)
235         {
236         case EE_STATE_START:
237                 jerry_ee_state = EE_STATE_OP_A;
238                 break;
239         case EE_STATE_OP_A:
240                 jerry_ee_op = (data << 1);
241                 jerry_ee_state = EE_STATE_OP_B;
242                 break;
243         case EE_STATE_OP_B:
244                 jerry_ee_op |= data;
245                 jerry_ee_direct_jump = 0;
246 //              WriteLog("eeprom: opcode %i\n",jerry_ee_op);
247
248                 switch (jerry_ee_op)
249                 {
250                 // Opcode 00: eEWEN, eERAL, eWRAL, eEWNDS
251                 case 0: jerry_ee_state = EE_STATE_0; break;
252                 // Opcode 01: eWRITE (Write selected register)
253                 case 1: jerry_ee_state = EE_STATE_1; break;
254                 // Opcode 10: eREAD (Read from EEPROM)
255                 case 2: jerry_ee_state = EE_STATE_2; break;
256                 // Opcode 11: eERASE (Erase selected register)
257                 case 3: jerry_ee_state = EE_STATE_3; break;
258                 }
259
260                 eeprom_set_di(data);
261                 break;
262         case EE_STATE_0:
263                 jerry_ee_rstate = EE_STATE_0_0;
264                 jerry_ee_state = EE_READ_ADDRESS;
265                 jerry_ee_direct_jump = 1;
266                 jerry_ee_address_cnt = 6;
267                 jerry_ee_address_data = 0;
268                 break;
269         case EE_STATE_0_0:
270                 switch ((jerry_ee_address_data >> 4) & 0x03)
271                 {
272                 // Opcode 00 00: eEWDS (Erase/Write disable)
273                 case 0: jerry_ee_state=EE_STATE_0_0_0; break;
274                 // Opcode 00 01: eWRAL (Write all registers)
275                 case 1: jerry_ee_state=EE_STATE_0_0_1; break;
276                 // Opcode 00 10: eERAL (Erase all registers)
277                 case 2: jerry_ee_state=EE_STATE_0_0_2; break;
278                 // Opcode 00 11: eEWEN (Erase/Write enable)
279                 case 3: jerry_ee_state=EE_STATE_0_0_3; break;
280                 }
281
282                 eeprom_set_di(data);
283                 break;
284         case EE_STATE_0_0_0:
285                 // writes disable
286                 // WriteLog("eeprom: read only\n");
287                 jerry_writes_enabled = 0;
288                 jerry_ee_state = EE_STATE_START;
289                 break;
290         case EE_STATE_0_0_1:
291                 // writes all
292                 jerry_ee_rstate = EE_STATE_0_0_1_0;
293                 jerry_ee_state = EE_READ_DATA;
294                 jerry_ee_data_cnt = 16;
295                 jerry_ee_data = 0;
296                 jerry_ee_direct_jump = 1;
297                 break;
298         case EE_STATE_0_0_1_0:
299                 // WriteLog("eeprom: filling eeprom with 0x%.4x\n",data);
300                 if (jerry_writes_enabled)
301                 {
302                         for(int i=0; i<64; i++)
303                                 eeprom_ram[i] = jerry_ee_data;
304
305                         EEPROMSave();                                           // Save it NOW!
306                 }
307
308                 //else
309                 //      WriteLog("eeprom: not writing because read only\n");
310                 jerry_ee_state = EE_STATE_BUSY;
311                 break;
312         case EE_STATE_0_0_2:
313                 // erase all
314                 //WriteLog("eeprom: erasing eeprom\n");
315                 if (jerry_writes_enabled)
316                         for(int i=0; i<64; i++)
317                                 eeprom_ram[i] = 0xFFFF;
318
319                 jerry_ee_state = EE_STATE_BUSY;
320                 break;
321         case EE_STATE_0_0_3:
322                 // writes enable
323                 //WriteLog("eeprom: read/write\n");
324                 jerry_writes_enabled = 1;
325                 jerry_ee_state = EE_STATE_START;
326                 break;
327         case EE_STATE_1:
328                 jerry_ee_rstate = EE_STATE_1_0;
329                 jerry_ee_state = EE_READ_ADDRESS;
330                 jerry_ee_address_cnt = 6;
331                 jerry_ee_address_data = 0;
332                 jerry_ee_direct_jump = 1;
333                 break;
334         case EE_STATE_1_0:
335                 jerry_ee_rstate = EE_STATE_1_1;
336                 jerry_ee_state = EE_READ_DATA;
337                 jerry_ee_data_cnt = 16;
338                 jerry_ee_data = 0;
339                 jerry_ee_direct_jump = 1;
340                 break;
341         case EE_STATE_1_1:
342                 //WriteLog("eeprom: writing 0x%.4x at 0x%.2x\n",jerry_ee_data,jerry_ee_address_data);
343                 if (jerry_writes_enabled)
344                 {
345                         eeprom_ram[jerry_ee_address_data] = jerry_ee_data;
346                         EEPROMSave();                                           // Save it NOW!
347                 }
348
349                 jerry_ee_state = EE_STATE_BUSY;
350                 break;
351         case EE_STATE_2:
352                 jerry_ee_rstate = EE_STATE_2_0;
353                 jerry_ee_state = EE_READ_ADDRESS;
354                 jerry_ee_address_cnt = 6;
355                 jerry_ee_address_data = 0;
356                 jerry_ee_data_cnt = 16;
357                 jerry_ee_data = 0;
358                 break;
359         case EE_STATE_3:
360                 jerry_ee_rstate = EE_STATE_3_0;
361                 jerry_ee_state = EE_READ_ADDRESS;
362                 jerry_ee_address_cnt = 6;
363                 jerry_ee_address_data = 0;
364                 jerry_ee_direct_jump = 1;
365                 break;
366         case EE_STATE_3_0:
367                 //WriteLog("eeprom: erasing 0x%.2x\n",jerry_ee_address_data);
368                 if (jerry_writes_enabled)
369                         eeprom_ram[jerry_ee_address_data] = 0xFFFF;
370
371                 jerry_ee_state = EE_STATE_BUSY;
372                 break;
373         case EE_READ_DATA:
374                 //WriteLog("eeprom:\t\t\t%i bit %i\n",data,jerry_ee_data_cnt-1);
375                 jerry_ee_data <<= 1;
376                 jerry_ee_data |= data;
377                 jerry_ee_data_cnt--;
378
379                 if (!jerry_ee_data_cnt)
380                 {
381                         jerry_ee_state = jerry_ee_rstate;
382
383                         if (jerry_ee_direct_jump)
384                                 eeprom_set_di(data);
385                 }
386
387                 break;
388         case EE_READ_ADDRESS:
389                 jerry_ee_address_data <<= 1;
390                 jerry_ee_address_data |= data;
391                 jerry_ee_address_cnt--;
392 //              WriteLog("eeprom:\t%i bits remaining\n",jerry_ee_address_cnt);
393
394                 if (!jerry_ee_address_cnt)
395                 {
396                         jerry_ee_state = jerry_ee_rstate;
397                         //WriteLog("eeprom:\t\tread address 0x%.2x\n",jerry_ee_address_data);
398
399                         if (jerry_ee_direct_jump)
400                                 eeprom_set_di(data);
401                 }
402
403                 break;
404         default:
405                 jerry_ee_state = EE_STATE_OP_A;
406         }
407 }
408
409
410 static void eeprom_set_cs(uint32_t /*state*/)
411 {
412 //      WriteLog("eeprom: cs=%i\n",state);
413         jerry_ee_state = EE_STATE_START;
414         jerry_ee_op = 0;
415         jerry_ee_rstate = 0;
416         jerry_ee_address_data = 0;
417         jerry_ee_address_cnt = 6;
418         jerry_ee_data = 0;
419         jerry_ee_data_cnt = 16;
420         jerry_writes_enabled = 1;
421 }
422
423
424 static uint32_t eeprom_get_do(void)
425 {
426         uint16_t data = 1;
427
428         switch (jerry_ee_state)
429         {
430         case EE_STATE_START:
431                 data = 1;
432                 break;
433         case EE_STATE_BUSY:
434                 jerry_ee_state = EE_STATE_START;
435                 data = 0;
436                 break;
437         case EE_STATE_2_0:
438                 jerry_ee_data_cnt--;
439                 data = (eeprom_ram[jerry_ee_address_data] >> jerry_ee_data_cnt) & 0x01;
440
441                 if (!jerry_ee_data_cnt)
442                 {
443                         //WriteLog("eeprom: read 0x%.4x at 0x%.2x cpu %i pc=0x%.8x\n",eeprom_ram[jerry_ee_address_data],jerry_ee_address_data,jaguar_cpu_in_exec,s68000readPC());
444                         jerry_ee_state = EE_STATE_START;
445                 }
446                 break;
447         }
448
449 //      WriteLog("eeprom: do=%i\n",data);
450         return data;
451 }
452