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