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