Mercurial > repos > blastem
comparison romdb.c @ 803:236a184bf6f0
Merge
author | Michael Pavone <pavone@retrodev.com> |
---|---|
date | Sun, 26 Jul 2015 16:51:03 -0700 |
parents | 724bbec47f86 |
children | e6f2c9dbf6c8 |
comparison
equal
deleted
inserted
replaced
802:6811f601008f | 803:236a184bf6f0 |
---|---|
1 #include <stdlib.h> | |
2 #include <string.h> | |
3 #include "config.h" | |
4 #include "romdb.h" | |
5 #include "util.h" | |
6 #include "blastem.h" | |
7 | |
8 #define TITLE_START 0x150 | |
9 #define TITLE_END (TITLE_START+48) | |
10 #define GAME_ID_OFF 0x183 | |
11 #define GAME_ID_LEN 8 | |
12 #define ROM_END 0x1A4 | |
13 #define RAM_ID 0x1B0 | |
14 #define RAM_FLAGS 0x1B2 | |
15 #define RAM_START 0x1B4 | |
16 #define RAM_END 0x1B8 | |
17 #define REGION_START 0x1F0 | |
18 | |
19 enum { | |
20 I2C_IDLE, | |
21 I2C_START, | |
22 I2C_DEVICE_ACK, | |
23 I2C_ADDRESS_HI, | |
24 I2C_ADDRESS_HI_ACK, | |
25 I2C_ADDRESS, | |
26 I2C_ADDRESS_ACK, | |
27 I2C_READ, | |
28 I2C_READ_ACK, | |
29 I2C_WRITE, | |
30 I2C_WRITE_ACK | |
31 }; | |
32 | |
33 char * i2c_states[] = { | |
34 "idle", | |
35 "start", | |
36 "device ack", | |
37 "address hi", | |
38 "address hi ack", | |
39 "address", | |
40 "address ack", | |
41 "read", | |
42 "read_ack", | |
43 "write", | |
44 "write_ack" | |
45 }; | |
46 | |
47 void eeprom_init(eeprom_state *state, uint8_t *buffer, uint32_t size) | |
48 { | |
49 state->slave_sda = 1; | |
50 state->host_sda = state->scl = 0; | |
51 state->buffer = buffer; | |
52 state->size = size; | |
53 state->state = I2C_IDLE; | |
54 } | |
55 | |
56 void set_host_sda(eeprom_state *state, uint8_t val) | |
57 { | |
58 if (state->scl) { | |
59 if (val & ~state->host_sda) { | |
60 //low to high, stop condition | |
61 state->state = I2C_IDLE; | |
62 state->slave_sda = 1; | |
63 } else if (~val & state->host_sda) { | |
64 //high to low, start condition | |
65 state->state = I2C_START; | |
66 state->slave_sda = 1; | |
67 state->counter = 8; | |
68 } | |
69 } | |
70 state->host_sda = val; | |
71 } | |
72 | |
73 void set_scl(eeprom_state *state, uint8_t val) | |
74 { | |
75 if (val & ~state->scl) { | |
76 //low to high transition | |
77 switch (state->state) | |
78 { | |
79 case I2C_START: | |
80 case I2C_ADDRESS_HI: | |
81 case I2C_ADDRESS: | |
82 case I2C_WRITE: | |
83 state->latch = state->host_sda | state->latch << 1; | |
84 state->counter--; | |
85 if (!state->counter) { | |
86 switch (state->state & 0x7F) | |
87 { | |
88 case I2C_START: | |
89 state->state = I2C_DEVICE_ACK; | |
90 break; | |
91 case I2C_ADDRESS_HI: | |
92 state->address = state->latch << 8; | |
93 state->state = I2C_ADDRESS_HI_ACK; | |
94 break; | |
95 case I2C_ADDRESS: | |
96 state->address |= state->latch; | |
97 state->state = I2C_ADDRESS_ACK; | |
98 break; | |
99 case I2C_WRITE: | |
100 state->buffer[state->address] = state->latch; | |
101 state->state = I2C_WRITE_ACK; | |
102 break; | |
103 } | |
104 } | |
105 break; | |
106 case I2C_DEVICE_ACK: | |
107 if (state->latch & 1) { | |
108 state->state = I2C_READ; | |
109 state->counter = 8; | |
110 state->latch = state->buffer[state->address]; | |
111 } else { | |
112 if (state->size < 256) { | |
113 state->address = state->latch >> 1; | |
114 state->state = I2C_WRITE; | |
115 } else if (state->size < 4096) { | |
116 state->address = (state->latch & 0xE) << 7; | |
117 state->state = I2C_ADDRESS; | |
118 } else { | |
119 state->state = I2C_ADDRESS_HI; | |
120 } | |
121 state->counter = 8; | |
122 } | |
123 break; | |
124 case I2C_ADDRESS_HI_ACK: | |
125 state->state = I2C_ADDRESS; | |
126 state->counter = 8; | |
127 break; | |
128 case I2C_ADDRESS_ACK: | |
129 state->state = I2C_WRITE; | |
130 state->address &= state->size-1; | |
131 state->counter = 8; | |
132 break; | |
133 case I2C_READ: | |
134 state->counter--; | |
135 if (!state->counter) { | |
136 state->state = I2C_READ_ACK; | |
137 } | |
138 break; | |
139 case I2C_READ_ACK: | |
140 state->state = I2C_READ; | |
141 state->counter = 8; | |
142 state->address++; | |
143 //TODO: page mask | |
144 state->address &= state->size-1; | |
145 state->latch = state->buffer[state->address]; | |
146 break; | |
147 case I2C_WRITE_ACK: | |
148 state->state = I2C_WRITE; | |
149 state->counter = 8; | |
150 state->address++; | |
151 //TODO: page mask | |
152 state->address &= state->size-1; | |
153 break; | |
154 } | |
155 } else if (~val & state->scl) { | |
156 //high to low transition | |
157 switch (state->state & 0x7F) | |
158 { | |
159 case I2C_DEVICE_ACK: | |
160 case I2C_ADDRESS_HI_ACK: | |
161 case I2C_ADDRESS_ACK: | |
162 case I2C_READ_ACK: | |
163 case I2C_WRITE_ACK: | |
164 state->slave_sda = 0; | |
165 break; | |
166 case I2C_READ: | |
167 state->slave_sda = state->latch >> 7; | |
168 state->latch = state->latch << 1; | |
169 break; | |
170 default: | |
171 state->slave_sda = 1; | |
172 break; | |
173 } | |
174 } | |
175 state->scl = val; | |
176 } | |
177 | |
178 uint8_t get_sda(eeprom_state *state) | |
179 { | |
180 return state->host_sda & state->slave_sda; | |
181 } | |
182 | |
183 uint16_t read_sram_w(uint32_t address, m68k_context * context) | |
184 { | |
185 genesis_context * gen = context->system; | |
186 address &= gen->save_ram_mask; | |
187 switch(gen->save_type) | |
188 { | |
189 case RAM_FLAG_BOTH: | |
190 return gen->save_storage[address] << 8 | gen->save_storage[address+1]; | |
191 case RAM_FLAG_EVEN: | |
192 return gen->save_storage[address >> 1] << 8 | 0xFF; | |
193 case RAM_FLAG_ODD: | |
194 return gen->save_storage[address >> 1] | 0xFF00; | |
195 } | |
196 return 0xFFFF;//We should never get here | |
197 } | |
198 | |
199 uint8_t read_sram_b(uint32_t address, m68k_context * context) | |
200 { | |
201 genesis_context * gen = context->system; | |
202 address &= gen->save_ram_mask; | |
203 switch(gen->save_type) | |
204 { | |
205 case RAM_FLAG_BOTH: | |
206 return gen->save_storage[address]; | |
207 case RAM_FLAG_EVEN: | |
208 if (address & 1) { | |
209 return 0xFF; | |
210 } else { | |
211 return gen->save_storage[address >> 1]; | |
212 } | |
213 case RAM_FLAG_ODD: | |
214 if (address & 1) { | |
215 return gen->save_storage[address >> 1]; | |
216 } else { | |
217 return 0xFF; | |
218 } | |
219 } | |
220 return 0xFF;//We should never get here | |
221 } | |
222 | |
223 m68k_context * write_sram_area_w(uint32_t address, m68k_context * context, uint16_t value) | |
224 { | |
225 genesis_context * gen = context->system; | |
226 if ((gen->bank_regs[0] & 0x3) == 1) { | |
227 address &= gen->save_ram_mask; | |
228 switch(gen->save_type) | |
229 { | |
230 case RAM_FLAG_BOTH: | |
231 gen->save_storage[address] = value >> 8; | |
232 gen->save_storage[address+1] = value; | |
233 break; | |
234 case RAM_FLAG_EVEN: | |
235 gen->save_storage[address >> 1] = value >> 8; | |
236 break; | |
237 case RAM_FLAG_ODD: | |
238 gen->save_storage[address >> 1] = value; | |
239 break; | |
240 } | |
241 } | |
242 return context; | |
243 } | |
244 | |
245 m68k_context * write_sram_area_b(uint32_t address, m68k_context * context, uint8_t value) | |
246 { | |
247 genesis_context * gen = context->system; | |
248 if ((gen->bank_regs[0] & 0x3) == 1) { | |
249 address &= gen->save_ram_mask; | |
250 switch(gen->save_type) | |
251 { | |
252 case RAM_FLAG_BOTH: | |
253 gen->save_storage[address] = value; | |
254 break; | |
255 case RAM_FLAG_EVEN: | |
256 if (!(address & 1)) { | |
257 gen->save_storage[address >> 1] = value; | |
258 } | |
259 break; | |
260 case RAM_FLAG_ODD: | |
261 if (address & 1) { | |
262 gen->save_storage[address >> 1] = value; | |
263 } | |
264 break; | |
265 } | |
266 } | |
267 return context; | |
268 } | |
269 | |
270 m68k_context * write_bank_reg_w(uint32_t address, m68k_context * context, uint16_t value) | |
271 { | |
272 genesis_context * gen = context->system; | |
273 address &= 0xE; | |
274 address >>= 1; | |
275 gen->bank_regs[address] = value; | |
276 if (!address) { | |
277 if (value & 1) { | |
278 for (int i = 0; i < 8; i++) | |
279 { | |
280 context->mem_pointers[gen->mapper_start_index + i] = NULL; | |
281 } | |
282 } else { | |
283 //Used for games that only use the mapper for SRAM | |
284 context->mem_pointers[gen->mapper_start_index] = cart + 0x200000/2; | |
285 //For games that need more than 4MB | |
286 for (int i = 1; i < 8; i++) | |
287 { | |
288 context->mem_pointers[gen->mapper_start_index + i] = cart + 0x40000*gen->bank_regs[i]; | |
289 } | |
290 } | |
291 } else { | |
292 context->mem_pointers[gen->mapper_start_index + address] = cart + 0x40000*value; | |
293 } | |
294 return context; | |
295 } | |
296 | |
297 m68k_context * write_bank_reg_b(uint32_t address, m68k_context * context, uint8_t value) | |
298 { | |
299 if (address & 1) { | |
300 write_bank_reg_w(address, context, value); | |
301 } | |
302 return context; | |
303 } | |
304 eeprom_map *find_eeprom_map(uint32_t address, genesis_context *gen) | |
305 { | |
306 for (int i = 0; i < gen->num_eeprom; i++) | |
307 { | |
308 if (address >= gen->eeprom_map[i].start && address <= gen->eeprom_map[i].end) { | |
309 return gen->eeprom_map + i; | |
310 } | |
311 } | |
312 return NULL; | |
313 } | |
314 | |
315 void * write_eeprom_i2c_w(uint32_t address, void * context, uint16_t value) | |
316 { | |
317 genesis_context *gen = ((m68k_context *)context)->system; | |
318 eeprom_map *map = find_eeprom_map(address, gen); | |
319 if (!map) { | |
320 fatal_error("Could not find EEPROM map for address %X\n", address); | |
321 } | |
322 if (map->scl_mask) { | |
323 set_scl(&gen->eeprom, (value & map->scl_mask) != 0); | |
324 } | |
325 if (map->sda_write_mask) { | |
326 set_host_sda(&gen->eeprom, (value & map->sda_write_mask) != 0); | |
327 } | |
328 return context; | |
329 } | |
330 | |
331 void * write_eeprom_i2c_b(uint32_t address, void * context, uint8_t value) | |
332 { | |
333 genesis_context *gen = ((m68k_context *)context)->system; | |
334 eeprom_map *map = find_eeprom_map(address, gen); | |
335 if (!map) { | |
336 fatal_error("Could not find EEPROM map for address %X\n", address); | |
337 } | |
338 | |
339 uint16_t expanded, mask; | |
340 if (address & 1) { | |
341 expanded = value; | |
342 mask = 0xFF; | |
343 } else { | |
344 expanded = value << 8; | |
345 mask = 0xFF00; | |
346 } | |
347 if (map->scl_mask & mask) { | |
348 set_scl(&gen->eeprom, (expanded & map->scl_mask) != 0); | |
349 } | |
350 if (map->sda_write_mask & mask) { | |
351 set_host_sda(&gen->eeprom, (expanded & map->sda_write_mask) != 0); | |
352 } | |
353 return context; | |
354 } | |
355 | |
356 uint16_t read_eeprom_i2c_w(uint32_t address, void * context) | |
357 { | |
358 genesis_context *gen = ((m68k_context *)context)->system; | |
359 eeprom_map *map = find_eeprom_map(address, gen); | |
360 if (!map) { | |
361 fatal_error("Could not find EEPROM map for address %X\n", address); | |
362 } | |
363 uint16_t ret = 0; | |
364 if (map->sda_read_bit < 16) { | |
365 ret = get_sda(&gen->eeprom) << map->sda_read_bit; | |
366 } | |
367 return ret; | |
368 } | |
369 | |
370 uint8_t read_eeprom_i2c_b(uint32_t address, void * context) | |
371 { | |
372 genesis_context *gen = ((m68k_context *)context)->system; | |
373 eeprom_map *map = find_eeprom_map(address, gen); | |
374 if (!map) { | |
375 fatal_error("Could not find EEPROM map for address %X\n", address); | |
376 } | |
377 uint8_t bit = address & 1 ? map->sda_read_bit : map->sda_read_bit - 8; | |
378 uint8_t ret = 0; | |
379 if (bit < 8) { | |
380 ret = get_sda(&gen->eeprom) << bit; | |
381 } | |
382 return ret; | |
383 } | |
384 | |
385 tern_node *load_rom_db() | |
386 { | |
387 char *exe_dir = get_exe_dir(); | |
388 if (!exe_dir) { | |
389 fatal_error("Failed to find executable path\n"); | |
390 } | |
391 char *path = alloc_concat(exe_dir, "/rom.db"); | |
392 tern_node *db = parse_config_file(path); | |
393 free(path); | |
394 if (!db) { | |
395 fatal_error("Failed to load ROM DB\n"); | |
396 } | |
397 return db; | |
398 } | |
399 | |
400 char *get_header_name(uint8_t *rom) | |
401 { | |
402 uint8_t *last = rom + TITLE_END - 1; | |
403 uint8_t *src = rom + TITLE_START; | |
404 | |
405 while (last > src && (*last <= 0x20 || *last >= 0x80)) | |
406 { | |
407 last--; | |
408 } | |
409 if (last == src) { | |
410 //TODO: Use other name field | |
411 return strdup("UNKNOWN"); | |
412 } else { | |
413 last++; | |
414 char *ret = malloc(last - (rom + TITLE_START) + 1); | |
415 uint8_t *dst; | |
416 for (dst = ret; src < last; src++) | |
417 { | |
418 if (*src >= 0x20 && *src < 0x80) { | |
419 *(dst++) = *src; | |
420 } | |
421 } | |
422 *dst = 0; | |
423 return ret; | |
424 } | |
425 } | |
426 | |
427 char *region_chars = "UB4JEA"; | |
428 uint8_t region_bits[] = {REGION_U, REGION_U, REGION_U, REGION_J, REGION_E, REGION_E}; | |
429 | |
430 uint8_t translate_region_char(uint8_t c) | |
431 { | |
432 for (int i = 0; i < sizeof(region_bits); i++) | |
433 { | |
434 if (c == region_chars[i]) { | |
435 return region_bits[i]; | |
436 } | |
437 } | |
438 return 0; | |
439 } | |
440 | |
441 uint8_t get_header_regions(uint8_t *rom) | |
442 { | |
443 uint8_t regions = 0; | |
444 for (int i = 0; i < 3; i++) | |
445 { | |
446 regions |= translate_region_char(rom[REGION_START + i]); | |
447 } | |
448 return regions; | |
449 } | |
450 | |
451 uint32_t get_u32be(uint8_t *data) | |
452 { | |
453 return *data << 24 | data[1] << 16 | data[2] << 8 | data[3]; | |
454 } | |
455 | |
456 uint32_t calc_mask(uint32_t src_size, uint32_t start, uint32_t end) | |
457 { | |
458 uint32_t map_size = end-start+1; | |
459 if (src_size < map_size) { | |
460 return nearest_pow2(src_size)-1; | |
461 } else if (!start) { | |
462 return 0xFFFFFF; | |
463 } else { | |
464 return nearest_pow2(map_size)-1; | |
465 } | |
466 } | |
467 | |
468 void add_memmap_header(rom_info *info, uint8_t *rom, uint32_t size, memmap_chunk const *base_map, int base_chunks) | |
469 { | |
470 uint32_t rom_end = get_u32be(rom + ROM_END) + 1; | |
471 if (size > rom_end) { | |
472 rom_end = size; | |
473 } else if (rom_end > nearest_pow2(size)) { | |
474 rom_end = nearest_pow2(size); | |
475 } | |
476 if (rom[RAM_ID] == 'R' && rom[RAM_ID+1] == 'A') { | |
477 uint32_t ram_start = get_u32be(rom + RAM_START); | |
478 uint32_t ram_end = get_u32be(rom + RAM_END); | |
479 uint32_t ram_flags = info->save_type = rom[RAM_FLAGS] & RAM_FLAG_MASK; | |
480 ram_start &= 0xFFFFFE; | |
481 ram_end |= 1; | |
482 info->save_mask = ram_end - ram_start; | |
483 uint32_t save_size = info->save_mask + 1; | |
484 if (ram_flags != RAM_FLAG_BOTH) { | |
485 save_size /= 2; | |
486 } | |
487 info->save_size = save_size; | |
488 info->save_buffer = malloc(save_size); | |
489 | |
490 info->map_chunks = base_chunks + (ram_start >= rom_end ? 2 : 3); | |
491 info->map = malloc(sizeof(memmap_chunk) * info->map_chunks); | |
492 memset(info->map, 0, sizeof(memmap_chunk)*2); | |
493 memcpy(info->map+2, base_map, sizeof(memmap_chunk) * base_chunks); | |
494 | |
495 if (ram_start >= rom_end) { | |
496 info->map[0].end = rom_end > 0x400000 ? rom_end : 0x400000; | |
497 //TODO: ROM mirroring | |
498 info->map[0].mask = 0xFFFFFF; | |
499 info->map[0].flags = MMAP_READ; | |
500 info->map[0].buffer = rom; | |
501 | |
502 info->map[1].start = ram_start; | |
503 info->map[1].mask = info->save_mask; | |
504 info->map[1].end = ram_end + 1; | |
505 info->map[1].flags = MMAP_READ | MMAP_WRITE; | |
506 | |
507 if (ram_flags == RAM_FLAG_ODD) { | |
508 info->map[1].flags |= MMAP_ONLY_ODD; | |
509 } else if (ram_flags == RAM_FLAG_EVEN) { | |
510 info->map[1].flags |= MMAP_ONLY_EVEN; | |
511 } | |
512 info->map[1].buffer = info->save_buffer; | |
513 } else { | |
514 //Assume the standard Sega mapper | |
515 info->map[0].end = 0x200000; | |
516 info->map[0].mask = 0xFFFFFF; | |
517 info->map[0].flags = MMAP_READ; | |
518 info->map[0].buffer = rom; | |
519 | |
520 info->map[1].start = 0x200000; | |
521 info->map[1].end = 0x400000; | |
522 info->map[1].mask = 0x1FFFFF; | |
523 info->map[1].flags = MMAP_READ | MMAP_PTR_IDX | MMAP_FUNC_NULL; | |
524 info->map[1].ptr_index = info->mapper_start_index = 0; | |
525 info->map[1].read_16 = (read_16_fun)read_sram_w;//these will only be called when mem_pointers[2] == NULL | |
526 info->map[1].read_8 = (read_8_fun)read_sram_b; | |
527 info->map[1].write_16 = (write_16_fun)write_sram_area_w;//these will be called all writes to the area | |
528 info->map[1].write_8 = (write_8_fun)write_sram_area_b; | |
529 info->map[1].buffer = cart + 0x200000; | |
530 | |
531 memmap_chunk *last = info->map + info->map_chunks - 1; | |
532 memset(last, 0, sizeof(memmap_chunk)); | |
533 last->start = 0xA13000; | |
534 last->end = 0xA13100; | |
535 last->mask = 0xFF; | |
536 last->write_16 = (write_16_fun)write_bank_reg_w; | |
537 last->write_8 = (write_8_fun)write_bank_reg_b; | |
538 } | |
539 } else { | |
540 info->map_chunks = base_chunks + 1; | |
541 info->map = malloc(sizeof(memmap_chunk) * info->map_chunks); | |
542 memset(info->map, 0, sizeof(memmap_chunk)); | |
543 memcpy(info->map+1, base_map, sizeof(memmap_chunk) * base_chunks); | |
544 | |
545 info->map[0].end =rom_end > 0x400000 ? rom_end : 0x400000; | |
546 info->map[0].mask = 0xFFFFFF; | |
547 info->map[0].flags = MMAP_READ; | |
548 info->map[0].buffer = rom; | |
549 info->save_type = SAVE_NONE; | |
550 } | |
551 } | |
552 | |
553 rom_info configure_rom_heuristics(uint8_t *rom, uint32_t rom_size, memmap_chunk const *base_map, uint32_t base_chunks) | |
554 { | |
555 rom_info info; | |
556 info.name = get_header_name(rom); | |
557 info.regions = get_header_regions(rom); | |
558 add_memmap_header(&info, rom, rom_size, base_map, base_chunks); | |
559 return info; | |
560 } | |
561 | |
562 typedef struct { | |
563 rom_info *info; | |
564 uint8_t *rom; | |
565 tern_node *root; | |
566 uint32_t rom_size; | |
567 int index; | |
568 int num_els; | |
569 uint16_t ptr_index; | |
570 } map_iter_state; | |
571 | |
572 void eeprom_read_fun(char *key, tern_val val, void *data) | |
573 { | |
574 int bit = atoi(key); | |
575 if (bit < 0 || bit > 15) { | |
576 fprintf(stderr, "bit %s is out of range", key); | |
577 return; | |
578 } | |
579 char *pin = val.ptrval; | |
580 if (strcmp(pin, "sda")) { | |
581 fprintf(stderr, "bit %s is connected to unrecognized read pin %s", key, pin); | |
582 return; | |
583 } | |
584 eeprom_map *map = data; | |
585 map->sda_read_bit = bit; | |
586 } | |
587 | |
588 void eeprom_write_fun(char *key, tern_val val, void *data) | |
589 { | |
590 int bit = atoi(key); | |
591 if (bit < 0 || bit > 15) { | |
592 fprintf(stderr, "bit %s is out of range", key); | |
593 return; | |
594 } | |
595 char *pin = val.ptrval; | |
596 eeprom_map *map = data; | |
597 if (!strcmp(pin, "sda")) { | |
598 map->sda_write_mask = 1 << bit; | |
599 return; | |
600 } | |
601 if (!strcmp(pin, "scl")) { | |
602 map->scl_mask = 1 << bit; | |
603 return; | |
604 } | |
605 fprintf(stderr, "bit %s is connected to unrecognized write pin %s", key, pin); | |
606 } | |
607 | |
608 void process_sram_def(char *key, map_iter_state *state) | |
609 { | |
610 if (!state->info->save_size) { | |
611 char * size = tern_find_path(state->root, "SRAM\0size\0").ptrval; | |
612 if (!size) { | |
613 fatal_error("ROM DB map entry %d with address %s has device type SRAM, but the SRAM size is not defined\n", state->index, key); | |
614 } | |
615 state->info->save_size = atoi(size); | |
616 if (!state->info->save_size) { | |
617 fatal_error("SRAM size %s is invalid\n", size); | |
618 } | |
619 state->info->save_mask = nearest_pow2(state->info->save_size)-1; | |
620 state->info->save_buffer = malloc(state->info->save_size); | |
621 memset(state->info->save_buffer, 0, state->info->save_size); | |
622 char *bus = tern_find_path(state->root, "SRAM\0bus\0").ptrval; | |
623 if (!strcmp(bus, "odd")) { | |
624 state->info->save_type = RAM_FLAG_ODD; | |
625 } else if(!strcmp(bus, "even")) { | |
626 state->info->save_type = RAM_FLAG_EVEN; | |
627 } else { | |
628 state->info->save_type = RAM_FLAG_BOTH; | |
629 } | |
630 } | |
631 } | |
632 | |
633 void process_eeprom_def(char * key, map_iter_state *state) | |
634 { | |
635 if (!state->info->save_size) { | |
636 char * size = tern_find_path(state->root, "EEPROM\0size\0").ptrval; | |
637 if (!size) { | |
638 fatal_error("ROM DB map entry %d with address %s has device type EEPROM, but the EEPROM size is not defined\n", state->index, key); | |
639 } | |
640 state->info->save_size = atoi(size); | |
641 if (!state->info->save_size) { | |
642 fatal_error("EEPROM size %s is invalid\n", size); | |
643 } | |
644 char *etype = tern_find_path(state->root, "EEPROM\0type\0").ptrval; | |
645 if (!etype) { | |
646 etype = "i2c"; | |
647 } | |
648 if (!strcmp(etype, "i2c")) { | |
649 state->info->save_type = SAVE_I2C; | |
650 } else { | |
651 fatal_error("EEPROM type %s is invalid\n", etype); | |
652 } | |
653 state->info->save_buffer = malloc(state->info->save_size); | |
654 memset(state->info->save_buffer, 0xFF, state->info->save_size); | |
655 state->info->eeprom_map = malloc(sizeof(eeprom_map) * state->num_els); | |
656 memset(state->info->eeprom_map, 0, sizeof(eeprom_map) * state->num_els); | |
657 } | |
658 } | |
659 | |
660 void add_eeprom_map(tern_node *node, uint32_t start, uint32_t end, map_iter_state *state) | |
661 { | |
662 eeprom_map *eep_map = state->info->eeprom_map + state->info->num_eeprom; | |
663 eep_map->start = start; | |
664 eep_map->end = end; | |
665 eep_map->sda_read_bit = 0xFF; | |
666 tern_node * bits_read = tern_find_ptr(node, "bits_read"); | |
667 if (bits_read) { | |
668 tern_foreach(bits_read, eeprom_read_fun, eep_map); | |
669 } | |
670 tern_node * bits_write = tern_find_ptr(node, "bits_write"); | |
671 if (bits_write) { | |
672 tern_foreach(bits_write, eeprom_write_fun, eep_map); | |
673 } | |
674 printf("EEPROM address %X: sda read: %X, sda write: %X, scl: %X\n", start, eep_map->sda_read_bit, eep_map->sda_write_mask, eep_map->scl_mask); | |
675 state->info->num_eeprom++; | |
676 } | |
677 | |
678 void map_iter_fun(char *key, tern_val val, void *data) | |
679 { | |
680 map_iter_state *state = data; | |
681 tern_node *node = tern_get_node(val); | |
682 if (!node) { | |
683 fatal_error("ROM DB map entry %d with address %s is not a node\n", state->index, key); | |
684 } | |
685 uint32_t start = strtol(key, NULL, 16); | |
686 uint32_t end = strtol(tern_find_ptr_default(node, "last", "0"), NULL, 16); | |
687 if (!end || end < start) { | |
688 fatal_error("'last' value is missing or invalid for ROM DB map entry %d with address %s\n", state->index, key); | |
689 } | |
690 char * dtype = tern_find_ptr_default(node, "device", "ROM"); | |
691 uint32_t offset = strtol(tern_find_ptr_default(node, "offset", "0"), NULL, 16); | |
692 memmap_chunk *map = state->info->map + state->index; | |
693 map->start = start; | |
694 map->end = end + 1; | |
695 if (!strcmp(dtype, "ROM")) { | |
696 map->buffer = state->rom + offset; | |
697 map->flags = MMAP_READ; | |
698 map->mask = calc_mask(state->rom_size - offset, start, end); | |
699 } else if (!strcmp(dtype, "EEPROM")) { | |
700 process_eeprom_def(key, state); | |
701 add_eeprom_map(node, start, end, state); | |
702 | |
703 map->write_16 = write_eeprom_i2c_w; | |
704 map->write_8 = write_eeprom_i2c_b; | |
705 map->read_16 = read_eeprom_i2c_w; | |
706 map->read_8 = read_eeprom_i2c_b; | |
707 map->mask = 0xFFFFFF; | |
708 } else if (!strcmp(dtype, "SRAM")) { | |
709 process_sram_def(key, state); | |
710 map->buffer = state->info->save_buffer + offset; | |
711 map->flags = MMAP_READ | MMAP_WRITE; | |
712 if (state->info->save_type == RAM_FLAG_ODD) { | |
713 map->flags |= MMAP_ONLY_ODD; | |
714 } else if(state->info->save_type == RAM_FLAG_EVEN) { | |
715 map->flags |= MMAP_ONLY_EVEN; | |
716 } | |
717 map->mask = calc_mask(state->info->save_size, start, end); | |
718 } else if (!strcmp(dtype, "Sega mapper")) { | |
719 state->info->mapper_start_index = state->ptr_index++; | |
720 state->info->map_chunks+=7; | |
721 state->info->map = realloc(state->info->map, sizeof(memmap_chunk) * state->info->map_chunks); | |
722 memset(state->info->map + state->info->map_chunks - 7, 0, sizeof(memmap_chunk) * 7); | |
723 map = state->info->map + state->index; | |
724 char *save_device = tern_find_path(node, "save\0device\0").ptrval; | |
725 if (save_device && !strcmp(save_device, "EEPROM")) { | |
726 process_eeprom_def(key, state); | |
727 add_eeprom_map(node, start & map->mask, end & map->mask, state); | |
728 } | |
729 for (int i = 0; i < 7; i++, state->index++, map++) | |
730 { | |
731 map->start = start + i * 0x80000; | |
732 map->end = start + (i + 1) * 0x80000; | |
733 map->mask = 0x7FFFF; | |
734 map->buffer = state->rom + offset + i * 0x80000; | |
735 map->ptr_index = state->ptr_index++; | |
736 if (i < 3 || !save_device) { | |
737 map->flags = MMAP_READ | MMAP_PTR_IDX; | |
738 } else { | |
739 map->flags = MMAP_READ | MMAP_PTR_IDX | MMAP_FUNC_NULL; | |
740 if (!strcmp(save_device, "SRAM")) { | |
741 process_sram_def(key, state); | |
742 map->read_16 = (read_16_fun)read_sram_w;//these will only be called when mem_pointers[2] == NULL | |
743 map->read_8 = (read_8_fun)read_sram_b; | |
744 map->write_16 = (write_16_fun)write_sram_area_w;//these will be called all writes to the area | |
745 map->write_8 = (write_8_fun)write_sram_area_b; | |
746 } else if (!strcmp(save_device, "EEPROM")) { | |
747 map->write_16 = write_eeprom_i2c_w; | |
748 map->write_8 = write_eeprom_i2c_b; | |
749 map->read_16 = read_eeprom_i2c_w; | |
750 map->read_8 = read_eeprom_i2c_b; | |
751 } | |
752 } | |
753 } | |
754 map->start = 0xA13000; | |
755 map->end = 0xA13100; | |
756 map->mask = 0xFF; | |
757 map->write_16 = (write_16_fun)write_bank_reg_w; | |
758 map->write_8 = (write_8_fun)write_bank_reg_b; | |
759 } else { | |
760 fatal_error("Invalid device type for ROM DB map entry %d with address %s\n", state->index, key); | |
761 } | |
762 state->index++; | |
763 } | |
764 | |
765 rom_info configure_rom(tern_node *rom_db, void *vrom, uint32_t rom_size, memmap_chunk const *base_map, uint32_t base_chunks) | |
766 { | |
767 uint8_t product_id[GAME_ID_LEN+1]; | |
768 uint8_t *rom = vrom; | |
769 product_id[GAME_ID_LEN] = 0; | |
770 for (int i = 0; i < GAME_ID_LEN; i++) | |
771 { | |
772 if (rom[GAME_ID_OFF + i] <= ' ') { | |
773 product_id[i] = 0; | |
774 break; | |
775 } | |
776 product_id[i] = rom[GAME_ID_OFF + i]; | |
777 | |
778 } | |
779 printf("Product ID: %s\n", product_id); | |
780 tern_node * entry = tern_find_ptr(rom_db, product_id); | |
781 if (!entry) { | |
782 puts("Not found in ROM DB, examining header\n"); | |
783 return configure_rom_heuristics(rom, rom_size, base_map, base_chunks); | |
784 } | |
785 rom_info info; | |
786 info.name = tern_find_ptr(entry, "name"); | |
787 if (info.name) { | |
788 printf("Found name: %s\n", info.name); | |
789 info.name = strdup(info.name); | |
790 } else { | |
791 info.name = get_header_name(rom); | |
792 } | |
793 | |
794 char *dbreg = tern_find_ptr(entry, "regions"); | |
795 info.regions = 0; | |
796 if (dbreg) { | |
797 while (*dbreg != 0) | |
798 { | |
799 info.regions |= translate_region_char(*(dbreg++)); | |
800 } | |
801 } | |
802 if (!info.regions) { | |
803 info.regions = get_header_regions(rom); | |
804 } | |
805 | |
806 tern_node *map = tern_find_ptr(entry, "map"); | |
807 if (map) { | |
808 info.save_type = SAVE_NONE; | |
809 info.map_chunks = tern_count(map); | |
810 if (info.map_chunks) { | |
811 info.map_chunks += base_chunks; | |
812 info.save_buffer = NULL; | |
813 info.save_size = 0; | |
814 info.map = malloc(sizeof(memmap_chunk) * info.map_chunks); | |
815 info.eeprom_map = NULL; | |
816 info.num_eeprom = 0; | |
817 memset(info.map, 0, sizeof(memmap_chunk) * info.map_chunks); | |
818 map_iter_state state = {&info, rom, entry, rom_size, 0, info.map_chunks - base_chunks, 0}; | |
819 tern_foreach(map, map_iter_fun, &state); | |
820 memcpy(info.map + state.index, base_map, sizeof(memmap_chunk) * base_chunks); | |
821 } else { | |
822 add_memmap_header(&info, rom, rom_size, base_map, base_chunks); | |
823 } | |
824 } else { | |
825 add_memmap_header(&info, rom, rom_size, base_map, base_chunks); | |
826 } | |
827 | |
828 return info; | |
829 } |