3 * (c) Copyright Dave, 2004
\r
4 * (C) notaz, 2006-2010
\r
5 * (C) irixxxx, 2019-2024
\r
7 * This work is licensed under the terms of MAME license.
\r
8 * See COPYING file in the top-level directory.
\r
12 #include "pico_int.h"
\r
16 #include "sound/ym2612.h"
\r
17 #include "sound/sn76496.h"
\r
19 extern unsigned int lastSSRamWrite; // used by serial eeprom code
\r
21 uptr m68k_read8_map [0x1000000 >> M68K_MEM_SHIFT];
\r
22 uptr m68k_read16_map [0x1000000 >> M68K_MEM_SHIFT];
\r
23 uptr m68k_write8_map [0x1000000 >> M68K_MEM_SHIFT];
\r
24 uptr m68k_write16_map[0x1000000 >> M68K_MEM_SHIFT];
\r
26 static void xmap_set(uptr *map, int shift, u32 start_addr, u32 end_addr,
\r
27 const void *func_or_mh, int is_func)
\r
30 // workaround bug (segfault) in
\r
31 // Apple LLVM version 4.2 (clang-425.0.27) (based on LLVM 3.2svn)
\r
34 uptr addr = (uptr)func_or_mh;
\r
35 int mask = (1 << shift) - 1;
\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
45 elprintf(EL_STATUS|EL_ANOMALY, "xmap_set: ptr is not aligned: %08lx", addr);
\r
52 for (i = start_addr >> shift; i <= end_addr >> shift; i++) {
\r
59 void z80_map_set(uptr *map, u16 start_addr, u16 end_addr,
\r
60 const void *func_or_mh, int is_func)
\r
62 xmap_set(map, Z80_MEM_SHIFT, start_addr, end_addr, func_or_mh, is_func);
\r
65 Cz80_Set_Fetch(&CZ80, start_addr, end_addr, (FPTR)func_or_mh);
\r
69 void cpu68k_map_set(uptr *map, u32 start_addr, u32 end_addr,
\r
70 const void *func_or_mh, int is_func)
\r
72 xmap_set(map, M68K_MEM_SHIFT, start_addr, end_addr, func_or_mh, is_func & 1);
\r
74 // setup FAME fetchmap
\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
87 // more specialized/optimized function (does same as above)
\r
88 void cpu68k_map_read_mem(u32 start_addr, u32 end_addr, void *ptr, int is_sub)
\r
90 uptr *r8map, *r16map;
\r
91 uptr addr = (uptr)ptr;
\r
92 int shift = M68K_MEM_SHIFT;
\r
96 r8map = m68k_read8_map;
\r
97 r16map = m68k_read16_map;
\r
99 r8map = s68k_read8_map;
\r
100 r16map = s68k_read16_map;
\r
103 addr -= start_addr;
\r
105 for (i = start_addr >> shift; i <= end_addr >> shift; i++)
\r
106 r8map[i] = r16map[i] = addr;
\r
108 // setup FAME fetchmap
\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
120 void cpu68k_map_all_ram(u32 start_addr, u32 end_addr, void *ptr, int is_sub)
\r
122 uptr *r8map, *r16map, *w8map, *w16map;
\r
123 uptr addr = (uptr)ptr;
\r
124 int shift = M68K_MEM_SHIFT;
\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
133 r8map = s68k_read8_map;
\r
134 r16map = s68k_read16_map;
\r
135 w8map = s68k_write8_map;
\r
136 w16map = s68k_write16_map;
\r
139 addr -= start_addr;
\r
141 for (i = start_addr >> shift; i <= end_addr >> shift; i++)
\r
142 r8map[i] = r16map[i] = w8map[i] = w16map[i] = addr;
\r
144 // setup FAME fetchmap
\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
156 void cpu68k_map_read_funcs(u32 start_addr, u32 end_addr, u32 (*r8)(u32), u32 (*r16)(u32), int is_sub)
\r
158 uptr *r8map, *r16map;
\r
159 uptr ar8 = (uptr)r8, ar16 = (uptr)r16;
\r
160 int shift = M68K_MEM_SHIFT;
\r
164 r8map = m68k_read8_map;
\r
165 r16map = m68k_read16_map;
\r
167 r8map = s68k_read8_map;
\r
168 r16map = s68k_read16_map;
\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
177 void 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
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
186 r8map = m68k_read8_map;
\r
187 r16map = m68k_read16_map;
\r
188 w8map = m68k_write8_map;
\r
189 w16map = m68k_write16_map;
\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
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
205 u32 PicoRead16_floating(u32 a)
\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
214 static u32 m68k_unmapped_read8(u32 a)
\r
216 elprintf(EL_UIO, "m68k unmapped r8 [%06x] @%06x", a, SekPc);
\r
217 return a < 0x400000 ? 0 : (u8)PicoRead16_floating(a);
\r
220 static u32 m68k_unmapped_read16(u32 a)
\r
222 elprintf(EL_UIO, "m68k unmapped r16 [%06x] @%06x", a, SekPc);
\r
223 return a < 0x400000 ? 0 : PicoRead16_floating(a);
\r
226 static void m68k_unmapped_write8(u32 a, u32 d)
\r
228 elprintf(EL_UIO, "m68k unmapped w8 [%06x] %02x @%06x", a, d & 0xff, SekPc);
\r
231 static void m68k_unmapped_write16(u32 a, u32 d)
\r
233 elprintf(EL_UIO, "m68k unmapped w16 [%06x] %04x @%06x", a, d & 0xffff, SekPc);
\r
236 void m68k_map_unmap(u32 start_addr, u32 end_addr)
\r
239 // workaround bug (segfault) in
\r
240 // Apple LLVM version 4.2 (clang-425.0.27) (based on LLVM 3.2svn)
\r
244 int shift = M68K_MEM_SHIFT;
\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
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
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
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
264 #ifndef _ASM_MEMORY_C
\r
265 MAKE_68K_READ8(m68k_read8, m68k_read8_map)
\r
266 MAKE_68K_READ16(m68k_read16, m68k_read16_map)
\r
267 MAKE_68K_READ32(m68k_read32, m68k_read16_map)
\r
268 MAKE_68K_WRITE8(m68k_write8, m68k_write8_map)
\r
269 MAKE_68K_WRITE16(m68k_write16, m68k_write16_map)
\r
270 MAKE_68K_WRITE32(m68k_write32, m68k_write16_map)
\r
273 // -----------------------------------------------------------------
\r
275 static u32 ym2612_read_local_68k(void);
\r
276 static int ym2612_write_local(u32 a, u32 d, int is_from_z80);
\r
277 static void z80_mem_setup(void);
\r
279 #ifdef _ASM_MEMORY_C
\r
280 u32 PicoRead8_sram(u32 a);
\r
281 u32 PicoRead16_sram(u32 a);
\r
284 #ifdef EMU_CORE_DEBUG
\r
285 u32 lastread_a, lastread_d[16]={0,}, lastwrite_cyc_d[16]={0,}, lastwrite_mus_d[16]={0,};
\r
286 int lrp_cyc=0, lrp_mus=0, lwp_cyc=0, lwp_mus=0;
\r
287 extern unsigned int ppop;
\r
291 void log_io(unsigned int addr, int bits, int rw);
\r
292 #elif defined(_MSC_VER)
\r
295 #define log_io(...)
\r
298 #if defined(EMU_C68K)
\r
299 u32 cyclone_crashed(u32 pc, struct Cyclone *context)
\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
311 context->membase = (u32)Pico.rom;
\r
312 context->pc = (u32)Pico.rom + pc24;
\r
314 return context->pc;
\r
318 // -----------------------------------------------------------------
\r
321 static u32 read_pad_3btn(int i, u32 out_bits)
\r
323 u32 pad = ~PicoIn.padInt[i]; // Get inverse of pad MXYZ SACB RLDU
\r
326 if (out_bits & 0x40) // TH
\r
327 value = pad & 0x3f; // ?1CB RLDU
\r
329 value = ((pad & 0xc0) >> 2) | (pad & 3); // ?0SA 00DU
\r
331 value |= out_bits & 0x40;
\r
335 static u32 read_pad_6btn(int i, u32 out_bits)
\r
337 u32 pad = ~PicoIn.padInt[i]; // Get inverse of pad MXYZ SACB RLDU
\r
338 int phase = Pico.m.padTHPhase[i];
\r
341 if (phase == 2 && !(out_bits & 0x40)) {
\r
342 value = (pad & 0xc0) >> 2; // ?0SA 0000
\r
345 else if (phase == 3) {
\r
346 if (out_bits & 0x40)
\r
347 value = (pad & 0x30) | ((pad >> 8) & 0xf); // ?1CB MXYZ
\r
349 value = ((pad & 0xc0) >> 2) | 0x0f; // ?0SA 1111
\r
353 if (out_bits & 0x40) // TH
\r
354 value = pad & 0x3f; // ?1CB RLDU
\r
356 value = ((pad & 0xc0) >> 2) | (pad & 3); // ?0SA 00DU
\r
359 value |= out_bits & 0x40;
\r
363 static u32 read_pad_team(int i, u32 out_bits)
\r
366 int phase = Pico.m.padTHPhase[i];
\r
376 case 4: case 5: case 6: case 7: // controller IDs, all 3 btn for now
\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
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
392 value |= (out_bits & 0x40) | ((out_bits & 0x20)>>1);
\r
396 static u32 read_pad_4way(int i, u32 out_bits)
\r
398 u32 pad = (PicoMem.ioports[2] & 0x70) >> 4;
\r
401 if (i == 0 && pad <= 3)
\r
402 value = read_pad_3btn(pad, out_bits);
\r
404 value |= (out_bits & 0x40);
\r
408 static u32 read_pad_mouse(int i, u32 out_bits)
\r
410 int phase = Pico.m.padTHPhase[i];
\r
413 int x = PicoIn.mouseInt[0] - PicoIn.mouseInt[2];
\r
414 int y = PicoIn.mouseInt[3] - PicoIn.mouseInt[1];
\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
431 // latch current mouse position during readout
\r
432 PicoIn.mouseInt[0] = PicoIn.mouse[0];
\r
433 PicoIn.mouseInt[1] = PicoIn.mouse[1];
\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
439 value = (PicoIn.padInt[i] & 0xf0) >> 4; // SMRL, mapped from SACB
\r
441 case 6: // high nibble of x
\r
442 value = (x>>4) & 0xf;
\r
444 case 7: // low nibble of x
\r
447 case 8: // high nibble of y
\r
448 value = (y>>4) & 0xf;
\r
450 case 9: // low nibble of y
\r
451 default: // also sent on all later phases
\r
456 value |= (out_bits & 0x40) | ((out_bits & 0x20)>>1);
\r
460 static u32 read_nothing(int i, u32 out_bits)
\r
465 typedef u32 (port_read_func)(int index, u32 out_bits);
\r
467 static port_read_func *port_readers[3] = {
\r
473 static int padTHLatency[3];
\r
474 static int padTLLatency[3];
\r
476 static NOINLINE u32 port_read(int i)
\r
478 u32 data_reg = PicoMem.ioports[i + 1];
\r
479 u32 ctrl_reg = PicoMem.ioports[i + 4] | 0x80;
\r
482 out = data_reg & ctrl_reg;
\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
489 if (CYCLES_GE(SekCyclesDone(), padTHLatency[i])) {
\r
491 padTHLatency[i] = SekCyclesDone();
\r
493 out |= mask & ~ctrl_reg;
\r
495 in = port_readers[i](i, out);
\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
504 return (in & ~ctrl_reg) | (data_reg & ctrl_reg);
\r
507 // pad export for J-Cart
\r
508 u32 PicoReadPad(int i, u32 out_bits)
\r
510 return read_pad_3btn(i, out_bits);
\r
513 void PicoSetInputDevice(int port, enum input_device device)
\r
515 port_read_func *func;
\r
517 if (port < 0 || port > 2)
\r
520 if (port == 1 && port_readers[0] == read_pad_team)
\r
521 func = read_nothing;
\r
523 else switch (device) {
\r
524 case PICO_INPUT_PAD_3BTN:
\r
525 func = read_pad_3btn;
\r
528 case PICO_INPUT_PAD_6BTN:
\r
529 func = read_pad_6btn;
\r
532 case PICO_INPUT_PAD_TEAM:
\r
533 func = read_pad_team;
\r
536 case PICO_INPUT_PAD_4WAY:
\r
537 func = read_pad_4way;
\r
540 case PICO_INPUT_MOUSE:
\r
541 func = read_pad_mouse;
\r
545 func = read_nothing;
\r
549 port_readers[port] = func;
\r
552 NOINLINE u32 io_ports_read(u32 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
566 NOINLINE void io_ports_write(u32 a, u32 d)
\r
570 // for some controllers, changing TH/TR changes controller state
\r
571 if (1 <= a && a <= 2)
\r
573 Pico.m.padDelay[a - 1] = 0;
\r
574 if (port_readers[a - 1] == read_pad_team) {
\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
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
596 } else if (!(PicoMem.ioports[a] & 0x40) && (d & 0x40))
\r
597 Pico.m.padTHPhase[a - 1]++;
\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
608 // certain IO ports can be used as RAM
\r
609 PicoMem.ioports[a] = d;
\r
612 int io_ports_pack(void *buf, size_t size)
\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
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
632 void io_ports_unpack(const void *buf, size_t size)
\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
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
651 static int z80_cycles_from_68k(void)
\r
653 int m68k_cnt = SekCyclesDone() - Pico.t.m68c_frame_start;
\r
654 return cycles_68k_to_z80(m68k_cnt);
\r
657 void NOINLINE ctl_write_z80busreq(u32 d)
\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
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
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
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
687 void NOINLINE ctl_write_z80reset(u32 d)
\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
695 if ((PicoIn.opt & POPT_EN_Z80) && Pico.m.z80Run) {
\r
697 PicoSyncZ80(SekCyclesDone());
\r
698 pprof_end_sub(m68k);
\r
700 Pico.t.z80_busdelay &= 0xff; // also resets bus request
\r
706 Pico.t.z80c_aim = Pico.t.z80c_cnt = z80_cycles_from_68k() + 2;
\r
709 Pico.m.z80_reset = d;
\r
713 static void psg_write_68k(u32 d)
\r
715 PsndDoPSG(z80_cycles_from_68k());
\r
719 static void psg_write_z80(u32 d)
\r
721 PsndDoPSG(z80_cyclesDone());
\r
725 // -----------------------------------------------------------------
\r
727 #ifndef _ASM_MEMORY_C
\r
729 // cart (save) RAM area (usually 0x200000 - ...)
\r
730 static u32 PicoRead8_sram(u32 a)
\r
733 if (Pico.sv.start <= a && a <= Pico.sv.end && (Pico.m.sram_reg & SRR_MAPPED))
\r
735 if (Pico.sv.flags & SRF_EEPROM) {
\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
746 // XXX: this is banking unfriendly
\r
747 if (a < Pico.romsize)
\r
748 return Pico.rom[MEM_BE2(a)];
\r
750 return m68k_unmapped_read8(a);
\r
753 static u32 PicoRead16_sram(u32 a)
\r
756 if (Pico.sv.start <= a && a <= Pico.sv.end && (Pico.m.sram_reg & SRR_MAPPED))
\r
758 if (Pico.sv.flags & SRF_EEPROM)
\r
761 u8 *pm = (u8 *)(Pico.sv.data - Pico.sv.start + a);
\r
765 elprintf(EL_SRAMIO, "sram r16 [%06x] %04x @ %06x", a, d, SekPc);
\r
769 if (a < Pico.romsize)
\r
770 return *(u16 *)(Pico.rom + a);
\r
772 return m68k_unmapped_read16(a);
\r
775 #endif // _ASM_MEMORY_C
\r
777 static void PicoWrite8_sram(u32 a, u32 d)
\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
784 elprintf(EL_SRAMIO, "sram w8 [%06x] %02x @ %06x", a, d & 0xff, SekPc);
\r
785 if (Pico.sv.flags & SRF_EEPROM)
\r
787 EEPROM_write8(a, d);
\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
798 static void PicoWrite16_sram(u32 a, u32 d)
\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
805 elprintf(EL_SRAMIO, "sram w16 [%06x] %04x @ %06x", a, d & 0xffff, SekPc);
\r
806 if (Pico.sv.flags & SRF_EEPROM)
\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
816 if (pm[1] != (u8)d) {
\r
817 Pico.sv.changed = 1;
\r
823 // z80 area (0xa00000 - 0xa0ffff)
\r
824 // TODO: verify mirrors VDP and bank reg (bank area mirroring verified)
\r
825 static u32 PicoRead8_z80(u32 a)
\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
833 SekCyclesBurnRun(1);
\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
840 elprintf(EL_UIO|EL_ANOMALY, "68k bad read [%06x] @%06x", a, SekPc);
\r
841 d = (u8)PicoRead16_floating(a);
\r
846 static u32 PicoRead16_z80(u32 a)
\r
848 u32 d = PicoRead8_z80(a);
\r
849 return d | (d << 8);
\r
852 static void PicoWrite8_z80(u32 a, u32 d)
\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
859 SekCyclesBurnRun(1);
\r
861 if ((a & 0x4000) == 0x0000) { // z80 RAM
\r
862 PicoMem.zram[a & 0x1fff] = (u8)d;
\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
870 // TODO: probably other VDP access too? Maybe more mirrors?
\r
871 if ((a & 0x7ff9) == 0x7f11) { // PSG Sound
\r
875 if ((a & 0x7f00) == 0x6000) // Z80 BANK register
\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
883 elprintf(EL_UIO|EL_ANOMALY, "68k bad write [%06x] %02x @ %06x", a, d&0xff, SekPc);
\r
886 static void PicoWrite16_z80(u32 a, u32 d)
\r
888 // for RAM, only most significant byte is sent
\r
889 // TODO: verify remaining accesses
\r
890 PicoWrite8_z80(a, d >> 8);
\r
893 #ifndef _ASM_MEMORY_C
\r
895 // IO/control area (0xa10000 - 0xa1ffff)
\r
896 u32 PicoRead8_io(u32 a)
\r
900 if ((a & 0xffe0) == 0x0000) { // I/O ports
\r
901 d = io_ports_read(a);
\r
905 if ((a & 0xfc00) == 0x1000) {
\r
906 d = (u8)PicoRead16_floating(a);
\r
908 if ((a & 0xff01) == 0x1100) { // z80 busreq (verified)
\r
909 // bit8 seems to be readable in this range
\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
921 d = PicoRead8_32x(a);
\r
927 u32 PicoRead16_io(u32 a)
\r
931 if ((a & 0xffe0) == 0x0000) { // I/O ports
\r
932 d = io_ports_read(a);
\r
937 // bit8 seems to be readable in this range
\r
938 if ((a & 0xfc00) == 0x1000) {
\r
939 d = PicoRead16_floating(a);
\r
941 if ((a & 0xff00) == 0x1100) { // z80 busreq
\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
950 d = PicoRead16_32x(a);
\r
956 void PicoWrite8_io(u32 a, u32 d)
\r
958 if ((a & 0xffe1) == 0x0001) { // I/O ports (verified: only LSB!)
\r
959 io_ports_write(a, d);
\r
962 if ((a & 0xff01) == 0x1100) { // z80 busreq
\r
963 ctl_write_z80busreq(d);
\r
966 if ((a & 0xff01) == 0x1200) { // z80 reset
\r
967 ctl_write_z80reset(d);
\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
976 PicoWrite8_32x(a, d);
\r
979 void PicoWrite16_io(u32 a, u32 d)
\r
981 if ((a & 0xffe0) == 0x0000) { // I/O ports (verified: only LSB!)
\r
982 io_ports_write(a, d);
\r
985 if ((a & 0xff00) == 0x1100) { // z80 busreq
\r
986 ctl_write_z80busreq(d >> 8);
\r
989 if ((a & 0xff00) == 0x1200) { // z80 reset
\r
990 ctl_write_z80reset(d >> 8);
\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
999 PicoWrite16_32x(a, d);
\r
1002 #endif // _ASM_MEMORY_C
\r
1004 // VDP area (0xc00000 - 0xdfffff)
\r
1005 // TODO: verify if lower byte goes to PSG on word writes
\r
1006 u32 PicoRead8_vdp(u32 a)
\r
1009 if ((a & 0x00f0) == 0x0000) {
\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
1017 case 0x0c: d = PicoVideoRead8HV_H(0); break;
\r
1019 case 0x0d: d = PicoVideoRead8HV_L(0); break;
\r
1020 default: d = (u8)PicoRead16_floating(a); break;
\r
1023 elprintf(EL_UIO|EL_ANOMALY, "68k bad read [%06x] @%06x", a, SekPc);
\r
1024 d = (u8)PicoRead16_floating(a);
\r
1029 static u32 PicoRead16_vdp(u32 a)
\r
1031 if ((a & 0x00e0) == 0x0000)
\r
1032 return PicoVideoRead(a);
\r
1034 elprintf(EL_UIO|EL_ANOMALY, "68k bad read [%06x] @%06x", a, SekPc);
\r
1038 static void PicoWrite8_vdp(u32 a, u32 d)
\r
1040 if ((a & 0x00f9) == 0x0011) { // PSG Sound
\r
1044 if ((a & 0x00e0) == 0x0000) {
\r
1046 PicoVideoWrite(a, d | (d << 8));
\r
1050 elprintf(EL_UIO|EL_ANOMALY, "68k bad write [%06x] %02x @%06x", a, d & 0xff, SekPc);
\r
1053 static void PicoWrite16_vdp(u32 a, u32 d)
\r
1055 if ((a & 0x00f9) == 0x0010) { // PSG Sound
\r
1059 if ((a & 0x00e0) == 0x0000) {
\r
1060 PicoVideoWrite(a, d);
\r
1064 elprintf(EL_UIO|EL_ANOMALY, "68k bad write [%06x] %04x @%06x", a, d & 0xffff, SekPc);
\r
1067 // -----------------------------------------------------------------
\r
1070 static void m68k_mem_setup(void);
\r
1073 PICO_INTERNAL void PicoMemSetup(void)
\r
1075 int mask, rs, sstart, a;
\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
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
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
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
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
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
1119 for (a = 0xc00000; a < 0xe00000; a += 0x010000) {
\r
1120 if ((a & 0xe700e0) != 0xc00000)
\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
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
1136 // Setup memory callbacks:
\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
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
1165 unsigned int (*pm68k_read_memory_8) (unsigned int address) = NULL;
\r
1166 unsigned int (*pm68k_read_memory_16)(unsigned int address) = NULL;
\r
1167 unsigned int (*pm68k_read_memory_32)(unsigned int address) = NULL;
\r
1168 void (*pm68k_write_memory_8) (unsigned int address, unsigned char value) = NULL;
\r
1169 void (*pm68k_write_memory_16)(unsigned int address, unsigned short value) = NULL;
\r
1170 void (*pm68k_write_memory_32)(unsigned int address, unsigned int value) = NULL;
\r
1172 /* it appears that Musashi doesn't always mask the unused bits */
\r
1173 unsigned int m68k_read_memory_8 (unsigned int address) { return pm68k_read_memory_8 (address) & 0xff; }
\r
1174 unsigned int m68k_read_memory_16(unsigned int address) { return pm68k_read_memory_16(address) & 0xffff; }
\r
1175 unsigned int m68k_read_memory_32(unsigned int address) { return pm68k_read_memory_32(address); }
\r
1176 void m68k_write_memory_8 (unsigned int address, unsigned int value) { pm68k_write_memory_8 (address, (u8)value); }
\r
1177 void m68k_write_memory_16(unsigned int address, unsigned int value) { pm68k_write_memory_16(address,(u16)value); }
\r
1178 void m68k_write_memory_32(unsigned int address, unsigned int value) { pm68k_write_memory_32(address, value); }
\r
1180 static void m68k_mem_setup(void)
\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
1189 #endif // EMU_M68K
\r
1192 // -----------------------------------------------------------------
\r
1194 static int get_scanline(int is_from_z80)
\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
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
1218 return Pico.m.scanline;
\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
1229 /* probably should not be in this file, but it's near related code here */
\r
1230 void ym2612_sync_timers(int z80_cycles, int mode_old, int mode_new)
\r
1232 int xcycles = z80_cycles << 8;
\r
1234 // update timer status
\r
1235 ym2612_update_status(xcycles);
\r
1239 while (xcycles >= Pico.t.timer_a_next_oflow)
\r
1240 Pico.t.timer_a_next_oflow += Pico.t.timer_a_step;
\r
1243 if ((mode_old ^ mode_new) & 1)
\r
1246 Pico.t.timer_a_next_oflow = TIMER_NO_OFLOW;
\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
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
1259 elprintf(EL_YMTIMER, "timer a upd to %i @ %i", Pico.t.timer_a_next_oflow>>8, z80_cycles);
\r
1263 while (xcycles >= Pico.t.timer_b_next_oflow)
\r
1264 Pico.t.timer_b_next_oflow += Pico.t.timer_b_step;
\r
1267 if ((mode_old ^ mode_new) & 2)
\r
1270 Pico.t.timer_b_next_oflow = TIMER_NO_OFLOW;
\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
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
1283 elprintf(EL_YMTIMER, "timer b upd to %i @ %i", Pico.t.timer_b_next_oflow>>8, z80_cycles);
\r
1286 // ym2612 DAC and timer I/O handlers for z80
\r
1287 static int ym2612_write_local(u32 a, u32 d, int is_from_z80)
\r
1289 int cycles = is_from_z80 ? z80_cyclesDone() : z80_cycles_from_68k();
\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
1300 if (PicoIn.opt & POPT_EXT_FM) YM2612Write_940(a, d, -1);
\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
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
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
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
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
1342 case 0x27: { /* mode, timer control */
\r
1343 int old_mode = ym2612.OPN.ST.mode;
\r
1345 elprintf(EL_YMTIMER, "st mode %02x", d);
\r
1346 ym2612_sync_timers(cycles, old_mode, d);
\r
1348 ym2612.OPN.ST.mode = d;
\r
1350 /* reset Timer a flag */
\r
1352 ym2612.OPN.ST.status &= ~1;
\r
1354 /* reset Timer b flag */
\r
1356 ym2612.OPN.ST.status &= ~2;
\r
1358 if ((d ^ old_mode) & 0xc0) {
\r
1360 if (PicoIn.opt & POPT_EXT_FM) return YM2612Write_940(a, d, get_scanline(is_from_z80));
\r
1367 case 0x2a: { /* DAC data */
\r
1368 //elprintf(EL_STATUS, "%03i dac w %08x z80 %i", cycles, d, is_from_z80);
\r
1370 PsndDoDAC(cycles);
\r
1371 ym2612.dacout = ((int)d - 0x80) << DAC_SHIFT;
\r
1374 case 0x2b: { /* DAC Sel (YM2612) */
\r
1375 ym2612.dacen = d & 0x80;
\r
1377 if (PicoIn.opt & POPT_EXT_FM) YM2612Write_940(a, d, get_scanline(is_from_z80));
\r
1386 if (PicoIn.opt & POPT_EXT_FM)
\r
1387 return YM2612Write_940(a, d, get_scanline(is_from_z80));
\r
1390 return YM2612Write_(a, d);
\r
1394 static u32 ym2612_read_local_z80(void)
\r
1396 int xcycles = z80_cyclesDone() << 8;
\r
1398 ym2612_update_status(xcycles);
\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
1406 static u32 ym2612_read_local_68k(void)
\r
1408 int xcycles = z80_cycles_from_68k() << 8;
\r
1410 ym2612_update_status(xcycles);
\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
1418 // legacy code, only used for GP2X
\r
1419 void ym2612_pack_state_old(void)
\r
1421 // timers are saved as tick counts, in 16.16 int format
\r
1422 int tat = 0, tbt = 0, busy = 0;
\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
1433 if (PicoIn.opt & POPT_EXT_FM)
\r
1434 YM2612PicoStateSave2_940(tat, tbt);
\r
1437 YM2612PicoStateSave2(tat, tbt, busy);
\r
1440 int ym2612_pack_timers(void *buf, size_t size)
\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
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
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
1466 // legacy code, only used for GP2X
\r
1467 void ym2612_unpack_state_old(void)
\r
1469 int i, ret, tat, tbt, busy = 0;
\r
1470 YM2612PicoStateLoad();
\r
1471 Pico.t.m68c_frame_start = SekCyclesDone();
\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
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
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
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
1496 if (PicoIn.opt & POPT_EXT_FM)
\r
1497 ret = YM2612PicoStateLoad2_940(&tat, &tbt);
\r
1500 ret = YM2612PicoStateLoad2(&tat, &tbt, &busy);
\r
1502 elprintf(EL_STATUS, "old ym2612 state");
\r
1503 return; // no saved timers
\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
1517 void ym2612_unpack_timers(const void *buf, size_t size)
\r
1519 int tac, tat, tbc, tbt, busy;
\r
1521 assert(size >= 16);
\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
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
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
1544 #if defined(NO_32X) && defined(_ASM_MEMORY_C)
\r
1545 // referenced by asm code
\r
1546 u32 PicoRead8_32x(u32 a) { return 0; }
\r
1547 u32 PicoRead16_32x(u32 a) { return 0; }
\r
1548 void PicoWrite8_32x(u32 a, u32 d) {}
\r
1549 void PicoWrite16_32x(u32 a, u32 d) {}
\r
1552 // -----------------------------------------------------------------
\r
1553 // z80 memhandlers
\r
1555 static void access_68k_bus(int delay) // bus delay as Q8
\r
1557 // TODO: if the 68K is in DMA wait, Z80 has to wait until DMA ends
\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
1569 static unsigned char z80_md_vdp_read(unsigned short a)
\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
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
1582 case 0x0c: return PicoVideoGetV(get_scanline(1), 1);
\r
1584 case 0x0d: return Pico.m.rotate++;
\r
1588 elprintf(EL_ANOMALY, "z80 invalid r8 [%06x] %02x", a, 0xff);
\r
1592 static unsigned char z80_md_bank_read(unsigned short a)
\r
1594 unsigned int addr68k;
\r
1595 unsigned char ret = 0xff;
\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
1600 addr68k = Pico.m.z80_bank68k << 15;
\r
1601 addr68k |= a & 0x7fff;
\r
1603 if (addr68k < 0xe00000) // can't read from 68K RAM
\r
1604 ret = m68k_read8(addr68k);
\r
1606 elprintf(EL_Z80BNK, "z80->68k r8 [%06x] %02x", addr68k, ret);
\r
1610 static void z80_md_ym2612_write(unsigned int a, unsigned char data)
\r
1612 if (PicoIn.opt & POPT_EN_FM)
\r
1613 ym2612_write_local(a, data, 1);
\r
1616 static void z80_md_vdp_br_write(unsigned int a, unsigned char data)
\r
1618 if ((a&0xfff9) == 0x7f11) // 7f11 7f13 7f15 7f17
\r
1620 psg_write_z80(data);
\r
1623 // at least VDP data writes hang my machine
\r
1625 if ((a>>8) == 0x60)
\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
1633 elprintf(EL_ANOMALY, "z80 invalid w8 [%06x] %02x", a, data);
\r
1636 static void z80_md_bank_write(unsigned int a, unsigned char data)
\r
1638 unsigned int addr68k;
\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
1643 addr68k = Pico.m.z80_bank68k << 15;
\r
1644 addr68k += a & 0x7fff;
\r
1646 elprintf(EL_Z80BNK, "z80->68k w8 [%06x] %02x", addr68k, data);
\r
1647 m68k_write8(addr68k, data);
\r
1650 // -----------------------------------------------------------------
\r
1652 static unsigned char z80_md_in(unsigned short p)
\r
1654 elprintf(EL_ANOMALY, "Z80 port %04x read", p);
\r
1658 static void z80_md_out(unsigned short p, unsigned char d)
\r
1660 elprintf(EL_ANOMALY, "Z80 port %04x write %02x", p, d);
\r
1663 static void z80_mem_setup(void)
\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
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
1678 drZ80.z80_in = z80_md_in;
\r
1679 drZ80.z80_out = z80_md_out;
\r
1682 Cz80_Set_INPort(&CZ80, z80_md_in);
\r
1683 Cz80_Set_OUTPort(&CZ80, z80_md_out);
\r
1687 // vim:shiftwidth=2:ts=2:expandtab
\r