Browse Source

Rendering dot tweaks; more PPU debug

v2
Nathaniel Walizer 8 months ago
parent
commit
7ab2e52abb
3 changed files with 54 additions and 29 deletions
  1. +5
    -10
      src/f6502.c
  2. +38
    -13
      src/nes.c
  3. +11
    -6
      src/ppu.c

+ 5
- 10
src/f6502.c View File

@@ -186,11 +186,13 @@ static inline int f6502_write(nes_Memory* mem,
case 0x2000:
switch (addr & 0x7U) {
case ppu_reg_ctrl:
LOGI("PPU: CTRL %02X", val);
if ( (mem->ppu.status & ppu_Status_VBlank) &&
!(mem->ppu.ctrl & ppu_Control_VBlank) &&
(val & ppu_Control_VBlank)) {
f6502_Core* core = container_of(mem, f6502_Core, memory);
/* Trigger NMI if VBlank was set */
f6502_set_NMI(core, 0);
f6502_set_NMI(core, 1);
ret = TRIGGER_INT;
}
@@ -232,10 +234,7 @@ static inline int f6502_write(nes_Memory* mem,
if (mem->ppu.latch) {
mem->ppu.t &= 0xFF00U;
mem->ppu.t |= val;
mem->ppu.addr = (mem->ppu.t & 0x3FFFU);
// Keep ctrl & t nametable in sync
mem->ppu.ctrl &= ~ppu_Control_Nametable_Mask;
mem->ppu.ctrl |= ((val >> 10) & ppu_Control_Nametable_Mask);
mem->ppu.addr = mem->ppu.t;
LOGI("PPU: ADDR %04X", mem->ppu.addr);
} else {
mem->ppu.t &= 0x00FFU;
@@ -1715,14 +1714,10 @@ step_done:

int f6502_step(f6502_Core* core, int clocks) {
int clocks_elapsed = 0;
// TODO: Why are we processing seven clocks prior to NMI?
// This passes the interrupt test with 6 steps
/*
// NMI occurs after next instruction
if (f6502_nmi_ready(core)) {
clocks_elapsed += f6502_do_step(core, 7);
clocks -= clocks_elapsed;
clocks_elapsed += f6502_do_step(core, 1);
}
*/
clocks_elapsed += f6502_check_interrupts(core);
clocks = f6502_do_step(core, clocks - clocks_elapsed);
clocks_elapsed += CLOCKS(clocks);


+ 38
- 13
src/nes.c View File

@@ -3,7 +3,7 @@
#include "nes.h"
#include "port.h"

//#define NESE_DEBUG "NES"
#define NESE_DEBUG "NES"
#include "log.h"


@@ -57,6 +57,7 @@ static int nes_hsync(nes* sys, void* plat) {
}

} else {
/*
nes_ppu_render_line(&sys->ppu,
&sys->core.memory.ppu);
nese_line_ready(
@@ -67,6 +68,7 @@ static int nes_hsync(nes* sys, void* plat) {
nes_ppu_visible_line)),
sys->ppu.scanline - nes_ppu_visible_line
);
*/
}
}

@@ -105,10 +107,12 @@ static int nes_hsync(nes* sys, void* plat) {
return status;
}

#define vblank_set_dot (1U)
#define mapper_hsync_dot (300U)
#define render_dot (256U)
#define vblank_clear_dot (341U)
#define mapper_hsync_dot (324U)
#define vblank_clear_dot (260U)
#define render_dot (257U)
#define vblank_set_dot (0U)

#define scanline_dots (nes_ppu_scanline_dots)

int nes_loop(nes* sys, void* plat) {
int status = 0;
@@ -116,9 +120,17 @@ int nes_loop(nes* sys, void* plat) {
bool mapper_hsync = false;
bool vbl_clear = false;
bool vbl_set = false;
bool render = false;

while (0 == status) {
int target_dot = nes_ppu_scanline_dots;
int target_dot = 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 ( nes_ppu_frame_end_line - 1 == sys->ppu.scanline &&
(sys->core.memory.ppu.status & ppu_Status_VBlank)) {
@@ -126,12 +138,11 @@ int nes_loop(nes* sys, void* plat) {
vbl_clear = true;
}

if ( sys->core.memory.mapper.hsync &&
sys->ppu.scanline > nes_ppu_prerender_line &&
if ( sys->ppu.scanline >= nes_ppu_visible_line &&
sys->ppu.scanline < nes_ppu_postrender_line &&
dot < mapper_hsync_dot) {
target_dot = mapper_hsync_dot;
mapper_hsync = true;
dot < render_dot ) {
target_dot = render_dot;
render = true;
}

if ( vbl_set ||
@@ -189,6 +200,20 @@ int nes_loop(nes* sys, void* plat) {
vbl_set = false;
}

if (render && dot >= render_dot) {
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
);
render = false;
}

if (vbl_clear && dot >= vblank_clear_dot) {
sys->core.memory.ppu.status &= ~ppu_Status_VBlank;
vbl_clear = false;
@@ -201,8 +226,8 @@ int nes_loop(nes* sys, void* plat) {
}

// It's possible we returned due to a pending interrupt.
if (dot >= nes_ppu_scanline_dots) {
dot -= nes_ppu_scanline_dots;
if (dot >= scanline_dots) {
dot -= scanline_dots;
status = nes_hsync(sys, plat);
if ( nes_ppu_vblank_line == sys->ppu.scanline &&
dot >= vblank_set_dot ) {


+ 11
- 6
src/ppu.c View File

@@ -115,12 +115,19 @@ void nes_ppu_render_line(nes_PPU* ppu, nes_PPU_Memory* mem) {

} else {
int back_bank = nes_PPU_Nametable_Bank_Index +
((mem->addr >> 10) & 3);
((mem->addr >> 10) & 3);

int y_coarse = (mem->addr >> 5) & 0x1F;
int y_coarse = (mem->addr >> 5) & 0x1FU;
int y_fine = mem->addr >> 12;
int x_coarse = mem->addr & 0x1FU;

LOGD("Scanline %d N %d X %d Y %d",
ppu->scanline,
back_bank - nes_PPU_Nametable_Bank_Index,
(x_coarse * 8) + mem->x,
(y_coarse * 8) + y_fine
);

const int bank_off = !!(mem->ctrl & ppu_Control_Back_Bank) << 2;

const uint8_t* nametable = mem->bank[back_bank] + (y_coarse * 32) + x_coarse;
@@ -347,16 +354,14 @@ void nes_ppu_render_line(nes_PPU* ppu, nes_PPU_Memory* mem) {

// Increment internal registers
if (mem->mask & (ppu_Mask_Sprite | ppu_Mask_Back)) {
uint16_t mask = 0b10000011111;
const uint16_t mask = 0b10000011111;
mem->addr = (mem->addr & ~mask) | (mem->t & mask);

int y_scroll = (mem->addr >> 12) |
((mem->addr >> 2) & 0xF8U);
if (nes_ppu_render_h - 1 == y_scroll) {
y_scroll = 0;
mem->addr ^= 0x800;
} else if (0xFFU == y_scroll) {
y_scroll = 0;
mem->addr ^= 0x0800U;
} else {
++y_scroll;
}


Loading…
Cancel
Save