Mercurial > repos > blastem
comparison romdb.c @ 766:1b2f8280ba81
WIP changes to support reading cart memory map from ROM DB
author | Michael Pavone <pavone@retrodev.com> |
---|---|
date | Sun, 05 Jul 2015 14:21:34 -0700 |
parents | dc54387ee1cd |
children | ea525f600b1d |
comparison
equal
deleted
inserted
replaced
765:dc54387ee1cd | 766:1b2f8280ba81 |
---|---|
1 #include <stdlib.h> | 1 #include <stdlib.h> |
2 #include <string.h> | 2 #include <string.h> |
3 #include "config.h" | 3 #include "config.h" |
4 #include "romdb.h" | 4 #include "romdb.h" |
5 #include "util.h" | 5 #include "util.h" |
6 #include "blastem.h" | |
6 | 7 |
7 #define TITLE_START 0x150 | 8 #define TITLE_START 0x150 |
8 #define TITLE_END (TITLE_START+48) | 9 #define TITLE_END (TITLE_START+48) |
9 #define GAME_ID_OFF 0x183 | 10 #define GAME_ID_OFF 0x183 |
10 #define GAME_ID_LEN 8 | 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 | |
11 #define REGION_START 0x1F0 | 17 #define REGION_START 0x1F0 |
18 | |
19 uint16_t read_sram_w(uint32_t address, m68k_context * context) | |
20 { | |
21 genesis_context * gen = context->system; | |
22 address &= gen->save_ram_mask; | |
23 switch(gen->save_flags) | |
24 { | |
25 case RAM_FLAG_BOTH: | |
26 return gen->save_ram[address] << 8 | gen->save_ram[address+1]; | |
27 case RAM_FLAG_EVEN: | |
28 return gen->save_ram[address >> 1] << 8 | 0xFF; | |
29 case RAM_FLAG_ODD: | |
30 return gen->save_ram[address >> 1] | 0xFF00; | |
31 } | |
32 return 0xFFFF;//We should never get here | |
33 } | |
34 | |
35 uint8_t read_sram_b(uint32_t address, m68k_context * context) | |
36 { | |
37 genesis_context * gen = context->system; | |
38 address &= gen->save_ram_mask; | |
39 switch(gen->save_flags) | |
40 { | |
41 case RAM_FLAG_BOTH: | |
42 return gen->save_ram[address]; | |
43 case RAM_FLAG_EVEN: | |
44 if (address & 1) { | |
45 return 0xFF; | |
46 } else { | |
47 return gen->save_ram[address >> 1]; | |
48 } | |
49 case RAM_FLAG_ODD: | |
50 if (address & 1) { | |
51 return gen->save_ram[address >> 1]; | |
52 } else { | |
53 return 0xFF; | |
54 } | |
55 } | |
56 return 0xFF;//We should never get here | |
57 } | |
58 | |
59 m68k_context * write_sram_area_w(uint32_t address, m68k_context * context, uint16_t value) | |
60 { | |
61 genesis_context * gen = context->system; | |
62 if ((gen->bank_regs[0] & 0x3) == 1) { | |
63 address &= gen->save_ram_mask; | |
64 switch(gen->save_flags) | |
65 { | |
66 case RAM_FLAG_BOTH: | |
67 gen->save_ram[address] = value >> 8; | |
68 gen->save_ram[address+1] = value; | |
69 break; | |
70 case RAM_FLAG_EVEN: | |
71 gen->save_ram[address >> 1] = value >> 8; | |
72 break; | |
73 case RAM_FLAG_ODD: | |
74 gen->save_ram[address >> 1] = value; | |
75 break; | |
76 } | |
77 } | |
78 return context; | |
79 } | |
80 | |
81 m68k_context * write_sram_area_b(uint32_t address, m68k_context * context, uint8_t value) | |
82 { | |
83 genesis_context * gen = context->system; | |
84 if ((gen->bank_regs[0] & 0x3) == 1) { | |
85 address &= gen->save_ram_mask; | |
86 switch(gen->save_flags) | |
87 { | |
88 case RAM_FLAG_BOTH: | |
89 gen->save_ram[address] = value; | |
90 break; | |
91 case RAM_FLAG_EVEN: | |
92 if (!(address & 1)) { | |
93 gen->save_ram[address >> 1] = value; | |
94 } | |
95 break; | |
96 case RAM_FLAG_ODD: | |
97 if (address & 1) { | |
98 gen->save_ram[address >> 1] = value; | |
99 } | |
100 break; | |
101 } | |
102 } | |
103 return context; | |
104 } | |
105 | |
106 m68k_context * write_bank_reg_w(uint32_t address, m68k_context * context, uint16_t value) | |
107 { | |
108 genesis_context * gen = context->system; | |
109 address &= 0xE; | |
110 address >>= 1; | |
111 gen->bank_regs[address] = value; | |
112 if (!address) { | |
113 if (value & 1) { | |
114 context->mem_pointers[2] = NULL; | |
115 } else { | |
116 context->mem_pointers[2] = cart + 0x200000/2; | |
117 } | |
118 } | |
119 return context; | |
120 } | |
121 | |
122 m68k_context * write_bank_reg_b(uint32_t address, m68k_context * context, uint8_t value) | |
123 { | |
124 if (address & 1) { | |
125 genesis_context * gen = context->system; | |
126 address &= 0xE; | |
127 address >>= 1; | |
128 gen->bank_regs[address] = value; | |
129 if (!address) { | |
130 if (value & 1) { | |
131 context->mem_pointers[2] = NULL; | |
132 } else { | |
133 context->mem_pointers[2] = cart + 0x200000/2; | |
134 } | |
135 } | |
136 } | |
137 return context; | |
138 } | |
12 | 139 |
13 tern_node *load_rom_db() | 140 tern_node *load_rom_db() |
14 { | 141 { |
15 char *exe_dir = get_exe_dir(); | 142 char *exe_dir = get_exe_dir(); |
16 if (!exe_dir) { | 143 if (!exe_dir) { |
75 regions |= translate_region_char(rom[REGION_START + i]); | 202 regions |= translate_region_char(rom[REGION_START + i]); |
76 } | 203 } |
77 return regions; | 204 return regions; |
78 } | 205 } |
79 | 206 |
80 | 207 uint32_t get_u32be(uint8_t *data) |
81 rom_info configure_rom_heuristics(uint8_t *rom) | 208 { |
209 return *data << 24 | data[1] << 16 | data[2] << 8 | data[3]; | |
210 } | |
211 | |
212 void add_memmap_header(rom_info *info, uint8_t *rom, uint32_t size, memmap_chunk const *base_map, int base_chunks) | |
213 { | |
214 if (rom[RAM_ID] == 'R' && rom[RAM_ID+1] == 'A') { | |
215 uint32_t rom_end = get_u32be(rom + ROM_END) + 1; | |
216 uint32_t ram_start = get_u32be(rom + RAM_START); | |
217 uint32_t ram_end = get_u32be(rom + RAM_END); | |
218 uint32_t ram_flags = info->save_type = rom[RAM_FLAGS] & RAM_FLAG_MASK; | |
219 ram_start &= 0xFFFFFE; | |
220 ram_end |= 1; | |
221 | |
222 info->map_chunks = base_chunks + (ram_start >= rom_end ? 2 : 3); | |
223 info->map = malloc(sizeof(memmap_chunk) * info->map_chunks); | |
224 memset(info->map, 0, sizeof(memmap_chunk)*2); | |
225 memcpy(info->map+2, base_map, sizeof(memmap_chunk) * base_chunks); | |
226 | |
227 if (ram_start >= rom_end) { | |
228 info->map[0].end = rom_end; | |
229 //TODO: ROM mirroring | |
230 info->map[0].mask = 0xFFFFFF; | |
231 info->map[0].flags = MMAP_READ; | |
232 info->map[0].buffer = rom; | |
233 | |
234 info->map[1].start = ram_start; | |
235 info->map[1].mask = ram_end - ram_start; | |
236 info->map[1].end = ram_end + 1; | |
237 info->map[1].flags = MMAP_READ | MMAP_WRITE; | |
238 uint32_t size = info->map[1].mask + 1; | |
239 if (ram_flags == RAM_FLAG_ODD) { | |
240 info->map[1].flags |= MMAP_ONLY_ODD; | |
241 size /= 2; | |
242 } else if (ram_flags == RAM_FLAG_EVEN) { | |
243 info->map[1].flags |= MMAP_ONLY_EVEN; | |
244 size /= 2; | |
245 } | |
246 info->map[1].buffer = malloc(size); | |
247 } else { | |
248 //Assume the standard Sega mapper | |
249 info->map[0].end = 0x200000; | |
250 info->map[0].mask = 0xFFFFFF; | |
251 info->map[0].flags = MMAP_READ; | |
252 info->map[0].buffer = rom; | |
253 | |
254 info->map[1].start = 0x200000; | |
255 info->map[1].end = 0x400000; | |
256 info->map[1].mask = 0x1FFFFF; | |
257 info->map[1].flags = MMAP_READ | MMAP_PTR_IDX | MMAP_FUNC_NULL; | |
258 info->map[1].ptr_index = 2; | |
259 info->map[1].read_16 = (read_16_fun)read_sram_w;//these will only be called when mem_pointers[2] == NULL | |
260 info->map[1].read_8 = (read_8_fun)read_sram_b; | |
261 info->map[1].write_16 = (write_16_fun)write_sram_area_w;//these will be called all writes to the area | |
262 info->map[1].write_8 = (write_8_fun)write_sram_area_b; | |
263 info->map[1].buffer = cart + 0x200000; | |
264 | |
265 memmap_chunk *last = info->map + info->map_chunks - 1; | |
266 memset(last, 0, sizeof(memmap_chunk)); | |
267 last->start = 0xA13000; | |
268 last->end = 0xA13100; | |
269 last->mask = 0xFF; | |
270 last->write_16 = (write_16_fun)write_bank_reg_w; | |
271 last->write_8 = (write_8_fun)write_bank_reg_b; | |
272 } | |
273 } else { | |
274 info->map_chunks = base_chunks + 1; | |
275 info->map = malloc(sizeof(memmap_chunk) * info->map_chunks); | |
276 memset(info->map, 0, sizeof(memmap_chunk)); | |
277 memcpy(info->map+1, base_map, sizeof(memmap_chunk) * base_chunks); | |
278 | |
279 info->map[0].end = 0x400000; | |
280 info->map[0].mask = 0xFFFFFF; | |
281 info->map[0].flags = MMAP_READ; | |
282 info->map[0].buffer = rom; | |
283 info->save_type = SAVE_NONE; | |
284 } | |
285 } | |
286 | |
287 rom_info configure_rom_heuristics(uint8_t *rom, uint32_t rom_size, memmap_chunk const *base_map, uint32_t base_chunks) | |
82 { | 288 { |
83 rom_info info; | 289 rom_info info; |
84 info.name = get_header_name(rom); | 290 info.name = get_header_name(rom); |
85 info.regions = get_header_regions(rom); | 291 info.regions = get_header_regions(rom); |
292 add_memmap_header(&info, rom, rom_size, base_map, base_chunks); | |
86 return info; | 293 return info; |
87 } | 294 } |
88 | 295 |
89 rom_info configure_rom(tern_node *rom_db, void *vrom) | 296 rom_info configure_rom(tern_node *rom_db, void *vrom, uint32_t rom_size, memmap_chunk const *base_map, uint32_t base_chunks) |
90 { | 297 { |
91 uint8_t product_id[GAME_ID_LEN+1]; | 298 uint8_t product_id[GAME_ID_LEN+1]; |
92 uint8_t *rom = vrom; | 299 uint8_t *rom = vrom; |
93 product_id[GAME_ID_LEN] = 0; | 300 product_id[GAME_ID_LEN] = 0; |
94 for (int i = 0; i < GAME_ID_LEN; i++) | 301 for (int i = 0; i < GAME_ID_LEN; i++) |
100 product_id[i] = rom[GAME_ID_OFF + i]; | 307 product_id[i] = rom[GAME_ID_OFF + i]; |
101 | 308 |
102 } | 309 } |
103 tern_node * entry = tern_find_prefix(rom_db, product_id); | 310 tern_node * entry = tern_find_prefix(rom_db, product_id); |
104 if (!entry) { | 311 if (!entry) { |
105 return configure_rom_heuristics(rom); | 312 return configure_rom_heuristics(rom, rom_size, base_map, base_chunks); |
106 } | 313 } |
107 rom_info info; | 314 rom_info info; |
108 info.name = tern_find_ptr(entry, "name"); | 315 info.name = tern_find_ptr(entry, "name"); |
109 if (info.name) { | 316 if (info.name) { |
110 info.name = strdup(info.name); | 317 info.name = strdup(info.name); |
121 } | 328 } |
122 } | 329 } |
123 if (!info.regions) { | 330 if (!info.regions) { |
124 info.regions = get_header_regions(rom); | 331 info.regions = get_header_regions(rom); |
125 } | 332 } |
333 | |
334 tern_node *map = tern_find_prefix(entry, "map"); | |
335 if (map) { | |
336 uint32_t map_count = tern_count(map); | |
337 if (map_count) { | |
338 | |
339 } else { | |
340 add_memmap_header(&info, rom, rom_size, base_map, base_chunks); | |
341 } | |
342 } else { | |
343 add_memmap_header(&info, rom, rom_size, base_map, base_chunks); | |
344 } | |
345 | |
126 return info; | 346 return info; |
127 } | 347 } |