| @@ -43,9 +43,7 @@ void nes_mem_write(nes* sys, uint16_t addr, uint8_t val) { | |||||
| nes_mem_read(sys, ((uint16_t)val << 8) + i); | nes_mem_read(sys, ((uint16_t)val << 8) + i); | ||||
| } | } | ||||
| sys->cpu.cycle += 513U; | sys->cpu.cycle += 513U; | ||||
| sys->ppu.cycle += (513U * nes_clock_cpu_div) / | |||||
| nes_clock_ppu_div; | |||||
| // TODO: Increment APU cycles? | |||||
| // Other subsystem cycles are driven by CPU cycles | |||||
| } else if (addr < nes_mem_exp_start) { | } else if (addr < nes_mem_exp_start) { | ||||
| nes_apu_write(&sys->apu, addr, val); | nes_apu_write(&sys->apu, addr, val); | ||||
| @@ -58,7 +58,7 @@ int main(int argc, char* argv[]) { | |||||
| int last_frame_rendered = -1; | int last_frame_rendered = -1; | ||||
| for (int i = 0; i < n_loops && status == 0; ++i) { | for (int i = 0; i < n_loops && status == 0; ++i) { | ||||
| int run = 0; | int run = 0; | ||||
| status = nes_run(&sys, 12, &run); | |||||
| status = nes_run(&sys, nes_clock_cpu_div, &run); | |||||
| total_cycles += run; | total_cycles += run; | ||||
| /* | /* | ||||
| float us_run = ( run * 1000. * 1000. * | float us_run = ( run * 1000. * 1000. * | ||||
| @@ -141,34 +141,27 @@ int nes_ppu_run(nes_ppu* ppu, int cycles) { | |||||
| ppu->cycle += cycles; | ppu->cycle += cycles; | ||||
| if ( 0 != ppu->hit_line && | |||||
| ppu->scanline > ppu->hit_line && | |||||
| ppu->cycle > ppu->hit_dot) { | |||||
| ppu->status |= ppu_Status_Hit; | |||||
| } | |||||
| while (ppu->cycle >= nes_ppu_dots) { | while (ppu->cycle >= nes_ppu_dots) { | ||||
| ppu->cycle -= nes_ppu_dots; | ppu->cycle -= nes_ppu_dots; | ||||
| if ( ppu->scanline <= nes_ppu_prerender && | |||||
| if ( ppu->scanline < nes_ppu_prerender && | |||||
| (ppu->frame & 1)) { | (ppu->frame & 1)) { | ||||
| // Prerender line is one dot shorter in odd frames | // Prerender line is one dot shorter in odd frames | ||||
| // Fake it by incrementing the cycle in this case | // Fake it by incrementing the cycle in this case | ||||
| // TODO: Only if actually rendering | |||||
| ppu->cycle++; | ppu->cycle++; | ||||
| } | } | ||||
| ppu->scanline++; | ppu->scanline++; | ||||
| if (ppu->scanline >= nes_ppu_prerender + | |||||
| nes_ppu_height + | |||||
| nes_ppu_postrender + | |||||
| nes_ppu_vblank) { | |||||
| if (ppu->scanline >= nes_ppu_frame) { | |||||
| ppu->status &= ~(ppu_Status_VBlank | ppu_Status_Hit); | ppu->status &= ~(ppu_Status_VBlank | ppu_Status_Hit); | ||||
| ppu->hit_line = 0; | ppu->hit_line = 0; | ||||
| ppu->hit_dot = 0; | ppu->hit_dot = 0; | ||||
| ppu->scanline = 0; | |||||
| ppu->scanline -= nes_ppu_frame; | |||||
| ppu->frame++; | ppu->frame++; | ||||
| // TODO: Render callback if vblank was previously set | |||||
| } else if (ppu->scanline >= nes_ppu_prerender + | |||||
| nes_ppu_height + | |||||
| nes_ppu_postrender) { | |||||
| // TODO: Render callback if vblank was previously set? | |||||
| } else if (ppu->scanline >= nes_ppu_active) { | |||||
| ppu->status |= ppu_Status_VBlank; | ppu->status |= ppu_Status_VBlank; | ||||
| if (ppu->control & ppu_Control_VBlank) { | if (ppu->control & ppu_Control_VBlank) { | ||||
| vblank = 1; | vblank = 1; | ||||
| @@ -176,6 +169,12 @@ int nes_ppu_run(nes_ppu* ppu, int cycles) { | |||||
| } | } | ||||
| } | } | ||||
| if ( 0 != ppu->hit_line && | |||||
| ppu->scanline > ppu->hit_line && | |||||
| ppu->cycle > ppu->hit_dot) { | |||||
| ppu->status |= ppu_Status_Hit; | |||||
| } | |||||
| return vblank; | return vblank; | ||||
| } | } | ||||
| @@ -10,15 +10,16 @@ | |||||
| #define nes_ppu_postrender (1U) | #define nes_ppu_postrender (1U) | ||||
| #define nes_ppu_vblank (20U) | #define nes_ppu_vblank (20U) | ||||
| #define nes_ppu_active_cycles \ | |||||
| (nes_ppu_dots * (nes_ppu_prerender + \ | |||||
| nes_ppu_height + \ | |||||
| nes_ppu_postrender)) | |||||
| #define nes_ppu_active (nes_ppu_prerender + \ | |||||
| nes_ppu_height + \ | |||||
| nes_ppu_postrender) | |||||
| #define nes_ppu_vblank_cycles (nes_ppu_dots * nes_ppu_vblank) | |||||
| #define nes_ppu_frame (nes_ppu_active + nes_ppu_vblank) | |||||
| #define nes_frame_cycles (nes_ppu_active_cycles + \ | |||||
| nes_ppu_vblank_cycles) | |||||
| #define nes_ppu_active_cycles (nes_ppu_dots * nes_ppu_active) | |||||
| #define nes_ppu_vblank_cycles (nes_ppu_dots * nes_ppu_vblank) | |||||
| #define nes_ppu_frame_cycles (nes_ppu_dots * nes_ppu_frame) | |||||
| #define nes_ppu_scan_w (320U) // Includes full overscan | #define nes_ppu_scan_w (320U) // Includes full overscan | ||||
| #define nes_ppu_scan_h nes_ppu_height | #define nes_ppu_scan_h nes_ppu_height | ||||