be2c4208 |
1 | #include "../pico_int.h" |
2 | #include "../memory.h" |
3 | |
4 | static const char str_mars[] = "MARS"; |
5 | |
974fdb5b |
6 | struct Pico32xMem *Pico32xMem; |
7 | |
5e49c3a8 |
8 | static void bank_switch(int b); |
9 | |
974fdb5b |
10 | // SH2 faking |
11 | static const u16 comm_fakevals[] = { |
12 | 0x4d5f, 0x4f4b, // M_OK |
13 | 0x535f, 0x4f4b, // S_OK |
5e49c3a8 |
14 | 0x4D41, 0x5346, // MASF - Brutal Unleashed |
15 | 0x5331, 0x4d31, // Darxide |
16 | 0x5332, 0x4d32, |
17 | 0x5333, 0x4d33, |
18 | 0x0000, 0x0000, // eq for doom |
974fdb5b |
19 | 0x0002, // Mortal Kombat |
20 | 0, // pad |
be2c4208 |
21 | }; |
5e49c3a8 |
22 | int p32x_csum_faked; |
be2c4208 |
23 | |
be2c4208 |
24 | static u32 p32x_reg_read16(u32 a) |
25 | { |
26 | a &= 0x3e; |
27 | |
974fdb5b |
28 | // SH2 faker |
29 | if ((a & 0x30) == 0x20) |
30 | { |
5e49c3a8 |
31 | static int f = 0; |
32 | if (a == 0x28 && !p32x_csum_faked) { |
33 | p32x_csum_faked = 1; |
974fdb5b |
34 | return *(unsigned short *)(Pico.rom + 0x18e); |
35 | } |
36 | if (f >= sizeof(comm_fakevals) / sizeof(comm_fakevals[0])) |
37 | f = 0; |
38 | return comm_fakevals[f++]; |
39 | } |
40 | |
be2c4208 |
41 | return Pico32x.regs[a / 2]; |
42 | } |
43 | |
be2c4208 |
44 | static void p32x_reg_write8(u32 a, u32 d) |
45 | { |
46 | a &= 0x3f; |
47 | |
48 | if (a == 1 && !(Pico32x.regs[0] & 1)) { |
49 | Pico32x.regs[0] |= 1; |
50 | Pico32xStartup(); |
51 | return; |
52 | } |
5e49c3a8 |
53 | |
54 | if (!(Pico32x.regs[0] & 1)) |
55 | return; |
56 | |
57 | if (a == 5) { |
58 | d &= 7; |
59 | if (Pico32x.regs[4/2] != d) { |
60 | Pico32x.regs[4/2] = d; |
61 | bank_switch(d); |
62 | return; |
63 | } |
64 | } |
65 | } |
66 | |
67 | static void p32x_reg_write16(u32 a, u32 d) |
68 | { |
69 | p32x_reg_write8(a + 1, d); |
be2c4208 |
70 | } |
71 | |
72 | // VDP regs |
73 | static u32 p32x_vdp_read16(u32 a) |
74 | { |
75 | a &= 0x0e; |
76 | |
77 | return Pico32x.vdp_regs[a / 2]; |
78 | } |
79 | |
be2c4208 |
80 | static void p32x_vdp_write8(u32 a, u32 d) |
81 | { |
974fdb5b |
82 | u16 *r = Pico32x.vdp_regs; |
be2c4208 |
83 | a &= 0x0f; |
84 | |
974fdb5b |
85 | // TODO: verify what's writeable |
be2c4208 |
86 | switch (a) { |
974fdb5b |
87 | case 0x01: |
88 | if (((r[0] & 3) == 0) != ((d & 3) == 0)) { // forced blanking changed |
89 | if (Pico.video.status & 8) |
90 | r[0x0a/2] |= P32XV_VBLK; |
91 | else |
92 | r[0x0a/2] &= ~P32XV_VBLK; |
93 | } |
5e49c3a8 |
94 | // priority inversion is handled in palette |
95 | if ((r[0] ^ d) & P32XV_PRI) |
96 | Pico32x.dirty_pal = 1; |
974fdb5b |
97 | r[0] = (r[0] & P32XV_nPAL) | (d & 0xff); |
98 | break; |
be2c4208 |
99 | case 0x0b: |
974fdb5b |
100 | d &= 1; |
101 | Pico32x.pending_fb = d; |
102 | // if we are blanking and FS bit is changing |
103 | if ((r[0x0a/2] & P32XV_VBLK) && ((r[0x0a/2] ^ d) & P32XV_FS)) { |
104 | r[0x0a/2] ^= 1; |
105 | Pico32xSwapDRAM(d ^ 1); |
be2c4208 |
106 | } |
107 | break; |
108 | } |
109 | } |
110 | |
974fdb5b |
111 | static void p32x_vdp_write16(u32 a, u32 d) |
112 | { |
113 | p32x_vdp_write8(a | 1, d); |
114 | } |
115 | |
be2c4208 |
116 | // default 32x handlers |
117 | u32 PicoRead8_32x(u32 a) |
118 | { |
119 | u32 d = 0; |
120 | if ((a & 0xffc0) == 0x5100) { // a15100 |
121 | d = p32x_reg_read16(a); |
122 | goto out_16to8; |
123 | } |
124 | |
974fdb5b |
125 | if (!(Pico32x.regs[0] & 1)) |
126 | goto no_vdp; |
127 | |
128 | if ((a & 0xfff0) == 0x5180) { // a15180 |
be2c4208 |
129 | d = p32x_vdp_read16(a); |
130 | goto out_16to8; |
131 | } |
132 | |
974fdb5b |
133 | if ((a & 0xfe00) == 0x5200) { // a15200 |
134 | d = Pico32xMem->pal[(a & 0x1ff) / 2]; |
135 | goto out_16to8; |
136 | } |
137 | |
138 | no_vdp: |
be2c4208 |
139 | if ((a & 0xfffc) == 0x30ec) { // a130ec |
140 | d = str_mars[a & 3]; |
141 | goto out; |
142 | } |
143 | |
144 | elprintf(EL_UIO, "m68k unmapped r8 [%06x] @%06x", a, SekPc); |
145 | return d; |
146 | |
147 | out_16to8: |
148 | if (a & 1) |
149 | d &= 0xff; |
150 | else |
151 | d >>= 8; |
152 | |
153 | out: |
154 | elprintf(EL_32X, "m68k 32x r8 [%06x] %02x @%06x", a, d, SekPc); |
155 | return d; |
156 | } |
157 | |
158 | u32 PicoRead16_32x(u32 a) |
159 | { |
160 | u32 d = 0; |
161 | if ((a & 0xffc0) == 0x5100) { // a15100 |
162 | d = p32x_reg_read16(a); |
163 | goto out; |
164 | } |
165 | |
974fdb5b |
166 | if (!(Pico32x.regs[0] & 1)) |
167 | goto no_vdp; |
168 | |
169 | if ((a & 0xfff0) == 0x5180) { // a15180 |
be2c4208 |
170 | d = p32x_vdp_read16(a); |
171 | goto out; |
172 | } |
173 | |
974fdb5b |
174 | if ((a & 0xfe00) == 0x5200) { // a15200 |
175 | d = Pico32xMem->pal[(a & 0x1ff) / 2]; |
176 | goto out; |
177 | } |
178 | |
179 | no_vdp: |
be2c4208 |
180 | if ((a & 0xfffc) == 0x30ec) { // a130ec |
181 | d = !(a & 2) ? ('M'<<8)|'A' : ('R'<<8)|'S'; |
182 | goto out; |
183 | } |
184 | |
185 | elprintf(EL_UIO, "m68k unmapped r16 [%06x] @%06x", a, SekPc); |
186 | return d; |
187 | |
188 | out: |
189 | elprintf(EL_32X, "m68k 32x r16 [%06x] %04x @%06x", a, d, SekPc); |
190 | return d; |
191 | } |
192 | |
193 | void PicoWrite8_32x(u32 a, u32 d) |
194 | { |
195 | if ((a & 0xfc00) == 0x5000) |
196 | elprintf(EL_32X, "m68k 32x w8 [%06x] %02x @%06x", a, d & 0xff, SekPc); |
197 | |
198 | if ((a & 0xffc0) == 0x5100) { // a15100 |
199 | p32x_reg_write8(a, d); |
200 | return; |
201 | } |
202 | |
974fdb5b |
203 | if (!(Pico32x.regs[0] & 1)) |
204 | goto no_vdp; |
205 | |
206 | if ((a & 0xfff0) == 0x5180) { // a15180 |
be2c4208 |
207 | p32x_vdp_write8(a, d); |
208 | return; |
209 | } |
210 | |
974fdb5b |
211 | // TODO: verify |
212 | if ((a & 0xfe00) == 0x5200) { // a15200 |
213 | elprintf(EL_32X|EL_ANOMALY, "m68k 32x PAL w8 [%06x] %02x @%06x", a, d & 0xff, SekPc); |
214 | ((u8 *)Pico32xMem->pal)[(a & 0x1ff) ^ 1] = d; |
215 | Pico32x.dirty_pal = 1; |
216 | return; |
217 | } |
218 | |
219 | no_vdp: |
be2c4208 |
220 | elprintf(EL_UIO, "m68k unmapped w8 [%06x] %02x @%06x", a, d & 0xff, SekPc); |
221 | } |
222 | |
223 | void PicoWrite16_32x(u32 a, u32 d) |
224 | { |
225 | if ((a & 0xfc00) == 0x5000) |
226 | elprintf(EL_UIO, "m68k 32x w16 [%06x] %04x @%06x", a, d & 0xffff, SekPc); |
227 | |
228 | if ((a & 0xffc0) == 0x5100) { // a15100 |
229 | p32x_reg_write16(a, d); |
230 | return; |
231 | } |
232 | |
974fdb5b |
233 | if (!(Pico32x.regs[0] & 1)) |
234 | goto no_vdp; |
235 | |
236 | if ((a & 0xfff0) == 0x5180) { // a15180 |
be2c4208 |
237 | p32x_vdp_write16(a, d); |
238 | return; |
239 | } |
240 | |
974fdb5b |
241 | if ((a & 0xfe00) == 0x5200) { // a15200 |
242 | Pico32xMem->pal[(a & 0x1ff) / 2] = d; |
243 | Pico32x.dirty_pal = 1; |
244 | return; |
245 | } |
246 | |
247 | no_vdp: |
be2c4208 |
248 | elprintf(EL_UIO, "m68k unmapped w16 [%06x] %04x @%06x", a, d & 0xffff, SekPc); |
249 | } |
250 | |
251 | // hint vector is writeable |
252 | static void PicoWrite8_hint(u32 a, u32 d) |
253 | { |
254 | if ((a & 0xfffc) == 0x0070) { |
255 | Pico32xMem->m68k_rom[a ^ 1] = d; |
256 | return; |
257 | } |
258 | |
259 | elprintf(EL_UIO, "m68k unmapped w8 [%06x] %02x @%06x", a, d & 0xff, SekPc); |
260 | } |
261 | |
262 | static void PicoWrite16_hint(u32 a, u32 d) |
263 | { |
264 | if ((a & 0xfffc) == 0x0070) { |
265 | ((u16 *)Pico32xMem->m68k_rom)[a/2] = d; |
266 | return; |
267 | } |
268 | |
269 | elprintf(EL_UIO, "m68k unmapped w16 [%06x] %04x @%06x", a, d & 0xffff, SekPc); |
270 | } |
271 | |
974fdb5b |
272 | void Pico32xSwapDRAM(int b) |
273 | { |
274 | cpu68k_map_set(m68k_read8_map, 0x840000, 0x85ffff, Pico32xMem->dram[b], 0); |
275 | cpu68k_map_set(m68k_read16_map, 0x840000, 0x85ffff, Pico32xMem->dram[b], 0); |
276 | cpu68k_map_set(m68k_write8_map, 0x840000, 0x85ffff, Pico32xMem->dram[b], 0); |
277 | cpu68k_map_set(m68k_write16_map, 0x840000, 0x85ffff, Pico32xMem->dram[b], 0); |
278 | } |
279 | |
5e49c3a8 |
280 | static void bank_switch(int b) |
281 | { |
282 | unsigned int rs, bank; |
283 | |
284 | bank = b << 20; |
285 | if (bank >= Pico.romsize) { |
286 | elprintf(EL_32X|EL_ANOMALY, "missing bank @ %06x", bank); |
287 | return; |
288 | } |
289 | |
290 | // 32X ROM (unbanked, XXX: consider mirroring?) |
291 | rs = (Pico.romsize + M68K_BANK_MASK) & ~M68K_BANK_MASK; |
292 | rs -= bank; |
293 | if (rs > 0x100000) |
294 | rs = 0x100000; |
295 | cpu68k_map_set(m68k_read8_map, 0x900000, 0x900000 + rs - 1, Pico.rom + bank, 0); |
296 | cpu68k_map_set(m68k_read16_map, 0x900000, 0x900000 + rs - 1, Pico.rom + bank, 0); |
297 | |
298 | elprintf(EL_32X, "bank %06x-%06x -> %06x", 0x900000, 0x900000 + rs - 1, bank); |
299 | } |
300 | |
be2c4208 |
301 | #define HWSWAP(x) (((x) << 16) | ((x) >> 16)) |
302 | void PicoMemSetup32x(void) |
303 | { |
304 | unsigned short *ps; |
305 | unsigned int *pl; |
5e49c3a8 |
306 | unsigned int rs; |
be2c4208 |
307 | int i; |
308 | |
309 | Pico32xMem = calloc(1, sizeof(*Pico32xMem)); |
310 | if (Pico32xMem == NULL) { |
311 | elprintf(EL_STATUS, "OOM"); |
312 | return; |
313 | } |
314 | |
315 | // generate 68k ROM |
316 | ps = (unsigned short *)Pico32xMem->m68k_rom; |
317 | pl = (unsigned int *)Pico32xMem->m68k_rom; |
318 | for (i = 1; i < 0xc0/4; i++) |
974fdb5b |
319 | pl[i] = HWSWAP(0x880200 + (i - 1) * 6); |
be2c4208 |
320 | |
321 | // fill with nops |
322 | for (i = 0xc0/2; i < 0x100/2; i++) |
323 | ps[i] = 0x4e71; |
324 | |
5e49c3a8 |
325 | #if 0 |
be2c4208 |
326 | ps[0xc0/2] = 0x46fc; |
327 | ps[0xc2/2] = 0x2700; // move #0x2700,sr |
328 | ps[0xfe/2] = 0x60fe; // jump to self |
5e49c3a8 |
329 | #else |
330 | ps[0xfe/2] = 0x4e75; // rts |
331 | #endif |
be2c4208 |
332 | |
333 | // fill remaining mem with ROM |
974fdb5b |
334 | memcpy(Pico32xMem->m68k_rom + 0x100, Pico.rom + 0x100, sizeof(Pico32xMem->m68k_rom) - 0x100); |
be2c4208 |
335 | |
336 | // cartridge area becomes unmapped |
337 | // XXX: we take the easy way and don't unmap ROM, |
338 | // so that we can avoid handling the RV bit. |
339 | // m68k_map_unmap(0x000000, 0x3fffff); |
340 | |
341 | // MD ROM area |
974fdb5b |
342 | rs = sizeof(Pico32xMem->m68k_rom); |
343 | cpu68k_map_set(m68k_read8_map, 0x000000, rs - 1, Pico32xMem->m68k_rom, 0); |
344 | cpu68k_map_set(m68k_read16_map, 0x000000, rs - 1, Pico32xMem->m68k_rom, 0); |
345 | cpu68k_map_set(m68k_write8_map, 0x000000, rs - 1, PicoWrite8_hint, 1); // TODO verify |
346 | cpu68k_map_set(m68k_write16_map, 0x000000, rs - 1, PicoWrite16_hint, 1); |
347 | |
348 | // DRAM area |
349 | Pico32xSwapDRAM(1); |
be2c4208 |
350 | |
351 | // 32X ROM (unbanked, XXX: consider mirroring?) |
5e49c3a8 |
352 | rs = (Pico.romsize + M68K_BANK_MASK) & ~M68K_BANK_MASK; |
353 | if (rs > 0x80000) |
354 | rs = 0x80000; |
355 | cpu68k_map_set(m68k_read8_map, 0x880000, 0x880000 + rs - 1, Pico.rom, 0); |
356 | cpu68k_map_set(m68k_read16_map, 0x880000, 0x880000 + rs - 1, Pico.rom, 0); |
be2c4208 |
357 | |
358 | // 32X ROM (banked) |
5e49c3a8 |
359 | bank_switch(0); |
be2c4208 |
360 | } |
361 | |