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 }