Mercurial > repos > blastem
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 } |