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