summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPeter Fors <peter.fors@mindkiller.com>2025-04-01 01:40:54 +0200
committerPeter Fors <peter.fors@mindkiller.com>2025-04-01 01:40:54 +0200
commit69d0ba33d6bb502015fc1cf07892be6d9c045d77 (patch)
treef3e27d0c04788dda4238c319becd2632280ca61e
parentc00eb3a942ca184e2c2f6c60e3649d301bd8007c (diff)
broken
-rw-r--r--mknes.h6
-rw-r--r--ppu.c141
2 files changed, 60 insertions, 87 deletions
diff --git a/mknes.h b/mknes.h
index afd0369..d3b1028 100644
--- a/mknes.h
+++ b/mknes.h
@@ -55,12 +55,6 @@ struct ppu_state {
uint32_t vram_addr;
uint8_t write_latch;
- uint32_t render_coarse_x;
- uint32_t render_coarse_y;
- uint32_t render_fine_y;
- uint32_t render_nt_x;
- uint32_t render_nt_y;
-
uint32_t cycle;
uint32_t scanline;
uint32_t dot;
diff --git a/ppu.c b/ppu.c
index dbf8e2b..f2e3048 100644
--- a/ppu.c
+++ b/ppu.c
@@ -1,4 +1,3 @@
-
static uint8_t memory_read_dma(struct nes_state *state, uint32_t offset);
static void ppu_reset(struct nes_state *state) {
@@ -6,7 +5,6 @@ static void ppu_reset(struct nes_state *state) {
__builtin_memset(ppu, 0, sizeof(struct ppu_state));
ppu->scanline = 261;
-
}
static uint32_t nt_mirror(uint8_t mode, uint32_t addr) {
@@ -56,11 +54,11 @@ static uint8_t ppu_read_mem(struct nes_state *state, uint32_t addr) {
static void ppu_write_mem(struct nes_state *state, uint32_t addr, uint8_t value) {
struct ppu_state *ppu = &state->ppu;
-
addr &= 0x3fff;
if(addr < 0x2000) {
- return; // CHR ROM is read-only
+ // CHR ROM is read-only
+ return;
} else if(addr < 0x3f00) {
uint32_t mirrored = nt_mirror(state->ines.mirroring, addr - 0x2000);
ppu->vram[mirrored] = value;
@@ -69,37 +67,30 @@ static void ppu_write_mem(struct nes_state *state, uint32_t addr, uint8_t value)
}
}
-
static void ppu_write_2000(struct nes_state *state, uint8_t value) {
struct ppu_state *ppu = &state->ppu;
ppu->control = value;
ppu->nt_x_offset = (value & 0x01) ? 0x400 : 0;
ppu->nt_y_offset = (value & 0x02) ? 0x800 : 0;
- // printf("write 0x2000 %d\n", value);
}
static void ppu_write_2001(struct nes_state *state, uint8_t value) {
state->ppu.mask = value;
- // printf("PPU $2001 write: %02x (BG: %s, SPR: %s)\n", value, (value & 0x08) ? "on" : "off", (value & 0x10) ? "on" : "off");
}
static void ppu_write_2003(struct nes_state *state, uint8_t value) {
state->ppu.oam_addr = value;
- // printf("write 0x2003 %d\n", value);
}
static void ppu_write_2004(struct nes_state *state, uint8_t value) {
state->ppu.oam[state->ppu.oam_addr] = value;
state->ppu.oam_addr++;
- // printf("write 0x2004 %d\n", value);
}
static void ppu_write_2005(struct nes_state *state, uint8_t value) {
struct ppu_state *ppu = &state->ppu;
- // printf("2005 write at sc=%u dot=%u: %02x\n", ppu->scanline, ppu->dot, value);
-
if(ppu->write_latch == 0) {
ppu->fine_x = value & 0x07;
ppu->vram_addr = (ppu->vram_addr & ~0x001f) | ((value >> 3) & 0x1f);
@@ -109,7 +100,6 @@ static void ppu_write_2005(struct nes_state *state, uint8_t value) {
uint32_t fine_y = value & 0x07;
uint32_t nt_y = (value & 0x80) ? 0x800 : 0;
- // Bits 5–9: coarse Y, bit 11: nt_y, bits 12–14: fine Y
ppu->vram_addr = (ppu->vram_addr & ~0x7be0) | (coarse_y << 5) | nt_y | (fine_y << 12);
ppu->write_latch = 0;
}
@@ -118,8 +108,6 @@ static void ppu_write_2005(struct nes_state *state, uint8_t value) {
static void ppu_write_2006(struct nes_state *state, uint8_t value) {
struct ppu_state *ppu = &state->ppu;
- // printf("2006 write at sc=%u dot=%u: %02x\n", ppu->scanline, ppu->dot, value);
-
if(ppu->write_latch == 0) {
ppu->vram_addr = ((uint32_t)(value & 0x3f)) << 8;
ppu->write_latch = 1;
@@ -131,12 +119,8 @@ static void ppu_write_2006(struct nes_state *state, uint8_t value) {
static void ppu_write_2007(struct nes_state *state, uint8_t value) {
struct ppu_state *ppu = &state->ppu;
- // printf("PPU $2007 write: addr=%04x val=%02x\n", ppu->vram_addr, value);
ppu_write_mem(state, ppu->vram_addr, value);
-
-// printf("w%04x:%02x cx=%u cy=%u fx=%u ntx=%x nty=%x ", ppu->vram_addr, value, ppu->coarse_x, ppu->coarse_y, ppu->fine_x, ppu->nt_x_offset, ppu->nt_y_offset);
-
ppu->vram_addr += (ppu->control & 0x04) ? 32 : 1;
ppu->vram_addr &= 0x3fff;
}
@@ -145,24 +129,19 @@ static uint8_t ppu_read_2002(struct nes_state *state) {
struct ppu_state *ppu = &state->ppu;
uint8_t result = ppu->vblank | ppu->sprite_zero_hit | ppu->sprite_overflow;
- // printf("PPU $2002 read at PC=%04x: result=%02x (vblank=%02x)\n", state->cpu.pc, result, ppu->vblank);
-
ppu->vblank = 0;
ppu->write_latch = 0;
return result;
}
static uint8_t ppu_read_2004(struct nes_state *state) {
- printf("ppu_read_2004\n");
return state->ppu.oam[state->ppu.oam_addr];
}
static uint8_t ppu_read_2007(struct nes_state *state) {
struct ppu_state *ppu = &state->ppu;
- // printf("ppu_read_2007\n");
uint8_t value = ppu_read_mem(state, ppu->vram_addr);
-
ppu->vram_addr += (ppu->control & 0x04) ? 32 : 1;
ppu->vram_addr &= 0x3fff;
return value;
@@ -170,58 +149,62 @@ static uint8_t ppu_read_2007(struct nes_state *state) {
static void ppu_inc_x(struct nes_state *state) {
struct ppu_state *ppu = &state->ppu;
-
- ppu->render_coarse_x++;
- if(ppu->render_coarse_x == 32) {
- ppu->render_coarse_x = 0;
- ppu->render_nt_x ^= 0x400;
+ if((ppu->vram_addr & 0x001f) == 31) {
+ ppu->vram_addr &= ~0x001f;
+ ppu->vram_addr ^= 0x0400;
+ } else {
+ ppu->vram_addr += 1;
}
}
static void ppu_inc_y(struct nes_state *state) {
struct ppu_state *ppu = &state->ppu;
- ppu->render_fine_y++;
- if(ppu->render_fine_y == 8) {
- ppu->render_fine_y = 0;
- ppu->render_coarse_y++;
-
- if(ppu->render_coarse_y == 30) {
- ppu->render_coarse_y = 0;
- ppu->render_nt_y ^= 0x800;
+ if((ppu->vram_addr & 0x7000) != 0x7000) {
+ ppu->vram_addr += 0x1000;
+ } else {
+ ppu->vram_addr &= ~0x7000;
+ uint32_t y = (ppu->vram_addr >> 5) & 0x1f;
+
+ if(y == 29) {
+ y = 0;
+ ppu->vram_addr ^= 0x0800;
+ } else if(y == 31) {
+ y = 0;
+ } else {
+ y++;
}
+
+ ppu->vram_addr = (ppu->vram_addr & ~0x03e0) | (y << 5);
}
}
static uint8_t ppu_fetch_name_table(struct nes_state *state) {
struct ppu_state *ppu = &state->ppu;
- uint32_t addr = 0x2000 | ppu->render_nt_x | ppu->render_nt_y | (ppu->render_coarse_y << 5) | ppu->render_coarse_x;
+ uint32_t addr = 0x2000 | (ppu->vram_addr & 0x0fff);
return ppu_read_mem(state, addr);
}
static uint8_t ppu_fetch_attribute(struct nes_state *state) {
struct ppu_state *ppu = &state->ppu;
- uint32_t x = ppu->render_coarse_x;
- uint32_t y = ppu->render_coarse_y;
- uint32_t nt = (ppu->render_nt_y ? 0x800 : 0) | (ppu->render_nt_x ? 0x400 : 0);
- uint32_t addr = 0x23c0 | (nt & 0x0c00) | ((y >> 2) << 3) | (x >> 2);
-
- return ppu_read_mem(state, addr);
+ uint32_t v = ppu->vram_addr;
+ uint32_t nt = 0x23c0 | (v & 0x0c00) | ((v >> 4) & 0x38) | ((v >> 2) & 0x07);
+ return ppu_read_mem(state, nt);
}
static uint8_t ppu_fetch_pattern_lo(struct nes_state *state, uint8_t tile) {
struct ppu_state *ppu = &state->ppu;
uint32_t base = (ppu->control & 0x10) ? 0x1000 : 0x0000;
- uint32_t addr = base + tile * 16 + ppu->render_fine_y;
+ uint32_t addr = base + tile * 16 + ((ppu->vram_addr >> 12) & 0x7);
return ppu_read_mem(state, addr);
}
static uint8_t ppu_fetch_pattern_hi(struct nes_state *state, uint8_t tile) {
struct ppu_state *ppu = &state->ppu;
uint32_t base = (ppu->control & 0x10) ? 0x1000 : 0x0000;
- uint32_t addr = base + tile * 16 + ppu->render_fine_y + 8;
+ uint32_t addr = base + tile * 16 + ((ppu->vram_addr >> 12) & 0x7) + 8;
return ppu_read_mem(state, addr);
}
@@ -274,31 +257,6 @@ static void ppu_render_pixel(struct nes_state *state) {
ppu->pixels[y * 256 + x] = color_index;
}
-static void ppu_evaluate_sprites(struct nes_state *state, uint32_t target_scanline) {
- struct ppu_state *ppu = &state->ppu;
-
- ppu->sprite_count = 0;
-
- for(uint32_t i = 0; i < 64; i++) {
- uint8_t y = ppu->oam[i * 4 + 0];
- uint8_t height = (ppu->control & 0x20) ? 16 : 8;
-
- if(target_scanline >= y && target_scanline < y + height) {
- if(ppu->sprite_count < 8) {
- uint8_t *dest = &ppu->secondary_oam[ppu->sprite_count * 4];
- dest[0] = y;
- dest[1] = ppu->oam[i * 4 + 1];
- dest[2] = ppu->oam[i * 4 + 2];
- dest[3] = ppu->oam[i * 4 + 3];
- ppu->sprite_count++;
- } else {
- ppu->sprite_overflow = 0x20;
- break;
- }
- }
- }
-}
-
static uint8_t ppu_fetch_sprite_pattern_lo(struct nes_state *state, uint8_t tile, uint8_t y_offset, uint8_t attr, uint8_t height) {
uint32_t addr;
@@ -327,6 +285,7 @@ static uint8_t ppu_fetch_sprite_pattern_hi(struct nes_state *state, uint8_t tile
return ppu_read_mem(state, addr);
}
+
static void ppu_render_sprites(struct nes_state *state) {
struct ppu_state *ppu = &state->ppu;
@@ -390,22 +349,43 @@ static void ppu_render_sprites(struct nes_state *state) {
}
}
+static void ppu_evaluate_sprites(struct nes_state *state, uint32_t target_scanline) {
+ struct ppu_state *ppu = &state->ppu;
+
+ ppu->sprite_count = 0;
+
+ for(uint32_t i = 0; i < 64; i++) {
+ uint8_t y = ppu->oam[i * 4 + 0];
+ uint8_t height = (ppu->control & 0x20) ? 16 : 8;
+
+ if(target_scanline >= y && target_scanline < y + height) {
+ if(ppu->sprite_count < 8) {
+ uint8_t *dest = &ppu->secondary_oam[ppu->sprite_count * 4];
+ dest[0] = y;
+ dest[1] = ppu->oam[i * 4 + 1];
+ dest[2] = ppu->oam[i * 4 + 2];
+ dest[3] = ppu->oam[i * 4 + 3];
+ ppu->sprite_count++;
+ } else {
+ ppu->sprite_overflow = 0x20;
+ break;
+ }
+ }
+ }
+}
+
+
static void ppu_copy_horizontal_scroll(struct nes_state *state) {
struct ppu_state *ppu = &state->ppu;
- uint32_t addr = ppu->vram_addr;
- ppu->render_coarse_x = (addr >> 0) & 0x1f;
- ppu->render_nt_x = (addr & 0x400) ? 0x400 : 0;
+ ppu->vram_addr = (ppu->vram_addr & ~0x041f) | (ppu->t_addr & 0x041f);
}
static void ppu_copy_vertical_scroll(struct nes_state *state) {
struct ppu_state *ppu = &state->ppu;
- uint32_t addr = ppu->vram_addr;
- ppu->render_coarse_y = (addr >> 5) & 0x1f;
- ppu->render_fine_y = (addr >> 12) & 0x07;
- ppu->render_nt_y = (addr & 0x800) ? 0x800 : 0;
+ ppu->vram_addr = (ppu->vram_addr & ~0x7be0) | (ppu->t_addr & 0x7be0);
}
-__attribute__((flatten))
+
static void ppu_tick(struct nes_state *state) {
struct ppu_state *ppu = &state->ppu;
@@ -431,7 +411,7 @@ static void ppu_tick(struct nes_state *state) {
break;
case 7: {
uint8_t attr = ppu->next_attr;
- uint8_t shift = ((ppu->render_coarse_y >> 2) & 2) | ((ppu->render_coarse_x >> 1) & 1);
+ uint8_t shift = ((ppu->coarse_y >> 2) & 2) | ((ppu->coarse_x >> 1) & 1);
ppu->bg_attribute_latch = (attr >> (shift * 2)) & 3;
ppu_load_background_shifters(state, ppu->next_lo, ppu->next_hi);
break;
@@ -458,7 +438,7 @@ static void ppu_tick(struct nes_state *state) {
}
}
- if(scanline == 261 && dot >= 280) { // && dot <= 304) {
+ if(scanline == 261 && dot >= 280 && dot <= 304) {
ppu_copy_vertical_scroll(state);
}
}
@@ -507,4 +487,3 @@ static void ppu_dma_4014(struct nes_state *state, uint8_t page) {
ppu_write_2004(state, val);
}
}
-