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