2 // Jaguar EEPROM handler
5 // GCC/SDL port by Niels Wagenaar (Linux/WIN32) and Caz (BeOS)
6 // Cleanups/enhancements by James Hammons
7 // (C) 2010 Underground Software
9 // JLH = James Hammons <jlhamm@acm.org>
10 // JPM = Jean-Paul Mari <djipi.mari@gmail.com>
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
26 #include <string.h> // For memset
33 static uint16_t eeprom_ram
[64];
34 static uint16_t cdromEEPROM
[64];
37 // Private function prototypes
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
);
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
};
53 // Local global variables
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;
65 static char eeprom_filename
[MAX_PATH
];
66 static char cdromEEPROMFilename
[MAX_PATH
];
67 static bool haveEEPROM
= false;
68 static bool haveCDROMEEPROM
= false;
71 // EEPROM initialisations
76 // No need for EEPROM for the Memory Track device :-P
77 if (jaguarMainROMCRC32
== 0xFDF37F47)
79 WriteLog("EEPROM: Memory Track device detected...\n");
83 // Handle regular cartridge EEPROM
84 sprintf(eeprom_filename
, "%s%08X.eeprom", vjs
.EEPROMPath
, (unsigned int)jaguarMainROMCRC32
);
85 fp
= fopen(eeprom_filename
, "rb");
89 ReadEEPROMFromFile(fp
, eeprom_ram
);
91 WriteLog("EEPROM: Loaded from %s\n", eeprom_filename
);
96 WriteLog("EEPROM: Could not open file \"%s\"!\n", eeprom_filename
);
99 // Handle JagCD EEPROM
100 sprintf(cdromEEPROMFilename
, "%scdrom.eeprom", vjs
.EEPROMPath
);
101 fp
= fopen(cdromEEPROMFilename
, "rb");
105 ReadEEPROMFromFile(fp
, cdromEEPROM
);
107 WriteLog("EEPROM: Loaded from cdrom.eeprom\n");
108 haveCDROMEEPROM
= true;
112 WriteLog("EEPROM: Could not open file \"%s\"!\n", cdromEEPROMFilename
);
119 void EepromReset(void)
123 memset(eeprom_ram
, 0xFF, 64 * sizeof(uint16_t));
126 if (!haveCDROMEEPROM
)
128 memset(cdromEEPROM
, 0xFF, 64 * sizeof(uint16_t));
134 void EepromDone(void)
136 WriteLog("EEPROM: Done.\n");
141 static void EEPROMSave(void)
145 // Check if EEPROM directory exists and try to create it if not
146 if (_mkdir(vjs
.EEPROMPath
))
148 WriteLog("EEPROM: Could not create directory \"%s!\"\n", vjs
.EEPROMPath
);
151 // Write out regular cartridge EEPROM data
152 fp
= fopen(eeprom_filename
, "wb");
155 WriteEEPROMToFile(fp
, eeprom_ram
);
160 WriteLog("EEPROM: Could not create file \"%s!\"\n", eeprom_filename
);
163 // Write out JagCD EEPROM data
164 fp
= fopen(cdromEEPROMFilename
, "wb");
167 WriteEEPROMToFile(fp
, cdromEEPROM
);
172 WriteLog("EEPROM: Could not create file \"%s!\"\n", cdromEEPROMFilename
);
178 // Read/write EEPROM files to disk in an endian safe manner
180 void ReadEEPROMFromFile(FILE * file
, uint16_t * ram
)
183 size_t ignored
= fread(buffer
, 1, 128, file
);
185 for (int i
= 0; i
< 64; i
++)
187 ram
[i
] = (buffer
[(i
* 2) + 0] << 8) | buffer
[(i
* 2) + 1];
192 void WriteEEPROMToFile(FILE * file
, uint16_t * ram
)
196 for(int i
=0; i
<64; i
++)
198 buffer
[(i
* 2) + 0] = ram
[i
] >> 8;
199 buffer
[(i
* 2) + 1] = ram
[i
] & 0xFF;
202 fwrite(buffer
, 1, 128, file
);
206 uint8_t EepromReadByte(uint32_t offset
)
211 return eeprom_get_do();
219 WriteLog("EEPROM: unmapped 0x%.8x\n", offset
);
228 uint16_t EepromReadWord(uint32_t offset
)
230 return ((uint16_t)EepromReadByte(offset
+ 0) << 8) | EepromReadByte(offset
+ 1);
234 void EepromWriteByte(uint32_t offset
, uint8_t data
)
241 eeprom_set_di(data
& 0x01);
248 WriteLog("eeprom: unmapped 0x%.8x\n",offset
);
255 void EepromWriteWord(uint32_t offset
, uint16_t data
)
257 EepromWriteByte(offset
+ 0, (data
>> 8) & 0xFF);
258 EepromWriteByte(offset
+ 1, data
& 0xFF);
264 ; Commands specific to the National Semiconductor NM93C14
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
279 static void eeprom_set_di(uint32_t data
)
282 WriteLog("eeprom: di=%i\n",data
);
283 WriteLog("eeprom: state %i\n",jerry_ee_state
);
286 switch (jerry_ee_state
)
289 jerry_ee_state
= EE_STATE_OP_A
;
292 jerry_ee_op
= (data
<< 1);
293 jerry_ee_state
= EE_STATE_OP_B
;
297 jerry_ee_direct_jump
= 0;
299 WriteLog("eeprom: opcode %i\n",jerry_ee_op
);
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;
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;
324 switch ((jerry_ee_address_data
>> 4) & 0x03)
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;
341 WriteLog("eeprom: read only\n");
343 jerry_writes_enabled
= 0;
344 jerry_ee_state
= EE_STATE_START
;
348 jerry_ee_rstate
= EE_STATE_0_0_1_0
;
349 jerry_ee_state
= EE_READ_DATA
;
350 jerry_ee_data_cnt
= 16;
352 jerry_ee_direct_jump
= 1;
354 case EE_STATE_0_0_1_0
:
356 WriteLog("eeprom: filling eeprom with 0x%.4x\n",data
);
358 if (jerry_writes_enabled
)
360 for(int i
=0; i
<64; i
++)
361 eeprom_ram
[i
] = jerry_ee_data
;
363 EEPROMSave(); // Save it NOW!
368 WriteLog("eeprom: not writing because read only\n");
370 jerry_ee_state
= EE_STATE_BUSY
;
375 WriteLog("eeprom: erasing eeprom\n");
377 if (jerry_writes_enabled
)
378 for(int i
=0; i
<64; i
++)
379 eeprom_ram
[i
] = 0xFFFF;
381 jerry_ee_state
= EE_STATE_BUSY
;
386 WriteLog("eeprom: read/write\n");
388 jerry_writes_enabled
= 1;
389 jerry_ee_state
= EE_STATE_START
;
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;
399 jerry_ee_rstate
= EE_STATE_1_1
;
400 jerry_ee_state
= EE_READ_DATA
;
401 jerry_ee_data_cnt
= 16;
403 jerry_ee_direct_jump
= 1;
407 WriteLog("eeprom: writing 0x%.4x at 0x%.2x\n",jerry_ee_data
,jerry_ee_address_data
);
409 if (jerry_writes_enabled
)
411 eeprom_ram
[jerry_ee_address_data
] = jerry_ee_data
;
412 EEPROMSave(); // Save it NOW!
415 jerry_ee_state
= EE_STATE_BUSY
;
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;
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;
434 WriteLog("eeprom: erasing 0x%.2x\n",jerry_ee_address_data
);
436 if (jerry_writes_enabled
)
437 eeprom_ram
[jerry_ee_address_data
] = 0xFFFF;
439 jerry_ee_state
= EE_STATE_BUSY
;
443 WriteLog("eeprom:\t\t\t%i bit %i\n",data
,jerry_ee_data_cnt
-1);
446 jerry_ee_data
|= data
;
449 if (!jerry_ee_data_cnt
)
451 jerry_ee_state
= jerry_ee_rstate
;
453 if (jerry_ee_direct_jump
)
458 case EE_READ_ADDRESS
:
459 jerry_ee_address_data
<<= 1;
460 jerry_ee_address_data
|= data
;
461 jerry_ee_address_cnt
--;
463 WriteLog("eeprom:\t%i bits remaining\n",jerry_ee_address_cnt
);
466 if (!jerry_ee_address_cnt
)
468 jerry_ee_state
= jerry_ee_rstate
;
470 WriteLog("eeprom:\t\tread address 0x%.2x\n",jerry_ee_address_data
);
473 if (jerry_ee_direct_jump
)
479 jerry_ee_state
= EE_STATE_OP_A
;
484 static void eeprom_set_cs(uint32_t state
)
487 WriteLog("eeprom: cs=%i\n",state
);
489 jerry_ee_state
= EE_STATE_START
;
492 jerry_ee_address_data
= 0;
493 jerry_ee_address_cnt
= 6;
495 jerry_ee_data_cnt
= 16;
496 jerry_writes_enabled
= 1;
500 static uint32_t eeprom_get_do(void)
504 switch (jerry_ee_state
)
510 jerry_ee_state
= EE_STATE_START
;
515 data
= (eeprom_ram
[jerry_ee_address_data
] >> jerry_ee_data_cnt
) & 0x01;
517 if (!jerry_ee_data_cnt
)
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());
522 jerry_ee_state
= EE_STATE_START
;
528 WriteLog("eeprom: do=%i\n",data
);