comparison romdb.c @ 1414:d94855080529

Move I2C EEPROM and NOR Flash functions out of romdb.c into new files
author Michael Pavone <pavone@retrodev.com>
date Fri, 23 Jun 2017 21:48:38 -0700
parents 3d7f668dce3d
children f7d653bb8899
comparison
equal deleted inserted replaced
1413:3d7f668dce3d 1414:d94855080529
6 #include "hash.h" 6 #include "hash.h"
7 #include "genesis.h" 7 #include "genesis.h"
8 #include "menu.h" 8 #include "menu.h"
9 #include "xband.h" 9 #include "xband.h"
10 #include "realtec.h" 10 #include "realtec.h"
11 #include "nor.h"
11 12
12 #define DOM_TITLE_START 0x120 13 #define DOM_TITLE_START 0x120
13 #define DOM_TITLE_END 0x150 14 #define DOM_TITLE_END 0x150
14 #define TITLE_START DOM_TITLE_END 15 #define TITLE_START DOM_TITLE_END
15 #define TITLE_END (TITLE_START+48) 16 #define TITLE_END (TITLE_START+48)
26 return "EEPROM"; 27 return "EEPROM";
27 } else if(save_type == SAVE_NOR) { 28 } else if(save_type == SAVE_NOR) {
28 return "NOR Flash"; 29 return "NOR Flash";
29 } 30 }
30 return "SRAM"; 31 return "SRAM";
31 }
32
33 enum {
34 I2C_IDLE,
35 I2C_START,
36 I2C_DEVICE_ACK,
37 I2C_ADDRESS_HI,
38 I2C_ADDRESS_HI_ACK,
39 I2C_ADDRESS,
40 I2C_ADDRESS_ACK,
41 I2C_READ,
42 I2C_READ_ACK,
43 I2C_WRITE,
44 I2C_WRITE_ACK
45 };
46
47 char * i2c_states[] = {
48 "idle",
49 "start",
50 "device ack",
51 "address hi",
52 "address hi ack",
53 "address",
54 "address ack",
55 "read",
56 "read_ack",
57 "write",
58 "write_ack"
59 };
60
61 void eeprom_init(eeprom_state *state, uint8_t *buffer, uint32_t size)
62 {
63 state->slave_sda = 1;
64 state->host_sda = state->scl = 0;
65 state->buffer = buffer;
66 state->size = size;
67 state->state = I2C_IDLE;
68 }
69
70 void set_host_sda(eeprom_state *state, uint8_t val)
71 {
72 if (state->scl) {
73 if (val & ~state->host_sda) {
74 //low to high, stop condition
75 state->state = I2C_IDLE;
76 state->slave_sda = 1;
77 } else if (~val & state->host_sda) {
78 //high to low, start condition
79 state->state = I2C_START;
80 state->slave_sda = 1;
81 state->counter = 8;
82 }
83 }
84 state->host_sda = val;
85 }
86
87 void set_scl(eeprom_state *state, uint8_t val)
88 {
89 if (val & ~state->scl) {
90 //low to high transition
91 switch (state->state)
92 {
93 case I2C_START:
94 case I2C_ADDRESS_HI:
95 case I2C_ADDRESS:
96 case I2C_WRITE:
97 state->latch = state->host_sda | state->latch << 1;
98 state->counter--;
99 if (!state->counter) {
100 switch (state->state & 0x7F)
101 {
102 case I2C_START:
103 state->state = I2C_DEVICE_ACK;
104 break;
105 case I2C_ADDRESS_HI:
106 state->address = state->latch << 8;
107 state->state = I2C_ADDRESS_HI_ACK;
108 break;
109 case I2C_ADDRESS:
110 state->address |= state->latch;
111 state->state = I2C_ADDRESS_ACK;
112 break;
113 case I2C_WRITE:
114 state->buffer[state->address] = state->latch;
115 state->state = I2C_WRITE_ACK;
116 break;
117 }
118 }
119 break;
120 case I2C_DEVICE_ACK:
121 if (state->latch & 1) {
122 state->state = I2C_READ;
123 state->counter = 8;
124 if (state->size < 256) {
125 state->address = state->latch >> 1;
126 }
127 state->latch = state->buffer[state->address];
128 } else {
129 if (state->size < 256) {
130 state->address = state->latch >> 1;
131 state->state = I2C_WRITE;
132 } else if (state->size < 4096) {
133 state->address = (state->latch & 0xE) << 7;
134 state->state = I2C_ADDRESS;
135 } else {
136 state->state = I2C_ADDRESS_HI;
137 }
138 state->counter = 8;
139 }
140 break;
141 case I2C_ADDRESS_HI_ACK:
142 state->state = I2C_ADDRESS;
143 state->counter = 8;
144 break;
145 case I2C_ADDRESS_ACK:
146 state->state = I2C_WRITE;
147 state->address &= state->size-1;
148 state->counter = 8;
149 break;
150 case I2C_READ:
151 state->counter--;
152 if (!state->counter) {
153 state->state = I2C_READ_ACK;
154 }
155 break;
156 case I2C_READ_ACK:
157 state->state = I2C_READ;
158 state->counter = 8;
159 state->address++;
160 //TODO: page mask
161 state->address &= state->size-1;
162 state->latch = state->buffer[state->address];
163 break;
164 case I2C_WRITE_ACK:
165 state->state = I2C_WRITE;
166 state->counter = 8;
167 state->address++;
168 //TODO: page mask
169 state->address &= state->size-1;
170 break;
171 }
172 } else if (~val & state->scl) {
173 //high to low transition
174 switch (state->state & 0x7F)
175 {
176 case I2C_DEVICE_ACK:
177 case I2C_ADDRESS_HI_ACK:
178 case I2C_ADDRESS_ACK:
179 case I2C_READ_ACK:
180 case I2C_WRITE_ACK:
181 state->slave_sda = 0;
182 break;
183 case I2C_READ:
184 state->slave_sda = state->latch >> 7;
185 state->latch = state->latch << 1;
186 break;
187 default:
188 state->slave_sda = 1;
189 break;
190 }
191 }
192 state->scl = val;
193 }
194
195 uint8_t get_sda(eeprom_state *state)
196 {
197 return state->host_sda & state->slave_sda;
198 }
199
200 enum {
201 NOR_NORMAL,
202 NOR_PRODUCTID,
203 NOR_BOOTBLOCK
204 };
205
206 enum {
207 NOR_CMD_IDLE,
208 NOR_CMD_AA,
209 NOR_CMD_55
210 };
211
212 //Technically this value shoudl be slightly different between NTSC and PAL
213 //as it's defined as 200 micro-seconds, not in clock cycles
214 #define NOR_WRITE_PAUSE 10690
215
216 void nor_flash_init(nor_state *state, uint8_t *buffer, uint32_t size, uint32_t page_size, uint16_t product_id, uint8_t bus_flags)
217 {
218 state->buffer = buffer;
219 state->page_buffer = malloc(page_size);
220 memset(state->page_buffer, 0xFF, page_size);
221 state->size = size;
222 state->page_size = page_size;
223 state->product_id = product_id;
224 state->last_write_cycle = 0xFFFFFFFF;
225 state->mode = NOR_NORMAL;
226 state->cmd_state = NOR_CMD_IDLE;
227 state->alt_cmd = 0;
228 state->bus_flags = bus_flags;
229 }
230
231 void nor_run(nor_state *state, uint32_t cycle)
232 {
233 if (state->last_write_cycle == 0xFFFFFFFF) {
234 return;
235 }
236 if (cycle - state->last_write_cycle >= NOR_WRITE_PAUSE) {
237 state->last_write_cycle = 0xFFFFFFFF;
238 for (uint32_t i = 0; i < state->page_size; i++) {
239 state->buffer[state->current_page + i] = state->page_buffer[i];
240 }
241 memset(state->page_buffer, 0xFF, state->page_size);
242 }
243 }
244
245 uint8_t nor_flash_read_b(uint32_t address, void *vcontext)
246 {
247 m68k_context *m68k = vcontext;
248 genesis_context *gen = m68k->system;
249 nor_state *state = &gen->nor;
250 if (
251 ((address & 1) && state->bus_flags == RAM_FLAG_EVEN) ||
252 (!(address & 1) && state->bus_flags == RAM_FLAG_ODD)
253 ) {
254 return 0xFF;
255 }
256 if (state->bus_flags != RAM_FLAG_BOTH) {
257 address = address >> 1;
258 }
259
260 nor_run(state, m68k->current_cycle);
261 switch (state->mode)
262 {
263 case NOR_NORMAL:
264 return state->buffer[address & (state->size-1)];
265 break;
266 case NOR_PRODUCTID:
267 switch (address & (state->size - 1))
268 {
269 case 0:
270 return state->product_id >> 8;
271 case 1:
272 return state->product_id;
273 case 2:
274 //TODO: Implement boot block protection
275 return 0xFE;
276 default:
277 return 0xFE;
278 }
279 break;
280 case NOR_BOOTBLOCK:
281 break;
282 }
283 return 0xFF;
284 }
285
286 uint16_t nor_flash_read_w(uint32_t address, void *context)
287 {
288 uint16_t value = nor_flash_read_b(address, context) << 8;
289 value |= nor_flash_read_b(address+1, context);
290 return value;
291 }
292
293 void nor_write_byte(nor_state *state, uint32_t address, uint8_t value, uint32_t cycle)
294 {
295 switch(state->mode)
296 {
297 case NOR_NORMAL:
298 if (state->last_write_cycle != 0xFFFFFFFF) {
299 state->current_page = address & (state->size - 1) & ~(state->page_size - 1);
300 }
301 state->page_buffer[address & (state->page_size - 1)] = value;
302 break;
303 case NOR_PRODUCTID:
304 break;
305 case NOR_BOOTBLOCK:
306 //TODO: Implement boot block protection
307 state->mode = NOR_NORMAL;
308 break;
309 }
310 }
311
312 void *nor_flash_write_b(uint32_t address, void *vcontext, uint8_t value)
313 {
314 m68k_context *m68k = vcontext;
315 genesis_context *gen = m68k->system;
316 nor_state *state = &gen->nor;
317 if (
318 ((address & 1) && state->bus_flags == RAM_FLAG_EVEN) ||
319 (!(address & 1) && state->bus_flags == RAM_FLAG_ODD)
320 ) {
321 return vcontext;
322 }
323 if (state->bus_flags != RAM_FLAG_BOTH) {
324 address = address >> 1;
325 }
326
327 nor_run(state, m68k->current_cycle);
328 switch (state->cmd_state)
329 {
330 case NOR_CMD_IDLE:
331 if (value == 0xAA && (address & (state->size - 1)) == 0x5555) {
332 state->cmd_state = NOR_CMD_AA;
333 } else {
334 nor_write_byte(state, address, value, m68k->current_cycle);
335 state->cmd_state = NOR_CMD_IDLE;
336 }
337 break;
338 case NOR_CMD_AA:
339 if (value == 0x55 && (address & (state->size - 1)) == 0x2AAA) {
340 state->cmd_state = NOR_CMD_55;
341 } else {
342 nor_write_byte(state, 0x5555, 0xAA, m68k->current_cycle);
343 nor_write_byte(state, address, value, m68k->current_cycle);
344 state->cmd_state = NOR_CMD_IDLE;
345 }
346 break;
347 case NOR_CMD_55:
348 if ((address & (state->size - 1)) == 0x5555) {
349 if (state->alt_cmd) {
350 switch(value)
351 {
352 case 0x10:
353 puts("UNIMPLEMENTED: NOR flash erase");
354 break;
355 case 0x20:
356 puts("UNIMPLEMENTED: NOR flash disable protection");
357 break;
358 case 0x40:
359 state->mode = NOR_BOOTBLOCK;
360 break;
361 case 0x60:
362 state->mode = NOR_PRODUCTID;
363 break;
364 }
365 } else {
366 switch(value)
367 {
368 case 0x80:
369 state->alt_cmd = 1;
370 break;
371 case 0x90:
372 state->mode = NOR_PRODUCTID;
373 break;
374 case 0xA0:
375 puts("UNIMPLEMENTED: NOR flash enable protection");
376 break;
377 case 0xF0:
378 state->mode = NOR_NORMAL;
379 break;
380 default:
381 printf("Unrecognized unshifted NOR flash command %X\n", value);
382 }
383 }
384 } else {
385 nor_write_byte(state, 0x5555, 0xAA, m68k->current_cycle);
386 nor_write_byte(state, 0x2AAA, 0x55, m68k->current_cycle);
387 nor_write_byte(state, address, value, m68k->current_cycle);
388 }
389 state->cmd_state = NOR_CMD_IDLE;
390 break;
391 }
392 return vcontext;
393 }
394
395 void *nor_flash_write_w(uint32_t address, void *vcontext, uint16_t value)
396 {
397 nor_flash_write_b(address, vcontext, value >> 8);
398 return nor_flash_write_b(address + 1, vcontext, value);
399 } 32 }
400 33
401 uint16_t read_sram_w(uint32_t address, m68k_context * context) 34 uint16_t read_sram_w(uint32_t address, m68k_context * context)
402 { 35 {
403 genesis_context * gen = context->system; 36 genesis_context * gen = context->system;
528 { 161 {
529 if (address & 1) { 162 if (address & 1) {
530 write_bank_reg_w(address, context, value); 163 write_bank_reg_w(address, context, value);
531 } 164 }
532 return context; 165 return context;
533 }
534 eeprom_map *find_eeprom_map(uint32_t address, genesis_context *gen)
535 {
536 for (int i = 0; i < gen->num_eeprom; i++)
537 {
538 if (address >= gen->eeprom_map[i].start && address <= gen->eeprom_map[i].end) {
539 return gen->eeprom_map + i;
540 }
541 }
542 return NULL;
543 }
544
545 void * write_eeprom_i2c_w(uint32_t address, void * context, uint16_t value)
546 {
547 genesis_context *gen = ((m68k_context *)context)->system;
548 eeprom_map *map = find_eeprom_map(address, gen);
549 if (!map) {
550 fatal_error("Could not find EEPROM map for address %X\n", address);
551 }
552 if (map->scl_mask) {
553 set_scl(&gen->eeprom, (value & map->scl_mask) != 0);
554 }
555 if (map->sda_write_mask) {
556 set_host_sda(&gen->eeprom, (value & map->sda_write_mask) != 0);
557 }
558 return context;
559 }
560
561 void * write_eeprom_i2c_b(uint32_t address, void * context, uint8_t value)
562 {
563 genesis_context *gen = ((m68k_context *)context)->system;
564 eeprom_map *map = find_eeprom_map(address, gen);
565 if (!map) {
566 fatal_error("Could not find EEPROM map for address %X\n", address);
567 }
568
569 uint16_t expanded, mask;
570 if (address & 1) {
571 expanded = value;
572 mask = 0xFF;
573 } else {
574 expanded = value << 8;
575 mask = 0xFF00;
576 }
577 if (map->scl_mask & mask) {
578 set_scl(&gen->eeprom, (expanded & map->scl_mask) != 0);
579 }
580 if (map->sda_write_mask & mask) {
581 set_host_sda(&gen->eeprom, (expanded & map->sda_write_mask) != 0);
582 }
583 return context;
584 }
585
586 uint16_t read_eeprom_i2c_w(uint32_t address, void * context)
587 {
588 genesis_context *gen = ((m68k_context *)context)->system;
589 eeprom_map *map = find_eeprom_map(address, gen);
590 if (!map) {
591 fatal_error("Could not find EEPROM map for address %X\n", address);
592 }
593 uint16_t ret = 0;
594 if (map->sda_read_bit < 16) {
595 ret = get_sda(&gen->eeprom) << map->sda_read_bit;
596 }
597 return ret;
598 }
599
600 uint8_t read_eeprom_i2c_b(uint32_t address, void * context)
601 {
602 genesis_context *gen = ((m68k_context *)context)->system;
603 eeprom_map *map = find_eeprom_map(address, gen);
604 if (!map) {
605 fatal_error("Could not find EEPROM map for address %X\n", address);
606 }
607 uint8_t bit = address & 1 ? map->sda_read_bit : map->sda_read_bit - 8;
608 uint8_t ret = 0;
609 if (bit < 8) {
610 ret = get_sda(&gen->eeprom) << bit;
611 }
612 return ret;
613 } 166 }
614 167
615 tern_node *load_rom_db() 168 tern_node *load_rom_db()
616 { 169 {
617 tern_node *db = parse_bundled_config("rom.db"); 170 tern_node *db = parse_bundled_config("rom.db");