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