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