Commit | Line | Data |
---|---|---|
cf76e892 JPM |
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 |