b3838905b6cf921107a55d8f067f17e2c0519ddb
[picodrive.git] / pico / cd / memory.c
1 /*\r
2  * Memory I/O handlers for Sega/Mega CD.\r
3  * (C) notaz, 2007-2009\r
4  * (C) irixxxx, 2019-2024\r
5  *\r
6  * This work is licensed under the terms of MAME license.\r
7  * See COPYING file in the top-level directory.\r
8  */\r
9 \r
10 #include "../pico_int.h"\r
11 #include "../memory.h"\r
12 #include "megasd.h"\r
13 \r
14 uptr s68k_read8_map  [0x1000000 >> M68K_MEM_SHIFT];\r
15 uptr s68k_read16_map [0x1000000 >> M68K_MEM_SHIFT];\r
16 uptr s68k_write8_map [0x1000000 >> M68K_MEM_SHIFT];\r
17 uptr s68k_write16_map[0x1000000 >> M68K_MEM_SHIFT];\r
18 \r
19 #ifndef _ASM_CD_MEMORY_C\r
20 MAKE_68K_READ8(s68k_read8, s68k_read8_map)\r
21 MAKE_68K_READ16(s68k_read16, s68k_read16_map)\r
22 MAKE_68K_READ32(s68k_read32, s68k_read16_map)\r
23 MAKE_68K_WRITE8(s68k_write8, s68k_write8_map)\r
24 MAKE_68K_WRITE16(s68k_write16, s68k_write16_map)\r
25 MAKE_68K_WRITE32(s68k_write32, s68k_write16_map)\r
26 #endif\r
27 \r
28 u32 pcd_base_address;\r
29 #define BASE pcd_base_address\r
30 \r
31 // -----------------------------------------------------------------\r
32 \r
33 // provided by ASM code:\r
34 #ifdef _ASM_CD_MEMORY_C\r
35 u32 PicoReadS68k8_pr(u32 a);\r
36 u32 PicoReadS68k16_pr(u32 a);\r
37 void PicoWriteS68k8_pr(u32 a, u32 d);\r
38 void PicoWriteS68k16_pr(u32 a, u32 d);\r
39 \r
40 u32 PicoReadM68k8_cell0(u32 a);\r
41 u32 PicoReadM68k8_cell1(u32 a);\r
42 u32 PicoReadM68k16_cell0(u32 a);\r
43 u32 PicoReadM68k16_cell1(u32 a);\r
44 void PicoWriteM68k8_cell0(u32 a, u32 d);\r
45 void PicoWriteM68k8_cell1(u32 a, u32 d);\r
46 void PicoWriteM68k16_cell0(u32 a, u32 d);\r
47 void PicoWriteM68k16_cell1(u32 a, u32 d);\r
48 \r
49 u32 PicoReadS68k8_dec0(u32 a);\r
50 u32 PicoReadS68k8_dec1(u32 a);\r
51 u32 PicoReadS68k16_dec0(u32 a);\r
52 u32 PicoReadS68k16_dec1(u32 a);\r
53 void PicoWriteS68k8_dec_m0b0(u32 a, u32 d);\r
54 void PicoWriteS68k8_dec_m1b0(u32 a, u32 d);\r
55 void PicoWriteS68k8_dec_m2b0(u32 a, u32 d);\r
56 void PicoWriteS68k8_dec_m0b1(u32 a, u32 d);\r
57 void PicoWriteS68k8_dec_m1b1(u32 a, u32 d);\r
58 void PicoWriteS68k8_dec_m2b1(u32 a, u32 d);\r
59 void PicoWriteS68k16_dec_m0b0(u32 a, u32 d);\r
60 void PicoWriteS68k16_dec_m1b0(u32 a, u32 d);\r
61 void PicoWriteS68k16_dec_m2b0(u32 a, u32 d);\r
62 void PicoWriteS68k16_dec_m0b1(u32 a, u32 d);\r
63 void PicoWriteS68k16_dec_m1b1(u32 a, u32 d);\r
64 void PicoWriteS68k16_dec_m2b1(u32 a, u32 d);\r
65 #endif\r
66 \r
67 static void remap_prg_window(u32 r1, u32 r3);\r
68 static void remap_word_ram(u32 r3);\r
69 \r
70 // poller detection\r
71 #define POLL_LIMIT 16\r
72 #define POLL_CYCLES 52\r
73 \r
74 void m68k_comm_check(u32 a)\r
75 {\r
76   u32 cycles = SekCyclesDone();\r
77   u32 clkdiff = cycles - Pico_mcd->m.m68k_poll_clk;\r
78   pcd_sync_s68k(cycles, 0);\r
79   if (a == 0x0e && !(Pico_mcd->m.state_flags & PCD_ST_S68K_SYNC) && (Pico_mcd->s68k_regs[3]&0x4)) {\r
80     // there are cases when slave updates comm and only switches RAM\r
81     // over after that (mcd1 bios), so there must be a resync..\r
82     SekEndRun(64);\r
83     Pico_mcd->m.state_flags |= PCD_ST_S68K_SYNC;\r
84   }\r
85   Pico_mcd->m.m68k_poll_clk = cycles;\r
86   if (SekNotPolling || a != Pico_mcd->m.m68k_poll_a || clkdiff > POLL_CYCLES || clkdiff <= 16) {\r
87     Pico_mcd->m.m68k_poll_a = a;\r
88     Pico_mcd->m.m68k_poll_cnt = 0;\r
89     SekNotPolling = 0;\r
90     return;\r
91   }\r
92   Pico_mcd->m.m68k_poll_cnt++;\r
93   Pico_mcd->m.state_flags &= ~PCD_ST_M68K_POLL;\r
94   if (Pico_mcd->m.m68k_poll_cnt >= POLL_LIMIT) {\r
95     Pico_mcd->m.state_flags |= PCD_ST_M68K_POLL;\r
96     SekEndRun(8);\r
97   }\r
98 }\r
99 \r
100 u32 pcd_stopwatch_read(int sub)\r
101 {\r
102   // ugh... stopwatch runs 384 cycles per step, divide by mult with inverse\r
103   u32 d = sub ? SekCyclesDoneS68k() : pcd_cycles_m68k_to_s68k(SekCyclesDone());\r
104   d = ((d - Pico_mcd->m.stopwatch_base_c) * ((1LL << 32) / 384)) >> 32;\r
105   return d & 0x0fff;\r
106 }\r
107 \r
108 #ifndef _ASM_CD_MEMORY_C\r
109 static u32 m68k_reg_read16(u32 a)\r
110 {\r
111   u32 d = 0;\r
112   a &= 0x3e;\r
113 \r
114   switch (a) {\r
115     case 0:\r
116       pcd_sync_s68k(SekCyclesDone(), 0);\r
117       d = ((Pico_mcd->s68k_regs[0x33] & PCDS_IEN2) << 13) |\r
118           (Pico_mcd->m.state_flags & PCD_ST_S68K_IFL2) | Pico_mcd->m.busreq;\r
119       goto end;\r
120     case 2:\r
121       m68k_comm_check(a);\r
122       d = (Pico_mcd->s68k_regs[a]<<8) | (Pico_mcd->s68k_regs[a+1]&0xc7);\r
123       elprintf(EL_CDREG3, "m68k_regs r3: %02x @%06x", (u8)d, SekPc);\r
124       goto end;\r
125     case 4:\r
126       pcd_sync_s68k(SekCyclesDone(), 0);\r
127       d = Pico_mcd->s68k_regs[4]<<8;\r
128       goto end;\r
129     case 6:\r
130       d = *(u16 *)(Pico_mcd->bios + 0x72);\r
131       goto end;\r
132     case 8:\r
133       d = cdc_host_r(0);\r
134       goto end;\r
135     case 0xa:\r
136       elprintf(EL_UIO, "m68k FIXME: reserved read");\r
137       goto end;\r
138     case 0xc: // 384 cycle stopwatch timer\r
139       pcd_sync_s68k(SekCyclesDone(), 0);\r
140       d = pcd_stopwatch_read(0);\r
141       elprintf(EL_CDREGS, "m68k stopwatch timer read (%04x)", d);\r
142       goto end;\r
143   }\r
144 \r
145   if (a < 0x30) {\r
146     // comm flag/cmd/status (0xE-0x2F)\r
147     m68k_comm_check(a);\r
148     d = (Pico_mcd->s68k_regs[a]<<8) | Pico_mcd->s68k_regs[a+1];\r
149     return d;\r
150   }\r
151 \r
152   elprintf(EL_UIO, "m68k_regs FIXME invalid read @ %02x", a);\r
153 \r
154 end:\r
155   return d;\r
156 }\r
157 #endif\r
158 \r
159 #ifndef _ASM_CD_MEMORY_C\r
160 static\r
161 #endif\r
162 void m68k_reg_write8(u32 a, u32 d)\r
163 {\r
164   u32 dold;\r
165   a &= 0x3f;\r
166 \r
167   Pico_mcd->m.state_flags &= ~PCD_ST_M68K_POLL;\r
168   Pico_mcd->m.m68k_poll_cnt = 0;\r
169 \r
170   switch (a) {\r
171     case 0:\r
172       d &= 1;\r
173       pcd_sync_s68k(SekCyclesDone(), 0);\r
174       if (d && (Pico_mcd->s68k_regs[0x33] & PCDS_IEN2)) {\r
175         elprintf(EL_INTS, "m68k: s68k irq 2");\r
176         Pico_mcd->m.state_flags |= PCD_ST_S68K_IFL2;\r
177         pcd_irq_s68k(2, 1);\r
178       } else {\r
179         Pico_mcd->m.state_flags &= ~PCD_ST_S68K_IFL2;\r
180         pcd_irq_s68k(2, 0);\r
181       }\r
182       return;\r
183     case 1:\r
184       d &= 3;\r
185       dold = Pico_mcd->m.busreq;\r
186 //      if (!(d & 1))\r
187 //        d |= 2; // verified: can't release bus on reset\r
188       if (dold == d)\r
189         return;\r
190 \r
191       pcd_sync_s68k(SekCyclesDone(), 0);\r
192 \r
193       if ((dold ^ d) & 1)\r
194         elprintf(EL_INTSW, "m68k: s68k reset %i", !(d&1));\r
195       if (!(d & 1))\r
196         Pico_mcd->m.state_flags |= PCD_ST_S68K_RST;\r
197       else if (d == 1 && (Pico_mcd->m.state_flags & PCD_ST_S68K_RST)) {\r
198         Pico_mcd->m.state_flags &= ~(PCD_ST_S68K_RST|PCD_ST_S68K_POLL|PCD_ST_S68K_SLEEP);\r
199         elprintf(EL_CDREGS, "m68k: resetting s68k");\r
200         SekResetS68k();\r
201         SekCycleCntS68k += 40;\r
202       }\r
203       if (((dold & 3) == 1) != ((d & 3) == 1)) {\r
204         elprintf(EL_INTSW, "m68k: s68k brq %i", d >> 1);\r
205         remap_prg_window(d, Pico_mcd->s68k_regs[3]);\r
206       }\r
207       Pico_mcd->m.busreq = d;\r
208       return;\r
209     case 2:\r
210       elprintf(EL_CDREGS, "m68k: prg wp=%02x", d);\r
211       goto write_comm;\r
212     case 3:\r
213       elprintf(EL_CDREG3, "m68k_regs w3: %02x @%06x", (u8)d, SekPc);\r
214       dold = Pico_mcd->s68k_regs[3];\r
215       if ((d ^ dold) & 0xc0) {\r
216         elprintf(EL_CDREGS, "m68k: prg bank: %i -> %i",\r
217           (Pico_mcd->s68k_regs[a]>>6), ((d>>6)&3));\r
218         remap_prg_window(Pico_mcd->m.busreq, d);\r
219       }\r
220 \r
221       // 2M mode state is tracked regardless of current mode\r
222       if (d & 2) {\r
223         Pico_mcd->m.dmna_ret_2m |= 2;\r
224         Pico_mcd->m.dmna_ret_2m &= ~1;\r
225       }\r
226       if (dold & 4) { // 1M mode\r
227         d ^= 2;       // 0 sets DMNA, 1 does nothing\r
228         d = (d & 0xc2) | (dold & 0x1f);\r
229       }\r
230       else\r
231         d = (d & 0xc0) | (dold & 0x1c) | Pico_mcd->m.dmna_ret_2m;\r
232       if ((dold ^ d) & 0x1f)\r
233         remap_word_ram(d);\r
234       goto write_comm;\r
235     case 6:\r
236       Pico_mcd->bios[MEM_BE2(0x72)] = d; // simple hint vector changer\r
237       return;\r
238     case 7:\r
239       Pico_mcd->bios[MEM_BE2(0x73)] = d;\r
240       elprintf(EL_CDREGS, "hint vector set to %04x%04x",\r
241         ((u16 *)Pico_mcd->bios)[0x70/2], ((u16 *)Pico_mcd->bios)[0x72/2]);\r
242       return;\r
243     case 8:\r
244       (void) cdc_host_r(0); // acts same as reading\r
245       return;\r
246     case 0x0f:\r
247       a = 0x0e;\r
248     case 0x0e:\r
249       goto write_comm;\r
250   }\r
251 \r
252   if ((a&0xf0) == 0x10)\r
253     goto write_comm;\r
254 \r
255   elprintf(EL_UIO, "m68k FIXME: invalid write? [%02x] %02x", a, d);\r
256   return;\r
257 \r
258 write_comm:\r
259   if (Pico_mcd->s68k_regs[a] == (u8)d)\r
260     return;\r
261 \r
262   pcd_sync_s68k(SekCyclesDone(), 0);\r
263   Pico_mcd->s68k_regs[a] = d;\r
264   if (a == 0x03) {\r
265     // There are cases when master checks for successful switching of RAM to\r
266     // slave. This can produce race conditions where slave switches RAM back to\r
267     // master while master is delayed by interrupt before the check executes.\r
268     // Delay slave a bit to make sure master can check before slave changes.\r
269     SekCycleCntS68k += 24; // Silpheed\r
270   }\r
271   if (!((Pico_mcd->m.s68k_poll_a ^ a) & ~1)) {\r
272     if (Pico_mcd->m.state_flags & PCD_ST_S68K_POLL)\r
273       elprintf(EL_CDPOLL, "s68k poll release, a=%02x", a);\r
274     Pico_mcd->m.state_flags &= ~PCD_ST_S68K_POLL;\r
275     Pico_mcd->m.s68k_poll_cnt = 0;\r
276   }\r
277 }\r
278 \r
279 u32 s68k_poll_detect(u32 a, u32 d)\r
280 {\r
281 #ifdef USE_POLL_DETECT\r
282   u32 cycles, cnt = 0;\r
283   if (Pico_mcd->m.state_flags & (PCD_ST_S68K_POLL|PCD_ST_S68K_SLEEP))\r
284     return d;\r
285 \r
286   cycles = SekCyclesDoneS68k();\r
287   if (!SekNotPollingS68k && a == Pico_mcd->m.s68k_poll_a) {\r
288     u32 clkdiff = cycles - Pico_mcd->m.s68k_poll_clk;\r
289     if (clkdiff <= POLL_CYCLES) {\r
290       cnt = Pico_mcd->m.s68k_poll_cnt + 1;\r
291       //printf("-- diff: %u, cnt = %i\n", clkdiff, cnt);\r
292       Pico_mcd->m.state_flags &= ~PCD_ST_S68K_POLL;\r
293       if (cnt > POLL_LIMIT) {\r
294         Pico_mcd->m.state_flags |= PCD_ST_S68K_POLL;\r
295         SekEndRunS68k(8);\r
296         elprintf(EL_CDPOLL, "s68k poll detected @%06x, a=%02x",\r
297           SekPcS68k, a);\r
298       } else if (cnt > 2)\r
299         SekEndRunS68k(240);\r
300     }\r
301   }\r
302   Pico_mcd->m.s68k_poll_a = a;\r
303   Pico_mcd->m.s68k_poll_clk = cycles;\r
304   Pico_mcd->m.s68k_poll_cnt = cnt;\r
305   SekNotPollingS68k = 0;\r
306 #endif\r
307   return d;\r
308 }\r
309 \r
310 #define READ_FONT_DATA(basemask) \\r
311 { \\r
312       unsigned int fnt = CPU_LE4(*(u32 *)(Pico_mcd->s68k_regs + 0x4c)); \\r
313       unsigned int col0 = (fnt >> 8) & 0x0f, col1 = (fnt >> 12) & 0x0f;   \\r
314       if (fnt & (basemask << 0)) d  = col1      ; else d  = col0;       \\r
315       if (fnt & (basemask << 1)) d |= col1 <<  4; else d |= col0 <<  4; \\r
316       if (fnt & (basemask << 2)) d |= col1 <<  8; else d |= col0 <<  8; \\r
317       if (fnt & (basemask << 3)) d |= col1 << 12; else d |= col0 << 12; \\r
318 }\r
319 \r
320 \r
321 #ifndef _ASM_CD_MEMORY_C\r
322 static\r
323 #endif\r
324 u32 s68k_reg_read16(u32 a)\r
325 {\r
326   u32 d=0;\r
327 \r
328   switch (a) {\r
329     case 0:\r
330       d = ((Pico_mcd->s68k_regs[0]&3)<<8) | 1; // ver = 0, not in reset state\r
331       goto end;\r
332     case 2:\r
333       d = (Pico_mcd->s68k_regs[2]<<8) | (Pico_mcd->s68k_regs[3]&0x1f);\r
334       elprintf(EL_CDREG3, "s68k_regs r3: %02x @%06x", (u8)d, SekPcS68k);\r
335       s68k_poll_detect(a, d);\r
336       goto end;\r
337     case 4:\r
338       d = (Pico_mcd->s68k_regs[4]<<8) | (Pico_mcd->s68k_regs[5]&0x1f);\r
339       goto end;\r
340     case 6:\r
341       d = cdc_reg_r();\r
342       goto end;\r
343     case 8:\r
344       d = cdc_host_r(1);\r
345       goto end;\r
346     case 0xc:\r
347       d = pcd_stopwatch_read(1);\r
348       elprintf(EL_CDREGS, "s68k stopwatch timer read (%04x)", d);\r
349       goto end;\r
350     case 0x30:\r
351       elprintf(EL_CDREGS, "s68k int3 timer read (%02x)", Pico_mcd->s68k_regs[0x31]);\r
352       d = Pico_mcd->s68k_regs[0x31];\r
353       goto end;\r
354     case 0x34: // fader\r
355       d = 0; // no busy bit\r
356       goto end;\r
357     case 0x50: // font data (check: Lunar 2, Silpheed)\r
358       READ_FONT_DATA(0x00100000);\r
359       goto end;\r
360     case 0x52:\r
361       READ_FONT_DATA(0x00010000);\r
362       goto end;\r
363     case 0x54:\r
364       READ_FONT_DATA(0x10000000);\r
365       goto end;\r
366     case 0x56:\r
367       READ_FONT_DATA(0x01000000);\r
368       goto end;\r
369   }\r
370 \r
371   d = (Pico_mcd->s68k_regs[a]<<8) | Pico_mcd->s68k_regs[a+1];\r
372 \r
373   if ((a >= 0x0e && a < 0x30) || a == 0x58)\r
374     d = s68k_poll_detect(a, d);\r
375 \r
376 end:\r
377   return d;\r
378 }\r
379 \r
380 #ifndef _ASM_CD_MEMORY_C\r
381 static\r
382 #endif\r
383 void s68k_reg_write8(u32 a, u32 d)\r
384 {\r
385   // Warning: d might have upper bits set\r
386   switch (a) {\r
387     case 1:\r
388       if (!(d & 1))\r
389         pcd_soft_reset();\r
390       return;\r
391     case 2: a++; // byte access only, ignores LDS/UDS\r
392     case 3: {\r
393       int dold = Pico_mcd->s68k_regs[3];\r
394       elprintf(EL_CDREG3, "s68k_regs w3: %02x @%06x", (u8)d, SekPcS68k);\r
395       d &= 0x1d;\r
396       d |= dold & 0xc2;\r
397 \r
398       // 2M mode state\r
399       if (d & 1) {\r
400         Pico_mcd->m.dmna_ret_2m |= 1;\r
401         Pico_mcd->m.dmna_ret_2m &= ~2; // DMNA clears\r
402       }\r
403 \r
404       if (d & 4)\r
405       {\r
406         if (!(dold & 4)) {\r
407           elprintf(EL_CDREG3, "wram mode 2M->1M");\r
408           wram_2M_to_1M(Pico_mcd->word_ram2M);\r
409         }\r
410 \r
411         if ((d ^ dold) & 0x05)\r
412           d &= ~2; // clear DMNA - swap complete\r
413       }\r
414       else\r
415       {\r
416         if (dold & 4) {\r
417           elprintf(EL_CDREG3, "wram mode 1M->2M");\r
418           wram_1M_to_2M(Pico_mcd->word_ram2M);\r
419         }\r
420         d = (d & ~3) | Pico_mcd->m.dmna_ret_2m;\r
421       }\r
422       if ((dold ^ d) & 0x1f)\r
423         remap_word_ram(d);\r
424       goto write_comm;\r
425     }\r
426     case 4:\r
427       elprintf(EL_CDREGS, "s68k CDC dest: %x", d&7);\r
428       Pico_mcd->s68k_regs[a] = (d&7); // CDC mode\r
429       Pico_mcd->s68k_regs[0xa] = Pico_mcd->s68k_regs[0xb] = 0; // resets DMA\r
430       return;\r
431     case 5:\r
432       //dprintf("s68k CDC reg addr: %x", d&0x1f);\r
433       Pico_mcd->s68k_regs[a] = (d&0x1f);\r
434       return;\r
435     case 7:\r
436       cdc_reg_w(d & 0xff);\r
437       return;\r
438     case 0xa:\r
439     case 0xb:\r
440       // word access only. 68k sets both bus halves to value d.\r
441       elprintf(EL_CDREGS, "s68k set CDC dma addr");\r
442       Pico_mcd->s68k_regs[0xa] = Pico_mcd->s68k_regs[0xb] = d;\r
443       return;\r
444     case 0xc:\r
445     case 0xd: // 384 cycle stopwatch timer\r
446       elprintf(EL_CDREGS|EL_CD, "s68k clear stopwatch (%x)", d);\r
447       // does this also reset internal 384 cycle counter?\r
448       Pico_mcd->m.stopwatch_base_c = SekCyclesDoneS68k();\r
449       return;\r
450     case 0x0e: a++;\r
451     case 0x0f:\r
452       goto write_comm;\r
453     case 0x30: a++;\r
454     case 0x31: // 384 cycle int3 timer\r
455       d &= 0xff;\r
456       elprintf(EL_CDREGS|EL_CD, "s68k set int3 timer: %02x", d);\r
457       Pico_mcd->s68k_regs[a] = (u8) d;\r
458       if (d) // XXX: d or d+1? mcd-verificator results suggest d+1\r
459         pcd_event_schedule_s68k(PCD_EVENT_TIMER3, (d+1) * 384);\r
460       else\r
461         pcd_event_schedule(0, PCD_EVENT_TIMER3, 0);\r
462       break;\r
463     case 0x33: // IRQ mask\r
464       elprintf(EL_CDREGS|EL_CD, "s68k irq mask: %02x", d);\r
465       d &= 0x7e;\r
466       if ((d ^ Pico_mcd->s68k_regs[0x33]) & PCDS_IEN4) {\r
467         // XXX: emulate pending irq instead?\r
468         if ((d & PCDS_IEN4) && (Pico_mcd->s68k_regs[0x37] & 4)) {\r
469           elprintf(EL_INTS, "cdd export irq 4 (unmask)");\r
470           pcd_irq_s68k(4, 1);\r
471         }\r
472       }\r
473       if ((d ^ Pico_mcd->s68k_regs[0x33]) & ~d & PCDS_IEN2)\r
474         pcd_irq_s68k(2, 0);\r
475       break;\r
476     case 0x34: // fader\r
477       Pico_mcd->s68k_regs[a] = (u8) d & 0x7f;\r
478       return;\r
479     case 0x36:\r
480       return; // d/m bit is unsetable\r
481     case 0x37: {\r
482       u32 d_old = Pico_mcd->s68k_regs[0x37];\r
483       Pico_mcd->s68k_regs[0x37] = d & 7;\r
484       if ((d ^ d_old) & 4) {\r
485         if ((d & 4) && (Pico_mcd->s68k_regs[0x33] & PCDS_IEN4)) {\r
486           elprintf(EL_INTS, "cdd export irq 4");\r
487           pcd_irq_s68k(4, 1);\r
488         }\r
489       }\r
490       return;\r
491     }\r
492     case 0x4b:\r
493       Pico_mcd->s68k_regs[a] = 0; // (u8) d; ?\r
494       cdd_process();\r
495       {\r
496         static const char *nm[] =\r
497           { "stat", "stop", "read_toc", "play",\r
498             "seek", "???",  "pause",    "resume",\r
499             "ff",   "fr",   "tjump",    "???",\r
500             "close","open", "???",      "???" };\r
501         u8 *c = &Pico_mcd->s68k_regs[0x42];\r
502         u8 *s = &Pico_mcd->s68k_regs[0x38];\r
503         elprintf(EL_CD,\r
504           "CDD command: %02x %02x %02x %02x %02x %02x %02x %02x %12s",\r
505           c[0], c[1], c[2], c[3], c[4], c[5], c[6], c[7], nm[c[0] & 0x0f]);\r
506         elprintf(EL_CD,\r
507           "CDD status:  %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x",\r
508           s[0], s[1], s[2], s[3], s[4], s[5], s[6], s[7], s[8], s[9]);\r
509       }\r
510       return;\r
511     case 0x4c: a++;\r
512       break;\r
513     case 0x58:\r
514       return;\r
515   }\r
516 \r
517   if ((a&0x1f0) == 0x20)\r
518     goto write_comm;\r
519 \r
520   if ((a&0x1f0) == 0x10 || (a >= 0x38 && a < 0x42))\r
521   {\r
522     elprintf(EL_UIO, "s68k FIXME: invalid write @ %02x?", a);\r
523     return;\r
524   }\r
525 \r
526   Pico_mcd->s68k_regs[a] = (u8) d;\r
527   return;\r
528 \r
529 write_comm:\r
530   if (Pico_mcd->s68k_regs[a] == (u8)d)\r
531     return;\r
532 \r
533   Pico_mcd->s68k_regs[a] = (u8) d;\r
534   if (!((Pico_mcd->m.m68k_poll_a ^ a) & ~1)) {\r
535     SekEndRunS68k(8);\r
536     Pico_mcd->m.state_flags &= ~PCD_ST_M68K_POLL;\r
537     Pico_mcd->m.m68k_poll_cnt = 0;\r
538   }\r
539 }\r
540 \r
541 void s68k_reg_write16(u32 a, u32 d)\r
542 {\r
543   u8 *r = Pico_mcd->s68k_regs;\r
544 \r
545   Pico_mcd->m.state_flags &= ~PCD_ST_S68K_POLL;\r
546   Pico_mcd->m.s68k_poll_cnt = 0;\r
547 \r
548   if ((a & 0x1f0) == 0x20)\r
549     goto write_comm;\r
550 \r
551   switch (a) {\r
552     case 0x02:\r
553     case 0x0e:\r
554     case 0x30:\r
555     case 0x4c:\r
556       // these are only byte registers, LDS/UDS ignored\r
557       return s68k_reg_write8(a + 1, d);\r
558     case 0x08:\r
559       return (void) cdc_host_r(1); // acts same as reading\r
560     case 0x0a: // DMA address\r
561       r[0xa] = d >> 8;\r
562       r[0xb] = d;\r
563       return;\r
564     case 0x58: // stamp data size\r
565       r[0x59] = d & 7;\r
566       return;\r
567     case 0x5a: // stamp map base address\r
568       r[0x5a] = d >> 8;\r
569       r[0x5b] = d & 0xe0;\r
570       return;\r
571     case 0x5c: // V cell size\r
572       r[0x5d] = d & 0x1f;\r
573       return;\r
574     case 0x5e: // image buffer start address\r
575       r[0x5e] = d >> 8;\r
576       r[0x5f] = d & 0xf8;\r
577       return;\r
578     case 0x60: // image buffer offset\r
579       r[0x61] = d & 0x3f;\r
580       return;\r
581     case 0x62: // h dot size\r
582       r[0x62] = (d >> 8) & 1;\r
583       r[0x63] = d;\r
584       return;\r
585     case 0x64: // v dot size\r
586       r[0x65] = d;\r
587       return;\r
588     case 0x66: // trace vector base address\r
589       d &= 0xfffe;\r
590       r[0x66] = d >> 8;\r
591       r[0x67] = d;\r
592       gfx_start(d);\r
593       return;\r
594     default:\r
595       break;\r
596   }\r
597 \r
598   s68k_reg_write8(a,     d >> 8);\r
599   s68k_reg_write8(a + 1, d & 0xff);\r
600   return;\r
601 \r
602 write_comm:\r
603   if (r[a] == (u8)(d >> 8) && r[a + 1] == (u8)d)\r
604     return;\r
605 \r
606   r[a] = d >> 8;\r
607   r[a + 1] = d;\r
608   if (!((Pico_mcd->m.m68k_poll_a ^ a) & ~1)) {\r
609     SekEndRunS68k(8);\r
610     Pico_mcd->m.state_flags &= ~PCD_ST_M68K_POLL;\r
611     Pico_mcd->m.m68k_poll_cnt = 0;\r
612   }\r
613 }\r
614 \r
615 // -----------------------------------------------------------------\r
616 //                          Main 68k\r
617 // -----------------------------------------------------------------\r
618 \r
619 #ifndef _ASM_CD_MEMORY_C\r
620 #include "cell_map.c"\r
621 \r
622 // WORD RAM, cell aranged area (220000 - 23ffff)\r
623 static u32 PicoReadM68k8_cell0(u32 a)\r
624 {\r
625   a = (a&3) | (cell_map(a >> 2) << 2); // cell arranged\r
626   return Pico_mcd->word_ram1M[0][MEM_BE2(a)];\r
627 }\r
628 \r
629 static u32 PicoReadM68k8_cell1(u32 a)\r
630 {\r
631   a = (a&3) | (cell_map(a >> 2) << 2);\r
632   return Pico_mcd->word_ram1M[1][MEM_BE2(a)];\r
633 }\r
634 \r
635 static u32 PicoReadM68k16_cell0(u32 a)\r
636 {\r
637   a = (a&2) | (cell_map(a >> 2) << 2);\r
638   return *(u16 *)(Pico_mcd->word_ram1M[0] + a);\r
639 }\r
640 \r
641 static u32 PicoReadM68k16_cell1(u32 a)\r
642 {\r
643   a = (a&2) | (cell_map(a >> 2) << 2);\r
644   return *(u16 *)(Pico_mcd->word_ram1M[1] + a);\r
645 }\r
646 \r
647 static void PicoWriteM68k8_cell0(u32 a, u32 d)\r
648 {\r
649   a = (a&3) | (cell_map(a >> 2) << 2);\r
650   Pico_mcd->word_ram1M[0][MEM_BE2(a)] = d;\r
651 }\r
652 \r
653 static void PicoWriteM68k8_cell1(u32 a, u32 d)\r
654 {\r
655   a = (a&3) | (cell_map(a >> 2) << 2);\r
656   Pico_mcd->word_ram1M[1][MEM_BE2(a)] = d;\r
657 }\r
658 \r
659 static void PicoWriteM68k16_cell0(u32 a, u32 d)\r
660 {\r
661   a = (a&3) | (cell_map(a >> 2) << 2);\r
662   *(u16 *)(Pico_mcd->word_ram1M[0] + a) = d;\r
663 }\r
664 \r
665 static void PicoWriteM68k16_cell1(u32 a, u32 d)\r
666 {\r
667   a = (a&3) | (cell_map(a >> 2) << 2);\r
668   *(u16 *)(Pico_mcd->word_ram1M[1] + a) = d;\r
669 }\r
670 #endif\r
671 \r
672 // RAM cart (400000 - 7fffff, optional)\r
673 static u32 PicoReadM68k8_ramc(u32 a)\r
674 {\r
675   u32 d = 0;\r
676 \r
677   if (Pico.romsize == 0 && (PicoIn.opt & POPT_EN_MCD_RAMCART)) {\r
678     if ((a & 0xf00001) == 0x400001) {\r
679       if (Pico.sv.data != NULL)\r
680         d = 3; // 64k cart\r
681       return d;\r
682     }\r
683 \r
684     if ((a & 0xf00001) == 0x600001) {\r
685       if (Pico.sv.data != NULL)\r
686         d = Pico.sv.data[((a >> 1) & 0xffff) + 0x2000];\r
687       return d;\r
688     }\r
689 \r
690     if ((a & 0xf00001) == 0x700001)\r
691       return Pico_mcd->m.bcram_reg;\r
692   }\r
693 \r
694   elprintf(EL_UIO, "m68k unmapped r8  [%06x] @%06x", a, SekPc);\r
695   return d;\r
696 }\r
697 \r
698 static u32 PicoReadM68k16_ramc(u32 a)\r
699 {\r
700   elprintf(EL_ANOMALY, "ramcart r16: [%06x] @%06x", a, SekPc);\r
701   return PicoReadM68k8_ramc(a + 1);\r
702 }\r
703 \r
704 static void PicoWriteM68k8_ramc(u32 a, u32 d)\r
705 {\r
706   if (Pico.romsize == 0 && (PicoIn.opt & POPT_EN_MCD_RAMCART)) {\r
707     if ((a & 0xf00001) == 0x600001) {\r
708       if (Pico.sv.data != NULL && (Pico_mcd->m.bcram_reg & 1)) {\r
709         Pico.sv.data[((a >> 1) & 0xffff) + 0x2000] = d;\r
710         Pico.sv.changed = 1;\r
711       }\r
712       return;\r
713     }\r
714 \r
715     if ((a & 0xf00001) == 0x700001) {\r
716       Pico_mcd->m.bcram_reg = d;\r
717       return;\r
718     }\r
719   }\r
720 \r
721   elprintf(EL_UIO, "m68k unmapped w8  [%06x]   %02x @%06x",\r
722     a, d & 0xff, SekPc);\r
723 }\r
724 \r
725 static void PicoWriteM68k16_ramc(u32 a, u32 d)\r
726 {\r
727   elprintf(EL_ANOMALY, "ramcart w16: [%06x] %04x @%06x",\r
728     a, d, SekPcS68k);\r
729   PicoWriteM68k8_ramc(a + 1, d);\r
730 }\r
731 \r
732 // IO/control/cd registers (a10000 - ...)\r
733 #ifndef _ASM_CD_MEMORY_C\r
734 u32 PicoRead8_mcd_io(u32 a)\r
735 {\r
736   u32 d;\r
737   if ((a & 0xff00) == 0x2000) { // a12000 - a120ff\r
738     d = m68k_reg_read16(a); // TODO: m68k_reg_read8\r
739     if (!(a & 1))\r
740       d >>= 8;\r
741     d &= 0xff;\r
742     elprintf(EL_CDREGS, "m68k_regs r8:  [%02x]   %02x @%06x",\r
743       a & 0x3f, d, SekPc);\r
744     return d;\r
745   }\r
746 \r
747   // fallback to default MD handler\r
748   return PicoRead8_io(a);\r
749 }\r
750 \r
751 u32 PicoRead16_mcd_io(u32 a)\r
752 {\r
753   u32 d;\r
754   if ((a & 0xff00) == 0x2000) {\r
755     d = m68k_reg_read16(a);\r
756     elprintf(EL_CDREGS, "m68k_regs r16: [%02x] %04x @%06x",\r
757       a & 0x3f, d, SekPc);\r
758     return d;\r
759   }\r
760 \r
761   return PicoRead16_io(a);\r
762 }\r
763 \r
764 void PicoWrite8_mcd_io(u32 a, u32 d)\r
765 {\r
766   if ((a & 0xff00) == 0x2000) { // a12000 - a120ff\r
767     elprintf(EL_CDREGS, "m68k_regs w8:  [%02x]   %02x @%06x",\r
768       a & 0x3f, d, SekPc);\r
769     m68k_reg_write8(a, d);\r
770     return;\r
771   }\r
772 \r
773   if (carthw_ssf2_active)\r
774     carthw_ssf2_write8(a, d); // for MSU/MD+\r
775   else\r
776     PicoWrite8_io(a, d);\r
777 }\r
778 \r
779 void PicoWrite16_mcd_io(u32 a, u32 d)\r
780 {\r
781   if ((a & 0xff00) == 0x2000) { // a12000 - a120ff\r
782     elprintf(EL_CDREGS, "m68k_regs w16: [%02x] %04x @%06x",\r
783       a & 0x3f, d, SekPc);\r
784 \r
785     m68k_reg_write8(a, d >> 8);\r
786     if ((a & 0x3e) != 0x0e) // special case\r
787       m68k_reg_write8(a + 1, d & 0xff);\r
788     return;\r
789   }\r
790 \r
791   if (carthw_ssf2_active)\r
792     carthw_ssf2_write16(a, d); // for MSU/MD+\r
793   else\r
794     PicoWrite16_io(a, d);\r
795 }\r
796 #endif\r
797 \r
798 // -----------------------------------------------------------------\r
799 //                           Sub 68k\r
800 // -----------------------------------------------------------------\r
801 \r
802 static u32 s68k_unmapped_read8(u32 a)\r
803 {\r
804   elprintf(EL_UIO, "s68k unmapped r8  [%06x] @%06x", a, SekPc);\r
805   return 0;\r
806 }\r
807 \r
808 static u32 s68k_unmapped_read16(u32 a)\r
809 {\r
810   elprintf(EL_UIO, "s68k unmapped r16 [%06x] @%06x", a, SekPc);\r
811   return 0;\r
812 }\r
813 \r
814 static void s68k_unmapped_write8(u32 a, u32 d)\r
815 {\r
816   elprintf(EL_UIO, "s68k unmapped w8  [%06x]   %02x @%06x",\r
817     a, d & 0xff, SekPc);\r
818 }\r
819 \r
820 static void s68k_unmapped_write16(u32 a, u32 d)\r
821 {\r
822   elprintf(EL_UIO, "s68k unmapped w16 [%06x] %04x @%06x",\r
823     a, d & 0xffff, SekPc);\r
824 }\r
825 \r
826 // PRG RAM protected range (000000 - 01fdff)?\r
827 // XXX verify: ff00 or 1fe00 max?\r
828 static void PicoWriteS68k8_prgwp(u32 a, u32 d)\r
829 {\r
830   if (a >= (Pico_mcd->s68k_regs[2] << 9))\r
831     Pico_mcd->prg_ram[MEM_BE2(a)] = d;\r
832 }\r
833 \r
834 static void PicoWriteS68k16_prgwp(u32 a, u32 d)\r
835 {\r
836   if (a >= (Pico_mcd->s68k_regs[2] << 9))\r
837     *(u16 *)(Pico_mcd->prg_ram + a) = d;\r
838 }\r
839 \r
840 #ifndef _ASM_CD_MEMORY_C\r
841 \r
842 // decode (080000 - 0bffff, in 1M mode)\r
843 static u32 PicoReadS68k8_dec0(u32 a)\r
844 {\r
845   u32 d = Pico_mcd->word_ram1M[0][MEM_BE2(a >> 1) & 0x1ffff];\r
846   if (a & 1)\r
847     d &= 0x0f;\r
848   else\r
849     d >>= 4;\r
850   return d;\r
851 }\r
852 \r
853 static u32 PicoReadS68k8_dec1(u32 a)\r
854 {\r
855   u32 d = Pico_mcd->word_ram1M[1][MEM_BE2(a >> 1) & 0x1ffff];\r
856   if (a & 1)\r
857     d &= 0x0f;\r
858   else\r
859     d >>= 4;\r
860   return d;\r
861 }\r
862 \r
863 static u32 PicoReadS68k16_dec0(u32 a)\r
864 {\r
865   u32 d = Pico_mcd->word_ram1M[0][MEM_BE2(a >> 1) & 0x1ffff];\r
866   d |= d << 4;\r
867   d &= ~0xf0;\r
868   return d;\r
869 }\r
870 \r
871 static u32 PicoReadS68k16_dec1(u32 a)\r
872 {\r
873   u32 d = Pico_mcd->word_ram1M[1][MEM_BE2(a >> 1) & 0x1ffff];\r
874   d |= d << 4;\r
875   d &= ~0xf0;\r
876   return d;\r
877 }\r
878 \r
879 /* check: jaguar xj 220 (draws entire world using decode) */\r
880 #define mk_decode_w8(bank)                                        \\r
881 static void PicoWriteS68k8_dec_m0b##bank(u32 a, u32 d)            \\r
882 {                                                                 \\r
883   u8 *pd = &Pico_mcd->word_ram1M[bank][MEM_BE2(a >> 1) & 0x1ffff];\\r
884                                                                   \\r
885   if (!(a & 1))                                                   \\r
886     *pd = (*pd & 0x0f) | (d << 4);                                \\r
887   else                                                            \\r
888     *pd = (*pd & 0xf0) | (d & 0x0f);                              \\r
889 }                                                                 \\r
890                                                                   \\r
891 static void PicoWriteS68k8_dec_m1b##bank(u32 a, u32 d)            \\r
892 {                                                                 \\r
893   u8 *pd = &Pico_mcd->word_ram1M[bank][MEM_BE2(a >> 1) & 0x1ffff];\\r
894   u8 mask = (a & 1) ? 0x0f : 0xf0;                                \\r
895                                                                   \\r
896   if (!(*pd & mask) && (d & 0x0f)) /* underwrite */               \\r
897     PicoWriteS68k8_dec_m0b##bank(a, d);                           \\r
898 }                                                                 \\r
899                                                                   \\r
900 static void PicoWriteS68k8_dec_m2b##bank(u32 a, u32 d) /* ...and m3? */ \\r
901 {                                                                 \\r
902   if (d & 0x0f) /* overwrite */                                   \\r
903     PicoWriteS68k8_dec_m0b##bank(a, d);                           \\r
904 }\r
905 \r
906 mk_decode_w8(0)\r
907 mk_decode_w8(1)\r
908 \r
909 #define mk_decode_w16(bank)                                       \\r
910 static void PicoWriteS68k16_dec_m0b##bank(u32 a, u32 d)           \\r
911 {                                                                 \\r
912   u8 *pd = &Pico_mcd->word_ram1M[bank][MEM_BE2(a >> 1) & 0x1ffff];\\r
913                                                                   \\r
914   d &= 0x0f0f;                                                    \\r
915   *pd = d | (d >> 4);                                             \\r
916 }                                                                 \\r
917                                                                   \\r
918 static void PicoWriteS68k16_dec_m1b##bank(u32 a, u32 d)           \\r
919 {                                                                 \\r
920   u8 *pd = &Pico_mcd->word_ram1M[bank][MEM_BE2(a >> 1) & 0x1ffff];\\r
921                                                                   \\r
922   d &= 0x0f0f; /* underwrite */                                   \\r
923   if (!(*pd & 0xf0)) *pd |= d >> 4;                               \\r
924   if (!(*pd & 0x0f)) *pd |= d;                                    \\r
925 }                                                                 \\r
926                                                                   \\r
927 static void PicoWriteS68k16_dec_m2b##bank(u32 a, u32 d)           \\r
928 {                                                                 \\r
929   u8 *pd = &Pico_mcd->word_ram1M[bank][MEM_BE2(a >> 1) & 0x1ffff];\\r
930                                                                   \\r
931   d &= 0x0f0f; /* overwrite */                                    \\r
932   d |= d >> 4;                                                    \\r
933                                                                   \\r
934   if (!(d & 0xf0)) d |= *pd & 0xf0;                               \\r
935   if (!(d & 0x0f)) d |= *pd & 0x0f;                               \\r
936   *pd = d;                                                        \\r
937 }\r
938 \r
939 mk_decode_w16(0)\r
940 mk_decode_w16(1)\r
941 \r
942 #endif\r
943 \r
944 // backup RAM (fe0000 - feffff)\r
945 static u32 PicoReadS68k8_bram(u32 a)\r
946 {\r
947   return Pico_mcd->bram[(a>>1)&0x1fff];\r
948 }\r
949 \r
950 static u32 PicoReadS68k16_bram(u32 a)\r
951 {\r
952   u32 d;\r
953   elprintf(EL_ANOMALY, "FIXME: s68k_bram r16: [%06x] @%06x", a, SekPcS68k);\r
954   a = (a >> 1) & 0x1fff;\r
955   d = Pico_mcd->bram[a];\r
956   return d;\r
957 }\r
958 \r
959 static void PicoWriteS68k8_bram(u32 a, u32 d)\r
960 {\r
961   if (a & 1) {\r
962     Pico_mcd->bram[(a >> 1) & 0x1fff] = d;\r
963     Pico.sv.changed = 1;\r
964   }\r
965 }\r
966 \r
967 static void PicoWriteS68k16_bram(u32 a, u32 d)\r
968 {\r
969   elprintf(EL_ANOMALY, "s68k_bram w16: [%06x] %04x @%06x", a, d, SekPcS68k);\r
970   a = (a >> 1) & 0x1fff;\r
971   Pico_mcd->bram[a++] = d;\r
972   Pico.sv.changed = 1;\r
973 }\r
974 \r
975 #ifndef _ASM_CD_MEMORY_C\r
976 \r
977 // PCM and registers (ff0000 - ffffff)\r
978 static u32 PicoReadS68k8_pr(u32 a)\r
979 {\r
980   u32 d = 0;\r
981 \r
982   // regs\r
983   if ((a & 0xfe00) == 0x8000) {\r
984     a &= 0x1ff;\r
985     if (a >= 0x0e && a < 0x30) {\r
986       d = Pico_mcd->s68k_regs[a];\r
987       d = s68k_poll_detect(a & ~1, d);\r
988       goto regs_done;\r
989     }\r
990     d = s68k_reg_read16(a & ~1);\r
991     if (!(a & 1))\r
992       d >>= 8;\r
993 \r
994 regs_done:\r
995     d &= 0xff;\r
996     elprintf(EL_CDREGS, "s68k_regs r8: [%02x] %02x @%06x",\r
997       a, d, SekPcS68k);\r
998     return d;\r
999   }\r
1000 \r
1001   // PCM\r
1002   // XXX: verify: probably odd addrs only?\r
1003   if ((a & 0x8000) == 0x0000) {\r
1004     a &= 0x7fff;\r
1005     if (a >= 0x2000)\r
1006       d = Pico_mcd->pcm_ram_b[Pico_mcd->pcm.bank][(a >> 1) & 0xfff];\r
1007     else if (a >= 0x20)\r
1008       d = pcd_pcm_read(a >> 1);\r
1009 \r
1010     return d;\r
1011   }\r
1012 \r
1013   return s68k_unmapped_read8(a);\r
1014 }\r
1015 \r
1016 static u32 PicoReadS68k16_pr(u32 a)\r
1017 {\r
1018   u32 d = 0;\r
1019 \r
1020   // regs\r
1021   if ((a & 0xfe00) == 0x8000) {\r
1022     a &= 0x1fe;\r
1023     d = s68k_reg_read16(a);\r
1024 \r
1025     elprintf(EL_CDREGS, "s68k_regs r16: [%02x] %04x @%06x",\r
1026       a, d, SekPcS68k);\r
1027     return d;\r
1028   }\r
1029 \r
1030   // PCM\r
1031   if ((a & 0x8000) == 0x0000) {\r
1032     a &= 0x7fff;\r
1033     if (a >= 0x2000)\r
1034       d = Pico_mcd->pcm_ram_b[Pico_mcd->pcm.bank][(a >> 1) & 0xfff];\r
1035     else if (a >= 0x20)\r
1036       d = pcd_pcm_read(a >> 1);\r
1037 \r
1038     return d;\r
1039   }\r
1040 \r
1041   return s68k_unmapped_read16(a);\r
1042 }\r
1043 \r
1044 static void PicoWriteS68k8_pr(u32 a, u32 d)\r
1045 {\r
1046   // regs\r
1047   if ((a & 0xfe00) == 0x8000) {\r
1048     a &= 0x1ff;\r
1049     elprintf(EL_CDREGS, "s68k_regs w8: [%02x] %02x @%06x", a, d, SekPcS68k);\r
1050     if (0x59 <= a && a < 0x68) // word regs\r
1051       s68k_reg_write16(a & ~1, (d << 8) | d);\r
1052     else\r
1053       s68k_reg_write8(a, d);\r
1054     return;\r
1055   }\r
1056 \r
1057   // PCM\r
1058   if ((a & 0x8000) == 0x0000) {\r
1059     a &= 0x7fff;\r
1060     if (a >= 0x2000)\r
1061       Pico_mcd->pcm_ram_b[Pico_mcd->pcm.bank][(a>>1)&0xfff] = d;\r
1062     else if (a < 0x12)\r
1063       pcd_pcm_write(a>>1, d);\r
1064     return;\r
1065   }\r
1066 \r
1067   s68k_unmapped_write8(a, d);\r
1068 }\r
1069 \r
1070 static void PicoWriteS68k16_pr(u32 a, u32 d)\r
1071 {\r
1072   // regs\r
1073   if ((a & 0xfe00) == 0x8000) {\r
1074     a &= 0x1fe;\r
1075     elprintf(EL_CDREGS, "s68k_regs w16: [%02x] %04x @%06x", a, d, SekPcS68k);\r
1076     s68k_reg_write16(a, d);\r
1077     return;\r
1078   }\r
1079 \r
1080   // PCM\r
1081   if ((a & 0x8000) == 0x0000) {\r
1082     a &= 0x7fff;\r
1083     if (a >= 0x2000)\r
1084       Pico_mcd->pcm_ram_b[Pico_mcd->pcm.bank][(a>>1)&0xfff] = d;\r
1085     else if (a < 0x12)\r
1086       pcd_pcm_write(a>>1, d & 0xff);\r
1087     return;\r
1088   }\r
1089 \r
1090   s68k_unmapped_write16(a, d);\r
1091 }\r
1092 \r
1093 #endif\r
1094 \r
1095 static const void *m68k_cell_read8[]   = { PicoReadM68k8_cell0, PicoReadM68k8_cell1 };\r
1096 static const void *m68k_cell_read16[]  = { PicoReadM68k16_cell0, PicoReadM68k16_cell1 };\r
1097 static const void *m68k_cell_write8[]  = { PicoWriteM68k8_cell0, PicoWriteM68k8_cell1 };\r
1098 static const void *m68k_cell_write16[] = { PicoWriteM68k16_cell0, PicoWriteM68k16_cell1 };\r
1099 \r
1100 static const void *s68k_dec_read8[]   = { PicoReadS68k8_dec0, PicoReadS68k8_dec1 };\r
1101 static const void *s68k_dec_read16[]  = { PicoReadS68k16_dec0, PicoReadS68k16_dec1 };\r
1102 \r
1103 static const void *s68k_dec_write8[2][4] = {\r
1104   { PicoWriteS68k8_dec_m0b0, PicoWriteS68k8_dec_m1b0, PicoWriteS68k8_dec_m2b0, PicoWriteS68k8_dec_m2b0 },\r
1105   { PicoWriteS68k8_dec_m0b1, PicoWriteS68k8_dec_m1b1, PicoWriteS68k8_dec_m2b1, PicoWriteS68k8_dec_m2b1 },\r
1106 };\r
1107 \r
1108 static const void *s68k_dec_write16[2][4] = {\r
1109   { PicoWriteS68k16_dec_m0b0, PicoWriteS68k16_dec_m1b0, PicoWriteS68k16_dec_m2b0, PicoWriteS68k16_dec_m2b0 },\r
1110   { PicoWriteS68k16_dec_m0b1, PicoWriteS68k16_dec_m1b1, PicoWriteS68k16_dec_m2b1, PicoWriteS68k16_dec_m2b1 },\r
1111 };\r
1112 \r
1113 // -----------------------------------------------------------------\r
1114 \r
1115 static void remap_prg_window(u32 r1, u32 r3)\r
1116 {\r
1117   // PRG RAM, mapped to main CPU if sub is not running\r
1118   if ((r1 & 3) != 1) {\r
1119     void *bank = Pico_mcd->prg_ram_b[(r3 >> 6) & 3];\r
1120     cpu68k_map_all_ram(BASE+0x020000, BASE+0x03ffff, bank, 0);\r
1121   } else {\r
1122     m68k_map_unmap(BASE+0x020000, BASE+0x03ffff);\r
1123   }\r
1124 }\r
1125 \r
1126 // if sub CPU accesses Word-RAM while it is assigned to the main CPU,\r
1127 // GA doesn't assert DTACK, which means the CPU is blocked until the Word_RAM\r
1128 // is reassigned to it (e.g. Mega Race).\r
1129 // since DTACK isn't on the expansion port, main cpu accesses are not blocked.\r
1130 // XXX is data read/written if main is accessing Word_RAM while not owning it?\r
1131 static u32 s68k_wordram_main_read8(u32 a)\r
1132 {\r
1133   Pico_mcd->m.state_flags |= PCD_ST_S68K_SLEEP;\r
1134   SekEndRunS68k(0);\r
1135   return Pico_mcd->word_ram2M[MEM_BE2(a) & 0x3ffff];\r
1136 }\r
1137 \r
1138 static u32 s68k_wordram_main_read16(u32 a)\r
1139 {\r
1140   Pico_mcd->m.state_flags |= PCD_ST_S68K_SLEEP;\r
1141   SekEndRunS68k(0);\r
1142   return ((u16 *)Pico_mcd->word_ram2M)[(a >> 1) & 0x1ffff];\r
1143 }\r
1144 \r
1145 static void s68k_wordram_main_write8(u32 a, u32 d)\r
1146 {\r
1147   Pico_mcd->m.state_flags |= PCD_ST_S68K_SLEEP;\r
1148   SekEndRunS68k(0);\r
1149   Pico_mcd->word_ram2M[MEM_BE2(a) & 0x3ffff] = d;\r
1150 }\r
1151 \r
1152 static void s68k_wordram_main_write16(u32 a, u32 d)\r
1153 {\r
1154   Pico_mcd->m.state_flags |= PCD_ST_S68K_SLEEP;\r
1155   SekEndRunS68k(0);\r
1156   ((u16 *)Pico_mcd->word_ram2M)[(a >> 1) & 0x1ffff] = d;\r
1157 }\r
1158 \r
1159 static void remap_word_ram(u32 r3)\r
1160 {\r
1161   void *bank;\r
1162 \r
1163   // WORD RAM\r
1164   if (!(r3 & 4)) {\r
1165     // 2M mode.\r
1166     bank = Pico_mcd->word_ram2M;\r
1167     if (r3 & 1) {\r
1168       cpu68k_map_all_ram(BASE+0x200000, BASE+0x23ffff, bank, 0);\r
1169       cpu68k_map_all_funcs(0x80000, 0xbffff,\r
1170           s68k_wordram_main_read8, s68k_wordram_main_read16,\r
1171           s68k_wordram_main_write8, s68k_wordram_main_write16, 1);\r
1172     } else {\r
1173       Pico_mcd->m.state_flags &= ~PCD_ST_S68K_SLEEP;\r
1174       cpu68k_map_all_ram(0x080000, 0x0bffff, bank, 1);\r
1175       m68k_map_unmap(BASE+0x200000, BASE+0x23ffff);\r
1176     }\r
1177     // TODO: handle 0x0c0000\r
1178   }\r
1179   else {\r
1180     int b0 = r3 & 1;\r
1181     int m = (r3 & 0x18) >> 3;\r
1182     Pico_mcd->m.state_flags &= ~PCD_ST_S68K_SLEEP;\r
1183     bank = Pico_mcd->word_ram1M[b0];\r
1184     cpu68k_map_all_ram(BASE+0x200000, BASE+0x21ffff, bank, 0);\r
1185     bank = Pico_mcd->word_ram1M[b0 ^ 1];\r
1186     cpu68k_map_all_ram(0x0c0000, 0x0effff, bank, 1);\r
1187     // "cell arrange" on m68k\r
1188     cpu68k_map_all_funcs(BASE+0x220000, BASE+0x23ffff,\r
1189         m68k_cell_read8[b0], m68k_cell_read16[b0],\r
1190         m68k_cell_write8[b0], m68k_cell_write16[b0], 0);\r
1191     // "decode format" on s68k\r
1192     cpu68k_map_all_funcs(0x80000, 0xbffff,\r
1193         s68k_dec_read8[b0^1], s68k_dec_read16[b0^1],\r
1194         s68k_dec_write8[b0^1][m], s68k_dec_write16[b0^1][m], 1);\r
1195   }\r
1196 }\r
1197 \r
1198 void pcd_state_loaded_mem(void)\r
1199 {\r
1200   u32 r3 = Pico_mcd->s68k_regs[3];\r
1201 \r
1202   /* after load events */\r
1203   if (r3 & 4) // 1M mode?\r
1204     wram_2M_to_1M(Pico_mcd->word_ram2M);\r
1205   remap_word_ram(r3);\r
1206   remap_prg_window(Pico_mcd->m.busreq, r3);\r
1207   Pico_mcd->m.dmna_ret_2m &= 3;\r
1208 \r
1209   // restore hint vector\r
1210   *(u16 *)(Pico_mcd->bios + 0x72) = Pico_mcd->m.hint_vector;\r
1211 }\r
1212 \r
1213 #ifdef EMU_M68K\r
1214 static void m68k_mem_setup_cd(void);\r
1215 #endif\r
1216 \r
1217 PICO_INTERNAL void PicoMemSetupCD(void)\r
1218 {\r
1219   if (Pico_mcd == NULL) {\r
1220     static u8 bios_id[4] = "SEGA";\r
1221     PicoCreateMCD(NULL, 0);\r
1222     // BIOS faking for MSU-MD, checks for "SEGA" at 0x400100 to detect CD drive\r
1223     memcpy(Pico_mcd->bios+0x100, bios_id, 4);\r
1224   }\r
1225 \r
1226   pcd_base_address = (Pico.romsize ? 0x400000 : 0x000000);\r
1227 \r
1228   // setup default main68k map\r
1229   PicoMemSetup();\r
1230 \r
1231   // main68k map (BIOS or MSU mapped by PicoMemSetup()):\r
1232   cpu68k_map_set(m68k_read8_map,   BASE, BASE+0x01ffff, Pico_mcd->bios, 0);\r
1233   cpu68k_map_set(m68k_read16_map,  BASE, BASE+0x01ffff, Pico_mcd->bios, 0);\r
1234   if (pcd_base_address != 0) { // cartridge (for MSU/MD+)\r
1235     // MD+ on MEGASD plus mirror\r
1236     u32 base = 0x040000-(1<<M68K_MEM_SHIFT);\r
1237     cpu68k_map_set(m68k_write8_map,  base, 0x03ffff, msd_write8, 1);\r
1238     cpu68k_map_set(m68k_write16_map, base, 0x03ffff, msd_write16, 1);\r
1239     cpu68k_map_set(m68k_write8_map,  base+0x080000, 0x0bffff, msd_write8, 1);\r
1240     cpu68k_map_set(m68k_write16_map, base+0x080000, 0x0bffff, msd_write16, 1);\r
1241     msd_reset();\r
1242   } else { // no cartridge\r
1243     // RAM cart\r
1244     cpu68k_map_set(m68k_read8_map,   0x400000, 0x7fffff, PicoReadM68k8_ramc, 1);\r
1245     cpu68k_map_set(m68k_read16_map,  0x400000, 0x7fffff, PicoReadM68k16_ramc, 1);\r
1246     cpu68k_map_set(m68k_write8_map,  0x400000, 0x7fffff, PicoWriteM68k8_ramc, 1);\r
1247     cpu68k_map_set(m68k_write16_map, 0x400000, 0x7fffff, PicoWriteM68k16_ramc, 1);\r
1248   }\r
1249 \r
1250   // registers/IO:\r
1251   cpu68k_map_set(m68k_read8_map,   0xa10000, 0xa1ffff, PicoRead8_mcd_io, 1);\r
1252   cpu68k_map_set(m68k_read16_map,  0xa10000, 0xa1ffff, PicoRead16_mcd_io, 1);\r
1253   cpu68k_map_set(m68k_write8_map,  0xa10000, 0xa1ffff, PicoWrite8_mcd_io, 1);\r
1254   cpu68k_map_set(m68k_write16_map, 0xa10000, 0xa1ffff, PicoWrite16_mcd_io, 1);\r
1255 \r
1256   // sub68k map\r
1257   cpu68k_map_set(s68k_read8_map,   0x000000, 0xffffff, s68k_unmapped_read8, 3);\r
1258   cpu68k_map_set(s68k_read16_map,  0x000000, 0xffffff, s68k_unmapped_read16, 3);\r
1259   cpu68k_map_set(s68k_write8_map,  0x000000, 0xffffff, s68k_unmapped_write8, 3);\r
1260   cpu68k_map_set(s68k_write16_map, 0x000000, 0xffffff, s68k_unmapped_write16, 3);\r
1261 \r
1262   // PRG RAM\r
1263   cpu68k_map_set(s68k_read8_map,   0x000000, 0x07ffff, Pico_mcd->prg_ram, 2);\r
1264   cpu68k_map_set(s68k_read16_map,  0x000000, 0x07ffff, Pico_mcd->prg_ram, 2);\r
1265   cpu68k_map_set(s68k_write8_map,  0x000000, 0x07ffff, Pico_mcd->prg_ram, 2);\r
1266   cpu68k_map_set(s68k_write16_map, 0x000000, 0x07ffff, Pico_mcd->prg_ram, 2);\r
1267   cpu68k_map_set(s68k_write8_map,  0x000000, 0x01ffff, PicoWriteS68k8_prgwp, 3);\r
1268   cpu68k_map_set(s68k_write16_map, 0x000000, 0x01ffff, PicoWriteS68k16_prgwp, 3);\r
1269 \r
1270   // BRAM\r
1271   cpu68k_map_set(s68k_read8_map,   0xfe0000, 0xfeffff, PicoReadS68k8_bram, 3);\r
1272   cpu68k_map_set(s68k_read16_map,  0xfe0000, 0xfeffff, PicoReadS68k16_bram, 3);\r
1273   cpu68k_map_set(s68k_write8_map,  0xfe0000, 0xfeffff, PicoWriteS68k8_bram, 3);\r
1274   cpu68k_map_set(s68k_write16_map, 0xfe0000, 0xfeffff, PicoWriteS68k16_bram, 3);\r
1275 \r
1276   // PCM, regs\r
1277   cpu68k_map_set(s68k_read8_map,   0xff0000, 0xffffff, PicoReadS68k8_pr, 3);\r
1278   cpu68k_map_set(s68k_read16_map,  0xff0000, 0xffffff, PicoReadS68k16_pr, 3);\r
1279   cpu68k_map_set(s68k_write8_map,  0xff0000, 0xffffff, PicoWriteS68k8_pr, 3);\r
1280   cpu68k_map_set(s68k_write16_map, 0xff0000, 0xffffff, PicoWriteS68k16_pr, 3);\r
1281 \r
1282   // RAMs\r
1283   remap_prg_window(2,1);\r
1284   remap_word_ram(1);\r
1285 \r
1286 #ifdef EMU_C68K\r
1287   // s68k\r
1288   PicoCpuCS68k.read8  = (void *)s68k_read8_map;\r
1289   PicoCpuCS68k.read16 = (void *)s68k_read16_map;\r
1290   PicoCpuCS68k.read32 = (void *)s68k_read16_map;\r
1291   PicoCpuCS68k.write8  = (void *)s68k_write8_map;\r
1292   PicoCpuCS68k.write16 = (void *)s68k_write16_map;\r
1293   PicoCpuCS68k.write32 = (void *)s68k_write16_map;\r
1294   PicoCpuCS68k.checkpc = NULL; /* unused */\r
1295   PicoCpuCS68k.fetch8  = NULL;\r
1296   PicoCpuCS68k.fetch16 = NULL;\r
1297   PicoCpuCS68k.fetch32 = NULL;\r
1298 #endif\r
1299 #ifdef EMU_F68K\r
1300   // s68k\r
1301   PicoCpuFS68k.read_byte  = (void *)s68k_read8;\r
1302   PicoCpuFS68k.read_word  = (void *)s68k_read16;\r
1303   PicoCpuFS68k.read_long  = (void *)s68k_read32;\r
1304   PicoCpuFS68k.write_byte = (void *)s68k_write8;\r
1305   PicoCpuFS68k.write_word = (void *)s68k_write16;\r
1306   PicoCpuFS68k.write_long = (void *)s68k_write32;\r
1307 #endif\r
1308 #ifdef EMU_M68K\r
1309   m68k_mem_setup_cd();\r
1310 #endif\r
1311 }\r
1312 \r
1313 \r
1314 #ifdef EMU_M68K\r
1315 u32  m68k_read8(u32 a);\r
1316 u32  m68k_read16(u32 a);\r
1317 u32  m68k_read32(u32 a);\r
1318 void m68k_write8(u32 a, u8 d);\r
1319 void m68k_write16(u32 a, u16 d);\r
1320 void m68k_write32(u32 a, u32 d);\r
1321 \r
1322 static unsigned int PicoReadCD8w (unsigned int a) {\r
1323         return m68ki_cpu_p == &PicoCpuMS68k ? s68k_read8(a) : m68k_read8(a);\r
1324 }\r
1325 static unsigned int PicoReadCD16w(unsigned int a) {\r
1326         return m68ki_cpu_p == &PicoCpuMS68k ? s68k_read16(a) : m68k_read16(a);\r
1327 }\r
1328 static unsigned int PicoReadCD32w(unsigned int a) {\r
1329         return m68ki_cpu_p == &PicoCpuMS68k ? s68k_read32(a) : m68k_read32(a);\r
1330 }\r
1331 static void PicoWriteCD8w (unsigned int a, unsigned char d) {\r
1332         if (m68ki_cpu_p == &PicoCpuMS68k) s68k_write8(a, d); else m68k_write8(a, d);\r
1333 }\r
1334 static void PicoWriteCD16w(unsigned int a, unsigned short d) {\r
1335         if (m68ki_cpu_p == &PicoCpuMS68k) s68k_write16(a, d); else m68k_write16(a, d);\r
1336 }\r
1337 static void PicoWriteCD32w(unsigned int a, unsigned int d) {\r
1338         if (m68ki_cpu_p == &PicoCpuMS68k) s68k_write32(a, d); else m68k_write32(a, d);\r
1339 }\r
1340 \r
1341 extern unsigned int (*pm68k_read_memory_8) (unsigned int address);\r
1342 extern unsigned int (*pm68k_read_memory_16)(unsigned int address);\r
1343 extern unsigned int (*pm68k_read_memory_32)(unsigned int address);\r
1344 extern void (*pm68k_write_memory_8) (unsigned int address, unsigned char  value);\r
1345 extern void (*pm68k_write_memory_16)(unsigned int address, unsigned short value);\r
1346 extern void (*pm68k_write_memory_32)(unsigned int address, unsigned int   value);\r
1347 \r
1348 static void m68k_mem_setup_cd(void)\r
1349 {\r
1350   pm68k_read_memory_8  = PicoReadCD8w;\r
1351   pm68k_read_memory_16 = PicoReadCD16w;\r
1352   pm68k_read_memory_32 = PicoReadCD32w;\r
1353   pm68k_write_memory_8  = PicoWriteCD8w;\r
1354   pm68k_write_memory_16 = PicoWriteCD16w;\r
1355   pm68k_write_memory_32 = PicoWriteCD32w;\r
1356 }\r
1357 #endif // EMU_M68K\r
1358 \r
1359 // vim:shiftwidth=2:ts=2:expandtab\r