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); }
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); }
//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; }
void CPU::add_clocks(unsigned clocks) { status.irq_lock = false; unsigned ticks = clocks >> 1; while(ticks--) { tick(); if(hcounter() & 2) { input.tick(); poll_interrupts(); } if(joypad_counter() == 0) { joypad_edge(); } } step(clocks); if(status.dram_refreshed == false && hcounter() >= status.dram_refresh_position) { status.dram_refreshed = true; add_clocks(40); } }
void CPU::add_clocks(unsigned clocks) { status.irq_lock = false; unsigned ticks = clocks >> 1; while(ticks--) { tick(); if(hcounter() & 2) poll_interrupts(); } step(clocks); status.auto_joypad_clock += clocks; if(status.auto_joypad_clock >= 256) { status.auto_joypad_clock -= 256; step_auto_joypad_poll(); } if(status.dram_refreshed == false && hcounter() >= status.dram_refresh_position) { status.dram_refreshed = true; add_clocks(40); } }
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; } }
unsigned CPU::dma_counter() { return (status.dma_counter + hcounter()) & 7; }
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;