pandora: fix readme and pxml version
[picodrive.git] / pico / memory.c
... / ...
CommitLineData
1/*\r
2 * memory handling\r
3 * (c) Copyright Dave, 2004\r
4 * (C) notaz, 2006-2010\r
5 * (C) irixxxx, 2019-2024\r
6 *\r
7 * This work is licensed under the terms of MAME license.\r
8 * See COPYING file in the top-level directory.\r
9 */\r
10\r
11#include <assert.h>\r
12#include "pico_int.h"\r
13#include "memory.h"\r
14#include "state.h"\r
15\r
16#include "sound/ym2612.h"\r
17#include "sound/sn76496.h"\r
18\r
19extern unsigned int lastSSRamWrite; // used by serial eeprom code\r
20\r
21uptr m68k_read8_map [0x1000000 >> M68K_MEM_SHIFT];\r
22uptr m68k_read16_map [0x1000000 >> M68K_MEM_SHIFT];\r
23uptr m68k_write8_map [0x1000000 >> M68K_MEM_SHIFT];\r
24uptr m68k_write16_map[0x1000000 >> M68K_MEM_SHIFT];\r
25\r
26static void xmap_set(uptr *map, int shift, u32 start_addr, u32 end_addr,\r
27 const void *func_or_mh, int is_func)\r
28{\r
29#ifdef __clang__\r
30 // workaround bug (segfault) in \r
31 // Apple LLVM version 4.2 (clang-425.0.27) (based on LLVM 3.2svn)\r
32 volatile \r
33#endif\r
34 uptr addr = (uptr)func_or_mh;\r
35 int mask = (1 << shift) - 1;\r
36 int i;\r
37\r
38 if ((start_addr & mask) != 0 || (end_addr & mask) != mask) {\r
39 elprintf(EL_STATUS|EL_ANOMALY, "xmap_set: tried to map bad range: %06x-%06x",\r
40 start_addr, end_addr);\r
41 return;\r
42 }\r
43\r
44 if (addr & 1) {\r
45 elprintf(EL_STATUS|EL_ANOMALY, "xmap_set: ptr is not aligned: %08lx", addr);\r
46 return;\r
47 }\r
48\r
49 if (!is_func)\r
50 addr -= start_addr;\r
51\r
52 for (i = start_addr >> shift; i <= end_addr >> shift; i++) {\r
53 map[i] = addr >> 1;\r
54 if (is_func)\r
55 map[i] |= MAP_FLAG;\r
56 }\r
57}\r
58\r
59void z80_map_set(uptr *map, u16 start_addr, u16 end_addr,\r
60 const void *func_or_mh, int is_func)\r
61{\r
62 xmap_set(map, Z80_MEM_SHIFT, start_addr, end_addr, func_or_mh, is_func);\r
63#ifdef _USE_CZ80\r
64 if (!is_func)\r
65 Cz80_Set_Fetch(&CZ80, start_addr, end_addr, (FPTR)func_or_mh);\r
66#endif\r
67}\r
68\r
69void cpu68k_map_set(uptr *map, u32 start_addr, u32 end_addr,\r
70 const void *func_or_mh, int is_func)\r
71{\r
72 xmap_set(map, M68K_MEM_SHIFT, start_addr, end_addr, func_or_mh, is_func & 1);\r
73#ifdef EMU_F68K\r
74 // setup FAME fetchmap\r
75 if (!(is_func & 1))\r
76 {\r
77 M68K_CONTEXT *ctx = is_func & 2 ? &PicoCpuFS68k : &PicoCpuFM68k;\r
78 int shiftout = 24 - FAMEC_FETCHBITS;\r
79 int i = start_addr >> shiftout;\r
80 uptr base = (uptr)func_or_mh - (i << shiftout);\r
81 for (; i <= (end_addr >> shiftout); i++)\r
82 ctx->Fetch[i] = base;\r
83 }\r
84#endif\r
85}\r
86\r
87// more specialized/optimized function (does same as above)\r
88void cpu68k_map_read_mem(u32 start_addr, u32 end_addr, void *ptr, int is_sub)\r
89{\r
90 uptr *r8map, *r16map;\r
91 uptr addr = (uptr)ptr;\r
92 int shift = M68K_MEM_SHIFT;\r
93 int i;\r
94\r
95 if (!is_sub) {\r
96 r8map = m68k_read8_map;\r
97 r16map = m68k_read16_map;\r
98 } else {\r
99 r8map = s68k_read8_map;\r
100 r16map = s68k_read16_map;\r
101 }\r
102\r
103 addr -= start_addr;\r
104 addr >>= 1;\r
105 for (i = start_addr >> shift; i <= end_addr >> shift; i++)\r
106 r8map[i] = r16map[i] = addr;\r
107#ifdef EMU_F68K\r
108 // setup FAME fetchmap\r
109 {\r
110 M68K_CONTEXT *ctx = is_sub ? &PicoCpuFS68k : &PicoCpuFM68k;\r
111 int shiftout = 24 - FAMEC_FETCHBITS;\r
112 i = start_addr >> shiftout;\r
113 addr = (uptr)ptr - (i << shiftout);\r
114 for (; i <= (end_addr >> shiftout); i++)\r
115 ctx->Fetch[i] = addr;\r
116 }\r
117#endif\r
118}\r
119\r
120void cpu68k_map_all_ram(u32 start_addr, u32 end_addr, void *ptr, int is_sub)\r
121{\r
122 uptr *r8map, *r16map, *w8map, *w16map;\r
123 uptr addr = (uptr)ptr;\r
124 int shift = M68K_MEM_SHIFT;\r
125 int i;\r
126\r
127 if (!is_sub) {\r
128 r8map = m68k_read8_map;\r
129 r16map = m68k_read16_map;\r
130 w8map = m68k_write8_map;\r
131 w16map = m68k_write16_map;\r
132 } else {\r
133 r8map = s68k_read8_map;\r
134 r16map = s68k_read16_map;\r
135 w8map = s68k_write8_map;\r
136 w16map = s68k_write16_map;\r
137 }\r
138\r
139 addr -= start_addr;\r
140 addr >>= 1;\r
141 for (i = start_addr >> shift; i <= end_addr >> shift; i++)\r
142 r8map[i] = r16map[i] = w8map[i] = w16map[i] = addr;\r
143#ifdef EMU_F68K\r
144 // setup FAME fetchmap\r
145 {\r
146 M68K_CONTEXT *ctx = is_sub ? &PicoCpuFS68k : &PicoCpuFM68k;\r
147 int shiftout = 24 - FAMEC_FETCHBITS;\r
148 i = start_addr >> shiftout;\r
149 addr = (uptr)ptr - (i << shiftout);\r
150 for (; i <= (end_addr >> shiftout); i++)\r
151 ctx->Fetch[i] = addr;\r
152 }\r
153#endif\r
154}\r
155\r
156void cpu68k_map_read_funcs(u32 start_addr, u32 end_addr, u32 (*r8)(u32), u32 (*r16)(u32), int is_sub)\r
157{\r
158 uptr *r8map, *r16map;\r
159 uptr ar8 = (uptr)r8, ar16 = (uptr)r16;\r
160 int shift = M68K_MEM_SHIFT;\r
161 int i;\r
162\r
163 if (!is_sub) {\r
164 r8map = m68k_read8_map;\r
165 r16map = m68k_read16_map;\r
166 } else {\r
167 r8map = s68k_read8_map;\r
168 r16map = s68k_read16_map;\r
169 }\r
170\r
171 ar8 = (ar8 >> 1 ) | MAP_FLAG;\r
172 ar16 = (ar16 >> 1 ) | MAP_FLAG;\r
173 for (i = start_addr >> shift; i <= end_addr >> shift; i++)\r
174 r8map[i] = ar8, r16map[i] = ar16;\r
175}\r
176\r
177void cpu68k_map_all_funcs(u32 start_addr, u32 end_addr, u32 (*r8)(u32), u32 (*r16)(u32), void (*w8)(u32, u32), void (*w16)(u32, u32), int is_sub)\r
178{\r
179 uptr *r8map, *r16map, *w8map, *w16map;\r
180 uptr ar8 = (uptr)r8, ar16 = (uptr)r16;\r
181 uptr aw8 = (uptr)w8, aw16 = (uptr)w16;\r
182 int shift = M68K_MEM_SHIFT;\r
183 int i;\r
184\r
185 if (!is_sub) {\r
186 r8map = m68k_read8_map;\r
187 r16map = m68k_read16_map;\r
188 w8map = m68k_write8_map;\r
189 w16map = m68k_write16_map;\r
190 } else {\r
191 r8map = s68k_read8_map;\r
192 r16map = s68k_read16_map;\r
193 w8map = s68k_write8_map;\r
194 w16map = s68k_write16_map;\r
195 }\r
196\r
197 ar8 = (ar8 >> 1 ) | MAP_FLAG;\r
198 ar16 = (ar16 >> 1 ) | MAP_FLAG;\r
199 aw8 = (aw8 >> 1 ) | MAP_FLAG;\r
200 aw16 = (aw16 >> 1 ) | MAP_FLAG;\r
201 for (i = start_addr >> shift; i <= end_addr >> shift; i++)\r
202 r8map[i] = ar8, r16map[i] = ar16, w8map[i] = aw8, w16map[i] = aw16;\r
203}\r
204\r
205u32 PicoRead16_floating(u32 a)\r
206{\r
207 // faking open bus\r
208 u16 d = (Pico.m.rotate += 0x41);\r
209 d ^= (d << 5) ^ (d << 8);\r
210 if ((a & 0xff0000) == 0xa10000) return d; // MegaCD pulldowns don't work here curiously\r
211 return (PicoIn.AHW & PAHW_MCD) ? 0x00 : d; // pulldown if MegaCD2 attached\r
212}\r
213\r
214static u32 m68k_unmapped_read8(u32 a)\r
215{\r
216 elprintf(EL_UIO, "m68k unmapped r8 [%06x] @%06x", a, SekPc);\r
217 return a < 0x400000 ? 0 : (u8)PicoRead16_floating(a);\r
218}\r
219\r
220static u32 m68k_unmapped_read16(u32 a)\r
221{\r
222 elprintf(EL_UIO, "m68k unmapped r16 [%06x] @%06x", a, SekPc);\r
223 return a < 0x400000 ? 0 : PicoRead16_floating(a);\r
224}\r
225\r
226static void m68k_unmapped_write8(u32 a, u32 d)\r
227{\r
228 elprintf(EL_UIO, "m68k unmapped w8 [%06x] %02x @%06x", a, d & 0xff, SekPc);\r
229}\r
230\r
231static void m68k_unmapped_write16(u32 a, u32 d)\r
232{\r
233 elprintf(EL_UIO, "m68k unmapped w16 [%06x] %04x @%06x", a, d & 0xffff, SekPc);\r
234}\r
235\r
236void m68k_map_unmap(u32 start_addr, u32 end_addr)\r
237{\r
238#ifdef __clang__\r
239 // workaround bug (segfault) in \r
240 // Apple LLVM version 4.2 (clang-425.0.27) (based on LLVM 3.2svn)\r
241 volatile \r
242#endif\r
243 uptr addr;\r
244 int shift = M68K_MEM_SHIFT;\r
245 int i;\r
246\r
247 addr = (uptr)m68k_unmapped_read8;\r
248 for (i = start_addr >> shift; i <= end_addr >> shift; i++)\r
249 m68k_read8_map[i] = (addr >> 1) | MAP_FLAG;\r
250\r
251 addr = (uptr)m68k_unmapped_read16;\r
252 for (i = start_addr >> shift; i <= end_addr >> shift; i++)\r
253 m68k_read16_map[i] = (addr >> 1) | MAP_FLAG;\r
254\r
255 addr = (uptr)m68k_unmapped_write8;\r
256 for (i = start_addr >> shift; i <= end_addr >> shift; i++)\r
257 m68k_write8_map[i] = (addr >> 1) | MAP_FLAG;\r
258\r
259 addr = (uptr)m68k_unmapped_write16;\r
260 for (i = start_addr >> shift; i <= end_addr >> shift; i++)\r
261 m68k_write16_map[i] = (addr >> 1) | MAP_FLAG;\r
262}\r
263\r
264#ifndef _ASM_MEMORY_C\r
265MAKE_68K_READ8(m68k_read8, m68k_read8_map)\r
266MAKE_68K_READ16(m68k_read16, m68k_read16_map)\r
267MAKE_68K_READ32(m68k_read32, m68k_read16_map)\r
268MAKE_68K_WRITE8(m68k_write8, m68k_write8_map)\r
269MAKE_68K_WRITE16(m68k_write16, m68k_write16_map)\r
270MAKE_68K_WRITE32(m68k_write32, m68k_write16_map)\r
271#endif\r
272\r
273// -----------------------------------------------------------------\r
274\r
275static u32 ym2612_read_local_68k(void);\r
276static int ym2612_write_local(u32 a, u32 d, int is_from_z80);\r
277static void z80_mem_setup(void);\r
278\r
279#ifdef _ASM_MEMORY_C\r
280u32 PicoRead8_sram(u32 a);\r
281u32 PicoRead16_sram(u32 a);\r
282#endif\r
283\r
284#ifdef EMU_CORE_DEBUG\r
285u32 lastread_a, lastread_d[16]={0,}, lastwrite_cyc_d[16]={0,}, lastwrite_mus_d[16]={0,};\r
286int lrp_cyc=0, lrp_mus=0, lwp_cyc=0, lwp_mus=0;\r
287extern unsigned int ppop;\r
288#endif\r
289\r
290#ifdef IO_STATS\r
291void log_io(unsigned int addr, int bits, int rw);\r
292#elif defined(_MSC_VER)\r
293#define log_io\r
294#else\r
295#define log_io(...)\r
296#endif\r
297\r
298#if defined(EMU_C68K)\r
299u32 cyclone_crashed(u32 pc, struct Cyclone *context)\r
300{\r
301 // check for underlying ROM, in case of on-cart hw overlaying part of ROM\r
302 // NB assumes code isn't executed from the overlay, but I've never seen this\r
303 u32 pc24 = pc & 0xffffff;\r
304 if (pc24 >= Pico.romsize) {\r
305 // no ROM, so it's probably an illegal access\r
306 pc24 = Pico.romsize;\r
307 elprintf(EL_STATUS|EL_ANOMALY, "%c68k crash detected @ %06x",\r
308 context == &PicoCpuCM68k ? 'm' : 's', pc);\r
309 }\r
310\r
311 context->membase = (u32)Pico.rom;\r
312 context->pc = (u32)Pico.rom + pc24;\r
313\r
314 return context->pc;\r
315}\r
316#endif\r
317\r
318// -----------------------------------------------------------------\r
319// memmap helpers\r
320\r
321static u32 read_pad_3btn(int i, u32 out_bits)\r
322{\r
323 u32 pad = ~PicoIn.padInt[i]; // Get inverse of pad MXYZ SACB RLDU\r
324 u32 value;\r
325\r
326 if (out_bits & 0x40) // TH\r
327 value = pad & 0x3f; // ?1CB RLDU\r
328 else\r
329 value = ((pad & 0xc0) >> 2) | (pad & 3); // ?0SA 00DU\r
330\r
331 value |= out_bits & 0x40;\r
332 return value;\r
333}\r
334\r
335static u32 read_pad_6btn(int i, u32 out_bits)\r
336{\r
337 u32 pad = ~PicoIn.padInt[i]; // Get inverse of pad MXYZ SACB RLDU\r
338 int phase = Pico.m.padTHPhase[i];\r
339 u32 value;\r
340\r
341 if (phase == 2 && !(out_bits & 0x40)) {\r
342 value = (pad & 0xc0) >> 2; // ?0SA 0000\r
343 goto out;\r
344 }\r
345 else if (phase == 3) {\r
346 if (out_bits & 0x40)\r
347 value = (pad & 0x30) | ((pad >> 8) & 0xf); // ?1CB MXYZ\r
348 else\r
349 value = ((pad & 0xc0) >> 2) | 0x0f; // ?0SA 1111\r
350 goto out;\r
351 }\r
352\r
353 if (out_bits & 0x40) // TH\r
354 value = pad & 0x3f; // ?1CB RLDU\r
355 else\r
356 value = ((pad & 0xc0) >> 2) | (pad & 3); // ?0SA 00DU\r
357\r
358out:\r
359 value |= out_bits & 0x40;\r
360 return value;\r
361}\r
362\r
363static u32 read_pad_team(int i, u32 out_bits)\r
364{\r
365 u32 pad;\r
366 int phase = Pico.m.padTHPhase[i];\r
367 u32 value;\r
368\r
369 switch (phase) {\r
370 case 0:\r
371 value = 0x03;\r
372 break;\r
373 case 1:\r
374 value = 0x0f;\r
375 break;\r
376 case 4: case 5: case 6: case 7: // controller IDs, all 3 btn for now\r
377 value = 0x00;\r
378 break;\r
379 case 8: case 10: case 12: case 14:\r
380 pad = ~PicoIn.padInt[(phase-8) >> 1];\r
381 value = pad & 0x0f; // ?x?x RLDU\r
382 break;\r
383 case 9: case 11: case 13: case 15:\r
384 pad = ~PicoIn.padInt[(phase-8) >> 1];\r
385 value = (pad & 0xf0) >> 4; // ?x?x SACB\r
386 break;\r
387 default:\r
388 value = 0;\r
389 break;\r
390 }\r
391\r
392 value |= (out_bits & 0x40) | ((out_bits & 0x20)>>1);\r
393 return value;\r
394}\r
395\r
396static u32 read_pad_4way(int i, u32 out_bits)\r
397{\r
398 u32 pad = (PicoMem.ioports[2] & 0x70) >> 4;\r
399 u32 value = 0;\r
400\r
401 if (i == 0 && pad <= 3)\r
402 value = read_pad_3btn(pad, out_bits);\r
403\r
404 value |= (out_bits & 0x40);\r
405 return value;\r
406}\r
407\r
408static u32 read_pad_mouse(int i, u32 out_bits)\r
409{\r
410 int phase = Pico.m.padTHPhase[i];\r
411 u32 value;\r
412\r
413 int x = PicoIn.mouseInt[0] - PicoIn.mouseInt[2];\r
414 int y = PicoIn.mouseInt[3] - PicoIn.mouseInt[1];\r
415\r
416 switch (phase) {\r
417 case 0:\r
418 value = 0x00;\r
419 break;\r
420 case 1:\r
421 value = 0x0b;\r
422 break;\r
423 case 2:\r
424 value = 0x0f;\r
425 // store last read values for x,y difference calculation\r
426 PicoIn.mouseInt[2] = PicoIn.mouseInt[0];\r
427 PicoIn.mouseInt[3] = PicoIn.mouseInt[1];\r
428 break;\r
429 case 3:\r
430 value = 0x0f;\r
431 // latch current mouse position during readout\r
432 PicoIn.mouseInt[0] = PicoIn.mouse[0];\r
433 PicoIn.mouseInt[1] = PicoIn.mouse[1];\r
434 break;\r
435 case 4: // xxxx OOSS, OO = y,x overflow, SS = y,x sign bits\r
436 value = (x<0) | ((y<0)<<1) | ((x<-255||x>255)<<2) | ((y<-255||y>255)<<3);\r
437 break;\r
438 case 5:\r
439 value = (PicoIn.padInt[i] & 0xf0) >> 4; // SMRL, mapped from SACB\r
440 break;\r
441 case 6: // high nibble of x\r
442 value = (x>>4) & 0xf;\r
443 break;\r
444 case 7: // low nibble of x\r
445 value = x & 0xf;\r
446 break;\r
447 case 8: // high nibble of y\r
448 value = (y>>4) & 0xf;\r
449 break;\r
450 case 9: // low nibble of y\r
451 default: // also sent on all later phases\r
452 value = y & 0xf;\r
453 break;\r
454 }\r
455\r
456 value |= (out_bits & 0x40) | ((out_bits & 0x20)>>1);\r
457 return value;\r
458}\r
459\r
460static u32 read_nothing(int i, u32 out_bits)\r
461{\r
462 return 0xff;\r
463}\r
464\r
465typedef u32 (port_read_func)(int index, u32 out_bits);\r
466\r
467static port_read_func *port_readers[3] = {\r
468 read_pad_3btn,\r
469 read_pad_3btn,\r
470 read_nothing\r
471};\r
472\r
473static int padTHLatency[3];\r
474static int padTLLatency[3];\r
475\r
476static NOINLINE u32 port_read(int i)\r
477{\r
478 u32 data_reg = PicoMem.ioports[i + 1];\r
479 u32 ctrl_reg = PicoMem.ioports[i + 4] | 0x80;\r
480 u32 in, out;\r
481\r
482 out = data_reg & ctrl_reg;\r
483\r
484 // pull-ups: should be 0x7f, but Decap Attack has a bug where it temp.\r
485 // disables output before doing TH-low read, so emulate RC filter for TH.\r
486 // Decap Attack reportedly doesn't work on Nomad but works on most\r
487 // other MD revisions (different pull-up strength?).\r
488 u32 mask = 0x3f;\r
489 if (CYCLES_GE(SekCyclesDone(), padTHLatency[i])) {\r
490 mask |= 0x40;\r
491 padTHLatency[i] = SekCyclesDone();\r
492 }\r
493 out |= mask & ~ctrl_reg;\r
494\r
495 in = port_readers[i](i, out);\r
496\r
497 // Sega mouse uses the TL/TR lines for req/ack. For buggy drivers, make sure\r
498 // there's some delay before ack is sent by taking over the new TL line level\r
499 if (CYCLES_GE(SekCyclesDone(), padTLLatency[i]))\r
500 padTLLatency[i] = SekCyclesDone();\r
501 else\r
502 in ^= 0x10; // TL\r
503\r
504 return (in & ~ctrl_reg) | (data_reg & ctrl_reg);\r
505}\r
506\r
507// pad export for J-Cart\r
508u32 PicoReadPad(int i, u32 out_bits)\r
509{\r
510 return read_pad_3btn(i, out_bits);\r
511}\r
512\r
513void PicoSetInputDevice(int port, enum input_device device)\r
514{\r
515 port_read_func *func;\r
516\r
517 if (port < 0 || port > 2)\r
518 return;\r
519\r
520 if (port == 1 && port_readers[0] == read_pad_team)\r
521 func = read_nothing;\r
522\r
523 else switch (device) {\r
524 case PICO_INPUT_PAD_3BTN:\r
525 func = read_pad_3btn;\r
526 break;\r
527\r
528 case PICO_INPUT_PAD_6BTN:\r
529 func = read_pad_6btn;\r
530 break;\r
531\r
532 case PICO_INPUT_PAD_TEAM:\r
533 func = read_pad_team;\r
534 break;\r
535\r
536 case PICO_INPUT_PAD_4WAY:\r
537 func = read_pad_4way;\r
538 break;\r
539\r
540 case PICO_INPUT_MOUSE:\r
541 func = read_pad_mouse;\r
542 break;\r
543\r
544 default:\r
545 func = read_nothing;\r
546 break;\r
547 }\r
548\r
549 port_readers[port] = func;\r
550}\r
551\r
552NOINLINE u32 io_ports_read(u32 a)\r
553{\r
554 u32 d;\r
555 a = (a>>1) & 0xf;\r
556 switch (a) {\r
557 case 0: d = Pico.m.hardware; break; // Hardware value (Version register)\r
558 case 1: d = port_read(0); break;\r
559 case 2: d = port_read(1); break;\r
560 case 3: d = port_read(2); break;\r
561 default: d = PicoMem.ioports[a]; break; // IO ports can be used as RAM\r
562 }\r
563 return d;\r
564}\r
565\r
566NOINLINE void io_ports_write(u32 a, u32 d)\r
567{\r
568 a = (a>>1) & 0xf;\r
569\r
570 // for some controllers, changing TH/TR changes controller state\r
571 if (1 <= a && a <= 2)\r
572 {\r
573 Pico.m.padDelay[a - 1] = 0;\r
574 if (port_readers[a - 1] == read_pad_team) {\r
575 if (d & 0x40)\r
576 Pico.m.padTHPhase[a - 1] = 0;\r
577 else if ((d^PicoMem.ioports[a]) & 0x60)\r
578 Pico.m.padTHPhase[a - 1]++;\r
579 } else if (port_readers[0] == read_pad_4way) {\r
580 if (a == 2 && ((PicoMem.ioports[a] ^ d) & 0x70))\r
581 Pico.m.padTHPhase[0] = 0;\r
582 if (a == 1 && !(PicoMem.ioports[a] & 0x40) && (d & 0x40))\r
583 Pico.m.padTHPhase[0]++;\r
584 } else if (port_readers[a - 1] == read_pad_mouse) {\r
585 if ((d^PicoMem.ioports[a]) & 0x20) {\r
586 if (Pico.m.padTHPhase[a - 1]) { // in readout?\r
587 padTLLatency[a - 1] = SekCyclesDone() + 100;\r
588 Pico.m.padTHPhase[a - 1]++;\r
589 } else // in ID cycle\r
590 padTLLatency[a - 1] = SekCyclesDone() + 25; // Cannon Fodder\r
591 }\r
592 if ((d^PicoMem.ioports[a]) & 0x40) {\r
593 // 1->0 transition starts the readout protocol\r
594 Pico.m.padTHPhase[a - 1] = !(d & 0x40);\r
595 }\r
596 } else if (!(PicoMem.ioports[a] & 0x40) && (d & 0x40))\r
597 Pico.m.padTHPhase[a - 1]++;\r
598 }\r
599\r
600 // after switching TH to input there's a latency before the pullup value is \r
601 // read back as input (see Decap Attack, not in Samurai Showdown, 32x WWF Raw)\r
602 if (4 <= a && a <= 5) {\r
603 if ((PicoMem.ioports[a] & 0x40) && !(d & 0x40) && !(PicoMem.ioports[a - 3] & 0x40))\r
604 // latency after switching to input and output was low\r
605 padTHLatency[a - 4] = SekCyclesDone() + 25;\r
606 }\r
607\r
608 // certain IO ports can be used as RAM\r
609 PicoMem.ioports[a] = d;\r
610}\r
611\r
612int io_ports_pack(void *buf, size_t size)\r
613{\r
614 size_t b, i;\r
615 memcpy(buf, PicoMem.ioports, (b = sizeof(PicoMem.ioports)));\r
616 for (i = 0; i < ARRAY_SIZE(Pico.m.padTHPhase); i++)\r
617 save_u8_(buf, &b, Pico.m.padTHPhase[i]);\r
618 for (i = 0; i < ARRAY_SIZE(Pico.m.padDelay); i++)\r
619 save_u8_(buf, &b, Pico.m.padDelay[i]);\r
620 for (i = 0; i < ARRAY_SIZE(padTHLatency); i++) {\r
621 save_s32(buf, &b, padTHLatency[i]);\r
622 save_s32(buf, &b, padTLLatency[i]);\r
623 }\r
624 for (i = 0; i < 4; i++)\r
625 save_u16(buf, &b, PicoIn.padInt[i]);\r
626 for (i = 0; i < 4; i++)\r
627 save_s32(buf, &b, PicoIn.mouseInt[i]);\r
628 assert(b <= size);\r
629 return b;\r
630}\r
631\r
632void io_ports_unpack(const void *buf, size_t size)\r
633{\r
634 size_t b, i;\r
635 memcpy(PicoMem.ioports, buf, (b = sizeof(PicoMem.ioports)));\r
636 for (i = 0; i < ARRAY_SIZE(Pico.m.padTHPhase); i++)\r
637 Pico.m.padTHPhase[i] = load_u8_(buf, &b);\r
638 for (i = 0; i < ARRAY_SIZE(Pico.m.padDelay); i++)\r
639 Pico.m.padDelay[i] = load_u8_(buf, &b);\r
640 for (i = 0; i < ARRAY_SIZE(padTHLatency); i++) {\r
641 padTHLatency[i] = load_s32(buf, &b);\r
642 padTLLatency[i] = load_s32(buf, &b);\r
643 }\r
644 for (i = 0; i < 4; i++)\r
645 PicoIn.padInt[i] = load_u16(buf, &b);\r
646 for (i = 0; i < 4; i++)\r
647 PicoIn.mouseInt[i] = load_s32(buf, &b);\r
648 assert(b <= size);\r
649}\r
650\r
651static int z80_cycles_from_68k(void)\r
652{\r
653 int m68k_cnt = SekCyclesDone() - Pico.t.m68c_frame_start;\r
654 return cycles_68k_to_z80(m68k_cnt);\r
655}\r
656\r
657void NOINLINE ctl_write_z80busreq(u32 d)\r
658{\r
659 d&=1; d^=1;\r
660 elprintf(EL_BUSREQ, "set_zrun: %i->%i [%u] @%06x", Pico.m.z80Run, d, SekCyclesDone(), SekPc);\r
661 if (d ^ Pico.m.z80Run)\r
662 {\r
663 if (d)\r
664 {\r
665 Pico.t.z80c_aim = Pico.t.z80c_cnt = z80_cycles_from_68k() + 2;\r
666 Pico.t.z80c_cnt += Pico.t.z80_busdelay >> 8;\r
667 Pico.t.z80_busdelay &= 0xff;\r
668 }\r
669 else\r
670 {\r
671 if ((PicoIn.opt & POPT_EN_Z80) && !Pico.m.z80_reset) {\r
672 // Z80 grants bus after the current M cycle, even within an insn\r
673 // simulate this by accumulating the last insn overhang in busdelay\r
674 unsigned granted;\r
675 pprof_start(m68k);\r
676 PicoSyncZ80(SekCyclesDone());\r
677 pprof_end_sub(m68k);\r
678 granted = Pico.t.z80c_aim + 6; // M cycle is 3-6 cycles \r
679 Pico.t.z80_busdelay += (Pico.t.z80c_cnt - granted) << 8;\r
680 Pico.t.z80c_cnt = granted;\r
681 }\r
682 }\r
683 Pico.m.z80Run = d;\r
684 }\r
685}\r
686\r
687void NOINLINE ctl_write_z80reset(u32 d)\r
688{\r
689 d&=1; d^=1;\r
690 elprintf(EL_BUSREQ, "set_zreset: %i->%i [%u] @%06x", Pico.m.z80_reset, d, SekCyclesDone(), SekPc);\r
691 if (d ^ Pico.m.z80_reset)\r
692 {\r
693 if (d)\r
694 {\r
695 if ((PicoIn.opt & POPT_EN_Z80) && Pico.m.z80Run) {\r
696 pprof_start(m68k);\r
697 PicoSyncZ80(SekCyclesDone());\r
698 pprof_end_sub(m68k);\r
699 }\r
700 Pico.t.z80_busdelay &= 0xff; // also resets bus request\r
701 YM2612ResetChip();\r
702 timers_reset();\r
703 }\r
704 else\r
705 {\r
706 Pico.t.z80c_aim = Pico.t.z80c_cnt = z80_cycles_from_68k() + 2;\r
707 z80_reset();\r
708 }\r
709 Pico.m.z80_reset = d;\r
710 }\r
711}\r
712\r
713static void psg_write_68k(u32 d)\r
714{\r
715 PsndDoPSG(z80_cycles_from_68k());\r
716 SN76496Write(d);\r
717}\r
718\r
719static void psg_write_z80(u32 d)\r
720{\r
721 PsndDoPSG(z80_cyclesDone());\r
722 SN76496Write(d);\r
723}\r
724\r
725// -----------------------------------------------------------------\r
726\r
727#ifndef _ASM_MEMORY_C\r
728\r
729// cart (save) RAM area (usually 0x200000 - ...)\r
730static u32 PicoRead8_sram(u32 a)\r
731{\r
732 u32 d;\r
733 if (Pico.sv.start <= a && a <= Pico.sv.end && (Pico.m.sram_reg & SRR_MAPPED))\r
734 {\r
735 if (Pico.sv.flags & SRF_EEPROM) {\r
736 d = EEPROM_read();\r
737 if (!(a & 1))\r
738 d >>= 8;\r
739 d &= 0xff;\r
740 } else\r
741 d = *(u8 *)(Pico.sv.data - Pico.sv.start + a);\r
742 elprintf(EL_SRAMIO, "sram r8 [%06x] %02x @ %06x", a, d, SekPc);\r
743 return d;\r
744 }\r
745\r
746 // XXX: this is banking unfriendly\r
747 if (a < Pico.romsize)\r
748 return Pico.rom[MEM_BE2(a)];\r
749 \r
750 return m68k_unmapped_read8(a);\r
751}\r
752\r
753static u32 PicoRead16_sram(u32 a)\r
754{\r
755 u32 d;\r
756 if (Pico.sv.start <= a && a <= Pico.sv.end && (Pico.m.sram_reg & SRR_MAPPED))\r
757 {\r
758 if (Pico.sv.flags & SRF_EEPROM)\r
759 d = EEPROM_read();\r
760 else {\r
761 u8 *pm = (u8 *)(Pico.sv.data - Pico.sv.start + a);\r
762 d = pm[0] << 8;\r
763 d |= pm[1];\r
764 }\r
765 elprintf(EL_SRAMIO, "sram r16 [%06x] %04x @ %06x", a, d, SekPc);\r
766 return d;\r
767 }\r
768\r
769 if (a < Pico.romsize)\r
770 return *(u16 *)(Pico.rom + a);\r
771\r
772 return m68k_unmapped_read16(a);\r
773}\r
774\r
775#endif // _ASM_MEMORY_C\r
776\r
777static void PicoWrite8_sram(u32 a, u32 d)\r
778{\r
779 if (a > Pico.sv.end || a < Pico.sv.start || !(Pico.m.sram_reg & SRR_MAPPED)) {\r
780 m68k_unmapped_write8(a, d);\r
781 return;\r
782 }\r
783\r
784 elprintf(EL_SRAMIO, "sram w8 [%06x] %02x @ %06x", a, d & 0xff, SekPc);\r
785 if (Pico.sv.flags & SRF_EEPROM)\r
786 {\r
787 EEPROM_write8(a, d);\r
788 }\r
789 else {\r
790 u8 *pm = (u8 *)(Pico.sv.data - Pico.sv.start + a);\r
791 if (*pm != (u8)d) {\r
792 Pico.sv.changed = 1;\r
793 *pm = (u8)d;\r
794 }\r
795 }\r
796}\r
797\r
798static void PicoWrite16_sram(u32 a, u32 d)\r
799{\r
800 if (a > Pico.sv.end || a < Pico.sv.start || !(Pico.m.sram_reg & SRR_MAPPED)) {\r
801 m68k_unmapped_write16(a, d);\r
802 return;\r
803 }\r
804\r
805 elprintf(EL_SRAMIO, "sram w16 [%06x] %04x @ %06x", a, d & 0xffff, SekPc);\r
806 if (Pico.sv.flags & SRF_EEPROM)\r
807 {\r
808 EEPROM_write16(d);\r
809 }\r
810 else {\r
811 u8 *pm = (u8 *)(Pico.sv.data - Pico.sv.start + a);\r
812 if (pm[0] != (u8)(d >> 8)) {\r
813 Pico.sv.changed = 1;\r
814 pm[0] = (u8)(d >> 8);\r
815 }\r
816 if (pm[1] != (u8)d) {\r
817 Pico.sv.changed = 1;\r
818 pm[1] = (u8)d;\r
819 }\r
820 }\r
821}\r
822\r
823// z80 area (0xa00000 - 0xa0ffff)\r
824// TODO: verify mirrors VDP and bank reg (bank area mirroring verified)\r
825static u32 PicoRead8_z80(u32 a)\r
826{\r
827 u32 d;\r
828 if ((Pico.m.z80Run | Pico.m.z80_reset | (z80_cycles_from_68k() < Pico.t.z80c_cnt)) &&\r
829 !(PicoIn.quirks & PQUIRK_NO_Z80_BUS_LOCK)) {\r
830 elprintf(EL_ANOMALY, "68k z80 read with no bus! [%06x] @ %06x", a, SekPc);\r
831 return (u8)PicoRead16_floating(a);\r
832 }\r
833 SekCyclesBurnRun(1);\r
834\r
835 if ((a & 0x4000) == 0x0000) {\r
836 d = PicoMem.zram[a & 0x1fff];\r
837 } else if ((a & 0x6000) == 0x4000) // 0x4000-0x5fff\r
838 d = ym2612_read_local_68k(); \r
839 else {\r
840 elprintf(EL_UIO|EL_ANOMALY, "68k bad read [%06x] @%06x", a, SekPc);\r
841 d = (u8)PicoRead16_floating(a);\r
842 }\r
843 return d;\r
844}\r
845\r
846static u32 PicoRead16_z80(u32 a)\r
847{\r
848 u32 d = PicoRead8_z80(a);\r
849 return d | (d << 8);\r
850}\r
851\r
852static void PicoWrite8_z80(u32 a, u32 d)\r
853{\r
854 if ((Pico.m.z80Run | Pico.m.z80_reset) && !(PicoIn.quirks & PQUIRK_NO_Z80_BUS_LOCK)) {\r
855 // verified on real hw\r
856 elprintf(EL_ANOMALY, "68k z80 write with no bus or reset! [%06x] %02x @ %06x", a, d&0xff, SekPc);\r
857 return;\r
858 }\r
859 SekCyclesBurnRun(1);\r
860\r
861 if ((a & 0x4000) == 0x0000) { // z80 RAM\r
862 PicoMem.zram[a & 0x1fff] = (u8)d;\r
863 return;\r
864 }\r
865 if ((a & 0x6000) == 0x4000) { // FM Sound\r
866 if (PicoIn.opt & POPT_EN_FM)\r
867 ym2612_write_local(a & 3, d & 0xff, 0);\r
868 return;\r
869 }\r
870 // TODO: probably other VDP access too? Maybe more mirrors?\r
871 if ((a & 0x7ff9) == 0x7f11) { // PSG Sound\r
872 psg_write_68k(d);\r
873 return;\r
874 }\r
875 if ((a & 0x7f00) == 0x6000) // Z80 BANK register\r
876 {\r
877 Pico.m.z80_bank68k >>= 1;\r
878 Pico.m.z80_bank68k |= d << 8;\r
879 Pico.m.z80_bank68k &= 0x1ff; // 9 bits and filled in the new top one\r
880 elprintf(EL_Z80BNK, "z80 bank=%06x", Pico.m.z80_bank68k << 15);\r
881 return;\r
882 }\r
883 elprintf(EL_UIO|EL_ANOMALY, "68k bad write [%06x] %02x @ %06x", a, d&0xff, SekPc);\r
884}\r
885\r
886static void PicoWrite16_z80(u32 a, u32 d)\r
887{\r
888 // for RAM, only most significant byte is sent\r
889 // TODO: verify remaining accesses\r
890 PicoWrite8_z80(a, d >> 8);\r
891}\r
892\r
893#ifndef _ASM_MEMORY_C\r
894\r
895// IO/control area (0xa10000 - 0xa1ffff)\r
896u32 PicoRead8_io(u32 a)\r
897{\r
898 u32 d;\r
899\r
900 if ((a & 0xffe0) == 0x0000) { // I/O ports\r
901 d = io_ports_read(a);\r
902 goto end;\r
903 }\r
904\r
905 if ((a & 0xfc00) == 0x1000) {\r
906 d = (u8)PicoRead16_floating(a);\r
907\r
908 if ((a & 0xff01) == 0x1100) { // z80 busreq (verified)\r
909 // bit8 seems to be readable in this range\r
910 if (!(a & 1)) {\r
911 d &= ~0x01;\r
912 // Z80 ahead of 68K only if in BUSREQ, BUSACK only after 68K reached Z80\r
913 d |= (z80_cycles_from_68k() < Pico.t.z80c_cnt);\r
914 d |= (Pico.m.z80Run | Pico.m.z80_reset) & 1;\r
915 elprintf(EL_BUSREQ, "get_zrun: %02x [%u] @%06x", d, SekCyclesDone(), SekPc);\r
916 }\r
917 }\r
918 goto end;\r
919 }\r
920\r
921 d = PicoRead8_32x(a);\r
922\r
923end:\r
924 return d;\r
925}\r
926\r
927u32 PicoRead16_io(u32 a)\r
928{\r
929 u32 d;\r
930\r
931 if ((a & 0xffe0) == 0x0000) { // I/O ports\r
932 d = io_ports_read(a);\r
933 d |= d << 8;\r
934 goto end;\r
935 }\r
936\r
937 // bit8 seems to be readable in this range\r
938 if ((a & 0xfc00) == 0x1000) {\r
939 d = PicoRead16_floating(a);\r
940\r
941 if ((a & 0xff00) == 0x1100) { // z80 busreq\r
942 d &= ~0x0100;\r
943 d |= (z80_cycles_from_68k() < Pico.t.z80c_cnt) << 8;\r
944 d |= ((Pico.m.z80Run | Pico.m.z80_reset) & 1) << 8;\r
945 elprintf(EL_BUSREQ, "get_zrun: %04x [%u] @%06x", d, SekCyclesDone(), SekPc);\r
946 }\r
947 goto end;\r
948 }\r
949\r
950 d = PicoRead16_32x(a);\r
951\r
952end:\r
953 return d;\r
954}\r
955\r
956void PicoWrite8_io(u32 a, u32 d)\r
957{\r
958 if ((a & 0xffe1) == 0x0001) { // I/O ports (verified: only LSB!)\r
959 io_ports_write(a, d);\r
960 return;\r
961 }\r
962 if ((a & 0xff01) == 0x1100) { // z80 busreq\r
963 ctl_write_z80busreq(d);\r
964 return;\r
965 }\r
966 if ((a & 0xff01) == 0x1200) { // z80 reset\r
967 ctl_write_z80reset(d);\r
968 return;\r
969 }\r
970 if (a == 0xa130f1) { // sram access register\r
971 elprintf(EL_SRAMIO, "sram reg=%02x", d);\r
972 Pico.m.sram_reg &= ~(SRR_MAPPED|SRR_READONLY);\r
973 Pico.m.sram_reg |= (u8)(d & 3);\r
974 return;\r
975 }\r
976 PicoWrite8_32x(a, d);\r
977}\r
978\r
979void PicoWrite16_io(u32 a, u32 d)\r
980{\r
981 if ((a & 0xffe0) == 0x0000) { // I/O ports (verified: only LSB!)\r
982 io_ports_write(a, d);\r
983 return;\r
984 }\r
985 if ((a & 0xff00) == 0x1100) { // z80 busreq\r
986 ctl_write_z80busreq(d >> 8);\r
987 return;\r
988 }\r
989 if ((a & 0xff00) == 0x1200) { // z80 reset\r
990 ctl_write_z80reset(d >> 8);\r
991 return;\r
992 }\r
993 if (a == 0xa130f0) { // sram access register\r
994 elprintf(EL_SRAMIO, "sram reg=%02x", d);\r
995 Pico.m.sram_reg &= ~(SRR_MAPPED|SRR_READONLY);\r
996 Pico.m.sram_reg |= (u8)(d & 3);\r
997 return;\r
998 }\r
999 PicoWrite16_32x(a, d);\r
1000}\r
1001\r
1002#endif // _ASM_MEMORY_C\r
1003\r
1004// VDP area (0xc00000 - 0xdfffff)\r
1005// TODO: verify if lower byte goes to PSG on word writes\r
1006u32 PicoRead8_vdp(u32 a)\r
1007{\r
1008 u32 d;\r
1009 if ((a & 0x00f0) == 0x0000) {\r
1010 switch (a & 0x0d)\r
1011 {\r
1012 case 0x00: d = PicoVideoRead8DataH(0); break;\r
1013 case 0x01: d = PicoVideoRead8DataL(0); break;\r
1014 case 0x04: d = PicoVideoRead8CtlH(0); break;\r
1015 case 0x05: d = PicoVideoRead8CtlL(0); break;\r
1016 case 0x08:\r
1017 case 0x0c: d = PicoVideoRead8HV_H(0); break;\r
1018 case 0x09:\r
1019 case 0x0d: d = PicoVideoRead8HV_L(0); break;\r
1020 default: d = (u8)PicoRead16_floating(a); break;\r
1021 }\r
1022 } else {\r
1023 elprintf(EL_UIO|EL_ANOMALY, "68k bad read [%06x] @%06x", a, SekPc);\r
1024 d = (u8)PicoRead16_floating(a);\r
1025 }\r
1026 return d;\r
1027}\r
1028\r
1029static u32 PicoRead16_vdp(u32 a)\r
1030{\r
1031 if ((a & 0x00e0) == 0x0000)\r
1032 return PicoVideoRead(a);\r
1033\r
1034 elprintf(EL_UIO|EL_ANOMALY, "68k bad read [%06x] @%06x", a, SekPc);\r
1035 return 0;\r
1036}\r
1037\r
1038static void PicoWrite8_vdp(u32 a, u32 d)\r
1039{\r
1040 if ((a & 0x00f9) == 0x0011) { // PSG Sound\r
1041 psg_write_68k(d);\r
1042 return;\r
1043 }\r
1044 if ((a & 0x00e0) == 0x0000) {\r
1045 d &= 0xff;\r
1046 PicoVideoWrite(a, d | (d << 8));\r
1047 return;\r
1048 }\r
1049\r
1050 elprintf(EL_UIO|EL_ANOMALY, "68k bad write [%06x] %02x @%06x", a, d & 0xff, SekPc);\r
1051}\r
1052\r
1053static void PicoWrite16_vdp(u32 a, u32 d)\r
1054{\r
1055 if ((a & 0x00f9) == 0x0010) { // PSG Sound\r
1056 psg_write_68k(d);\r
1057 return;\r
1058 }\r
1059 if ((a & 0x00e0) == 0x0000) {\r
1060 PicoVideoWrite(a, d);\r
1061 return;\r
1062 }\r
1063\r
1064 elprintf(EL_UIO|EL_ANOMALY, "68k bad write [%06x] %04x @%06x", a, d & 0xffff, SekPc);\r
1065}\r
1066\r
1067// -----------------------------------------------------------------\r
1068\r
1069#ifdef EMU_M68K\r
1070static void m68k_mem_setup(void);\r
1071#endif\r
1072\r
1073PICO_INTERNAL void PicoMemSetup(void)\r
1074{\r
1075 int mask, rs, sstart, a;\r
1076\r
1077 // setup the memory map\r
1078 cpu68k_map_set(m68k_read8_map, 0x000000, 0xffffff, m68k_unmapped_read8, 1);\r
1079 cpu68k_map_set(m68k_read16_map, 0x000000, 0xffffff, m68k_unmapped_read16, 1);\r
1080 cpu68k_map_set(m68k_write8_map, 0x000000, 0xffffff, m68k_unmapped_write8, 1);\r
1081 cpu68k_map_set(m68k_write16_map, 0x000000, 0xffffff, m68k_unmapped_write16, 1);\r
1082\r
1083 // ROM\r
1084 // align to bank size. We know ROM loader allocated enough for this\r
1085 mask = (1 << M68K_MEM_SHIFT) - 1;\r
1086 rs = (Pico.romsize + mask) & ~mask;\r
1087 if (rs > 0xa00000) rs = 0xa00000; // max cartridge area\r
1088 if (rs) {\r
1089 cpu68k_map_set(m68k_read8_map, 0x000000, rs - 1, Pico.rom, 0);\r
1090 cpu68k_map_set(m68k_read16_map, 0x000000, rs - 1, Pico.rom, 0);\r
1091 }\r
1092\r
1093 // Common case of on-cart (save) RAM, usually at 0x200000-...\r
1094 if ((Pico.sv.flags & SRF_ENABLED) && Pico.sv.data != NULL) {\r
1095 sstart = Pico.sv.start & ~mask;\r
1096 rs = Pico.sv.end - sstart;\r
1097 rs = (rs + mask) & ~mask;\r
1098 if (sstart + rs >= 0x1000000)\r
1099 rs = 0x1000000 - sstart;\r
1100 cpu68k_map_set(m68k_read8_map, sstart, sstart + rs - 1, PicoRead8_sram, 1);\r
1101 cpu68k_map_set(m68k_read16_map, sstart, sstart + rs - 1, PicoRead16_sram, 1);\r
1102 cpu68k_map_set(m68k_write8_map, sstart, sstart + rs - 1, PicoWrite8_sram, 1);\r
1103 cpu68k_map_set(m68k_write16_map, sstart, sstart + rs - 1, PicoWrite16_sram, 1);\r
1104 }\r
1105\r
1106 // Z80 region\r
1107 cpu68k_map_set(m68k_read8_map, 0xa00000, 0xa0ffff, PicoRead8_z80, 1);\r
1108 cpu68k_map_set(m68k_read16_map, 0xa00000, 0xa0ffff, PicoRead16_z80, 1);\r
1109 cpu68k_map_set(m68k_write8_map, 0xa00000, 0xa0ffff, PicoWrite8_z80, 1);\r
1110 cpu68k_map_set(m68k_write16_map, 0xa00000, 0xa0ffff, PicoWrite16_z80, 1);\r
1111\r
1112 // IO/control region\r
1113 cpu68k_map_set(m68k_read8_map, 0xa10000, 0xa1ffff, PicoRead8_io, 1);\r
1114 cpu68k_map_set(m68k_read16_map, 0xa10000, 0xa1ffff, PicoRead16_io, 1);\r
1115 cpu68k_map_set(m68k_write8_map, 0xa10000, 0xa1ffff, PicoWrite8_io, 1);\r
1116 cpu68k_map_set(m68k_write16_map, 0xa10000, 0xa1ffff, PicoWrite16_io, 1);\r
1117\r
1118 // VDP region\r
1119 for (a = 0xc00000; a < 0xe00000; a += 0x010000) {\r
1120 if ((a & 0xe700e0) != 0xc00000)\r
1121 continue;\r
1122 cpu68k_map_set(m68k_read8_map, a, a + 0xffff, PicoRead8_vdp, 1);\r
1123 cpu68k_map_set(m68k_read16_map, a, a + 0xffff, PicoRead16_vdp, 1);\r
1124 cpu68k_map_set(m68k_write8_map, a, a + 0xffff, PicoWrite8_vdp, 1);\r
1125 cpu68k_map_set(m68k_write16_map, a, a + 0xffff, PicoWrite16_vdp, 1);\r
1126 }\r
1127\r
1128 // RAM and it's mirrors\r
1129 for (a = 0xe00000; a < 0x1000000; a += 0x010000) {\r
1130 cpu68k_map_set(m68k_read8_map, a, a + 0xffff, PicoMem.ram, 0);\r
1131 cpu68k_map_set(m68k_read16_map, a, a + 0xffff, PicoMem.ram, 0);\r
1132 cpu68k_map_set(m68k_write8_map, a, a + 0xffff, PicoMem.ram, 0);\r
1133 cpu68k_map_set(m68k_write16_map, a, a + 0xffff, PicoMem.ram, 0);\r
1134 }\r
1135\r
1136 // Setup memory callbacks:\r
1137#ifdef EMU_C68K\r
1138 PicoCpuCM68k.read8 = (void *)m68k_read8_map;\r
1139 PicoCpuCM68k.read16 = (void *)m68k_read16_map;\r
1140 PicoCpuCM68k.read32 = (void *)m68k_read16_map;\r
1141 PicoCpuCM68k.write8 = (void *)m68k_write8_map;\r
1142 PicoCpuCM68k.write16 = (void *)m68k_write16_map;\r
1143 PicoCpuCM68k.write32 = (void *)m68k_write16_map;\r
1144 PicoCpuCM68k.checkpc = NULL; /* unused */\r
1145 PicoCpuCM68k.fetch8 = NULL;\r
1146 PicoCpuCM68k.fetch16 = NULL;\r
1147 PicoCpuCM68k.fetch32 = NULL;\r
1148#endif\r
1149#ifdef EMU_F68K\r
1150 PicoCpuFM68k.read_byte = (void *)m68k_read8;\r
1151 PicoCpuFM68k.read_word = (void *)m68k_read16;\r
1152 PicoCpuFM68k.read_long = (void *)m68k_read32;\r
1153 PicoCpuFM68k.write_byte = (void *)m68k_write8;\r
1154 PicoCpuFM68k.write_word = (void *)m68k_write16;\r
1155 PicoCpuFM68k.write_long = (void *)m68k_write32;\r
1156#endif\r
1157#ifdef EMU_M68K\r
1158 m68k_mem_setup();\r
1159#endif\r
1160\r
1161 z80_mem_setup();\r
1162}\r
1163\r
1164#ifdef EMU_M68K\r
1165unsigned int (*pm68k_read_memory_8) (unsigned int address) = NULL;\r
1166unsigned int (*pm68k_read_memory_16)(unsigned int address) = NULL;\r
1167unsigned int (*pm68k_read_memory_32)(unsigned int address) = NULL;\r
1168void (*pm68k_write_memory_8) (unsigned int address, unsigned char value) = NULL;\r
1169void (*pm68k_write_memory_16)(unsigned int address, unsigned short value) = NULL;\r
1170void (*pm68k_write_memory_32)(unsigned int address, unsigned int value) = NULL;\r
1171\r
1172/* it appears that Musashi doesn't always mask the unused bits */\r
1173unsigned int m68k_read_memory_8 (unsigned int address) { return pm68k_read_memory_8 (address) & 0xff; }\r
1174unsigned int m68k_read_memory_16(unsigned int address) { return pm68k_read_memory_16(address) & 0xffff; }\r
1175unsigned int m68k_read_memory_32(unsigned int address) { return pm68k_read_memory_32(address); }\r
1176void m68k_write_memory_8 (unsigned int address, unsigned int value) { pm68k_write_memory_8 (address, (u8)value); }\r
1177void m68k_write_memory_16(unsigned int address, unsigned int value) { pm68k_write_memory_16(address,(u16)value); }\r
1178void m68k_write_memory_32(unsigned int address, unsigned int value) { pm68k_write_memory_32(address, value); }\r
1179\r
1180static void m68k_mem_setup(void)\r
1181{\r
1182 pm68k_read_memory_8 = m68k_read8;\r
1183 pm68k_read_memory_16 = m68k_read16;\r
1184 pm68k_read_memory_32 = m68k_read32;\r
1185 pm68k_write_memory_8 = m68k_write8;\r
1186 pm68k_write_memory_16 = m68k_write16;\r
1187 pm68k_write_memory_32 = m68k_write32;\r
1188}\r
1189#endif // EMU_M68K\r
1190\r
1191\r
1192// -----------------------------------------------------------------\r
1193\r
1194static int get_scanline(int is_from_z80)\r
1195{\r
1196 if (is_from_z80) {\r
1197 // ugh... compute by dividing cycles since frame start by cycles per line\r
1198 // need some fractional resolution here, else there may be an extra line\r
1199 int cycles_line = cycles_68k_to_z80((unsigned)(488.5*256))+1; // cycles per line, Q8\r
1200 int cycles_z80 = (z80_cyclesLeft<0 ? Pico.t.z80c_aim:z80_cyclesDone())<<8;\r
1201 int cycles = cycles_line * Pico.t.z80_scanline;\r
1202 // approximation by multiplying with inverse\r
1203 if (cycles_z80 - cycles >= 4*cycles_line) {\r
1204 // compute 1/cycles_line, storing the result to avoid future dividing\r
1205 static int cycles_line_o, cycles_line_i;\r
1206 if (cycles_line_o != cycles_line)\r
1207 { cycles_line_o = cycles_line, cycles_line_i = (1<<22) / cycles_line; }\r
1208 // compute lines = diff/cycles_line = diff*(1/cycles_line)\r
1209 int lines = ((cycles_z80 - cycles) * cycles_line_i) >> 22;\r
1210 Pico.t.z80_scanline += lines, cycles += cycles_line * lines;\r
1211 }\r
1212 // handle any rounding leftover\r
1213 while (cycles_z80 - cycles >= cycles_line)\r
1214 Pico.t.z80_scanline ++, cycles += cycles_line;\r
1215 return Pico.t.z80_scanline;\r
1216 }\r
1217\r
1218 return Pico.m.scanline;\r
1219}\r
1220\r
1221#define ym2612_update_status(xcycles) \\r
1222 ym2612.OPN.ST.status &= ~0x80; \\r
1223 ym2612.OPN.ST.status |= (xcycles < Pico.t.ym2612_busy) * 0x80; \\r
1224 if (xcycles >= Pico.t.timer_a_next_oflow) \\r
1225 ym2612.OPN.ST.status |= (ym2612.OPN.ST.mode >> 2) & 1; \\r
1226 if (xcycles >= Pico.t.timer_b_next_oflow) \\r
1227 ym2612.OPN.ST.status |= (ym2612.OPN.ST.mode >> 2) & 2\r
1228\r
1229/* probably should not be in this file, but it's near related code here */\r
1230void ym2612_sync_timers(int z80_cycles, int mode_old, int mode_new)\r
1231{\r
1232 int xcycles = z80_cycles << 8;\r
1233\r
1234 // update timer status\r
1235 ym2612_update_status(xcycles);\r
1236\r
1237 // update timer a\r
1238 if (mode_old & 1)\r
1239 while (xcycles >= Pico.t.timer_a_next_oflow)\r
1240 Pico.t.timer_a_next_oflow += Pico.t.timer_a_step;\r
1241\r
1242 // turning on/off\r
1243 if ((mode_old ^ mode_new) & 1)\r
1244 {\r
1245 if (mode_old & 1)\r
1246 Pico.t.timer_a_next_oflow = TIMER_NO_OFLOW;\r
1247 else {\r
1248 /* The internal tick of the YM2612 takes 144 clock cycles (with clock\r
1249 * being OSC/7), or 67.2 z80 cycles. Timers are run once each tick.\r
1250 * Starting a timer takes place at the next tick, so xcycles needs to be\r
1251 * rounded up to that: t = next tick# = (xcycles / TICK_ZCYCLES) + 1\r
1252 */\r
1253 unsigned t = ((xcycles * (((1LL<<32)/TIMER_A_TICK_ZCYCLES)+1))>>32) + 1;\r
1254 Pico.t.timer_a_next_oflow = t*TIMER_A_TICK_ZCYCLES + Pico.t.timer_a_step;\r
1255 }\r
1256 }\r
1257\r
1258 if (mode_new & 1)\r
1259 elprintf(EL_YMTIMER, "timer a upd to %i @ %i", Pico.t.timer_a_next_oflow>>8, z80_cycles);\r
1260\r
1261 // update timer b\r
1262 if (mode_old & 2)\r
1263 while (xcycles >= Pico.t.timer_b_next_oflow)\r
1264 Pico.t.timer_b_next_oflow += Pico.t.timer_b_step;\r
1265\r
1266 // turning on/off\r
1267 if ((mode_old ^ mode_new) & 2)\r
1268 {\r
1269 if (mode_old & 2)\r
1270 Pico.t.timer_b_next_oflow = TIMER_NO_OFLOW;\r
1271 else {\r
1272 /* timer b has a divider of 16 which runs in its own counter. It is not\r
1273 * reset by loading timer b. The first run of timer b after loading is\r
1274 * therefore shorter by up to 15 ticks.\r
1275 */\r
1276 unsigned t = ((xcycles * (((1LL<<32)/TIMER_A_TICK_ZCYCLES)+1))>>32) + 1;\r
1277 int step = Pico.t.timer_b_step - TIMER_A_TICK_ZCYCLES*(t&15);\r
1278 Pico.t.timer_b_next_oflow = t*TIMER_A_TICK_ZCYCLES + step;\r
1279 }\r
1280 }\r
1281\r
1282 if (mode_new & 2)\r
1283 elprintf(EL_YMTIMER, "timer b upd to %i @ %i", Pico.t.timer_b_next_oflow>>8, z80_cycles);\r
1284}\r
1285\r
1286// ym2612 DAC and timer I/O handlers for z80\r
1287static int ym2612_write_local(u32 a, u32 d, int is_from_z80)\r
1288{\r
1289 int cycles = is_from_z80 ? z80_cyclesDone() : z80_cycles_from_68k();\r
1290 int addr;\r
1291\r
1292 a &= 3;\r
1293 switch (a)\r
1294 {\r
1295 case 0: /* address port 0 */\r
1296 case 2: /* address port 1 */\r
1297 ym2612.OPN.ST.address = d;\r
1298 ym2612.addr_A1 = (a & 2) >> 1;\r
1299#ifdef __GP2X__\r
1300 if (PicoIn.opt & POPT_EXT_FM) YM2612Write_940(a, d, -1);\r
1301#endif\r
1302 return 0;\r
1303\r
1304 case 1: /* data port 0 */\r
1305 case 3: /* data port 1 */\r
1306 addr = ym2612.OPN.ST.address | ((int)ym2612.addr_A1 << 8);\r
1307 ym2612.REGS[addr] = d;\r
1308\r
1309 // the busy flag in the YM2612 status is actually a 32 cycle timer\r
1310 // (89.6 Z80 cycles), triggered by any write to the data port.\r
1311 Pico.t.ym2612_busy = (cycles << 8) + YMBUSY_ZCYCLES; // Q8 for convenience\r
1312\r
1313 switch (addr)\r
1314 {\r
1315 case 0x24: // timer A High 8\r
1316 case 0x25: { // timer A Low 2\r
1317 int TAnew = (addr == 0x24) ? ((ym2612.OPN.ST.TA & 0x03)|(((int)d)<<2))\r
1318 : ((ym2612.OPN.ST.TA & 0x3fc)|(d&3));\r
1319 if (ym2612.OPN.ST.TA != TAnew)\r
1320 {\r
1321 ym2612_sync_timers(cycles, ym2612.OPN.ST.mode, ym2612.OPN.ST.mode);\r
1322 //elprintf(EL_STATUS, "timer a set %i", TAnew);\r
1323 ym2612.OPN.ST.TA = TAnew;\r
1324 //ym2612.OPN.ST.TAC = (1024-TAnew)*18;\r
1325 //ym2612.OPN.ST.TAT = 0;\r
1326 Pico.t.timer_a_step = TIMER_A_TICK_ZCYCLES * (1024 - TAnew);\r
1327 elprintf(EL_YMTIMER, "timer a set to %i, %i", 1024 - TAnew, Pico.t.timer_a_next_oflow>>8);\r
1328 }\r
1329 return 0;\r
1330 }\r
1331 case 0x26: // timer B\r
1332 if (ym2612.OPN.ST.TB != d) {\r
1333 ym2612_sync_timers(cycles, ym2612.OPN.ST.mode, ym2612.OPN.ST.mode);\r
1334 //elprintf(EL_STATUS, "timer b set %i", d);\r
1335 ym2612.OPN.ST.TB = d;\r
1336 //ym2612.OPN.ST.TBC = (256-d) * 288;\r
1337 //ym2612.OPN.ST.TBT = 0;\r
1338 Pico.t.timer_b_step = TIMER_B_TICK_ZCYCLES * (256 - d);\r
1339 elprintf(EL_YMTIMER, "timer b set to %i, %i", 256 - d, Pico.t.timer_b_next_oflow>>8);\r
1340 }\r
1341 return 0;\r
1342 case 0x27: { /* mode, timer control */\r
1343 int old_mode = ym2612.OPN.ST.mode;\r
1344\r
1345 elprintf(EL_YMTIMER, "st mode %02x", d);\r
1346 ym2612_sync_timers(cycles, old_mode, d);\r
1347\r
1348 ym2612.OPN.ST.mode = d;\r
1349\r
1350 /* reset Timer a flag */\r
1351 if (d & 0x10)\r
1352 ym2612.OPN.ST.status &= ~1;\r
1353\r
1354 /* reset Timer b flag */\r
1355 if (d & 0x20)\r
1356 ym2612.OPN.ST.status &= ~2;\r
1357\r
1358 if ((d ^ old_mode) & 0xc0) {\r
1359#ifdef __GP2X__\r
1360 if (PicoIn.opt & POPT_EXT_FM) return YM2612Write_940(a, d, get_scanline(is_from_z80));\r
1361#endif\r
1362 PsndDoFM(cycles);\r
1363 return 1;\r
1364 }\r
1365 return 0;\r
1366 }\r
1367 case 0x2a: { /* DAC data */\r
1368 //elprintf(EL_STATUS, "%03i dac w %08x z80 %i", cycles, d, is_from_z80);\r
1369 if (ym2612.dacen)\r
1370 PsndDoDAC(cycles);\r
1371 ym2612.dacout = ((int)d - 0x80) << DAC_SHIFT;\r
1372 return 0;\r
1373 }\r
1374 case 0x2b: { /* DAC Sel (YM2612) */\r
1375 ym2612.dacen = d & 0x80;\r
1376#ifdef __GP2X__\r
1377 if (PicoIn.opt & POPT_EXT_FM) YM2612Write_940(a, d, get_scanline(is_from_z80));\r
1378#endif\r
1379 return 0;\r
1380 }\r
1381 }\r
1382 break;\r
1383 }\r
1384\r
1385#ifdef __GP2X__\r
1386 if (PicoIn.opt & POPT_EXT_FM)\r
1387 return YM2612Write_940(a, d, get_scanline(is_from_z80));\r
1388#endif\r
1389 PsndDoFM(cycles);\r
1390 return YM2612Write_(a, d);\r
1391}\r
1392\r
1393\r
1394static u32 ym2612_read_local_z80(void)\r
1395{\r
1396 int xcycles = z80_cyclesDone() << 8;\r
1397\r
1398 ym2612_update_status(xcycles);\r
1399\r
1400 elprintf(EL_YMTIMER, "timer z80 read %i, sched %i, %i @ %i|%i",\r
1401 ym2612.OPN.ST.status, Pico.t.timer_a_next_oflow >> 8,\r
1402 Pico.t.timer_b_next_oflow >> 8, xcycles >> 8, (xcycles >> 8) / 228);\r
1403 return ym2612.OPN.ST.status;\r
1404}\r
1405\r
1406static u32 ym2612_read_local_68k(void)\r
1407{\r
1408 int xcycles = z80_cycles_from_68k() << 8;\r
1409\r
1410 ym2612_update_status(xcycles);\r
1411\r
1412 elprintf(EL_YMTIMER, "timer 68k read %i, sched %i, %i @ %i|%i",\r
1413 ym2612.OPN.ST.status, Pico.t.timer_a_next_oflow >> 8,\r
1414 Pico.t.timer_b_next_oflow >> 8, xcycles >> 8, (xcycles >> 8) / 228);\r
1415 return ym2612.OPN.ST.status;\r
1416}\r
1417\r
1418// legacy code, only used for GP2X\r
1419void ym2612_pack_state_old(void)\r
1420{\r
1421 // timers are saved as tick counts, in 16.16 int format\r
1422 int tat = 0, tbt = 0, busy = 0;\r
1423 u8 buf[16];\r
1424 size_t b = 0;\r
1425\r
1426 ym2612_pack_timers(buf, sizeof(buf));\r
1427 load_u16(buf, &b), load_u16(buf, &b);\r
1428 tat = load_u32(buf, &b);\r
1429 tbt = load_u32(buf, &b);\r
1430 busy = load_u32(buf, &b);\r
1431\r
1432#ifdef __GP2X__\r
1433 if (PicoIn.opt & POPT_EXT_FM)\r
1434 YM2612PicoStateSave2_940(tat, tbt);\r
1435 else\r
1436#endif\r
1437 YM2612PicoStateSave2(tat, tbt, busy);\r
1438}\r
1439\r
1440int ym2612_pack_timers(void *buf, size_t size)\r
1441{\r
1442 // timers are saved as tick counts, in 16.16 int format\r
1443 int tac, tat = 0, tbc, tbt = 0, busy = 0;\r
1444 size_t b = 0;\r
1445\r
1446 tac = 1024 - ym2612.OPN.ST.TA;\r
1447 tbc = 256 - ym2612.OPN.ST.TB;\r
1448 if (Pico.t.ym2612_busy > 0)\r
1449 busy = cycles_z80_to_68k(Pico.t.ym2612_busy);\r
1450 if (Pico.t.timer_a_next_oflow != TIMER_NO_OFLOW)\r
1451 tat = ((Pico.t.timer_a_step - Pico.t.timer_a_next_oflow) * ((1LL<<32)/TIMER_A_TICK_ZCYCLES+1))>>16;\r
1452 if (Pico.t.timer_b_next_oflow != TIMER_NO_OFLOW)\r
1453 tbt = ((Pico.t.timer_b_step - Pico.t.timer_b_next_oflow) * ((1LL<<32)/TIMER_B_TICK_ZCYCLES+1))>>16;\r
1454 elprintf(EL_YMTIMER, "save: timer a %i/%i", tat >> 16, tac);\r
1455 elprintf(EL_YMTIMER, "save: timer b %i/%i", tbt >> 16, tbc);\r
1456\r
1457 assert(size >= 16);\r
1458 save_u16(buf, &b, ym2612.OPN.ST.TA);\r
1459 save_u16(buf, &b, ym2612.OPN.ST.TB);\r
1460 save_u32(buf, &b, tat);\r
1461 save_u32(buf, &b, tbt);\r
1462 save_u32(buf, &b, busy);\r
1463 return b;\r
1464}\r
1465\r
1466// legacy code, only used for GP2X\r
1467void ym2612_unpack_state_old(void)\r
1468{\r
1469 int i, ret, tat, tbt, busy = 0;\r
1470 YM2612PicoStateLoad();\r
1471 Pico.t.m68c_frame_start = SekCyclesDone();\r
1472\r
1473 // feed all the registers and update internal state\r
1474 for (i = 0x20; i < 0xA0; i++) {\r
1475 ym2612_write_local(0, i, 0);\r
1476 ym2612_write_local(1, ym2612.REGS[i], 0);\r
1477 }\r
1478 for (i = 0x30; i < 0xA0; i++) {\r
1479 ym2612_write_local(2, i, 0);\r
1480 ym2612_write_local(3, ym2612.REGS[i|0x100], 0);\r
1481 }\r
1482 for (i = 0xAF; i >= 0xA0; i--) { // must apply backwards\r
1483 ym2612_write_local(2, i, 0);\r
1484 ym2612_write_local(3, ym2612.REGS[i|0x100], 0);\r
1485 ym2612_write_local(0, i, 0);\r
1486 ym2612_write_local(1, ym2612.REGS[i], 0);\r
1487 }\r
1488 for (i = 0xB0; i < 0xB8; i++) {\r
1489 ym2612_write_local(0, i, 0);\r
1490 ym2612_write_local(1, ym2612.REGS[i], 0);\r
1491 ym2612_write_local(2, i, 0);\r
1492 ym2612_write_local(3, ym2612.REGS[i|0x100], 0);\r
1493 }\r
1494\r
1495#ifdef __GP2X__\r
1496 if (PicoIn.opt & POPT_EXT_FM)\r
1497 ret = YM2612PicoStateLoad2_940(&tat, &tbt);\r
1498 else\r
1499#endif\r
1500 ret = YM2612PicoStateLoad2(&tat, &tbt, &busy);\r
1501 if (ret != 0) {\r
1502 elprintf(EL_STATUS, "old ym2612 state");\r
1503 return; // no saved timers\r
1504 }\r
1505 {\r
1506 u8 tmp[16];\r
1507 size_t b = 0;\r
1508 save_u16(tmp, &b, ym2612.OPN.ST.TA);\r
1509 save_u16(tmp, &b, ym2612.OPN.ST.TB);\r
1510 save_u32(tmp, &b, tat);\r
1511 save_u32(tmp, &b, tbt);\r
1512 save_u32(tmp, &b, busy);\r
1513 ym2612_unpack_timers(tmp, b);\r
1514 }\r
1515}\r
1516\r
1517void ym2612_unpack_timers(const void *buf, size_t size)\r
1518{\r
1519 int tac, tat, tbc, tbt, busy;\r
1520 size_t b = 0;\r
1521 assert(size >= 16);\r
1522 if (size < 16)\r
1523 return;\r
1524 ym2612.OPN.ST.TA = load_u16(buf, &b);\r
1525 ym2612.OPN.ST.TB = load_u16(buf, &b);\r
1526 tat = load_u32(buf, &b);\r
1527 tbt = load_u32(buf, &b);\r
1528 busy = load_u32(buf, &b);\r
1529 Pico.t.ym2612_busy = cycles_68k_to_z80(busy);\r
1530 tac = (1024 - ym2612.OPN.ST.TA) << 16;\r
1531 tbc = (256 - ym2612.OPN.ST.TB) << 16;\r
1532 if (ym2612.OPN.ST.mode & 1)\r
1533 Pico.t.timer_a_next_oflow = (1LL * (tac-tat) * TIMER_A_TICK_ZCYCLES)>>16;\r
1534 else\r
1535 Pico.t.timer_a_next_oflow = TIMER_NO_OFLOW;\r
1536 if (ym2612.OPN.ST.mode & 2)\r
1537 Pico.t.timer_b_next_oflow = (1LL * (tbc-tbt) * TIMER_B_TICK_ZCYCLES)>>16;\r
1538 else\r
1539 Pico.t.timer_b_next_oflow = TIMER_NO_OFLOW;\r
1540 elprintf(EL_YMTIMER, "load: %i/%i, timer_a_next_oflow %i", tat>>16, tac>>16, Pico.t.timer_a_next_oflow >> 8);\r
1541 elprintf(EL_YMTIMER, "load: %i/%i, timer_b_next_oflow %i", tbt>>16, tbc>>16, Pico.t.timer_b_next_oflow >> 8);\r
1542}\r
1543\r
1544#if defined(NO_32X) && defined(_ASM_MEMORY_C)\r
1545// referenced by asm code\r
1546u32 PicoRead8_32x(u32 a) { return 0; }\r
1547u32 PicoRead16_32x(u32 a) { return 0; }\r
1548void PicoWrite8_32x(u32 a, u32 d) {}\r
1549void PicoWrite16_32x(u32 a, u32 d) {}\r
1550#endif\r
1551\r
1552// -----------------------------------------------------------------\r
1553// z80 memhandlers\r
1554\r
1555static void access_68k_bus(int delay) // bus delay as Q8\r
1556{\r
1557 // TODO: if the 68K is in DMA wait, Z80 has to wait until DMA ends\r
1558\r
1559 // 68k bus access delay for z80. The fractional part needs to be accumulated\r
1560 // until an additional cycle is full. That is then added to the integer part.\r
1561 Pico.t.z80_busdelay += (delay&0xff); // accumulate\r
1562 z80_subCLeft((delay>>8) + (Pico.t.z80_busdelay>>8));\r
1563 Pico.t.z80_busdelay &= 0xff; // leftover cycle fraction\r
1564 // don't use SekCyclesBurn() here since the Z80 doesn't run in cycle lock to\r
1565 // the 68K. Count the stolen cycles to be accounted later in the 68k CPU runs\r
1566 Pico.t.z80_buscycles += 0x80; // TODO <=8.4 for Rick 2, but >=8.9 for misc_test\r
1567}\r
1568\r
1569static unsigned char z80_md_vdp_read(unsigned short a)\r
1570{\r
1571 if ((a & 0xff00) == 0x7f00) {\r
1572 // 68k bus access delay=3.3 per kabuto, for notaz picotest 2.42<delay<2.57?\r
1573 access_68k_bus(0x280); // Q8, picotest: 0x26d(>2.42) - 0x292(<2.57)\r
1574\r
1575 switch (a & 0x0d)\r
1576 {\r
1577 case 0x00: return PicoVideoRead8DataH(1);\r
1578 case 0x01: return PicoVideoRead8DataL(1);\r
1579 case 0x04: return PicoVideoRead8CtlH(1);\r
1580 case 0x05: return PicoVideoRead8CtlL(1);\r
1581 case 0x08:\r
1582 case 0x0c: return PicoVideoGetV(get_scanline(1), 1);\r
1583 case 0x09:\r
1584 case 0x0d: return Pico.m.rotate++;\r
1585 }\r
1586 }\r
1587\r
1588 elprintf(EL_ANOMALY, "z80 invalid r8 [%06x] %02x", a, 0xff);\r
1589 return 0xff;\r
1590}\r
1591\r
1592static unsigned char z80_md_bank_read(unsigned short a)\r
1593{\r
1594 unsigned int addr68k;\r
1595 unsigned char ret = 0xff;\r
1596\r
1597 // 68k bus access delay=3.3 per kabuto, but for notaz picotest 3.02<delay<3.32\r
1598 access_68k_bus(0x340); // Q8, picotest: 0x306(>3.02)-0x351(<3.32)\r
1599\r
1600 addr68k = Pico.m.z80_bank68k << 15;\r
1601 addr68k |= a & 0x7fff;\r
1602\r
1603 if (addr68k < 0xe00000) // can't read from 68K RAM\r
1604 ret = m68k_read8(addr68k);\r
1605\r
1606 elprintf(EL_Z80BNK, "z80->68k r8 [%06x] %02x", addr68k, ret);\r
1607 return ret;\r
1608}\r
1609\r
1610static void z80_md_ym2612_write(unsigned int a, unsigned char data)\r
1611{\r
1612 if (PicoIn.opt & POPT_EN_FM)\r
1613 ym2612_write_local(a, data, 1);\r
1614}\r
1615\r
1616static void z80_md_vdp_br_write(unsigned int a, unsigned char data)\r
1617{\r
1618 if ((a&0xfff9) == 0x7f11) // 7f11 7f13 7f15 7f17\r
1619 {\r
1620 psg_write_z80(data);\r
1621 return;\r
1622 }\r
1623 // at least VDP data writes hang my machine\r
1624\r
1625 if ((a>>8) == 0x60)\r
1626 {\r
1627 Pico.m.z80_bank68k >>= 1;\r
1628 Pico.m.z80_bank68k |= data << 8;\r
1629 Pico.m.z80_bank68k &= 0x1ff; // 9 bits and filled in the new top one\r
1630 return;\r
1631 }\r
1632\r
1633 elprintf(EL_ANOMALY, "z80 invalid w8 [%06x] %02x", a, data);\r
1634}\r
1635\r
1636static void z80_md_bank_write(unsigned int a, unsigned char data)\r
1637{\r
1638 unsigned int addr68k;\r
1639\r
1640 // 68k bus access delay=3.3 per kabuto, but for notaz picotest 3.02<delay<3.32\r
1641 access_68k_bus(0x340); // Q8, picotest: 0x306(>3.02)-0x351(<3.32)\r
1642\r
1643 addr68k = Pico.m.z80_bank68k << 15;\r
1644 addr68k += a & 0x7fff;\r
1645\r
1646 elprintf(EL_Z80BNK, "z80->68k w8 [%06x] %02x", addr68k, data);\r
1647 m68k_write8(addr68k, data);\r
1648}\r
1649\r
1650// -----------------------------------------------------------------\r
1651\r
1652static unsigned char z80_md_in(unsigned short p)\r
1653{\r
1654 elprintf(EL_ANOMALY, "Z80 port %04x read", p);\r
1655 return 0xff;\r
1656}\r
1657\r
1658static void z80_md_out(unsigned short p, unsigned char d)\r
1659{\r
1660 elprintf(EL_ANOMALY, "Z80 port %04x write %02x", p, d);\r
1661}\r
1662\r
1663static void z80_mem_setup(void)\r
1664{\r
1665 z80_map_set(z80_read_map, 0x0000, 0x1fff, PicoMem.zram, 0);\r
1666 z80_map_set(z80_read_map, 0x2000, 0x3fff, PicoMem.zram, 0);\r
1667 z80_map_set(z80_read_map, 0x4000, 0x5fff, ym2612_read_local_z80, 1);\r
1668 z80_map_set(z80_read_map, 0x6000, 0x7fff, z80_md_vdp_read, 1);\r
1669 z80_map_set(z80_read_map, 0x8000, 0xffff, z80_md_bank_read, 1);\r
1670\r
1671 z80_map_set(z80_write_map, 0x0000, 0x1fff, PicoMem.zram, 0);\r
1672 z80_map_set(z80_write_map, 0x2000, 0x3fff, PicoMem.zram, 0);\r
1673 z80_map_set(z80_write_map, 0x4000, 0x5fff, z80_md_ym2612_write, 1);\r
1674 z80_map_set(z80_write_map, 0x6000, 0x7fff, z80_md_vdp_br_write, 1);\r
1675 z80_map_set(z80_write_map, 0x8000, 0xffff, z80_md_bank_write, 1);\r
1676\r
1677#ifdef _USE_DRZ80\r
1678 drZ80.z80_in = z80_md_in;\r
1679 drZ80.z80_out = z80_md_out;\r
1680#endif\r
1681#ifdef _USE_CZ80\r
1682 Cz80_Set_INPort(&CZ80, z80_md_in);\r
1683 Cz80_Set_OUTPort(&CZ80, z80_md_out);\r
1684#endif\r
1685}\r
1686\r
1687// vim:shiftwidth=2:ts=2:expandtab\r