a12b1b29 |
1 | /* |
000f5335 |
2 | * Support for a few cart mappers and some protection. |
30f0fdd4 |
3 | * (C) notaz, 2008-2011 |
99bd61f8 |
4 | * (C) irixxxx, 2021-2024 |
65ca3034 |
5 | * |
cff531af |
6 | * This work is licensed under the terms of MAME license. |
7 | * See COPYING file in the top-level directory. |
a12b1b29 |
8 | */ |
9 | |
efcba75f |
10 | #include "../pico_int.h" |
45f2f245 |
11 | #include "../memory.h" |
6a47c2d4 |
12 | #include "eeprom_spi.h" |
757f8dae |
13 | |
a12b1b29 |
14 | |
f5080654 |
15 | static int have_bank(u32 base) |
16 | { |
17 | // the loader allocs in 512K quantities |
18 | if (base >= Pico.romsize) { |
19 | elprintf(EL_ANOMALY|EL_STATUS, "carthw: missing bank @ %06x", base); |
20 | return 0; |
21 | } |
22 | return 1; |
23 | } |
24 | |
8b9dbcde |
25 | /* standard/ssf2 mapper */ |
26 | int carthw_ssf2_active; |
27 | unsigned char carthw_ssf2_banks[8]; |
000f5335 |
28 | |
29 | static carthw_state_chunk carthw_ssf2_state[] = |
30 | { |
8b9dbcde |
31 | { CHUNK_CARTHW, sizeof(carthw_ssf2_banks), &carthw_ssf2_banks }, |
32 | { 0, 0, NULL } |
000f5335 |
33 | }; |
34 | |
8fde2033 |
35 | void carthw_ssf2_write8(u32 a, u32 d) |
000f5335 |
36 | { |
8b9dbcde |
37 | u32 target, base; |
000f5335 |
38 | |
e370f4d6 |
39 | if ((a & ~0x0e) != 0xa130f1 || a == 0xa130f1) { |
8b9dbcde |
40 | PicoWrite8_io(a, d); |
41 | return; |
42 | } |
000f5335 |
43 | |
8b9dbcde |
44 | a &= 0x0e; |
45 | if (a == 0) |
46 | return; |
47 | if (carthw_ssf2_banks[a >> 1] == d) |
48 | return; |
49 | |
50 | base = d << 19; |
51 | target = a << 18; |
52 | if (!have_bank(base)) |
53 | return; |
54 | carthw_ssf2_banks[a >> 1] = d; |
55 | |
56 | cpu68k_map_set(m68k_read8_map, target, target + 0x80000 - 1, Pico.rom + base, 0); |
57 | cpu68k_map_set(m68k_read16_map, target, target + 0x80000 - 1, Pico.rom + base, 0); |
8fde2033 |
58 | } |
59 | |
60 | void carthw_ssf2_write16(u32 a, u32 d) |
61 | { |
62 | PicoWrite16_io(a, d); |
63 | if ((a & ~0x0f) == 0xa130f0) |
64 | carthw_ssf2_write8(a + 1, d); |
000f5335 |
65 | } |
66 | |
67 | static void carthw_ssf2_mem_setup(void) |
68 | { |
8fde2033 |
69 | cpu68k_map_set(m68k_write8_map, 0xa10000, 0xa1ffff, carthw_ssf2_write8, 1); |
70 | cpu68k_map_set(m68k_write16_map, 0xa10000, 0xa1ffff, carthw_ssf2_write16, 1); |
000f5335 |
71 | } |
72 | |
73 | static void carthw_ssf2_statef(void) |
74 | { |
f8dba3f6 |
75 | int i, reg; |
76 | for (i = 1; i < 8; i++) { |
77 | reg = carthw_ssf2_banks[i]; |
d4b5888a |
78 | carthw_ssf2_banks[i] = ~reg; |
f8dba3f6 |
79 | carthw_ssf2_write8(0xa130f1 | (i << 1), reg); |
80 | } |
8b9dbcde |
81 | } |
82 | |
83 | static void carthw_ssf2_unload(void) |
84 | { |
85 | memset(carthw_ssf2_banks, 0, sizeof(carthw_ssf2_banks)); |
86 | carthw_ssf2_active = 0; |
000f5335 |
87 | } |
88 | |
89 | void carthw_ssf2_startup(void) |
90 | { |
8b9dbcde |
91 | int i; |
000f5335 |
92 | |
8b9dbcde |
93 | elprintf(EL_STATUS, "SSF2 mapper startup"); |
000f5335 |
94 | |
8b9dbcde |
95 | // default map |
96 | for (i = 0; i < 8; i++) |
97 | carthw_ssf2_banks[i] = i; |
000f5335 |
98 | |
8b9dbcde |
99 | PicoCartMemSetup = carthw_ssf2_mem_setup; |
100 | PicoLoadStateHook = carthw_ssf2_statef; |
101 | PicoCartUnloadHook = carthw_ssf2_unload; |
102 | carthw_chunks = carthw_ssf2_state; |
103 | carthw_ssf2_active = 1; |
000f5335 |
104 | } |
105 | |
106 | |
45f2f245 |
107 | /* Common *-in-1 pirate mapper. |
108 | * Switches banks based on addr lines when /TIME is set. |
109 | * TODO: verify |
110 | */ |
111 | static unsigned int carthw_Xin1_baddr = 0; |
757f8dae |
112 | |
45f2f245 |
113 | static void carthw_Xin1_do(u32 a, int mask, int shift) |
757f8dae |
114 | { |
115 | int len; |
116 | |
45f2f245 |
117 | carthw_Xin1_baddr = a; |
118 | a &= mask; |
119 | a <<= shift; |
757f8dae |
120 | len = Pico.romsize - a; |
121 | if (len <= 0) { |
45f2f245 |
122 | elprintf(EL_ANOMALY|EL_STATUS, "X-in-1: missing bank @ %06x", a); |
757f8dae |
123 | return; |
124 | } |
125 | |
45f2f245 |
126 | len = (len + M68K_BANK_MASK) & ~M68K_BANK_MASK; |
127 | cpu68k_map_set(m68k_read8_map, 0x000000, len - 1, Pico.rom + a, 0); |
128 | cpu68k_map_set(m68k_read16_map, 0x000000, len - 1, Pico.rom + a, 0); |
757f8dae |
129 | } |
130 | |
45f2f245 |
131 | static carthw_state_chunk carthw_Xin1_state[] = |
757f8dae |
132 | { |
45f2f245 |
133 | { CHUNK_CARTHW, sizeof(carthw_Xin1_baddr), &carthw_Xin1_baddr }, |
134 | { 0, 0, NULL } |
135 | }; |
136 | |
04cb5a19 |
137 | // TODO: reads should also work, but then we need to handle open bus |
45f2f245 |
138 | static void carthw_Xin1_write8(u32 a, u32 d) |
139 | { |
140 | if ((a & 0xffff00) != 0xa13000) { |
141 | PicoWrite8_io(a, d); |
142 | return; |
143 | } |
144 | |
04cb5a19 |
145 | carthw_Xin1_do(a, 0x3e, 16); |
146 | } |
147 | |
148 | static void carthw_Xin1_write16(u32 a, u32 d) |
149 | { |
150 | if ((a & 0xffff00) != 0xa13000) { |
151 | PicoWrite16_io(a, d); |
152 | return; |
153 | } |
154 | |
155 | carthw_Xin1_write8(a + 1, d); |
757f8dae |
156 | } |
157 | |
45f2f245 |
158 | static void carthw_Xin1_mem_setup(void) |
bdec53c9 |
159 | { |
04cb5a19 |
160 | cpu68k_map_set(m68k_write8_map, 0xa10000, 0xa1ffff, carthw_Xin1_write8, 1); |
161 | cpu68k_map_set(m68k_write16_map, 0xa10000, 0xa1ffff, carthw_Xin1_write16, 1); |
bdec53c9 |
162 | } |
163 | |
45f2f245 |
164 | static void carthw_Xin1_reset(void) |
757f8dae |
165 | { |
45f2f245 |
166 | carthw_Xin1_write8(0xa13000, 0); |
167 | } |
757f8dae |
168 | |
45f2f245 |
169 | static void carthw_Xin1_statef(void) |
170 | { |
171 | carthw_Xin1_write8(carthw_Xin1_baddr, 0); |
172 | } |
757f8dae |
173 | |
45f2f245 |
174 | void carthw_Xin1_startup(void) |
175 | { |
176 | elprintf(EL_STATUS, "X-in-1 mapper startup"); |
757f8dae |
177 | |
45f2f245 |
178 | PicoCartMemSetup = carthw_Xin1_mem_setup; |
179 | PicoResetHook = carthw_Xin1_reset; |
180 | PicoLoadStateHook = carthw_Xin1_statef; |
181 | carthw_chunks = carthw_Xin1_state; |
757f8dae |
182 | } |
183 | |
a12b1b29 |
184 | |
185 | /* Realtec, based on TascoDLX doc |
186 | * http://www.sharemation.com/TascoDLX/REALTEC%20Cart%20Mapper%20-%20description%20v1.txt |
187 | */ |
188 | static int realtec_bank = 0x80000000, realtec_size = 0x80000000; |
a12b1b29 |
189 | |
45f2f245 |
190 | static void carthw_realtec_write8(u32 a, u32 d) |
a12b1b29 |
191 | { |
192 | int i, bank_old = realtec_bank, size_old = realtec_size; |
193 | |
194 | if (a == 0x400000) |
195 | { |
196 | realtec_bank &= 0x0e0000; |
197 | realtec_bank |= 0x300000 & (d << 19); |
198 | if (realtec_bank != bank_old) |
199 | elprintf(EL_ANOMALY, "write [%06x] %02x @ %06x", a, d, SekPc); |
200 | } |
201 | else if (a == 0x402000) |
202 | { |
203 | realtec_size = (d << 17) & 0x3e0000; |
204 | if (realtec_size != size_old) |
205 | elprintf(EL_ANOMALY, "write [%06x] %02x @ %06x", a, d, SekPc); |
206 | } |
207 | else if (a == 0x404000) |
208 | { |
209 | realtec_bank &= 0x300000; |
210 | realtec_bank |= 0x0e0000 & (d << 17); |
211 | if (realtec_bank != bank_old) |
212 | elprintf(EL_ANOMALY, "write [%06x] %02x @ %06x", a, d, SekPc); |
213 | } |
214 | else |
215 | elprintf(EL_ANOMALY, "realtec: unexpected write [%06x] %02x @ %06x", a, d, SekPc); |
65ca3034 |
216 | |
a12b1b29 |
217 | if (realtec_bank >= 0 && realtec_size >= 0 && |
218 | (realtec_bank != bank_old || realtec_size != size_old)) |
219 | { |
220 | elprintf(EL_ANOMALY, "realtec: new bank %06x, size %06x", realtec_bank, realtec_size, SekPc); |
45f2f245 |
221 | if (realtec_size > Pico.romsize - realtec_bank) |
a12b1b29 |
222 | { |
223 | elprintf(EL_ANOMALY, "realtec: bank too large / out of range?"); |
224 | return; |
225 | } |
226 | |
45f2f245 |
227 | for (i = 0; i < 0x400000; i += realtec_size) { |
228 | cpu68k_map_set(m68k_read8_map, i, realtec_size - 1, Pico.rom + realtec_bank, 0); |
229 | cpu68k_map_set(m68k_read16_map, i, realtec_size - 1, Pico.rom + realtec_bank, 0); |
230 | } |
a12b1b29 |
231 | } |
232 | } |
233 | |
0b35350d |
234 | static void carthw_realtec_reset(void) |
a12b1b29 |
235 | { |
236 | int i; |
45f2f245 |
237 | |
a12b1b29 |
238 | /* map boot code */ |
45f2f245 |
239 | for (i = 0; i < 0x400000; i += M68K_BANK_SIZE) { |
240 | cpu68k_map_set(m68k_read8_map, i, i + M68K_BANK_SIZE - 1, Pico.rom + Pico.romsize, 0); |
241 | cpu68k_map_set(m68k_read16_map, i, i + M68K_BANK_SIZE - 1, Pico.rom + Pico.romsize, 0); |
242 | } |
243 | cpu68k_map_set(m68k_write8_map, 0x400000, 0x400000 + M68K_BANK_SIZE - 1, carthw_realtec_write8, 1); |
a12b1b29 |
244 | realtec_bank = realtec_size = 0x80000000; |
245 | } |
246 | |
247 | void carthw_realtec_startup(void) |
248 | { |
45f2f245 |
249 | int i; |
a12b1b29 |
250 | |
45f2f245 |
251 | elprintf(EL_STATUS, "Realtec mapper startup"); |
a12b1b29 |
252 | |
45f2f245 |
253 | // allocate additional bank for boot code |
254 | // (we know those ROMs have aligned size) |
a736af3e |
255 | i = PicoCartResize(Pico.romsize + M68K_BANK_SIZE); |
256 | if (i != 0) { |
a12b1b29 |
257 | elprintf(EL_STATUS, "OOM"); |
258 | return; |
259 | } |
a12b1b29 |
260 | |
45f2f245 |
261 | // create bank for boot code |
262 | for (i = 0; i < M68K_BANK_SIZE; i += 0x2000) |
263 | memcpy(Pico.rom + Pico.romsize + i, Pico.rom + Pico.romsize - 0x2000, 0x2000); |
264 | |
a12b1b29 |
265 | PicoResetHook = carthw_realtec_reset; |
266 | } |
267 | |
0b35350d |
268 | /* Radica mapper, based on DevSter's info |
269 | * http://devster.monkeeh.com/sega/radica/ |
45f2f245 |
270 | * XXX: mostly the same as X-in-1, merge? |
0b35350d |
271 | */ |
45f2f245 |
272 | static u32 carthw_radica_read16(u32 a) |
0b35350d |
273 | { |
45f2f245 |
274 | if ((a & 0xffff00) != 0xa13000) |
275 | return PicoRead16_io(a); |
0b35350d |
276 | |
45f2f245 |
277 | carthw_Xin1_do(a, 0x7e, 15); |
0b35350d |
278 | |
279 | return 0; |
280 | } |
281 | |
45f2f245 |
282 | static void carthw_radica_mem_setup(void) |
283 | { |
284 | cpu68k_map_set(m68k_read16_map, 0xa10000, 0xa1ffff, carthw_radica_read16, 1); |
285 | } |
286 | |
0b35350d |
287 | static void carthw_radica_statef(void) |
288 | { |
45f2f245 |
289 | carthw_radica_read16(carthw_Xin1_baddr); |
0b35350d |
290 | } |
291 | |
292 | static void carthw_radica_reset(void) |
293 | { |
45f2f245 |
294 | carthw_radica_read16(0xa13000); |
0b35350d |
295 | } |
296 | |
297 | void carthw_radica_startup(void) |
298 | { |
45f2f245 |
299 | elprintf(EL_STATUS, "Radica mapper startup"); |
0b35350d |
300 | |
45f2f245 |
301 | PicoCartMemSetup = carthw_radica_mem_setup; |
302 | PicoResetHook = carthw_radica_reset; |
0b35350d |
303 | PicoLoadStateHook = carthw_radica_statef; |
45f2f245 |
304 | carthw_chunks = carthw_Xin1_state; |
0b35350d |
305 | } |
306 | |
30f0fdd4 |
307 | |
308 | /* Pier Solar. Based on my own research */ |
309 | static unsigned char pier_regs[8]; |
310 | static unsigned char pier_dump_prot; |
311 | |
312 | static carthw_state_chunk carthw_pier_state[] = |
313 | { |
314 | { CHUNK_CARTHW, sizeof(pier_regs), pier_regs }, |
315 | { CHUNK_CARTHW + 1, sizeof(pier_dump_prot), &pier_dump_prot }, |
6a47c2d4 |
316 | { CHUNK_CARTHW + 2, 0, NULL }, // filled later |
30f0fdd4 |
317 | { 0, 0, NULL } |
318 | }; |
319 | |
320 | static void carthw_pier_write8(u32 a, u32 d) |
321 | { |
322 | u32 a8, target, base; |
323 | |
324 | if ((a & 0xffff00) != 0xa13000) { |
325 | PicoWrite8_io(a, d); |
326 | return; |
327 | } |
328 | |
329 | a8 = a & 0x0f; |
330 | pier_regs[a8 / 2] = d; |
331 | |
332 | elprintf(EL_UIO, "pier w8 [%06x] %02x @%06x", a, d & 0xffff, SekPc); |
333 | switch (a8) { |
334 | case 0x01: |
335 | break; |
336 | case 0x03: |
337 | if (!(pier_regs[0] & 2)) |
338 | goto unmapped; |
339 | target = 0x280000; |
340 | base = d << 19; |
341 | goto do_map; |
342 | case 0x05: |
343 | if (!(pier_regs[0] & 2)) |
344 | goto unmapped; |
345 | target = 0x300000; |
346 | base = d << 19; |
347 | goto do_map; |
348 | case 0x07: |
349 | if (!(pier_regs[0] & 2)) |
350 | goto unmapped; |
351 | target = 0x380000; |
352 | base = d << 19; |
353 | goto do_map; |
354 | case 0x09: |
88fd63ad |
355 | Pico.sv.changed = 1; |
6a47c2d4 |
356 | eeprom_spi_write(d); |
30f0fdd4 |
357 | break; |
358 | case 0x0b: |
359 | // eeprom read |
360 | default: |
361 | unmapped: |
362 | //elprintf(EL_UIO, "pier w8 [%06x] %02x @%06x", a, d & 0xffff, SekPc); |
363 | elprintf(EL_STATUS, "-- unmapped w8 [%06x] %02x @%06x", a, d & 0xffff, SekPc); |
364 | break; |
365 | } |
366 | return; |
367 | |
368 | do_map: |
f5080654 |
369 | if (!have_bank(base)) |
30f0fdd4 |
370 | return; |
f5080654 |
371 | |
30f0fdd4 |
372 | cpu68k_map_set(m68k_read8_map, target, target + 0x80000 - 1, Pico.rom + base, 0); |
373 | cpu68k_map_set(m68k_read16_map, target, target + 0x80000 - 1, Pico.rom + base, 0); |
374 | } |
375 | |
376 | static void carthw_pier_write16(u32 a, u32 d) |
377 | { |
378 | if ((a & 0xffff00) != 0xa13000) { |
379 | PicoWrite16_io(a, d); |
380 | return; |
381 | } |
382 | |
383 | elprintf(EL_UIO, "pier w16 [%06x] %04x @%06x", a, d & 0xffff, SekPc); |
384 | carthw_pier_write8(a + 1, d); |
385 | } |
386 | |
387 | static u32 carthw_pier_read8(u32 a) |
388 | { |
389 | if ((a & 0xffff00) != 0xa13000) |
390 | return PicoRead8_io(a); |
391 | |
392 | if (a == 0xa1300b) |
6a47c2d4 |
393 | return eeprom_spi_read(a); |
30f0fdd4 |
394 | |
395 | elprintf(EL_UIO, "pier r8 [%06x] @%06x", a, SekPc); |
396 | return 0; |
397 | } |
398 | |
399 | static void carthw_pier_statef(void); |
400 | |
401 | static u32 carthw_pier_prot_read8(u32 a) |
402 | { |
403 | /* it takes more than just these reads here to disable ROM protection, |
404 | * but for game emulation purposes this is enough. */ |
405 | if (pier_dump_prot > 0) |
406 | pier_dump_prot--; |
407 | if (pier_dump_prot == 0) { |
408 | carthw_pier_statef(); |
409 | elprintf(EL_STATUS, "prot off on r8 @%06x", SekPc); |
410 | } |
411 | elprintf(EL_UIO, "pier r8 [%06x] @%06x", a, SekPc); |
412 | |
57c5a5e5 |
413 | return Pico.rom[MEM_BE2(a & 0x7fff)]; |
30f0fdd4 |
414 | } |
415 | |
416 | static void carthw_pier_mem_setup(void) |
417 | { |
418 | cpu68k_map_set(m68k_write8_map, 0xa10000, 0xa1ffff, carthw_pier_write8, 1); |
419 | cpu68k_map_set(m68k_write16_map, 0xa10000, 0xa1ffff, carthw_pier_write16, 1); |
420 | cpu68k_map_set(m68k_read8_map, 0xa10000, 0xa1ffff, carthw_pier_read8, 1); |
421 | } |
422 | |
423 | static void carthw_pier_prot_mem_setup(int prot_enable) |
424 | { |
425 | if (prot_enable) { |
426 | /* the dump protection.. */ |
427 | int a; |
428 | for (a = 0x000000; a < 0x400000; a += M68K_BANK_SIZE) { |
429 | cpu68k_map_set(m68k_read8_map, a, a + 0xffff, Pico.rom + Pico.romsize, 0); |
430 | cpu68k_map_set(m68k_read16_map, a, a + 0xffff, Pico.rom + Pico.romsize, 0); |
431 | } |
432 | cpu68k_map_set(m68k_read8_map, M68K_BANK_SIZE, M68K_BANK_SIZE * 2 - 1, |
433 | carthw_pier_prot_read8, 1); |
434 | } |
435 | else { |
436 | cpu68k_map_set(m68k_read8_map, 0, 0x27ffff, Pico.rom, 0); |
437 | cpu68k_map_set(m68k_read16_map, 0, 0x27ffff, Pico.rom, 0); |
438 | } |
439 | } |
440 | |
441 | static void carthw_pier_statef(void) |
442 | { |
443 | carthw_pier_prot_mem_setup(pier_dump_prot); |
444 | |
445 | if (!pier_dump_prot) { |
446 | /* setup all banks */ |
447 | u32 r0 = pier_regs[0]; |
448 | carthw_pier_write8(0xa13001, 3); |
449 | carthw_pier_write8(0xa13003, pier_regs[1]); |
450 | carthw_pier_write8(0xa13005, pier_regs[2]); |
451 | carthw_pier_write8(0xa13007, pier_regs[3]); |
452 | carthw_pier_write8(0xa13001, r0); |
453 | } |
454 | } |
455 | |
456 | static void carthw_pier_reset(void) |
457 | { |
458 | pier_regs[0] = 1; |
459 | pier_regs[1] = pier_regs[2] = pier_regs[3] = 0; |
30f0fdd4 |
460 | carthw_pier_statef(); |
6a47c2d4 |
461 | eeprom_spi_init(NULL); |
30f0fdd4 |
462 | } |
463 | |
464 | void carthw_pier_startup(void) |
465 | { |
6a47c2d4 |
466 | void *eeprom_state; |
467 | int eeprom_size = 0; |
30f0fdd4 |
468 | int i; |
469 | |
470 | elprintf(EL_STATUS, "Pier Solar mapper startup"); |
471 | |
472 | // mostly same as for realtec.. |
473 | i = PicoCartResize(Pico.romsize + M68K_BANK_SIZE); |
474 | if (i != 0) { |
475 | elprintf(EL_STATUS, "OOM"); |
476 | return; |
477 | } |
478 | |
2b46e6c1 |
479 | pier_dump_prot = 3; |
480 | |
30f0fdd4 |
481 | // create dump protection bank |
482 | for (i = 0; i < M68K_BANK_SIZE; i += 0x8000) |
483 | memcpy(Pico.rom + Pico.romsize + i, Pico.rom, 0x8000); |
484 | |
6a47c2d4 |
485 | // save EEPROM |
486 | eeprom_state = eeprom_spi_init(&eeprom_size); |
88fd63ad |
487 | Pico.sv.flags = 0; |
488 | Pico.sv.size = 0x10000; |
489 | Pico.sv.data = calloc(1, Pico.sv.size); |
490 | if (!Pico.sv.data) |
491 | Pico.sv.size = 0; |
6a47c2d4 |
492 | carthw_pier_state[2].ptr = eeprom_state; |
493 | carthw_pier_state[2].size = eeprom_size; |
494 | |
30f0fdd4 |
495 | PicoCartMemSetup = carthw_pier_mem_setup; |
496 | PicoResetHook = carthw_pier_reset; |
497 | PicoLoadStateHook = carthw_pier_statef; |
498 | carthw_chunks = carthw_pier_state; |
499 | } |
500 | |
b7697ca3 |
501 | /* superfighter mappers, see mame: mame/src/devices/bus/megadrive/rom.cpp */ |
60392bf4 |
502 | unsigned int carthw_sf00x_reg; |
503 | |
504 | static carthw_state_chunk carthw_sf00x_state[] = |
505 | { |
506 | { CHUNK_CARTHW, sizeof(carthw_sf00x_reg), &carthw_sf00x_reg }, |
507 | { 0, 0, NULL } |
508 | }; |
509 | |
b7697ca3 |
510 | // SF-001 |
511 | |
512 | // additionally map SRAM at 0x3c0000 for the newer version of sf001 |
513 | static u32 carthw_sf001_read8_sram(u32 a) |
60392bf4 |
514 | { |
b7697ca3 |
515 | return m68k_read8((a & 0xffff) + Pico.sv.start); |
60392bf4 |
516 | } |
517 | |
b7697ca3 |
518 | static u32 carthw_sf001_read16_sram(u32 a) |
60392bf4 |
519 | { |
b7697ca3 |
520 | return m68k_read16((a & 0xffff) + Pico.sv.start); |
60392bf4 |
521 | } |
522 | |
b7697ca3 |
523 | static void carthw_sf001_write8_sram(u32 a, u32 d) |
60392bf4 |
524 | { |
b7697ca3 |
525 | m68k_write8((a & 0xffff) + Pico.sv.start, d); |
60392bf4 |
526 | } |
527 | |
b7697ca3 |
528 | static void carthw_sf001_write16_sram(u32 a, u32 d) |
60392bf4 |
529 | { |
b7697ca3 |
530 | m68k_write16((a & 0xffff) + Pico.sv.start, d); |
60392bf4 |
531 | } |
532 | |
b7697ca3 |
533 | static void carthw_sf001_write8(u32 a, u32 d) |
60392bf4 |
534 | { |
b7697ca3 |
535 | if ((a & 0xf00) != 0xe00 || (carthw_sf00x_reg & 0x20)) // wrong addr / locked |
60392bf4 |
536 | return; |
537 | |
538 | if (d & 0x80) { |
539 | // bank 0xe at addr 0x000000 |
540 | cpu68k_map_set(m68k_read8_map, 0x000000, 0x040000-1, Pico.rom+0x380000, 0); |
541 | cpu68k_map_set(m68k_read16_map, 0x000000, 0x040000-1, Pico.rom+0x380000, 0); |
b7697ca3 |
542 | // SRAM also at 0x3c0000 for newer mapper version |
60392bf4 |
543 | cpu68k_map_set(m68k_read8_map, 0x3c0000, 0x400000-1, carthw_sf001_read8_sram, 1); |
544 | cpu68k_map_set(m68k_read16_map, 0x3c0000, 0x400000-1, carthw_sf001_read16_sram, 1); |
545 | cpu68k_map_set(m68k_write8_map, 0x3c0000, 0x400000-1, carthw_sf001_write8_sram, 1); |
546 | cpu68k_map_set(m68k_write16_map,0x3c0000, 0x400000-1, carthw_sf001_write16_sram, 1); |
547 | } else { |
548 | // bank 0x0 at addr 0x000000 |
549 | cpu68k_map_set(m68k_read8_map, 0x000000, 0x040000-1, Pico.rom, 0); |
550 | cpu68k_map_set(m68k_read16_map, 0x000000, 0x040000-1, Pico.rom, 0); |
551 | // SRAM off, bank 0xf at addr 0x3c0000 |
552 | cpu68k_map_set(m68k_read8_map, 0x3c0000, 0x400000-1, Pico.rom+0x3c0000, 0); |
553 | cpu68k_map_set(m68k_read16_map, 0x3c0000, 0x400000-1, Pico.rom+0x3c0000, 0); |
554 | cpu68k_map_set(m68k_write8_map, 0x3c0000, 0x400000-1, Pico.rom+0x3c0000, 0); |
555 | cpu68k_map_set(m68k_write16_map,0x3c0000, 0x400000-1, Pico.rom+0x3c0000, 0); |
556 | } |
557 | carthw_sf00x_reg = d; |
558 | } |
559 | |
b7697ca3 |
560 | static void carthw_sf001_write16(u32 a, u32 d) |
60392bf4 |
561 | { |
562 | carthw_sf001_write8(a + 1, d); |
563 | } |
564 | |
565 | static void carthw_sf001_mem_setup(void) |
566 | { |
b7697ca3 |
567 | // writing to low cartridge addresses |
60392bf4 |
568 | cpu68k_map_set(m68k_write8_map, 0x000000, 0x00ffff, carthw_sf001_write8, 1); |
569 | cpu68k_map_set(m68k_write16_map, 0x000000, 0x00ffff, carthw_sf001_write16, 1); |
570 | } |
571 | |
572 | static void carthw_sf001_reset(void) |
573 | { |
b7697ca3 |
574 | carthw_sf00x_reg = 0; |
60392bf4 |
575 | carthw_sf001_write8(0x0e01, 0); |
576 | } |
577 | |
578 | static void carthw_sf001_statef(void) |
579 | { |
b7697ca3 |
580 | int reg = carthw_sf00x_reg; |
581 | carthw_sf00x_reg = 0; |
582 | carthw_sf001_write8(0x0e01, reg); |
60392bf4 |
583 | } |
584 | |
585 | void carthw_sf001_startup(void) |
586 | { |
587 | PicoCartMemSetup = carthw_sf001_mem_setup; |
588 | PicoResetHook = carthw_sf001_reset; |
589 | PicoLoadStateHook = carthw_sf001_statef; |
590 | carthw_chunks = carthw_sf00x_state; |
591 | } |
592 | |
b7697ca3 |
593 | // SF-002 |
60392bf4 |
594 | |
b7697ca3 |
595 | static void carthw_sf002_write8(u32 a, u32 d) |
60392bf4 |
596 | { |
b7697ca3 |
597 | if ((a & 0xf00) != 0xe00) |
60392bf4 |
598 | return; |
599 | |
600 | if (d & 0x80) { |
601 | // bank 0x00-0x0e on addr 0x20000 |
602 | cpu68k_map_set(m68k_read8_map, 0x200000, 0x3c0000-1, Pico.rom, 0); |
603 | cpu68k_map_set(m68k_read16_map, 0x200000, 0x3c0000-1, Pico.rom, 0); |
604 | } else { |
605 | // bank 0x10-0x1e on addr 0x20000 |
606 | cpu68k_map_set(m68k_read8_map, 0x200000, 0x3c0000-1, Pico.rom+0x200000, 0); |
607 | cpu68k_map_set(m68k_read16_map, 0x200000, 0x3c0000-1, Pico.rom+0x200000, 0); |
608 | } |
609 | carthw_sf00x_reg = d; |
610 | } |
611 | |
b7697ca3 |
612 | static void carthw_sf002_write16(u32 a, u32 d) |
60392bf4 |
613 | { |
614 | carthw_sf002_write8(a + 1, d); |
615 | } |
616 | |
617 | static void carthw_sf002_mem_setup(void) |
618 | { |
b7697ca3 |
619 | // writing to low cartridge addresses |
60392bf4 |
620 | cpu68k_map_set(m68k_write8_map, 0x000000, 0x00ffff, carthw_sf002_write8, 1); |
621 | cpu68k_map_set(m68k_write16_map, 0x000000, 0x00ffff, carthw_sf002_write16, 1); |
622 | } |
623 | |
624 | static void carthw_sf002_reset(void) |
625 | { |
626 | carthw_sf002_write8(0x0e01, 0); |
627 | } |
628 | |
629 | static void carthw_sf002_statef(void) |
630 | { |
631 | carthw_sf002_write8(0x0e01, carthw_sf00x_reg); |
632 | } |
633 | |
634 | void carthw_sf002_startup(void) |
635 | { |
636 | PicoCartMemSetup = carthw_sf002_mem_setup; |
637 | PicoResetHook = carthw_sf002_reset; |
638 | PicoLoadStateHook = carthw_sf002_statef; |
639 | carthw_chunks = carthw_sf00x_state; |
640 | } |
641 | |
b7697ca3 |
642 | // SF-004 |
643 | |
644 | // reading from cartridge I/O region returns the current bank index |
645 | static u32 carthw_sf004_read8(u32 a) |
646 | { |
647 | if ((a & ~0xff) == 0xa13000) |
648 | return carthw_sf00x_reg & 0xf0; // bank index |
649 | return PicoRead8_io(a); |
650 | } |
651 | |
652 | static u32 carthw_sf004_read16(u32 a) |
653 | { |
654 | if ((a & ~0xff) == 0xa13000) |
655 | return carthw_sf00x_reg & 0xf0; |
656 | return PicoRead16_io(a); |
657 | } |
658 | |
659 | // writing to low cartridge adresses changes mappings |
660 | static void carthw_sf004_write8(u32 a, u32 d) |
661 | { |
662 | int idx, i; |
663 | unsigned bs = 0x40000; // bank size |
664 | |
665 | // there are 3 byte-sized regs, stored together in carthw_sf00x_reg |
666 | if (!(carthw_sf00x_reg & 0x8000)) |
667 | return; // locked |
668 | |
669 | switch (a & 0xf00) { |
670 | case 0xd00: |
671 | carthw_sf00x_reg = (carthw_sf00x_reg & ~0xff0000) | ((d & 0xff) << 16); |
672 | return PicoWrite8_io(0xa130f1, (d & 0x80) ? SRR_MAPPED : 0); // SRAM mapping |
673 | case 0xe00: |
674 | carthw_sf00x_reg = (carthw_sf00x_reg & ~0x00ff00) | ((d & 0xff) << 8); |
675 | break; |
676 | case 0xf00: |
677 | carthw_sf00x_reg = (carthw_sf00x_reg & ~0x0000ff) | ((d & 0xff) << 0); |
678 | break; |
679 | default: |
680 | return; // wrong addr |
681 | } |
682 | |
683 | // bank mapping changed |
684 | idx = ((carthw_sf00x_reg>>4) & 0x7); // bank index |
685 | if ((carthw_sf00x_reg>>8) & 0x40) { |
686 | // linear bank mapping, starting at idx |
687 | for (i = 0; i < 8; i++, idx = (idx+1) & 0x7) { |
688 | cpu68k_map_set(m68k_read8_map, i*bs, (i+1)*bs-1, Pico.rom + idx*bs, 0); |
689 | cpu68k_map_set(m68k_read16_map, i*bs, (i+1)*bs-1, Pico.rom + idx*bs, 0); |
690 | } |
691 | } else { |
692 | // single bank mapping |
693 | for (i = 0; i < 8; i++) { |
694 | cpu68k_map_set(m68k_read8_map, i*bs, (i+1)*bs-1, Pico.rom + idx*bs, 0); |
695 | cpu68k_map_set(m68k_read16_map, i*bs, (i+1)*bs-1, Pico.rom + idx*bs, 0); |
696 | } |
697 | } |
698 | } |
699 | |
700 | static void carthw_sf004_write16(u32 a, u32 d) |
701 | { |
702 | carthw_sf004_write8(a + 1, d); |
703 | } |
704 | |
705 | static void carthw_sf004_mem_setup(void) |
706 | { |
707 | // writing to low cartridge addresses |
708 | cpu68k_map_set(m68k_write8_map, 0x000000, 0x00ffff, carthw_sf004_write8, 1); |
709 | cpu68k_map_set(m68k_write16_map, 0x000000, 0x00ffff, carthw_sf004_write16, 1); |
710 | // reading from the cartridge I/O region |
711 | cpu68k_map_set(m68k_read8_map, 0xa10000, 0xa1ffff, carthw_sf004_read8, 1); |
712 | cpu68k_map_set(m68k_read16_map, 0xa10000, 0xa1ffff, carthw_sf004_read16, 1); |
713 | } |
714 | |
715 | static void carthw_sf004_reset(void) |
716 | { |
717 | carthw_sf00x_reg = -1; |
718 | carthw_sf004_write8(0x0d01, 0); |
719 | carthw_sf004_write8(0x0f01, 0); |
720 | carthw_sf004_write8(0x0e01, 0x80); |
721 | } |
722 | |
723 | static void carthw_sf004_statef(void) |
724 | { |
725 | int reg = carthw_sf00x_reg; |
726 | carthw_sf00x_reg = -1; |
727 | carthw_sf004_write8(0x0d01, reg >> 16); |
728 | carthw_sf004_write8(0x0f01, reg >> 0); |
729 | carthw_sf004_write8(0x0e01, reg >> 8); |
730 | } |
731 | |
732 | void carthw_sf004_startup(void) |
733 | { |
734 | PicoCartMemSetup = carthw_sf004_mem_setup; |
735 | PicoResetHook = carthw_sf004_reset; |
736 | PicoLoadStateHook = carthw_sf004_statef; |
737 | carthw_chunks = carthw_sf00x_state; |
738 | } |
739 | |
fe9a06d2 |
740 | /* Simple protection through reading flash ID */ |
741 | static int flash_writecount; |
742 | |
743 | static carthw_state_chunk carthw_flash_state[] = |
744 | { |
745 | { CHUNK_CARTHW, sizeof(flash_writecount), &flash_writecount }, |
746 | { 0, 0, NULL } |
747 | }; |
748 | |
749 | static u32 PicoRead16_flash(u32 a) { return (a&6) ? 0x2257 : 0x0020; } |
750 | |
751 | static void PicoWrite16_flash(u32 a, u32 d) |
752 | { |
753 | int banksz = (1<<M68K_MEM_SHIFT)-1; |
754 | switch (++flash_writecount) { |
755 | case 3: cpu68k_map_set(m68k_read16_map, 0, banksz, PicoRead16_flash, 1); |
756 | break; |
757 | case 4: cpu68k_map_read_mem(0, banksz, Pico.rom, 0); |
758 | flash_writecount = 0; |
759 | break; |
760 | } |
761 | } |
762 | |
763 | static void carthw_flash_mem_setup(void) |
764 | { |
765 | cpu68k_map_set(m68k_write16_map, 0, 0x7fffff, PicoWrite16_flash, 1); |
766 | } |
767 | |
768 | void carthw_flash_startup(void) |
769 | { |
770 | elprintf(EL_STATUS, "Flash prot emu startup"); |
771 | |
772 | PicoCartMemSetup = carthw_flash_mem_setup; |
773 | carthw_chunks = carthw_flash_state; |
774 | } |
775 | |
000f5335 |
776 | /* Simple unlicensed ROM protection emulation */ |
777 | static struct { |
30f0fdd4 |
778 | u32 addr; |
779 | u32 mask; |
780 | u16 val; |
781 | u16 readonly; |
e1e8ca17 |
782 | } sprot_items[8]; |
000f5335 |
783 | static int sprot_item_count; |
784 | |
e1e8ca17 |
785 | static carthw_state_chunk carthw_sprot_state[] = |
786 | { |
787 | { CHUNK_CARTHW, sizeof(sprot_items), &sprot_items }, |
788 | { 0, 0, NULL } |
789 | }; |
790 | |
000f5335 |
791 | static u16 *carthw_sprot_get_val(u32 a, int rw_only) |
792 | { |
30f0fdd4 |
793 | int i; |
794 | |
795 | for (i = 0; i < sprot_item_count; i++) |
796 | if ((a & sprot_items[i].mask) == sprot_items[i].addr) |
797 | if (!rw_only || !sprot_items[i].readonly) |
798 | return &sprot_items[i].val; |
000f5335 |
799 | |
30f0fdd4 |
800 | return NULL; |
000f5335 |
801 | } |
802 | |
803 | static u32 PicoRead8_sprot(u32 a) |
804 | { |
805 | u16 *val; |
806 | u32 d; |
807 | |
000f5335 |
808 | val = carthw_sprot_get_val(a, 0); |
809 | if (val != NULL) { |
810 | d = *val; |
811 | if (!(a & 1)) |
812 | d >>= 8; |
813 | elprintf(EL_UIO, "prot r8 [%06x] %02x @%06x", a, d, SekPc); |
814 | return d; |
815 | } |
e1e8ca17 |
816 | else if (0xa10000 <= a && a <= 0xa1ffff) |
817 | return PicoRead8_io(a); |
818 | |
819 | elprintf(EL_UIO, "prot r8 [%06x] MISS @%06x", a, SekPc); |
820 | return 0; |
000f5335 |
821 | } |
822 | |
823 | static u32 PicoRead16_sprot(u32 a) |
824 | { |
825 | u16 *val; |
826 | |
000f5335 |
827 | val = carthw_sprot_get_val(a, 0); |
828 | if (val != NULL) { |
829 | elprintf(EL_UIO, "prot r16 [%06x] %04x @%06x", a, *val, SekPc); |
830 | return *val; |
831 | } |
e1e8ca17 |
832 | else if (0xa10000 <= a && a <= 0xa1ffff) |
833 | return PicoRead16_io(a); |
834 | |
835 | elprintf(EL_UIO, "prot r16 [%06x] MISS @%06x", a, SekPc); |
836 | return 0; |
000f5335 |
837 | } |
838 | |
839 | static void PicoWrite8_sprot(u32 a, u32 d) |
840 | { |
841 | u16 *val; |
842 | |
000f5335 |
843 | val = carthw_sprot_get_val(a, 1); |
844 | if (val != NULL) { |
845 | if (a & 1) |
846 | *val = (*val & 0xff00) | (d | 0xff); |
847 | else |
848 | *val = (*val & 0x00ff) | (d << 8); |
849 | elprintf(EL_UIO, "prot w8 [%06x] %02x @%06x", a, d & 0xff, SekPc); |
850 | } |
e1e8ca17 |
851 | else if (0xa10000 <= a && a <= 0xa1ffff) |
852 | return PicoWrite8_io(a, d); |
853 | |
854 | elprintf(EL_UIO, "prot w8 [%06x] %02x MISS @%06x", a, d & 0xff, SekPc); |
000f5335 |
855 | } |
856 | |
857 | static void PicoWrite16_sprot(u32 a, u32 d) |
858 | { |
859 | u16 *val; |
860 | |
000f5335 |
861 | val = carthw_sprot_get_val(a, 1); |
862 | if (val != NULL) { |
863 | *val = d; |
864 | elprintf(EL_UIO, "prot w16 [%06x] %04x @%06x", a, d & 0xffff, SekPc); |
865 | } |
e1e8ca17 |
866 | else if (0xa10000 <= a && a <= 0xa1ffff) |
867 | return PicoWrite16_io(a, d); |
868 | |
869 | elprintf(EL_UIO, "prot w16 [%06x] %04x MISS @%06x", a, d & 0xffff, SekPc); |
000f5335 |
870 | } |
871 | |
872 | void carthw_sprot_new_location(unsigned int a, unsigned int mask, unsigned short val, int is_ro) |
873 | { |
e1e8ca17 |
874 | int sprot_elems = sizeof(sprot_items)/sizeof(sprot_items[0]); |
875 | if (sprot_item_count == sprot_elems) { |
876 | elprintf(EL_STATUS, "too many sprot items"); |
877 | return; |
000f5335 |
878 | } |
879 | |
880 | sprot_items[sprot_item_count].addr = a; |
881 | sprot_items[sprot_item_count].mask = mask; |
882 | sprot_items[sprot_item_count].val = val; |
883 | sprot_items[sprot_item_count].readonly = is_ro; |
884 | sprot_item_count++; |
885 | } |
886 | |
887 | static void carthw_sprot_unload(void) |
888 | { |
e1e8ca17 |
889 | sprot_item_count = 0; |
000f5335 |
890 | } |
891 | |
892 | static void carthw_sprot_mem_setup(void) |
893 | { |
894 | int start; |
895 | |
e1e8ca17 |
896 | // map 0x400000 - 0x7fffff, /TIME areas (which are tipically used) |
000f5335 |
897 | start = (Pico.romsize + M68K_BANK_MASK) & ~M68K_BANK_MASK; |
e1e8ca17 |
898 | if (start < 0x400000) start = 0x400000; |
899 | |
000f5335 |
900 | cpu68k_map_set(m68k_read8_map, start, 0x7fffff, PicoRead8_sprot, 1); |
901 | cpu68k_map_set(m68k_read16_map, start, 0x7fffff, PicoRead16_sprot, 1); |
902 | cpu68k_map_set(m68k_write8_map, start, 0x7fffff, PicoWrite8_sprot, 1); |
903 | cpu68k_map_set(m68k_write16_map, start, 0x7fffff, PicoWrite16_sprot, 1); |
904 | |
905 | cpu68k_map_set(m68k_read8_map, 0xa10000, 0xa1ffff, PicoRead8_sprot, 1); |
906 | cpu68k_map_set(m68k_read16_map, 0xa10000, 0xa1ffff, PicoRead16_sprot, 1); |
907 | cpu68k_map_set(m68k_write8_map, 0xa10000, 0xa1ffff, PicoWrite8_sprot, 1); |
908 | cpu68k_map_set(m68k_write16_map, 0xa10000, 0xa1ffff, PicoWrite16_sprot, 1); |
909 | } |
910 | |
911 | void carthw_sprot_startup(void) |
912 | { |
913 | elprintf(EL_STATUS, "Prot emu startup"); |
914 | |
915 | PicoCartMemSetup = carthw_sprot_mem_setup; |
916 | PicoCartUnloadHook = carthw_sprot_unload; |
e1e8ca17 |
917 | carthw_chunks = carthw_sprot_state; |
000f5335 |
918 | } |
919 | |
920 | /* Protection emulation for Lion King 3. Credits go to Haze */ |
e1e8ca17 |
921 | static struct { |
922 | u32 bank; |
923 | u8 cmd, data; |
924 | } carthw_lk3_regs; |
925 | |
926 | static carthw_state_chunk carthw_lk3_state[] = |
927 | { |
928 | { CHUNK_CARTHW, sizeof(carthw_lk3_regs), &carthw_lk3_regs }, |
929 | { 0, 0, NULL } |
930 | }; |
931 | |
932 | static u8 *carthw_lk3_mem; // shadow copy memory |
933 | static u32 carthw_lk3_madr[0x100000/M68K_BANK_SIZE]; |
000f5335 |
934 | |
935 | static u32 PicoRead8_plk3(u32 a) |
936 | { |
937 | u32 d = 0; |
e1e8ca17 |
938 | switch (carthw_lk3_regs.cmd) { |
939 | case 0: d = carthw_lk3_regs.data << 1; break; |
940 | case 1: d = carthw_lk3_regs.data >> 1; break; |
000f5335 |
941 | case 2: // nibble rotate |
e1e8ca17 |
942 | d = ((carthw_lk3_regs.data >> 4) | (carthw_lk3_regs.data << 4)) & 0xff; |
000f5335 |
943 | break; |
944 | case 3: // bit rotate |
e1e8ca17 |
945 | d = carthw_lk3_regs.data; |
000f5335 |
946 | d = (d >> 4) | (d << 4); |
947 | d = ((d & 0xcc) >> 2) | ((d & 0x33) << 2); |
948 | d = ((d & 0xaa) >> 1) | ((d & 0x55) << 1); |
949 | break; |
000f5335 |
950 | default: |
e1e8ca17 |
951 | elprintf(EL_UIO, "unhandled prot cmd %02x @%06x", carthw_lk3_regs.cmd, SekPc); |
000f5335 |
952 | break; |
953 | } |
954 | |
955 | elprintf(EL_UIO, "prot r8 [%06x] %02x @%06x", a, d, SekPc); |
956 | return d; |
957 | } |
958 | |
959 | static void PicoWrite8_plk3p(u32 a, u32 d) |
960 | { |
961 | elprintf(EL_UIO, "prot w8 [%06x] %02x @%06x", a, d & 0xff, SekPc); |
962 | if (a & 2) |
e1e8ca17 |
963 | carthw_lk3_regs.cmd = d & 0x3; |
000f5335 |
964 | else |
e1e8ca17 |
965 | carthw_lk3_regs.data = d; |
000f5335 |
966 | } |
967 | |
968 | static void PicoWrite8_plk3b(u32 a, u32 d) |
969 | { |
e1e8ca17 |
970 | u32 addr; |
000f5335 |
971 | |
972 | elprintf(EL_UIO, "prot w8 [%06x] %02x @%06x", a, d & 0xff, SekPc); |
973 | addr = d << 15; |
e1e8ca17 |
974 | if (addr+0x10000 >= Pico.romsize) { |
975 | elprintf(EL_UIO|EL_ANOMALY, "lk3_mapper: bank too large: %02x", d); |
000f5335 |
976 | return; |
977 | } |
e1e8ca17 |
978 | |
979 | if (addr != carthw_lk3_regs.bank) { |
980 | // banking is by or'ing the bank address in the 1st megabyte, not adding. |
981 | // only do linear mapping if map addresses aren't overlapping bank address |
982 | u32 len = M68K_BANK_SIZE; |
983 | u32 a, b; |
984 | for (b = 0x000000; b < 0x0100000; b += len) { |
985 | if (!((b + (len-1)) & addr)) { |
986 | cpu68k_map_set(m68k_read8_map, b, b + (len-1), Pico.rom+addr + b, 0); |
987 | cpu68k_map_set(m68k_read16_map, b, b + (len-1), Pico.rom+addr + b, 0); |
988 | } else { |
989 | // overlap. ugh, need a shadow copy since banks can contain code and |
990 | // 68K cpu emulator cores need mapped access to code memory |
991 | if (carthw_lk3_madr[b/len] != addr) // only if shadow isn't the same |
992 | for (a = b; a < b+M68K_BANK_SIZE; a += 0x8000) |
993 | memcpy(carthw_lk3_mem + a, Pico.rom + (addr|a), 0x8000); |
994 | carthw_lk3_madr[b/len] = addr; |
995 | cpu68k_map_set(m68k_read8_map, b, b + (len-1), carthw_lk3_mem + b, 0); |
996 | cpu68k_map_set(m68k_read16_map, b, b + (len-1), carthw_lk3_mem + b, 0); |
997 | } |
998 | } |
999 | } |
1000 | carthw_lk3_regs.bank = addr; |
000f5335 |
1001 | } |
1002 | |
e1e8ca17 |
1003 | static void carthw_lk3_mem_setup(void) |
000f5335 |
1004 | { |
1005 | cpu68k_map_set(m68k_read8_map, 0x600000, 0x7fffff, PicoRead8_plk3, 1); |
1006 | cpu68k_map_set(m68k_write8_map, 0x600000, 0x6fffff, PicoWrite8_plk3p, 1); |
1007 | cpu68k_map_set(m68k_write8_map, 0x700000, 0x7fffff, PicoWrite8_plk3b, 1); |
e1e8ca17 |
1008 | carthw_lk3_regs.bank = 0; |
000f5335 |
1009 | } |
1010 | |
e1e8ca17 |
1011 | static void carthw_lk3_statef(void) |
000f5335 |
1012 | { |
81e3d012 |
1013 | int bank = carthw_lk3_regs.bank >> 15; |
1014 | carthw_lk3_regs.bank = -1; |
1015 | PicoWrite8_plk3b(0x700000, bank); |
e1e8ca17 |
1016 | } |
1017 | |
1018 | static void carthw_lk3_unload(void) |
1019 | { |
1020 | free(carthw_lk3_mem); |
1021 | carthw_lk3_mem = NULL; |
1022 | memset(carthw_lk3_madr, 0, sizeof(carthw_lk3_madr)); |
1023 | } |
000f5335 |
1024 | |
e1e8ca17 |
1025 | void carthw_lk3_startup(void) |
1026 | { |
000f5335 |
1027 | elprintf(EL_STATUS, "lk3 prot emu startup"); |
1028 | |
e1e8ca17 |
1029 | // allocate space for shadow copy |
1030 | if (carthw_lk3_mem == NULL) |
1031 | carthw_lk3_mem = malloc(0x100000); |
1032 | if (carthw_lk3_mem == NULL) { |
000f5335 |
1033 | elprintf(EL_STATUS, "OOM"); |
1034 | return; |
1035 | } |
000f5335 |
1036 | |
e1e8ca17 |
1037 | PicoCartMemSetup = carthw_lk3_mem_setup; |
1038 | PicoLoadStateHook = carthw_lk3_statef; |
1039 | PicoCartUnloadHook = carthw_lk3_unload; |
1040 | carthw_chunks = carthw_lk3_state; |
1041 | } |
1042 | |
1043 | /* SMW64 mapper, based on mame source */ |
1044 | static struct { |
1045 | u32 bank60, bank61; |
1046 | u16 data[8], ctrl[4]; |
1047 | } carthw_smw64_regs; |
1048 | |
1049 | static carthw_state_chunk carthw_smw64_state[] = |
1050 | { |
1051 | { CHUNK_CARTHW, sizeof(carthw_smw64_regs), &carthw_smw64_regs }, |
1052 | { 0, 0, NULL } |
1053 | }; |
1054 | |
1055 | static u32 PicoRead8_smw64(u32 a) |
1056 | { |
1057 | u16 *data = carthw_smw64_regs.data, *ctrl = carthw_smw64_regs.ctrl; |
1058 | u32 d = 0; |
1059 | |
1060 | if (a & 1) { |
1061 | if (a>>16 == 0x66) switch ((a>>1) & 7) { |
1062 | case 0: d = carthw_smw64_regs.data[0] ; break; |
1063 | case 1: d = carthw_smw64_regs.data[0]+1; break; |
1064 | case 2: d = carthw_smw64_regs.data[1] ; break; |
1065 | case 3: d = carthw_smw64_regs.data[1]+1; break; |
1066 | case 4: d = carthw_smw64_regs.data[2] ; break; |
1067 | case 5: d = carthw_smw64_regs.data[2]+1; break; |
1068 | case 6: d = carthw_smw64_regs.data[2]+2; break; |
1069 | case 7: d = carthw_smw64_regs.data[2]+3; break; |
1070 | } else /*0x67*/ { // :-O |
1071 | if (ctrl[1] & 0x80) |
1072 | d = ctrl[2] & 0x40 ? data[4]&data[5] : data[4]^0xff; |
1073 | if (a & 2) |
1074 | d &= 0x7f; |
1075 | else if (ctrl[2] & 0x80) { |
1076 | if (ctrl[2] & 0x20) |
1077 | data[2] = (data[5] << 2) & 0xfc; |
1078 | else |
1079 | data[0] = ((data[4] << 1) ^ data[3]) & 0xfe; |
1080 | } |
1081 | } |
1082 | } |
1083 | |
1084 | elprintf(EL_UIO, "prot r8 [%06x] %02x @%06x", a, d, SekPc); |
1085 | return d; |
1086 | } |
1087 | |
1088 | static u32 PicoRead16_smw64(u32 a) |
1089 | { |
1090 | return PicoRead8_smw64(a+1); |
1091 | } |
1092 | |
1093 | static void PicoWrite8_smw64(u32 a, u32 d) |
1094 | { |
1095 | u16 *data = carthw_smw64_regs.data, *ctrl = carthw_smw64_regs.ctrl; |
1096 | |
1097 | if ((a & 3) == 1) { |
1098 | switch (a >> 16) { |
1099 | case 0x60: ctrl[0] = d; break; |
1100 | case 0x64: data[4] = d; break; |
1101 | case 0x67: |
1102 | if (ctrl[1] & 0x80) { |
1103 | carthw_smw64_regs.bank60 = 0x80000 + ((d<<14) & 0x70000); |
1104 | cpu68k_map_set(m68k_read8_map, 0x600000, 0x60ffff, Pico.rom + carthw_smw64_regs.bank60, 0); |
1105 | cpu68k_map_set(m68k_read16_map, 0x600000, 0x60ffff, Pico.rom + carthw_smw64_regs.bank60, 0); |
1106 | } |
1107 | ctrl[2] = d; |
1108 | } |
1109 | } else if ((a & 3) == 3) { |
1110 | switch (a >> 16) { |
1111 | case 0x61: ctrl[1] = d; break; |
1112 | case 0x64: data[5] = d; break; |
1113 | case 0x60: |
1114 | switch (ctrl[0] & 7) { // :-O |
1115 | case 0: data[0] = (data[0]^data[3] ^ d) & 0xfe; break; |
1116 | case 1: data[1] = ( d) & 0xfe; break; |
1117 | case 7: |
1118 | carthw_smw64_regs.bank61 = 0x80000 + ((d<<14) & 0x70000); |
1119 | cpu68k_map_set(m68k_read8_map, 0x610000, 0x61ffff, Pico.rom + carthw_smw64_regs.bank61, 0); |
1120 | cpu68k_map_set(m68k_read16_map, 0x610000, 0x61ffff, Pico.rom + carthw_smw64_regs.bank61, 0); |
1121 | break; |
1122 | } |
1123 | data[3] = d; |
1124 | } |
1125 | } |
1126 | } |
1127 | |
1128 | static void PicoWrite16_smw64(u32 a, u32 d) |
1129 | { |
1130 | PicoWrite8_smw64(a+1, d); |
1131 | } |
1132 | |
1133 | static void carthw_smw64_mem_setup(void) |
1134 | { |
1135 | // 1st 512 KB mirrored |
1136 | cpu68k_map_set(m68k_read8_map, 0x080000, 0x0fffff, Pico.rom, 0); |
1137 | cpu68k_map_set(m68k_read16_map, 0x080000, 0x0fffff, Pico.rom, 0); |
1138 | |
1139 | cpu68k_map_set(m68k_read8_map, 0x660000, 0x67ffff, PicoRead8_smw64, 1); |
1140 | cpu68k_map_set(m68k_read16_map, 0x660000, 0x67ffff, PicoRead16_smw64, 1); |
1141 | cpu68k_map_set(m68k_write8_map, 0x600000, 0x67ffff, PicoWrite8_smw64, 1); |
1142 | cpu68k_map_set(m68k_write16_map, 0x600000, 0x67ffff, PicoWrite16_smw64, 1); |
1143 | } |
1144 | |
1145 | static void carthw_smw64_statef(void) |
1146 | { |
1147 | cpu68k_map_set(m68k_read8_map, 0x600000, 0x60ffff, Pico.rom + carthw_smw64_regs.bank60, 0); |
1148 | cpu68k_map_set(m68k_read16_map, 0x600000, 0x60ffff, Pico.rom + carthw_smw64_regs.bank60, 0); |
1149 | cpu68k_map_set(m68k_read8_map, 0x610000, 0x61ffff, Pico.rom + carthw_smw64_regs.bank61, 0); |
1150 | cpu68k_map_set(m68k_read16_map, 0x610000, 0x61ffff, Pico.rom + carthw_smw64_regs.bank61, 0); |
1151 | } |
1152 | |
1153 | static void carthw_smw64_reset(void) |
1154 | { |
1155 | memset(&carthw_smw64_regs, 0, sizeof(carthw_smw64_regs)); |
1156 | } |
1157 | |
1158 | void carthw_smw64_startup(void) |
1159 | { |
1160 | elprintf(EL_STATUS, "SMW64 mapper startup"); |
1161 | |
1162 | PicoCartMemSetup = carthw_smw64_mem_setup; |
1163 | PicoResetHook = carthw_smw64_reset; |
1164 | PicoLoadStateHook = carthw_smw64_statef; |
1165 | carthw_chunks = carthw_smw64_state; |
000f5335 |
1166 | } |
1167 | |
99bd61f8 |
1168 | /* J-Cart */ |
1169 | unsigned char carthw_jcart_th; |
1170 | |
1171 | static carthw_state_chunk carthw_jcart_state[] = |
1172 | { |
1173 | { CHUNK_CARTHW, sizeof(carthw_jcart_th), &carthw_jcart_th }, |
1174 | { 0, 0, NULL } |
1175 | }; |
1176 | |
1177 | static void carthw_jcart_write8(u32 a, u32 d) |
1178 | { |
1179 | carthw_jcart_th = (d&1) << 6; |
1180 | } |
1181 | |
1182 | static void carthw_jcart_write16(u32 a, u32 d) |
1183 | { |
1184 | carthw_jcart_write8(a+1, d); |
1185 | } |
1186 | |
1187 | static u32 carthw_jcart_read8(u32 a) |
1188 | { |
1189 | u32 v = PicoReadPad(2 + (a&1), 0x3f | carthw_jcart_th); |
1190 | // some carts additionally have an EEPROM; SDA is also readable in this range |
1191 | if (Pico.m.sram_reg & SRR_MAPPED) |
1192 | v |= EEPROM_read() & 0x80; // SDA is always on bit 7 for J-Carts |
1193 | return v; |
1194 | } |
1195 | |
1196 | static u32 carthw_jcart_read16(u32 a) |
1197 | { |
1198 | return carthw_jcart_read8(a) | (carthw_jcart_read8(a+1) << 8); |
1199 | } |
1200 | |
1201 | static void carthw_jcart_mem_setup(void) |
1202 | { |
1203 | cpu68k_map_set(m68k_write8_map, 0x380000, 0x3fffff, carthw_jcart_write8, 1); |
1204 | cpu68k_map_set(m68k_write16_map, 0x380000, 0x3fffff, carthw_jcart_write16, 1); |
1205 | cpu68k_map_set(m68k_read8_map, 0x380000, 0x3fffff, carthw_jcart_read8, 1); |
1206 | cpu68k_map_set(m68k_read16_map, 0x380000, 0x3fffff, carthw_jcart_read16, 1); |
1207 | } |
1208 | |
1209 | void carthw_jcart_startup(void) |
1210 | { |
1211 | elprintf(EL_STATUS, "J-Cart startup"); |
1212 | |
1213 | PicoCartMemSetup = carthw_jcart_mem_setup; |
1214 | carthw_chunks = carthw_jcart_state; |
1215 | } |
1216 | |
6a47c2d4 |
1217 | // vim:ts=2:sw=2:expandtab |