uint8 sSMP::op_read(uint16 addr) { add_clocks(12); uint8 r = op_busread(addr); add_clocks(12); tick_timers(); return r; }
uint8 SMP::op_read(uint16 addr) { add_clocks(12); uint8 r = op_busread(addr); add_clocks(12); cycle_edge(); return r; }
uint8 CPU::op_read(uint32 addr) { status.clock_count = speed(addr); dma_edge(); add_clocks(status.clock_count - 4); regs.mdr = bus.read(addr); add_clocks(4); alu_edge(); debugger.op_read(addr, regs.mdr); return regs.mdr; }
uint8 SMP::op_read(uint16 addr, eCDLog_Flags flags) { debugger.op_read(addr); add_clocks(12); cdlInfo.currFlags = flags; uint8 r = op_busread(addr); add_clocks(12); cycle_edge(); return r; }
void CPU::dma_transfer(bool direction, uint8 bbus, uint32 abus) { if(direction == 0) { add_clocks(4); regs.mdr = dma_read(abus); add_clocks(4); if (dma_transfer_valid(bbus, abus)) bus.write(0x2100 | bbus, regs.mdr); } else { add_clocks(4); regs.mdr = dma_transfer_valid(bbus, abus) ? bus.read(0x2100 | bbus) : 0x00; add_clocks(4); if (dma_addr_valid(abus)) bus.write(abus, regs.mdr); } }
void sSMP::cycle_edge() { t0.tick(); t1.tick(); t2.tick(); //TEST register S-SMP speed control //24 clocks have already been added for this cycle at this point switch(status.clock_speed) { case 0: break; //100% speed case 1: add_clocks(24); break; // 50% speed case 2: while(true) add_clocks(24); // 0% speed -- locks S-SMP case 3: add_clocks(24 * 9); break; // 10% speed } }
void SMP::op_write(uint16 addr, uint8 data) { debugger.op_write(addr, data); add_clocks(24); op_buswrite(addr, data); cycle_edge(); }
void CPU::queue_event(unsigned id) { switch(id) { case QueueEvent::DramRefresh: return add_clocks(40); case QueueEvent::HdmaRun: return hdma_run(); case QueueEvent::ControllerLatch: return ppu.latch_counters(); } }
void CPU::enter() { while(true) { if(scheduler.sync == Scheduler::SynchronizeMode::CPU) { scheduler.sync = Scheduler::SynchronizeMode::All; scheduler.exit(Scheduler::ExitReason::SynchronizeEvent); } if(status.interrupt_pending) { status.interrupt_pending = false; if(status.nmi_pending) { status.nmi_pending = false; status.interrupt_vector = (regs.e == false ? 0xffea : 0xfffa); op_irq(); } else if(status.irq_pending) { status.irq_pending = false; status.interrupt_vector = (regs.e == false ? 0xffee : 0xfffe); op_irq(); } else if(status.reset_pending) { status.reset_pending = false; add_clocks(186); regs.pc.l = bus.read(0xfffc); regs.pc.h = bus.read(0xfffd); } } op_step(); } }
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()); } } }
uint8 CPU::op_read(uint16 addr) { if(status.oam_dma_pending) { status.oam_dma_pending = false; op_read(addr); oam_dma(); } while(status.rdy_line == 0) { regs.mdr = bus.read(status.rdy_addr ? status.rdy_addr() : addr); add_clocks(12); } regs.mdr = bus.read(addr); add_clocks(12); return regs.mdr; }
void CPU::enter() { while(true) { if(scheduler.sync == Scheduler::SynchronizeMode::CPU) { // we can only stop if there's enough time for at least one more event // on both the PPU and the SMP if (smp.clock < 0 && ppu.clock < 0) { scheduler.sync = Scheduler::SynchronizeMode::All; scheduler.exit(Scheduler::ExitReason::SynchronizeEvent); } } if(status.interrupt_pending) { status.interrupt_pending = false; if(status.nmi_pending) { status.nmi_pending = false; regs.vector = (regs.e == false ? 0xffea : 0xfffa); op_irq(); debugger.op_nmi(); } else if(status.irq_pending) { status.irq_pending = false; regs.vector = (regs.e == false ? 0xffee : 0xfffe); op_irq(); debugger.op_irq(); } else if(status.reset_pending) { status.reset_pending = false; add_clocks(186); regs.pc.l = bus.read(0xfffc); regs.pc.h = bus.read(0xfffd); } } op_step(); } }
void CPU::op_write(uint32 addr, uint8 data) { alu_edge(); status.clock_count = speed(addr); dma_edge(); add_clocks(status.clock_count); bus.write(addr, regs.mdr = data); debugger.op_write(addr, regs.mdr); }
void CPU::hblank() { if(status.dma_mode == 1 && status.dma_length && ppu.status.ly < 144) { for(unsigned n = 0; n < 16; n++) { dma_write(status.dma_target++, dma_read(status.dma_source++)); } add_clocks(8 << status.speed_double); status.dma_length -= 16; } }
void CPU::hblank() { if(status.dma_mode == 1 && status.dma_length) { for(unsigned n = 0; n < 16; n++) { bus.write(status.dma_target++, bus.read(status.dma_source++)); add_clocks(4); } status.dma_length -= 16; } }
void CPU::dma_run() { add_clocks(8); dma_edge(); for(unsigned i = 0; i < 8; i++) { if(channel[i].dma_enabled == false) continue; add_clocks(8); dma_edge(); unsigned index = 0; do { dma_transfer(channel[i].direction, dma_bbus(i, index++), dma_addr(i)); dma_edge(); } while(channel[i].dma_enabled && --channel[i].transfer_size); channel[i].dma_enabled = false; } status.irq_lock = true; }
void CPU::hdma_update(unsigned i) { add_clocks(4); regs.mdr = dma_read((channel[i].source_bank << 16) | channel[i].hdma_addr); add_clocks(4); if((channel[i].line_counter & 0x7f) == 0) { channel[i].line_counter = regs.mdr; channel[i].hdma_addr++; channel[i].hdma_completed = (channel[i].line_counter == 0); channel[i].hdma_do_transfer = !channel[i].hdma_completed; if(channel[i].indirect) { add_clocks(4); regs.mdr = dma_read(hdma_addr(i)); add_clocks(4); channel[i].indirect_addr = regs.mdr << 8; if(!channel[i].hdma_completed || hdma_active_after(i)) { add_clocks(4); regs.mdr = dma_read(hdma_addr(i)); add_clocks(4); channel[i].indirect_addr >>= 8; channel[i].indirect_addr |= regs.mdr << 8; }
void bPPU::enter() { loop: //H = 0 (initialize) scanline(); if(ivcounter() == 0) frame(); add_clocks(10); //H = 10 (OAM address reset) if(ivcounter() == (!overscan() ? 225 : 240)) { if(regs.display_disabled == false) { regs.oam_addr = regs.oam_baseaddr << 1; regs.oam_firstsprite = (regs.oam_priority == false) ? 0 : (regs.oam_addr >> 2) & 127; } }
void SuperFX::enter() { while(true) { if(scheduler.sync == Scheduler::SynchronizeMode::All) { scheduler.exit(Scheduler::ExitReason::SynchronizeEvent); } if(regs.sfr.g == 0) { add_clocks(6); continue; } op_exec(peekpipe()); if(r15_modified == false) regs.r[15]++; } }
void SuperFX::enter() { while(true) { if(scheduler.sync.i == Scheduler::SynchronizeMode::All) { scheduler.exit(Scheduler::ExitReason::SynchronizeEvent); } if(regs.sfr.g == 0) { add_clocks(6); synchronize_cpu(); continue; } (this->*opcode_table[(regs.sfr & 0x0300) + peekpipe()])(); if(r15_modified == false) regs.r[15]++; if(++instruction_counter >= 128) { instruction_counter = 0; synchronize_cpu(); } } }
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); } }
void sSMP::op_io() { add_clocks(24); tick_timers(); }
void SuperFX::rambuffer_sync() { if(regs.ramcl) add_clocks(regs.ramcl); }
void CPU::op_write(unsigned addr, uint8 data) { add_clocks(speed(addr)); bus.write(addr, regs.mdr = data); }
uint8 CPU::op_read(unsigned addr) { regs.mdr = bus.read(addr); add_clocks(speed(addr)); return regs.mdr; }
void CPU::op_io() { add_clocks(6); }
void sCPU::dma_add_clocks(unsigned clocks) { status.dma_clocks += clocks; add_clocks(clocks); }
void sSMP::op_write(uint16 addr, uint8 data) { add_clocks(24); op_buswrite(addr, data); tick_timers(); }
void SMP::op_io() { add_clocks(24); cycle_edge(); }