Beispiel #1
0
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;
}
Beispiel #3
0
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;
  }
Beispiel #4
0
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];
}
Beispiel #5
0
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 {
Beispiel #7
0
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!");
}
Beispiel #8
0
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);
}
Beispiel #9
0
// 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;
  }
}