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