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