32x: some missed code from MAME, minor tweaks
[picodrive.git] / pico / 32x / memory.c
1 #include "../pico_int.h"
2 #include "../memory.h"
3
4 static const char str_mars[] = "MARS";
5
6 struct Pico32xMem *Pico32xMem;
7
8 static void bank_switch(int b);
9
10 #define MSB8(x) ((x) >> 8)
11
12 // poll detection
13 struct poll_det {
14         int addr, pc, cnt;
15 };
16 static struct poll_det m68k_poll;
17 static struct poll_det msh2_poll;
18
19 #define POLL_THRESHOLD 6
20
21 static int poll_detect(struct poll_det *pd, u32 a, u32 pc, int flag)
22 {
23   int ret = 0;
24
25   if (a - 2 <= pd->addr && pd->addr <= a + 2 && pd->pc == pc) {
26     pd->cnt++;
27     if (pd->cnt > POLL_THRESHOLD) {
28       if (!(Pico32x.emu_flags & flag)) {
29         elprintf(EL_32X, "%s poll addr %08x @ %06x",
30           flag == P32XF_68KPOLL ? "m68k" : (flag == P32XF_MSH2POLL ? "msh2" : "ssh2"), a, pc);
31         ret = 1;
32       }
33       Pico32x.emu_flags |= flag;
34     }
35   }
36   else
37     pd->cnt = 0;
38   pd->addr = a;
39   pd->pc = pc;
40
41   return ret;
42 }
43
44 static int poll_undetect(struct poll_det *pd, int flag)
45 {
46   int ret = 0;
47   if (pd->cnt > POLL_THRESHOLD)
48     ret = 1;
49   pd->addr = pd->cnt = 0;
50   Pico32x.emu_flags &= ~flag;
51   return ret;
52 }
53
54 // SH2 faking
55 #define FAKE_SH2
56 int p32x_csum_faked;
57 #ifdef FAKE_SH2
58 static const u16 comm_fakevals[] = {
59   0x4d5f, 0x4f4b, // M_OK
60   0x535f, 0x4f4b, // S_OK
61   0x4D41, 0x5346, // MASF - Brutal Unleashed
62   0x5331, 0x4d31, // Darxide
63   0x5332, 0x4d32,
64   0x5333, 0x4d33,
65   0x0000, 0x0000, // eq for doom
66   0x0002, // Mortal Kombat
67 //  0, // pad
68 };
69
70 static u32 sh2_comm_faker(u32 a)
71 {
72   static int f = 0;
73   if (a == 0x28 && !p32x_csum_faked) {
74     p32x_csum_faked = 1;
75     return *(unsigned short *)(Pico.rom + 0x18e);
76   }
77   if (f >= sizeof(comm_fakevals) / sizeof(comm_fakevals[0]))
78     f = 0;
79   return comm_fakevals[f++];
80 }
81 #endif
82
83 static u32 p32x_reg_read16(u32 a)
84 {
85   a &= 0x3e;
86
87 #if 0
88   if ((a & 0x30) == 0x20)
89     return sh2_comm_faker(a);
90 #else
91   if (poll_detect(&m68k_poll, a, SekPc, P32XF_68KPOLL)) {
92     SekSetStop(1);
93     SekEndRun(16);
94   }
95 #endif
96 #ifdef FAKE_SH2
97   // fake only slave for now
98   if (a == 0x24 || a == 0x26)
99     return sh2_comm_faker(a);
100 #endif
101
102   return Pico32x.regs[a / 2];
103 }
104
105 static void p32x_reg_write8(u32 a, u32 d)
106 {
107   u16 *r = Pico32x.regs;
108   a &= 0x3f;
109
110   if (a == 1 && !(r[0] & 1)) {
111     r[0] |= 1;
112     Pico32xStartup();
113     return;
114   }
115
116   if (!(r[0] & 1))
117     return;
118
119   switch (a) {
120     case 0:
121       r[0] = (r[0] & 0x83) | ((d << 8) & P32XS_FM);
122       break;
123     case 5:
124       d &= 7;
125       if (r[4/2] != d) {
126         r[4/2] = d;
127         bank_switch(d);
128       }
129       break;
130   }
131 }
132
133 static void p32x_reg_write16(u32 a, u32 d)
134 {
135   u16 *r = Pico32x.regs;
136   a &= 0x3e;
137
138   switch (a) {
139     case 0:
140       r[0] = (r[0] & 0x83) | (d & P32XS_FM);
141       return;
142   }
143
144   if ((a & 0x30) == 0x20 && r[a / 2] != d) {
145     r[a / 2] = d;
146     if (poll_undetect(&msh2_poll, P32XF_MSH2POLL))
147       // if SH2 is busy waiting, it needs to see the result ASAP
148       SekEndRun(16);
149     return;
150   }
151
152   p32x_reg_write8(a + 1, d);
153 }
154
155 // VDP regs
156 static u32 p32x_vdp_read16(u32 a)
157 {
158   a &= 0x0e;
159
160   return Pico32x.vdp_regs[a / 2];
161 }
162
163 static void p32x_vdp_write8(u32 a, u32 d)
164 {
165   u16 *r = Pico32x.vdp_regs;
166   a &= 0x0f;
167
168   // TODO: verify what's writeable
169   switch (a) {
170     case 0x01:
171       if (((r[0] & 3) == 0) != ((d & 3) == 0)) { // forced blanking changed
172         if (Pico.video.status & 8)
173           r[0x0a/2] |=  P32XV_VBLK;
174         else
175           r[0x0a/2] &= ~P32XV_VBLK;
176       }
177       // priority inversion is handled in palette
178       if ((r[0] ^ d) & P32XV_PRI)
179         Pico32x.dirty_pal = 1;
180       r[0] = (r[0] & P32XV_nPAL) | (d & 0xff);
181       break;
182     case 0x0b:
183       d &= 1;
184       Pico32x.pending_fb = d;
185       // if we are blanking and FS bit is changing
186       if ((r[0x0a/2] & P32XV_VBLK) && ((r[0x0a/2] ^ d) & P32XV_FS)) {
187         r[0x0a/2] ^= 1;
188         Pico32xSwapDRAM(d ^ 1);
189         elprintf(EL_32X, "VDP FS: %d", r[0x0a/2] & P32XV_FS);
190       }
191       break;
192   }
193 }
194
195 static void p32x_vdp_write16(u32 a, u32 d)
196 {
197   p32x_vdp_write8(a | 1, d);
198 }
199
200 // SH2 regs
201 static u32 p32x_sh2reg_read16(u32 a)
202 {
203   a &= 0xff; // ?
204
205   if (poll_detect(&msh2_poll, a, ash2_pc(), P32XF_MSH2POLL))
206     ash2_end_run(8);
207
208   if (a == 0) {
209     return (Pico32x.regs[0] & P32XS_FM) | P32XS2_ADEN;
210   }
211   if ((a & 0x30) == 0x20)
212     return Pico32x.regs[a / 2];
213
214   return 0;
215 }
216
217 static void p32x_sh2reg_write8(u32 a, u32 d)
218 {
219 }
220
221 static void p32x_sh2reg_write16(u32 a, u32 d)
222 {
223   a &= 0xff;
224
225   if ((a & 0x30) == 0x20) {
226     Pico32x.regs[a/2] = d;
227     if (poll_undetect(&m68k_poll, P32XF_68KPOLL))
228       // dangerous, but let's just assume 68k program
229       // didn't issue STOP itself.
230       SekSetStop(0);
231     return;
232   }
233
234   p32x_sh2reg_write8(a | 1, d);
235 }
236
237 // default 32x handlers
238 u32 PicoRead8_32x(u32 a)
239 {
240   u32 d = 0;
241   if ((a & 0xffc0) == 0x5100) { // a15100
242     d = p32x_reg_read16(a);
243     goto out_16to8;
244   }
245
246   if (!(Pico32x.regs[0] & 1))
247     goto no_vdp;
248
249   if ((a & 0xfff0) == 0x5180) { // a15180
250     d = p32x_vdp_read16(a);
251     goto out_16to8;
252   }
253
254   if ((a & 0xfe00) == 0x5200) { // a15200
255     d = Pico32xMem->pal[(a & 0x1ff) / 2];
256     goto out_16to8;
257   }
258
259 no_vdp:
260   if ((a & 0xfffc) == 0x30ec) { // a130ec
261     d = str_mars[a & 3];
262     goto out;
263   }
264
265   elprintf(EL_UIO, "m68k unmapped r8  [%06x] @%06x", a, SekPc);
266   return d;
267
268 out_16to8:
269   if (a & 1)
270     d &= 0xff;
271   else
272     d >>= 8;
273
274 out:
275   elprintf(EL_32X, "m68k 32x r8  [%06x]   %02x @%06x", a, d, SekPc);
276   return d;
277 }
278
279 u32 PicoRead16_32x(u32 a)
280 {
281   u32 d = 0;
282   if ((a & 0xffc0) == 0x5100) { // a15100
283     d = p32x_reg_read16(a);
284     goto out;
285   }
286
287   if (!(Pico32x.regs[0] & 1))
288     goto no_vdp;
289
290   if ((a & 0xfff0) == 0x5180) { // a15180
291     d = p32x_vdp_read16(a);
292     goto out;
293   }
294
295   if ((a & 0xfe00) == 0x5200) { // a15200
296     d = Pico32xMem->pal[(a & 0x1ff) / 2];
297     goto out;
298   }
299
300 no_vdp:
301   if ((a & 0xfffc) == 0x30ec) { // a130ec
302     d = !(a & 2) ? ('M'<<8)|'A' : ('R'<<8)|'S';
303     goto out;
304   }
305
306   elprintf(EL_UIO, "m68k unmapped r16 [%06x] @%06x", a, SekPc);
307   return d;
308
309 out:
310   elprintf(EL_32X, "m68k 32x r16 [%06x] %04x @%06x", a, d, SekPc);
311   return d;
312 }
313
314 void PicoWrite8_32x(u32 a, u32 d)
315 {
316   if ((a & 0xfc00) == 0x5000)
317     elprintf(EL_32X, "m68k 32x w8  [%06x]   %02x @%06x", a, d & 0xff, SekPc);
318
319   if ((a & 0xffc0) == 0x5100) { // a15100
320     p32x_reg_write8(a, d);
321     return;
322   }
323
324   if (!(Pico32x.regs[0] & 1))
325     goto no_vdp;
326
327   if ((a & 0xfff0) == 0x5180) { // a15180
328     p32x_vdp_write8(a, d);
329     return;
330   }
331
332   // TODO: verify
333   if ((a & 0xfe00) == 0x5200) { // a15200
334     elprintf(EL_32X|EL_ANOMALY, "m68k 32x PAL w8  [%06x]   %02x @%06x", a, d & 0xff, SekPc);
335     ((u8 *)Pico32xMem->pal)[(a & 0x1ff) ^ 1] = d;
336     Pico32x.dirty_pal = 1;
337     return;
338   }
339
340 no_vdp:
341   elprintf(EL_UIO, "m68k unmapped w8  [%06x]   %02x @%06x", a, d & 0xff, SekPc);
342 }
343
344 void PicoWrite16_32x(u32 a, u32 d)
345 {
346   if ((a & 0xfc00) == 0x5000)
347     elprintf(EL_UIO, "m68k 32x w16 [%06x] %04x @%06x", a, d & 0xffff, SekPc);
348
349   if ((a & 0xffc0) == 0x5100) { // a15100
350     p32x_reg_write16(a, d);
351     return;
352   }
353
354   if (!(Pico32x.regs[0] & 1))
355     goto no_vdp;
356
357   if ((a & 0xfff0) == 0x5180) { // a15180
358     p32x_vdp_write16(a, d);
359     return;
360   }
361
362   if ((a & 0xfe00) == 0x5200) { // a15200
363     Pico32xMem->pal[(a & 0x1ff) / 2] = d;
364     Pico32x.dirty_pal = 1;
365     return;
366   }
367
368 no_vdp:
369   elprintf(EL_UIO, "m68k unmapped w16 [%06x] %04x @%06x", a, d & 0xffff, SekPc);
370 }
371
372 // hint vector is writeable
373 static void PicoWrite8_hint(u32 a, u32 d)
374 {
375   if ((a & 0xfffc) == 0x0070) {
376     Pico32xMem->m68k_rom[a ^ 1] = d;
377     return;
378   }
379
380   elprintf(EL_UIO, "m68k unmapped w8  [%06x]   %02x @%06x", a, d & 0xff, SekPc);
381 }
382
383 static void PicoWrite16_hint(u32 a, u32 d)
384 {
385   if ((a & 0xfffc) == 0x0070) {
386     ((u16 *)Pico32xMem->m68k_rom)[a/2] = d;
387     return;
388   }
389
390   elprintf(EL_UIO, "m68k unmapped w16 [%06x] %04x @%06x", a, d & 0xffff, SekPc);
391 }
392
393 void Pico32xSwapDRAM(int b)
394 {
395   cpu68k_map_set(m68k_read8_map,   0x840000, 0x85ffff, Pico32xMem->dram[b], 0);
396   cpu68k_map_set(m68k_read16_map,  0x840000, 0x85ffff, Pico32xMem->dram[b], 0);
397   cpu68k_map_set(m68k_write8_map,  0x840000, 0x85ffff, Pico32xMem->dram[b], 0);
398   cpu68k_map_set(m68k_write16_map, 0x840000, 0x85ffff, Pico32xMem->dram[b], 0);
399 }
400
401 static void bank_switch(int b)
402 {
403   unsigned int rs, bank;
404
405   bank = b << 20;
406   if (bank >= Pico.romsize) {
407     elprintf(EL_32X|EL_ANOMALY, "missing bank @ %06x", bank);
408     return;
409   }
410
411   // 32X ROM (unbanked, XXX: consider mirroring?)
412   rs = (Pico.romsize + M68K_BANK_MASK) & ~M68K_BANK_MASK;
413   rs -= bank;
414   if (rs > 0x100000)
415     rs = 0x100000;
416   cpu68k_map_set(m68k_read8_map,   0x900000, 0x900000 + rs - 1, Pico.rom + bank, 0);
417   cpu68k_map_set(m68k_read16_map,  0x900000, 0x900000 + rs - 1, Pico.rom + bank, 0);
418
419   elprintf(EL_32X, "bank %06x-%06x -> %06x", 0x900000, 0x900000 + rs - 1, bank);
420 }
421
422 // -----------------------------------------------------------------
423 //                              SH2  
424 // -----------------------------------------------------------------
425
426 u32 pico32x_read8(u32 a)
427 {
428   u32 d = 0;
429   if (a < sizeof(Pico32xMem->sh2_rom_m))
430     return Pico32xMem->sh2_rom_m[a ^ 1];
431
432   if ((a & 0x0ffc0000) == 0x06000000)
433     return Pico32xMem->sdram[(a & 0x3ffff) ^ 1];
434
435   if ((a & 0x0fc00000) == 0x02000000)
436     if ((a & 0x003fffff) < Pico.romsize)
437       return Pico.rom[(a & 0x3fffff) ^ 1];
438
439   if ((a & 0x0fffff00) == 0x4000) {
440     d = p32x_sh2reg_read16(a);
441     goto out_16to8;
442   }
443
444   if ((a & 0x0fffff00) == 0x4100) {
445     d = p32x_vdp_read16(a);
446     goto out_16to8;
447   }
448
449   if ((a & 0x0fffff00) == 0x4200) {
450     d = Pico32xMem->pal[(a & 0x1ff) / 2];
451     goto out_16to8;
452   }
453
454   elprintf(EL_UIO, "sh2 unmapped r8  [%08x]       %02x @%06x", a, d, ash2_pc());
455   return d;
456
457 out_16to8:
458   if (a & 1)
459     d &= 0xff;
460   else
461     d >>= 8;
462
463   elprintf(EL_32X, "sh2 r8  [%08x]       %02x @%06x", a, d, ash2_pc());
464   return d;
465 }
466
467 u32 pico32x_read16(u32 a)
468 {
469   u32 d = 0;
470
471   if (a < sizeof(Pico32xMem->sh2_rom_m))
472     return *(u16 *)(Pico32xMem->sh2_rom_m + a);
473
474   if ((a & 0x0ffc0000) == 0x06000000)
475     return ((u16 *)Pico32xMem->sdram)[(a & 0x3ffff) / 2];
476
477   if ((a & 0x0fc00000) == 0x02000000)
478     if ((a & 0x003fffff) < Pico.romsize)
479       return ((u16 *)Pico.rom)[(a & 0x3fffff) / 2];
480
481   if ((a & 0x0fffff00) == 0x4000) {
482     d = p32x_sh2reg_read16(a);
483     goto out;
484   }
485
486   if ((a & 0x0fffff00) == 0x4100) {
487     d = p32x_vdp_read16(a);
488     goto out;
489   }
490
491   if ((a & 0x0fffff00) == 0x4200) {
492     d = Pico32xMem->pal[(a & 0x1ff) / 2];
493     goto out;
494   }
495
496   elprintf(EL_UIO, "sh2 unmapped r16 [%08x]     %04x @%06x", a, d, ash2_pc());
497   return d;
498
499 out:
500   elprintf(EL_32X, "sh2 r16 [%08x]     %04x @%06x", a, d, ash2_pc());
501   return d;
502 }
503
504 u32 pico32x_read32(u32 a)
505 {
506 //  elprintf(EL_UIO, "sh2 r32 [%08x] %08x @%06x", a, d, ash2_pc());
507   return (pico32x_read16(a) << 16) | pico32x_read16(a + 2);
508 }
509
510 void pico32x_write8(u32 a, u32 d)
511 {
512   if ((a & 0x0ffffc00) == 0x4000)
513     elprintf(EL_32X, "sh2 w8  [%08x]       %02x @%06x", a, d & 0xff, ash2_pc());
514
515   if ((a & 0x0ffc0000) == 0x06000000) {
516     Pico32xMem->sdram[(a & 0x3ffff) ^ 1] = d;
517     return;
518   }
519
520   if ((a & 0x0ffe0000) == 0x04000000) {
521     u8 *dram = (u8 *)Pico32xMem->dram[(Pico32x.vdp_regs[0x0a/2] & P32XV_FS) ^ 1];
522     dram[(a & 0x1ffff) ^ 1] = d;
523     return;
524   }
525
526   if ((a & 0x0fffff00) == 0x4100) {
527     p32x_vdp_write8(a, d);
528     return;
529   }
530
531   if ((a & 0x0fffff00) == 0x4000) {
532     p32x_sh2reg_write8(a, d);
533     return;
534   }
535
536   elprintf(EL_UIO, "sh2 unmapped w8  [%08x]       %02x @%06x", a, d & 0xff, ash2_pc());
537 }
538
539 void pico32x_write16(u32 a, u32 d)
540 {
541   if ((a & 0x0ffffc00) == 0x4000)
542     elprintf(EL_32X, "sh2 w16 [%08x]     %04x @%06x", a, d & 0xffff, ash2_pc());
543
544   if ((a & 0x0ffc0000) == 0x06000000) {
545     ((u16 *)Pico32xMem->sdram)[(a & 0x3ffff) / 2] = d;
546     return;
547   }
548
549   if ((a & 0x0ffe0000) == 0x04000000) {
550     Pico32xMem->dram[(Pico32x.vdp_regs[0x0a/2] & P32XV_FS) ^ 1][(a & 0x1ffff) / 2] = d;
551     return;
552   }
553
554   if ((a & 0x0fffff00) == 0x4100) {
555     p32x_vdp_write16(a, d);
556     return;
557   }
558
559   if ((a & 0x0ffffe00) == 0x4200) {
560     Pico32xMem->pal[(a & 0x1ff) / 2] = d;
561     Pico32x.dirty_pal = 1;
562     return;
563   }
564
565   if ((a & 0x0fffff00) == 0x4000) {
566     p32x_sh2reg_write16(a, d);
567     return;
568   }
569
570   elprintf(EL_UIO, "sh2 unmapped w16 [%08x]     %04x @%06x", a, d & 0xffff, ash2_pc());
571 }
572
573 void pico32x_write32(u32 a, u32 d)
574 {
575 //  elprintf(EL_UIO, "sh2 w32 [%08x] %08x @%06x", a, d, ash2_pc());
576   pico32x_write16(a, d >> 16);
577   pico32x_write16(a + 2, d);
578 }
579
580 #define HWSWAP(x) (((x) << 16) | ((x) >> 16))
581 void PicoMemSetup32x(void)
582 {
583   unsigned short *ps;
584   unsigned int *pl;
585   unsigned int rs;
586   int i;
587
588   Pico32xMem = calloc(1, sizeof(*Pico32xMem));
589   if (Pico32xMem == NULL) {
590     elprintf(EL_STATUS, "OOM");
591     return;
592   }
593
594   // generate 68k ROM
595   ps = (unsigned short *)Pico32xMem->m68k_rom;
596   pl = (unsigned int *)Pico32xMem->m68k_rom;
597   for (i = 1; i < 0xc0/4; i++)
598     pl[i] = HWSWAP(0x880200 + (i - 1) * 6);
599
600   // fill with nops
601   for (i = 0xc0/2; i < 0x100/2; i++)
602     ps[i] = 0x4e71;
603
604 #if 0
605   ps[0xc0/2] = 0x46fc;
606   ps[0xc2/2] = 0x2700; // move #0x2700,sr
607   ps[0xfe/2] = 0x60fe; // jump to self
608 #else
609   ps[0xfe/2] = 0x4e75; // rts
610 #endif
611
612   // fill remaining mem with ROM
613   memcpy(Pico32xMem->m68k_rom + 0x100, Pico.rom + 0x100, sizeof(Pico32xMem->m68k_rom) - 0x100);
614
615   // 32X ROM
616   // TODO: move
617   {
618     FILE *f = fopen("32X_M_BIOS.BIN", "rb");
619     int i;
620     if (f == NULL) {
621       printf("missing BIOS\n");
622       exit(1);
623     }
624     fread(Pico32xMem->sh2_rom_m, 1, sizeof(Pico32xMem->sh2_rom_m), f);
625     fclose(f);
626     for (i = 0; i < sizeof(Pico32xMem->sh2_rom_m); i += 2) {
627       int t = Pico32xMem->sh2_rom_m[i];
628       Pico32xMem->sh2_rom_m[i] = Pico32xMem->sh2_rom_m[i + 1];
629       Pico32xMem->sh2_rom_m[i + 1] = t;
630     }
631   }
632
633   // cartridge area becomes unmapped
634   // XXX: we take the easy way and don't unmap ROM,
635   // so that we can avoid handling the RV bit.
636   // m68k_map_unmap(0x000000, 0x3fffff);
637
638   // MD ROM area
639   rs = sizeof(Pico32xMem->m68k_rom);
640   cpu68k_map_set(m68k_read8_map,   0x000000, rs - 1, Pico32xMem->m68k_rom, 0);
641   cpu68k_map_set(m68k_read16_map,  0x000000, rs - 1, Pico32xMem->m68k_rom, 0);
642   cpu68k_map_set(m68k_write8_map,  0x000000, rs - 1, PicoWrite8_hint, 1); // TODO verify
643   cpu68k_map_set(m68k_write16_map, 0x000000, rs - 1, PicoWrite16_hint, 1);
644
645   // DRAM area
646   Pico32xSwapDRAM(1);
647
648   // 32X ROM (unbanked, XXX: consider mirroring?)
649   rs = (Pico.romsize + M68K_BANK_MASK) & ~M68K_BANK_MASK;
650   if (rs > 0x80000)
651     rs = 0x80000;
652   cpu68k_map_set(m68k_read8_map,   0x880000, 0x880000 + rs - 1, Pico.rom, 0);
653   cpu68k_map_set(m68k_read16_map,  0x880000, 0x880000 + rs - 1, Pico.rom, 0);
654
655   // 32X ROM (banked)
656   bank_switch(0);
657 }
658