pandora: fix readme and pxml version
[picodrive.git] / pico / memory.c
CommitLineData
cff531af 1/*\r
2 * memory handling\r
3 * (c) Copyright Dave, 2004\r
4 * (C) notaz, 2006-2010\r
7bf552b5 5 * (C) irixxxx, 2019-2024\r
cff531af 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
cc68a136 10\r
ccce7ee7 11#include <assert.h>\r
efcba75f 12#include "pico_int.h"\r
af37bca8 13#include "memory.h"\r
ccce7ee7 14#include "state.h"\r
cc68a136 15\r
cc68a136 16#include "sound/ym2612.h"\r
17#include "sound/sn76496.h"\r
18\r
c8d1e9b6 19extern unsigned int lastSSRamWrite; // used by serial eeprom code\r
cc68a136 20\r
bcf65fd6 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
af37bca8 25\r
7ed05f84 26static void xmap_set(uptr *map, int shift, u32 start_addr, u32 end_addr,\r
0ace9b9a 27 const void *func_or_mh, int is_func)\r
af37bca8 28{\r
faf543ce 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
bcf65fd6 34 uptr addr = (uptr)func_or_mh;\r
af37bca8 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
add51c49 55 map[i] |= MAP_FLAG;\r
af37bca8 56 }\r
57}\r
58\r
7ed05f84 59void z80_map_set(uptr *map, u16 start_addr, u16 end_addr,\r
0ace9b9a 60 const void *func_or_mh, int is_func)\r
af37bca8 61{\r
62 xmap_set(map, Z80_MEM_SHIFT, start_addr, end_addr, func_or_mh, is_func);\r
032c76a3 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
af37bca8 67}\r
68\r
7ed05f84 69void cpu68k_map_set(uptr *map, u32 start_addr, u32 end_addr,\r
0ace9b9a 70 const void *func_or_mh, int is_func)\r
af37bca8 71{\r
02ff0254 72 xmap_set(map, M68K_MEM_SHIFT, start_addr, end_addr, func_or_mh, is_func & 1);\r
c6b118c0 73#ifdef EMU_F68K\r
74 // setup FAME fetchmap\r
02ff0254 75 if (!(is_func & 1))\r
c6b118c0 76 {\r
02ff0254 77 M68K_CONTEXT *ctx = is_func & 2 ? &PicoCpuFS68k : &PicoCpuFM68k;\r
c6b118c0 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
02ff0254 82 ctx->Fetch[i] = base;\r
c6b118c0 83 }\r
84#endif\r
af37bca8 85}\r
86\r
87// more specialized/optimized function (does same as above)\r
8eeb3426 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
7ed05f84 120void cpu68k_map_all_ram(u32 start_addr, u32 end_addr, void *ptr, int is_sub)\r
af37bca8 121{\r
bcf65fd6 122 uptr *r8map, *r16map, *w8map, *w16map;\r
123 uptr addr = (uptr)ptr;\r
af37bca8 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
c6b118c0 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
af37bca8 154}\r
155\r
8eeb3426 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
9f29605f 205u32 PicoRead16_floating(u32 a)\r
206{\r
207 // faking open bus\r
a0ddd242 208 u16 d = (Pico.m.rotate += 0x41);\r
9f29605f 209 d ^= (d << 5) ^ (d << 8);\r
41670496 210 if ((a & 0xff0000) == 0xa10000) return d; // MegaCD pulldowns don't work here curiously\r
9f29605f 211 return (PicoIn.AHW & PAHW_MCD) ? 0x00 : d; // pulldown if MegaCD2 attached\r
212}\r
213\r
af37bca8 214static u32 m68k_unmapped_read8(u32 a)\r
215{\r
216 elprintf(EL_UIO, "m68k unmapped r8 [%06x] @%06x", a, SekPc);\r
1eb630c2 217 return a < 0x400000 ? 0 : (u8)PicoRead16_floating(a);\r
af37bca8 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
1eb630c2 223 return a < 0x400000 ? 0 : PicoRead16_floating(a);\r
af37bca8 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
7ed05f84 236void m68k_map_unmap(u32 start_addr, u32 end_addr)\r
af37bca8 237{\r
faf543ce 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
bcf65fd6 243 uptr addr;\r
af37bca8 244 int shift = M68K_MEM_SHIFT;\r
245 int i;\r
246\r
bcf65fd6 247 addr = (uptr)m68k_unmapped_read8;\r
af37bca8 248 for (i = start_addr >> shift; i <= end_addr >> shift; i++)\r
add51c49 249 m68k_read8_map[i] = (addr >> 1) | MAP_FLAG;\r
af37bca8 250\r
bcf65fd6 251 addr = (uptr)m68k_unmapped_read16;\r
af37bca8 252 for (i = start_addr >> shift; i <= end_addr >> shift; i++)\r
add51c49 253 m68k_read16_map[i] = (addr >> 1) | MAP_FLAG;\r
af37bca8 254\r
bcf65fd6 255 addr = (uptr)m68k_unmapped_write8;\r
af37bca8 256 for (i = start_addr >> shift; i <= end_addr >> shift; i++)\r
add51c49 257 m68k_write8_map[i] = (addr >> 1) | MAP_FLAG;\r
af37bca8 258\r
bcf65fd6 259 addr = (uptr)m68k_unmapped_write16;\r
af37bca8 260 for (i = start_addr >> shift; i <= end_addr >> shift; i++)\r
add51c49 261 m68k_write16_map[i] = (addr >> 1) | MAP_FLAG;\r
af37bca8 262}\r
263\r
78d817c3 264#ifndef _ASM_MEMORY_C\r
af37bca8 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
78d817c3 271#endif\r
af37bca8 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
cc68a136 278\r
0ace9b9a 279#ifdef _ASM_MEMORY_C\r
280u32 PicoRead8_sram(u32 a);\r
281u32 PicoRead16_sram(u32 a);\r
282#endif\r
cc68a136 283\r
03e4f2a3 284#ifdef EMU_CORE_DEBUG\r
cc68a136 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
4f65685b 290#ifdef IO_STATS\r
291void log_io(unsigned int addr, int bits, int rw);\r
dca310c4 292#elif defined(_MSC_VER)\r
293#define log_io\r
4f65685b 294#else\r
295#define log_io(...)\r
296#endif\r
297\r
70357ce5 298#if defined(EMU_C68K)\r
3bbce622 299u32 cyclone_crashed(u32 pc, struct Cyclone *context)\r
cc68a136 300{\r
3bbce622 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
5e89f0f5 311 context->membase = (u32)Pico.rom;\r
3bbce622 312 context->pc = (u32)Pico.rom + pc24;\r
313\r
314 return context->pc;\r
cc68a136 315}\r
316#endif\r
317\r
cc68a136 318// -----------------------------------------------------------------\r
af37bca8 319// memmap helpers\r
cc68a136 320\r
531a8f38 321static u32 read_pad_3btn(int i, u32 out_bits)\r
e5503e2f 322{\r
93f9619e 323 u32 pad = ~PicoIn.padInt[i]; // Get inverse of pad MXYZ SACB RLDU\r
531a8f38 324 u32 value;\r
e5503e2f 325\r
531a8f38 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
e5503e2f 330\r
531a8f38 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
93f9619e 337 u32 pad = ~PicoIn.padInt[i]; // Get inverse of pad MXYZ SACB RLDU\r
531a8f38 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
0738c83e 345 else if (phase == 3) {\r
531a8f38 346 if (out_bits & 0x40)\r
6890dcfa 347 value = (pad & 0x30) | ((pad >> 8) & 0xf); // ?1CB MXYZ\r
531a8f38 348 else\r
6890dcfa 349 value = ((pad & 0xc0) >> 2) | 0x0f; // ?0SA 1111\r
531a8f38 350 goto out;\r
e5503e2f 351 }\r
352\r
531a8f38 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
e5503e2f 357\r
531a8f38 358out:\r
359 value |= out_bits & 0x40;\r
360 return value;\r
e5503e2f 361}\r
362\r
d650a7a2 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
1d5885dd 369 switch (phase) {\r
370 case 0:\r
d650a7a2 371 value = 0x03;\r
1d5885dd 372 break;\r
373 case 1:\r
d650a7a2 374 value = 0x0f;\r
1d5885dd 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
d650a7a2 381 value = pad & 0x0f; // ?x?x RLDU\r
1d5885dd 382 break;\r
383 case 9: case 11: case 13: case 15:\r
384 pad = ~PicoIn.padInt[(phase-8) >> 1];\r
d650a7a2 385 value = (pad & 0xf0) >> 4; // ?x?x SACB\r
1d5885dd 386 break;\r
387 default:\r
388 value = 0;\r
389 break;\r
d650a7a2 390 }\r
391\r
d650a7a2 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
1d5885dd 401 if (i == 0 && pad <= 3)\r
402 value = read_pad_3btn(pad, out_bits);\r
d650a7a2 403\r
404 value |= (out_bits & 0x40);\r
405 return value;\r
406}\r
407\r
0738c83e 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
531a8f38 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
0ace9b9a 472\r
4a521146 473static int padTHLatency[3];\r
474static int padTLLatency[3];\r
66e9abff 475\r
531a8f38 476static NOINLINE u32 port_read(int i)\r
477{\r
88fd63ad 478 u32 data_reg = PicoMem.ioports[i + 1];\r
479 u32 ctrl_reg = PicoMem.ioports[i + 4] | 0x80;\r
531a8f38 480 u32 in, out;\r
481\r
482 out = data_reg & ctrl_reg;\r
1d366b1a 483\r
484 // pull-ups: should be 0x7f, but Decap Attack has a bug where it temp.\r
133006a9 485 // disables output before doing TH-low read, so emulate RC filter for TH.\r
4a521146 486 // Decap Attack reportedly doesn't work on Nomad but works on most\r
1d366b1a 487 // other MD revisions (different pull-up strength?).\r
e05680a2 488 u32 mask = 0x3f;\r
489 if (CYCLES_GE(SekCyclesDone(), padTHLatency[i])) {\r
490 mask |= 0x40;\r
491 padTHLatency[i] = SekCyclesDone();\r
492 }\r
66e9abff 493 out |= mask & ~ctrl_reg;\r
531a8f38 494\r
495 in = port_readers[i](i, out);\r
496\r
0738c83e 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
531a8f38 504 return (in & ~ctrl_reg) | (data_reg & ctrl_reg);\r
505}\r
506\r
99bd61f8 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
531a8f38 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
1d5885dd 520 if (port == 1 && port_readers[0] == read_pad_team)\r
521 func = read_nothing;\r
522\r
523 else switch (device) {\r
531a8f38 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
d650a7a2 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
0738c83e 540 case PICO_INPUT_MOUSE:\r
541 func = read_pad_mouse;\r
542 break;\r
543\r
531a8f38 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
cc68a136 553{\r
af37bca8 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
531a8f38 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
88fd63ad 561 default: d = PicoMem.ioports[a]; break; // IO ports can be used as RAM\r
7969166e 562 }\r
af37bca8 563 return d;\r
cc68a136 564}\r
cc68a136 565\r
531a8f38 566NOINLINE void io_ports_write(u32 a, u32 d)\r
9dc09829 567{\r
af37bca8 568 a = (a>>1) & 0xf;\r
569\r
0738c83e 570 // for some controllers, changing TH/TR changes controller state\r
531a8f38 571 if (1 <= a && a <= 2)\r
af37bca8 572 {\r
573 Pico.m.padDelay[a - 1] = 0;\r
d650a7a2 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
1d5885dd 579 } else if (port_readers[0] == read_pad_4way) {\r
d650a7a2 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
0738c83e 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
d650a7a2 596 } else if (!(PicoMem.ioports[a] & 0x40) && (d & 0x40))\r
af37bca8 597 Pico.m.padTHPhase[a - 1]++;\r
9dc09829 598 }\r
af37bca8 599\r
e05680a2 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
6c6d449e 602 if (4 <= a && a <= 5) {\r
e2a5b098 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
6c6d449e 605 padTHLatency[a - 4] = SekCyclesDone() + 25;\r
e05680a2 606 }\r
66e9abff 607\r
5e89f0f5 608 // certain IO ports can be used as RAM\r
88fd63ad 609 PicoMem.ioports[a] = d;\r
9dc09829 610}\r
611\r
4a521146 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
922c3352 621 save_s32(buf, &b, padTHLatency[i]);\r
622 save_s32(buf, &b, padTLLatency[i]);\r
4a521146 623 }\r
922c3352 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
4a521146 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
922c3352 641 padTHLatency[i] = load_s32(buf, &b);\r
642 padTLLatency[i] = load_s32(buf, &b);\r
4a521146 643 }\r
922c3352 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
4a521146 648 assert(b <= size);\r
649}\r
650\r
ae214f1c 651static int z80_cycles_from_68k(void)\r
652{\r
88fd63ad 653 int m68k_cnt = SekCyclesDone() - Pico.t.m68c_frame_start;\r
3162a710 654 return cycles_68k_to_z80(m68k_cnt);\r
ae214f1c 655}\r
656\r
0ace9b9a 657void NOINLINE ctl_write_z80busreq(u32 d)\r
7969166e 658{\r
af37bca8 659 d&=1; d^=1;\r
ebd70cb5 660 elprintf(EL_BUSREQ, "set_zrun: %i->%i [%u] @%06x", Pico.m.z80Run, d, SekCyclesDone(), SekPc);\r
af37bca8 661 if (d ^ Pico.m.z80Run)\r
662 {\r
663 if (d)\r
664 {\r
2f0c5639 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
71f9c68f 667 Pico.t.z80_busdelay &= 0xff;\r
af37bca8 668 }\r
669 else\r
670 {\r
93f9619e 671 if ((PicoIn.opt & POPT_EN_Z80) && !Pico.m.z80_reset) {\r
274dd51a 672 // Z80 grants bus after the current M cycle, even within an insn\r
71f9c68f 673 // simulate this by accumulating the last insn overhang in busdelay\r
274dd51a 674 unsigned granted;\r
f6c49d38 675 pprof_start(m68k);\r
ae214f1c 676 PicoSyncZ80(SekCyclesDone());\r
274dd51a 677 pprof_end_sub(m68k);\r
678 granted = Pico.t.z80c_aim + 6; // M cycle is 3-6 cycles \r
71f9c68f 679 Pico.t.z80_busdelay += (Pico.t.z80c_cnt - granted) << 8;\r
680 Pico.t.z80c_cnt = granted;\r
f6c49d38 681 }\r
af37bca8 682 }\r
683 Pico.m.z80Run = d;\r
7969166e 684 }\r
af37bca8 685}\r
686\r
0ace9b9a 687void NOINLINE ctl_write_z80reset(u32 d)\r
af37bca8 688{\r
689 d&=1; d^=1;\r
ebd70cb5 690 elprintf(EL_BUSREQ, "set_zreset: %i->%i [%u] @%06x", Pico.m.z80_reset, d, SekCyclesDone(), SekPc);\r
af37bca8 691 if (d ^ Pico.m.z80_reset)\r
692 {\r
693 if (d)\r
694 {\r
93f9619e 695 if ((PicoIn.opt & POPT_EN_Z80) && Pico.m.z80Run) {\r
f6c49d38 696 pprof_start(m68k);\r
af37bca8 697 PicoSyncZ80(SekCyclesDone());\r
f6c49d38 698 pprof_end_sub(m68k);\r
699 }\r
274dd51a 700 Pico.t.z80_busdelay &= 0xff; // also resets bus request\r
af37bca8 701 YM2612ResetChip();\r
702 timers_reset();\r
7969166e 703 }\r
af37bca8 704 else\r
705 {\r
274dd51a 706 Pico.t.z80c_aim = Pico.t.z80c_cnt = z80_cycles_from_68k() + 2;\r
af37bca8 707 z80_reset();\r
7969166e 708 }\r
af37bca8 709 Pico.m.z80_reset = d;\r
7969166e 710 }\r
711}\r
cc68a136 712\r
5d638db0 713static void psg_write_68k(u32 d)\r
714{\r
15caa286 715 PsndDoPSG(z80_cycles_from_68k());\r
5d638db0 716 SN76496Write(d);\r
717}\r
718\r
719static void psg_write_z80(u32 d)\r
720{\r
15caa286 721 PsndDoPSG(z80_cyclesDone());\r
5d638db0 722 SN76496Write(d);\r
723}\r
724\r
af37bca8 725// -----------------------------------------------------------------\r
fa1e5e29 726\r
0ace9b9a 727#ifndef _ASM_MEMORY_C\r
728\r
af37bca8 729// cart (save) RAM area (usually 0x200000 - ...)\r
730static u32 PicoRead8_sram(u32 a)\r
731{\r
af37bca8 732 u32 d;\r
88fd63ad 733 if (Pico.sv.start <= a && a <= Pico.sv.end && (Pico.m.sram_reg & SRR_MAPPED))\r
af37bca8 734 {\r
88fd63ad 735 if (Pico.sv.flags & SRF_EEPROM) {\r
af37bca8 736 d = EEPROM_read();\r
45f2f245 737 if (!(a & 1))\r
738 d >>= 8;\r
78d817c3 739 d &= 0xff;\r
45f2f245 740 } else\r
88fd63ad 741 d = *(u8 *)(Pico.sv.data - Pico.sv.start + a);\r
45f2f245 742 elprintf(EL_SRAMIO, "sram r8 [%06x] %02x @ %06x", a, d, SekPc);\r
af37bca8 743 return d;\r
744 }\r
cc68a136 745\r
45f2f245 746 // XXX: this is banking unfriendly\r
af37bca8 747 if (a < Pico.romsize)\r
57c5a5e5 748 return Pico.rom[MEM_BE2(a)];\r
af37bca8 749 \r
750 return m68k_unmapped_read8(a);\r
751}\r
cc68a136 752\r
af37bca8 753static u32 PicoRead16_sram(u32 a)\r
cc68a136 754{\r
af37bca8 755 u32 d;\r
88fd63ad 756 if (Pico.sv.start <= a && a <= Pico.sv.end && (Pico.m.sram_reg & SRR_MAPPED))\r
af37bca8 757 {\r
88fd63ad 758 if (Pico.sv.flags & SRF_EEPROM)\r
af37bca8 759 d = EEPROM_read();\r
45f2f245 760 else {\r
88fd63ad 761 u8 *pm = (u8 *)(Pico.sv.data - Pico.sv.start + a);\r
af37bca8 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
cc68a136 768\r
af37bca8 769 if (a < Pico.romsize)\r
770 return *(u16 *)(Pico.rom + a);\r
cc68a136 771\r
af37bca8 772 return m68k_unmapped_read16(a);\r
773}\r
cc68a136 774\r
0ace9b9a 775#endif // _ASM_MEMORY_C\r
776\r
af37bca8 777static void PicoWrite8_sram(u32 a, u32 d)\r
778{\r
88fd63ad 779 if (a > Pico.sv.end || a < Pico.sv.start || !(Pico.m.sram_reg & SRR_MAPPED)) {\r
45f2f245 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
88fd63ad 785 if (Pico.sv.flags & SRF_EEPROM)\r
af37bca8 786 {\r
45f2f245 787 EEPROM_write8(a, d);\r
cc68a136 788 }\r
45f2f245 789 else {\r
88fd63ad 790 u8 *pm = (u8 *)(Pico.sv.data - Pico.sv.start + a);\r
af37bca8 791 if (*pm != (u8)d) {\r
88fd63ad 792 Pico.sv.changed = 1;\r
af37bca8 793 *pm = (u8)d;\r
794 }\r
795 }\r
796}\r
cc68a136 797\r
af37bca8 798static void PicoWrite16_sram(u32 a, u32 d)\r
799{\r
88fd63ad 800 if (a > Pico.sv.end || a < Pico.sv.start || !(Pico.m.sram_reg & SRR_MAPPED)) {\r
45f2f245 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
88fd63ad 806 if (Pico.sv.flags & SRF_EEPROM)\r
45f2f245 807 {\r
808 EEPROM_write16(d);\r
809 }\r
810 else {\r
88fd63ad 811 u8 *pm = (u8 *)(Pico.sv.data - Pico.sv.start + a);\r
1dd0871f 812 if (pm[0] != (u8)(d >> 8)) {\r
88fd63ad 813 Pico.sv.changed = 1;\r
1dd0871f 814 pm[0] = (u8)(d >> 8);\r
815 }\r
816 if (pm[1] != (u8)d) {\r
88fd63ad 817 Pico.sv.changed = 1;\r
1dd0871f 818 pm[1] = (u8)d;\r
45f2f245 819 }\r
820 }\r
af37bca8 821}\r
cc68a136 822\r
af37bca8 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
9f29605f 827 u32 d;\r
71f9c68f 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
af37bca8 830 elprintf(EL_ANOMALY, "68k z80 read with no bus! [%06x] @ %06x", a, SekPc);\r
9f29605f 831 return (u8)PicoRead16_floating(a);\r
af37bca8 832 }\r
a17fb021 833 SekCyclesBurnRun(1);\r
c060a9ab 834\r
133006a9 835 if ((a & 0x4000) == 0x0000) {\r
88fd63ad 836 d = PicoMem.zram[a & 0x1fff];\r
133006a9 837 } else if ((a & 0x6000) == 0x4000) // 0x4000-0x5fff\r
af37bca8 838 d = ym2612_read_local_68k(); \r
9f29605f 839 else {\r
af37bca8 840 elprintf(EL_UIO|EL_ANOMALY, "68k bad read [%06x] @%06x", a, SekPc);\r
9f29605f 841 d = (u8)PicoRead16_floating(a);\r
842 }\r
af37bca8 843 return d;\r
844}\r
b542be46 845\r
af37bca8 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
a17fb021 854 if ((Pico.m.z80Run | Pico.m.z80_reset) && !(PicoIn.quirks & PQUIRK_NO_Z80_BUS_LOCK)) {\r
af37bca8 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
a17fb021 859 SekCyclesBurnRun(1);\r
af37bca8 860\r
861 if ((a & 0x4000) == 0x0000) { // z80 RAM\r
88fd63ad 862 PicoMem.zram[a & 0x1fff] = (u8)d;\r
af37bca8 863 return;\r
864 }\r
865 if ((a & 0x6000) == 0x4000) { // FM Sound\r
93f9619e 866 if (PicoIn.opt & POPT_EN_FM)\r
8ac9ab7f 867 ym2612_write_local(a & 3, d & 0xff, 0);\r
af37bca8 868 return;\r
869 }\r
870 // TODO: probably other VDP access too? Maybe more mirrors?\r
871 if ((a & 0x7ff9) == 0x7f11) { // PSG Sound\r
5d638db0 872 psg_write_68k(d);\r
af37bca8 873 return;\r
874 }\r
af37bca8 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
cc68a136 882 }\r
af37bca8 883 elprintf(EL_UIO|EL_ANOMALY, "68k bad write [%06x] %02x @ %06x", a, d&0xff, SekPc);\r
cc68a136 884}\r
885\r
af37bca8 886static void PicoWrite16_z80(u32 a, u32 d)\r
cc68a136 887{\r
af37bca8 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
cc68a136 892\r
0ace9b9a 893#ifndef _ASM_MEMORY_C\r
894\r
af37bca8 895// IO/control area (0xa10000 - 0xa1ffff)\r
896u32 PicoRead8_io(u32 a)\r
897{\r
898 u32 d;\r
cc68a136 899\r
af37bca8 900 if ((a & 0xffe0) == 0x0000) { // I/O ports\r
901 d = io_ports_read(a);\r
cc68a136 902 goto end;\r
903 }\r
cc68a136 904\r
5e89f0f5 905 if ((a & 0xfc00) == 0x1000) {\r
a0ddd242 906 d = (u8)PicoRead16_floating(a);\r
907\r
5e89f0f5 908 if ((a & 0xff01) == 0x1100) { // z80 busreq (verified)\r
d97d056c 909 // bit8 seems to be readable in this range\r
910 if (!(a & 1)) {\r
911 d &= ~0x01;\r
71f9c68f 912 // Z80 ahead of 68K only if in BUSREQ, BUSACK only after 68K reached Z80\r
a17fb021 913 d |= (z80_cycles_from_68k() < Pico.t.z80c_cnt);\r
d97d056c 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
5e89f0f5 917 }\r
af37bca8 918 goto end;\r
cc68a136 919 }\r
af37bca8 920\r
93f9619e 921 d = PicoRead8_32x(a);\r
be2c4208 922\r
af37bca8 923end:\r
cc68a136 924 return d;\r
925}\r
926\r
af37bca8 927u32 PicoRead16_io(u32 a)\r
cc68a136 928{\r
af37bca8 929 u32 d;\r
cc68a136 930\r
af37bca8 931 if ((a & 0xffe0) == 0x0000) { // I/O ports\r
932 d = io_ports_read(a);\r
bdd6a009 933 d |= d << 8;\r
cc68a136 934 goto end;\r
935 }\r
936\r
af37bca8 937 // bit8 seems to be readable in this range\r
5e89f0f5 938 if ((a & 0xfc00) == 0x1000) {\r
a0ddd242 939 d = PicoRead16_floating(a);\r
940\r
5e89f0f5 941 if ((a & 0xff00) == 0x1100) { // z80 busreq\r
d97d056c 942 d &= ~0x0100;\r
a17fb021 943 d |= (z80_cycles_from_68k() < Pico.t.z80c_cnt) << 8;\r
5e89f0f5 944 d |= ((Pico.m.z80Run | Pico.m.z80_reset) & 1) << 8;\r
ebd70cb5 945 elprintf(EL_BUSREQ, "get_zrun: %04x [%u] @%06x", d, SekCyclesDone(), SekPc);\r
5e89f0f5 946 }\r
af37bca8 947 goto end;\r
cc68a136 948 }\r
af37bca8 949\r
93f9619e 950 d = PicoRead16_32x(a);\r
be2c4208 951\r
af37bca8 952end:\r
cc68a136 953 return d;\r
954}\r
cc68a136 955\r
af37bca8 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
45f2f245 972 Pico.m.sram_reg &= ~(SRR_MAPPED|SRR_READONLY);\r
973 Pico.m.sram_reg |= (u8)(d & 3);\r
af37bca8 974 return;\r
975 }\r
93f9619e 976 PicoWrite8_32x(a, d);\r
af37bca8 977}\r
cc68a136 978\r
af37bca8 979void PicoWrite16_io(u32 a, u32 d)\r
cc68a136 980{\r
af37bca8 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
45f2f245 995 Pico.m.sram_reg &= ~(SRR_MAPPED|SRR_READONLY);\r
996 Pico.m.sram_reg |= (u8)(d & 3);\r
af37bca8 997 return;\r
998 }\r
93f9619e 999 PicoWrite16_32x(a, d);\r
af37bca8 1000}\r
cc68a136 1001\r
0ace9b9a 1002#endif // _ASM_MEMORY_C\r
1003\r
af37bca8 1004// VDP area (0xc00000 - 0xdfffff)\r
1005// TODO: verify if lower byte goes to PSG on word writes\r
75b84e4b 1006u32 PicoRead8_vdp(u32 a)\r
af37bca8 1007{\r
9f29605f 1008 u32 d;\r
75b84e4b 1009 if ((a & 0x00f0) == 0x0000) {\r
1010 switch (a & 0x0d)\r
1011 {\r
d97d056c 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
75b84e4b 1016 case 0x08:\r
d97d056c 1017 case 0x0c: d = PicoVideoRead8HV_H(0); break;\r
75b84e4b 1018 case 0x09:\r
d97d056c 1019 case 0x0d: d = PicoVideoRead8HV_L(0); break;\r
9f29605f 1020 default: d = (u8)PicoRead16_floating(a); break;\r
75b84e4b 1021 }\r
9f29605f 1022 } else {\r
d97d056c 1023 elprintf(EL_UIO|EL_ANOMALY, "68k bad read [%06x] @%06x", a, SekPc);\r
9f29605f 1024 d = (u8)PicoRead16_floating(a);\r
1025 }\r
d97d056c 1026 return d;\r
cc68a136 1027}\r
1028\r
af37bca8 1029static u32 PicoRead16_vdp(u32 a)\r
cc68a136 1030{\r
af37bca8 1031 if ((a & 0x00e0) == 0x0000)\r
1032 return PicoVideoRead(a);\r
cc68a136 1033\r
af37bca8 1034 elprintf(EL_UIO|EL_ANOMALY, "68k bad read [%06x] @%06x", a, SekPc);\r
1035 return 0;\r
cc68a136 1036}\r
1037\r
af37bca8 1038static void PicoWrite8_vdp(u32 a, u32 d)\r
cc68a136 1039{\r
af37bca8 1040 if ((a & 0x00f9) == 0x0011) { // PSG Sound\r
5d638db0 1041 psg_write_68k(d);\r
cc68a136 1042 return;\r
1043 }\r
af37bca8 1044 if ((a & 0x00e0) == 0x0000) {\r
1045 d &= 0xff;\r
1046 PicoVideoWrite(a, d | (d << 8));\r
b542be46 1047 return;\r
1048 }\r
1049\r
af37bca8 1050 elprintf(EL_UIO|EL_ANOMALY, "68k bad write [%06x] %02x @%06x", a, d & 0xff, SekPc);\r
cc68a136 1051}\r
1052\r
af37bca8 1053static void PicoWrite16_vdp(u32 a, u32 d)\r
1054{\r
7aab4768 1055 if ((a & 0x00f9) == 0x0010) { // PSG Sound\r
5d638db0 1056 psg_write_68k(d);\r
7aab4768 1057 return;\r
1058 }\r
af37bca8 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
cc68a136 1066\r
1067// -----------------------------------------------------------------\r
f53f286a 1068\r
9037e45d 1069#ifdef EMU_M68K\r
1070static void m68k_mem_setup(void);\r
1071#endif\r
1072\r
f8ef8ff7 1073PICO_INTERNAL void PicoMemSetup(void)\r
1074{\r
88fd63ad 1075 int mask, rs, sstart, a;\r
af37bca8 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
e1e8ca17 1087 if (rs > 0xa00000) rs = 0xa00000; // max cartridge area\r
549dd407 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
af37bca8 1092\r
1093 // Common case of on-cart (save) RAM, usually at 0x200000-...\r
88fd63ad 1094 if ((Pico.sv.flags & SRF_ENABLED) && Pico.sv.data != NULL) {\r
60392bf4 1095 sstart = Pico.sv.start & ~mask;\r
88fd63ad 1096 rs = Pico.sv.end - sstart;\r
af37bca8 1097 rs = (rs + mask) & ~mask;\r
88fd63ad 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
af37bca8 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
88fd63ad 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
af37bca8 1134 }\r
1135\r
cc68a136 1136 // Setup memory callbacks:\r
70357ce5 1137#ifdef EMU_C68K\r
5e89f0f5 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
cc68a136 1148#endif\r
70357ce5 1149#ifdef EMU_F68K\r
4cc0fcaf 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
70357ce5 1156#endif\r
9037e45d 1157#ifdef EMU_M68K\r
1158 m68k_mem_setup();\r
1159#endif\r
c8d1e9b6 1160\r
1161 z80_mem_setup();\r
cc68a136 1162}\r
1163\r
cc68a136 1164#ifdef EMU_M68K\r
9037e45d 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
cc68a136 1171\r
9037e45d 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
9037e45d 1179\r
1180static void m68k_mem_setup(void)\r
1181{\r
af37bca8 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
cc68a136 1188}\r
cc68a136 1189#endif // EMU_M68K\r
1190\r
1191\r
4b9c5888 1192// -----------------------------------------------------------------\r
1193\r
4b9c5888 1194static int get_scanline(int is_from_z80)\r
1195{\r
1196 if (is_from_z80) {\r
f61d0a45 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
7263343d 1199 int cycles_line = cycles_68k_to_z80((unsigned)(488.5*256))+1; // cycles per line, Q8\r
f61d0a45 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
7263343d 1203 if (cycles_z80 - cycles >= 4*cycles_line) {\r
f61d0a45 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
88fd63ad 1215 return Pico.t.z80_scanline;\r
4b9c5888 1216 }\r
1217\r
2aa27095 1218 return Pico.m.scanline;\r
4b9c5888 1219}\r
1220\r
0e2e188e 1221#define ym2612_update_status(xcycles) \\r
83025d7a 1222 ym2612.OPN.ST.status &= ~0x80; \\r
1223 ym2612.OPN.ST.status |= (xcycles < Pico.t.ym2612_busy) * 0x80; \\r
0e2e188e 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
48dc74f2 1229/* probably should not be in this file, but it's near related code here */\r
43e6eaad 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
0e2e188e 1234 // update timer status\r
1235 ym2612_update_status(xcycles);\r
43e6eaad 1236\r
0e2e188e 1237 // update timer a\r
43e6eaad 1238 if (mode_old & 1)\r
0e2e188e 1239 while (xcycles >= Pico.t.timer_a_next_oflow)\r
6311a3ba 1240 Pico.t.timer_a_next_oflow += Pico.t.timer_a_step;\r
43e6eaad 1241\r
0e2e188e 1242 // turning on/off\r
1243 if ((mode_old ^ mode_new) & 1)\r
43e6eaad 1244 {\r
48dc74f2 1245 if (mode_old & 1)\r
6311a3ba 1246 Pico.t.timer_a_next_oflow = TIMER_NO_OFLOW;\r
0e2e188e 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
80f51a1d 1253 unsigned t = ((xcycles * (((1LL<<32)/TIMER_A_TICK_ZCYCLES)+1))>>32) + 1;\r
0e2e188e 1254 Pico.t.timer_a_next_oflow = t*TIMER_A_TICK_ZCYCLES + Pico.t.timer_a_step;\r
1255 }\r
43e6eaad 1256 }\r
0e2e188e 1257\r
43e6eaad 1258 if (mode_new & 1)\r
6311a3ba 1259 elprintf(EL_YMTIMER, "timer a upd to %i @ %i", Pico.t.timer_a_next_oflow>>8, z80_cycles);\r
43e6eaad 1260\r
0e2e188e 1261 // update timer b\r
43e6eaad 1262 if (mode_old & 2)\r
0e2e188e 1263 while (xcycles >= Pico.t.timer_b_next_oflow)\r
6311a3ba 1264 Pico.t.timer_b_next_oflow += Pico.t.timer_b_step;\r
43e6eaad 1265\r
0e2e188e 1266 // turning on/off\r
43e6eaad 1267 if ((mode_old ^ mode_new) & 2)\r
1268 {\r
48dc74f2 1269 if (mode_old & 2)\r
6311a3ba 1270 Pico.t.timer_b_next_oflow = TIMER_NO_OFLOW;\r
0e2e188e 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
80f51a1d 1276 unsigned t = ((xcycles * (((1LL<<32)/TIMER_A_TICK_ZCYCLES)+1))>>32) + 1;\r
0e2e188e 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
43e6eaad 1280 }\r
0e2e188e 1281\r
43e6eaad 1282 if (mode_new & 2)\r
6311a3ba 1283 elprintf(EL_YMTIMER, "timer b upd to %i @ %i", Pico.t.timer_b_next_oflow>>8, z80_cycles);\r
43e6eaad 1284}\r
1285\r
4b9c5888 1286// ym2612 DAC and timer I/O handlers for z80\r
af37bca8 1287static int ym2612_write_local(u32 a, u32 d, int is_from_z80)\r
4b9c5888 1288{\r
83025d7a 1289 int cycles = is_from_z80 ? z80_cyclesDone() : z80_cycles_from_68k();\r
4b9c5888 1290 int addr;\r
1291\r
1292 a &= 3;\r
4b9c5888 1293 switch (a)\r
1294 {\r
1295 case 0: /* address port 0 */\r
225260ba 1296 case 2: /* address port 1 */\r
4b9c5888 1297 ym2612.OPN.ST.address = d;\r
225260ba 1298 ym2612.addr_A1 = (a & 2) >> 1;\r
4b9c5888 1299#ifdef __GP2X__\r
93f9619e 1300 if (PicoIn.opt & POPT_EXT_FM) YM2612Write_940(a, d, -1);\r
4b9c5888 1301#endif\r
1302 return 0;\r
1303\r
1304 case 1: /* data port 0 */\r
225260ba 1305 case 3: /* data port 1 */\r
1306 addr = ym2612.OPN.ST.address | ((int)ym2612.addr_A1 << 8);\r
4b9c5888 1307 ym2612.REGS[addr] = d;\r
1308\r
83025d7a 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
f5c022a8 1311 Pico.t.ym2612_busy = (cycles << 8) + YMBUSY_ZCYCLES; // Q8 for convenience\r
83025d7a 1312\r
4b9c5888 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
c3d70d13 1321 ym2612_sync_timers(cycles, ym2612.OPN.ST.mode, ym2612.OPN.ST.mode);\r
4b9c5888 1322 //elprintf(EL_STATUS, "timer a set %i", TAnew);\r
1323 ym2612.OPN.ST.TA = TAnew;\r
e53704e6 1324 //ym2612.OPN.ST.TAC = (1024-TAnew)*18;\r
4b9c5888 1325 //ym2612.OPN.ST.TAT = 0;\r
7263343d 1326 Pico.t.timer_a_step = TIMER_A_TICK_ZCYCLES * (1024 - TAnew);\r
6311a3ba 1327 elprintf(EL_YMTIMER, "timer a set to %i, %i", 1024 - TAnew, Pico.t.timer_a_next_oflow>>8);\r
4b9c5888 1328 }\r
1329 return 0;\r
1330 }\r
1331 case 0x26: // timer B\r
1332 if (ym2612.OPN.ST.TB != d) {\r
c3d70d13 1333 ym2612_sync_timers(cycles, ym2612.OPN.ST.mode, ym2612.OPN.ST.mode);\r
4b9c5888 1334 //elprintf(EL_STATUS, "timer b set %i", d);\r
1335 ym2612.OPN.ST.TB = d;\r
e53704e6 1336 //ym2612.OPN.ST.TBC = (256-d) * 288;\r
4b9c5888 1337 //ym2612.OPN.ST.TBT = 0;\r
7263343d 1338 Pico.t.timer_b_step = TIMER_B_TICK_ZCYCLES * (256 - d);\r
6311a3ba 1339 elprintf(EL_YMTIMER, "timer b set to %i, %i", 256 - d, Pico.t.timer_b_next_oflow>>8);\r
4b9c5888 1340 }\r
1341 return 0;\r
1342 case 0x27: { /* mode, timer control */\r
1343 int old_mode = ym2612.OPN.ST.mode;\r
6f7beab4 1344\r
43e6eaad 1345 elprintf(EL_YMTIMER, "st mode %02x", d);\r
1346 ym2612_sync_timers(cycles, old_mode, d);\r
4b9c5888 1347\r
0e2e188e 1348 ym2612.OPN.ST.mode = d;\r
1349\r
43e6eaad 1350 /* reset Timer a flag */\r
1351 if (d & 0x10)\r
1352 ym2612.OPN.ST.status &= ~1;\r
4b9c5888 1353\r
1354 /* reset Timer b flag */\r
1355 if (d & 0x20)\r
1356 ym2612.OPN.ST.status &= ~2;\r
1357\r
43e6eaad 1358 if ((d ^ old_mode) & 0xc0) {\r
4b9c5888 1359#ifdef __GP2X__\r
93f9619e 1360 if (PicoIn.opt & POPT_EXT_FM) return YM2612Write_940(a, d, get_scanline(is_from_z80));\r
4b9c5888 1361#endif\r
2e5cbf5b 1362 PsndDoFM(cycles);\r
43e6eaad 1363 return 1;\r
1364 }\r
4b9c5888 1365 return 0;\r
1366 }\r
225260ba 1367 case 0x2a: { /* DAC data */\r
225260ba 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
ccce7ee7 1371 ym2612.dacout = ((int)d - 0x80) << DAC_SHIFT;\r
225260ba 1372 return 0;\r
1373 }\r
4b9c5888 1374 case 0x2b: { /* DAC Sel (YM2612) */\r
43e14010 1375 ym2612.dacen = d & 0x80;\r
4b9c5888 1376#ifdef __GP2X__\r
43e14010 1377 if (PicoIn.opt & POPT_EXT_FM) YM2612Write_940(a, d, get_scanline(is_from_z80));\r
4b9c5888 1378#endif\r
1379 return 0;\r
1380 }\r
1381 }\r
1382 break;\r
4b9c5888 1383 }\r
1384\r
1385#ifdef __GP2X__\r
93f9619e 1386 if (PicoIn.opt & POPT_EXT_FM)\r
4b9c5888 1387 return YM2612Write_940(a, d, get_scanline(is_from_z80));\r
1388#endif\r
83025d7a 1389 PsndDoFM(cycles);\r
4b9c5888 1390 return YM2612Write_(a, d);\r
1391}\r
1392\r
453d2a6e 1393\r
553c3eaa 1394static u32 ym2612_read_local_z80(void)\r
4b9c5888 1395{\r
1396 int xcycles = z80_cyclesDone() << 8;\r
4b9c5888 1397\r
0e2e188e 1398 ym2612_update_status(xcycles);\r
43e6eaad 1399\r
6311a3ba 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
43e6eaad 1403 return ym2612.OPN.ST.status;\r
1404}\r
1405\r
af37bca8 1406static u32 ym2612_read_local_68k(void)\r
43e6eaad 1407{\r
ae214f1c 1408 int xcycles = z80_cycles_from_68k() << 8;\r
43e6eaad 1409\r
0e2e188e 1410 ym2612_update_status(xcycles);\r
43e6eaad 1411\r
6311a3ba 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
4b9c5888 1415 return ym2612.OPN.ST.status;\r
1416}\r
1417\r
5e41124a 1418// legacy code, only used for GP2X\r
bcf8175e 1419void ym2612_pack_state_old(void)\r
d2721b08 1420{\r
e53704e6 1421 // timers are saved as tick counts, in 16.16 int format\r
5e41124a 1422 int tat = 0, tbt = 0, busy = 0;\r
1423 u8 buf[16];\r
1424 size_t b = 0;\r
bcf8175e 1425\r
5e41124a 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
bcf8175e 1431\r
d2721b08 1432#ifdef __GP2X__\r
93f9619e 1433 if (PicoIn.opt & POPT_EXT_FM)\r
e4fb433c 1434 YM2612PicoStateSave2_940(tat, tbt);\r
d2721b08 1435 else\r
1436#endif\r
bcf8175e 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
5e41124a 1445\r
bcf8175e 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
ccce7ee7 1463 return b;\r
d2721b08 1464}\r
1465\r
5e41124a 1466// legacy code, only used for GP2X\r
ccce7ee7 1467void ym2612_unpack_state_old(void)\r
453d2a6e 1468{\r
ccce7ee7 1469 int i, ret, tat, tbt, busy = 0;\r
453d2a6e 1470 YM2612PicoStateLoad();\r
a16fbc10 1471 Pico.t.m68c_frame_start = SekCyclesDone();\r
453d2a6e 1472\r
1473 // feed all the registers and update internal state\r
db49317b 1474 for (i = 0x20; i < 0xA0; i++) {\r
453d2a6e 1475 ym2612_write_local(0, i, 0);\r
1476 ym2612_write_local(1, ym2612.REGS[i], 0);\r
1477 }\r
db49317b 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
453d2a6e 1491 ym2612_write_local(2, i, 0);\r
1492 ym2612_write_local(3, ym2612.REGS[i|0x100], 0);\r
1493 }\r
d2721b08 1494\r
1495#ifdef __GP2X__\r
93f9619e 1496 if (PicoIn.opt & POPT_EXT_FM)\r
e4fb433c 1497 ret = YM2612PicoStateLoad2_940(&tat, &tbt);\r
d2721b08 1498 else\r
1499#endif\r
f5c022a8 1500 ret = YM2612PicoStateLoad2(&tat, &tbt, &busy);\r
db49317b 1501 if (ret != 0) {\r
1502 elprintf(EL_STATUS, "old ym2612 state");\r
1503 return; // no saved timers\r
1504 }\r
ccce7ee7 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
e53704e6 1516\r
ccce7ee7 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
f5c022a8 1529 Pico.t.ym2612_busy = cycles_68k_to_z80(busy);\r
e53704e6 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
5d4a7fb9 1533 Pico.t.timer_a_next_oflow = (1LL * (tac-tat) * TIMER_A_TICK_ZCYCLES)>>16;\r
e53704e6 1534 else\r
6311a3ba 1535 Pico.t.timer_a_next_oflow = TIMER_NO_OFLOW;\r
e53704e6 1536 if (ym2612.OPN.ST.mode & 2)\r
5d4a7fb9 1537 Pico.t.timer_b_next_oflow = (1LL * (tbc-tbt) * TIMER_B_TICK_ZCYCLES)>>16;\r
e53704e6 1538 else\r
6311a3ba 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
453d2a6e 1542}\r
1543\r
f3a57b2d 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
cc68a136 1552// -----------------------------------------------------------------\r
1553// z80 memhandlers\r
1554\r
e0c4dac1 1555static void access_68k_bus(int delay) // bus delay as Q8\r
1556{\r
a17fb021 1557 // TODO: if the 68K is in DMA wait, Z80 has to wait until DMA ends\r
a17fb021 1558\r
e0c4dac1 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
71f9c68f 1561 Pico.t.z80_busdelay += (delay&0xff); // accumulate\r
e0c4dac1 1562 z80_subCLeft((delay>>8) + (Pico.t.z80_busdelay>>8));\r
71f9c68f 1563 Pico.t.z80_busdelay &= 0xff; // leftover cycle fraction\r
7263343d 1564 // don't use SekCyclesBurn() here since the Z80 doesn't run in cycle lock to\r
e0c4dac1 1565 // the 68K. Count the stolen cycles to be accounted later in the 68k CPU runs\r
5d4a7fb9 1566 Pico.t.z80_buscycles += 0x80; // TODO <=8.4 for Rick 2, but >=8.9 for misc_test\r
e0c4dac1 1567}\r
1568\r
553c3eaa 1569static unsigned char z80_md_vdp_read(unsigned short a)\r
cc68a136 1570{\r
133006a9 1571 if ((a & 0xff00) == 0x7f00) {\r
7263343d 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
d1b8bcc6 1574\r
75b84e4b 1575 switch (a & 0x0d)\r
1576 {\r
1613ec6c 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
75b84e4b 1581 case 0x08:\r
46b4c1d3 1582 case 0x0c: return PicoVideoGetV(get_scanline(1), 1);\r
75b84e4b 1583 case 0x09:\r
1584 case 0x0d: return Pico.m.rotate++;\r
1585 }\r
1586 }\r
b0e08dff 1587\r
c8d1e9b6 1588 elprintf(EL_ANOMALY, "z80 invalid r8 [%06x] %02x", a, 0xff);\r
1589 return 0xff;\r
1590}\r
cc68a136 1591\r
553c3eaa 1592static unsigned char z80_md_bank_read(unsigned short a)\r
c8d1e9b6 1593{\r
c8d1e9b6 1594 unsigned int addr68k;\r
a17fb021 1595 unsigned char ret = 0xff;\r
cc68a136 1596\r
7263343d 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
d1b8bcc6 1599\r
1600 addr68k = Pico.m.z80_bank68k << 15;\r
1601 addr68k |= a & 0x7fff;\r
c8d1e9b6 1602\r
a17fb021 1603 if (addr68k < 0xe00000) // can't read from 68K RAM\r
1604 ret = m68k_read8(addr68k);\r
cc68a136 1605\r
c8d1e9b6 1606 elprintf(EL_Z80BNK, "z80->68k r8 [%06x] %02x", addr68k, ret);\r
cc68a136 1607 return ret;\r
1608}\r
1609\r
553c3eaa 1610static void z80_md_ym2612_write(unsigned int a, unsigned char data)\r
cc68a136 1611{\r
93f9619e 1612 if (PicoIn.opt & POPT_EN_FM)\r
8ac9ab7f 1613 ym2612_write_local(a, data, 1);\r
c8d1e9b6 1614}\r
cc68a136 1615\r
553c3eaa 1616static void z80_md_vdp_br_write(unsigned int a, unsigned char data)\r
c8d1e9b6 1617{\r
c8d1e9b6 1618 if ((a&0xfff9) == 0x7f11) // 7f11 7f13 7f15 7f17\r
cc68a136 1619 {\r
5d638db0 1620 psg_write_z80(data);\r
cc68a136 1621 return;\r
1622 }\r
b0e08dff 1623 // at least VDP data writes hang my machine\r
cc68a136 1624\r
c8d1e9b6 1625 if ((a>>8) == 0x60)\r
cc68a136 1626 {\r
c8d1e9b6 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
cc68a136 1630 return;\r
1631 }\r
1632\r
c8d1e9b6 1633 elprintf(EL_ANOMALY, "z80 invalid w8 [%06x] %02x", a, data);\r
1634}\r
cc68a136 1635\r
553c3eaa 1636static void z80_md_bank_write(unsigned int a, unsigned char data)\r
c8d1e9b6 1637{\r
c8d1e9b6 1638 unsigned int addr68k;\r
69996cb7 1639\r
7263343d 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
134092fe 1642\r
c8d1e9b6 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
af37bca8 1647 m68k_write8(addr68k, data);\r
cc68a136 1648}\r
1649\r
c8d1e9b6 1650// -----------------------------------------------------------------\r
1651\r
1652static unsigned char z80_md_in(unsigned short p)\r
a4221917 1653{\r
c8d1e9b6 1654 elprintf(EL_ANOMALY, "Z80 port %04x read", p);\r
1655 return 0xff;\r
a4221917 1656}\r
1657\r
c8d1e9b6 1658static void z80_md_out(unsigned short p, unsigned char d)\r
cc68a136 1659{\r
c8d1e9b6 1660 elprintf(EL_ANOMALY, "Z80 port %04x write %02x", p, d);\r
cc68a136 1661}\r
c8d1e9b6 1662\r
af37bca8 1663static void z80_mem_setup(void)\r
c8d1e9b6 1664{\r
88fd63ad 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
c8d1e9b6 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
88fd63ad 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
c8d1e9b6 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
c8d1e9b6 1682 Cz80_Set_INPort(&CZ80, z80_md_in);\r
1683 Cz80_Set_OUTPort(&CZ80, z80_md_out);\r
a4221917 1684#endif\r
c8d1e9b6 1685}\r
cc68a136 1686\r
531a8f38 1687// vim:shiftwidth=2:ts=2:expandtab\r