|
- #include <stddef.h>
-
- #include "nes.h"
- #include "port.h"
-
- //#define NESE_DEBUG "NES"
- #include "log.h"
-
-
- void nes_init(nes* sys) {
- f6502_init(&sys->core);
- // TODO: Init PPU
- // TODO: Init APU
- }
-
- void nes_reset(nes* sys) {
- f6502_reset(&sys->core);
- // TODO: Reset PPU
- // TODO: Reset APU
- }
-
- void nes_done(nes* sys) {
- // TODO: deallocate RAM, etc.
- }
-
- static int nes_vsync(nes* sys, void* plat) {
- int status = 0;
-
- sys->core.memory.ppu.status |= ppu_Status_VBlank;
- if (sys->core.memory.ppu.ctrl & ppu_Control_VBlank) {
- LOGD("VBlank NMI");
- f6502_set_NMI(&sys->core, 1);
- }
-
- // TODO: APU Sync
- // TODO: APU Frame IRQ
-
- nes_Memory* mem = &sys->core.memory;
- if (0 == status && NULL != mem->mapper.vsync) {
- mem->mapper.vsync(&mem->mapper);
- status = nese_update_input(plat, &mem->input);
- }
-
- return status;
- }
-
- static int nes_hsync(nes* sys, void* plat) {
- int status = 0;
-
- // TODO: APU sync
-
- if (sys->ppu.scanline < nes_ppu_postrender_line) {
- if (sys->ppu.scanline < nes_ppu_visible_line) {
- if ( sys->core.memory.ppu.mask &
- (ppu_Mask_Sprite | ppu_Mask_Back)) {
- sys->core.memory.ppu.addr =
- sys->core.memory.ppu.t;
- }
-
- } else {
- nes_ppu_render_line(&sys->ppu,
- &sys->core.memory.ppu);
- nese_line_ready(
- plat,
- sys->ppu.screen_data +
- ( nes_ppu_render_w *
- ( sys->ppu.scanline -
- nes_ppu_visible_line)),
- sys->ppu.scanline - nes_ppu_visible_line
- );
- }
- }
-
- sys->ppu.scanline++;
- if (nes_ppu_frame_end_line == sys->ppu.scanline) {
- sys->ppu.scanline = nes_ppu_prerender_line;
- }
-
- switch (sys->ppu.scanline) {
- case nes_ppu_prerender_line:
- { nes_PPU_Memory* mem = &sys->core.memory.ppu;
-
- f6502_set_NMI(&sys->core, 0);
-
- mem->status &= ~(ppu_Status_VBlank | ppu_Status_Hit);
- nes_ppu_find_hit_line(&sys->ppu, mem);
-
- // Emulate the happy part of the backdrop override quirk
- int pal_idx = ((mem->addr & 0x3F00U) == 0x3F00U) ?
- (mem->addr & 0x1FU) : 0;
- LOGD("Background: %d", pal_idx);
- // Don't use the rendering palette (masked transparency)
- status = nese_frame_start(plat, mem->pal_bank[0x300 + pal_idx] & 0x3FU);
-
- } break;
-
- case nes_ppu_postrender_line:
- status = nese_frame_ready(plat);
- break;
-
- case nes_ppu_vblank_line:
- status = nes_vsync(sys, plat);
- break;
- }
-
- return status;
- }
-
- #define mapper_hsync_dot (300U)
-
- int nes_loop(nes* sys, void* plat) {
- int status = 0;
- int dot = 0;
- bool mapper_hsync = false;
-
- while (0 == status) {
- // TODO: Move to inline PPU function?
- int target_dot = nes_ppu_scanline_dots;
-
- if ( sys->core.memory.mapper.hsync &&
- sys->ppu.scanline > nes_ppu_prerender_line &&
- sys->ppu.scanline < nes_ppu_postrender_line &&
- dot < mapper_hsync_dot) {
- target_dot = mapper_hsync_dot;
- mapper_hsync = true;
- }
-
- if ( sys->ppu.hit_line == sys->ppu.scanline &&
- ( sys->core.memory.ppu.mask &
- (ppu_Mask_Sprite | ppu_Mask_Back)) &&
- !(sys->core.memory.ppu.status & ppu_Status_Hit)) {
- int hit_dot = ((oam_sprite*)sys->core.memory.ppu.oam)->x;
- if (dot >= hit_dot) {
- LOGD("Line %d sprite 0 hit @ %d", sys->ppu.hit_line, hit_dot);
- sys->core.memory.ppu.status |= ppu_Status_Hit;
- } else {
- target_dot = hit_dot;
- }
- }
-
- if (target_dot > dot) {
- int cpu_cycles = (target_dot - dot + 2) / 3;
- dot += 3 * f6502_step(&sys->core, cpu_cycles);
- }
-
- if (mapper_hsync && dot >= mapper_hsync_dot) {
- nes_Memory* mem = &sys->core.memory;
- mem->mapper.hsync(&mem->mapper);
- mapper_hsync = false;
- }
-
- // It's possible we returned due to a pending interrupt.
- if (dot >= nes_ppu_scanline_dots) {
- dot -= nes_ppu_scanline_dots;
- status = nes_hsync(sys, plat);
- }
- }
-
- return status;
- }
|