示例#1
0
文件: timing.cpp 项目: gilligan/bsnes
void CPU::scanline() {
  synchronize_smp();
  synchronize_ppu();
  synchronize_coprocessor();
  system.scanline();

  if(vcounter() == 0) hdma_init();

  queue.enqueue(534, QueueEvent::DramRefresh);

  if(vcounter() <= (ppu.overscan() == false ? 224 : 239)) {
    queue.enqueue(1104 + 8, QueueEvent::HdmaRun);
  }

  if(vcounter() == input.latchy) {
    queue.enqueue(input.latchx, QueueEvent::ControllerLatch);
  }

  bool nmi_valid = status.nmi_valid;
  status.nmi_valid = vcounter() >= (ppu.overscan() == false ? 225 : 240);
  if(!nmi_valid && status.nmi_valid) {
    status.nmi_line = true;
    if(status.nmi_enabled) status.nmi_transition = true;
  } else if(nmi_valid && !status.nmi_valid) {
    status.nmi_line = false;
  }

  if(status.auto_joypad_poll_enabled && vcounter() == (ppu.overscan() == false ? 227 : 242)) {
    input.poll();
    run_auto_joypad_poll();
  }
}
示例#2
0
//called by ppu.tick() when Hcounter=0
void CPU::scanline() {
  status.lineclocks = lineclocks();

  //forcefully sync S-CPU to other processors, in case chips are not communicating
  synchronize_ppu();
  synchronize_smp();
  synchronize_coprocessor();
  system.scanline();

  if(vcounter() == 0) {
    //HDMA init triggers once every frame
    status.hdma_init_position = (cpu_version == 1 ? 12 + 8 - dma_counter() : 12 + dma_counter());
    status.hdma_init_triggered = false;
    
    status.auto_joypad_counter = 0;
  }

  //DRAM refresh occurs once every scanline
  if(cpu_version == 2) status.dram_refresh_position = 530 + 8 - dma_counter();
  status.dram_refreshed = false;

  //HDMA triggers once every visible scanline
  if(vcounter() <= (ppu.overscan() == false ? 224 : 239)) {
    status.hdma_position = 1104;
    status.hdma_triggered = false;
  }
}
示例#3
0
文件: timing.cpp 项目: gilligan/bsnes
void CPU::add_clocks(unsigned clocks) {
  if(status.hirq_enabled) {
    if(status.virq_enabled) {
      unsigned cpu_time = vcounter() * 1364 + hcounter();
      unsigned irq_time = status.vtime * 1364 + status.htime * 4;
      unsigned framelines = (system.region() == System::Region::NTSC ? 262 : 312) + field();
      if(cpu_time > irq_time) irq_time += framelines * 1364;
      bool irq_valid = status.irq_valid;
      status.irq_valid = cpu_time <= irq_time && cpu_time + clocks > irq_time;
      if(!irq_valid && status.irq_valid) status.irq_line = true;
    } else {
      unsigned irq_time = status.htime * 4;
      if(hcounter() > irq_time) irq_time += 1364;
      bool irq_valid = status.irq_valid;
      status.irq_valid = hcounter() <= irq_time && hcounter() + clocks > irq_time;
      if(!irq_valid && status.irq_valid) status.irq_line = true;
    }
    if(status.irq_line) status.irq_transition = true;
  } else if(status.virq_enabled) {
    bool irq_valid = status.irq_valid;
    status.irq_valid = vcounter() == status.vtime;
    if(!irq_valid && status.irq_valid) status.irq_line = true;
    if(status.irq_line) status.irq_transition = true;
  } else {
    status.irq_valid = false;
  }

  tick(clocks);
  queue.tick(clocks);
  step(clocks);
}
示例#4
0
void CPU::add_clocks(unsigned clocks) {
  if(status.hirq_enabled) {
    if(status.virq_enabled) {
      unsigned cpu_time = vcounter() * 1364 + hcounter();
      unsigned irq_time = status.virq_pos * 1364 + status.hirq_pos * 4;
      if(cpu_time > irq_time) irq_time += fieldlines() * 1364;
      bool irq_valid = status.irq_valid;
      status.irq_valid = cpu_time <= irq_time && cpu_time + clocks > irq_time;
      if(!irq_valid && status.irq_valid) status.irq_line = true;
    } else {
      unsigned irq_time = status.hirq_pos * 4;
      if(hcounter() > irq_time) irq_time += 1364;
      bool irq_valid = status.irq_valid;
      status.irq_valid = hcounter() <= irq_time && hcounter() + clocks > irq_time;
      if(!irq_valid && status.irq_valid) status.irq_line = true;
    }
    if(status.irq_line) status.irq_transition = true;
  } else if(status.virq_enabled) {
    bool irq_valid = status.irq_valid;
    status.irq_valid = vcounter() == status.virq_pos;
    if(!irq_valid && status.irq_valid) status.irq_line = true;
    if(status.irq_line) status.irq_transition = true;
  } else {
    status.irq_valid = false;
  }

  tick(clocks);
  queue.tick(clocks);
  step(clocks);
}
示例#5
0
//HVBJOY
//7   = VBLANK acknowledge
//6   = HBLANK acknowledge
//5-1 = MDR
//0   = JOYPAD acknowledge
uint8 CPU::mmio_r4212() {
  uint8 r = (regs.mdr & 0x3e);
  uint16 vs = ppu.overscan() == false ? 225 : 240;
  if(vcounter() >= vs && vcounter() <= (vs + 2)) r |= 0x01;  //auto joypad polling
  if(hcounter() <= 2 || hcounter() >= 1096) r |= 0x40;  //hblank
  if(vcounter() >= vs) r |= 0x80;  //vblank
  return r;
}
示例#6
0
void PPU::enter() {
  while(true) {
    if(scheduler.sync == Scheduler::SynchronizeMode::All) {
      scheduler.exit(Scheduler::ExitReason::SynchronizeEvent);
    }

    scanline();
    if(vcounter() < display.height && vcounter()) {
      add_clocks(512);
      render_scanline();
      add_clocks(lineclocks() - 512);
    } else {
      add_clocks(lineclocks());
    }
  }
}
示例#7
0
void PPU::scanline() {
  if(vcounter() == 0) {
    frame();
    bg1.frame();
    bg2.frame();
    bg3.frame();
    bg4.frame();
  }

  bg1.scanline();
  bg2.scanline();
  bg3.scanline();
  bg4.scanline();
  oam.scanline();
  window.scanline();
  screen.scanline();
}
示例#8
0
void PPU::scanline() {
  line = vcounter();

  if(line == 0) {
    frame();

    //RTO flag reset
    regs.time_over  = false;
    regs.range_over = false;
  }

  if(line == 1) {
    //mosaic reset
    for(int bg = BG1; bg <= BG4; bg++) regs.bg_y[bg] = 1;
    regs.mosaic_countdown = regs.mosaic_size + 1;
    regs.mosaic_countdown--;
  } else {
    for(int bg = BG1; bg <= BG4; bg++) {
      if(!regs.mosaic_enabled[bg] || !regs.mosaic_countdown) regs.bg_y[bg] = line;
    }
    if(!regs.mosaic_countdown) regs.mosaic_countdown = regs.mosaic_size + 1;
    regs.mosaic_countdown--;
  }
}
示例#9
0
uint8 CPU::mmio_read(unsigned addr) {
  if((addr & 0xffc0) == 0x2140) {
    synchronize_smp();
    return smp.port_read(addr & 3);
  }

  switch(addr & 0xffff) {
    case 0x2180: {
      uint8 result = bus.read(0x7e0000 | status.wram_addr);
      status.wram_addr = (status.wram_addr + 1) & 0x01ffff;
      return result;
    }

    case 0x4016: {
      uint8 result = regs.mdr & 0xfc;
      result |= input.port1->data() & 3;
      return result;
    }

    case 0x4017: {
      uint8 result = (regs.mdr & 0xe0) | 0x1c;
      result |= input.port2->data() & 3;
			if (!status.auto_joypad_poll_enabled) interface()->inputNotify(0x4017);
      return result;
    }

    case 0x4210: {
      uint8 result = (regs.mdr & 0x70);
      result |= status.nmi_line << 7;
      result |= 0x02;  //CPU revision
      status.nmi_line = false;
      return result;
    }

    case 0x4211: {
      uint8 result = (regs.mdr & 0x7f);
      result |= status.irq_line << 7;
      status.irq_line = false;
      return result;
    }

    case 0x4212: {
      uint8 result = (regs.mdr & 0x3e);
      unsigned vbstart = ppu.overscan() == false ? 225 : 240;

      if(vcounter() >= vbstart && vcounter() <= vbstart + 2) result |= 0x01;
      if(hcounter() <= 2 || hcounter() >= 1096) result |= 0x40;
      if(vcounter() >= vbstart) result |= 0x80;

      return result;
    }

    case 0x4213: 
			// interface()->inputNotify(0x4213); // if there are lag counter issues with super scope, uncomment this
			return status.pio;

    case 0x4214: return status.rddiv >> 0;
    case 0x4215: return status.rddiv >> 8;
    case 0x4216: return status.rdmpy >> 0;
    case 0x4217: return status.rdmpy >> 8;

    case 0x4218: interface()->inputNotify(0x4218); return status.joy1l;
    case 0x4219: interface()->inputNotify(0x4219); return status.joy1h;
    case 0x421a: interface()->inputNotify(0x421a); return status.joy2l;
    case 0x421b: interface()->inputNotify(0x421b); return status.joy2h;
    case 0x421c: interface()->inputNotify(0x421c); return status.joy3l;
    case 0x421d: interface()->inputNotify(0x421d); return status.joy3h;
    case 0x421e: interface()->inputNotify(0x421e); return status.joy4l;
    case 0x421f: interface()->inputNotify(0x421f); return status.joy4h;
  }

  if((addr & 0xff80) == 0x4300) {
    unsigned i = (addr >> 4) & 7;
    switch(addr & 0xff8f) {
      case 0x4300: {
        return (channel[i].direction << 7)
             | (channel[i].indirect << 6)
             | (channel[i].unused << 5)
             | (channel[i].reverse_transfer << 4)
             | (channel[i].fixed_transfer << 3)
             | (channel[i].transfer_mode << 0);
      }

      case 0x4301: return channel[i].dest_addr;
      case 0x4302: return channel[i].source_addr >> 0;
      case 0x4303: return channel[i].source_addr >> 8;
      case 0x4304: return channel[i].source_bank;
      case 0x4305: return channel[i].transfer_size >> 0;
      case 0x4306: return channel[i].transfer_size >> 8;
      case 0x4307: return channel[i].indirect_bank;
      case 0x4308: return channel[i].hdma_addr >> 0;
      case 0x4309: return channel[i].hdma_addr >> 8;
      case 0x430a: return channel[i].line_counter;
      case 0x430b: case 0x430f: return channel[i].unknown;
    }
  }
示例#10
0
void PPU::scanline() {
  display.width = !hires() ? 256 : 512;
  display.height = !overscan() ? 225 : 240;
  if(vcounter() == 0) frame();
  if(vcounter() == display.height && regs.display_disable == false) oam.address_reset();
}
示例#11
0
uint16 PPUcounter::hdot() const {
  if(system.region.i == System::Region::NTSC && status.interlace == false && vcounter() == 240 && field() == 1) {
    return (hcounter() >> 2);
  } else {
    return (hcounter() - ((hcounter() > 1292) << 1) - ((hcounter() > 1310) << 1)) >> 2;