a12b1b29 |
1 | /* |
000f5335 |
2 | * Support for a few cart mappers and some protection. |
30f0fdd4 |
3 | * (C) notaz, 2008-2011 |
65ca3034 |
4 | * |
cff531af |
5 | * This work is licensed under the terms of MAME license. |
6 | * See COPYING file in the top-level directory. |
a12b1b29 |
7 | */ |
8 | |
efcba75f |
9 | #include "../pico_int.h" |
45f2f245 |
10 | #include "../memory.h" |
6a47c2d4 |
11 | #include "eeprom_spi.h" |
757f8dae |
12 | |
a12b1b29 |
13 | |
f5080654 |
14 | static int have_bank(u32 base) |
15 | { |
16 | // the loader allocs in 512K quantities |
17 | if (base >= Pico.romsize) { |
18 | elprintf(EL_ANOMALY|EL_STATUS, "carthw: missing bank @ %06x", base); |
19 | return 0; |
20 | } |
21 | return 1; |
22 | } |
23 | |
8b9dbcde |
24 | /* standard/ssf2 mapper */ |
25 | int carthw_ssf2_active; |
26 | unsigned char carthw_ssf2_banks[8]; |
000f5335 |
27 | |
28 | static carthw_state_chunk carthw_ssf2_state[] = |
29 | { |
8b9dbcde |
30 | { CHUNK_CARTHW, sizeof(carthw_ssf2_banks), &carthw_ssf2_banks }, |
31 | { 0, 0, NULL } |
000f5335 |
32 | }; |
33 | |
34 | static void carthw_ssf2_write8(u32 a, u32 d) |
35 | { |
8b9dbcde |
36 | u32 target, base; |
000f5335 |
37 | |
8b9dbcde |
38 | if ((a & 0xfffff0) != 0xa130f0) { |
39 | PicoWrite8_io(a, d); |
40 | return; |
41 | } |
000f5335 |
42 | |
8b9dbcde |
43 | a &= 0x0e; |
44 | if (a == 0) |
45 | return; |
46 | if (carthw_ssf2_banks[a >> 1] == d) |
47 | return; |
48 | |
49 | base = d << 19; |
50 | target = a << 18; |
51 | if (!have_bank(base)) |
52 | return; |
53 | carthw_ssf2_banks[a >> 1] = d; |
54 | |
55 | cpu68k_map_set(m68k_read8_map, target, target + 0x80000 - 1, Pico.rom + base, 0); |
56 | cpu68k_map_set(m68k_read16_map, target, target + 0x80000 - 1, Pico.rom + base, 0); |
57 | if (PicoIn.AHW & PAHW_32X) |
58 | p32x_update_banks(); |
000f5335 |
59 | } |
60 | |
61 | static void carthw_ssf2_mem_setup(void) |
62 | { |
8b9dbcde |
63 | cpu68k_map_set(m68k_write8_map, 0xa10000, 0xa1ffff, carthw_ssf2_write8, 1); |
000f5335 |
64 | } |
65 | |
66 | static void carthw_ssf2_statef(void) |
67 | { |
8b9dbcde |
68 | int i; |
69 | for (i = 1; i < 8; i++) |
70 | carthw_ssf2_write8(0xa130f0 | (i << 1), carthw_ssf2_banks[i]); |
71 | } |
72 | |
73 | static void carthw_ssf2_unload(void) |
74 | { |
75 | memset(carthw_ssf2_banks, 0, sizeof(carthw_ssf2_banks)); |
76 | carthw_ssf2_active = 0; |
000f5335 |
77 | } |
78 | |
79 | void carthw_ssf2_startup(void) |
80 | { |
8b9dbcde |
81 | int i; |
000f5335 |
82 | |
8b9dbcde |
83 | elprintf(EL_STATUS, "SSF2 mapper startup"); |
000f5335 |
84 | |
8b9dbcde |
85 | // default map |
86 | for (i = 0; i < 8; i++) |
87 | carthw_ssf2_banks[i] = i; |
000f5335 |
88 | |
8b9dbcde |
89 | PicoCartMemSetup = carthw_ssf2_mem_setup; |
90 | PicoLoadStateHook = carthw_ssf2_statef; |
91 | PicoCartUnloadHook = carthw_ssf2_unload; |
92 | carthw_chunks = carthw_ssf2_state; |
93 | carthw_ssf2_active = 1; |
000f5335 |
94 | } |
95 | |
96 | |
45f2f245 |
97 | /* Common *-in-1 pirate mapper. |
98 | * Switches banks based on addr lines when /TIME is set. |
99 | * TODO: verify |
100 | */ |
101 | static unsigned int carthw_Xin1_baddr = 0; |
757f8dae |
102 | |
45f2f245 |
103 | static void carthw_Xin1_do(u32 a, int mask, int shift) |
757f8dae |
104 | { |
105 | int len; |
106 | |
45f2f245 |
107 | carthw_Xin1_baddr = a; |
108 | a &= mask; |
109 | a <<= shift; |
757f8dae |
110 | len = Pico.romsize - a; |
111 | if (len <= 0) { |
45f2f245 |
112 | elprintf(EL_ANOMALY|EL_STATUS, "X-in-1: missing bank @ %06x", a); |
757f8dae |
113 | return; |
114 | } |
115 | |
45f2f245 |
116 | len = (len + M68K_BANK_MASK) & ~M68K_BANK_MASK; |
117 | cpu68k_map_set(m68k_read8_map, 0x000000, len - 1, Pico.rom + a, 0); |
118 | cpu68k_map_set(m68k_read16_map, 0x000000, len - 1, Pico.rom + a, 0); |
757f8dae |
119 | } |
120 | |
45f2f245 |
121 | static carthw_state_chunk carthw_Xin1_state[] = |
757f8dae |
122 | { |
45f2f245 |
123 | { CHUNK_CARTHW, sizeof(carthw_Xin1_baddr), &carthw_Xin1_baddr }, |
124 | { 0, 0, NULL } |
125 | }; |
126 | |
127 | // TODO: test a0, reads, w16 |
128 | static void carthw_Xin1_write8(u32 a, u32 d) |
129 | { |
130 | if ((a & 0xffff00) != 0xa13000) { |
131 | PicoWrite8_io(a, d); |
132 | return; |
133 | } |
134 | |
135 | carthw_Xin1_do(a, 0x3f, 16); |
757f8dae |
136 | } |
137 | |
45f2f245 |
138 | static void carthw_Xin1_mem_setup(void) |
bdec53c9 |
139 | { |
45f2f245 |
140 | cpu68k_map_set(m68k_write8_map, 0xa10000, 0xa1ffff, carthw_Xin1_write8, 1); |
bdec53c9 |
141 | } |
142 | |
45f2f245 |
143 | static void carthw_Xin1_reset(void) |
757f8dae |
144 | { |
45f2f245 |
145 | carthw_Xin1_write8(0xa13000, 0); |
146 | } |
757f8dae |
147 | |
45f2f245 |
148 | static void carthw_Xin1_statef(void) |
149 | { |
150 | carthw_Xin1_write8(carthw_Xin1_baddr, 0); |
151 | } |
757f8dae |
152 | |
45f2f245 |
153 | void carthw_Xin1_startup(void) |
154 | { |
155 | elprintf(EL_STATUS, "X-in-1 mapper startup"); |
757f8dae |
156 | |
45f2f245 |
157 | PicoCartMemSetup = carthw_Xin1_mem_setup; |
158 | PicoResetHook = carthw_Xin1_reset; |
159 | PicoLoadStateHook = carthw_Xin1_statef; |
160 | carthw_chunks = carthw_Xin1_state; |
757f8dae |
161 | } |
162 | |
a12b1b29 |
163 | |
164 | /* Realtec, based on TascoDLX doc |
165 | * http://www.sharemation.com/TascoDLX/REALTEC%20Cart%20Mapper%20-%20description%20v1.txt |
166 | */ |
167 | static int realtec_bank = 0x80000000, realtec_size = 0x80000000; |
a12b1b29 |
168 | |
45f2f245 |
169 | static void carthw_realtec_write8(u32 a, u32 d) |
a12b1b29 |
170 | { |
171 | int i, bank_old = realtec_bank, size_old = realtec_size; |
172 | |
173 | if (a == 0x400000) |
174 | { |
175 | realtec_bank &= 0x0e0000; |
176 | realtec_bank |= 0x300000 & (d << 19); |
177 | if (realtec_bank != bank_old) |
178 | elprintf(EL_ANOMALY, "write [%06x] %02x @ %06x", a, d, SekPc); |
179 | } |
180 | else if (a == 0x402000) |
181 | { |
182 | realtec_size = (d << 17) & 0x3e0000; |
183 | if (realtec_size != size_old) |
184 | elprintf(EL_ANOMALY, "write [%06x] %02x @ %06x", a, d, SekPc); |
185 | } |
186 | else if (a == 0x404000) |
187 | { |
188 | realtec_bank &= 0x300000; |
189 | realtec_bank |= 0x0e0000 & (d << 17); |
190 | if (realtec_bank != bank_old) |
191 | elprintf(EL_ANOMALY, "write [%06x] %02x @ %06x", a, d, SekPc); |
192 | } |
193 | else |
194 | elprintf(EL_ANOMALY, "realtec: unexpected write [%06x] %02x @ %06x", a, d, SekPc); |
65ca3034 |
195 | |
a12b1b29 |
196 | if (realtec_bank >= 0 && realtec_size >= 0 && |
197 | (realtec_bank != bank_old || realtec_size != size_old)) |
198 | { |
199 | elprintf(EL_ANOMALY, "realtec: new bank %06x, size %06x", realtec_bank, realtec_size, SekPc); |
45f2f245 |
200 | if (realtec_size > Pico.romsize - realtec_bank) |
a12b1b29 |
201 | { |
202 | elprintf(EL_ANOMALY, "realtec: bank too large / out of range?"); |
203 | return; |
204 | } |
205 | |
45f2f245 |
206 | for (i = 0; i < 0x400000; i += realtec_size) { |
207 | cpu68k_map_set(m68k_read8_map, i, realtec_size - 1, Pico.rom + realtec_bank, 0); |
208 | cpu68k_map_set(m68k_read16_map, i, realtec_size - 1, Pico.rom + realtec_bank, 0); |
209 | } |
a12b1b29 |
210 | } |
211 | } |
212 | |
0b35350d |
213 | static void carthw_realtec_reset(void) |
a12b1b29 |
214 | { |
215 | int i; |
45f2f245 |
216 | |
a12b1b29 |
217 | /* map boot code */ |
45f2f245 |
218 | for (i = 0; i < 0x400000; i += M68K_BANK_SIZE) { |
219 | cpu68k_map_set(m68k_read8_map, i, i + M68K_BANK_SIZE - 1, Pico.rom + Pico.romsize, 0); |
220 | cpu68k_map_set(m68k_read16_map, i, i + M68K_BANK_SIZE - 1, Pico.rom + Pico.romsize, 0); |
221 | } |
222 | cpu68k_map_set(m68k_write8_map, 0x400000, 0x400000 + M68K_BANK_SIZE - 1, carthw_realtec_write8, 1); |
a12b1b29 |
223 | realtec_bank = realtec_size = 0x80000000; |
224 | } |
225 | |
226 | void carthw_realtec_startup(void) |
227 | { |
45f2f245 |
228 | int i; |
a12b1b29 |
229 | |
45f2f245 |
230 | elprintf(EL_STATUS, "Realtec mapper startup"); |
a12b1b29 |
231 | |
45f2f245 |
232 | // allocate additional bank for boot code |
233 | // (we know those ROMs have aligned size) |
a736af3e |
234 | i = PicoCartResize(Pico.romsize + M68K_BANK_SIZE); |
235 | if (i != 0) { |
a12b1b29 |
236 | elprintf(EL_STATUS, "OOM"); |
237 | return; |
238 | } |
a12b1b29 |
239 | |
45f2f245 |
240 | // create bank for boot code |
241 | for (i = 0; i < M68K_BANK_SIZE; i += 0x2000) |
242 | memcpy(Pico.rom + Pico.romsize + i, Pico.rom + Pico.romsize - 0x2000, 0x2000); |
243 | |
a12b1b29 |
244 | PicoResetHook = carthw_realtec_reset; |
245 | } |
246 | |
0b35350d |
247 | /* Radica mapper, based on DevSter's info |
248 | * http://devster.monkeeh.com/sega/radica/ |
45f2f245 |
249 | * XXX: mostly the same as X-in-1, merge? |
0b35350d |
250 | */ |
45f2f245 |
251 | static u32 carthw_radica_read16(u32 a) |
0b35350d |
252 | { |
45f2f245 |
253 | if ((a & 0xffff00) != 0xa13000) |
254 | return PicoRead16_io(a); |
0b35350d |
255 | |
45f2f245 |
256 | carthw_Xin1_do(a, 0x7e, 15); |
0b35350d |
257 | |
258 | return 0; |
259 | } |
260 | |
45f2f245 |
261 | static void carthw_radica_mem_setup(void) |
262 | { |
263 | cpu68k_map_set(m68k_read16_map, 0xa10000, 0xa1ffff, carthw_radica_read16, 1); |
264 | } |
265 | |
0b35350d |
266 | static void carthw_radica_statef(void) |
267 | { |
45f2f245 |
268 | carthw_radica_read16(carthw_Xin1_baddr); |
0b35350d |
269 | } |
270 | |
271 | static void carthw_radica_reset(void) |
272 | { |
45f2f245 |
273 | carthw_radica_read16(0xa13000); |
0b35350d |
274 | } |
275 | |
276 | void carthw_radica_startup(void) |
277 | { |
45f2f245 |
278 | elprintf(EL_STATUS, "Radica mapper startup"); |
0b35350d |
279 | |
45f2f245 |
280 | PicoCartMemSetup = carthw_radica_mem_setup; |
281 | PicoResetHook = carthw_radica_reset; |
0b35350d |
282 | PicoLoadStateHook = carthw_radica_statef; |
45f2f245 |
283 | carthw_chunks = carthw_Xin1_state; |
0b35350d |
284 | } |
285 | |
30f0fdd4 |
286 | |
287 | /* Pier Solar. Based on my own research */ |
288 | static unsigned char pier_regs[8]; |
289 | static unsigned char pier_dump_prot; |
290 | |
291 | static carthw_state_chunk carthw_pier_state[] = |
292 | { |
293 | { CHUNK_CARTHW, sizeof(pier_regs), pier_regs }, |
294 | { CHUNK_CARTHW + 1, sizeof(pier_dump_prot), &pier_dump_prot }, |
6a47c2d4 |
295 | { CHUNK_CARTHW + 2, 0, NULL }, // filled later |
30f0fdd4 |
296 | { 0, 0, NULL } |
297 | }; |
298 | |
299 | static void carthw_pier_write8(u32 a, u32 d) |
300 | { |
301 | u32 a8, target, base; |
302 | |
303 | if ((a & 0xffff00) != 0xa13000) { |
304 | PicoWrite8_io(a, d); |
305 | return; |
306 | } |
307 | |
308 | a8 = a & 0x0f; |
309 | pier_regs[a8 / 2] = d; |
310 | |
311 | elprintf(EL_UIO, "pier w8 [%06x] %02x @%06x", a, d & 0xffff, SekPc); |
312 | switch (a8) { |
313 | case 0x01: |
314 | break; |
315 | case 0x03: |
316 | if (!(pier_regs[0] & 2)) |
317 | goto unmapped; |
318 | target = 0x280000; |
319 | base = d << 19; |
320 | goto do_map; |
321 | case 0x05: |
322 | if (!(pier_regs[0] & 2)) |
323 | goto unmapped; |
324 | target = 0x300000; |
325 | base = d << 19; |
326 | goto do_map; |
327 | case 0x07: |
328 | if (!(pier_regs[0] & 2)) |
329 | goto unmapped; |
330 | target = 0x380000; |
331 | base = d << 19; |
332 | goto do_map; |
333 | case 0x09: |
88fd63ad |
334 | Pico.sv.changed = 1; |
6a47c2d4 |
335 | eeprom_spi_write(d); |
30f0fdd4 |
336 | break; |
337 | case 0x0b: |
338 | // eeprom read |
339 | default: |
340 | unmapped: |
341 | //elprintf(EL_UIO, "pier w8 [%06x] %02x @%06x", a, d & 0xffff, SekPc); |
342 | elprintf(EL_STATUS, "-- unmapped w8 [%06x] %02x @%06x", a, d & 0xffff, SekPc); |
343 | break; |
344 | } |
345 | return; |
346 | |
347 | do_map: |
f5080654 |
348 | if (!have_bank(base)) |
30f0fdd4 |
349 | return; |
f5080654 |
350 | |
30f0fdd4 |
351 | cpu68k_map_set(m68k_read8_map, target, target + 0x80000 - 1, Pico.rom + base, 0); |
352 | cpu68k_map_set(m68k_read16_map, target, target + 0x80000 - 1, Pico.rom + base, 0); |
353 | } |
354 | |
355 | static void carthw_pier_write16(u32 a, u32 d) |
356 | { |
357 | if ((a & 0xffff00) != 0xa13000) { |
358 | PicoWrite16_io(a, d); |
359 | return; |
360 | } |
361 | |
362 | elprintf(EL_UIO, "pier w16 [%06x] %04x @%06x", a, d & 0xffff, SekPc); |
363 | carthw_pier_write8(a + 1, d); |
364 | } |
365 | |
366 | static u32 carthw_pier_read8(u32 a) |
367 | { |
368 | if ((a & 0xffff00) != 0xa13000) |
369 | return PicoRead8_io(a); |
370 | |
371 | if (a == 0xa1300b) |
6a47c2d4 |
372 | return eeprom_spi_read(a); |
30f0fdd4 |
373 | |
374 | elprintf(EL_UIO, "pier r8 [%06x] @%06x", a, SekPc); |
375 | return 0; |
376 | } |
377 | |
378 | static void carthw_pier_statef(void); |
379 | |
380 | static u32 carthw_pier_prot_read8(u32 a) |
381 | { |
382 | /* it takes more than just these reads here to disable ROM protection, |
383 | * but for game emulation purposes this is enough. */ |
384 | if (pier_dump_prot > 0) |
385 | pier_dump_prot--; |
386 | if (pier_dump_prot == 0) { |
387 | carthw_pier_statef(); |
388 | elprintf(EL_STATUS, "prot off on r8 @%06x", SekPc); |
389 | } |
390 | elprintf(EL_UIO, "pier r8 [%06x] @%06x", a, SekPc); |
391 | |
392 | return Pico.rom[(a & 0x7fff) ^ 1]; |
393 | } |
394 | |
395 | static void carthw_pier_mem_setup(void) |
396 | { |
397 | cpu68k_map_set(m68k_write8_map, 0xa10000, 0xa1ffff, carthw_pier_write8, 1); |
398 | cpu68k_map_set(m68k_write16_map, 0xa10000, 0xa1ffff, carthw_pier_write16, 1); |
399 | cpu68k_map_set(m68k_read8_map, 0xa10000, 0xa1ffff, carthw_pier_read8, 1); |
400 | } |
401 | |
402 | static void carthw_pier_prot_mem_setup(int prot_enable) |
403 | { |
404 | if (prot_enable) { |
405 | /* the dump protection.. */ |
406 | int a; |
407 | for (a = 0x000000; a < 0x400000; a += M68K_BANK_SIZE) { |
408 | cpu68k_map_set(m68k_read8_map, a, a + 0xffff, Pico.rom + Pico.romsize, 0); |
409 | cpu68k_map_set(m68k_read16_map, a, a + 0xffff, Pico.rom + Pico.romsize, 0); |
410 | } |
411 | cpu68k_map_set(m68k_read8_map, M68K_BANK_SIZE, M68K_BANK_SIZE * 2 - 1, |
412 | carthw_pier_prot_read8, 1); |
413 | } |
414 | else { |
415 | cpu68k_map_set(m68k_read8_map, 0, 0x27ffff, Pico.rom, 0); |
416 | cpu68k_map_set(m68k_read16_map, 0, 0x27ffff, Pico.rom, 0); |
417 | } |
418 | } |
419 | |
420 | static void carthw_pier_statef(void) |
421 | { |
422 | carthw_pier_prot_mem_setup(pier_dump_prot); |
423 | |
424 | if (!pier_dump_prot) { |
425 | /* setup all banks */ |
426 | u32 r0 = pier_regs[0]; |
427 | carthw_pier_write8(0xa13001, 3); |
428 | carthw_pier_write8(0xa13003, pier_regs[1]); |
429 | carthw_pier_write8(0xa13005, pier_regs[2]); |
430 | carthw_pier_write8(0xa13007, pier_regs[3]); |
431 | carthw_pier_write8(0xa13001, r0); |
432 | } |
433 | } |
434 | |
435 | static void carthw_pier_reset(void) |
436 | { |
437 | pier_regs[0] = 1; |
438 | pier_regs[1] = pier_regs[2] = pier_regs[3] = 0; |
30f0fdd4 |
439 | carthw_pier_statef(); |
6a47c2d4 |
440 | eeprom_spi_init(NULL); |
30f0fdd4 |
441 | } |
442 | |
443 | void carthw_pier_startup(void) |
444 | { |
6a47c2d4 |
445 | void *eeprom_state; |
446 | int eeprom_size = 0; |
30f0fdd4 |
447 | int i; |
448 | |
449 | elprintf(EL_STATUS, "Pier Solar mapper startup"); |
450 | |
451 | // mostly same as for realtec.. |
452 | i = PicoCartResize(Pico.romsize + M68K_BANK_SIZE); |
453 | if (i != 0) { |
454 | elprintf(EL_STATUS, "OOM"); |
455 | return; |
456 | } |
457 | |
2b46e6c1 |
458 | pier_dump_prot = 3; |
459 | |
30f0fdd4 |
460 | // create dump protection bank |
461 | for (i = 0; i < M68K_BANK_SIZE; i += 0x8000) |
462 | memcpy(Pico.rom + Pico.romsize + i, Pico.rom, 0x8000); |
463 | |
6a47c2d4 |
464 | // save EEPROM |
465 | eeprom_state = eeprom_spi_init(&eeprom_size); |
88fd63ad |
466 | Pico.sv.flags = 0; |
467 | Pico.sv.size = 0x10000; |
468 | Pico.sv.data = calloc(1, Pico.sv.size); |
469 | if (!Pico.sv.data) |
470 | Pico.sv.size = 0; |
6a47c2d4 |
471 | carthw_pier_state[2].ptr = eeprom_state; |
472 | carthw_pier_state[2].size = eeprom_size; |
473 | |
30f0fdd4 |
474 | PicoCartMemSetup = carthw_pier_mem_setup; |
475 | PicoResetHook = carthw_pier_reset; |
476 | PicoLoadStateHook = carthw_pier_statef; |
477 | carthw_chunks = carthw_pier_state; |
478 | } |
479 | |
000f5335 |
480 | /* Simple unlicensed ROM protection emulation */ |
481 | static struct { |
30f0fdd4 |
482 | u32 addr; |
483 | u32 mask; |
484 | u16 val; |
485 | u16 readonly; |
000f5335 |
486 | } *sprot_items; |
487 | static int sprot_item_alloc; |
488 | static int sprot_item_count; |
489 | |
490 | static u16 *carthw_sprot_get_val(u32 a, int rw_only) |
491 | { |
30f0fdd4 |
492 | int i; |
493 | |
494 | for (i = 0; i < sprot_item_count; i++) |
495 | if ((a & sprot_items[i].mask) == sprot_items[i].addr) |
496 | if (!rw_only || !sprot_items[i].readonly) |
497 | return &sprot_items[i].val; |
000f5335 |
498 | |
30f0fdd4 |
499 | return NULL; |
000f5335 |
500 | } |
501 | |
502 | static u32 PicoRead8_sprot(u32 a) |
503 | { |
504 | u16 *val; |
505 | u32 d; |
506 | |
507 | if (0xa10000 <= a && a < 0xa12000) |
508 | return PicoRead8_io(a); |
509 | |
510 | val = carthw_sprot_get_val(a, 0); |
511 | if (val != NULL) { |
512 | d = *val; |
513 | if (!(a & 1)) |
514 | d >>= 8; |
515 | elprintf(EL_UIO, "prot r8 [%06x] %02x @%06x", a, d, SekPc); |
516 | return d; |
517 | } |
518 | else { |
519 | elprintf(EL_UIO, "prot r8 [%06x] MISS @%06x", a, SekPc); |
520 | return 0; |
521 | } |
522 | } |
523 | |
524 | static u32 PicoRead16_sprot(u32 a) |
525 | { |
526 | u16 *val; |
527 | |
528 | if (0xa10000 <= a && a < 0xa12000) |
529 | return PicoRead16_io(a); |
530 | |
531 | val = carthw_sprot_get_val(a, 0); |
532 | if (val != NULL) { |
533 | elprintf(EL_UIO, "prot r16 [%06x] %04x @%06x", a, *val, SekPc); |
534 | return *val; |
535 | } |
536 | else { |
537 | elprintf(EL_UIO, "prot r16 [%06x] MISS @%06x", a, SekPc); |
538 | return 0; |
539 | } |
540 | } |
541 | |
542 | static void PicoWrite8_sprot(u32 a, u32 d) |
543 | { |
544 | u16 *val; |
545 | |
546 | if (0xa10000 <= a && a < 0xa12000) { |
547 | PicoWrite8_io(a, d); |
548 | return; |
549 | } |
550 | |
551 | val = carthw_sprot_get_val(a, 1); |
552 | if (val != NULL) { |
553 | if (a & 1) |
554 | *val = (*val & 0xff00) | (d | 0xff); |
555 | else |
556 | *val = (*val & 0x00ff) | (d << 8); |
557 | elprintf(EL_UIO, "prot w8 [%06x] %02x @%06x", a, d & 0xff, SekPc); |
558 | } |
559 | else |
560 | elprintf(EL_UIO, "prot w8 [%06x] %02x MISS @%06x", a, d & 0xff, SekPc); |
561 | } |
562 | |
563 | static void PicoWrite16_sprot(u32 a, u32 d) |
564 | { |
565 | u16 *val; |
566 | |
567 | if (0xa10000 <= a && a < 0xa12000) { |
568 | PicoWrite16_io(a, d); |
569 | return; |
570 | } |
571 | |
572 | val = carthw_sprot_get_val(a, 1); |
573 | if (val != NULL) { |
574 | *val = d; |
575 | elprintf(EL_UIO, "prot w16 [%06x] %04x @%06x", a, d & 0xffff, SekPc); |
576 | } |
577 | else |
578 | elprintf(EL_UIO, "prot w16 [%06x] %04x MISS @%06x", a, d & 0xffff, SekPc); |
579 | } |
580 | |
581 | void carthw_sprot_new_location(unsigned int a, unsigned int mask, unsigned short val, int is_ro) |
582 | { |
583 | if (sprot_items == NULL) { |
584 | sprot_items = calloc(8, sizeof(sprot_items[0])); |
585 | sprot_item_alloc = 8; |
586 | sprot_item_count = 0; |
587 | } |
588 | |
589 | if (sprot_item_count == sprot_item_alloc) { |
590 | void *tmp; |
591 | sprot_item_alloc *= 2; |
592 | tmp = realloc(sprot_items, sprot_item_alloc); |
593 | if (tmp == NULL) { |
594 | elprintf(EL_STATUS, "OOM"); |
595 | return; |
596 | } |
597 | sprot_items = tmp; |
598 | } |
599 | |
600 | sprot_items[sprot_item_count].addr = a; |
601 | sprot_items[sprot_item_count].mask = mask; |
602 | sprot_items[sprot_item_count].val = val; |
603 | sprot_items[sprot_item_count].readonly = is_ro; |
604 | sprot_item_count++; |
605 | } |
606 | |
607 | static void carthw_sprot_unload(void) |
608 | { |
609 | free(sprot_items); |
610 | sprot_items = NULL; |
611 | sprot_item_count = sprot_item_alloc = 0; |
612 | } |
613 | |
614 | static void carthw_sprot_mem_setup(void) |
615 | { |
616 | int start; |
617 | |
618 | // map ROM - 0x7fffff, /TIME areas (which are tipically used) |
619 | start = (Pico.romsize + M68K_BANK_MASK) & ~M68K_BANK_MASK; |
620 | cpu68k_map_set(m68k_read8_map, start, 0x7fffff, PicoRead8_sprot, 1); |
621 | cpu68k_map_set(m68k_read16_map, start, 0x7fffff, PicoRead16_sprot, 1); |
622 | cpu68k_map_set(m68k_write8_map, start, 0x7fffff, PicoWrite8_sprot, 1); |
623 | cpu68k_map_set(m68k_write16_map, start, 0x7fffff, PicoWrite16_sprot, 1); |
624 | |
625 | cpu68k_map_set(m68k_read8_map, 0xa10000, 0xa1ffff, PicoRead8_sprot, 1); |
626 | cpu68k_map_set(m68k_read16_map, 0xa10000, 0xa1ffff, PicoRead16_sprot, 1); |
627 | cpu68k_map_set(m68k_write8_map, 0xa10000, 0xa1ffff, PicoWrite8_sprot, 1); |
628 | cpu68k_map_set(m68k_write16_map, 0xa10000, 0xa1ffff, PicoWrite16_sprot, 1); |
629 | } |
630 | |
631 | void carthw_sprot_startup(void) |
632 | { |
633 | elprintf(EL_STATUS, "Prot emu startup"); |
634 | |
635 | PicoCartMemSetup = carthw_sprot_mem_setup; |
636 | PicoCartUnloadHook = carthw_sprot_unload; |
637 | } |
638 | |
639 | /* Protection emulation for Lion King 3. Credits go to Haze */ |
640 | static u8 prot_lk3_cmd, prot_lk3_data; |
641 | |
642 | static u32 PicoRead8_plk3(u32 a) |
643 | { |
644 | u32 d = 0; |
645 | switch (prot_lk3_cmd) { |
646 | case 1: d = prot_lk3_data >> 1; break; |
647 | case 2: // nibble rotate |
648 | d = ((prot_lk3_data >> 4) | (prot_lk3_data << 4)) & 0xff; |
649 | break; |
650 | case 3: // bit rotate |
651 | d = prot_lk3_data; |
652 | d = (d >> 4) | (d << 4); |
653 | d = ((d & 0xcc) >> 2) | ((d & 0x33) << 2); |
654 | d = ((d & 0xaa) >> 1) | ((d & 0x55) << 1); |
655 | break; |
656 | /* Top Fighter 2000 MK VIII (Unl) |
657 | case 0x98: d = 0x50; break; // prot_lk3_data == a8 here |
658 | case 0x67: d = 0xde; break; // prot_lk3_data == 7b here (rot!) |
659 | case 0xb5: d = 0x9f; break; // prot_lk3_data == 4a |
660 | */ |
661 | default: |
662 | elprintf(EL_UIO, "unhandled prot cmd %02x @%06x", prot_lk3_cmd, SekPc); |
663 | break; |
664 | } |
665 | |
666 | elprintf(EL_UIO, "prot r8 [%06x] %02x @%06x", a, d, SekPc); |
667 | return d; |
668 | } |
669 | |
670 | static void PicoWrite8_plk3p(u32 a, u32 d) |
671 | { |
672 | elprintf(EL_UIO, "prot w8 [%06x] %02x @%06x", a, d & 0xff, SekPc); |
673 | if (a & 2) |
674 | prot_lk3_cmd = d; |
675 | else |
676 | prot_lk3_data = d; |
677 | } |
678 | |
679 | static void PicoWrite8_plk3b(u32 a, u32 d) |
680 | { |
681 | int addr; |
682 | |
683 | elprintf(EL_UIO, "prot w8 [%06x] %02x @%06x", a, d & 0xff, SekPc); |
684 | addr = d << 15; |
685 | if (addr + 0x8000 > Pico.romsize) { |
686 | elprintf(EL_UIO|EL_ANOMALY, "prot_lk3: bank too large: %02x", d); |
687 | return; |
688 | } |
689 | if (addr == 0) |
690 | memcpy(Pico.rom, Pico.rom + Pico.romsize, 0x8000); |
691 | else |
692 | memcpy(Pico.rom, Pico.rom + addr, 0x8000); |
693 | } |
694 | |
695 | static void carthw_prot_lk3_mem_setup(void) |
696 | { |
697 | cpu68k_map_set(m68k_read8_map, 0x600000, 0x7fffff, PicoRead8_plk3, 1); |
698 | cpu68k_map_set(m68k_write8_map, 0x600000, 0x6fffff, PicoWrite8_plk3p, 1); |
699 | cpu68k_map_set(m68k_write8_map, 0x700000, 0x7fffff, PicoWrite8_plk3b, 1); |
700 | } |
701 | |
702 | void carthw_prot_lk3_startup(void) |
703 | { |
a736af3e |
704 | int ret; |
000f5335 |
705 | |
706 | elprintf(EL_STATUS, "lk3 prot emu startup"); |
707 | |
708 | // allocate space for bank0 backup |
a736af3e |
709 | ret = PicoCartResize(Pico.romsize + 0x8000); |
710 | if (ret != 0) { |
000f5335 |
711 | elprintf(EL_STATUS, "OOM"); |
712 | return; |
713 | } |
000f5335 |
714 | memcpy(Pico.rom + Pico.romsize, Pico.rom, 0x8000); |
715 | |
716 | PicoCartMemSetup = carthw_prot_lk3_mem_setup; |
717 | } |
718 | |
6a47c2d4 |
719 | // vim:ts=2:sw=2:expandtab |