summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--base/base.c4
-rw-r--r--base/opengl.c2
-rw-r--r--base/settings.h2
-rwxr-xr-xbuild.sh2
-rw-r--r--mknes.c17
-rw-r--r--mknes.h27
-rw-r--r--ppu.c61
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
diff --git a/build.sh b/build.sh
index e05fc05..60de1d1 100755
--- a/build.sh
+++ b/build.sh
@@ -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 "
diff --git a/mknes.c b/mknes.c
index a156655..6150ba4 100644
--- a/mknes.c
+++ b/mknes.c
@@ -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);
diff --git a/mknes.h b/mknes.h
index 5997bc8..8ed7554 100644
--- a/mknes.h
+++ b/mknes.h
@@ -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
};
+
diff --git a/ppu.c b/ppu.c
index 1c34381..4246e20 100644
--- a/ppu.c
+++ b/ppu.c
@@ -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);
}