32x: RLE mode + tweaks, VR runs but unstable as everything else
[picodrive.git] / pico / 32x / memory.c
1 #include "../pico_int.h"
2 #include "../memory.h"
3
4 static const char str_mars[] = "MARS";
5
6 struct Pico32xMem *Pico32xMem;
7
8 static void bank_switch(int b);
9
10 // poll detection
11 #define POLL_THRESHOLD 6
12
13 struct poll_det {
14   u32 addr, cycles, cyc_max;
15   int cnt, flag;
16 };
17 static struct poll_det m68k_poll, sh2_poll[2];
18
19 static int p32x_poll_detect(struct poll_det *pd, u32 a, u32 cycles, int is_vdp)
20 {
21   int ret = 0, flag = pd->flag;
22
23   if (is_vdp)
24     flag <<= 3;
25
26   if (a - 2 <= pd->addr && pd->addr <= a + 2 && cycles - pd->cycles < pd->cyc_max) {
27     pd->cnt++;
28     if (pd->cnt > POLL_THRESHOLD) {
29       if (!(Pico32x.emu_flags & flag)) {
30         elprintf(EL_32X, "%s poll addr %08x, cyc %u",
31           flag & (P32XF_68KPOLL|P32XF_68KVPOLL) ? "m68k" :
32           (flag & (P32XF_MSH2POLL|P32XF_MSH2VPOLL) ? "msh2" : "ssh2"), a, cycles - pd->cycles);
33         ret = 1;
34       }
35       Pico32x.emu_flags |= flag;
36     }
37   }
38   else
39     pd->cnt = 0;
40   pd->addr = a;
41   pd->cycles = cycles;
42
43   return ret;
44 }
45
46 static int p32x_poll_undetect(struct poll_det *pd, int is_vdp)
47 {
48   int ret = 0, flag = pd->flag;
49   if (is_vdp)
50     flag <<= 3; // VDP only
51   else
52     flag |= flag << 3; // both
53   if (Pico32x.emu_flags & flag) {
54     elprintf(EL_32X, "poll %02x -> %02x", Pico32x.emu_flags, Pico32x.emu_flags & ~flag);
55     ret = 1;
56   }
57   Pico32x.emu_flags &= ~flag;
58   pd->addr = pd->cnt = 0;
59   return ret;
60 }
61
62 void p32x_poll_event(int cpu_mask, int is_vdp)
63 {
64   if (cpu_mask & 1)
65     p32x_poll_undetect(&sh2_poll[0], is_vdp);
66   if (cpu_mask & 2)
67     p32x_poll_undetect(&sh2_poll[1], is_vdp);
68 }
69
70 // SH2 faking
71 //#define FAKE_SH2
72 int p32x_csum_faked;
73 #ifdef FAKE_SH2
74 static const u16 comm_fakevals[] = {
75   0x4d5f, 0x4f4b, // M_OK
76   0x535f, 0x4f4b, // S_OK
77   0x4D41, 0x5346, // MASF - Brutal Unleashed
78   0x5331, 0x4d31, // Darxide
79   0x5332, 0x4d32,
80   0x5333, 0x4d33,
81   0x0000, 0x0000, // eq for doom
82   0x0002, // Mortal Kombat
83 //  0, // pad
84 };
85
86 static u32 sh2_comm_faker(u32 a)
87 {
88   static int f = 0;
89   if (a == 0x28 && !p32x_csum_faked) {
90     p32x_csum_faked = 1;
91     return *(unsigned short *)(Pico.rom + 0x18e);
92   }
93   if (f >= sizeof(comm_fakevals) / sizeof(comm_fakevals[0]))
94     f = 0;
95   return comm_fakevals[f++];
96 }
97 #endif
98
99 // DMAC handling
100 static struct {
101   unsigned int sar0, dar0, tcr0; // src addr, dst addr, transfer count
102   unsigned int chcr0; // chan ctl
103   unsigned int sar1, dar1, tcr1; // same for chan 1
104   unsigned int chcr1;
105   int pad[4];
106   unsigned int dmaor;
107 } * dmac0;
108
109 static void dma_68k2sh2_do(void)
110 {
111   unsigned short *dreqlen = &Pico32x.regs[0x10 / 2];
112   int i;
113
114   if (dmac0->tcr0 != *dreqlen)
115     elprintf(EL_32X|EL_ANOMALY, "tcr0 and dreq len differ: %d != %d", dmac0->tcr0, *dreqlen);
116
117   // HACK: assume bus is busy and SH2 is halted
118   // XXX: use different mechanism for this, not poll det
119   Pico32x.emu_flags |= P32XF_MSH2POLL; // id ? P32XF_SSH2POLL : P32XF_MSH2POLL;
120
121   for (i = 0; i < Pico32x.dmac_ptr && dmac0->tcr0 > 0; i++) {
122     extern void p32x_sh2_write16(u32 a, u32 d, int id);
123       elprintf(EL_32X, "dmaw [%08x] %04x, left %d", dmac0->dar0, Pico32x.dmac_fifo[i], *dreqlen);
124     p32x_sh2_write16(dmac0->dar0, Pico32x.dmac_fifo[i], 0);
125     dmac0->dar0 += 2;
126     dmac0->tcr0--;
127     (*dreqlen)--;
128   }
129
130   Pico32x.dmac_ptr = 0; // HACK
131   Pico32x.regs[6 / 2] &= ~P32XS_FULL;
132   if (*dreqlen == 0)
133     Pico32x.regs[6 / 2] &= ~P32XS_68S; // transfer complete
134   if (dmac0->tcr0 == 0) {
135     dmac0->chcr0 |= 2; // DMA has ended normally
136     p32x_poll_undetect(&sh2_poll[0], 0);
137   }
138 }
139
140 // ------------------------------------------------------------------
141 // 68k regs
142
143 static u32 p32x_reg_read16(u32 a)
144 {
145   a &= 0x3e;
146
147   if (a == 2) // INTM, INTS
148     return ((Pico32x.sh2irqi[0] & P32XI_CMD) >> 4) | ((Pico32x.sh2irqi[1] & P32XI_CMD) >> 3);
149 #if 0
150   if ((a & 0x30) == 0x20)
151     return sh2_comm_faker(a);
152 #else
153   if ((a & 0x30) == 0x20 && p32x_poll_detect(&m68k_poll, a, SekCyclesDoneT(), 0)) {
154     SekEndRun(16);
155   }
156 #endif
157
158   if ((a & 0x30) == 0x30)
159     return p32x_pwm_read16(a);
160
161   return Pico32x.regs[a / 2];
162 }
163
164 static void p32x_reg_write8(u32 a, u32 d)
165 {
166   u16 *r = Pico32x.regs;
167   a &= 0x3f;
168
169   // for things like bset on comm port
170   m68k_poll.cnt = 0;
171
172   if (a == 1 && !(r[0] & 1)) {
173     r[0] |= 1;
174     Pico32xStartup();
175     return;
176   }
177
178   if (!(r[0] & 1))
179     return;
180
181   switch (a) {
182     case 0: // adapter ctl
183       r[0] = (r[0] & 0x83) | ((d << 8) & P32XS_FM);
184       return;
185     case 3: // irq ctl
186       if ((d & 1) && !(Pico32x.sh2irqi[0] & P32XI_CMD)) {
187         Pico32x.sh2irqi[0] |= P32XI_CMD;
188         p32x_update_irls();
189         SekEndRun(16);
190       }
191       if ((d & 2) && !(Pico32x.sh2irqi[1] & P32XI_CMD)) {
192         Pico32x.sh2irqi[1] |= P32XI_CMD;
193         p32x_update_irls();
194         SekEndRun(16);
195       }
196       return;
197     case 5: // bank
198       d &= 7;
199       if (r[4 / 2] != d) {
200         r[4 / 2] = d;
201         bank_switch(d);
202       }
203       return;
204     case 7: // DREQ ctl
205       r[6 / 2] = (r[6 / 2] & P32XS_FULL) | (d & (P32XS_68S|P32XS_DMA|P32XS_RV));
206       return;
207     case 0x1b: // TV
208       r[0x1a / 2] = d;
209       return;
210   }
211
212   if ((a & 0x30) == 0x20) {
213     u8 *r8 = (u8 *)r;
214     r8[a ^ 1] = d;
215     if (p32x_poll_undetect(&sh2_poll[0], 0) || p32x_poll_undetect(&sh2_poll[1], 0))
216       // if some SH2 is busy waiting, it needs to see the result ASAP
217       SekEndRun(16);
218     return;
219   }
220 }
221
222 static void p32x_reg_write16(u32 a, u32 d)
223 {
224   u16 *r = Pico32x.regs;
225   a &= 0x3e;
226
227   // for things like bset on comm port
228   m68k_poll.cnt = 0;
229
230   switch (a) {
231     case 0x00: // adapter ctl
232       r[0] = (r[0] & 0x83) | (d & P32XS_FM);
233       return;
234     case 0x10: // DREQ len
235       r[a / 2] = d & ~3;
236       return;
237     case 0x12: // FIFO reg
238       if (!(r[6 / 2] & P32XS_68S)) {
239         elprintf(EL_32X|EL_ANOMALY, "DREQ FIFO w16 without 68S?");
240         return;
241       }
242       if (Pico32x.dmac_ptr < DMAC_FIFO_LEN) {
243         Pico32x.dmac_fifo[Pico32x.dmac_ptr++] = d;
244         if ((Pico32x.dmac_ptr & 3) == 0 && (dmac0->chcr0 & 3) == 1 && (dmac0->dmaor & 1))
245           dma_68k2sh2_do();
246         if (Pico32x.dmac_ptr == DMAC_FIFO_LEN)
247           r[6 / 2] |= P32XS_FULL;
248       }
249       break;
250   }
251
252   // DREQ src, dst
253   if      ((a & 0x38) == 0x08) {
254     r[a / 2] = d;
255     return;
256   }
257   // comm port
258   else if ((a & 0x30) == 0x20 && r[a / 2] != d) {
259     r[a / 2] = d;
260     if (p32x_poll_undetect(&sh2_poll[0], 0) || p32x_poll_undetect(&sh2_poll[1], 0))
261       // if some SH2 is busy waiting, it needs to see the result ASAP
262       SekEndRun(16);
263     return;
264   }
265   // PWM
266   else if ((a & 0x30) == 0x30) {
267     p32x_pwm_write16(a, d);
268     return;
269   }
270
271   p32x_reg_write8(a + 1, d);
272 }
273
274 // ------------------------------------------------------------------
275 // VDP regs
276 static u32 p32x_vdp_read16(u32 a)
277 {
278   a &= 0x0e;
279
280   return Pico32x.vdp_regs[a / 2];
281 }
282
283 static void p32x_vdp_write8(u32 a, u32 d)
284 {
285   u16 *r = Pico32x.vdp_regs;
286   a &= 0x0f;
287
288   // for FEN checks between writes
289   sh2_poll[0].cnt = 0;
290
291   // TODO: verify what's writeable
292   switch (a) {
293     case 0x01:
294       // priority inversion is handled in palette
295       if ((r[0] ^ d) & P32XV_PRI)
296         Pico32x.dirty_pal = 1;
297       r[0] = (r[0] & P32XV_nPAL) | (d & 0xff);
298       if ((d & 3) == 3)
299         elprintf(EL_32X|EL_ANOMALY, "TODO: mode3");
300       break;
301     case 0x05: // fill len
302       r[4 / 2] = d & 0xff;
303       break;
304     case 0x0b:
305       d &= 1;
306       Pico32x.pending_fb = d;
307       // if we are blanking and FS bit is changing
308       if (((r[0x0a/2] & P32XV_VBLK) || (r[0] & P32XV_Mx) == 0) && ((r[0x0a/2] ^ d) & P32XV_FS)) {
309         r[0x0a/2] ^= 1;
310         Pico32xSwapDRAM(d ^ 1);
311         elprintf(EL_32X, "VDP FS: %d", r[0x0a/2] & P32XV_FS);
312       }
313       break;
314   }
315 }
316
317 static void p32x_vdp_write16(u32 a, u32 d)
318 {
319   a &= 0x0e;
320   if (a == 6) { // fill start
321     Pico32x.vdp_regs[6 / 2] = d;
322     return;
323   }
324   if (a == 8) { // fill data
325     u16 *dram = Pico32xMem->dram[(Pico32x.vdp_regs[0x0a/2] & P32XV_FS) ^ 1];
326     int len = Pico32x.vdp_regs[4 / 2] + 1;
327     a = Pico32x.vdp_regs[6 / 2];
328     while (len--) {
329       dram[a] = d;
330       a = (a & 0xff00) | ((a + 1) & 0xff);
331     }
332     Pico32x.vdp_regs[6 / 2] = a;
333     Pico32x.vdp_regs[8 / 2] = d;
334     return;
335   }
336
337   p32x_vdp_write8(a | 1, d);
338 }
339
340 // ------------------------------------------------------------------
341 // SH2 regs
342
343 static u32 p32x_sh2reg_read16(u32 a, int cpuid)
344 {
345   u16 *r = Pico32x.regs;
346   a &= 0xfe; // ?
347
348   switch (a) {
349     case 0x00: // adapter/irq ctl
350       return (r[0] & P32XS_FM) | Pico32x.sh2_regs[0] | Pico32x.sh2irq_mask[cpuid];
351     case 0x04: // H count
352       return Pico32x.sh2_regs[4 / 2];
353     case 0x10: // DREQ len
354       return r[a / 2];
355   }
356
357   // DREQ src, dst
358   if ((a & 0x38) == 0x08)
359     return r[a / 2];
360   // comm port
361   if ((a & 0x30) == 0x20) {
362     if (p32x_poll_detect(&sh2_poll[cpuid], a, ash2_cycles_done(), 0))
363       ash2_end_run(8);
364     return r[a / 2];
365   }
366   if ((a & 0x30) == 0x30) {
367     sh2_poll[cpuid].cnt = 0;
368     return p32x_pwm_read16(a);
369   }
370
371   return 0;
372 }
373
374 static void p32x_sh2reg_write8(u32 a, u32 d, int cpuid)
375 {
376   a &= 0xff;
377   switch (a) {
378     case 0: // FM
379       Pico32x.regs[0] &= ~P32XS_FM;
380       Pico32x.regs[0] |= (d << 8) & P32XS_FM;
381       return;
382     case 1: // 
383       Pico32x.sh2irq_mask[cpuid] = d & 0x8f;
384       Pico32x.sh2_regs[0] &= ~0x80;
385       Pico32x.sh2_regs[0] |= d & 0x80;
386       p32x_update_irls();
387       return;
388     case 5: // H count
389       Pico32x.sh2_regs[4 / 2] = d & 0xff;
390       return;
391   }
392
393   if ((a & 0x30) == 0x20) {
394     u8 *r8 = (u8 *)Pico32x.regs;
395     r8[a ^ 1] = d;
396     p32x_poll_undetect(&m68k_poll, 0);
397     p32x_poll_undetect(&sh2_poll[cpuid ^ 1], 0);
398     return;
399   }
400 }
401
402 static void p32x_sh2reg_write16(u32 a, u32 d, int cpuid)
403 {
404   a &= 0xfe;
405
406   // comm
407   if ((a & 0x30) == 0x20 && Pico32x.regs[a/2] != d) {
408     Pico32x.regs[a / 2] = d;
409     p32x_poll_undetect(&m68k_poll, 0);
410     p32x_poll_undetect(&sh2_poll[cpuid ^ 1], 0);
411     return;
412   }
413   // PWM
414   else if ((a & 0x30) == 0x30) {
415     p32x_pwm_write16(a, d);
416     return;
417   }
418
419   switch (a) {
420     case 0: // FM
421       Pico32x.regs[0] &= ~P32XS_FM;
422       Pico32x.regs[0] |= d & P32XS_FM;
423       break;
424     case 0x14: Pico32x.sh2irqs &= ~P32XI_VRES; goto irls;
425     case 0x16: Pico32x.sh2irqs &= ~P32XI_VINT; goto irls;
426     case 0x18: Pico32x.sh2irqs &= ~P32XI_HINT; goto irls;
427     case 0x1a: Pico32x.sh2irqi[cpuid] &= ~P32XI_CMD; goto irls;
428     case 0x1c:
429       Pico32x.sh2irqs &= ~P32XI_PWM;
430       p32x_pwm_irq_check(0);
431       goto irls;
432   }
433
434   p32x_sh2reg_write8(a | 1, d, cpuid);
435   return;
436
437 irls:
438   p32x_update_irls();
439 }
440
441 // ------------------------------------------------------------------
442 // SH2 internal peripherals
443 static u32 sh2_peripheral_read8(u32 a, int id)
444 {
445   u8 *r = (void *)Pico32xMem->sh2_peri_regs[id];
446   u32 d;
447
448   a &= 0x1ff;
449   d = r[a];
450   if (a == 4)
451     d = 0x84; // SCI SSR
452
453   elprintf(EL_32X, "%csh2 peri r8  [%08x]       %02x @%06x", id ? 's' : 'm', a | ~0x1ff, d, sh2_pc(id));
454   return d;
455 }
456
457 static u32 sh2_peripheral_read32(u32 a, int id)
458 {
459   u32 d;
460   a &= 0x1fc;
461   d = Pico32xMem->sh2_peri_regs[id][a / 4];
462
463   elprintf(EL_32X, "%csh2 peri r32 [%08x] %08x @%06x", id ? 's' : 'm', a | ~0x1ff, d, sh2_pc(id));
464   return d;
465 }
466
467 static void sh2_peripheral_write8(u32 a, u32 d, int id)
468 {
469   u8 *r = (void *)Pico32xMem->sh2_peri_regs[id];
470   elprintf(EL_32X, "%csh2 peri w8  [%08x]       %02x @%06x", id ? 's' : 'm', a, d, sh2_pc(id));
471
472   a &= 0x1ff;
473   r[a] = d;
474 }
475
476 static void sh2_peripheral_write32(u32 a, u32 d, int id)
477 {
478   u32 *r = Pico32xMem->sh2_peri_regs[id];
479   elprintf(EL_32X, "%csh2 peri w32 [%08x] %08x @%06x", id ? 's' : 'm', a, d, sh2_pc(id));
480
481   a &= 0x1fc;
482   r[a / 4] = d;
483
484   switch (a) {
485     // division unit (TODO: verify):
486     case 0x104: // DVDNT: divident L, starts divide
487       elprintf(EL_32X, "%csh2 divide %08x / %08x", id ? 's' : 'm', d, r[0x100 / 4]);
488       if (r[0x100 / 4]) {
489         signed int divisor = r[0x100 / 4];
490                        r[0x118 / 4] = r[0x110 / 4] = (signed int)d % divisor;
491         r[0x104 / 4] = r[0x11c / 4] = r[0x114 / 4] = (signed int)d / divisor;
492       }
493       break;
494     case 0x114:
495       elprintf(EL_32X, "%csh2 divide %08x%08x / %08x @%08x",
496         id ? 's' : 'm', r[0x110 / 4], d, r[0x100 / 4], sh2_pc(id));
497       if (r[0x100 / 4]) {
498         signed long long divident = (signed long long)r[0x110 / 4] << 32 | d;
499         signed int divisor = r[0x100 / 4];
500         // XXX: undocumented mirroring to 0x118,0x11c?
501         r[0x118 / 4] = r[0x110 / 4] = divident % divisor;
502         r[0x11c / 4] = r[0x114 / 4] = divident / divisor;
503       }
504       break;
505   }
506
507   if ((a == 0x1b0 || a == 0x18c) && (dmac0->chcr0 & 3) == 1 && (dmac0->dmaor & 1)) {
508     elprintf(EL_32X, "sh2 DMA %08x -> %08x, cnt %d, chcr %04x @%06x",
509       dmac0->sar0, dmac0->dar0, dmac0->tcr0, dmac0->chcr0, sh2_pc(id));
510     dmac0->tcr0 &= 0xffffff;
511
512     // HACK: assume 68k starts writing soon and end the timeslice
513     ash2_end_run(16);
514
515     // DREQ is only sent after first 4 words are written.
516     // we do multiple of 4 words to avoid messing up alignment
517     if (dmac0->sar0 == 0x20004012 && Pico32x.dmac_ptr && (Pico32x.dmac_ptr & 3) == 0) {
518       elprintf(EL_32X, "68k -> sh2 DMA");
519       dma_68k2sh2_do();
520     }
521   }
522 }
523
524 // ------------------------------------------------------------------
525 // default 32x handlers
526 u32 PicoRead8_32x(u32 a)
527 {
528   u32 d = 0;
529   if ((a & 0xffc0) == 0x5100) { // a15100
530     d = p32x_reg_read16(a);
531     goto out_16to8;
532   }
533
534   if (!(Pico32x.regs[0] & 1))
535     goto no_vdp;
536
537   if ((a & 0xfff0) == 0x5180) { // a15180
538     d = p32x_vdp_read16(a);
539     goto out_16to8;
540   }
541
542   if ((a & 0xfe00) == 0x5200) { // a15200
543     d = Pico32xMem->pal[(a & 0x1ff) / 2];
544     goto out_16to8;
545   }
546
547 no_vdp:
548   if ((a & 0xfffc) == 0x30ec) { // a130ec
549     d = str_mars[a & 3];
550     goto out;
551   }
552
553   elprintf(EL_UIO, "m68k unmapped r8  [%06x] @%06x", a, SekPc);
554   return d;
555
556 out_16to8:
557   if (a & 1)
558     d &= 0xff;
559   else
560     d >>= 8;
561
562 out:
563   elprintf(EL_32X, "m68k 32x r8  [%06x]   %02x @%06x", a, d, SekPc);
564   return d;
565 }
566
567 u32 PicoRead16_32x(u32 a)
568 {
569   u32 d = 0;
570   if ((a & 0xffc0) == 0x5100) { // a15100
571     d = p32x_reg_read16(a);
572     goto out;
573   }
574
575   if (!(Pico32x.regs[0] & 1))
576     goto no_vdp;
577
578   if ((a & 0xfff0) == 0x5180) { // a15180
579     d = p32x_vdp_read16(a);
580     goto out;
581   }
582
583   if ((a & 0xfe00) == 0x5200) { // a15200
584     d = Pico32xMem->pal[(a & 0x1ff) / 2];
585     goto out;
586   }
587
588 no_vdp:
589   if ((a & 0xfffc) == 0x30ec) { // a130ec
590     d = !(a & 2) ? ('M'<<8)|'A' : ('R'<<8)|'S';
591     goto out;
592   }
593
594   elprintf(EL_UIO, "m68k unmapped r16 [%06x] @%06x", a, SekPc);
595   return d;
596
597 out:
598   elprintf(EL_32X, "m68k 32x r16 [%06x] %04x @%06x", a, d, SekPc);
599   return d;
600 }
601
602 void PicoWrite8_32x(u32 a, u32 d)
603 {
604   if ((a & 0xfc00) == 0x5000)
605     elprintf(EL_32X, "m68k 32x w8  [%06x]   %02x @%06x", a, d & 0xff, SekPc);
606
607   if ((a & 0xffc0) == 0x5100) { // a15100
608     p32x_reg_write8(a, d);
609     return;
610   }
611
612   if (!(Pico32x.regs[0] & 1))
613     goto no_vdp;
614
615   if ((a & 0xfff0) == 0x5180) { // a15180
616     p32x_vdp_write8(a, d);
617     return;
618   }
619
620   // TODO: verify
621   if ((a & 0xfe00) == 0x5200) { // a15200
622     elprintf(EL_32X|EL_ANOMALY, "m68k 32x PAL w8  [%06x]   %02x @%06x", a, d & 0xff, SekPc);
623     ((u8 *)Pico32xMem->pal)[(a & 0x1ff) ^ 1] = d;
624     Pico32x.dirty_pal = 1;
625     return;
626   }
627
628 no_vdp:
629   elprintf(EL_UIO, "m68k unmapped w8  [%06x]   %02x @%06x", a, d & 0xff, SekPc);
630 }
631
632 void PicoWrite16_32x(u32 a, u32 d)
633 {
634   if ((a & 0xfc00) == 0x5000)
635     elprintf(EL_UIO, "m68k 32x w16 [%06x] %04x @%06x", a, d & 0xffff, SekPc);
636
637   if ((a & 0xffc0) == 0x5100) { // a15100
638     p32x_reg_write16(a, d);
639     return;
640   }
641
642   if (!(Pico32x.regs[0] & 1))
643     goto no_vdp;
644
645   if ((a & 0xfff0) == 0x5180) { // a15180
646     p32x_vdp_write16(a, d);
647     return;
648   }
649
650   if ((a & 0xfe00) == 0x5200) { // a15200
651     Pico32xMem->pal[(a & 0x1ff) / 2] = d;
652     Pico32x.dirty_pal = 1;
653     return;
654   }
655
656 no_vdp:
657   elprintf(EL_UIO, "m68k unmapped w16 [%06x] %04x @%06x", a, d & 0xffff, SekPc);
658 }
659
660 // hint vector is writeable
661 static void PicoWrite8_hint(u32 a, u32 d)
662 {
663   if ((a & 0xfffc) == 0x0070) {
664     Pico32xMem->m68k_rom[a ^ 1] = d;
665     return;
666   }
667
668   elprintf(EL_UIO, "m68k unmapped w8  [%06x]   %02x @%06x", a, d & 0xff, SekPc);
669 }
670
671 static void PicoWrite16_hint(u32 a, u32 d)
672 {
673   if ((a & 0xfffc) == 0x0070) {
674     ((u16 *)Pico32xMem->m68k_rom)[a/2] = d;
675     return;
676   }
677
678   elprintf(EL_UIO, "m68k unmapped w16 [%06x] %04x @%06x", a, d & 0xffff, SekPc);
679 }
680
681 void Pico32xSwapDRAM(int b)
682 {
683   cpu68k_map_set(m68k_read8_map,   0x840000, 0x85ffff, Pico32xMem->dram[b], 0);
684   cpu68k_map_set(m68k_read16_map,  0x840000, 0x85ffff, Pico32xMem->dram[b], 0);
685   cpu68k_map_set(m68k_write8_map,  0x840000, 0x85ffff, Pico32xMem->dram[b], 0);
686   cpu68k_map_set(m68k_write16_map, 0x840000, 0x85ffff, Pico32xMem->dram[b], 0);
687 }
688
689 static void bank_switch(int b)
690 {
691   unsigned int rs, bank;
692
693   bank = b << 20;
694   if (bank >= Pico.romsize) {
695     elprintf(EL_32X|EL_ANOMALY, "missing bank @ %06x", bank);
696     return;
697   }
698
699   // 32X ROM (unbanked, XXX: consider mirroring?)
700   rs = (Pico.romsize + M68K_BANK_MASK) & ~M68K_BANK_MASK;
701   rs -= bank;
702   if (rs > 0x100000)
703     rs = 0x100000;
704   cpu68k_map_set(m68k_read8_map,   0x900000, 0x900000 + rs - 1, Pico.rom + bank, 0);
705   cpu68k_map_set(m68k_read16_map,  0x900000, 0x900000 + rs - 1, Pico.rom + bank, 0);
706
707   elprintf(EL_32X, "bank %06x-%06x -> %06x", 0x900000, 0x900000 + rs - 1, bank);
708 }
709
710 // -----------------------------------------------------------------
711 //                              SH2  
712 // -----------------------------------------------------------------
713
714 u32 p32x_sh2_read8(u32 a, int id)
715 {
716   u32 d = 0;
717
718   if (id == 0 && a < sizeof(Pico32xMem->sh2_rom_m))
719     return Pico32xMem->sh2_rom_m[a ^ 1];
720   if (id == 1 && a < sizeof(Pico32xMem->sh2_rom_s))
721     return Pico32xMem->sh2_rom_s[a ^ 1];
722
723   if ((a & 0xdffc0000) == 0x06000000)
724     return Pico32xMem->sdram[(a & 0x3ffff) ^ 1];
725
726   if ((a & 0xdfc00000) == 0x02000000)
727     if ((a & 0x003fffff) < Pico.romsize)
728       return Pico.rom[(a & 0x3fffff) ^ 1];
729
730   if ((a & ~0xfff) == 0xc0000000)
731     return Pico32xMem->data_array[id][(a & 0xfff) ^ 1];
732
733   if ((a & 0xdffe0000) == 0x04000000) {
734     u8 *dram = (u8 *)Pico32xMem->dram[(Pico32x.vdp_regs[0x0a/2] & P32XV_FS) ^ 1];
735     return dram[(a & 0x1ffff) ^ 1];
736   }
737
738   if ((a & 0xdfffff00) == 0x4000) {
739     d = p32x_sh2reg_read16(a, id);
740     goto out_16to8;
741   }
742
743   if ((a & 0xdfffff00) == 0x4100) {
744     d = p32x_vdp_read16(a);
745     if (p32x_poll_detect(&sh2_poll[id], a, ash2_cycles_done(), 1))
746       ash2_end_run(8);
747     goto out_16to8;
748   }
749
750   if ((a & 0xdfffff00) == 0x4200) {
751     d = Pico32xMem->pal[(a & 0x1ff) / 2];
752     goto out_16to8;
753   }
754
755   if ((a & 0xfffffe00) == 0xfffffe00)
756     return sh2_peripheral_read8(a, id);
757
758   elprintf(EL_UIO, "%csh2 unmapped r8  [%08x]       %02x @%06x",
759     id ? 's' : 'm', a, d, sh2_pc(id));
760   return d;
761
762 out_16to8:
763   if (a & 1)
764     d &= 0xff;
765   else
766     d >>= 8;
767
768   elprintf(EL_32X, "%csh2 r8  [%08x]       %02x @%06x",
769     id ? 's' : 'm', a, d, sh2_pc(id));
770   return d;
771 }
772
773 u32 p32x_sh2_read16(u32 a, int id)
774 {
775   u32 d = 0;
776
777   if (id == 0 && a < sizeof(Pico32xMem->sh2_rom_m))
778     return *(u16 *)(Pico32xMem->sh2_rom_m + a);
779   if (id == 1 && a < sizeof(Pico32xMem->sh2_rom_s))
780     return *(u16 *)(Pico32xMem->sh2_rom_s + a);
781
782   if ((a & 0xdffc0000) == 0x06000000)
783     return ((u16 *)Pico32xMem->sdram)[(a & 0x3ffff) / 2];
784
785   if ((a & 0xdfc00000) == 0x02000000)
786     if ((a & 0x003fffff) < Pico.romsize)
787       return ((u16 *)Pico.rom)[(a & 0x3fffff) / 2];
788
789   if ((a & ~0xfff) == 0xc0000000)
790     return ((u16 *)Pico32xMem->data_array[id])[(a & 0xfff) / 2];
791
792   if ((a & 0xdffe0000) == 0x04000000)
793     return Pico32xMem->dram[(Pico32x.vdp_regs[0x0a/2] & P32XV_FS) ^ 1][(a & 0x1ffff) / 2];
794
795   if ((a & 0xdfffff00) == 0x4000) {
796     d = p32x_sh2reg_read16(a, id);
797     if (!(EL_LOGMASK & EL_PWM) && (a & 0x30) == 0x30) // hide PWM
798       return d;
799     goto out;
800   }
801
802   if ((a & 0xdfffff00) == 0x4100) {
803     d = p32x_vdp_read16(a);
804     if (p32x_poll_detect(&sh2_poll[id], a, ash2_cycles_done(), 1))
805       ash2_end_run(8);
806     goto out;
807   }
808
809   if ((a & 0xdfffff00) == 0x4200) {
810     d = Pico32xMem->pal[(a & 0x1ff) / 2];
811     goto out;
812   }
813
814   elprintf(EL_UIO, "%csh2 unmapped r16 [%08x]     %04x @%06x",
815     id ? 's' : 'm', a, d, sh2_pc(id));
816   return d;
817
818 out:
819   elprintf(EL_32X, "%csh2 r16 [%08x]     %04x @%06x",
820     id ? 's' : 'm', a, d, sh2_pc(id));
821   return d;
822 }
823
824 u32 p32x_sh2_read32(u32 a, int id)
825 {
826   if ((a & 0xfffffe00) == 0xfffffe00)
827     return sh2_peripheral_read32(a, id);
828
829 //  elprintf(EL_UIO, "sh2 r32 [%08x] %08x @%06x", a, d, ash2_pc());
830   return (p32x_sh2_read16(a, id) << 16) | p32x_sh2_read16(a + 2, id);
831 }
832
833 void p32x_sh2_write8(u32 a, u32 d, int id)
834 {
835   if ((a & 0xdffffc00) == 0x4000)
836     elprintf(EL_32X, "%csh2 w8  [%08x]       %02x @%06x",
837       id ? 's' : 'm', a, d & 0xff, sh2_pc(id));
838
839   if ((a & 0xdffc0000) == 0x06000000) {
840     Pico32xMem->sdram[(a & 0x3ffff) ^ 1] = d;
841     return;
842   }
843
844   if ((a & 0xdffc0000) == 0x04000000) {
845     u8 *dram;
846     if (!(a & 0x20000) || d) {
847       dram = (u8 *)Pico32xMem->dram[(Pico32x.vdp_regs[0x0a/2] & P32XV_FS) ^ 1];
848       dram[(a & 0x1ffff) ^ 1] = d;
849       return;
850     }
851   }
852
853   if ((a & ~0xfff) == 0xc0000000) {
854     Pico32xMem->data_array[id][(a & 0xfff) ^ 1] = d;
855     return;
856   }
857
858   if ((a & 0xdfffff00) == 0x4100) {
859     p32x_vdp_write8(a, d);
860     return;
861   }
862
863   if ((a & 0xdfffff00) == 0x4000) {
864     p32x_sh2reg_write8(a, d, id);
865     return;
866   }
867
868   if ((a & 0xfffffe00) == 0xfffffe00) {
869     sh2_peripheral_write8(a, d, id);
870     return;
871   }
872
873   elprintf(EL_UIO, "%csh2 unmapped w8  [%08x]       %02x @%06x",
874     id ? 's' : 'm', a, d & 0xff, sh2_pc(id));
875 }
876
877 void p32x_sh2_write16(u32 a, u32 d, int id)
878 {
879   if ((a & 0xdffffc00) == 0x4000 && ((EL_LOGMASK & EL_PWM) || (a & 0x30) != 0x30)) // hide PWM
880     elprintf(EL_32X, "%csh2 w16 [%08x]     %04x @%06x",
881       id ? 's' : 'm', a, d & 0xffff, sh2_pc(id));
882
883   // ignore "Associative purge space"
884   if ((a & 0xf8000000) == 0x40000000)
885     return;
886
887   if ((a & 0xdffc0000) == 0x06000000) {
888     ((u16 *)Pico32xMem->sdram)[(a & 0x3ffff) / 2] = d;
889     return;
890   }
891
892   if ((a & ~0xfff) == 0xc0000000) {
893     ((u16 *)Pico32xMem->data_array[id])[(a & 0xfff) / 2] = d;
894     return;
895   }
896
897   if ((a & 0xdffc0000) == 0x04000000) {
898     u16 *pd = &Pico32xMem->dram[(Pico32x.vdp_regs[0x0a/2] & P32XV_FS) ^ 1][(a & 0x1ffff) / 2];
899     if (!(a & 0x20000)) {
900       *pd = d;
901       return;
902     }
903     // overwrite
904     if (!(d & 0xff00)) d |= *pd & 0xff00;
905     if (!(d & 0x00ff)) d |= *pd & 0x00ff;
906     *pd = d;
907     return;
908   }
909
910   if ((a & 0xdfffff00) == 0x4100) {
911     sh2_poll[id].cnt = 0; // for poll before VDP accesses
912     p32x_vdp_write16(a, d);
913     return;
914   }
915
916   if ((a & 0xdffffe00) == 0x4200) {
917     Pico32xMem->pal[(a & 0x1ff) / 2] = d;
918     Pico32x.dirty_pal = 1;
919     return;
920   }
921
922   if ((a & 0xdfffff00) == 0x4000) {
923     p32x_sh2reg_write16(a, d, id);
924     return;
925   }
926
927   elprintf(EL_UIO, "%csh2 unmapped w16 [%08x]     %04x @%06x",
928     id ? 's' : 'm', a, d & 0xffff, sh2_pc(id));
929 }
930
931 void p32x_sh2_write32(u32 a, u32 d, int id)
932 {
933   if ((a & 0xfffffe00) == 0xfffffe00) {
934     sh2_peripheral_write32(a, d, id);
935     return;
936   }
937
938   p32x_sh2_write16(a, d >> 16, id);
939   p32x_sh2_write16(a + 2, d, id);
940 }
941
942 #define HWSWAP(x) (((x) << 16) | ((x) >> 16))
943 void PicoMemSetup32x(void)
944 {
945   unsigned short *ps;
946   unsigned int *pl;
947   unsigned int rs;
948   int i;
949
950   Pico32xMem = calloc(1, sizeof(*Pico32xMem));
951   if (Pico32xMem == NULL) {
952     elprintf(EL_STATUS, "OOM");
953     return;
954   }
955
956   dmac0 = (void *)&Pico32xMem->sh2_peri_regs[0][0x180 / 4];
957
958   // generate 68k ROM
959   ps = (unsigned short *)Pico32xMem->m68k_rom;
960   pl = (unsigned int *)Pico32xMem->m68k_rom;
961   for (i = 1; i < 0xc0/4; i++)
962     pl[i] = HWSWAP(0x880200 + (i - 1) * 6);
963
964   // fill with nops
965   for (i = 0xc0/2; i < 0x100/2; i++)
966     ps[i] = 0x4e71;
967
968 #if 0
969   ps[0xc0/2] = 0x46fc;
970   ps[0xc2/2] = 0x2700; // move #0x2700,sr
971   ps[0xfe/2] = 0x60fe; // jump to self
972 #else
973   ps[0xfe/2] = 0x4e75; // rts
974 #endif
975
976   // fill remaining mem with ROM
977   memcpy(Pico32xMem->m68k_rom + 0x100, Pico.rom + 0x100, sizeof(Pico32xMem->m68k_rom) - 0x100);
978
979   // 32X ROM
980   // TODO: move
981   {
982     FILE *f = fopen("32X_M_BIOS.BIN", "rb");
983     int i;
984     if (f == NULL) {
985       printf("missing 32X_M_BIOS.BIN\n");
986       exit(1);
987     }
988     fread(Pico32xMem->sh2_rom_m, 1, sizeof(Pico32xMem->sh2_rom_m), f);
989     fclose(f);
990     f = fopen("32X_S_BIOS.BIN", "rb");
991     if (f == NULL) {
992       printf("missing 32X_S_BIOS.BIN\n");
993       exit(1);
994     }
995     fread(Pico32xMem->sh2_rom_s, 1, sizeof(Pico32xMem->sh2_rom_s), f);
996     fclose(f);
997     // byteswap
998     for (i = 0; i < sizeof(Pico32xMem->sh2_rom_m); i += 2) {
999       int t = Pico32xMem->sh2_rom_m[i];
1000       Pico32xMem->sh2_rom_m[i] = Pico32xMem->sh2_rom_m[i + 1];
1001       Pico32xMem->sh2_rom_m[i + 1] = t;
1002     }
1003     for (i = 0; i < sizeof(Pico32xMem->sh2_rom_s); i += 2) {
1004       int t = Pico32xMem->sh2_rom_s[i];
1005       Pico32xMem->sh2_rom_s[i] = Pico32xMem->sh2_rom_s[i + 1];
1006       Pico32xMem->sh2_rom_s[i + 1] = t;
1007     }
1008   }
1009
1010   // cartridge area becomes unmapped
1011   // XXX: we take the easy way and don't unmap ROM,
1012   // so that we can avoid handling the RV bit.
1013   // m68k_map_unmap(0x000000, 0x3fffff);
1014
1015   // MD ROM area
1016   rs = sizeof(Pico32xMem->m68k_rom);
1017   cpu68k_map_set(m68k_read8_map,   0x000000, rs - 1, Pico32xMem->m68k_rom, 0);
1018   cpu68k_map_set(m68k_read16_map,  0x000000, rs - 1, Pico32xMem->m68k_rom, 0);
1019   cpu68k_map_set(m68k_write8_map,  0x000000, rs - 1, PicoWrite8_hint, 1); // TODO verify
1020   cpu68k_map_set(m68k_write16_map, 0x000000, rs - 1, PicoWrite16_hint, 1);
1021
1022   // DRAM area
1023   Pico32xSwapDRAM(1);
1024
1025   // 32X ROM (unbanked, XXX: consider mirroring?)
1026   rs = (Pico.romsize + M68K_BANK_MASK) & ~M68K_BANK_MASK;
1027   if (rs > 0x80000)
1028     rs = 0x80000;
1029   cpu68k_map_set(m68k_read8_map,   0x880000, 0x880000 + rs - 1, Pico.rom, 0);
1030   cpu68k_map_set(m68k_read16_map,  0x880000, 0x880000 + rs - 1, Pico.rom, 0);
1031
1032   // 32X ROM (banked)
1033   bank_switch(0);
1034
1035   // setup poll detector
1036   m68k_poll.flag = P32XF_68KPOLL;
1037   m68k_poll.cyc_max = 64;
1038   sh2_poll[0].flag = P32XF_MSH2POLL;
1039   sh2_poll[0].cyc_max = 16;
1040   sh2_poll[1].flag = P32XF_SSH2POLL;
1041   sh2_poll[1].cyc_max = 16;
1042 }
1043