From e665f7a455548af7d9f5b58954c581a5d89df69b Mon Sep 17 00:00:00 2001 From: Lauchmelder Date: Sun, 31 Oct 2021 02:02:31 +0200 Subject: [PATCH] added mapper mbc1 --- NES Emulator/CMakeLists.txt | 2 +- NES Emulator/bus.c | 2 +- NES Emulator/mapper.c | 13 +++ NES Emulator/mappers/mapper001.c | 175 +++++++++++++++++++++++++++++++ NES Emulator/mappers/mapper001.h | 50 +++++++++ roms/coredump.nes | Bin 0 -> 16400 bytes 6 files changed, 240 insertions(+), 2 deletions(-) create mode 100644 NES Emulator/mappers/mapper001.c create mode 100644 NES Emulator/mappers/mapper001.h create mode 100644 roms/coredump.nes diff --git a/NES Emulator/CMakeLists.txt b/NES Emulator/CMakeLists.txt index 550b3df..62f51c0 100644 --- a/NES Emulator/CMakeLists.txt +++ b/NES Emulator/CMakeLists.txt @@ -1,6 +1,6 @@ cmake_minimum_required (VERSION 3.8) -add_executable (nesemu "main.c" "bus.c" "cpu.c" "cartridge.c" "opcodes.c" "log.c" "ppu.c" "mappers/mapper000.c" "mapper.c" "controller.c") +add_executable (nesemu "main.c" "bus.c" "cpu.c" "cartridge.c" "opcodes.c" "log.c" "ppu.c" "mappers/mapper000.c" "mapper.c" "controller.c" "mappers/mapper001.h" "mappers/mapper001.c") target_include_directories(nesemu PUBLIC ${SDL2_INCLUDE_DIRS}) target_link_libraries(nesemu PUBLIC ${SDL2_LIBRARIES}) diff --git a/NES Emulator/bus.c b/NES Emulator/bus.c index ccc4784..afe7fe3 100644 --- a/NES Emulator/bus.c +++ b/NES Emulator/bus.c @@ -34,7 +34,7 @@ struct Bus* createBus(SDL_Renderer* renderer) memset(bus->ram, 0x00, 0x18); // Create and insert cartridge - bus->cartridge = createCartridge(bus, "roms/donkeykong.nes"); + bus->cartridge = createCartridge(bus, "roms/nestest.nes"); // Create CPU and attach it bus->cpu = createCPU(bus); diff --git a/NES Emulator/mapper.c b/NES Emulator/mapper.c index 9174f40..ddb459e 100644 --- a/NES Emulator/mapper.c +++ b/NES Emulator/mapper.c @@ -4,6 +4,7 @@ #include #include "mappers/mapper000.h" +#include "mappers/mapper001.h" struct Mapper* createMapper(Byte id, Byte prg_rom_size, Byte chr_rom_size, FILE* fp) { @@ -30,6 +31,18 @@ struct Mapper* createMapper(Byte id, Byte prg_rom_size, Byte chr_rom_size, FILE* mapper->get_pattern_table_texture = &Mapper000_GetPatternTableTexture; } break; + case 1: + { + struct Mapper001* mp = createMapper001(prg_rom_size, chr_rom_size, fp); + mapper->mapperStruct = (void*)mp; + + mapper->read_cpu = &Mapper001_ReadCPU; + mapper->read_ppu = &Mapper001_ReadPPU; + mapper->write_cpu = &Mapper001_WriteCPU; + mapper->write_ppu = &Mapper001_WritePPU; + mapper->get_pattern_table_texture = &Mapper001_GetPatternTableTexture; + } break; + default: fprintf(stderr, "Mapper with ID %d is not implemented\n", id); exit(-1); diff --git a/NES Emulator/mappers/mapper001.c b/NES Emulator/mappers/mapper001.c new file mode 100644 index 0000000..be3278d --- /dev/null +++ b/NES Emulator/mappers/mapper001.c @@ -0,0 +1,175 @@ +#include "mapper001.h" + +struct Mapper001* createMapper001(Byte prg_rom_size, Byte chr_rom_size, FILE* fp) +{ + struct Mapper001* mapper = (struct Mapper001*)malloc(sizeof(struct Mapper001)); + if (mapper == NULL) + { + fprintf(stderr, "Failed to create Mapper 000. Aborting\n"); + exit(-1); + } + + mapper->prg_rom_size = prg_rom_size; + mapper->prg_rom = (Byte*)calloc(prg_rom_size, 0x4000); + if (mapper->prg_rom == NULL) + { + fprintf(stderr, "Failed to allocate cartridge PRG ROM. Aborting\n"); + exit(-1); + } + + mapper->chr_rom_size = chr_rom_size; + mapper->chr_rom = (Byte*)calloc(chr_rom_size, 0x2000); + if (mapper->chr_rom == NULL) + { + fprintf(stderr, "Failed to allocate cartridge CHR ROM. Aborting\n"); + exit(-1); + } + + fread(mapper->prg_rom, 0x4000, prg_rom_size, fp); + fread(mapper->chr_rom, 0x2000, chr_rom_size, fp); + + mapper->lowerChrBank = mapper->chr_rom; + mapper->upperChrBank = mapper->chr_rom + 0x1000; + mapper->lowerPrgBank = mapper->prg_rom; + mapper->upperPrgBank = mapper->prg_rom + 0x4000; + + return mapper; +} + +void destroyMapper001(struct Mapper001* mapper) +{ + free(mapper->chr_rom); + free(mapper->prg_rom); + + free(mapper); +} + +Byte Mapper001_ReadCPU(void* mapper, Word address) +{ + struct Mapper001* sMapper = (struct Mapper000*)mapper; + Byte val = 0x00; + + if (address >= 0x6000 && address < 0x8000) + { + fprintf(stderr, "This Mapper 000 implementation doesnt support FamilyBasic PRG RAM\n"); + exit(-1); + } + else if (address >= 0x8000 && address <= 0xBFFF) + { + val = sMapper->lowerPrgBank[address & 0x3FFF]; + } + else if (address >= 0xC000 && address <= 0xFFFF) + { + val = sMapper->upperPrgBank[address & 0x3FFF]; + } + else + { + fprintf(stderr, "Cartridge read access violation by the CPU at $%04X\n", address); + exit(-1); + } + + return val; +} + +Byte Mapper001_ReadPPU(void* mapper, Word address) +{ + struct Mapper001* sMapper = (struct Mapper000*)mapper; + Byte val = 0x00; + + if (address >= 0x2000) + { + fprintf(stderr, "Cartridge read access violation by the PPU at $%04X\n", address); + exit(-1); + } + else if (address < 0x1000 + 0x1000 * (1 - sMapper->control.chr_bank_mode)) + { + val = sMapper->lowerChrBank[address]; + } + else + { + val = sMapper->upperChrBank[address & 0x0FFF]; + } + + return val; +} + +void Mapper001_WriteCPU(void* mapper, Word address, Byte value) +{ + struct Mapper001* sMapper = (struct Mapper000*)mapper; + if ((value & 0x80) == 0x80) + { + sMapper->shiftRegister = 0x10; + sMapper->control.raw |= 0x0C; + return; + } + + if ((sMapper->shiftRegister & 0x1) != 0x1) + { + sMapper->shiftRegister >>= 1; + sMapper->shiftRegister |= ((value & 0x1) << 4); + return; + } + + Byte valueToBeWritten = (sMapper->shiftRegister >> 1) | ((value & 0x1) << 4); + if (address >= 0x8000 && address <= 0x9FFF) + { + sMapper->control.raw = valueToBeWritten; + } + else if (address >= 0xA000 && address <= 0xBFFF) + { + if (sMapper->control.chr_bank_mode == 0x00) // 8KB mode + valueToBeWritten &= ~(0x1); // clear last bit + + sMapper->lowerChrBank = sMapper->chr_rom + (size_t)valueToBeWritten * 0x1000; + } + else if (address >= 0xC000 && address <= 0xDFFF) + { + if (sMapper->control.chr_bank_mode == 0x00) // 8KB mode + { + return; // ignore + } + + sMapper->upperChrBank = sMapper->chr_rom + (size_t)valueToBeWritten * 0x1000; + } + else + { + switch (sMapper->control.prg_bank_mode) + { + case 0: // 32KB mode + case 1: + valueToBeWritten &= ~(0x1); + sMapper->lowerPrgBank = sMapper->prg_rom + ((size_t)valueToBeWritten & 0xE) * 0x8000; + sMapper->upperPrgBank = sMapper->lowerPrgBank + 0x4000; + break; + + case 2: // fix first bank, switch second + sMapper->lowerPrgBank = sMapper->prg_rom; + sMapper->upperPrgBank = sMapper->prg_rom + ((size_t)valueToBeWritten & 0xE) * 0x4000; + break; + + case 3: // fix last bank, switch first + sMapper->lowerPrgBank = sMapper->prg_rom + ((size_t)valueToBeWritten & 0xE) * 0x4000; + sMapper->upperPrgBank = sMapper->prg_rom + ((size_t)sMapper->prg_rom_size - 1) * 0x4000; + break; + + } + } +} + + +void Mapper001_WritePPU(void* mapper, Word address, Byte value) +{ + // nothing +} + +void Mapper001_GetPatternTableTexture(void* mapper, SDL_Texture* texture, int index) +{ + struct Mapper001* sMapper = (struct Mapper001*)mapper; + Byte* selectedBank = ((index == 0) ? sMapper->lowerChrBank : sMapper->upperChrBank); + + int pitch; + void* pixels; + SDL_LockTexture(texture, NULL, &pixels, &pitch); + SDL_memcpy(pixels, selectedBank, 0x1000); + SDL_UnlockTexture(texture); +} diff --git a/NES Emulator/mappers/mapper001.h b/NES Emulator/mappers/mapper001.h new file mode 100644 index 0000000..e31aab8 --- /dev/null +++ b/NES Emulator/mappers/mapper001.h @@ -0,0 +1,50 @@ +#ifndef _MAPPER_001_ +#define _MAPPER_001_ + +#include +#include "../types.h" +#include "SDL.h" + +struct Mapper001 +{ + Byte prg_rom_size; + Byte chr_rom_size; + + Byte* prg_rom; + Byte* chr_rom; + + /////////////////////////// + /// REGISTERS /// + /////////////////////////// + Byte shiftRegister; + + union + { + struct + { + Byte mirroring : 2; + Byte prg_bank_mode : 2; + Byte chr_bank_mode : 1; + Byte padding : 3; + }; + + Byte raw; + } control; + + Byte* lowerChrBank; + Byte* upperChrBank; + Byte* lowerPrgBank; + Byte* upperPrgBank; +}; + +struct Mapper001* createMapper001(Byte prg_rom_size, Byte chr_rom_size, FILE* fp); +void destroyMapper001(struct Mapper001* mapper); + +Byte Mapper001_ReadCPU(void* mapper, Word address); +Byte Mapper001_ReadPPU(void* mapper, Word address); +void Mapper001_WriteCPU(void* mapper, Word address, Byte value); +void Mapper001_WritePPU(void* mapper, Word address, Byte value); + +void Mapper001_GetPatternTableTexture(void* mapper, SDL_Texture* texture, int index); + +#endif // _MAPPER_001_ diff --git a/roms/coredump.nes b/roms/coredump.nes new file mode 100644 index 0000000000000000000000000000000000000000..779eda880f24fa25427cabaa2cc38befe51b301c GIT binary patch literal 16400 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 MSj|27-UGh>7ym%XKL7v# literal 0 HcmV?d00001