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