comparison romdb.c @ 2320:8016dbb0fcde

Initial work on ROM DB support for SMS/GG games
author Michael Pavone <pavone@retrodev.com>
date Tue, 09 May 2023 09:03:37 -0700
parents fd68fe5f723e
children 2eda5f81f91e
comparison
equal deleted inserted replaced
2319:ab3d8759da08 2320:8016dbb0fcde
1134 info.mouse_mode = tern_find_ptr(entry, "mouse_mode"); 1134 info.mouse_mode = tern_find_ptr(entry, "mouse_mode");
1135 info.wants_cd = !strcmp(tern_find_ptr_default(entry, "wants_cd", "no"), "yes"); 1135 info.wants_cd = !strcmp(tern_find_ptr_default(entry, "wants_cd", "no"), "yes");
1136 1136
1137 return info; 1137 return info;
1138 } 1138 }
1139
1140 void *sms_sega_mapper_write(uint32_t location, void *vcontext, uint8_t value);
1141 void sms_memmap_heuristics(rom_info *info, memmap_chunk const *base_map, uint32_t num_base_chunks)
1142 {
1143 uint32_t num_chunks = num_base_chunks + (info->rom_size > 0xC000 ? 5 : 1);
1144 memmap_chunk *chunks = calloc(num_chunks, sizeof(memmap_chunk));
1145 info->map = chunks;
1146 info->map_chunks = num_chunks;
1147 if (info->rom_size > 0xC000) {
1148 //TODO: codemasters header
1149 info->mapper_type = MAPPER_SMS_SEGA;
1150 memcpy(chunks + 4, base_map, sizeof(memmap_chunk) * num_base_chunks);
1151 chunks[0].start = 0;
1152 chunks[0].end = 0x400;
1153 chunks[0].mask = 0xFFFF;
1154 chunks[0].flags = MMAP_READ;
1155 chunks[0].buffer = info->rom;
1156 chunks[1].start = 0x400;
1157 chunks[1].end = 0x4000;
1158 chunks[1].mask = 0xFFFF;
1159 chunks[1].ptr_index = 0;
1160 chunks[1].flags = MMAP_READ|MMAP_PTR_IDX|MMAP_CODE;
1161 chunks[2].start = 0x4000;
1162 chunks[2].end = 0x8000;
1163 chunks[2].mask = 0x3FFF;
1164 chunks[2].ptr_index = 1;
1165 chunks[2].flags = MMAP_READ|MMAP_PTR_IDX|MMAP_CODE;
1166 chunks[3].start = 0x8000;
1167 chunks[3].end = 0xC000;
1168 chunks[3].mask = 0x3FFF;
1169 chunks[3].ptr_index = 2;
1170 chunks[3].flags = MMAP_READ|MMAP_PTR_IDX|MMAP_CODE;
1171 chunks[5].start = 0xFFFC;
1172 chunks[5].end = 0x10000;
1173 chunks[5].mask = 3;
1174 chunks[5].flags = MMAP_READ;
1175 chunks[5].write_8 = sms_sega_mapper_write;
1176 if (chunks[4].end > 0xFFFC) {
1177 //mapper regs overlap RAM from base map
1178 chunks[4].end = 0xFFFC;
1179 }
1180 } else {
1181 info->mapper_type = MAPPER_NONE;
1182 memcpy(chunks + 1, base_map, sizeof(memmap_chunk) * num_base_chunks);
1183 chunks[0].start = 0;
1184 chunks[0].end = 0xC000;
1185 chunks[0].mask = nearest_pow2(info->rom_size)-1;
1186 chunks[0].flags = MMAP_READ;
1187 chunks[0].buffer = info->rom;
1188 }
1189 }
1190
1191 void configure_rom_sms_heuristics(rom_info *info, uint32_t header_offset, memmap_chunk const *base_map, uint32_t num_base_chunks)
1192 {
1193 sms_memmap_heuristics(info, base_map, num_base_chunks);
1194 }
1195
1196 uint8_t check_sms_sega_header(uint8_t *rom, char *product_code, uint32_t offset)
1197 {
1198 if (memcmp(rom + offset, "TMR SEGA", strlen("TMR SEGA"))) {
1199 return 0;
1200 }
1201 char *cur = product_code + 4;
1202 uint8_t begin = rom[offset + 0xE] >> 4;
1203 if (begin < 0xA) {
1204 *(cur++) = begin + '0';
1205 } else {
1206 *(cur++) = '1';
1207 *(cur++) = begin - 0xA + '0';
1208 }
1209 uint8_t *src = rom + offset + 0xD;
1210 for (int i = 0; i < 2; i++, src--)
1211 {
1212 *(cur++) = (*src >> 4) + '0';
1213 *(cur++) = (*src & 0xF) + '0';
1214 }
1215 *cur = 0;
1216 return 1;
1217 }
1218
1219 rom_info configure_rom_sms(tern_node *rom_db, uint8_t *rom, uint32_t rom_size, memmap_chunk const *base_chunks, uint32_t num_base_chunks)
1220 {
1221 uint32_t expanded_size = nearest_pow2(rom_size);
1222 if (expanded_size > rom_size) {
1223 //generally carts with odd-sized ROMs have 2 power of 2 sized ROMs with the larger one first
1224 //TODO: Handle cases in which the 2nd ROM/part is a maller power of 2 than just half the first one
1225 uint32_t mirror_start = expanded_size >> 1;
1226 uint32_t mirror_size = expanded_size >> 2;
1227 if (mirror_start + mirror_size >= rom_size) {
1228 memcpy(rom + mirror_start + mirror_size, rom + mirror_start, mirror_size);
1229 }
1230 }
1231 char product_code[] = "sms:000000";
1232 uint8_t found_header = 0;
1233 uint32_t offset = 0;
1234 if (rom_size >= 0x8000) {
1235 offset = 0x7FF0;
1236 found_header = check_sms_sega_header(rom, product_code, offset);
1237 }
1238 if (!found_header && rom_size >= 0x4000) {
1239 offset = 0x3FF0;
1240 found_header = check_sms_sega_header(rom, product_code, offset);
1241 }
1242 if (!found_header && rom_size >= 0x2000) {
1243 offset = 0x1FF0;
1244 found_header = check_sms_sega_header(rom, product_code, offset);
1245 }
1246 debug_message("Product Code: %s\n", product_code);
1247 uint8_t raw_hash[20];
1248 sha1(rom, rom_size, raw_hash);
1249 uint8_t hex_hash[41];
1250 bin_to_hex(hex_hash, raw_hash, 20);
1251 debug_message("SHA1: %s\n", hex_hash);
1252 tern_node * entry = tern_find_node(rom_db, hex_hash);
1253 if (!entry) {
1254 entry = tern_find_node(rom_db, product_code);
1255 }
1256 rom_info info = {0};
1257 info.rom_size = rom_size;
1258 info.rom = rom;
1259 if (!entry) {
1260 debug_message("Not found in ROM DB, examining header\n\n");
1261 configure_rom_sms_heuristics(&info, offset, base_chunks, num_base_chunks);
1262 return info;
1263 }
1264 char *dbreg = tern_find_ptr(entry, "regions");
1265 info.regions = 0;
1266 if (dbreg) {
1267 while (*dbreg != 0)
1268 {
1269 info.regions |= translate_region_char(*(dbreg++));
1270 }
1271 }
1272 //TODO: check for and handle map from db
1273 sms_memmap_heuristics(&info, base_chunks, num_base_chunks);
1274 return info;
1275 }