pavone@764
|
1 #include <stdlib.h>
|
pavone@764
|
2 #include <string.h>
|
pavone@764
|
3 #include "config.h"
|
pavone@764
|
4 #include "romdb.h"
|
pavone@764
|
5 #include "util.h"
|
pavone@766
|
6 #include "blastem.h"
|
pavone@866
|
7 #include "menu.h"
|
pavone@764
|
8
|
pavone@765
|
9 #define TITLE_START 0x150
|
pavone@765
|
10 #define TITLE_END (TITLE_START+48)
|
pavone@764
|
11 #define GAME_ID_OFF 0x183
|
pavone@764
|
12 #define GAME_ID_LEN 8
|
pavone@766
|
13 #define ROM_END 0x1A4
|
pavone@766
|
14 #define RAM_ID 0x1B0
|
pavone@766
|
15 #define RAM_FLAGS 0x1B2
|
pavone@766
|
16 #define RAM_START 0x1B4
|
pavone@766
|
17 #define RAM_END 0x1B8
|
pavone@765
|
18 #define REGION_START 0x1F0
|
pavone@764
|
19
|
pavone@770
|
20 enum {
|
pavone@770
|
21 I2C_IDLE,
|
pavone@770
|
22 I2C_START,
|
pavone@770
|
23 I2C_DEVICE_ACK,
|
pavone@770
|
24 I2C_ADDRESS_HI,
|
pavone@770
|
25 I2C_ADDRESS_HI_ACK,
|
pavone@770
|
26 I2C_ADDRESS,
|
pavone@770
|
27 I2C_ADDRESS_ACK,
|
pavone@770
|
28 I2C_READ,
|
pavone@770
|
29 I2C_READ_ACK,
|
pavone@770
|
30 I2C_WRITE,
|
pavone@770
|
31 I2C_WRITE_ACK
|
pavone@770
|
32 };
|
pavone@770
|
33
|
pavone@770
|
34 char * i2c_states[] = {
|
pavone@770
|
35 "idle",
|
pavone@770
|
36 "start",
|
pavone@770
|
37 "device ack",
|
pavone@770
|
38 "address hi",
|
pavone@770
|
39 "address hi ack",
|
pavone@770
|
40 "address",
|
pavone@770
|
41 "address ack",
|
pavone@770
|
42 "read",
|
pavone@770
|
43 "read_ack",
|
pavone@770
|
44 "write",
|
pavone@770
|
45 "write_ack"
|
pavone@770
|
46 };
|
pavone@770
|
47
|
pavone@770
|
48 void eeprom_init(eeprom_state *state, uint8_t *buffer, uint32_t size)
|
pavone@769
|
49 {
|
pavone@769
|
50 state->slave_sda = 1;
|
pavone@769
|
51 state->host_sda = state->scl = 0;
|
pavone@770
|
52 state->buffer = buffer;
|
pavone@770
|
53 state->size = size;
|
pavone@770
|
54 state->state = I2C_IDLE;
|
pavone@769
|
55 }
|
pavone@769
|
56
|
pavone@769
|
57 void set_host_sda(eeprom_state *state, uint8_t val)
|
pavone@769
|
58 {
|
pavone@769
|
59 if (state->scl) {
|
pavone@769
|
60 if (val & ~state->host_sda) {
|
pavone@770
|
61 //low to high, stop condition
|
pavone@770
|
62 state->state = I2C_IDLE;
|
pavone@770
|
63 state->slave_sda = 1;
|
pavone@769
|
64 } else if (~val & state->host_sda) {
|
pavone@770
|
65 //high to low, start condition
|
pavone@770
|
66 state->state = I2C_START;
|
pavone@770
|
67 state->slave_sda = 1;
|
pavone@770
|
68 state->counter = 8;
|
pavone@769
|
69 }
|
pavone@769
|
70 }
|
pavone@769
|
71 state->host_sda = val;
|
pavone@769
|
72 }
|
pavone@769
|
73
|
pavone@769
|
74 void set_scl(eeprom_state *state, uint8_t val)
|
pavone@769
|
75 {
|
pavone@769
|
76 if (val & ~state->scl) {
|
pavone@770
|
77 //low to high transition
|
pavone@770
|
78 switch (state->state)
|
pavone@770
|
79 {
|
pavone@770
|
80 case I2C_START:
|
pavone@770
|
81 case I2C_ADDRESS_HI:
|
pavone@770
|
82 case I2C_ADDRESS:
|
pavone@770
|
83 case I2C_WRITE:
|
pavone@772
|
84 state->latch = state->host_sda | state->latch << 1;
|
pavone@770
|
85 state->counter--;
|
pavone@770
|
86 if (!state->counter) {
|
pavone@770
|
87 switch (state->state & 0x7F)
|
pavone@770
|
88 {
|
pavone@770
|
89 case I2C_START:
|
pavone@770
|
90 state->state = I2C_DEVICE_ACK;
|
pavone@770
|
91 break;
|
pavone@770
|
92 case I2C_ADDRESS_HI:
|
pavone@770
|
93 state->address = state->latch << 8;
|
pavone@770
|
94 state->state = I2C_ADDRESS_HI_ACK;
|
pavone@770
|
95 break;
|
pavone@770
|
96 case I2C_ADDRESS:
|
pavone@770
|
97 state->address |= state->latch;
|
pavone@770
|
98 state->state = I2C_ADDRESS_ACK;
|
pavone@770
|
99 break;
|
pavone@770
|
100 case I2C_WRITE:
|
pavone@770
|
101 state->buffer[state->address] = state->latch;
|
pavone@770
|
102 state->state = I2C_WRITE_ACK;
|
pavone@770
|
103 break;
|
pavone@770
|
104 }
|
pavone@770
|
105 }
|
pavone@770
|
106 break;
|
pavone@770
|
107 case I2C_DEVICE_ACK:
|
pavone@770
|
108 if (state->latch & 1) {
|
pavone@770
|
109 state->state = I2C_READ;
|
pavone@770
|
110 state->counter = 8;
|
pavone@938
|
111 if (state->size < 256) {
|
pavone@938
|
112 state->address = state->latch >> 1;
|
pavone@938
|
113 }
|
pavone@770
|
114 state->latch = state->buffer[state->address];
|
pavone@770
|
115 } else {
|
pavone@770
|
116 if (state->size < 256) {
|
pavone@770
|
117 state->address = state->latch >> 1;
|
pavone@770
|
118 state->state = I2C_WRITE;
|
pavone@779
|
119 } else if (state->size < 4096) {
|
pavone@779
|
120 state->address = (state->latch & 0xE) << 7;
|
pavone@770
|
121 state->state = I2C_ADDRESS;
|
pavone@770
|
122 } else {
|
pavone@770
|
123 state->state = I2C_ADDRESS_HI;
|
pavone@770
|
124 }
|
pavone@770
|
125 state->counter = 8;
|
pavone@770
|
126 }
|
pavone@770
|
127 break;
|
pavone@770
|
128 case I2C_ADDRESS_HI_ACK:
|
pavone@770
|
129 state->state = I2C_ADDRESS;
|
pavone@772
|
130 state->counter = 8;
|
pavone@770
|
131 break;
|
pavone@770
|
132 case I2C_ADDRESS_ACK:
|
pavone@770
|
133 state->state = I2C_WRITE;
|
pavone@779
|
134 state->address &= state->size-1;
|
pavone@772
|
135 state->counter = 8;
|
pavone@770
|
136 break;
|
pavone@770
|
137 case I2C_READ:
|
pavone@770
|
138 state->counter--;
|
pavone@770
|
139 if (!state->counter) {
|
pavone@770
|
140 state->state = I2C_READ_ACK;
|
pavone@770
|
141 }
|
pavone@770
|
142 break;
|
pavone@770
|
143 case I2C_READ_ACK:
|
pavone@770
|
144 state->state = I2C_READ;
|
pavone@772
|
145 state->counter = 8;
|
pavone@779
|
146 state->address++;
|
pavone@779
|
147 //TODO: page mask
|
pavone@779
|
148 state->address &= state->size-1;
|
pavone@780
|
149 state->latch = state->buffer[state->address];
|
pavone@770
|
150 break;
|
pavone@770
|
151 case I2C_WRITE_ACK:
|
pavone@770
|
152 state->state = I2C_WRITE;
|
pavone@772
|
153 state->counter = 8;
|
pavone@779
|
154 state->address++;
|
pavone@779
|
155 //TODO: page mask
|
pavone@779
|
156 state->address &= state->size-1;
|
pavone@770
|
157 break;
|
pavone@770
|
158 }
|
pavone@770
|
159 } else if (~val & state->scl) {
|
pavone@770
|
160 //high to low transition
|
pavone@770
|
161 switch (state->state & 0x7F)
|
pavone@770
|
162 {
|
pavone@770
|
163 case I2C_DEVICE_ACK:
|
pavone@770
|
164 case I2C_ADDRESS_HI_ACK:
|
pavone@770
|
165 case I2C_ADDRESS_ACK:
|
pavone@770
|
166 case I2C_READ_ACK:
|
pavone@770
|
167 case I2C_WRITE_ACK:
|
pavone@770
|
168 state->slave_sda = 0;
|
pavone@770
|
169 break;
|
pavone@770
|
170 case I2C_READ:
|
pavone@770
|
171 state->slave_sda = state->latch >> 7;
|
pavone@770
|
172 state->latch = state->latch << 1;
|
pavone@770
|
173 break;
|
pavone@770
|
174 default:
|
pavone@770
|
175 state->slave_sda = 1;
|
pavone@770
|
176 break;
|
pavone@770
|
177 }
|
pavone@769
|
178 }
|
pavone@769
|
179 state->scl = val;
|
pavone@769
|
180 }
|
pavone@769
|
181
|
pavone@769
|
182 uint8_t get_sda(eeprom_state *state)
|
pavone@769
|
183 {
|
pavone@769
|
184 return state->host_sda & state->slave_sda;
|
pavone@769
|
185 }
|
pavone@769
|
186
|
pavone@766
|
187 uint16_t read_sram_w(uint32_t address, m68k_context * context)
|
pavone@766
|
188 {
|
pavone@766
|
189 genesis_context * gen = context->system;
|
pavone@766
|
190 address &= gen->save_ram_mask;
|
pavone@767
|
191 switch(gen->save_type)
|
pavone@766
|
192 {
|
pavone@766
|
193 case RAM_FLAG_BOTH:
|
pavone@767
|
194 return gen->save_storage[address] << 8 | gen->save_storage[address+1];
|
pavone@766
|
195 case RAM_FLAG_EVEN:
|
pavone@767
|
196 return gen->save_storage[address >> 1] << 8 | 0xFF;
|
pavone@766
|
197 case RAM_FLAG_ODD:
|
pavone@767
|
198 return gen->save_storage[address >> 1] | 0xFF00;
|
pavone@766
|
199 }
|
pavone@766
|
200 return 0xFFFF;//We should never get here
|
pavone@766
|
201 }
|
pavone@766
|
202
|
pavone@766
|
203 uint8_t read_sram_b(uint32_t address, m68k_context * context)
|
pavone@766
|
204 {
|
pavone@766
|
205 genesis_context * gen = context->system;
|
pavone@766
|
206 address &= gen->save_ram_mask;
|
pavone@767
|
207 switch(gen->save_type)
|
pavone@766
|
208 {
|
pavone@766
|
209 case RAM_FLAG_BOTH:
|
pavone@767
|
210 return gen->save_storage[address];
|
pavone@766
|
211 case RAM_FLAG_EVEN:
|
pavone@766
|
212 if (address & 1) {
|
pavone@766
|
213 return 0xFF;
|
pavone@766
|
214 } else {
|
pavone@767
|
215 return gen->save_storage[address >> 1];
|
pavone@766
|
216 }
|
pavone@766
|
217 case RAM_FLAG_ODD:
|
pavone@766
|
218 if (address & 1) {
|
pavone@767
|
219 return gen->save_storage[address >> 1];
|
pavone@766
|
220 } else {
|
pavone@766
|
221 return 0xFF;
|
pavone@766
|
222 }
|
pavone@766
|
223 }
|
pavone@766
|
224 return 0xFF;//We should never get here
|
pavone@766
|
225 }
|
pavone@766
|
226
|
pavone@766
|
227 m68k_context * write_sram_area_w(uint32_t address, m68k_context * context, uint16_t value)
|
pavone@766
|
228 {
|
pavone@766
|
229 genesis_context * gen = context->system;
|
pavone@766
|
230 if ((gen->bank_regs[0] & 0x3) == 1) {
|
pavone@766
|
231 address &= gen->save_ram_mask;
|
pavone@767
|
232 switch(gen->save_type)
|
pavone@766
|
233 {
|
pavone@766
|
234 case RAM_FLAG_BOTH:
|
pavone@767
|
235 gen->save_storage[address] = value >> 8;
|
pavone@767
|
236 gen->save_storage[address+1] = value;
|
pavone@766
|
237 break;
|
pavone@766
|
238 case RAM_FLAG_EVEN:
|
pavone@767
|
239 gen->save_storage[address >> 1] = value >> 8;
|
pavone@766
|
240 break;
|
pavone@766
|
241 case RAM_FLAG_ODD:
|
pavone@767
|
242 gen->save_storage[address >> 1] = value;
|
pavone@766
|
243 break;
|
pavone@766
|
244 }
|
pavone@766
|
245 }
|
pavone@766
|
246 return context;
|
pavone@766
|
247 }
|
pavone@766
|
248
|
pavone@766
|
249 m68k_context * write_sram_area_b(uint32_t address, m68k_context * context, uint8_t value)
|
pavone@766
|
250 {
|
pavone@766
|
251 genesis_context * gen = context->system;
|
pavone@766
|
252 if ((gen->bank_regs[0] & 0x3) == 1) {
|
pavone@766
|
253 address &= gen->save_ram_mask;
|
pavone@767
|
254 switch(gen->save_type)
|
pavone@766
|
255 {
|
pavone@766
|
256 case RAM_FLAG_BOTH:
|
pavone@767
|
257 gen->save_storage[address] = value;
|
pavone@766
|
258 break;
|
pavone@766
|
259 case RAM_FLAG_EVEN:
|
pavone@766
|
260 if (!(address & 1)) {
|
pavone@767
|
261 gen->save_storage[address >> 1] = value;
|
pavone@766
|
262 }
|
pavone@766
|
263 break;
|
pavone@766
|
264 case RAM_FLAG_ODD:
|
pavone@766
|
265 if (address & 1) {
|
pavone@767
|
266 gen->save_storage[address >> 1] = value;
|
pavone@766
|
267 }
|
pavone@766
|
268 break;
|
pavone@766
|
269 }
|
pavone@766
|
270 }
|
pavone@766
|
271 return context;
|
pavone@766
|
272 }
|
pavone@766
|
273
|
pavone@766
|
274 m68k_context * write_bank_reg_w(uint32_t address, m68k_context * context, uint16_t value)
|
pavone@766
|
275 {
|
pavone@766
|
276 genesis_context * gen = context->system;
|
pavone@766
|
277 address &= 0xE;
|
pavone@766
|
278 address >>= 1;
|
pavone@766
|
279 gen->bank_regs[address] = value;
|
pavone@766
|
280 if (!address) {
|
pavone@766
|
281 if (value & 1) {
|
pavone@776
|
282 for (int i = 0; i < 8; i++)
|
pavone@776
|
283 {
|
pavone@776
|
284 context->mem_pointers[gen->mapper_start_index + i] = NULL;
|
pavone@776
|
285 }
|
pavone@766
|
286 } else {
|
pavone@776
|
287 //Used for games that only use the mapper for SRAM
|
pavone@776
|
288 context->mem_pointers[gen->mapper_start_index] = cart + 0x200000/2;
|
pavone@776
|
289 //For games that need more than 4MB
|
pavone@776
|
290 for (int i = 1; i < 8; i++)
|
pavone@776
|
291 {
|
pavone@776
|
292 context->mem_pointers[gen->mapper_start_index + i] = cart + 0x40000*gen->bank_regs[i];
|
pavone@776
|
293 }
|
pavone@766
|
294 }
|
pavone@776
|
295 } else {
|
pavone@776
|
296 context->mem_pointers[gen->mapper_start_index + address] = cart + 0x40000*value;
|
pavone@766
|
297 }
|
pavone@766
|
298 return context;
|
pavone@766
|
299 }
|
pavone@766
|
300
|
pavone@766
|
301 m68k_context * write_bank_reg_b(uint32_t address, m68k_context * context, uint8_t value)
|
pavone@766
|
302 {
|
pavone@766
|
303 if (address & 1) {
|
pavone@776
|
304 write_bank_reg_w(address, context, value);
|
pavone@766
|
305 }
|
pavone@766
|
306 return context;
|
pavone@766
|
307 }
|
pavone@769
|
308 eeprom_map *find_eeprom_map(uint32_t address, genesis_context *gen)
|
pavone@769
|
309 {
|
pavone@769
|
310 for (int i = 0; i < gen->num_eeprom; i++)
|
pavone@769
|
311 {
|
pavone@769
|
312 if (address >= gen->eeprom_map[i].start && address <= gen->eeprom_map[i].end) {
|
pavone@769
|
313 return gen->eeprom_map + i;
|
pavone@769
|
314 }
|
pavone@769
|
315 }
|
pavone@769
|
316 return NULL;
|
pavone@769
|
317 }
|
pavone@769
|
318
|
pavone@769
|
319 void * write_eeprom_i2c_w(uint32_t address, void * context, uint16_t value)
|
pavone@769
|
320 {
|
pavone@769
|
321 genesis_context *gen = ((m68k_context *)context)->system;
|
pavone@769
|
322 eeprom_map *map = find_eeprom_map(address, gen);
|
pavone@769
|
323 if (!map) {
|
pavone@792
|
324 fatal_error("Could not find EEPROM map for address %X\n", address);
|
pavone@769
|
325 }
|
pavone@772
|
326 if (map->scl_mask) {
|
pavone@772
|
327 set_scl(&gen->eeprom, (value & map->scl_mask) != 0);
|
pavone@772
|
328 }
|
pavone@769
|
329 if (map->sda_write_mask) {
|
pavone@769
|
330 set_host_sda(&gen->eeprom, (value & map->sda_write_mask) != 0);
|
pavone@769
|
331 }
|
pavone@769
|
332 return context;
|
pavone@769
|
333 }
|
pavone@769
|
334
|
pavone@769
|
335 void * write_eeprom_i2c_b(uint32_t address, void * context, uint8_t value)
|
pavone@769
|
336 {
|
pavone@769
|
337 genesis_context *gen = ((m68k_context *)context)->system;
|
pavone@769
|
338 eeprom_map *map = find_eeprom_map(address, gen);
|
pavone@769
|
339 if (!map) {
|
pavone@792
|
340 fatal_error("Could not find EEPROM map for address %X\n", address);
|
pavone@769
|
341 }
|
pavone@866
|
342
|
pavone@769
|
343 uint16_t expanded, mask;
|
pavone@769
|
344 if (address & 1) {
|
pavone@769
|
345 expanded = value;
|
pavone@769
|
346 mask = 0xFF;
|
pavone@769
|
347 } else {
|
pavone@769
|
348 expanded = value << 8;
|
pavone@769
|
349 mask = 0xFF00;
|
pavone@769
|
350 }
|
pavone@772
|
351 if (map->scl_mask & mask) {
|
pavone@772
|
352 set_scl(&gen->eeprom, (expanded & map->scl_mask) != 0);
|
pavone@772
|
353 }
|
pavone@769
|
354 if (map->sda_write_mask & mask) {
|
pavone@769
|
355 set_host_sda(&gen->eeprom, (expanded & map->sda_write_mask) != 0);
|
pavone@769
|
356 }
|
pavone@769
|
357 return context;
|
pavone@769
|
358 }
|
pavone@769
|
359
|
pavone@769
|
360 uint16_t read_eeprom_i2c_w(uint32_t address, void * context)
|
pavone@769
|
361 {
|
pavone@769
|
362 genesis_context *gen = ((m68k_context *)context)->system;
|
pavone@769
|
363 eeprom_map *map = find_eeprom_map(address, gen);
|
pavone@769
|
364 if (!map) {
|
pavone@792
|
365 fatal_error("Could not find EEPROM map for address %X\n", address);
|
pavone@769
|
366 }
|
pavone@769
|
367 uint16_t ret = 0;
|
pavone@769
|
368 if (map->sda_read_bit < 16) {
|
pavone@769
|
369 ret = get_sda(&gen->eeprom) << map->sda_read_bit;
|
pavone@769
|
370 }
|
pavone@938
|
371 return ret;
|
pavone@769
|
372 }
|
pavone@769
|
373
|
pavone@769
|
374 uint8_t read_eeprom_i2c_b(uint32_t address, void * context)
|
pavone@769
|
375 {
|
pavone@769
|
376 genesis_context *gen = ((m68k_context *)context)->system;
|
pavone@769
|
377 eeprom_map *map = find_eeprom_map(address, gen);
|
pavone@769
|
378 if (!map) {
|
pavone@792
|
379 fatal_error("Could not find EEPROM map for address %X\n", address);
|
pavone@769
|
380 }
|
pavone@769
|
381 uint8_t bit = address & 1 ? map->sda_read_bit : map->sda_read_bit - 8;
|
pavone@769
|
382 uint8_t ret = 0;
|
pavone@769
|
383 if (bit < 8) {
|
pavone@769
|
384 ret = get_sda(&gen->eeprom) << bit;
|
pavone@769
|
385 }
|
pavone@769
|
386 return ret;
|
pavone@769
|
387 }
|
pavone@766
|
388
|
pavone@764
|
389 tern_node *load_rom_db()
|
pavone@764
|
390 {
|
pavone@875
|
391 tern_node *db = parse_bundled_config("rom.db");
|
pavone@764
|
392 if (!db) {
|
pavone@792
|
393 fatal_error("Failed to load ROM DB\n");
|
pavone@764
|
394 }
|
pavone@764
|
395 return db;
|
pavone@764
|
396 }
|
pavone@764
|
397
|
pavone@764
|
398 char *get_header_name(uint8_t *rom)
|
pavone@764
|
399 {
|
pavone@764
|
400 uint8_t *last = rom + TITLE_END - 1;
|
pavone@764
|
401 uint8_t *src = rom + TITLE_START;
|
pavone@866
|
402
|
pavone@764
|
403 while (last > src && (*last <= 0x20 || *last >= 0x80))
|
pavone@764
|
404 {
|
pavone@764
|
405 last--;
|
pavone@764
|
406 }
|
pavone@764
|
407 if (last == src) {
|
pavone@764
|
408 //TODO: Use other name field
|
pavone@764
|
409 return strdup("UNKNOWN");
|
pavone@764
|
410 } else {
|
pavone@764
|
411 last++;
|
pavone@764
|
412 char *ret = malloc(last - (rom + TITLE_START) + 1);
|
pavone@764
|
413 uint8_t *dst;
|
pavone@764
|
414 for (dst = ret; src < last; src++)
|
pavone@764
|
415 {
|
pavone@764
|
416 if (*src >= 0x20 && *src < 0x80) {
|
pavone@764
|
417 *(dst++) = *src;
|
pavone@764
|
418 }
|
pavone@764
|
419 }
|
pavone@764
|
420 *dst = 0;
|
pavone@764
|
421 return ret;
|
pavone@764
|
422 }
|
pavone@764
|
423 }
|
pavone@764
|
424
|
pavone@765
|
425 char *region_chars = "UB4JEA";
|
pavone@765
|
426 uint8_t region_bits[] = {REGION_U, REGION_U, REGION_U, REGION_J, REGION_E, REGION_E};
|
pavone@765
|
427
|
pavone@765
|
428 uint8_t translate_region_char(uint8_t c)
|
pavone@765
|
429 {
|
pavone@765
|
430 for (int i = 0; i < sizeof(region_bits); i++)
|
pavone@765
|
431 {
|
pavone@765
|
432 if (c == region_chars[i]) {
|
pavone@765
|
433 return region_bits[i];
|
pavone@765
|
434 }
|
pavone@765
|
435 }
|
pavone@765
|
436 return 0;
|
pavone@765
|
437 }
|
pavone@765
|
438
|
pavone@765
|
439 uint8_t get_header_regions(uint8_t *rom)
|
pavone@765
|
440 {
|
pavone@765
|
441 uint8_t regions = 0;
|
pavone@765
|
442 for (int i = 0; i < 3; i++)
|
pavone@765
|
443 {
|
pavone@765
|
444 regions |= translate_region_char(rom[REGION_START + i]);
|
pavone@765
|
445 }
|
pavone@765
|
446 return regions;
|
pavone@765
|
447 }
|
pavone@765
|
448
|
pavone@766
|
449 uint32_t get_u32be(uint8_t *data)
|
pavone@766
|
450 {
|
pavone@766
|
451 return *data << 24 | data[1] << 16 | data[2] << 8 | data[3];
|
pavone@766
|
452 }
|
pavone@765
|
453
|
pavone@768
|
454 uint32_t calc_mask(uint32_t src_size, uint32_t start, uint32_t end)
|
pavone@768
|
455 {
|
pavone@768
|
456 uint32_t map_size = end-start+1;
|
pavone@768
|
457 if (src_size < map_size) {
|
pavone@768
|
458 return nearest_pow2(src_size)-1;
|
pavone@768
|
459 } else if (!start) {
|
pavone@768
|
460 return 0xFFFFFF;
|
pavone@768
|
461 } else {
|
pavone@768
|
462 return nearest_pow2(map_size)-1;
|
pavone@768
|
463 }
|
pavone@768
|
464 }
|
pavone@768
|
465
|
pavone@766
|
466 void add_memmap_header(rom_info *info, uint8_t *rom, uint32_t size, memmap_chunk const *base_map, int base_chunks)
|
pavone@766
|
467 {
|
pavone@777
|
468 uint32_t rom_end = get_u32be(rom + ROM_END) + 1;
|
pavone@777
|
469 if (size > rom_end) {
|
pavone@777
|
470 rom_end = size;
|
pavone@777
|
471 } else if (rom_end > nearest_pow2(size)) {
|
pavone@777
|
472 rom_end = nearest_pow2(size);
|
pavone@777
|
473 }
|
pavone@766
|
474 if (rom[RAM_ID] == 'R' && rom[RAM_ID+1] == 'A') {
|
pavone@766
|
475 uint32_t ram_start = get_u32be(rom + RAM_START);
|
pavone@766
|
476 uint32_t ram_end = get_u32be(rom + RAM_END);
|
pavone@766
|
477 uint32_t ram_flags = info->save_type = rom[RAM_FLAGS] & RAM_FLAG_MASK;
|
pavone@766
|
478 ram_start &= 0xFFFFFE;
|
pavone@766
|
479 ram_end |= 1;
|
pavone@767
|
480 info->save_mask = ram_end - ram_start;
|
pavone@777
|
481 uint32_t save_size = info->save_mask + 1;
|
pavone@767
|
482 if (ram_flags != RAM_FLAG_BOTH) {
|
pavone@777
|
483 save_size /= 2;
|
pavone@767
|
484 }
|
pavone@777
|
485 info->save_size = save_size;
|
pavone@777
|
486 info->save_buffer = malloc(save_size);
|
pavone@866
|
487
|
pavone@766
|
488 info->map_chunks = base_chunks + (ram_start >= rom_end ? 2 : 3);
|
pavone@766
|
489 info->map = malloc(sizeof(memmap_chunk) * info->map_chunks);
|
pavone@766
|
490 memset(info->map, 0, sizeof(memmap_chunk)*2);
|
pavone@766
|
491 memcpy(info->map+2, base_map, sizeof(memmap_chunk) * base_chunks);
|
pavone@866
|
492
|
pavone@766
|
493 if (ram_start >= rom_end) {
|
pavone@825
|
494 info->map[0].end = rom_end < 0x400000 ? nearest_pow2(rom_end) - 1 : 0xFFFFFF;
|
pavone@766
|
495 //TODO: ROM mirroring
|
pavone@766
|
496 info->map[0].mask = 0xFFFFFF;
|
pavone@766
|
497 info->map[0].flags = MMAP_READ;
|
pavone@766
|
498 info->map[0].buffer = rom;
|
pavone@866
|
499
|
pavone@766
|
500 info->map[1].start = ram_start;
|
pavone@767
|
501 info->map[1].mask = info->save_mask;
|
pavone@766
|
502 info->map[1].end = ram_end + 1;
|
pavone@766
|
503 info->map[1].flags = MMAP_READ | MMAP_WRITE;
|
pavone@866
|
504
|
pavone@766
|
505 if (ram_flags == RAM_FLAG_ODD) {
|
pavone@766
|
506 info->map[1].flags |= MMAP_ONLY_ODD;
|
pavone@766
|
507 } else if (ram_flags == RAM_FLAG_EVEN) {
|
pavone@766
|
508 info->map[1].flags |= MMAP_ONLY_EVEN;
|
pavone@766
|
509 }
|
pavone@767
|
510 info->map[1].buffer = info->save_buffer;
|
pavone@766
|
511 } else {
|
pavone@766
|
512 //Assume the standard Sega mapper
|
pavone@766
|
513 info->map[0].end = 0x200000;
|
pavone@766
|
514 info->map[0].mask = 0xFFFFFF;
|
pavone@766
|
515 info->map[0].flags = MMAP_READ;
|
pavone@766
|
516 info->map[0].buffer = rom;
|
pavone@866
|
517
|
pavone@766
|
518 info->map[1].start = 0x200000;
|
pavone@766
|
519 info->map[1].end = 0x400000;
|
pavone@766
|
520 info->map[1].mask = 0x1FFFFF;
|
pavone@766
|
521 info->map[1].flags = MMAP_READ | MMAP_PTR_IDX | MMAP_FUNC_NULL;
|
pavone@776
|
522 info->map[1].ptr_index = info->mapper_start_index = 0;
|
pavone@766
|
523 info->map[1].read_16 = (read_16_fun)read_sram_w;//these will only be called when mem_pointers[2] == NULL
|
pavone@766
|
524 info->map[1].read_8 = (read_8_fun)read_sram_b;
|
pavone@766
|
525 info->map[1].write_16 = (write_16_fun)write_sram_area_w;//these will be called all writes to the area
|
pavone@766
|
526 info->map[1].write_8 = (write_8_fun)write_sram_area_b;
|
pavone@766
|
527 info->map[1].buffer = cart + 0x200000;
|
pavone@866
|
528
|
pavone@766
|
529 memmap_chunk *last = info->map + info->map_chunks - 1;
|
pavone@766
|
530 memset(last, 0, sizeof(memmap_chunk));
|
pavone@766
|
531 last->start = 0xA13000;
|
pavone@766
|
532 last->end = 0xA13100;
|
pavone@766
|
533 last->mask = 0xFF;
|
pavone@766
|
534 last->write_16 = (write_16_fun)write_bank_reg_w;
|
pavone@766
|
535 last->write_8 = (write_8_fun)write_bank_reg_b;
|
pavone@766
|
536 }
|
pavone@766
|
537 } else {
|
pavone@766
|
538 info->map_chunks = base_chunks + 1;
|
pavone@766
|
539 info->map = malloc(sizeof(memmap_chunk) * info->map_chunks);
|
pavone@766
|
540 memset(info->map, 0, sizeof(memmap_chunk));
|
pavone@766
|
541 memcpy(info->map+1, base_map, sizeof(memmap_chunk) * base_chunks);
|
pavone@866
|
542
|
pavone@825
|
543 info->map[0].end = rom_end > 0x400000 ? rom_end : 0x400000;
|
pavone@825
|
544 info->map[0].mask = rom_end < 0x400000 ? nearest_pow2(rom_end) - 1 : 0xFFFFFF;
|
pavone@766
|
545 info->map[0].flags = MMAP_READ;
|
pavone@766
|
546 info->map[0].buffer = rom;
|
pavone@766
|
547 info->save_type = SAVE_NONE;
|
pavone@766
|
548 }
|
pavone@766
|
549 }
|
pavone@766
|
550
|
pavone@766
|
551 rom_info configure_rom_heuristics(uint8_t *rom, uint32_t rom_size, memmap_chunk const *base_map, uint32_t base_chunks)
|
pavone@764
|
552 {
|
pavone@764
|
553 rom_info info;
|
pavone@764
|
554 info.name = get_header_name(rom);
|
pavone@765
|
555 info.regions = get_header_regions(rom);
|
pavone@766
|
556 add_memmap_header(&info, rom, rom_size, base_map, base_chunks);
|
pavone@915
|
557 info.port1_override = info.port2_override = info.ext_override = info.mouse_mode = NULL;
|
pavone@765
|
558 return info;
|
pavone@764
|
559 }
|
pavone@764
|
560
|
pavone@768
|
561 typedef struct {
|
pavone@768
|
562 rom_info *info;
|
pavone@768
|
563 uint8_t *rom;
|
pavone@768
|
564 tern_node *root;
|
pavone@768
|
565 uint32_t rom_size;
|
pavone@768
|
566 int index;
|
pavone@769
|
567 int num_els;
|
pavone@776
|
568 uint16_t ptr_index;
|
pavone@768
|
569 } map_iter_state;
|
pavone@768
|
570
|
pavone@769
|
571 void eeprom_read_fun(char *key, tern_val val, void *data)
|
pavone@769
|
572 {
|
pavone@769
|
573 int bit = atoi(key);
|
pavone@769
|
574 if (bit < 0 || bit > 15) {
|
pavone@769
|
575 fprintf(stderr, "bit %s is out of range", key);
|
pavone@769
|
576 return;
|
pavone@769
|
577 }
|
pavone@769
|
578 char *pin = val.ptrval;
|
pavone@769
|
579 if (strcmp(pin, "sda")) {
|
pavone@769
|
580 fprintf(stderr, "bit %s is connected to unrecognized read pin %s", key, pin);
|
pavone@769
|
581 return;
|
pavone@769
|
582 }
|
pavone@769
|
583 eeprom_map *map = data;
|
pavone@769
|
584 map->sda_read_bit = bit;
|
pavone@769
|
585 }
|
pavone@769
|
586
|
pavone@769
|
587 void eeprom_write_fun(char *key, tern_val val, void *data)
|
pavone@769
|
588 {
|
pavone@769
|
589 int bit = atoi(key);
|
pavone@769
|
590 if (bit < 0 || bit > 15) {
|
pavone@769
|
591 fprintf(stderr, "bit %s is out of range", key);
|
pavone@769
|
592 return;
|
pavone@769
|
593 }
|
pavone@769
|
594 char *pin = val.ptrval;
|
pavone@769
|
595 eeprom_map *map = data;
|
pavone@769
|
596 if (!strcmp(pin, "sda")) {
|
pavone@769
|
597 map->sda_write_mask = 1 << bit;
|
pavone@769
|
598 return;
|
pavone@769
|
599 }
|
pavone@769
|
600 if (!strcmp(pin, "scl")) {
|
pavone@769
|
601 map->scl_mask = 1 << bit;
|
pavone@769
|
602 return;
|
pavone@769
|
603 }
|
pavone@769
|
604 fprintf(stderr, "bit %s is connected to unrecognized write pin %s", key, pin);
|
pavone@769
|
605 }
|
pavone@769
|
606
|
pavone@774
|
607 void process_sram_def(char *key, map_iter_state *state)
|
pavone@774
|
608 {
|
pavone@774
|
609 if (!state->info->save_size) {
|
pavone@774
|
610 char * size = tern_find_path(state->root, "SRAM\0size\0").ptrval;
|
pavone@774
|
611 if (!size) {
|
pavone@792
|
612 fatal_error("ROM DB map entry %d with address %s has device type SRAM, but the SRAM size is not defined\n", state->index, key);
|
pavone@774
|
613 }
|
pavone@774
|
614 state->info->save_size = atoi(size);
|
pavone@774
|
615 if (!state->info->save_size) {
|
pavone@792
|
616 fatal_error("SRAM size %s is invalid\n", size);
|
pavone@774
|
617 }
|
pavone@775
|
618 state->info->save_mask = nearest_pow2(state->info->save_size)-1;
|
pavone@774
|
619 state->info->save_buffer = malloc(state->info->save_size);
|
pavone@774
|
620 memset(state->info->save_buffer, 0, state->info->save_size);
|
pavone@774
|
621 char *bus = tern_find_path(state->root, "SRAM\0bus\0").ptrval;
|
pavone@774
|
622 if (!strcmp(bus, "odd")) {
|
pavone@774
|
623 state->info->save_type = RAM_FLAG_ODD;
|
pavone@774
|
624 } else if(!strcmp(bus, "even")) {
|
pavone@774
|
625 state->info->save_type = RAM_FLAG_EVEN;
|
pavone@774
|
626 } else {
|
pavone@774
|
627 state->info->save_type = RAM_FLAG_BOTH;
|
pavone@774
|
628 }
|
pavone@774
|
629 }
|
pavone@774
|
630 }
|
pavone@774
|
631
|
pavone@774
|
632 void process_eeprom_def(char * key, map_iter_state *state)
|
pavone@774
|
633 {
|
pavone@774
|
634 if (!state->info->save_size) {
|
pavone@774
|
635 char * size = tern_find_path(state->root, "EEPROM\0size\0").ptrval;
|
pavone@774
|
636 if (!size) {
|
pavone@792
|
637 fatal_error("ROM DB map entry %d with address %s has device type EEPROM, but the EEPROM size is not defined\n", state->index, key);
|
pavone@774
|
638 }
|
pavone@774
|
639 state->info->save_size = atoi(size);
|
pavone@774
|
640 if (!state->info->save_size) {
|
pavone@792
|
641 fatal_error("EEPROM size %s is invalid\n", size);
|
pavone@774
|
642 }
|
pavone@774
|
643 char *etype = tern_find_path(state->root, "EEPROM\0type\0").ptrval;
|
pavone@774
|
644 if (!etype) {
|
pavone@774
|
645 etype = "i2c";
|
pavone@774
|
646 }
|
pavone@774
|
647 if (!strcmp(etype, "i2c")) {
|
pavone@774
|
648 state->info->save_type = SAVE_I2C;
|
pavone@774
|
649 } else {
|
pavone@792
|
650 fatal_error("EEPROM type %s is invalid\n", etype);
|
pavone@774
|
651 }
|
pavone@774
|
652 state->info->save_buffer = malloc(state->info->save_size);
|
pavone@774
|
653 memset(state->info->save_buffer, 0xFF, state->info->save_size);
|
pavone@774
|
654 state->info->eeprom_map = malloc(sizeof(eeprom_map) * state->num_els);
|
pavone@774
|
655 memset(state->info->eeprom_map, 0, sizeof(eeprom_map) * state->num_els);
|
pavone@774
|
656 }
|
pavone@774
|
657 }
|
pavone@774
|
658
|
pavone@774
|
659 void add_eeprom_map(tern_node *node, uint32_t start, uint32_t end, map_iter_state *state)
|
pavone@774
|
660 {
|
pavone@774
|
661 eeprom_map *eep_map = state->info->eeprom_map + state->info->num_eeprom;
|
pavone@774
|
662 eep_map->start = start;
|
pavone@774
|
663 eep_map->end = end;
|
pavone@774
|
664 eep_map->sda_read_bit = 0xFF;
|
pavone@774
|
665 tern_node * bits_read = tern_find_ptr(node, "bits_read");
|
pavone@774
|
666 if (bits_read) {
|
pavone@774
|
667 tern_foreach(bits_read, eeprom_read_fun, eep_map);
|
pavone@774
|
668 }
|
pavone@774
|
669 tern_node * bits_write = tern_find_ptr(node, "bits_write");
|
pavone@774
|
670 if (bits_write) {
|
pavone@774
|
671 tern_foreach(bits_write, eeprom_write_fun, eep_map);
|
pavone@774
|
672 }
|
pavone@774
|
673 printf("EEPROM address %X: sda read: %X, sda write: %X, scl: %X\n", start, eep_map->sda_read_bit, eep_map->sda_write_mask, eep_map->scl_mask);
|
pavone@774
|
674 state->info->num_eeprom++;
|
pavone@774
|
675 }
|
pavone@774
|
676
|
pavone@768
|
677 void map_iter_fun(char *key, tern_val val, void *data)
|
pavone@768
|
678 {
|
pavone@768
|
679 map_iter_state *state = data;
|
pavone@768
|
680 tern_node *node = tern_get_node(val);
|
pavone@768
|
681 if (!node) {
|
pavone@792
|
682 fatal_error("ROM DB map entry %d with address %s is not a node\n", state->index, key);
|
pavone@768
|
683 }
|
pavone@768
|
684 uint32_t start = strtol(key, NULL, 16);
|
pavone@768
|
685 uint32_t end = strtol(tern_find_ptr_default(node, "last", "0"), NULL, 16);
|
pavone@768
|
686 if (!end || end < start) {
|
pavone@792
|
687 fatal_error("'last' value is missing or invalid for ROM DB map entry %d with address %s\n", state->index, key);
|
pavone@768
|
688 }
|
pavone@768
|
689 char * dtype = tern_find_ptr_default(node, "device", "ROM");
|
pavone@774
|
690 uint32_t offset = strtol(tern_find_ptr_default(node, "offset", "0"), NULL, 16);
|
pavone@768
|
691 memmap_chunk *map = state->info->map + state->index;
|
pavone@768
|
692 map->start = start;
|
pavone@774
|
693 map->end = end + 1;
|
pavone@768
|
694 if (!strcmp(dtype, "ROM")) {
|
pavone@768
|
695 map->buffer = state->rom + offset;
|
pavone@768
|
696 map->flags = MMAP_READ;
|
pavone@774
|
697 map->mask = calc_mask(state->rom_size - offset, start, end);
|
pavone@768
|
698 } else if (!strcmp(dtype, "EEPROM")) {
|
pavone@774
|
699 process_eeprom_def(key, state);
|
pavone@774
|
700 add_eeprom_map(node, start, end, state);
|
pavone@866
|
701
|
pavone@769
|
702 map->write_16 = write_eeprom_i2c_w;
|
pavone@769
|
703 map->write_8 = write_eeprom_i2c_b;
|
pavone@769
|
704 map->read_16 = read_eeprom_i2c_w;
|
pavone@769
|
705 map->read_8 = read_eeprom_i2c_b;
|
pavone@769
|
706 map->mask = 0xFFFFFF;
|
pavone@768
|
707 } else if (!strcmp(dtype, "SRAM")) {
|
pavone@774
|
708 process_sram_def(key, state);
|
pavone@768
|
709 map->buffer = state->info->save_buffer + offset;
|
pavone@768
|
710 map->flags = MMAP_READ | MMAP_WRITE;
|
pavone@768
|
711 if (state->info->save_type == RAM_FLAG_ODD) {
|
pavone@768
|
712 map->flags |= MMAP_ONLY_ODD;
|
pavone@768
|
713 } else if(state->info->save_type == RAM_FLAG_EVEN) {
|
pavone@768
|
714 map->flags |= MMAP_ONLY_EVEN;
|
pavone@768
|
715 }
|
pavone@768
|
716 map->mask = calc_mask(state->info->save_size, start, end);
|
pavone@866
|
717 } else if (!strcmp(dtype, "RAM")) {
|
pavone@866
|
718 uint32_t size = strtol(tern_find_ptr_default(node, "size", "0"), NULL, 16);
|
pavone@866
|
719 if (!size || size > map->end - map->start) {
|
pavone@866
|
720 size = map->end - map->start;
|
pavone@866
|
721 }
|
pavone@866
|
722 map->buffer = malloc(size);
|
pavone@866
|
723 map->mask = calc_mask(size, start, end);
|
pavone@866
|
724 map->flags = MMAP_READ | MMAP_WRITE;
|
pavone@866
|
725 char *bus = tern_find_ptr_default(node, "bus", "both");
|
pavone@866
|
726 if (!strcmp(dtype, "odd")) {
|
pavone@866
|
727 map->flags |= MMAP_ONLY_ODD;
|
pavone@866
|
728 } else if (!strcmp(dtype, "even")) {
|
pavone@866
|
729 map->flags |= MMAP_ONLY_EVEN;
|
pavone@866
|
730 } else {
|
pavone@866
|
731 map->flags |= MMAP_CODE;
|
pavone@866
|
732 }
|
pavone@774
|
733 } else if (!strcmp(dtype, "Sega mapper")) {
|
pavone@776
|
734 state->info->mapper_start_index = state->ptr_index++;
|
pavone@776
|
735 state->info->map_chunks+=7;
|
pavone@776
|
736 state->info->map = realloc(state->info->map, sizeof(memmap_chunk) * state->info->map_chunks);
|
pavone@776
|
737 memset(state->info->map + state->info->map_chunks - 7, 0, sizeof(memmap_chunk) * 7);
|
pavone@776
|
738 map = state->info->map + state->index;
|
pavone@774
|
739 char *save_device = tern_find_path(node, "save\0device\0").ptrval;
|
pavone@776
|
740 if (save_device && !strcmp(save_device, "EEPROM")) {
|
pavone@774
|
741 process_eeprom_def(key, state);
|
pavone@774
|
742 add_eeprom_map(node, start & map->mask, end & map->mask, state);
|
pavone@774
|
743 }
|
pavone@776
|
744 for (int i = 0; i < 7; i++, state->index++, map++)
|
pavone@776
|
745 {
|
pavone@776
|
746 map->start = start + i * 0x80000;
|
pavone@776
|
747 map->end = start + (i + 1) * 0x80000;
|
pavone@776
|
748 map->mask = 0x7FFFF;
|
pavone@776
|
749 map->buffer = state->rom + offset + i * 0x80000;
|
pavone@776
|
750 map->ptr_index = state->ptr_index++;
|
pavone@776
|
751 if (i < 3 || !save_device) {
|
pavone@776
|
752 map->flags = MMAP_READ | MMAP_PTR_IDX;
|
pavone@776
|
753 } else {
|
pavone@776
|
754 map->flags = MMAP_READ | MMAP_PTR_IDX | MMAP_FUNC_NULL;
|
pavone@776
|
755 if (!strcmp(save_device, "SRAM")) {
|
pavone@776
|
756 process_sram_def(key, state);
|
pavone@776
|
757 map->read_16 = (read_16_fun)read_sram_w;//these will only be called when mem_pointers[2] == NULL
|
pavone@776
|
758 map->read_8 = (read_8_fun)read_sram_b;
|
pavone@776
|
759 map->write_16 = (write_16_fun)write_sram_area_w;//these will be called all writes to the area
|
pavone@776
|
760 map->write_8 = (write_8_fun)write_sram_area_b;
|
pavone@776
|
761 } else if (!strcmp(save_device, "EEPROM")) {
|
pavone@776
|
762 map->write_16 = write_eeprom_i2c_w;
|
pavone@776
|
763 map->write_8 = write_eeprom_i2c_b;
|
pavone@776
|
764 map->read_16 = read_eeprom_i2c_w;
|
pavone@776
|
765 map->read_8 = read_eeprom_i2c_b;
|
pavone@776
|
766 }
|
pavone@776
|
767 }
|
pavone@776
|
768 }
|
pavone@774
|
769 map->start = 0xA13000;
|
pavone@774
|
770 map->end = 0xA13100;
|
pavone@774
|
771 map->mask = 0xFF;
|
pavone@774
|
772 map->write_16 = (write_16_fun)write_bank_reg_w;
|
pavone@774
|
773 map->write_8 = (write_8_fun)write_bank_reg_b;
|
pavone@866
|
774 } else if (!strcmp(dtype, "MENU")) {
|
pavone@866
|
775 //fake hardware for supporting menu
|
pavone@866
|
776 map->buffer = NULL;
|
pavone@866
|
777 map->mask = 0xFF;
|
pavone@866
|
778 map->write_16 = menu_write_w;
|
pavone@866
|
779 map->read_16 = menu_read_w;
|
pavone@768
|
780 } else {
|
pavone@792
|
781 fatal_error("Invalid device type for ROM DB map entry %d with address %s\n", state->index, key);
|
pavone@768
|
782 }
|
pavone@768
|
783 state->index++;
|
pavone@768
|
784 }
|
pavone@768
|
785
|
pavone@766
|
786 rom_info configure_rom(tern_node *rom_db, void *vrom, uint32_t rom_size, memmap_chunk const *base_map, uint32_t base_chunks)
|
pavone@764
|
787 {
|
pavone@764
|
788 uint8_t product_id[GAME_ID_LEN+1];
|
pavone@764
|
789 uint8_t *rom = vrom;
|
pavone@764
|
790 product_id[GAME_ID_LEN] = 0;
|
pavone@764
|
791 for (int i = 0; i < GAME_ID_LEN; i++)
|
pavone@764
|
792 {
|
pavone@764
|
793 if (rom[GAME_ID_OFF + i] <= ' ') {
|
pavone@764
|
794 product_id[i] = 0;
|
pavone@764
|
795 break;
|
pavone@764
|
796 }
|
pavone@764
|
797 product_id[i] = rom[GAME_ID_OFF + i];
|
pavone@866
|
798
|
pavone@764
|
799 }
|
pavone@768
|
800 printf("Product ID: %s\n", product_id);
|
pavone@768
|
801 tern_node * entry = tern_find_ptr(rom_db, product_id);
|
pavone@764
|
802 if (!entry) {
|
pavone@768
|
803 puts("Not found in ROM DB, examining header\n");
|
pavone@766
|
804 return configure_rom_heuristics(rom, rom_size, base_map, base_chunks);
|
pavone@764
|
805 }
|
pavone@764
|
806 rom_info info;
|
pavone@765
|
807 info.name = tern_find_ptr(entry, "name");
|
pavone@765
|
808 if (info.name) {
|
pavone@768
|
809 printf("Found name: %s\n", info.name);
|
pavone@765
|
810 info.name = strdup(info.name);
|
pavone@765
|
811 } else {
|
pavone@765
|
812 info.name = get_header_name(rom);
|
pavone@765
|
813 }
|
pavone@866
|
814
|
pavone@765
|
815 char *dbreg = tern_find_ptr(entry, "regions");
|
pavone@765
|
816 info.regions = 0;
|
pavone@765
|
817 if (dbreg) {
|
pavone@765
|
818 while (*dbreg != 0)
|
pavone@765
|
819 {
|
pavone@765
|
820 info.regions |= translate_region_char(*(dbreg++));
|
pavone@765
|
821 }
|
pavone@765
|
822 }
|
pavone@765
|
823 if (!info.regions) {
|
pavone@765
|
824 info.regions = get_header_regions(rom);
|
pavone@765
|
825 }
|
pavone@866
|
826
|
pavone@768
|
827 tern_node *map = tern_find_ptr(entry, "map");
|
pavone@766
|
828 if (map) {
|
pavone@774
|
829 info.save_type = SAVE_NONE;
|
pavone@768
|
830 info.map_chunks = tern_count(map);
|
pavone@768
|
831 if (info.map_chunks) {
|
pavone@768
|
832 info.map_chunks += base_chunks;
|
pavone@768
|
833 info.save_buffer = NULL;
|
pavone@768
|
834 info.save_size = 0;
|
pavone@768
|
835 info.map = malloc(sizeof(memmap_chunk) * info.map_chunks);
|
pavone@769
|
836 info.eeprom_map = NULL;
|
pavone@769
|
837 info.num_eeprom = 0;
|
pavone@774
|
838 memset(info.map, 0, sizeof(memmap_chunk) * info.map_chunks);
|
pavone@776
|
839 map_iter_state state = {&info, rom, entry, rom_size, 0, info.map_chunks - base_chunks, 0};
|
pavone@768
|
840 tern_foreach(map, map_iter_fun, &state);
|
pavone@768
|
841 memcpy(info.map + state.index, base_map, sizeof(memmap_chunk) * base_chunks);
|
pavone@766
|
842 } else {
|
pavone@766
|
843 add_memmap_header(&info, rom, rom_size, base_map, base_chunks);
|
pavone@766
|
844 }
|
pavone@766
|
845 } else {
|
pavone@766
|
846 add_memmap_header(&info, rom, rom_size, base_map, base_chunks);
|
pavone@766
|
847 }
|
pavone@866
|
848
|
pavone@913
|
849 tern_node *device_overrides = tern_find_ptr(entry, "device_overrides");
|
pavone@913
|
850 if (device_overrides) {
|
pavone@913
|
851 info.port1_override = tern_find_ptr(device_overrides, "1");
|
pavone@913
|
852 info.port2_override = tern_find_ptr(device_overrides, "2");
|
pavone@913
|
853 info.ext_override = tern_find_ptr(device_overrides, "ext");
|
pavone@913
|
854 } else {
|
pavone@913
|
855 info.port1_override = info.port2_override = info.ext_override = NULL;
|
pavone@913
|
856 }
|
pavone@915
|
857 info.mouse_mode = tern_find_ptr(entry, "mouse_mode");
|
pavone@913
|
858
|
pavone@764
|
859 return info;
|
pavone@765
|
860 }
|