Mercurial > repos > blastem
comparison xband.c @ 1228:2e6dcb5c11a2
WIP support for XBAND mapper hardware
author | Michael Pavone <pavone@retrodev.com> |
---|---|
date | Thu, 23 Feb 2017 00:08:37 -0800 |
parents | |
children | a8313793216a |
comparison
equal
deleted
inserted
replaced
1227:262c0ce8f586 | 1228:2e6dcb5c11a2 |
---|---|
1 #include <stdlib.h> | |
2 #include <stddef.h> | |
3 #include <string.h> | |
4 #include "romdb.h" | |
5 #include "genesis.h" | |
6 #include "tern.h" | |
7 #include "xband.h" | |
8 #include "util.h" | |
9 | |
10 #define BIT_ROM_HI 4 | |
11 | |
12 uint8_t xband_detect(uint8_t *rom, uint32_t rom_size) | |
13 { | |
14 //Internal ROM is 512KB, accept larger ones for overdumps and custom firmware | |
15 if (rom_size < (512*1024)) { | |
16 return 0; | |
17 } | |
18 | |
19 //ROM has no standard header, but does have a jump at $100 | |
20 if (rom[0x100] != 0x4E || rom[0x101] != 0xF9) { | |
21 return 0; | |
22 } | |
23 | |
24 //product ID is all NULL | |
25 for (int i = GAME_ID_OFF; i <= (GAME_ID_OFF + GAME_ID_LEN); i++) | |
26 { | |
27 if (rom[i]) { | |
28 return 0; | |
29 } | |
30 } | |
31 return 1; | |
32 } | |
33 | |
34 static xband *get_xband(genesis_context *gen) | |
35 { | |
36 if (!gen->extra) { | |
37 gen->extra = gen->m68k->options->gen.memmap[0].buffer; | |
38 gen->m68k->mem_pointers[2] = (uint16_t *)gen->save_storage; | |
39 } | |
40 return gen->extra; | |
41 } | |
42 | |
43 static void update_control(genesis_context *gen, uint8_t value) | |
44 { | |
45 xband *x = gen->extra; | |
46 if ((x->control ^ value) & BIT_ROM_HI) { | |
47 if (value & BIT_ROM_HI) { | |
48 gen->m68k->mem_pointers[0] = (uint16_t *)gen->save_storage; | |
49 gen->m68k->mem_pointers[1] = NULL; | |
50 gen->m68k->mem_pointers[2] = x->cart_space; | |
51 gen->m68k->mem_pointers[3] = x->cart_space - 0x100000; | |
52 } else { | |
53 gen->m68k->mem_pointers[0] = x->cart_space; | |
54 gen->m68k->mem_pointers[1] = x->cart_space; | |
55 gen->m68k->mem_pointers[2] = (uint16_t *)gen->save_storage; | |
56 gen->m68k->mem_pointers[3] = NULL; | |
57 } | |
58 m68k_invalidate_code_range(gen->m68k, 0, 0x3BC000); | |
59 } | |
60 x->control = value; | |
61 } | |
62 | |
63 static void *xband_write_b(uint32_t address, void *context, uint8_t value) | |
64 { | |
65 m68k_context *m68k = context; | |
66 genesis_context *gen = m68k->system; | |
67 xband *x = get_xband(gen); | |
68 if (address == 0x181) { | |
69 x->kill = value; | |
70 printf("Write to \"soft\" kill register %X\n", value); | |
71 } else if (address == 0x183) { | |
72 update_control(gen, value); | |
73 printf("Write to \"soft\" control register %X\n", value); | |
74 } else if ((x->control & BIT_ROM_HI && address < 0x200000) || (address >= 0x200000 && !(x->control & BIT_ROM_HI))) { | |
75 gen->save_storage[(address & 0xFFFF) ^ 1] = value; | |
76 m68k_handle_code_write(address, m68k); | |
77 //TODO: handle code at mirror addresses | |
78 } else { | |
79 printf("Unhandled write to cartridge area %X: %X\n", address, value); | |
80 } | |
81 return context; | |
82 } | |
83 | |
84 static void *xband_write_hi_b(uint32_t address, void *context, uint8_t value) | |
85 { | |
86 return xband_write_b(address | 0x200000, context, value); | |
87 } | |
88 | |
89 static void *xband_write_w(uint32_t address, void *context, uint16_t value) | |
90 { | |
91 m68k_context *m68k = context; | |
92 genesis_context *gen = m68k->system; | |
93 xband *x = get_xband(gen); | |
94 if (address == 0x180 || address == 0x182) { | |
95 return xband_write_b(address | 1, context, value); | |
96 } else if ((x->control & BIT_ROM_HI && address < 0x200000) || (address >= 0x200000 && !(x->control & BIT_ROM_HI))) { | |
97 gen->save_storage[address & 0xFFFE] = value; | |
98 gen->save_storage[(address & 0xFFFE) | 1] = value >> 8; | |
99 m68k_handle_code_write(address, m68k); | |
100 //TODO: handle code at mirror addresses | |
101 return context; | |
102 } | |
103 printf("Unhandled write to %X: %X\n", address, value); | |
104 return context; | |
105 } | |
106 | |
107 static void *xband_write_hi_w(uint32_t address, void *context, uint16_t value) | |
108 { | |
109 return xband_write_w(address | 0x200000, context, value); | |
110 } | |
111 | |
112 static uint16_t xband_read_w(uint32_t address, void *context) | |
113 { | |
114 m68k_context *m68k = context; | |
115 genesis_context *gen = m68k->system; | |
116 xband *x = get_xband(gen); | |
117 //TODO: actually do something intelligent here | |
118 return x->cart_space[address >> 1]; | |
119 } | |
120 | |
121 static uint16_t xband_read_hi_w(uint32_t address, void *context) | |
122 { | |
123 return xband_read_w(address | 0x200000, context); | |
124 } | |
125 | |
126 static uint8_t xband_read_b(uint32_t address, void *context) | |
127 { | |
128 uint16_t val = xband_read_w(address, context); | |
129 return address & 1 ? val : val >> 8; | |
130 } | |
131 | |
132 static uint8_t xband_read_hi_b(uint32_t address, void *context) | |
133 { | |
134 return xband_read_b(address | 0x200000, context); | |
135 } | |
136 | |
137 static void *xband_reg_write_b(uint32_t address, void *context, uint8_t value) | |
138 { | |
139 m68k_context *m68k = context; | |
140 genesis_context *gen = m68k->system; | |
141 if (!(address & 1)) { | |
142 printf("Ignoring write to even address %X: %X\n", address, value); | |
143 return context; | |
144 } | |
145 xband *x = get_xband(gen); | |
146 if (address < 0x3BFE00) { | |
147 uint32_t offset = (address - 0x3BC001) / 2; | |
148 if (offset < XBAND_REGS) { | |
149 x->regs[offset] = value; | |
150 printf("Write to register %X: %X\n", address, value); | |
151 } else { | |
152 printf("Unhandled register write %X: %X\n", address, value); | |
153 } | |
154 } else { | |
155 if (address == 0x3BFE01) { | |
156 x->kill = value; | |
157 printf("Write to kill register %X\n", value); | |
158 } else if (address == 0x3BFE03) { | |
159 update_control(gen, value); | |
160 printf("Write to control register %X\n", value); | |
161 } else { | |
162 printf("Unhandled register write %X: %X\n", address, value); | |
163 } | |
164 } | |
165 return context; | |
166 } | |
167 | |
168 static void *xband_reg_write_w(uint32_t address, void *context, uint16_t value) | |
169 { | |
170 return xband_reg_write_b(address | 1, context, value); | |
171 } | |
172 | |
173 static uint8_t xband_reg_read_b(uint32_t address, void *context) | |
174 { | |
175 m68k_context *m68k = context; | |
176 genesis_context *gen = m68k->system; | |
177 if (!(address & 1)) { | |
178 printf("Read from even address %X\n", address); | |
179 return gen->header.get_open_bus_value(&gen->header) >> 8; | |
180 } | |
181 xband *x = get_xband(gen); | |
182 if (address < 0x3BFE00) { | |
183 uint32_t offset = (address - 0x3BC001) / 2; | |
184 if (offset < XBAND_REGS) { | |
185 return x->regs[offset]; | |
186 } else { | |
187 printf("Unhandled register read from address %X\n", address); | |
188 return 0x5D; | |
189 } | |
190 } else { | |
191 if (address == 0x3BFE01) { | |
192 return x->kill; | |
193 } else if (address == 0x3BFE03) { | |
194 return x->control; | |
195 } else { | |
196 printf("Unhandled register read from address %X\n", address); | |
197 return 0x5D; | |
198 } | |
199 } | |
200 } | |
201 | |
202 static uint16_t xband_reg_read_w(uint32_t address, void *context) | |
203 { | |
204 m68k_context *m68k = context; | |
205 genesis_context *gen = m68k->system; | |
206 uint16_t value = xband_reg_read_b(address | 1, context); | |
207 value |= gen->header.get_open_bus_value(&gen->header) & 0xFF00; | |
208 return value; | |
209 } | |
210 | |
211 rom_info xband_configure_rom(tern_node *rom_db, void *rom, uint32_t rom_size, void *lock_on, uint32_t lock_on_size, memmap_chunk const *base_map, uint32_t base_chunks) | |
212 { | |
213 rom_info info; | |
214 if (lock_on && lock_on_size) { | |
215 rom_info lock_on_info = configure_rom(rom_db, lock_on, lock_on_size, NULL, 0, base_map, base_chunks); | |
216 info.name = alloc_concat("XBAND - ", lock_on_info.name); | |
217 info.regions = lock_on_info.regions; | |
218 //TODO: Move this to a shared function in romdbc.h | |
219 free(lock_on_info.name); | |
220 if (lock_on_info.save_type != SAVE_NONE) { | |
221 free(lock_on_info.save_buffer); | |
222 if (lock_on_info.save_type == SAVE_I2C) { | |
223 free(lock_on_info.eeprom_map); | |
224 } | |
225 } | |
226 free(lock_on_info.map); | |
227 free(lock_on_info.port1_override); | |
228 free(lock_on_info.port2_override); | |
229 free(lock_on_info.ext_override); | |
230 free(lock_on_info.mouse_mode); | |
231 } else { | |
232 info.name = strdup("XBAND"); | |
233 info.regions = REGION_J|REGION_U|REGION_E; | |
234 } | |
235 info.save_size = 64*1024; | |
236 info.save_buffer = malloc(info.save_size); | |
237 info.save_mask = info.save_size-1; | |
238 info.save_type = RAM_FLAG_BOTH; | |
239 info.port1_override = info.port2_override = info.ext_override = info.mouse_mode = NULL; | |
240 info.eeprom_map = NULL; | |
241 info.num_eeprom = 0; | |
242 xband *x = calloc(sizeof(xband), 1); | |
243 rom_size = nearest_pow2(rom_size); | |
244 for (int i = 0; (i + rom_size) <= sizeof(x->cart_space) / 2; i += rom_size) | |
245 { | |
246 memcpy(x->cart_space + i/2, rom, rom_size); | |
247 } | |
248 if (lock_on && lock_on_size >= 0x200) { | |
249 memcpy(x->cart_space + 0x80, ((uint16_t *)lock_on) + 0x80, 0x100); | |
250 } | |
251 byteswap_rom(0x400000, x->cart_space); | |
252 | |
253 info.map_chunks = base_chunks + 5; | |
254 info.map = calloc(sizeof(memmap_chunk), info.map_chunks); | |
255 info.map[0].mask = 0xFFFFFF; | |
256 info.map[0].aux_mask = 0xFFFFFF; | |
257 info.map[0].flags = MMAP_READ|MMAP_CODE|MMAP_PTR_IDX|MMAP_FUNC_NULL|MMAP_AUX_BUFF; | |
258 info.map[0].start = 0; | |
259 info.map[0].end = 0x10000; | |
260 info.map[0].ptr_index = 0; | |
261 info.map[0].buffer = x->cart_space; | |
262 info.map[0].write_16 = xband_write_w; | |
263 info.map[0].write_8 = xband_write_b; | |
264 info.map[0].read_16 = xband_read_w; | |
265 info.map[0].read_8 = xband_read_b; | |
266 info.map[1].mask = 0xFFFFFF; | |
267 info.map[1].aux_mask = 0xFFFFFF; | |
268 info.map[1].flags = MMAP_READ|MMAP_CODE|MMAP_PTR_IDX|MMAP_FUNC_NULL|MMAP_AUX_BUFF; | |
269 info.map[1].start = 0x10000; | |
270 info.map[1].end = 0x200000; | |
271 info.map[1].ptr_index = 1; | |
272 info.map[1].buffer = x->cart_space; | |
273 info.map[1].write_16 = xband_write_w; | |
274 info.map[1].write_8 = xband_write_b; | |
275 info.map[1].read_16 = xband_read_w; | |
276 info.map[1].read_8 = xband_read_b; | |
277 info.map[2].mask = 0xFFFF; | |
278 info.map[2].aux_mask = 0xFFFF; | |
279 info.map[2].flags = MMAP_READ|MMAP_CODE|MMAP_PTR_IDX|MMAP_FUNC_NULL; | |
280 info.map[2].start = 0x200000; | |
281 info.map[2].end = 0x210000; | |
282 info.map[2].ptr_index = 2; | |
283 info.map[2].buffer = NULL; | |
284 info.map[2].write_16 = xband_write_hi_w; | |
285 info.map[2].write_8 = xband_write_hi_b; | |
286 info.map[2].read_16 = xband_read_hi_w; | |
287 info.map[2].read_8 = xband_read_hi_b; | |
288 info.map[3].mask = 0xFFFFFF; | |
289 info.map[3].aux_mask = 0xFFFFFF; | |
290 info.map[3].flags = MMAP_READ|MMAP_CODE|MMAP_PTR_IDX|MMAP_FUNC_NULL; | |
291 info.map[3].start = 0x210000; | |
292 info.map[3].end = 0x3BC000; | |
293 info.map[3].ptr_index = 3; | |
294 info.map[3].buffer = NULL; | |
295 info.map[3].write_16 = xband_write_w; | |
296 info.map[3].write_8 = xband_write_b; | |
297 info.map[3].read_16 = xband_read_w; | |
298 info.map[3].read_8 = xband_read_b; | |
299 info.map[4].mask = 0xFFFFFF; | |
300 info.map[4].flags = MMAP_READ|MMAP_CODE|MMAP_PTR_IDX|MMAP_FUNC_NULL; | |
301 info.map[4].start = 0x3BC000; | |
302 info.map[4].end = 0x3C0000; | |
303 info.map[4].ptr_index = 4; | |
304 info.map[4].write_16 = xband_reg_write_w; | |
305 info.map[4].write_8 = xband_reg_write_b; | |
306 info.map[4].read_16 = xband_reg_read_w; | |
307 info.map[4].read_8 = xband_reg_read_b; | |
308 memcpy(info.map + 5, base_map, base_chunks * sizeof(memmap_chunk)); | |
309 | |
310 return info; | |
311 } |