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