Mercurial > repos > blastem
comparison romdb.c @ 768:2f48a3c187c6
Add support for reading cartridge memory map from ROM database, though without EEPROM support for now
author | Michael Pavone <pavone@retrodev.com> |
---|---|
date | Tue, 07 Jul 2015 19:33:33 -0700 |
parents | ea525f600b1d |
children | 4638b88bc72d |
comparison
equal
deleted
inserted
replaced
767:ea525f600b1d | 768:2f48a3c187c6 |
---|---|
205 } | 205 } |
206 | 206 |
207 uint32_t get_u32be(uint8_t *data) | 207 uint32_t get_u32be(uint8_t *data) |
208 { | 208 { |
209 return *data << 24 | data[1] << 16 | data[2] << 8 | data[3]; | 209 return *data << 24 | data[1] << 16 | data[2] << 8 | data[3]; |
210 } | |
211 | |
212 uint32_t calc_mask(uint32_t src_size, uint32_t start, uint32_t end) | |
213 { | |
214 uint32_t map_size = end-start+1; | |
215 if (src_size < map_size) { | |
216 return nearest_pow2(src_size)-1; | |
217 } else if (!start) { | |
218 return 0xFFFFFF; | |
219 } else { | |
220 return nearest_pow2(map_size)-1; | |
221 } | |
210 } | 222 } |
211 | 223 |
212 void add_memmap_header(rom_info *info, uint8_t *rom, uint32_t size, memmap_chunk const *base_map, int base_chunks) | 224 void add_memmap_header(rom_info *info, uint8_t *rom, uint32_t size, memmap_chunk const *base_map, int base_chunks) |
213 { | 225 { |
214 if (rom[RAM_ID] == 'R' && rom[RAM_ID+1] == 'A') { | 226 if (rom[RAM_ID] == 'R' && rom[RAM_ID+1] == 'A') { |
296 info.regions = get_header_regions(rom); | 308 info.regions = get_header_regions(rom); |
297 add_memmap_header(&info, rom, rom_size, base_map, base_chunks); | 309 add_memmap_header(&info, rom, rom_size, base_map, base_chunks); |
298 return info; | 310 return info; |
299 } | 311 } |
300 | 312 |
313 typedef struct { | |
314 rom_info *info; | |
315 uint8_t *rom; | |
316 tern_node *root; | |
317 uint32_t rom_size; | |
318 int index; | |
319 } map_iter_state; | |
320 | |
321 void map_iter_fun(char *key, tern_val val, void *data) | |
322 { | |
323 map_iter_state *state = data; | |
324 tern_node *node = tern_get_node(val); | |
325 if (!node) { | |
326 fprintf(stderr, "ROM DB map entry %d with address %s is not a node\n", state->index, key); | |
327 exit(1); | |
328 } | |
329 uint32_t start = strtol(key, NULL, 16); | |
330 uint32_t end = strtol(tern_find_ptr_default(node, "last", "0"), NULL, 16); | |
331 if (!end || end < start) { | |
332 fprintf(stderr, "'last' value is missing or invalid for ROM DB map entry %d with address %s\n", state->index, key); | |
333 exit(1); | |
334 } | |
335 char * dtype = tern_find_ptr_default(node, "device", "ROM"); | |
336 uint32_t offset = strtol(tern_find_ptr_default(node, "offset", "0"), NULL, 0); | |
337 memmap_chunk *map = state->info->map + state->index; | |
338 map->start = start; | |
339 map->end = end; | |
340 if (!strcmp(dtype, "ROM")) { | |
341 map->buffer = state->rom + offset; | |
342 map->flags = MMAP_READ; | |
343 map->mask = calc_mask(state->rom_size, start, end); | |
344 } else if (!strcmp(dtype, "EEPROM")) { | |
345 | |
346 | |
347 } else if (!strcmp(dtype, "SRAM")) { | |
348 if (!state->info->save_size) { | |
349 char * size = tern_find_path(state->root, "SRAM\0size\0").ptrval; | |
350 if (!size) { | |
351 fprintf(stderr, "ROM DB map entry %d with address %s has device type SRAM, but the SRAM size is not defined\n", state->index, key); | |
352 exit(1); | |
353 } | |
354 state->info->save_size = atoi(size); | |
355 if (!state->info->save_size) { | |
356 fprintf(stderr, "SRAM size %s is invalid\n", size); | |
357 exit(1); | |
358 } | |
359 state->info->save_buffer = malloc(state->info->save_size); | |
360 char *bus = tern_find_path(state->root, "SRAM\0bus\0").ptrval; | |
361 if (!strcmp(bus, "odd")) { | |
362 state->info->save_type = RAM_FLAG_ODD; | |
363 } else if(!strcmp(bus, "even")) { | |
364 state->info->save_type = RAM_FLAG_EVEN; | |
365 } else { | |
366 state->info->save_type = RAM_FLAG_BOTH; | |
367 } | |
368 } | |
369 map->buffer = state->info->save_buffer + offset; | |
370 map->flags = MMAP_READ | MMAP_WRITE; | |
371 if (state->info->save_type == RAM_FLAG_ODD) { | |
372 map->flags |= MMAP_ONLY_ODD; | |
373 } else if(state->info->save_type == RAM_FLAG_EVEN) { | |
374 map->flags |= MMAP_ONLY_EVEN; | |
375 } | |
376 map->mask = calc_mask(state->info->save_size, start, end); | |
377 } else { | |
378 fprintf(stderr, "Invalid device type for ROM DB map entry %d with address %s\n", state->index, key); | |
379 exit(1); | |
380 } | |
381 state->index++; | |
382 } | |
383 | |
301 rom_info configure_rom(tern_node *rom_db, void *vrom, uint32_t rom_size, memmap_chunk const *base_map, uint32_t base_chunks) | 384 rom_info configure_rom(tern_node *rom_db, void *vrom, uint32_t rom_size, memmap_chunk const *base_map, uint32_t base_chunks) |
302 { | 385 { |
303 uint8_t product_id[GAME_ID_LEN+1]; | 386 uint8_t product_id[GAME_ID_LEN+1]; |
304 uint8_t *rom = vrom; | 387 uint8_t *rom = vrom; |
305 product_id[GAME_ID_LEN] = 0; | 388 product_id[GAME_ID_LEN] = 0; |
310 break; | 393 break; |
311 } | 394 } |
312 product_id[i] = rom[GAME_ID_OFF + i]; | 395 product_id[i] = rom[GAME_ID_OFF + i]; |
313 | 396 |
314 } | 397 } |
315 tern_node * entry = tern_find_prefix(rom_db, product_id); | 398 printf("Product ID: %s\n", product_id); |
399 tern_node * entry = tern_find_ptr(rom_db, product_id); | |
316 if (!entry) { | 400 if (!entry) { |
401 puts("Not found in ROM DB, examining header\n"); | |
317 return configure_rom_heuristics(rom, rom_size, base_map, base_chunks); | 402 return configure_rom_heuristics(rom, rom_size, base_map, base_chunks); |
318 } | 403 } |
319 rom_info info; | 404 rom_info info; |
320 info.name = tern_find_ptr(entry, "name"); | 405 info.name = tern_find_ptr(entry, "name"); |
321 if (info.name) { | 406 if (info.name) { |
407 printf("Found name: %s\n", info.name); | |
322 info.name = strdup(info.name); | 408 info.name = strdup(info.name); |
323 } else { | 409 } else { |
324 info.name = get_header_name(rom); | 410 info.name = get_header_name(rom); |
325 } | 411 } |
326 | 412 |
334 } | 420 } |
335 if (!info.regions) { | 421 if (!info.regions) { |
336 info.regions = get_header_regions(rom); | 422 info.regions = get_header_regions(rom); |
337 } | 423 } |
338 | 424 |
339 tern_node *map = tern_find_prefix(entry, "map"); | 425 tern_node *map = tern_find_ptr(entry, "map"); |
340 if (map) { | 426 if (map) { |
341 uint32_t map_count = tern_count(map); | 427 info.map_chunks = tern_count(map); |
342 if (map_count) { | 428 if (info.map_chunks) { |
343 | 429 info.map_chunks += base_chunks; |
430 info.save_buffer = NULL; | |
431 info.save_size = 0; | |
432 info.map = malloc(sizeof(memmap_chunk) * info.map_chunks); | |
433 memset(info.map, 0, sizeof(memmap_chunk) * (info.map_chunks - base_chunks)); | |
434 map_iter_state state = {&info, rom, entry, rom_size, 0}; | |
435 tern_foreach(map, map_iter_fun, &state); | |
436 memcpy(info.map + state.index, base_map, sizeof(memmap_chunk) * base_chunks); | |
344 } else { | 437 } else { |
345 add_memmap_header(&info, rom, rom_size, base_map, base_chunks); | 438 add_memmap_header(&info, rom, rom_size, base_map, base_chunks); |
346 } | 439 } |
347 } else { | 440 } else { |
348 add_memmap_header(&info, rom, rom_size, base_map, base_chunks); | 441 add_memmap_header(&info, rom, rom_size, base_map, base_chunks); |