//this should only be called by PPU::PPUcounter::tick(n); //allows stepping by more than the smallest unit of time void PPUcounter::tick(unsigned clocks) { status.hcounter += clocks; if(status.hcounter >= lineclocks()) { status.hcounter -= lineclocks(); vcounter_tick(); } }
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()); } } }
//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; } }
//this should only be called by CPU::PPUcounter::tick(); //keeps track of previous counter positions in history table void PPUcounter::tick() { status.hcounter += 2; //increment by smallest unit of time if(status.hcounter >= 1360 && status.hcounter == lineclocks()) { status.hcounter = 0; vcounter_tick(); } history.index = (history.index + 1) & 2047; history.field [history.index] = status.field; history.vcounter[history.index] = status.vcounter; history.hcounter[history.index] = status.hcounter; }