static void SekIntAckF68K(unsigned level) { if (level == 4) { Pico.video.pending_ints = 0; elprintf(EL_INTS, "hack: @ %06x [%i]", SekPc, SekCyclesDone()); } else if(level == 6) { Pico.video.pending_ints &= ~0x20; elprintf(EL_INTS, "vack: @ %06x [%i]", SekPc, SekCyclesDone()); } PicoCpuFM68k.interrupts[0] = 0; }
static #endif u32 z80ReadBusReq(void) { u32 d=Pico.m.z80Run&1; if (!d && Pico.m.scanline != -1) { // needed by buggy Terminator (Sega CD) int stop_before = SekCyclesDone() - z80stopCycle; //elprintf(EL_BUSREQ, "get_zrun: stop before: %i", stop_before); // note: if we use 20 or more here, Barkley Shut Up and Jam! will purposedly crash itself. // but CD Terminator needs at least 32, so it only works because next frame cycle wrap. if (stop_before > 0 && stop_before < 20) // Gens uses 16 here d = 1; // bus not yet available } // |=0x80 for Shadow of the Beast & Super Offroad elprintf(EL_BUSREQ, "get_zrun: %02x [%i] @%06x", d|0x80, SekCyclesDone(), SekPc); return d|0x80; }
static int do_ack(int level) { struct PicoVideo *pv = &Pico.video; elprintf(EL_INTS, "%cack: @ %06x [%u], p=%02x", level == 6 ? 'v' : 'h', SekPc, SekCyclesDone(), pv->pending_ints); // the VDP doesn't look at the 68k level if (pv->pending_ints & pv->reg[1] & 0x20) { pv->pending_ints &= ~0x20; pv->status &= ~SR_F; return (pv->reg[0] & pv->pending_ints & 0x10) >> 2; }
static u32 p32x_reg_read16(u32 a) { a &= 0x3e; #if 0 if ((a & 0x30) == 0x20) return sh2_comm_faker(a); #else if ((a & 0x30) == 0x20) { unsigned int cycles = SekCyclesDone(); int comreg = 1 << (a & 0x0f) / 2; if (cycles - msh2.m68krcycles_done > 244 || (Pico32x.comm_dirty_68k & comreg)) p32x_sync_sh2s(cycles); if (Pico32x.comm_dirty_sh2 & comreg) Pico32x.comm_dirty_sh2 &= ~comreg; else if (m68k_poll_detect(a, cycles, P32XF_68KCPOLL)) { SekSetStop(1); SekEndRun(16); } goto out; } #endif if (a == 2) { // INTM, INTS unsigned int cycles = SekCyclesDone(); if (cycles - msh2.m68krcycles_done > 64) p32x_sync_sh2s(cycles); goto out; } if ((a & 0x30) == 0x30) return p32x_pwm_read16(a, NULL, SekCyclesDone()); out: return Pico32x.regs[a / 2]; }
void p32x_pwm_update(int *buf32, int length, int stereo) { short *pwmb; int step; int p = 0; int xmd; consume_fifo(NULL, SekCyclesDone()); xmd = Pico32x.regs[0x30 / 2] & 0x0f; if (xmd == 0 || xmd == 0x06 || xmd == 0x09 || xmd == 0x0f) goto out; // invalid? if (pwm_silent) return; step = (pwm_ptr << 16) / length; pwmb = Pico32xMem->pwm; if (stereo) { if (xmd == 0x05) { // normal while (length-- > 0) { *buf32++ += pwmb[0]; *buf32++ += pwmb[1]; p += step; pwmb += (p >> 16) * 2; p &= 0xffff; } } else if (xmd == 0x0a) { // channel swap while (length-- > 0) { *buf32++ += pwmb[1]; *buf32++ += pwmb[0]; p += step; pwmb += (p >> 16) * 2; p &= 0xffff; } } else { // mono - LMD, RMD specify dst if (xmd & 0x06) // src is R
static #endif void z80WriteBusReq(u32 d) { d&=1; d^=1; { if (!d) { // this is for a nasty situation where Z80 was enabled and disabled in the same 68k timeslice (Golden Axe III) if (Pico.m.z80Run) { int lineCycles; z80stopCycle = SekCyclesDone(); if ((Pico.m.z80Run&2) && Pico.m.scanline != -1) lineCycles=(488-SekCyclesLeft)&0x1ff; else lineCycles=z80stopCycle-z80startCycle; // z80 was started at current line if (lineCycles > 0) { // && lineCycles <= 488) { //dprintf("zrun: %i/%i cycles", lineCycles, (lineCycles>>1)-(lineCycles>>5)); lineCycles=(lineCycles>>1)-(lineCycles>>5); z80_run_nr(lineCycles); } } } else {
static void dreq0_write(u16 *r, u32 d) { if (!(r[6 / 2] & P32XS_68S)) { elprintf(EL_32X|EL_ANOMALY, "DREQ FIFO w16 without 68S?"); return; // ignored - tested } if (Pico32x.dmac0_fifo_ptr < DMAC_FIFO_LEN) { Pico32x.dmac_fifo[Pico32x.dmac0_fifo_ptr++] = d; if (Pico32x.dmac0_fifo_ptr == DMAC_FIFO_LEN) r[6 / 2] |= P32XS_FULL; // tested: len register decrements and 68S clears // even if SH2s/DMAC aren't active.. r[0x10 / 2]--; if (r[0x10 / 2] == 0) r[6 / 2] &= ~P32XS_68S; if ((Pico32x.dmac0_fifo_ptr & 3) == 0) { p32x_sync_sh2s(SekCyclesDone()); p32x_dreq0_trigger(); } } else elprintf(EL_32X|EL_ANOMALY, "DREQ FIFO overflow!"); }
static void p32x_reg_write16(u32 a, u32 d) { u16 *r = Pico32x.regs; a &= 0x3e; // for things like bset on comm port m68k_poll.cnt = 0; switch (a) { case 0x00: // adapter ctl if ((d ^ r[0]) & d & P32XS_nRES) p32x_reset_sh2s(); r[0] &= ~(P32XS_FM|P32XS_nRES|P32XS_ADEN); r[0] |= d & (P32XS_FM|P32XS_nRES|P32XS_ADEN); return; case 0x08: // DREQ src r[a / 2] = d & 0xff; return; case 0x0a: r[a / 2] = d & ~1; return; case 0x0c: // DREQ dest r[a / 2] = d & 0xff; return; case 0x0e: r[a / 2] = d; return; case 0x10: // DREQ len r[a / 2] = d & ~3; return; case 0x12: // FIFO reg dreq0_write(r, d); return; case 0x1a: // TV + mystery bit r[a / 2] = d & 0x0101; return; case 0x30: // PWM control d = (r[a / 2] & ~0x0f) | (d & 0x0f); r[a / 2] = d; p32x_pwm_write16(a, d, NULL, SekCyclesDone()); return; } // comm port if ((a & 0x30) == 0x20) { int cycles = SekCyclesDone(); int comreg; if (r[a / 2] == d) return; comreg = 1 << (a & 0x0f) / 2; if (Pico32x.comm_dirty_68k & comreg) p32x_sync_sh2s(cycles); r[a / 2] = d; p32x_sh2_poll_event(&sh2s[0], SH2_STATE_CPOLL, cycles); p32x_sh2_poll_event(&sh2s[1], SH2_STATE_CPOLL, cycles); Pico32x.comm_dirty_68k |= comreg; if (cycles - (int)msh2.m68krcycles_done > 120) p32x_sync_sh2s(cycles); return; } // PWM else if ((a & 0x30) == 0x30) { p32x_pwm_write16(a, d, NULL, SekCyclesDone()); return; } p32x_reg_write8(a + 1, d); }
// writable bits tested static void p32x_reg_write8(u32 a, u32 d) { u16 *r = Pico32x.regs; a &= 0x3f; // for things like bset on comm port m68k_poll.cnt = 0; switch (a) { case 0x00: // adapter ctl: FM writable REG8IN16(r, 0x00) = d & 0x80; return; case 0x01: // adapter ctl: RES and ADEN writable if ((d ^ r[0]) & d & P32XS_nRES) p32x_reset_sh2s(); REG8IN16(r, 0x01) &= ~(P32XS_nRES|P32XS_ADEN); REG8IN16(r, 0x01) |= d & (P32XS_nRES|P32XS_ADEN); return; case 0x02: // ignored, always 0 return; case 0x03: // irq ctl if ((d ^ r[0x02 / 2]) & 3) { int cycles = SekCyclesDone(); p32x_sync_sh2s(cycles); r[0x02 / 2] = d & 3; p32x_update_cmd_irq(NULL, cycles); } return; case 0x04: // ignored, always 0 return; case 0x05: // bank d &= 3; if (r[0x04 / 2] != d) { r[0x04 / 2] = d; bank_switch(d); } return; case 0x06: // ignored, always 0 return; case 0x07: // DREQ ctl REG8IN16(r, 0x07) &= ~(P32XS_68S|P32XS_DMA|P32XS_RV); if (!(d & P32XS_68S)) { Pico32x.dmac0_fifo_ptr = 0; REG8IN16(r, 0x07) &= ~P32XS_FULL; } REG8IN16(r, 0x07) |= d & (P32XS_68S|P32XS_DMA|P32XS_RV); return; case 0x08: // ignored, always 0 return; case 0x09: // DREQ src REG8IN16(r, 0x09) = d; return; case 0x0a: REG8IN16(r, 0x0a) = d; return; case 0x0b: REG8IN16(r, 0x0b) = d & 0xfe; return; case 0x0c: // ignored, always 0 return; case 0x0d: // DREQ dest case 0x0e: case 0x0f: case 0x10: // DREQ len REG8IN16(r, a) = d; return; case 0x11: REG8IN16(r, a) = d & 0xfc; return; // DREQ FIFO - writes to odd addr go to fifo // do writes to even work? Reads return 0 case 0x12: REG8IN16(r, a) = d; return; case 0x13: d = (REG8IN16(r, 0x12) << 8) | (d & 0xff); REG8IN16(r, 0x12) = 0; dreq0_write(r, d); return; case 0x14: // ignored, always 0 case 0x15: case 0x16: case 0x17: case 0x18: case 0x19: return; case 0x1a: // what's this? elprintf(EL_32X|EL_ANOMALY, "mystery w8 %02x %02x", a, d); REG8IN16(r, a) = d & 0x01; return; case 0x1b: // TV REG8IN16(r, a) = d & 0x01; return; case 0x1c: // ignored, always 0 case 0x1d: case 0x1e: case 0x1f: case 0x30: return; case 0x31: // PWM control REG8IN16(r, a) &= ~0x0f; REG8IN16(r, a) |= d & 0x0f; d = r[0x30 / 2]; goto pwm_write; case 0x32: // PWM cycle REG8IN16(r, a) = d & 0x0f; d = r[0x32 / 2]; goto pwm_write; case 0x33: REG8IN16(r, a) = d; d = r[0x32 / 2]; goto pwm_write; // PWM pulse regs.. Only writes to odd address send a value // to FIFO; reads are 0 (except status bits) case 0x34: case 0x36: case 0x38: REG8IN16(r, a) = d; return; case 0x35: case 0x37: case 0x39: d = (REG8IN16(r, a ^ 1) << 8) | (d & 0xff); REG8IN16(r, a ^ 1) = 0; goto pwm_write; case 0x3a: // ignored, always 0 case 0x3b: case 0x3c: case 0x3d: case 0x3e: case 0x3f: return; pwm_write: p32x_pwm_write16(a & ~1, d, NULL, SekCyclesDone()); return; } if ((a & 0x30) == 0x20) { int cycles = SekCyclesDone(); int comreg; if (REG8IN16(r, a) == d) return; comreg = 1 << (a & 0x0f) / 2; if (Pico32x.comm_dirty_68k & comreg) p32x_sync_sh2s(cycles); REG8IN16(r, a) = d; p32x_sh2_poll_event(&sh2s[0], SH2_STATE_CPOLL, cycles); p32x_sh2_poll_event(&sh2s[1], SH2_STATE_CPOLL, cycles); Pico32x.comm_dirty_68k |= comreg; if (cycles - (int)msh2.m68krcycles_done > 120) p32x_sync_sh2s(cycles); return; } }