32x: drc: bugfix
[picodrive.git] / pico / 32x / memory.c
... / ...
CommitLineData
1/*
2 * SH2 addr lines:
3 * iii. .cc. ..xx * // Internal, Cs, x
4 *
5 * Register map:
6 * a15100 F....... R.....EA F.....AC N...VHMP 4000 // Fm Ren nrEs Aden Cart heN V H cMd Pwm
7 * a15102 ........ ......SM ? 4002 // intS intM
8 * a15104 ........ ......10 ........ hhhhhhhh 4004 // bk1 bk0 Hint
9 * a15106 F....... .....SDR UE...... .....SDR 4006 // Full 68S Dma Rv fUll[fb] Empt[fb]
10 * a15108 (32bit DREQ src) 4008
11 * a1510c (32bit DREQ dst) 400c
12 * a15110 llllllll llllll00 4010 // DREQ Len
13 * a15112 (16bit FIFO reg) 4012
14 * a15114 ? (16bit VRES clr) 4014
15 * a15116 ? (16bit Vint clr) 4016
16 * a15118 ? (16bit Hint clr) 4018
17 * a1511a ........ .......C (16bit CMD clr) 401a // Cm
18 * a1511c ? (16bit PWM clr) 401c
19 * a1511e ? ? 401e
20 * a15120 (16 bytes comm) 2020
21 * a15130 (PWM) 2030
22 */
23#include "../pico_int.h"
24#include "../memory.h"
25
26#if 0
27#undef ash2_end_run
28#undef SekEndRun
29#define ash2_end_run(x)
30#define SekEndRun(x)
31#endif
32
33static const char str_mars[] = "MARS";
34
35void *p32x_bios_g, *p32x_bios_m, *p32x_bios_s;
36struct Pico32xMem *Pico32xMem;
37
38static void bank_switch(int b);
39
40// poll detection
41#define POLL_THRESHOLD 6
42
43struct poll_det {
44 u32 addr, cycles, cyc_max;
45 int cnt, flag;
46};
47static struct poll_det m68k_poll, sh2_poll[2];
48
49static int p32x_poll_detect(struct poll_det *pd, u32 a, u32 cycles, int is_vdp)
50{
51 int ret = 0, flag = pd->flag;
52
53 if (is_vdp)
54 flag <<= 3;
55
56 if (a - 2 <= pd->addr && pd->addr <= a + 2 && cycles - pd->cycles <= pd->cyc_max) {
57 pd->cnt++;
58 if (pd->cnt > POLL_THRESHOLD) {
59 if (!(Pico32x.emu_flags & flag)) {
60 elprintf(EL_32X, "%s poll addr %08x, cyc %u",
61 flag & (P32XF_68KPOLL|P32XF_68KVPOLL) ? "m68k" :
62 (flag & (P32XF_MSH2POLL|P32XF_MSH2VPOLL) ? "msh2" : "ssh2"), a, cycles - pd->cycles);
63 ret = 1;
64 }
65 Pico32x.emu_flags |= flag;
66 }
67 }
68 else {
69 pd->cnt = 0;
70 pd->addr = a;
71 }
72 pd->cycles = cycles;
73
74 return ret;
75}
76
77static int p32x_poll_undetect(struct poll_det *pd, int is_vdp)
78{
79 int ret = 0, flag = pd->flag;
80 if (is_vdp)
81 flag <<= 3; // VDP only
82 else
83 flag |= flag << 3; // both
84 if (Pico32x.emu_flags & flag) {
85 elprintf(EL_32X, "poll %02x -> %02x", Pico32x.emu_flags, Pico32x.emu_flags & ~flag);
86 ret = 1;
87 }
88 Pico32x.emu_flags &= ~flag;
89 pd->addr = pd->cnt = 0;
90 return ret;
91}
92
93void p32x_poll_event(int cpu_mask, int is_vdp)
94{
95 if (cpu_mask & 1)
96 p32x_poll_undetect(&sh2_poll[0], is_vdp);
97 if (cpu_mask & 2)
98 p32x_poll_undetect(&sh2_poll[1], is_vdp);
99}
100
101// SH2 faking
102//#define FAKE_SH2
103int p32x_csum_faked;
104#ifdef FAKE_SH2
105static const u16 comm_fakevals[] = {
106 0x4d5f, 0x4f4b, // M_OK
107 0x535f, 0x4f4b, // S_OK
108 0x4D41, 0x5346, // MASF - Brutal Unleashed
109 0x5331, 0x4d31, // Darxide
110 0x5332, 0x4d32,
111 0x5333, 0x4d33,
112 0x0000, 0x0000, // eq for doom
113 0x0002, // Mortal Kombat
114// 0, // pad
115};
116
117static u32 sh2_comm_faker(u32 a)
118{
119 static int f = 0;
120 if (a == 0x28 && !p32x_csum_faked) {
121 p32x_csum_faked = 1;
122 return *(unsigned short *)(Pico.rom + 0x18e);
123 }
124 if (f >= sizeof(comm_fakevals) / sizeof(comm_fakevals[0]))
125 f = 0;
126 return comm_fakevals[f++];
127}
128#endif
129
130// DMAC handling
131static struct {
132 unsigned int sar0, dar0, tcr0; // src addr, dst addr, transfer count
133 unsigned int chcr0; // chan ctl
134 unsigned int sar1, dar1, tcr1; // same for chan 1
135 unsigned int chcr1;
136 int pad[4];
137 unsigned int dmaor;
138} * dmac0;
139
140static void dma_68k2sh2_do(void)
141{
142 unsigned short *dreqlen = &Pico32x.regs[0x10 / 2];
143 int i;
144
145 if (dmac0->tcr0 != *dreqlen)
146 elprintf(EL_32X|EL_ANOMALY, "tcr0 and dreq len differ: %d != %d", dmac0->tcr0, *dreqlen);
147
148 // HACK: assume bus is busy and SH2 is halted
149 // XXX: use different mechanism for this, not poll det
150 Pico32x.emu_flags |= P32XF_MSH2POLL; // id ? P32XF_SSH2POLL : P32XF_MSH2POLL;
151
152 for (i = 0; i < Pico32x.dmac_ptr && dmac0->tcr0 > 0; i++) {
153 elprintf(EL_32X, "dmaw [%08x] %04x, left %d", dmac0->dar0, Pico32x.dmac_fifo[i], *dreqlen);
154 p32x_sh2_write16(dmac0->dar0, Pico32x.dmac_fifo[i], &msh2);
155 dmac0->dar0 += 2;
156 dmac0->tcr0--;
157 (*dreqlen)--;
158 }
159
160 Pico32x.dmac_ptr = 0; // HACK
161 Pico32x.regs[6 / 2] &= ~P32XS_FULL;
162 if (*dreqlen == 0)
163 Pico32x.regs[6 / 2] &= ~P32XS_68S; // transfer complete
164 if (dmac0->tcr0 == 0) {
165 dmac0->chcr0 |= 2; // DMA has ended normally
166 p32x_poll_undetect(&sh2_poll[0], 0);
167 }
168}
169
170// ------------------------------------------------------------------
171// 68k regs
172
173static u32 p32x_reg_read16(u32 a)
174{
175 a &= 0x3e;
176
177 if (a == 2) // INTM, INTS
178 return ((Pico32x.sh2irqi[0] & P32XI_CMD) >> 4) | ((Pico32x.sh2irqi[1] & P32XI_CMD) >> 3);
179#if 0
180 if ((a & 0x30) == 0x20)
181 return sh2_comm_faker(a);
182#else
183 if ((a & 0x30) == 0x20) {
184 // evil X-Men proto polls in a dbra loop and expects it to expire..
185 static u32 dr2 = 0;
186 if (SekDar(2) != dr2)
187 m68k_poll.cnt = 0;
188 dr2 = SekDar(2);
189
190 if (p32x_poll_detect(&m68k_poll, a, SekCyclesDoneT(), 0)) {
191 SekSetStop(1);
192 SekEndTimeslice(16);
193 }
194 dr2 = SekDar(2);
195 }
196#endif
197
198 if ((a & 0x30) == 0x30)
199 return p32x_pwm_read16(a);
200
201 return Pico32x.regs[a / 2];
202}
203
204static void p32x_reg_write8(u32 a, u32 d)
205{
206 u16 *r = Pico32x.regs;
207 a &= 0x3f;
208
209 // for things like bset on comm port
210 m68k_poll.cnt = 0;
211
212 switch (a) {
213 case 0: // adapter ctl
214 r[0] = (r[0] & ~P32XS_FM) | ((d << 8) & P32XS_FM);
215 return;
216 case 1: // adapter ctl, RES bit writeable
217 if ((d ^ r[0]) & d & P32XS_nRES)
218 p32x_reset_sh2s();
219 r[0] = (r[0] & ~P32XS_nRES) | (d & P32XS_nRES);
220 return;
221 case 3: // irq ctl
222 if ((d & 1) && !(Pico32x.sh2irqi[0] & P32XI_CMD)) {
223 Pico32x.sh2irqi[0] |= P32XI_CMD;
224 p32x_update_irls();
225 SekEndRun(16);
226 }
227 if ((d & 2) && !(Pico32x.sh2irqi[1] & P32XI_CMD)) {
228 Pico32x.sh2irqi[1] |= P32XI_CMD;
229 p32x_update_irls();
230 SekEndRun(16);
231 }
232 return;
233 case 5: // bank
234 d &= 7;
235 if (r[4 / 2] != d) {
236 r[4 / 2] = d;
237 bank_switch(d);
238 }
239 return;
240 case 7: // DREQ ctl
241 r[6 / 2] = (r[6 / 2] & P32XS_FULL) | (d & (P32XS_68S|P32XS_DMA|P32XS_RV));
242 return;
243 case 0x1b: // TV
244 r[0x1a / 2] = d;
245 return;
246 }
247
248 if ((a & 0x30) == 0x20) {
249 u8 *r8 = (u8 *)r;
250 r8[a ^ 1] = d;
251 p32x_poll_undetect(&sh2_poll[0], 0);
252 p32x_poll_undetect(&sh2_poll[1], 0);
253 // if some SH2 is busy waiting, it needs to see the result ASAP
254 if (SekCyclesLeftNoMCD > 32)
255 SekEndRun(32);
256 return;
257 }
258}
259
260static void p32x_reg_write16(u32 a, u32 d)
261{
262 u16 *r = Pico32x.regs;
263 a &= 0x3e;
264
265 // for things like bset on comm port
266 m68k_poll.cnt = 0;
267
268 switch (a) {
269 case 0x00: // adapter ctl
270 if ((d ^ r[0]) & d & P32XS_nRES)
271 p32x_reset_sh2s();
272 r[0] = (r[0] & ~(P32XS_FM|P32XS_nRES)) | (d & (P32XS_FM|P32XS_nRES));
273 return;
274 case 0x10: // DREQ len
275 r[a / 2] = d & ~3;
276 return;
277 case 0x12: // FIFO reg
278 if (!(r[6 / 2] & P32XS_68S)) {
279 elprintf(EL_32X|EL_ANOMALY, "DREQ FIFO w16 without 68S?");
280 return;
281 }
282 if (Pico32x.dmac_ptr < DMAC_FIFO_LEN) {
283 Pico32x.dmac_fifo[Pico32x.dmac_ptr++] = d;
284 if ((Pico32x.dmac_ptr & 3) == 0 && (dmac0->chcr0 & 3) == 1 && (dmac0->dmaor & 1))
285 dma_68k2sh2_do();
286 if (Pico32x.dmac_ptr == DMAC_FIFO_LEN)
287 r[6 / 2] |= P32XS_FULL;
288 }
289 break;
290 }
291
292 // DREQ src, dst
293 if ((a & 0x38) == 0x08) {
294 r[a / 2] = d;
295 return;
296 }
297 // comm port
298 else if ((a & 0x30) == 0x20 && r[a / 2] != d) {
299 r[a / 2] = d;
300 p32x_poll_undetect(&sh2_poll[0], 0);
301 p32x_poll_undetect(&sh2_poll[1], 0);
302 // same as for w8
303 if (SekCyclesLeftNoMCD > 32)
304 SekEndRun(32);
305 return;
306 }
307 // PWM
308 else if ((a & 0x30) == 0x30) {
309 p32x_pwm_write16(a, d);
310 return;
311 }
312
313 p32x_reg_write8(a + 1, d);
314}
315
316// ------------------------------------------------------------------
317// VDP regs
318static u32 p32x_vdp_read16(u32 a)
319{
320 a &= 0x0e;
321
322 return Pico32x.vdp_regs[a / 2];
323}
324
325static void p32x_vdp_write8(u32 a, u32 d)
326{
327 u16 *r = Pico32x.vdp_regs;
328 a &= 0x0f;
329
330 // for FEN checks between writes
331 sh2_poll[0].cnt = 0;
332
333 // TODO: verify what's writeable
334 switch (a) {
335 case 0x01:
336 // priority inversion is handled in palette
337 if ((r[0] ^ d) & P32XV_PRI)
338 Pico32x.dirty_pal = 1;
339 r[0] = (r[0] & P32XV_nPAL) | (d & 0xff);
340 break;
341 case 0x05: // fill len
342 r[4 / 2] = d & 0xff;
343 break;
344 case 0x0b:
345 d &= 1;
346 Pico32x.pending_fb = d;
347 // if we are blanking and FS bit is changing
348 if (((r[0x0a/2] & P32XV_VBLK) || (r[0] & P32XV_Mx) == 0) && ((r[0x0a/2] ^ d) & P32XV_FS)) {
349 r[0x0a/2] ^= 1;
350 Pico32xSwapDRAM(d ^ 1);
351 elprintf(EL_32X, "VDP FS: %d", r[0x0a/2] & P32XV_FS);
352 }
353 break;
354 }
355}
356
357static void p32x_vdp_write16(u32 a, u32 d)
358{
359 a &= 0x0e;
360 if (a == 6) { // fill start
361 Pico32x.vdp_regs[6 / 2] = d;
362 return;
363 }
364 if (a == 8) { // fill data
365 u16 *dram = Pico32xMem->dram[(Pico32x.vdp_regs[0x0a/2] & P32XV_FS) ^ 1];
366 int len = Pico32x.vdp_regs[4 / 2] + 1;
367 a = Pico32x.vdp_regs[6 / 2];
368 while (len--) {
369 dram[a] = d;
370 a = (a & 0xff00) | ((a + 1) & 0xff);
371 }
372 Pico32x.vdp_regs[6 / 2] = a;
373 Pico32x.vdp_regs[8 / 2] = d;
374 return;
375 }
376
377 p32x_vdp_write8(a | 1, d);
378}
379
380// ------------------------------------------------------------------
381// SH2 regs
382
383static u32 p32x_sh2reg_read16(u32 a, int cpuid)
384{
385 u16 *r = Pico32x.regs;
386 a &= 0xfe; // ?
387
388 switch (a) {
389 case 0x00: // adapter/irq ctl
390 return (r[0] & P32XS_FM) | Pico32x.sh2_regs[0] | Pico32x.sh2irq_mask[cpuid];
391 case 0x04: // H count (often as comm too)
392 if (p32x_poll_detect(&sh2_poll[cpuid], a, ash2_cycles_done(), 0))
393 ash2_end_run(8);
394 return Pico32x.sh2_regs[4 / 2];
395 case 0x10: // DREQ len
396 return r[a / 2];
397 }
398
399 // DREQ src, dst
400 if ((a & 0x38) == 0x08)
401 return r[a / 2];
402 // comm port
403 if ((a & 0x30) == 0x20) {
404 if (p32x_poll_detect(&sh2_poll[cpuid], a, ash2_cycles_done(), 0))
405 ash2_end_run(8);
406 return r[a / 2];
407 }
408 if ((a & 0x30) == 0x30) {
409 sh2_poll[cpuid].cnt = 0;
410 return p32x_pwm_read16(a);
411 }
412
413 return 0;
414}
415
416static void p32x_sh2reg_write8(u32 a, u32 d, int cpuid)
417{
418 a &= 0xff;
419 switch (a) {
420 case 0: // FM
421 Pico32x.regs[0] &= ~P32XS_FM;
422 Pico32x.regs[0] |= (d << 8) & P32XS_FM;
423 return;
424 case 1: //
425 Pico32x.sh2irq_mask[cpuid] = d & 0x8f;
426 Pico32x.sh2_regs[0] &= ~0x80;
427 Pico32x.sh2_regs[0] |= d & 0x80;
428 p32x_update_irls();
429 return;
430 case 5: // H count
431 Pico32x.sh2_regs[4 / 2] = d & 0xff;
432 p32x_poll_undetect(&sh2_poll[cpuid ^ 1], 0);
433 return;
434 }
435
436 if ((a & 0x30) == 0x20) {
437 u8 *r8 = (u8 *)Pico32x.regs;
438 r8[a ^ 1] = d;
439 if (p32x_poll_undetect(&m68k_poll, 0))
440 SekSetStop(0);
441 p32x_poll_undetect(&sh2_poll[cpuid ^ 1], 0);
442 return;
443 }
444}
445
446static void p32x_sh2reg_write16(u32 a, u32 d, int cpuid)
447{
448 a &= 0xfe;
449
450 // comm
451 if ((a & 0x30) == 0x20 && Pico32x.regs[a/2] != d) {
452 Pico32x.regs[a / 2] = d;
453 if (p32x_poll_undetect(&m68k_poll, 0))
454 SekSetStop(0);
455 p32x_poll_undetect(&sh2_poll[cpuid ^ 1], 0);
456 return;
457 }
458 // PWM
459 else if ((a & 0x30) == 0x30) {
460 p32x_pwm_write16(a, d);
461 return;
462 }
463
464 switch (a) {
465 case 0: // FM
466 Pico32x.regs[0] &= ~P32XS_FM;
467 Pico32x.regs[0] |= d & P32XS_FM;
468 break;
469 case 0x14: Pico32x.sh2irqs &= ~P32XI_VRES; goto irls;
470 case 0x16: Pico32x.sh2irqs &= ~P32XI_VINT; goto irls;
471 case 0x18: Pico32x.sh2irqs &= ~P32XI_HINT; goto irls;
472 case 0x1a: Pico32x.sh2irqi[cpuid] &= ~P32XI_CMD; goto irls;
473 case 0x1c:
474 Pico32x.sh2irqs &= ~P32XI_PWM;
475 p32x_timers_do(0);
476 goto irls;
477 }
478
479 p32x_sh2reg_write8(a | 1, d, cpuid);
480 return;
481
482irls:
483 p32x_update_irls();
484}
485
486// ------------------------------------------------------------------
487// SH2 internal peripherals
488// we keep them in little endian format
489static u32 sh2_peripheral_read8(u32 a, int id)
490{
491 u8 *r = (void *)Pico32xMem->sh2_peri_regs[id];
492 u32 d;
493
494 a &= 0x1ff;
495 d = PREG8(r, a);
496
497 elprintf(EL_32X, "%csh2 peri r8 [%08x] %02x @%06x", id ? 's' : 'm', a | ~0x1ff, d, sh2_pc(id));
498 return d;
499}
500
501static u32 sh2_peripheral_read16(u32 a, int id)
502{
503 u16 *r = (void *)Pico32xMem->sh2_peri_regs[id];
504 u32 d;
505
506 a &= 0x1ff;
507 d = r[(a / 2) ^ 1];
508
509 elprintf(EL_32X, "%csh2 peri r16 [%08x] %04x @%06x", id ? 's' : 'm', a | ~0x1ff, d, sh2_pc(id));
510 return d;
511}
512
513static u32 sh2_peripheral_read32(u32 a, int id)
514{
515 u32 d;
516 a &= 0x1fc;
517 d = Pico32xMem->sh2_peri_regs[id][a / 4];
518
519 elprintf(EL_32X, "%csh2 peri r32 [%08x] %08x @%06x", id ? 's' : 'm', a | ~0x1ff, d, sh2_pc(id));
520 return d;
521}
522
523static void sh2_peripheral_write8(u32 a, u32 d, int id)
524{
525 u8 *r = (void *)Pico32xMem->sh2_peri_regs[id];
526 elprintf(EL_32X, "%csh2 peri w8 [%08x] %02x @%06x", id ? 's' : 'm', a, d, sh2_pc(id));
527
528 a &= 0x1ff;
529 PREG8(r, a) = d;
530
531 // X-men SCI hack
532 if ((a == 2 && (d & 0x20)) || // transmiter enabled
533 (a == 4 && !(d & 0x80))) { // valid data in TDR
534 void *oregs = Pico32xMem->sh2_peri_regs[id ^ 1];
535 if ((PREG8(oregs, 2) & 0x50) == 0x50) { // receiver + irq enabled
536 int level = PREG8(oregs, 0x60) >> 4;
537 int vector = PREG8(oregs, 0x63) & 0x7f;
538 elprintf(EL_32X, "%csh2 SCI recv irq (%d, %d)", (id ^ 1) ? 's' : 'm', level, vector);
539 sh2_internal_irq(&sh2s[id ^ 1], level, vector);
540 }
541 }
542}
543
544static void sh2_peripheral_write16(u32 a, u32 d, int id)
545{
546 u16 *r = (void *)Pico32xMem->sh2_peri_regs[id];
547 elprintf(EL_32X, "%csh2 peri w16 [%08x] %04x @%06x", id ? 's' : 'm', a, d, sh2_pc(id));
548
549 a &= 0x1ff;
550
551 // evil WDT
552 if (a == 0x80) {
553 if ((d & 0xff00) == 0xa500) { // WTCSR
554 PREG8(r, 0x80) = d;
555 p32x_timers_recalc();
556 }
557 if ((d & 0xff00) == 0x5a00) // WTCNT
558 PREG8(r, 0x81) = d;
559 return;
560 }
561
562 r[(a / 2) ^ 1] = d;
563}
564
565static void sh2_peripheral_write32(u32 a, u32 d, int id)
566{
567 u32 *r = Pico32xMem->sh2_peri_regs[id];
568 elprintf(EL_32X, "%csh2 peri w32 [%08x] %08x @%06x", id ? 's' : 'm', a, d, sh2_pc(id));
569
570 a &= 0x1fc;
571 r[a / 4] = d;
572
573 switch (a) {
574 // division unit (TODO: verify):
575 case 0x104: // DVDNT: divident L, starts divide
576 elprintf(EL_32X, "%csh2 divide %08x / %08x", id ? 's' : 'm', d, r[0x100 / 4]);
577 if (r[0x100 / 4]) {
578 signed int divisor = r[0x100 / 4];
579 r[0x118 / 4] = r[0x110 / 4] = (signed int)d % divisor;
580 r[0x104 / 4] = r[0x11c / 4] = r[0x114 / 4] = (signed int)d / divisor;
581 }
582 else
583 r[0x110 / 4] = r[0x114 / 4] = r[0x118 / 4] = r[0x11c / 4] = 0; // ?
584 break;
585 case 0x114:
586 elprintf(EL_32X, "%csh2 divide %08x%08x / %08x @%08x",
587 id ? 's' : 'm', r[0x110 / 4], d, r[0x100 / 4], sh2_pc(id));
588 if (r[0x100 / 4]) {
589 signed long long divident = (signed long long)r[0x110 / 4] << 32 | d;
590 signed int divisor = r[0x100 / 4];
591 // XXX: undocumented mirroring to 0x118,0x11c?
592 r[0x118 / 4] = r[0x110 / 4] = divident % divisor;
593 divident /= divisor;
594 r[0x11c / 4] = r[0x114 / 4] = divident;
595 divident >>= 31;
596 if ((unsigned long long)divident + 1 > 1) {
597 //elprintf(EL_32X, "%csh2 divide overflow! @%08x", id ? 's' : 'm', sh2_pc(id));
598 r[0x11c / 4] = r[0x114 / 4] = divident > 0 ? 0x7fffffff : 0x80000000; // overflow
599 }
600 }
601 else
602 r[0x110 / 4] = r[0x114 / 4] = r[0x118 / 4] = r[0x11c / 4] = 0; // ?
603 break;
604 }
605
606 if ((a == 0x1b0 || a == 0x18c) && (dmac0->chcr0 & 3) == 1 && (dmac0->dmaor & 1)) {
607 elprintf(EL_32X, "sh2 DMA %08x -> %08x, cnt %d, chcr %04x @%06x",
608 dmac0->sar0, dmac0->dar0, dmac0->tcr0, dmac0->chcr0, sh2_pc(id));
609 dmac0->tcr0 &= 0xffffff;
610
611 // HACK: assume 68k starts writing soon and end the timeslice
612 ash2_end_run(16);
613
614 // DREQ is only sent after first 4 words are written.
615 // we do multiple of 4 words to avoid messing up alignment
616 if (dmac0->sar0 == 0x20004012 && Pico32x.dmac_ptr && (Pico32x.dmac_ptr & 3) == 0) {
617 elprintf(EL_32X, "68k -> sh2 DMA");
618 dma_68k2sh2_do();
619 }
620 }
621}
622
623// ------------------------------------------------------------------
624// 32x handlers
625
626// after ADEN
627static u32 PicoRead8_32x_on(u32 a)
628{
629 u32 d = 0;
630 if ((a & 0xffc0) == 0x5100) { // a15100
631 d = p32x_reg_read16(a);
632 goto out_16to8;
633 }
634
635 if ((a & 0xfc00) != 0x5000)
636 return PicoRead8_io(a);
637
638 if ((a & 0xfff0) == 0x5180) { // a15180
639 d = p32x_vdp_read16(a);
640 goto out_16to8;
641 }
642
643 if ((a & 0xfe00) == 0x5200) { // a15200
644 d = Pico32xMem->pal[(a & 0x1ff) / 2];
645 goto out_16to8;
646 }
647
648 if ((a & 0xfffc) == 0x30ec) { // a130ec
649 d = str_mars[a & 3];
650 goto out;
651 }
652
653 elprintf(EL_UIO, "m68k unmapped r8 [%06x] @%06x", a, SekPc);
654 return d;
655
656out_16to8:
657 if (a & 1)
658 d &= 0xff;
659 else
660 d >>= 8;
661
662out:
663 elprintf(EL_32X, "m68k 32x r8 [%06x] %02x @%06x", a, d, SekPc);
664 return d;
665}
666
667static u32 PicoRead16_32x_on(u32 a)
668{
669 u32 d = 0;
670 if ((a & 0xffc0) == 0x5100) { // a15100
671 d = p32x_reg_read16(a);
672 goto out;
673 }
674
675 if ((a & 0xfc00) != 0x5000)
676 return PicoRead16_io(a);
677
678 if ((a & 0xfff0) == 0x5180) { // a15180
679 d = p32x_vdp_read16(a);
680 goto out;
681 }
682
683 if ((a & 0xfe00) == 0x5200) { // a15200
684 d = Pico32xMem->pal[(a & 0x1ff) / 2];
685 goto out;
686 }
687
688 if ((a & 0xfffc) == 0x30ec) { // a130ec
689 d = !(a & 2) ? ('M'<<8)|'A' : ('R'<<8)|'S';
690 goto out;
691 }
692
693 elprintf(EL_UIO, "m68k unmapped r16 [%06x] @%06x", a, SekPc);
694 return d;
695
696out:
697 elprintf(EL_32X, "m68k 32x r16 [%06x] %04x @%06x", a, d, SekPc);
698 return d;
699}
700
701static void PicoWrite8_32x_on(u32 a, u32 d)
702{
703 if ((a & 0xfc00) == 0x5000)
704 elprintf(EL_32X, "m68k 32x w8 [%06x] %02x @%06x", a, d & 0xff, SekPc);
705
706 if ((a & 0xffc0) == 0x5100) { // a15100
707 p32x_reg_write8(a, d);
708 return;
709 }
710
711 if ((a & 0xfc00) != 0x5000) {
712 PicoWrite8_io(a, d);
713 return;
714 }
715
716 if ((a & 0xfff0) == 0x5180) { // a15180
717 p32x_vdp_write8(a, d);
718 return;
719 }
720
721 // TODO: verify
722 if ((a & 0xfe00) == 0x5200) { // a15200
723 elprintf(EL_32X|EL_ANOMALY, "m68k 32x PAL w8 [%06x] %02x @%06x", a, d & 0xff, SekPc);
724 ((u8 *)Pico32xMem->pal)[(a & 0x1ff) ^ 1] = d;
725 Pico32x.dirty_pal = 1;
726 return;
727 }
728
729 elprintf(EL_UIO, "m68k unmapped w8 [%06x] %02x @%06x", a, d & 0xff, SekPc);
730}
731
732static void PicoWrite16_32x_on(u32 a, u32 d)
733{
734 if ((a & 0xfc00) == 0x5000)
735 elprintf(EL_UIO, "m68k 32x w16 [%06x] %04x @%06x", a, d & 0xffff, SekPc);
736
737 if ((a & 0xffc0) == 0x5100) { // a15100
738 p32x_reg_write16(a, d);
739 return;
740 }
741
742 if ((a & 0xfc00) != 0x5000) {
743 PicoWrite16_io(a, d);
744 return;
745 }
746
747 if ((a & 0xfff0) == 0x5180) { // a15180
748 p32x_vdp_write16(a, d);
749 return;
750 }
751
752 if ((a & 0xfe00) == 0x5200) { // a15200
753 Pico32xMem->pal[(a & 0x1ff) / 2] = d;
754 Pico32x.dirty_pal = 1;
755 return;
756 }
757
758 elprintf(EL_UIO, "m68k unmapped w16 [%06x] %04x @%06x", a, d & 0xffff, SekPc);
759}
760
761// before ADEN
762u32 PicoRead8_32x(u32 a)
763{
764 u32 d = 0;
765 if ((a & 0xffc0) == 0x5100) { // a15100
766 // regs are always readable
767 d = ((u8 *)Pico32x.regs)[(a & 0x3f) ^ 1];
768 goto out;
769 }
770
771 if ((a & 0xfffc) == 0x30ec) { // a130ec
772 d = str_mars[a & 3];
773 goto out;
774 }
775
776 elprintf(EL_UIO, "m68k unmapped r8 [%06x] @%06x", a, SekPc);
777 return d;
778
779out:
780 elprintf(EL_32X, "m68k 32x r8 [%06x] %02x @%06x", a, d, SekPc);
781 return d;
782}
783
784u32 PicoRead16_32x(u32 a)
785{
786 u32 d = 0;
787 if ((a & 0xffc0) == 0x5100) { // a15100
788 d = Pico32x.regs[(a & 0x3f) / 2];
789 goto out;
790 }
791
792 if ((a & 0xfffc) == 0x30ec) { // a130ec
793 d = !(a & 2) ? ('M'<<8)|'A' : ('R'<<8)|'S';
794 goto out;
795 }
796
797 elprintf(EL_UIO, "m68k unmapped r16 [%06x] @%06x", a, SekPc);
798 return d;
799
800out:
801 elprintf(EL_32X, "m68k 32x r16 [%06x] %04x @%06x", a, d, SekPc);
802 return d;
803}
804
805void PicoWrite8_32x(u32 a, u32 d)
806{
807 if ((a & 0xffc0) == 0x5100) { // a15100
808 u16 *r = Pico32x.regs;
809
810 elprintf(EL_32X, "m68k 32x w8 [%06x] %02x @%06x", a, d & 0xff, SekPc);
811 a &= 0x3f;
812 if (a == 1) {
813 if ((d ^ r[0]) & d & P32XS_ADEN) {
814 Pico32xStartup();
815 r[0] &= ~P32XS_nRES; // causes reset if specified by this write
816 r[0] |= P32XS_ADEN;
817 p32x_reg_write8(a, d); // forward for reset processing
818 }
819 return;
820 }
821
822 // allow only COMM for now
823 if ((a & 0x30) == 0x20) {
824 u8 *r8 = (u8 *)r;
825 r8[a ^ 1] = d;
826 }
827 return;
828 }
829
830 elprintf(EL_UIO, "m68k unmapped w8 [%06x] %02x @%06x", a, d & 0xff, SekPc);
831}
832
833void PicoWrite16_32x(u32 a, u32 d)
834{
835 if ((a & 0xffc0) == 0x5100) { // a15100
836 u16 *r = Pico32x.regs;
837
838 elprintf(EL_UIO, "m68k 32x w16 [%06x] %04x @%06x", a, d & 0xffff, SekPc);
839 a &= 0x3e;
840 if (a == 0) {
841 if ((d ^ r[0]) & d & P32XS_ADEN) {
842 Pico32xStartup();
843 r[0] &= ~P32XS_nRES; // causes reset if specified by this write
844 r[0] |= P32XS_ADEN;
845 p32x_reg_write16(a, d); // forward for reset processing
846 }
847 return;
848 }
849
850 // allow only COMM for now
851 if ((a & 0x30) == 0x20)
852 r[a / 2] = d;
853 return;
854 }
855
856 elprintf(EL_UIO, "m68k unmapped w16 [%06x] %04x @%06x", a, d & 0xffff, SekPc);
857}
858
859// -----------------------------------------------------------------
860
861// hint vector is writeable
862static void PicoWrite8_hint(u32 a, u32 d)
863{
864 if ((a & 0xfffc) == 0x0070) {
865 Pico32xMem->m68k_rom[a ^ 1] = d;
866 return;
867 }
868
869 elprintf(EL_UIO, "m68k unmapped w8 [%06x] %02x @%06x", a, d & 0xff, SekPc);
870}
871
872static void PicoWrite16_hint(u32 a, u32 d)
873{
874 if ((a & 0xfffc) == 0x0070) {
875 ((u16 *)Pico32xMem->m68k_rom)[a/2] = d;
876 return;
877 }
878
879 elprintf(EL_UIO, "m68k unmapped w16 [%06x] %04x @%06x", a, d & 0xffff, SekPc);
880}
881
882static void bank_switch(int b)
883{
884 unsigned int rs, bank;
885
886 bank = b << 20;
887 if (bank >= Pico.romsize) {
888 elprintf(EL_32X|EL_ANOMALY, "missing bank @ %06x", bank);
889 return;
890 }
891
892 // 32X ROM (unbanked, XXX: consider mirroring?)
893 rs = (Pico.romsize + M68K_BANK_MASK) & ~M68K_BANK_MASK;
894 rs -= bank;
895 if (rs > 0x100000)
896 rs = 0x100000;
897 cpu68k_map_set(m68k_read8_map, 0x900000, 0x900000 + rs - 1, Pico.rom + bank, 0);
898 cpu68k_map_set(m68k_read16_map, 0x900000, 0x900000 + rs - 1, Pico.rom + bank, 0);
899
900 elprintf(EL_32X, "bank %06x-%06x -> %06x", 0x900000, 0x900000 + rs - 1, bank);
901
902#ifdef EMU_F68K
903 // setup FAME fetchmap
904 for (rs = 0x90; rs < 0xa0; rs++)
905 PicoCpuFM68k.Fetch[rs] = (u32)Pico.rom + bank - 0x900000;
906#endif
907}
908
909// -----------------------------------------------------------------
910// SH2
911// -----------------------------------------------------------------
912
913// read8
914static u32 sh2_read8_unmapped(u32 a, int id)
915{
916 elprintf(EL_UIO, "%csh2 unmapped r8 [%08x] %02x @%06x",
917 id ? 's' : 'm', a, 0, sh2_pc(id));
918 return 0;
919}
920
921static u32 sh2_read8_cs0(u32 a, int id)
922{
923 u32 d = 0;
924
925 // 0x3ff00 is veridied
926 if ((a & 0x3ff00) == 0x4000) {
927 d = p32x_sh2reg_read16(a, id);
928 goto out_16to8;
929 }
930
931 if ((a & 0x3ff00) == 0x4100) {
932 d = p32x_vdp_read16(a);
933 if (p32x_poll_detect(&sh2_poll[id], a, ash2_cycles_done(), 1))
934 ash2_end_run(8);
935 goto out_16to8;
936 }
937
938 // TODO: mirroring?
939 if (id == 0 && a < sizeof(Pico32xMem->sh2_rom_m))
940 return Pico32xMem->sh2_rom_m[a ^ 1];
941 if (id == 1 && a < sizeof(Pico32xMem->sh2_rom_s))
942 return Pico32xMem->sh2_rom_s[a ^ 1];
943
944 if ((a & 0x3ff00) == 0x4200) {
945 d = Pico32xMem->pal[(a & 0x1ff) / 2];
946 goto out_16to8;
947 }
948
949 return sh2_read8_unmapped(a, id);
950
951out_16to8:
952 if (a & 1)
953 d &= 0xff;
954 else
955 d >>= 8;
956
957 elprintf(EL_32X, "%csh2 r8 [%08x] %02x @%06x",
958 id ? 's' : 'm', a, d, sh2_pc(id));
959 return d;
960}
961
962static u32 sh2_read8_da(u32 a, int id)
963{
964 return Pico32xMem->data_array[id][(a & 0xfff) ^ 1];
965}
966
967// read16
968static u32 sh2_read16_unmapped(u32 a, int id)
969{
970 elprintf(EL_UIO, "%csh2 unmapped r16 [%08x] %04x @%06x",
971 id ? 's' : 'm', a, 0, sh2_pc(id));
972 return 0;
973}
974
975static u32 sh2_read16_cs0(u32 a, int id)
976{
977 u32 d = 0;
978
979 if ((a & 0x3ff00) == 0x4000) {
980 d = p32x_sh2reg_read16(a, id);
981 if (!(EL_LOGMASK & EL_PWM) && (a & 0x30) == 0x30) // hide PWM
982 return d;
983 goto out;
984 }
985
986 if ((a & 0x3ff00) == 0x4100) {
987 d = p32x_vdp_read16(a);
988 if (p32x_poll_detect(&sh2_poll[id], a, ash2_cycles_done(), 1))
989 ash2_end_run(8);
990 goto out;
991 }
992
993 if (id == 0 && a < sizeof(Pico32xMem->sh2_rom_m))
994 return *(u16 *)(Pico32xMem->sh2_rom_m + a);
995 if (id == 1 && a < sizeof(Pico32xMem->sh2_rom_s))
996 return *(u16 *)(Pico32xMem->sh2_rom_s + a);
997
998 if ((a & 0x3ff00) == 0x4200) {
999 d = Pico32xMem->pal[(a & 0x1ff) / 2];
1000 goto out;
1001 }
1002
1003 return sh2_read16_unmapped(a, id);
1004
1005out:
1006 elprintf(EL_32X, "%csh2 r16 [%08x] %04x @%06x",
1007 id ? 's' : 'm', a, d, sh2_pc(id));
1008 return d;
1009}
1010
1011static u32 sh2_read16_da(u32 a, int id)
1012{
1013 return ((u16 *)Pico32xMem->data_array[id])[(a & 0xfff) / 2];
1014}
1015
1016// write8
1017static void sh2_write8_unmapped(u32 a, u32 d, int id)
1018{
1019 elprintf(EL_UIO, "%csh2 unmapped w8 [%08x] %02x @%06x",
1020 id ? 's' : 'm', a, d & 0xff, sh2_pc(id));
1021}
1022
1023static void sh2_write8_cs0(u32 a, u32 d, int id)
1024{
1025 elprintf(EL_32X, "%csh2 w8 [%08x] %02x @%06x",
1026 id ? 's' : 'm', a, d & 0xff, sh2_pc(id));
1027
1028 if ((a & 0x3ff00) == 0x4100) {
1029 p32x_vdp_write8(a, d);
1030 return;
1031 }
1032
1033 if ((a & 0x3ff00) == 0x4000) {
1034 p32x_sh2reg_write8(a, d, id);
1035 return;
1036 }
1037
1038 sh2_write8_unmapped(a, d, id);
1039}
1040
1041#define sh2_write8_dramN(n) \
1042 if (!(a & 0x20000) || d) { \
1043 u8 *dram = (u8 *)Pico32xMem->dram[n]; \
1044 dram[(a & 0x1ffff) ^ 1] = d; \
1045 }
1046
1047static void sh2_write8_dram0(u32 a, u32 d, int id)
1048{
1049 sh2_write8_dramN(0);
1050}
1051
1052static void sh2_write8_dram1(u32 a, u32 d, int id)
1053{
1054 sh2_write8_dramN(1);
1055}
1056
1057static void sh2_write8_da(u32 a, u32 d, int id)
1058{
1059 Pico32xMem->data_array[id][(a & 0xfff) ^ 1] = d;
1060}
1061
1062// write16
1063static void sh2_write16_unmapped(u32 a, u32 d, int id)
1064{
1065 elprintf(EL_UIO, "%csh2 unmapped w16 [%08x] %04x @%06x",
1066 id ? 's' : 'm', a, d & 0xffff, sh2_pc(id));
1067}
1068
1069static void sh2_write16_cs0(u32 a, u32 d, int id)
1070{
1071 if (((EL_LOGMASK & EL_PWM) || (a & 0x30) != 0x30)) // hide PWM
1072 elprintf(EL_32X, "%csh2 w16 [%08x] %04x @%06x",
1073 id ? 's' : 'm', a, d & 0xffff, sh2_pc(id));
1074
1075 if ((a & 0x3ff00) == 0x4100) {
1076 sh2_poll[id].cnt = 0; // for poll before VDP accesses
1077 p32x_vdp_write16(a, d);
1078 return;
1079 }
1080
1081 if ((a & 0x3fe00) == 0x4200) {
1082 Pico32xMem->pal[(a & 0x1ff) / 2] = d;
1083 Pico32x.dirty_pal = 1;
1084 return;
1085 }
1086
1087 if ((a & 0x3ff00) == 0x4000) {
1088 p32x_sh2reg_write16(a, d, id);
1089 return;
1090 }
1091
1092 sh2_write16_unmapped(a, d, id);
1093}
1094
1095#define sh2_write16_dramN(n) \
1096 u16 *pd = &Pico32xMem->dram[n][(a & 0x1ffff) / 2]; \
1097 if (!(a & 0x20000)) { \
1098 *pd = d; \
1099 return; \
1100 } \
1101 /* overwrite */ \
1102 if (!(d & 0xff00)) d |= *pd & 0xff00; \
1103 if (!(d & 0x00ff)) d |= *pd & 0x00ff; \
1104 *pd = d
1105
1106static void sh2_write16_dram0(u32 a, u32 d, int id)
1107{
1108 sh2_write16_dramN(0);
1109}
1110
1111static void sh2_write16_dram1(u32 a, u32 d, int id)
1112{
1113 sh2_write16_dramN(1);
1114}
1115
1116static void sh2_write16_da(u32 a, u32 d, int id)
1117{
1118 ((u16 *)Pico32xMem->data_array[id])[(a & 0xfff) / 2] = d;
1119}
1120
1121
1122typedef struct {
1123 uptr addr; // stores (membase >> 1) or ((handler >> 1) | (1<<31))
1124 u32 mask;
1125} sh2_memmap;
1126
1127typedef u32 (sh2_read_handler)(u32 a, int id);
1128typedef void (sh2_write_handler)(u32 a, u32 d, int id);
1129
1130#define SH2MAP_ADDR2OFFS(a) \
1131 (((a >> 25) & 3) | ((a >> 27) & 0x1c))
1132
1133u32 p32x_sh2_read8(u32 a, SH2 *sh2)
1134{
1135 const sh2_memmap *sh2_map = sh2->read8_map;
1136 uptr p;
1137
1138 sh2_map += SH2MAP_ADDR2OFFS(a);
1139 p = sh2_map->addr;
1140 if (p & (1 << 31))
1141 return ((sh2_read_handler *)(p << 1))(a, sh2->is_slave);
1142 else
1143 return *(u8 *)((p << 1) + ((a & sh2_map->mask) ^ 1));
1144}
1145
1146u32 p32x_sh2_read16(u32 a, SH2 *sh2)
1147{
1148 const sh2_memmap *sh2_map = sh2->read16_map;
1149 uptr p;
1150
1151 sh2_map += SH2MAP_ADDR2OFFS(a);
1152 p = sh2_map->addr;
1153 if (p & (1 << 31))
1154 return ((sh2_read_handler *)(p << 1))(a, sh2->is_slave);
1155 else
1156 return *(u16 *)((p << 1) + ((a & sh2_map->mask) & ~1));
1157}
1158
1159u32 p32x_sh2_read32(u32 a, SH2 *sh2)
1160{
1161 const sh2_memmap *sh2_map = sh2->read16_map;
1162 sh2_read_handler *handler;
1163 u32 offs;
1164 uptr p;
1165
1166 offs = SH2MAP_ADDR2OFFS(a);
1167 sh2_map += offs;
1168 p = sh2_map->addr;
1169 if (!(p & (1 << 31))) {
1170 // XXX: maybe 32bit access instead with ror?
1171 u16 *pd = (u16 *)((p << 1) + ((a & sh2_map->mask) & ~1));
1172 return (pd[0] << 16) | pd[1];
1173 }
1174
1175 if (offs == 0x1f)
1176 return sh2_peripheral_read32(a, sh2->is_slave);
1177
1178 handler = (sh2_read_handler *)(p << 1);
1179 return (handler(a, sh2->is_slave) << 16) | handler(a + 2, sh2->is_slave);
1180}
1181
1182void p32x_sh2_write8(u32 a, u32 d, SH2 *sh2)
1183{
1184 const sh2_memmap *sh2_map = sh2->write8_map;
1185 uptr p;
1186
1187 sh2_map += SH2MAP_ADDR2OFFS(a);
1188 p = sh2_map->addr;
1189 if (p & (1 << 31))
1190 ((sh2_write_handler *)(p << 1))(a, d, sh2->is_slave);
1191 else
1192 *(u8 *)((p << 1) + ((a & sh2_map->mask) ^ 1)) = d;
1193}
1194
1195void p32x_sh2_write16(u32 a, u32 d, SH2 *sh2)
1196{
1197 const sh2_memmap *sh2_map = sh2->write16_map;
1198 uptr p;
1199
1200 sh2_map += SH2MAP_ADDR2OFFS(a);
1201 p = sh2_map->addr;
1202 if (p & (1 << 31))
1203 ((sh2_write_handler *)(p << 1))(a, d, sh2->is_slave);
1204 else
1205 *(u16 *)((p << 1) + ((a & sh2_map->mask) & ~1)) = d;
1206}
1207
1208void p32x_sh2_write32(u32 a, u32 d, SH2 *sh2)
1209{
1210 const sh2_memmap *sh2_map = sh2->write16_map;
1211 sh2_write_handler *handler;
1212 u32 offs;
1213 uptr p;
1214
1215 offs = SH2MAP_ADDR2OFFS(a);
1216 sh2_map += offs;
1217 p = sh2_map->addr;
1218 if (!(p & (1 << 31))) {
1219 u16 *pd = (u16 *)((p << 1) + ((a & sh2_map->mask) & ~1));
1220 pd[0] = d >> 16;
1221 pd[1] = d;
1222 return;
1223 }
1224
1225 if (offs == 0x1f) {
1226 sh2_peripheral_write32(a, d, sh2->is_slave);
1227 return;
1228 }
1229
1230 handler = (sh2_write_handler *)(p << 1);
1231 handler(a, d >> 16, sh2->is_slave);
1232 handler(a + 2, d, sh2->is_slave);
1233}
1234
1235// -----------------------------------------------------------------
1236
1237static const u16 msh2_code[] = {
1238 // trap instructions
1239 0xaffe, // bra <self>
1240 0x0009, // nop
1241 // have to wait a bit until m68k initial program finishes clearing stuff
1242 // to avoid races with game SH2 code, like in Tempo
1243 0xd004, // mov.l @(_m_ok,pc), r0
1244 0xd105, // mov.l @(_cnt,pc), r1
1245 0xd205, // mov.l @(_start,pc), r2
1246 0x71ff, // add #-1, r1
1247 0x4115, // cmp/pl r1
1248 0x89fc, // bt -2
1249 0xc208, // mov.l r0, @(h'20,gbr)
1250 0x6822, // mov.l @r2, r8
1251 0x482b, // jmp @r8
1252 0x0009, // nop
1253 ('M'<<8)|'_', ('O'<<8)|'K',
1254 0x0001, 0x0000,
1255 0x2200, 0x03e0 // master start pointer in ROM
1256};
1257
1258static const u16 ssh2_code[] = {
1259 0xaffe, // bra <self>
1260 0x0009, // nop
1261 // code to wait for master, in case authentic master BIOS is used
1262 0xd104, // mov.l @(_m_ok,pc), r1
1263 0xd206, // mov.l @(_start,pc), r2
1264 0xc608, // mov.l @(h'20,gbr), r0
1265 0x3100, // cmp/eq r0, r1
1266 0x8bfc, // bf #-2
1267 0xd003, // mov.l @(_s_ok,pc), r0
1268 0xc209, // mov.l r0, @(h'24,gbr)
1269 0x6822, // mov.l @r2, r8
1270 0x482b, // jmp @r8
1271 0x0009, // nop
1272 ('M'<<8)|'_', ('O'<<8)|'K',
1273 ('S'<<8)|'_', ('O'<<8)|'K',
1274 0x2200, 0x03e4 // slave start pointer in ROM
1275};
1276
1277#define HWSWAP(x) (((x) << 16) | ((x) >> 16))
1278static void get_bios(void)
1279{
1280 u16 *ps;
1281 u32 *pl;
1282 int i;
1283
1284 // M68K ROM
1285 if (p32x_bios_g != NULL) {
1286 elprintf(EL_STATUS|EL_32X, "32x: using supplied 68k BIOS");
1287 Byteswap(Pico32xMem->m68k_rom, p32x_bios_g, 0x100);
1288 }
1289 else {
1290 // generate 68k ROM
1291 ps = (u16 *)Pico32xMem->m68k_rom;
1292 pl = (u32 *)ps;
1293 for (i = 1; i < 0xc0/4; i++)
1294 pl[i] = HWSWAP(0x880200 + (i - 1) * 6);
1295
1296 // fill with nops
1297 for (i = 0xc0/2; i < 0x100/2; i++)
1298 ps[i] = 0x4e71;
1299
1300#if 0
1301 ps[0xc0/2] = 0x46fc;
1302 ps[0xc2/2] = 0x2700; // move #0x2700,sr
1303 ps[0xfe/2] = 0x60fe; // jump to self
1304#else
1305 ps[0xfe/2] = 0x4e75; // rts
1306#endif
1307 }
1308 // fill remaining m68k_rom page with game ROM
1309 memcpy(Pico32xMem->m68k_rom + 0x100, Pico.rom + 0x100, sizeof(Pico32xMem->m68k_rom) - 0x100);
1310
1311 // MSH2
1312 if (p32x_bios_m != NULL) {
1313 elprintf(EL_STATUS|EL_32X, "32x: using supplied master SH2 BIOS");
1314 Byteswap(Pico32xMem->sh2_rom_m, p32x_bios_m, sizeof(Pico32xMem->sh2_rom_m));
1315 }
1316 else {
1317 pl = (u32 *)Pico32xMem->sh2_rom_m;
1318
1319 // fill exception vector table to our trap address
1320 for (i = 0; i < 128; i++)
1321 pl[i] = HWSWAP(0x200);
1322
1323 // startup code
1324 memcpy(Pico32xMem->sh2_rom_m + 0x200, msh2_code, sizeof(msh2_code));
1325
1326 // reset SP
1327 pl[1] = pl[3] = HWSWAP(0x6040000);
1328 // start
1329 pl[0] = pl[2] = HWSWAP(0x204);
1330 }
1331
1332 // SSH2
1333 if (p32x_bios_s != NULL) {
1334 elprintf(EL_STATUS|EL_32X, "32x: using supplied slave SH2 BIOS");
1335 Byteswap(Pico32xMem->sh2_rom_s, p32x_bios_s, sizeof(Pico32xMem->sh2_rom_s));
1336 }
1337 else {
1338 pl = (u32 *)Pico32xMem->sh2_rom_s;
1339
1340 // fill exception vector table to our trap address
1341 for (i = 0; i < 128; i++)
1342 pl[i] = HWSWAP(0x200);
1343
1344 // startup code
1345 memcpy(Pico32xMem->sh2_rom_s + 0x200, ssh2_code, sizeof(ssh2_code));
1346
1347 // reset SP
1348 pl[1] = pl[3] = HWSWAP(0x603f800);
1349 // start
1350 pl[0] = pl[2] = HWSWAP(0x204);
1351 }
1352}
1353
1354#define MAP_MEMORY(m) ((uptr)(m) >> 1)
1355#define MAP_HANDLER(h) (((uptr)(h) >> 1) | (1 << 31))
1356
1357static sh2_memmap sh2_read8_map[0x20], sh2_read16_map[0x20];
1358static sh2_memmap sh2_write8_map[0x20], sh2_write16_map[0x20];
1359
1360void Pico32xSwapDRAM(int b)
1361{
1362 cpu68k_map_set(m68k_read8_map, 0x840000, 0x85ffff, Pico32xMem->dram[b], 0);
1363 cpu68k_map_set(m68k_read16_map, 0x840000, 0x85ffff, Pico32xMem->dram[b], 0);
1364 cpu68k_map_set(m68k_write8_map, 0x840000, 0x85ffff, Pico32xMem->dram[b], 0);
1365 cpu68k_map_set(m68k_write16_map, 0x840000, 0x85ffff, Pico32xMem->dram[b], 0);
1366
1367 // SH2
1368 sh2_read8_map[2].addr = sh2_read8_map[6].addr =
1369 sh2_read16_map[2].addr = sh2_read16_map[6].addr = MAP_MEMORY(Pico32xMem->dram[b]);
1370
1371 sh2_write8_map[2].addr = sh2_write8_map[6].addr = MAP_HANDLER(b ? sh2_write8_dram1 : sh2_write8_dram0);
1372 sh2_write16_map[2].addr = sh2_write16_map[6].addr = MAP_HANDLER(b ? sh2_write16_dram1 : sh2_write16_dram0);
1373}
1374
1375void PicoMemSetup32x(void)
1376{
1377 unsigned int rs;
1378 int i;
1379
1380 Pico32xMem = calloc(1, sizeof(*Pico32xMem));
1381 if (Pico32xMem == NULL) {
1382 elprintf(EL_STATUS, "OOM");
1383 return;
1384 }
1385
1386 dmac0 = (void *)&Pico32xMem->sh2_peri_regs[0][0x180 / 4];
1387
1388 get_bios();
1389
1390 // cartridge area becomes unmapped
1391 // XXX: we take the easy way and don't unmap ROM,
1392 // so that we can avoid handling the RV bit.
1393 // m68k_map_unmap(0x000000, 0x3fffff);
1394
1395 // MD ROM area
1396 rs = sizeof(Pico32xMem->m68k_rom);
1397 cpu68k_map_set(m68k_read8_map, 0x000000, rs - 1, Pico32xMem->m68k_rom, 0);
1398 cpu68k_map_set(m68k_read16_map, 0x000000, rs - 1, Pico32xMem->m68k_rom, 0);
1399 cpu68k_map_set(m68k_write8_map, 0x000000, rs - 1, PicoWrite8_hint, 1); // TODO verify
1400 cpu68k_map_set(m68k_write16_map, 0x000000, rs - 1, PicoWrite16_hint, 1);
1401
1402 // 32X ROM (unbanked, XXX: consider mirroring?)
1403 rs = (Pico.romsize + M68K_BANK_MASK) & ~M68K_BANK_MASK;
1404 if (rs > 0x80000)
1405 rs = 0x80000;
1406 cpu68k_map_set(m68k_read8_map, 0x880000, 0x880000 + rs - 1, Pico.rom, 0);
1407 cpu68k_map_set(m68k_read16_map, 0x880000, 0x880000 + rs - 1, Pico.rom, 0);
1408#ifdef EMU_F68K
1409 // setup FAME fetchmap
1410 PicoCpuFM68k.Fetch[0] = (u32)Pico32xMem->m68k_rom;
1411 for (rs = 0x88; rs < 0x90; rs++)
1412 PicoCpuFM68k.Fetch[rs] = (u32)Pico.rom - 0x880000;
1413#endif
1414
1415 // 32X ROM (banked)
1416 bank_switch(0);
1417
1418 // SYS regs
1419 cpu68k_map_set(m68k_read8_map, 0xa10000, 0xa1ffff, PicoRead8_32x_on, 1);
1420 cpu68k_map_set(m68k_read16_map, 0xa10000, 0xa1ffff, PicoRead16_32x_on, 1);
1421 cpu68k_map_set(m68k_write8_map, 0xa10000, 0xa1ffff, PicoWrite8_32x_on, 1);
1422 cpu68k_map_set(m68k_write16_map, 0xa10000, 0xa1ffff, PicoWrite16_32x_on, 1);
1423
1424 // SH2 maps: A31,A30,A29,CS1,CS0
1425 // all unmapped by default
1426 for (i = 0; i < 0x20; i++) {
1427 sh2_read8_map[i].addr = MAP_HANDLER(sh2_read8_unmapped);
1428 sh2_read16_map[i].addr = MAP_HANDLER(sh2_read16_unmapped);
1429 sh2_write8_map[i].addr = MAP_HANDLER(sh2_write8_unmapped);
1430 sh2_write16_map[i].addr = MAP_HANDLER(sh2_write16_unmapped);
1431 }
1432
1433 // CS0
1434 sh2_read8_map[0].addr = sh2_read8_map[4].addr = MAP_HANDLER(sh2_read8_cs0);
1435 sh2_read16_map[0].addr = sh2_read16_map[4].addr = MAP_HANDLER(sh2_read16_cs0);
1436 sh2_write8_map[0].addr = sh2_write8_map[4].addr = MAP_HANDLER(sh2_write8_cs0);
1437 sh2_write16_map[0].addr = sh2_write16_map[4].addr = MAP_HANDLER(sh2_write16_cs0);
1438 // CS1 - ROM
1439 sh2_read8_map[1].addr = sh2_read8_map[5].addr =
1440 sh2_read16_map[1].addr = sh2_read16_map[5].addr = MAP_MEMORY(Pico.rom);
1441 sh2_read8_map[1].mask = sh2_read8_map[5].mask =
1442 sh2_read16_map[1].mask = sh2_read16_map[5].mask = 0x3fffff; // FIXME
1443 // CS2 - DRAM - done by Pico32xSwapDRAM()
1444 sh2_read8_map[2].mask = sh2_read8_map[6].mask =
1445 sh2_read16_map[2].mask = sh2_read16_map[6].mask = 0x01ffff;
1446 // CS3 - SDRAM
1447 sh2_read8_map[3].addr = sh2_read8_map[7].addr =
1448 sh2_read16_map[3].addr = sh2_read16_map[7].addr =
1449 sh2_write8_map[3].addr = sh2_write8_map[7].addr =
1450 sh2_write16_map[3].addr = sh2_write16_map[7].addr = MAP_MEMORY(Pico32xMem->sdram);
1451 sh2_read8_map[3].mask = sh2_read8_map[7].mask =
1452 sh2_read16_map[3].mask = sh2_read16_map[7].mask =
1453 sh2_write8_map[3].mask = sh2_write8_map[7].mask =
1454 sh2_write16_map[3].mask = sh2_write16_map[7].mask = 0x03ffff;
1455 // SH2 data array
1456 sh2_read8_map[0x18].addr = MAP_HANDLER(sh2_read8_da);
1457 sh2_read16_map[0x18].addr = MAP_HANDLER(sh2_read16_da);
1458 sh2_write8_map[0x18].addr = MAP_HANDLER(sh2_write8_da);
1459 sh2_write16_map[0x18].addr = MAP_HANDLER(sh2_write16_da);
1460 // SH2 IO
1461 sh2_read8_map[0x1f].addr = MAP_HANDLER(sh2_peripheral_read8);
1462 sh2_read16_map[0x1f].addr = MAP_HANDLER(sh2_peripheral_read16);
1463 sh2_write8_map[0x1f].addr = MAP_HANDLER(sh2_peripheral_write8);
1464 sh2_write16_map[0x1f].addr = MAP_HANDLER(sh2_peripheral_write16);
1465
1466 // map DRAM area, both 68k and SH2
1467 Pico32xSwapDRAM(1);
1468
1469 msh2.read8_map = ssh2.read8_map = sh2_read8_map;
1470 msh2.read16_map = ssh2.read16_map = sh2_read16_map;
1471 msh2.write8_map = ssh2.write8_map = sh2_write8_map;
1472 msh2.write16_map = ssh2.write16_map = sh2_write16_map;
1473
1474 // setup poll detector
1475 m68k_poll.flag = P32XF_68KPOLL;
1476 m68k_poll.cyc_max = 64;
1477 sh2_poll[0].flag = P32XF_MSH2POLL;
1478 sh2_poll[0].cyc_max = 21;
1479 sh2_poll[1].flag = P32XF_SSH2POLL;
1480 sh2_poll[1].cyc_max = 16;
1481}
1482
1483// vim:shiftwidth=2:expandtab