diff options
| -rw-r--r-- | .gitignore | 1 | ||||
| -rw-r--r-- | callbacks.c | 32 | ||||
| -rw-r--r-- | mapper.c | 1 | ||||
| -rw-r--r-- | memory.c | 10 | ||||
| -rw-r--r-- | mknes.c | 15 | ||||
| -rw-r--r-- | mknes.h | 17 | ||||
| -rw-r--r-- | ppu.c | 3 |
7 files changed, 52 insertions, 27 deletions
@@ -1,6 +1,7 @@ .vscode mknes data +documentation TODO dump_mappers fragment_shader.h diff --git a/callbacks.c b/callbacks.c index a610a43..4523a68 100644 --- a/callbacks.c +++ b/callbacks.c @@ -53,25 +53,25 @@ static void key_callback(GLFWwindow *window, int key, int scancode, int action, if(action == GLFW_PRESS) { switch(key) { - case GLFW_KEY_X: nes_state->input[0] |= (1 << 0); break; // A - case GLFW_KEY_Z: nes_state->input[0] |= (1 << 1); break; // B - case GLFW_KEY_SPACE: nes_state->input[0] |= (1 << 2); break; // Select - case GLFW_KEY_ENTER: nes_state->input[0] |= (1 << 3); break; // Start - case GLFW_KEY_UP: nes_state->input[0] |= (1 << 4); break; - case GLFW_KEY_DOWN: nes_state->input[0] |= (1 << 5); break; - case GLFW_KEY_LEFT: nes_state->input[0] |= (1 << 6); break; - case GLFW_KEY_RIGHT: nes_state->input[0] |= (1 << 7); break; + case GLFW_KEY_X: nes_state->input[0] |= (1 << 0); break; // A + case GLFW_KEY_Z: nes_state->input[0] |= (1 << 1); break; // B + case GLFW_KEY_SPACE: nes_state->input[0] |= (1 << 2); break; // Select + case GLFW_KEY_ENTER: nes_state->input[0] |= (1 << 3); break; // Start + case GLFW_KEY_UP: nes_state->input[0] |= (1 << 4); break; + case GLFW_KEY_DOWN: nes_state->input[0] |= (1 << 5); break; + case GLFW_KEY_LEFT: nes_state->input[0] |= (1 << 6); break; + case GLFW_KEY_RIGHT: nes_state->input[0] |= (1 << 7); break; } } else if(action == GLFW_RELEASE) { switch(key) { - case GLFW_KEY_X: nes_state->input[0] &= ~(1 << 0); break; - case GLFW_KEY_Z: nes_state->input[0] &= ~(1 << 1); break; - case GLFW_KEY_SPACE: nes_state->input[0] &= ~(1 << 2); break; - case GLFW_KEY_ENTER: nes_state->input[0] &= ~(1 << 3); break; - case GLFW_KEY_UP: nes_state->input[0] &= ~(1 << 4); break; - case GLFW_KEY_DOWN: nes_state->input[0] &= ~(1 << 5); break; - case GLFW_KEY_LEFT: nes_state->input[0] &= ~(1 << 6); break; - case GLFW_KEY_RIGHT: nes_state->input[0] &= ~(1 << 7); break; + case GLFW_KEY_X: nes_state->input[0] &= ~(1 << 0); break; + case GLFW_KEY_Z: nes_state->input[0] &= ~(1 << 1); break; + case GLFW_KEY_SPACE: nes_state->input[0] &= ~(1 << 2); break; + case GLFW_KEY_ENTER: nes_state->input[0] &= ~(1 << 3); break; + case GLFW_KEY_UP: nes_state->input[0] &= ~(1 << 4); break; + case GLFW_KEY_DOWN: nes_state->input[0] &= ~(1 << 5); break; + case GLFW_KEY_LEFT: nes_state->input[0] &= ~(1 << 6); break; + case GLFW_KEY_RIGHT: nes_state->input[0] &= ~(1 << 7); break; } } @@ -37,6 +37,7 @@ static void mapper_default_tick(struct nes_state *state) { // No IRQ or timing l */ static struct mapper_entry mapper_table[] = { /* Mapper: 0 */ { 0x00, mapper_0000_prg_read, mapper_0000_prg_write, mapper_0000_chr_read, mapper_0000_chr_write, mapper_default_ciram_read, mapper_default_ciram_write, mapper_default_tick, mapper_0000_init }, +/* Mapper: 2 */ { 0x02, mapper_2002_prg_read, mapper_2002_prg_write, mapper_2002_chr_read, mapper_2002_chr_write, mapper_default_ciram_read, mapper_default_ciram_write, mapper_default_tick, mapper_2002_init }, /* Mapper: 3 */ { 0x03, mapper_0003_prg_read, mapper_0003_prg_write, mapper_0003_chr_read, mapper_0003_chr_write, mapper_default_ciram_read, mapper_default_ciram_write, mapper_default_tick, mapper_0003_init }, /* Mapper: 7 */ { 0x7, mapper_0007_prg_read, mapper_0007_prg_write, mapper_0007_chr_read, mapper_0007_chr_write, mapper_0007_ciram_read, mapper_0007_ciram_write, mapper_default_tick, mapper_0007_init }, /* Mapper: b */ { 0x0b, mapper_000b_prg_read, mapper_000b_prg_write, mapper_000b_chr_read, mapper_000b_chr_write, mapper_default_ciram_read, mapper_default_ciram_write, mapper_default_tick, mapper_000b_init }, @@ -8,15 +8,19 @@ static uint8_t memory_read(struct nes_state *restrict state, uint32_t offset) { if(LIKELY(offset < 0x2000)) { return state->ram[offset & 0x07ff]; + } else if(offset < 0x4000) { return ppu_read(state, offset); + } else if(offset == 0x4016 || offset == 0x4017) { uint32_t index = offset & 1; uint8_t value = (state->input_latch[index] >> state->input_bit[index]) & 1; state->input_bit[index]++; return value | 0x40; // Bit 6 open bus high, bit 7 low + } else if(LIKELY(offset >= 0x6000)) { return state->mapper.prg_read(state, offset); + } return 0; } @@ -28,10 +32,13 @@ static void memory_write(struct nes_state *restrict state, uint32_t offset, uint if(LIKELY(offset < 0x2000)) { state->ram[offset & 0x07ff] = value; + } else if(offset < 0x4000) { ppu_write(state, offset, value); + } else if(offset == 0x4014) { ppu_dma_4014(state, value); + } else if(offset == 0x4016) { uint8_t prev = state->input_strobe; state->input_strobe = value & 1; @@ -43,6 +50,7 @@ static void memory_write(struct nes_state *restrict state, uint32_t offset, uint state->input_bit[0] = 0; state->input_bit[1] = 0; } + } else if(offset >= 0x6000) { state->mapper.prg_write(state, offset, value); } @@ -53,8 +61,10 @@ static uint8_t memory_read_dma(struct nes_state *restrict state, uint32_t offset // Do not tick CPU/PPU/APU — caller handles timing if(LIKELY(offset < 0x2000)) { return state->ram[offset & 0x07ff]; + } else if(offset >= 0x6000) { return state->mapper.prg_read(state, offset); + } return 0; } @@ -90,6 +90,7 @@ static GLFWwindow *window; #include "render.c" static uint32_t frames; // debug information +// #include "smb_tas.h" // REMOVE ME // NES core #include "mapper.h" @@ -160,7 +161,6 @@ static void dump_nametable_text(struct nes_state *state, const char *filename) { - int main(int argc, char **argv) { #ifdef _WIN32 timeBeginPeriod(1); @@ -179,7 +179,9 @@ int main(int argc, char **argv) { // ines2_load(nstate, "data/0000/Excitebike (Japan, USA).nes"); // ines2_load(nstate, "data/0000/Ice Climber (USA, Europe, Korea).nes"); // ines2_load(nstate, "data/0000/Kung Fu (Japan, USA).nes"); - ines2_load(nstate, "data/0000/Super Mario Bros. (World) (HVC-SM).nes"); + // ines2_load(nstate, "data/0000/Super Mario Bros. (World) (HVC-SM).nes"); + // ines2_load(nstate, "data/Super Mario Bros. (W) (V1.0) [!].nes"); + ines2_load(nstate, "data/Super Mario Bros. (JU) [!].nes"); // ines2_load(nstate, "data/0000/Urban Champion (World).nes"); // ines2_load(nstate, "data/0000/Wrecking Crew (World).nes"); // ines2_load(nstate, "data/0000/scanline.nes"); @@ -199,11 +201,13 @@ int main(int argc, char **argv) { // ines2_load(nstate, "data/0000/Xevious - The Avenger (USA).zip"); // ines2_load(nstate, "data/tv.nes"); + // ines2_load(nstate, "data/Rad Racer II (USA).zip"); + // ines2_load(nstate, "data/0003/Flipull - An Exciting Cube Game (Japan) (En).zip"); // ines2_load(nstate, "data/0003/Friday the 13th (USA).zip"); // ines2_load(nstate, "data/0003/Ghostbusters (Japan).zip"); // ines2_load(nstate, "data/0003/Gradius (USA).zip"); - ines2_load(nstate, "data/0007/Battletoads (USA).zip"); + // ines2_load(nstate, "data/0007/Battletoads (USA).zip"); // ines2_load(nstate, "data/0007/Beetlejuice (USA).zip"); // ines2_load(nstate, "data/0007/Cabal (USA).zip"); @@ -275,6 +279,9 @@ int main(int argc, char **argv) { // printf("Frame: %d\n", frames); + +// static int32_t tas_frame = 0; +// nstate->input[0] = tas_input[tas_frame++]; while(!nstate->ppu.frame_ready) { // PROFILE_NAMED("nes emulator"); cpu_tick(nstate); @@ -282,7 +289,7 @@ int main(int argc, char **argv) { nstate->ppu.frame_ready = 0; frames++; -dump_nametable_text(nstate, "_foofbomb.txt"); +// dump_nametable_text(nstate, "_foofbomb.txt"); uint32_t * restrict dst = display_buffer; //buffer; uint8_t * restrict src = nstate->pixels; @@ -26,11 +26,11 @@ struct ppu_state { uint16_t bg_shift_attrib_low; uint16_t bg_shift_attrib_high; - uint32_t scanline; - uint32_t dot; - uint32_t vram_addr; - uint32_t temp_addr; - uint32_t fine_x; + uint16_t scanline; + uint16_t dot; + uint16_t vram_addr; + uint16_t temp_addr; + uint8_t fine_x; uint8_t bg_next_tile_id; uint8_t bg_next_tile_attrib; uint8_t bg_next_tile_lsb; @@ -49,20 +49,23 @@ struct ppu_state { uint8_t open_bus; - uint8_t frame_ready; uint8_t sprite_zero_hit_possible; uint8_t sprite_count; + uint8_t palette[32]; + + // NOTE(peter): CACHELINE 2 start here! + uint8_t sprite_indexes[8]; uint8_t sprite_positions[8]; uint8_t sprite_priorities[8]; uint8_t sprite_shift_lo[8]; uint8_t sprite_shift_hi[8]; - uint8_t palette[32]; uint8_t secondary_oam[32]; uint8_t oam[256]; + uint8_t frame_ready; } __attribute__((packed, aligned(64))); struct cpu_state { @@ -397,6 +397,9 @@ static void ppu_tick(struct nes_state *state) { } if(UNLIKELY(scanline == 241) && dot == 1) { + // static int32_t tas_frame = 0; + // state->input[0] = tas_input[tas_frame++]; + ppu->reg_status |= 0x80; if(ppu->reg_ctrl & 0x80) { state->nmi_pending = 1; |
