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