changeset 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
files rom.db romdb.c tern.c tern.h util.c util.h
diffstat 6 files changed, 132 insertions(+), 21 deletions(-) [+]
line wrap: on
line diff
--- a/rom.db	Mon Jul 06 19:46:46 2015 -0700
+++ b/rom.db	Tue Jul 07 19:33:33 2015 -0700
@@ -1,6 +1,6 @@
 T-081326 {
 	name NBA Jam
-	eeprom {
+	EEPROM {
 		type i2c
 		size 256
 	}
@@ -10,7 +10,7 @@
 			last 1FFFFF
 		}
 		200000 {
-			device eeprom
+			device EEPROM
 			last 3FFFFF
 			bits_read {
 				1 sda
@@ -24,7 +24,7 @@
 }
 T-81033 {
 	name NBA Jam
-	eeprom {
+	EEPROM {
 		type i2c
 		size 256
 	}
@@ -34,7 +34,7 @@
 			last 1FFFFF
 		}
 		200000 {
-			device eeprom
+			device EEPROM
 			last 3FFFFF
 			bits_read {
 				1 sda
@@ -48,7 +48,7 @@
 }
 T-081276 {
 	name NFL Quarterback Club
-	eeprom {
+	EEPROM {
 		type i2c
 		size 256
 	}
@@ -58,7 +58,7 @@
 			last 1FFFFF
 		}
 		200000 {
-			device eeprom
+			device EEPROM
 			last 3FFFFF
 			bits_read {
 				0 sda
@@ -72,7 +72,7 @@
 }
 T-81406 {
 	name NBA Jam TE
-	eeprom {
+	EEPROM {
 		type i2c
 		size 512
 	}
@@ -82,7 +82,7 @@
 			last 1FFFFF
 		}
 		200000 {
-			device eeprom
+			device EEPROM
 			last 3FFFFF
 			bits_read {
 				0 sda
@@ -96,7 +96,7 @@
 }
 T-081586 {
 	name NFL Quarterback Club '96
-	eeprom {
+	EEPROM {
 		type i2c
 		size 2048
 	}
@@ -106,7 +106,7 @@
 			last 1FFFFF
 		}
 		200000 {
-			device eeprom
+			device EEPROM
 			last 3FFFFF
 			bits_read {
 				0 sda
@@ -120,7 +120,7 @@
 }
 T-81576 {
 	name College Slam
-	eeprom {
+	EEPROM {
 		type i2c
 		size 8192
 	}
@@ -130,7 +130,7 @@
 			last 1FFFFF
 		}
 		200000 {
-			device eeprom
+			device EEPROM
 			last 3FFFFF
 			bits_read {
 				0 sda
@@ -144,7 +144,7 @@
 }
 T-81476 {
 	name Frank Thomas Big Hurt Baseball
-	eeprom {
+	EEPROM {
 		type i2c
 		size 8192
 	}
@@ -154,7 +154,7 @@
 			last 1FFFFF
 		}
 		200000 {
-			device eeprom
+			device EEPROM
 			last 3FFFFF
 			bits_read {
 				0 sda
--- a/romdb.c	Mon Jul 06 19:46:46 2015 -0700
+++ b/romdb.c	Tue Jul 07 19:33:33 2015 -0700
@@ -209,6 +209,18 @@
 	return *data << 24 | data[1] << 16 | data[2] << 8 | data[3];
 }
 
+uint32_t calc_mask(uint32_t src_size, uint32_t start, uint32_t end)
+{
+	uint32_t map_size = end-start+1;
+	if (src_size < map_size) {
+		return nearest_pow2(src_size)-1;
+	} else if (!start) {
+		return 0xFFFFFF;
+	} else {
+		return nearest_pow2(map_size)-1;
+	}
+}
+
 void add_memmap_header(rom_info *info, uint8_t *rom, uint32_t size, memmap_chunk const *base_map, int base_chunks)
 {
 	if (rom[RAM_ID] == 'R' && rom[RAM_ID+1] == 'A') {
@@ -298,6 +310,77 @@
 	return info;
 }
 
+typedef struct {
+	rom_info     *info;
+	uint8_t      *rom;
+	tern_node    *root;
+	uint32_t     rom_size;
+	int          index;
+} map_iter_state;
+
+void map_iter_fun(char *key, tern_val val, void *data)
+{
+	map_iter_state *state = data;
+	tern_node *node = tern_get_node(val);
+	if (!node) {
+		fprintf(stderr, "ROM DB map entry %d with address %s is not a node\n", state->index, key);
+		exit(1);
+	}
+	uint32_t start = strtol(key, NULL, 16);
+	uint32_t end = strtol(tern_find_ptr_default(node, "last", "0"), NULL, 16);
+	if (!end || end < start) {
+		fprintf(stderr, "'last' value is missing or invalid for ROM DB map entry %d with address %s\n", state->index, key);
+		exit(1);
+	}
+	char * dtype = tern_find_ptr_default(node, "device", "ROM");
+	uint32_t offset = strtol(tern_find_ptr_default(node, "offset", "0"), NULL, 0);
+	memmap_chunk *map = state->info->map + state->index;
+	map->start = start;
+	map->end = end;
+	if (!strcmp(dtype, "ROM")) {
+		map->buffer = state->rom + offset;
+		map->flags = MMAP_READ;
+		map->mask = calc_mask(state->rom_size, start, end);
+	} else if (!strcmp(dtype, "EEPROM")) {
+		
+	
+	} else if (!strcmp(dtype, "SRAM")) {
+		if (!state->info->save_size) {
+			char * size = tern_find_path(state->root, "SRAM\0size\0").ptrval;
+			if (!size) {
+				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);
+				exit(1);
+			}
+			state->info->save_size = atoi(size);
+			if (!state->info->save_size) {
+				fprintf(stderr, "SRAM size %s is invalid\n", size);
+				exit(1);
+			}
+			state->info->save_buffer = malloc(state->info->save_size);
+			char *bus = tern_find_path(state->root, "SRAM\0bus\0").ptrval;
+			if (!strcmp(bus, "odd")) {
+				state->info->save_type = RAM_FLAG_ODD;
+			} else if(!strcmp(bus, "even")) {
+				state->info->save_type = RAM_FLAG_EVEN;
+			} else {
+				state->info->save_type = RAM_FLAG_BOTH;
+			}
+		}
+		map->buffer = state->info->save_buffer + offset;
+		map->flags = MMAP_READ | MMAP_WRITE;
+		if (state->info->save_type == RAM_FLAG_ODD) {
+			map->flags |= MMAP_ONLY_ODD;
+		} else if(state->info->save_type == RAM_FLAG_EVEN) {
+			map->flags |= MMAP_ONLY_EVEN;
+		}
+		map->mask = calc_mask(state->info->save_size, start, end);
+	} else {
+		fprintf(stderr, "Invalid device type for ROM DB map entry %d with address %s\n", state->index, key);
+		exit(1);
+	}
+	state->index++;
+}
+
 rom_info configure_rom(tern_node *rom_db, void *vrom, uint32_t rom_size, memmap_chunk const *base_map, uint32_t base_chunks)
 {
 	uint8_t product_id[GAME_ID_LEN+1];
@@ -312,13 +395,16 @@
 		product_id[i] = rom[GAME_ID_OFF + i];
 		
 	}
-	tern_node * entry = tern_find_prefix(rom_db, product_id);
+	printf("Product ID: %s\n", product_id);
+	tern_node * entry = tern_find_ptr(rom_db, product_id);
 	if (!entry) {
+		puts("Not found in ROM DB, examining header\n");
 		return configure_rom_heuristics(rom, rom_size, base_map, base_chunks);
 	}
 	rom_info info;
 	info.name = tern_find_ptr(entry, "name");
 	if (info.name) {
+		printf("Found name: %s\n", info.name);
 		info.name = strdup(info.name);
 	} else {
 		info.name = get_header_name(rom);
@@ -336,11 +422,18 @@
 		info.regions = get_header_regions(rom);
 	}
 	
-	tern_node *map = tern_find_prefix(entry, "map");
+	tern_node *map = tern_find_ptr(entry, "map");
 	if (map) {
-		uint32_t map_count = tern_count(map);
-		if (map_count) {
-			
+		info.map_chunks = tern_count(map);
+		if (info.map_chunks) {
+			info.map_chunks += base_chunks;
+			info.save_buffer = NULL;
+			info.save_size = 0;
+			info.map = malloc(sizeof(memmap_chunk) * info.map_chunks);
+			memset(info.map, 0, sizeof(memmap_chunk) * (info.map_chunks - base_chunks));
+			map_iter_state state = {&info, rom, entry, rom_size, 0};
+			tern_foreach(map, map_iter_fun, &state);
+			memcpy(info.map + state.index, base_map, sizeof(memmap_chunk) * base_chunks);
 		} else {
 			add_memmap_header(&info, rom, rom_size, base_map, base_chunks);
 		}
--- a/tern.c	Mon Jul 06 19:46:46 2015 -0700
+++ b/tern.c	Tue Jul 07 19:33:33 2015 -0700
@@ -107,7 +107,11 @@
 {
 	tern_val ret;
 	if (tern_find(head, key, &ret)) {
-		return ret.ptrval;
+		if (ret.intval & 1) {
+			return (void *)(ret.intval & ~1);
+		} else {
+			return ret.ptrval;
+		}
 	}
 	return def;
 }
@@ -193,7 +197,7 @@
 		tern_foreach_int(head->straight.next, fun, data, keybuf, pos+1);
 	}
 	if (head->right) {
-		tern_foreach_int(head->left, fun, data, keybuf, pos);
+		tern_foreach_int(head->right, fun, data, keybuf, pos);
 	}
 }
 
--- a/tern.h	Mon Jul 06 19:46:46 2015 -0700
+++ b/tern.h	Tue Jul 07 19:33:33 2015 -0700
@@ -39,6 +39,7 @@
 tern_node * tern_insert_ptr(tern_node * head, char * key, void * value);
 tern_node * tern_insert_node(tern_node *head, char *key, tern_node *value);
 uint32_t tern_count(tern_node *head);
+void tern_foreach(tern_node *head, iter_fun fun, void *data);
 char * tern_int_key(uint32_t key, char * buf);
 tern_node * tern_get_node(tern_val value);
 
--- a/util.c	Mon Jul 06 19:46:46 2015 -0700
+++ b/util.c	Tue Jul 07 19:33:33 2015 -0700
@@ -2,6 +2,7 @@
 #include <stdlib.h>
 #include <stdio.h>
 #include <ctype.h>
+#include <stdint.h>
 
 #include <sys/types.h>
 #include <sys/stat.h>
@@ -68,6 +69,16 @@
 	return text+1;
 }
 
+uint32_t nearest_pow2(uint32_t val)
+{
+	uint32_t ret = 1;
+	while (ret < val)
+	{
+		ret = ret << 1;
+	}
+	return ret;
+}
+
 static char * exe_str;
 
 void set_exe_str(char * str)
--- a/util.h	Mon Jul 06 19:46:46 2015 -0700
+++ b/util.h	Tue Jul 07 19:33:33 2015 -0700
@@ -15,6 +15,8 @@
 char * strip_ws(char * text);
 //Inserts a null after the first word, returns a pointer to the second word
 char * split_keyval(char * text);
+//Gets the smallest power of two that is >= a certain value, won't work for values > 0x80000000
+uint32_t nearest_pow2(uint32_t val);
 //Should be called by main with the value of argv[0] for use by get_exe_dir
 void set_exe_str(char * str);
 //Returns the directory the executable is in