diff options
| author | Peter Fors <peter.fors@mindkiller.com> | 2025-04-02 12:19:38 +0200 |
|---|---|---|
| committer | Peter Fors <peter.fors@mindkiller.com> | 2025-04-02 12:19:38 +0200 |
| commit | 6f63478cf43d4c0b77cabe3f76710f2b9f0c912e (patch) | |
| tree | efc5ccd04867fc5bc66112e7280273718ebccb83 | |
| parent | 7888e1d5408ed5f88cff788c37b942076f6b9c63 (diff) | |
Itsa twerking.
| -rw-r--r-- | base/base.c | 4 | ||||
| -rw-r--r-- | base/opengl.c | 2 | ||||
| -rw-r--r-- | base/settings.h | 2 | ||||
| -rwxr-xr-x | build.sh | 2 | ||||
| -rw-r--r-- | mknes.c | 17 | ||||
| -rw-r--r-- | mknes.h | 27 | ||||
| -rw-r--r-- | ppu.c | 61 |
7 files changed, 70 insertions, 45 deletions
diff --git a/base/base.c b/base/base.c index ab30d8b..00b73ae 100644 --- a/base/base.c +++ b/base/base.c @@ -58,9 +58,9 @@ /* [=]===^=[ main ]=================================================================^===[=] */ int main(int argc, char **argv) { state.toggle_crt_emulation = true; - mkfw_init(SCREEN_WIDTH*3, SCREEN_HEIGHT*3); + mkfw_init(320*5, 240*5); mkfw_set_swapinterval(0); - mkfw_set_window_min_size_and_aspect(320*3, 240*3, 320, 240); + mkfw_set_window_min_size_and_aspect(320*5, 240*5, 320, 240); mkfw_set_key_callback(key_callback); mkfw_set_mouse_move_delta_callback(mouse_move_callback); mkfw_set_mouse_button_callback(mouse_button_callback); diff --git a/base/opengl.c b/base/opengl.c index 641a2a0..23cbecd 100644 --- a/base/opengl.c +++ b/base/opengl.c @@ -68,7 +68,7 @@ static void opengl_setup(const char *vertex_shader_src, const char *fragment_sha // Calculations for the shader. state.contrast = 1.0f; - state.saturation = 0.3f; + state.saturation = 0.0f; state.brightness = 1.0f; CrtsTone(state.tone_data, state.contrast, state.saturation, INPUT_THIN, INPUT_MASK); // NOTE(peter): Move this into the mainloop if change of contrast/saturation is added as an interactive thing. diff --git a/base/settings.h b/base/settings.h index c8d3c5c..be448c4 100644 --- a/base/settings.h +++ b/base/settings.h @@ -3,7 +3,7 @@ // #define PERF_TEST #ifndef PERF_TEST -// #define PROFILER +#define PROFILER #endif @@ -5,7 +5,7 @@ PROJECT_NAME="mknes" # Change this for each new project # Base configuration common to all builds CFLAGS="-std=gnu11 " -CFLAGS+="-mavx2 -mtune=native -mfunction-return=keep -mindirect-branch=keep " +CFLAGS+="-mavx2 -mbmi2 -mtune=native -mfunction-return=keep -mindirect-branch=keep " CFLAGS+="-fwrapv -ffast-math -fno-trapping-math -fwhole-program " CFLAGS+="-fno-stack-protector -fno-PIE -no-pie -fno-strict-aliasing -ffunction-sections -fdata-sections " CFLAGS+="-Wall -Wextra " @@ -20,6 +20,7 @@ static void render_callback(void) { clear_buffer(); while(!nstate.ppu.frame_ready) { + PROFILE_NAMED("nes emulator"); cpu_tick(&nstate); } nstate.ppu.frame_ready = 0; @@ -68,11 +69,23 @@ static void init_callback(void) { // ines2_load(&nstate, "data/nrom/10-Yard Fight (USA, Europe).nes"); // ines2_load(&nstate, "data/nrom/Balloon Fight (USA).nes"); // ines2_load(&nstate, "data/nrom/Excitebike (Japan, USA).nes"); - ines2_load(&nstate, "data/nrom/Ice Climber (USA, Europe, Korea).nes"); + // ines2_load(&nstate, "data/nrom/Ice Climber (USA, Europe, Korea).nes"); // ines2_load(&nstate, "data/nrom/Kung Fu (Japan, USA).nes"); // ines2_load(&nstate, "data/nrom/Super Mario Bros. (World) (HVC-SM).nes"); // ines2_load(&nstate, "data/nrom/Urban Champion (World).nes"); - // ines2_load(&nstate, "data/nrom/Wrecking Crew (World).nes"); + ines2_load(&nstate, "data/nrom/Wrecking Crew (World).nes"); + // ines2_load(&nstate, "data/nrom/scanline.nes"); + // ines2_load(&nstate, "data/nrom/Sayoonara!.NES"); + // ines2_load(&nstate, "data/nrom/raster_demos/RasterChromaLuma.NES"); + // ines2_load(&nstate, "data/nrom/raster_demos/RasterTest1.NES"); + // ines2_load(&nstate, "data/nrom/raster_demos/RasterTest2.NES"); + // ines2_load(&nstate, "data/nrom/raster_demos/RasterTest3.NES"); + // ines2_load(&nstate, "data/nrom/raster_demos/RasterTest3a.NES"); + // ines2_load(&nstate, "data/nrom/raster_demos/RasterTest3b.NES"); + // ines2_load(&nstate, "data/nrom/raster_demos/RasterTest3c.NES"); + // ines2_load(&nstate, "data/nrom/raster_demos/RasterTest3d.NES"); + // ines2_load(&nstate, "data/nrom/raster_demos/RasterTest3e.NES"); + // ines2_load(&nstate, "data/nrom/NEStress.NES"); mapper_setup(&nstate); uint32_t lo = nstate.mapper.read(&nstate, 0xfffc); @@ -147,12 +147,23 @@ struct nes_state { }; static uint32_t nes_palette[64] = { - 0x757575ff, 0x271a75ff, 0x3b0072ff, 0x4c0f64ff, 0x400048ff, 0x600027ff, 0x600000ff, 0x500f00ff, - 0x783a00ff, 0x755c00ff, 0x406c00ff, 0x504764ff, 0x005468ff, 0x000000ff, 0x000000ff, 0x000000ff, - 0xbfbfbfff, 0x273aa7ff, 0x5c14a7ff, 0x7514a7ff, 0x751468ff, 0x982727ff, 0xa03a00ff, 0x986c00ff, - 0x888800ff, 0x689800ff, 0x3aa700ff, 0x6c6c6cff, 0x007878ff, 0x000000ff, 0x000000ff, 0x000000ff, - 0xffffffff, 0x3ab5ffff, 0x5cb5ffff, 0x9888ffff, 0xa778ffff, 0xc87878ff, 0xf05c00ff, 0xf08800ff, - 0xe0a700ff, 0xb8b800ff, 0x88c800ff, 0xcccc68ff, 0x00e0d8ff, 0x000000ff, 0x000000ff, 0x000000ff, - 0xffffffff, 0xa7e0ffff, 0xb8d8ffff, 0xc8c8ffff, 0xd8b8ffff, 0xd8a7a7ff, 0xf0d0b8ff, 0xf0d898ff, - 0xf0c878ff, 0xd8d878ff, 0xb8e078ff, 0xd0e0b8ff, 0xb8f0f0ff, 0x000000ff, 0x000000ff, 0x000000ff +// 0x757575ff, 0x271a75ff, 0x3b0072ff, 0x4c0f64ff, 0x400048ff, 0x600027ff, 0x600000ff, 0x500f00ff, +// 0x783a00ff, 0x755c00ff, 0x406c00ff, 0x504764ff, 0x005468ff, 0x000000ff, 0x000000ff, 0x000000ff, +// 0xbfbfbfff, 0x273aa7ff, 0x5c14a7ff, 0x7514a7ff, 0x751468ff, 0x982727ff, 0xa03a00ff, 0x986c00ff, +// 0x888800ff, 0x689800ff, 0x3aa700ff, 0x6c6c6cff, 0x007878ff, 0x000000ff, 0x000000ff, 0x000000ff, +// 0xffffffff, 0x3ab5ffff, 0x5cb5ffff, 0x9888ffff, 0xa778ffff, 0xc87878ff, 0xf05c00ff, 0xf08800ff, +// 0xe0a700ff, 0xb8b800ff, 0x88c800ff, 0xcccc68ff, 0x00e0d8ff, 0x000000ff, 0x000000ff, 0x000000ff, +// 0xffffffff, 0xa7e0ffff, 0xb8d8ffff, 0xc8c8ffff, 0xd8b8ffff, 0xd8a7a7ff, 0xf0d0b8ff, 0xf0d898ff, +// 0xf0c878ff, 0xd8d878ff, 0xb8e078ff, 0xd0e0b8ff, 0xb8f0f0ff, 0x000000ff, 0x000000ff, 0x000000ff +// }; + +0x585858ff, 0x00237cff, 0x0d1099ff, 0x300092ff, 0x4f006cff, 0x600035ff, 0x5c0500ff, 0x461800ff, +0x272d00ff, 0x093e00ff, 0x004500ff, 0x004106ff, 0x003545ff, 0x000000ff, 0x000000ff, 0x000000ff, +0xa1a1a1ff, 0x0b53d7ff, 0x3337feff, 0x6621f7ff, 0x9515beff, 0xac166eff, 0xa62721ff, 0x864300ff, +0x596200ff, 0x2d7a00ff, 0x0c8500ff, 0x007f2aff, 0x006d85ff, 0x000000ff, 0x000000ff, 0x000000ff, +0xffffffff, 0x51a5feff, 0x8084feff, 0xbc6afeff, 0xf15bfeff, 0xfe5ec4ff, 0xfe7269ff, 0xe19321ff, +0xadb600ff, 0x79d300ff, 0x51df21ff, 0x3ad974ff, 0x39c3dfff, 0x424242ff, 0x000000ff, 0x000000ff, +0xffffffff, 0xb5d9feff, 0xcacafeff, 0xe3befeff, 0xf9b8feff, 0xfebae7ff, 0xfec3bcff, 0xf4d199ff, +0xdee086ff, 0xc6ec87ff, 0xb2f29dff, 0xa7f0c3ff, 0xa8e7f0ff, 0xacacacff, 0x000000ff, 0x000000ff }; + @@ -22,23 +22,27 @@ static void ppu_sprite_shift(struct nes_state *state) { static void ppu_reset(struct nes_state *state) { struct ppu_state *ppu = &state->ppu; memset(ppu, 0, sizeof(struct ppu_state)); - } static uint32_t ppu_resolve_ciram(struct nes_state *state, uint32_t addr) { - // Apply mirroring logic to address in $2000–$2FFF range addr &= 0x0fff; switch(state->ines.mirroring) { - case MIRROR_VERTICAL: - return (addr & 0x0800) | (addr & 0x03ff); // $2000/$2800 → $0000, $2400/$2C00 → $0400 - case MIRROR_HORIZONTAL: - return ((addr & 0x0400) >> 1) | (addr & 0x03ff); // $2000/$2400 → $0000, $2800/$2C00 → $0400 - default: - return addr & 0x07ff; // For now, 4-screen = direct + case MIRROR_VERTICAL: { + // $2000/$2800 → $0000, $2400/$2C00 → $0400 + return (addr & 0x0400) | (addr & 0x03ff); + } + case MIRROR_HORIZONTAL: { + // $2000/$2400 → $0000, $2800/$2C00 → $0400 + return ((addr & 0x0800) >> 1) | (addr & 0x03ff); + } + default: { + return addr & 0x07ff; + } } } + static uint8_t ppu_ciram_read(struct nes_state *state, uint32_t addr) { return state->ppu.ciram[ppu_resolve_ciram(state, addr)]; } @@ -47,7 +51,6 @@ static void ppu_ciram_write(struct nes_state *state, uint32_t addr, uint8_t valu state->ppu.ciram[ppu_resolve_ciram(state, addr)] = value; } - static void ppu_write_2000(struct nes_state *state, uint8_t value) { struct ppu_state *ppu = &state->ppu; ppu->reg_ctrl = value; @@ -96,12 +99,10 @@ 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; uint32_t addr = ppu->vram_addr & 0x3fff; - if(addr < 0x2000) { // CHR-RAM, skip } else if(addr < 0x3f00) { - uint32_t mirrored_addr = addr & 0x0fff; - ppu->ciram[mirrored_addr & 0x7ff] = value; + ppu_ciram_write(state, addr, value); } else if(addr < 0x4000) { uint32_t pal_addr = addr & 0x1f; if((pal_addr & 0x13) == 0x10) { @@ -132,31 +133,24 @@ static uint8_t ppu_read_2007(struct nes_state *state) { uint32_t addr = ppu->vram_addr & 0x3fff; uint8_t result = 0; - // Read from CHR-RAM (CHR-ROM in PPU) if(addr < 0x2000) { result = ppu->vram_read_buffer; ppu->vram_read_buffer = state->chrrom[addr]; } else if(addr < 0x3f00) { - // Read from CIRAM (internal VRAM) - uint32_t mirrored_addr = addr & 0x0fff; - if(state->ines.mirroring == 2) { - mirrored_addr |= (addr & 0x0800) ? 0x400 : 0x000; // Handle 4-screen mirroring - } - result = ppu->ciram[mirrored_addr & 0x7ff]; + result = ppu_ciram_read(state, addr); } else if(addr < 0x4000) { - // Read from palette uint32_t pal_addr = addr & 0x1f; if((pal_addr & 0x13) == 0x10) { - pal_addr &= ~0x10; // Skip over the unused area of the palette + pal_addr &= ~0x10; } result = ppu->palette[pal_addr]; } - // Update VRAM address based on control register ppu->vram_addr += (ppu->reg_ctrl & 0x04) ? 32 : 1; return result; } + static void ppu_evaluate_sprites(struct nes_state *state) { struct ppu_state *ppu = &state->ppu; uint8_t sprite_height = (ppu->reg_ctrl & 0x20) ? 16 : 8; @@ -297,6 +291,7 @@ static void ppu_render_pixel(struct nes_state *state) { ppu->pixels[y * 256 + x] = final_color; } +__attribute__((flatten)) static void ppu_tick(struct nes_state *state) { struct ppu_state *ppu = &state->ppu; @@ -322,12 +317,12 @@ static void ppu_tick(struct nes_state *state) { switch(dot % 8) { case 1: { uint32_t nt_addr = 0x2000 | (ppu->vram_addr & 0x0fff); - ppu->bg_next_tile_id = ppu->ciram[nt_addr & 0x07ff]; + ppu->bg_next_tile_id = ppu_ciram_read(state, nt_addr); break; } case 3: { uint32_t attr_addr = 0x23c0 | (ppu->vram_addr & 0x0c00) | ((ppu->vram_addr >> 4) & 0x38) | ((ppu->vram_addr >> 2) & 0x07); - uint8_t attr = ppu->ciram[attr_addr & 0x07ff]; + uint8_t attr = ppu_ciram_read(state, attr_addr); uint8_t shift = ((ppu->vram_addr >> 4) & 4) | (ppu->vram_addr & 2); ppu->bg_next_tile_attrib = (attr >> shift) & 3; break; @@ -356,12 +351,12 @@ static void ppu_tick(struct nes_state *state) { ppu->bg_shift_attrib_low = (ppu->bg_shift_attrib_low & 0xff00) | ((a & 1) ? 0xff : 0x00); ppu->bg_shift_attrib_high = (ppu->bg_shift_attrib_high & 0xff00) | ((a & 2) ? 0xff : 0x00); - if((ppu->vram_addr & 0x001f) == 31) { - ppu->vram_addr &= ~0x001f; - ppu->vram_addr ^= 0x0400; - } else { - ppu->vram_addr++; - } + if((ppu->vram_addr & 0x001f) == 31) { + ppu->vram_addr &= ~0x001f; + ppu->vram_addr ^= 0x0400; + } else { + ppu->vram_addr++; + } break; } @@ -395,6 +390,12 @@ static void ppu_tick(struct nes_state *state) { ppu->vram_addr = (ppu->vram_addr & ~0x7be0) | (ppu->temp_addr & 0x7be0); } +// if(scanline == 261 && dot >= 280 && dot <= 304) { +// printf("Scroll Copy (V): SL:%d DOT:%d vram_addr=%04x temp_addr=%04x\n", scanline, dot, ppu->vram_addr, ppu->temp_addr); +// ppu->vram_addr = (ppu->vram_addr & 0x041f) | (ppu->temp_addr & 0x7be0); +// } + + if(dot == 257 && scanline < 240) { ppu_evaluate_sprites(state); } |
