From 66785039a9f981489a7fd5a5cfa25a11988ff852 Mon Sep 17 00:00:00 2001 From: FyloZ Date: Thu, 23 May 2024 23:52:04 -0400 Subject: [PATCH] Fix memory mapping --- CMakeLists.txt | 4 +- cpu/cpu.c | 2 +- cpu/memory.c | 115 +++++++++++++++++++++++++++++++-------------- cpu/memory.h | 4 +- include/ppu.h | 15 ++++-- include/rom.h | 2 +- include/types.h | 6 +-- main.c | 2 +- mappers/nrom.c | 16 ++----- ppu/CMakeLists.txt | 6 +-- ppu/memory.c | 48 ------------------- ppu/memory.h | 28 ----------- ppu/ppu.c | 53 ++++++++------------- rom/ines.c | 4 +- rom/rom.c | 5 +- system.c | 6 +-- 16 files changed, 131 insertions(+), 185 deletions(-) delete mode 100644 ppu/memory.c delete mode 100644 ppu/memory.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 1564b1e..480ed19 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -11,7 +11,7 @@ add_subdirectory(cpu) add_subdirectory(ppu) add_subdirectory(mappers) add_subdirectory(rom) -add_subdirectory(debugger) +#add_subdirectory(debugger) add_subdirectory(utils) add_subdirectory(gui) @@ -29,7 +29,7 @@ set(SOURCE main.c system.c) add_executable(nes_emulator ${HEADERS} ${SOURCE}) -target_link_libraries(nes_emulator nes_cpu nes_ppu nes_mappers nes_rom nes_debugger nes_utils nes_gui log.c) +target_link_libraries(nes_emulator nes_cpu nes_ppu nes_mappers nes_rom nes_utils nes_gui log.c) target_include_directories(nes_emulator PUBLIC "${PROJECT_BINARY_DIR}" ${EXTRA_INCLUDES}) \ No newline at end of file diff --git a/cpu/cpu.c b/cpu/cpu.c index d3de015..a1d5765 100644 --- a/cpu/cpu.c +++ b/cpu/cpu.c @@ -64,7 +64,7 @@ void cpu_process_nmi() { } void oam_dma_upload() { - byte page_high_addr = *ppu_get_state()->oam_dma_register; // TODO + byte page_high_addr = ppu_get_state()->oam_dma_register; // TODO address page_addr = ((address) page_high_addr) << 8; byte n = 0xff; diff --git a/cpu/memory.c b/cpu/memory.c index ffec9c1..b7b93fa 100644 --- a/cpu/memory.c +++ b/cpu/memory.c @@ -8,62 +8,107 @@ #include "../include/rom.h" #include "cpu.h" + +#define RAM_SIZE 0x0800 #define RAM_MAX_ADDR 0x2000 -#define RAM_BANK_SIZE 0x800 #define PPU_MAX_ADDR 0x4000 -#define PPU_BANK_SIZE 0x8 #define APU_MAX_ADDR 0x4020 -#define MAX_ADDR 0xffff +#define UNMAPPED_MAX_ADDR 0x6000 +#define CARTRIDGE_RAM_MAX_ADDR 0x8000 +#define MEM_ADDR_MAX 0xffff byte ram[RAM_SIZE]; -byte mem_get_byte(address addr) { - assert(addr <= MAX_ADDR); +byte *mem_get_ptr(address addr) { + assert(addr <= RAM_MAX_ADDR); - if (addr >= RAM_MAX_ADDR && addr < PPU_MAX_ADDR) { - byte reg = (addr - RAM_MAX_ADDR) % PPU_BANK_SIZE; - return ppu_read_reg(reg); + if (addr < RAM_MAX_ADDR) { + address ram_addr = addr % RAM_SIZE; // There is four mirror of RAM + return &ram[ram_addr]; } - return ram[addr]; + // Only supported for RAM + assert(false); } -byte *mem_get_ptr(address addr) { - assert(addr <= MAX_ADDR); +byte mem_get_byte(address addr) { + assert(addr <= MEM_ADDR_MAX); - return &ram[addr]; + if (addr < RAM_MAX_ADDR) { + address ram_addr = addr % RAM_SIZE; + return ram[ram_addr]; + } else if (addr < PPU_MAX_ADDR) { + address relative_addr = addr - RAM_MAX_ADDR; + byte ppu_reg = relative_addr % 8; + return ppu_read_reg(ppu_reg); + } else if (addr < APU_MAX_ADDR) { + // TODO NES API and I/O registers + return 0; + } else if (addr < UNMAPPED_MAX_ADDR) { + // Unmapped + assert(false); + } else if (addr < CARTRIDGE_RAM_MAX_ADDR) { + // TODO Cartridge RAM + return 0; + } else { + address rom_addr = addr - CARTRIDGE_RAM_MAX_ADDR; + + Mapper *mapper = system_get_mapper(); + return *(mapper->mem_read(rom_addr)); + } } word mem_get_word(address addr) { - assert(addr < MAX_ADDR); + assert(addr <= MEM_ADDR_MAX - 1); - word word = ram[addr]; - word += ram[addr + 1] << 8; // Little endian - return word; + byte data1; + byte data2; + + if (addr < RAM_MAX_ADDR - 1) { + address ram_addr = addr % RAM_SIZE; + data1 = ram[ram_addr]; + data2 = ram[ram_addr + 1]; + } else if (addr < UNMAPPED_MAX_ADDR) { + // Unsupported + assert(false); + } else if (addr < CARTRIDGE_RAM_MAX_ADDR) { + // TODO Cartridge RAM + return 0; + } else { + address rom_addr = addr - CARTRIDGE_RAM_MAX_ADDR; + + Mapper *mapper = system_get_mapper(); + byte *location = mapper->mem_read(rom_addr); + + data1 = *location; + data2 = *(location + 1); + } + + return data1 + (data2 << 8); } -void mem_set_byte(address addr, byte byte) { - assert(addr < MAX_ADDR); - - log_trace("Writing '%02x' to address 0x%04x", byte, addr); +void mem_set_byte(address addr, byte data) { + assert(addr < MEM_ADDR_MAX); if (addr < RAM_MAX_ADDR) { - address init_ram_addr = addr % RAM_BANK_SIZE; - - // The value must also be cloned in the three mirrors - for (int i = 0; i < 4; i++) { - address ram_addr = init_ram_addr + RAM_BANK_SIZE * i; - ram[ram_addr] = byte; - } + address ram_addr = addr % RAM_SIZE; + ram[ram_addr] = data; } else if (addr < PPU_MAX_ADDR) { - address reg_addr = (addr - RAM_MAX_ADDR) % PPU_BANK_SIZE; - ppu_write_reg(reg_addr, byte); + address relative_addr = addr - RAM_MAX_ADDR; + byte ppu_reg = relative_addr % 8; + ppu_write_reg(ppu_reg, data); + } else if (addr == PPU_REGISTER_OAM_DMA_ADDR) { + // Writing to this address triggers an upload to the PPU memory + cpu_trigger_oam_dma(); + } else if (addr < APU_MAX_ADDR) { + // TODO NES API and I/O registers + } else if (addr < UNMAPPED_MAX_ADDR) { + // Unmapped + assert(false); + } else if (addr < CARTRIDGE_RAM_MAX_ADDR) { + // TODO Cartridge RAM } else { - ram[addr] = byte; - - if (addr == PPU_REGISTER_OAM_DMA_ADDR) { - // Writing to this address triggers an upload to the PPU memory - cpu_trigger_oam_dma(); - } + // ROM is read-only + assert(false); } } \ No newline at end of file diff --git a/cpu/memory.h b/cpu/memory.h index 6de54cf..771a0f6 100644 --- a/cpu/memory.h +++ b/cpu/memory.h @@ -37,8 +37,8 @@ word mem_get_word(address addr); * Sets a byte in a system's memory. * * @param addr The address to set - * @param value The value to set + * @param data The data to set */ -void mem_set_byte(address addr, byte value); +void mem_set_byte(address addr, byte data); #endif //NESEMULATOR_MEMORY_H diff --git a/include/ppu.h b/include/ppu.h index 2117125..26eb7e1 100644 --- a/include/ppu.h +++ b/include/ppu.h @@ -5,7 +5,6 @@ #include #include #include "types.h" -#include "../ppu/memory.h" #ifndef NESEMULATOR_PPU_H #define NESEMULATOR_PPU_H @@ -61,11 +60,18 @@ typedef struct ppu_memory { byte *palette; } PPUMemory; +typedef struct ppu_tile_fetch { + byte nametable; + byte attribute_table; + byte pattern_table_tile_low; + byte pattern_table_tile_high; +} PPUTileFetch; + typedef struct ppu { PPUMemory memory; - byte *registers; - byte *oam_dma_register; + byte registers[8]; + byte oam_dma_register; byte vram[PPU_VRAM_SIZE]; byte oam[PPU_OAM_SIZE]; bool odd_frame; @@ -90,8 +96,7 @@ PPU *ppu_get_state(); * * @param ppu */ -void ppu_init(byte *registers_ram, byte *oam_dma_register); -void ppu_uninit(); +void ppu_init(); /** * Cycles the PPU. diff --git a/include/rom.h b/include/rom.h index c55c284..8966bc3 100644 --- a/include/rom.h +++ b/include/rom.h @@ -19,7 +19,7 @@ typedef struct { bool nametable_mirrored; byte *prg_rom; - int prg_rom_size; + unsigned int prg_rom_size; byte *chr_rom; } Rom; diff --git a/include/types.h b/include/types.h index 81cb718..34f5338 100644 --- a/include/types.h +++ b/include/types.h @@ -5,14 +5,14 @@ #ifndef NESEMULATOR_TYPES_H #define NESEMULATOR_TYPES_H -#define RAM_SIZE 0xffff -#define VRAM_SIZE 0x4000 +//#define RAM_SIZE 0xffff +//#define VRAM_SIZE 0x4000 typedef unsigned char byte; typedef unsigned short address; typedef unsigned short word; //typedef byte ram[RAM_SIZE]; -typedef byte vram[VRAM_SIZE]; +//typedef byte vram[VRAM_SIZE]; #endif //NESEMULATOR_TYPES_H diff --git a/main.c b/main.c index 64d8364..4b94fb5 100644 --- a/main.c +++ b/main.c @@ -27,7 +27,7 @@ int main() { log_set_level(LOG_INFO); system_init(); - char *rom_path = "../test_roms/dk_japan.nes"; + char *rom_path = "../test_roms/dk_jp.nes"; if (!rom_load(rom_path)) { system_uninit(); diff --git a/mappers/nrom.c b/mappers/nrom.c index 8875801..2fcf27b 100644 --- a/mappers/nrom.c +++ b/mappers/nrom.c @@ -2,23 +2,17 @@ #include "../include/rom.h" #include "../cpu/memory.h" -#define SIMPLE_MAPPER_PRG_START_ADDR 0x8000 #define PRG_BANK_SIZE 0x4000 // 16Kb byte *nrom_mem_read(address addr) { - if (addr >= SIMPLE_MAPPER_PRG_START_ADDR) { - Rom *rom = rom_get(); - address relative_addr = addr - SIMPLE_MAPPER_PRG_START_ADDR; + Rom *rom = rom_get(); - if (addr < PRG_BANK_SIZE || rom->prg_rom_size > PRG_BANK_SIZE) { - return &rom->prg_rom[relative_addr]; - } - - // The second bank is mirrored - return &rom->prg_rom[relative_addr - PRG_BANK_SIZE]; + if (addr < PRG_BANK_SIZE || rom->prg_rom_size > PRG_BANK_SIZE) { + return &rom->prg_rom[addr]; } - return NULL; + // The second bank is mirrored + return &rom->prg_rom[addr - PRG_BANK_SIZE]; } byte *nrom_ppu_read(address addr) { diff --git a/ppu/CMakeLists.txt b/ppu/CMakeLists.txt index 8724ea9..296161b 100644 --- a/ppu/CMakeLists.txt +++ b/ppu/CMakeLists.txt @@ -1,7 +1,5 @@ -set(HEADERS pattern_table.h ppu.h palette.h - memory.h) -set(SOURCE pattern_table.c ppu.c palette.c - memory.c) +set(HEADERS pattern_table.h ppu.h palette.h) +set(SOURCE pattern_table.c ppu.c palette.c) add_library(nes_ppu ${SOURCE} ${HEADERS}) diff --git a/ppu/memory.c b/ppu/memory.c deleted file mode 100644 index d20bbdc..0000000 --- a/ppu/memory.c +++ /dev/null @@ -1,48 +0,0 @@ -// -// Created by william on 5/17/24. -// - -#include -#include "memory.h" - -void ppu_vram_fetch(PPUVramFetch *fetch, address addr) { - assert(addr < VRAM_SIZE); - - if (fetch->finished) { - fetch->finished = false; - return; - } - - fetch->data = *fetch->vram[addr]; - fetch->finished = true; -} - -void ppu_tile_fetch(PPUTileFetch *fetch, address addr) { - if (fetch->fetch_cycle >= 8) { - fetch->fetch_cycle = 0; - } - - if (fetch->fetch_cycle % 2 == 0) { - // First cycle of a memory fetch - ppu_vram_fetch(&fetch->vram_fetch, addr + (fetch->fetch_cycle / 2)); - } else { - // Second cycle of a fetch, the data should be available - byte data = fetch->vram_fetch.data; - switch (fetch->fetch_cycle) { - case 1: - fetch->nametable = data; - break; - case 3: - fetch->attribute_table = data; - break; - case 5: - fetch->pattern_table_tile_low = data; - break; - case 7: - fetch->pattern_table_tile_high = data; - break; - default: - assert(false); - } - } -} \ No newline at end of file diff --git a/ppu/memory.h b/ppu/memory.h deleted file mode 100644 index b27cf26..0000000 --- a/ppu/memory.h +++ /dev/null @@ -1,28 +0,0 @@ -// -// Created by william on 5/17/24. -// - -#include -#include "../include/types.h" - -#ifndef NES_EMULATOR_MEMORY_H -#define NES_EMULATOR_MEMORY_H - -typedef struct ppu_vram_fetch { - vram *vram; - byte data; - bool finished; -} PPUVramFetch; - -typedef struct ppu_tile_fetch { - byte nametable; - byte attribute_table; - byte pattern_table_tile_low; - byte pattern_table_tile_high; -} PPUTileFetch; - -void ppu_vram_fetch(PPUVramFetch *fetch, address addr); - -void ppu_tile_fetch(PPUTileFetch *fetch, address addr); - -#endif //NES_EMULATOR_MEMORY_H diff --git a/ppu/ppu.c b/ppu/ppu.c index ca8a0cc..7dc0809 100644 --- a/ppu/ppu.c +++ b/ppu/ppu.c @@ -29,12 +29,8 @@ PPU ppu_state; -void ppu_init(byte *registers_ram, byte *oam_dma_register) { +void ppu_init() { memset(&ppu_state, 0, sizeof(PPU)); - - ppu_state.oam_dma_register = oam_dma_register; - ppu_state.registers = registers_ram; - memset(&ppu_state.registers, 0, 8); } PPU *ppu_get_state() { @@ -62,24 +58,24 @@ void ppu_visible_frame(unsigned int cycle) { if (cycle == 0) { // Idle... } else if (cycle <= 256) { - byte tile_fetch_cycle = (cycle - 1) % 8; - switch (tile_fetch_cycle) { - case 1: - ppu_state.tile_fetch.nametable = ppu_read(ppu_state.ppu_address); - break; - case 3: - ppu_state.tile_fetch.attribute_table = ppu_read(ppu_state.ppu_address); - break; - case 5: - ppu_state.tile_fetch.pattern_table_tile_low = ppu_read(ppu_state.ppu_address); - break; - case 7: - ppu_state.tile_fetch.pattern_table_tile_high = ppu_read(ppu_state.ppu_address); - ppu_state.ppu_address++; - break; - default: - break; - } +// byte tile_fetch_cycle = (cycle - 1) % 8; +// switch (tile_fetch_cycle) { +// case 1: +// ppu_state.tile_fetch.nametable = ppu_read(ppu_state.ppu_address); +// break; +// case 3: +// ppu_state.tile_fetch.attribute_table = ppu_read(ppu_state.ppu_address); +// break; +// case 5: +// ppu_state.tile_fetch.pattern_table_tile_low = ppu_read(ppu_state.ppu_address); +// break; +// case 7: +// ppu_state.tile_fetch.pattern_table_tile_high = ppu_read(ppu_state.ppu_address); +// ppu_state.ppu_address++; +// break; +// default: +// break; +// } } else if (cycle <= 320) { // OAMADDR is cleared on sprite loading for pre-render and visible lines ppu_write_reg(PPU_REGISTER_OAM_ADDR, 0); @@ -180,15 +176,6 @@ byte ppu_read_reg(byte reg) { return ppu_state.registers[reg]; } -void ppu_write_reg_ram(byte reg, byte data) { - byte *ppu_ram = mem_get_ptr(PPU_RAM_BASE_ADDR); - - for (int i = 0; i < PPU_RAM_BANK_COUNT; i++) { - byte ram_offset = (i * PPU_RAM_BANK_SIZE) + reg; - *(ppu_ram + ram_offset) = data; - } -} - void ppu_write_reg(byte reg, byte data) { ppu_state.registers[reg] = data; @@ -234,7 +221,7 @@ void ppu_write_reg(byte reg, byte data) { ppu_write_reg(PPU_REGISTER_OAM_ADDR, oam_addr + 1); } - ppu_write_reg_ram(reg, data); + ppu_state.registers[reg] = data; } byte ppu_read(address addr) { diff --git a/rom/ines.c b/rom/ines.c index 987e900..53c8846 100644 --- a/rom/ines.c +++ b/rom/ines.c @@ -59,7 +59,7 @@ typedef struct { struct INesHeaderFlags flags; } INesHeader; -bool rom_is_ines(const char header[16]) { +bool rom_is_ines(const byte header[16]) { return header[0] == 'N' && header[1] == 'E' && header[2] == 'S'; } @@ -139,8 +139,6 @@ bool rom_ines_read_prg_rom(FILE *file, INesHeader *header, Rom *rom) { return false; } - system_get_mapper()->post_prg_load(header->prg_rom_size); - return true; } diff --git a/rom/rom.c b/rom/rom.c index 75f05b2..95cd738 100644 --- a/rom/rom.c +++ b/rom/rom.c @@ -21,14 +21,13 @@ bool rom_load(char *path) { return false; } - char header_buffer[ROM_HEADER_SIZE] = {0}; - size_t read_size = fread(header_buffer, sizeof(char), ROM_HEADER_SIZE, file); + size_t read_size = fread(&rom.header, sizeof(byte), ROM_HEADER_SIZE, file); if (read_size < ROM_HEADER_SIZE) { log_error("Failed to read ROM"); return false; } - if (!rom_is_ines(header_buffer)) { + if (!rom_is_ines(rom.header)) { log_error("Only iNes ROMs are supported"); return false; } diff --git a/system.c b/system.c index d2cc7fd..9e90c6a 100644 --- a/system.c +++ b/system.c @@ -13,11 +13,8 @@ System current_sys; void system_init() { - byte *registers_base_addr = mem_get_ptr(PPU_REGISTERS_BASE_ADDR); - byte *oam_dma_register = mem_get_ptr(PPU_REGISTER_OAM_DMA_ADDR); - cpu_init(); - ppu_init(registers_base_addr, oam_dma_register); + ppu_init(); current_sys.mapper = get_mapper(MAPPER_TYPE_SIMPLE); current_sys.cycle_count = 7; @@ -41,7 +38,6 @@ void system_next_frame() { } void system_uninit() { - ppu_uninit(); } unsigned int system_get_cycles() {