// // Created by william on 10/15/23. // #include #include "log.h" #include "memory.h" #include "../include/rom.h" #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 byte mem_get_byte(System *system, address addr) { assert(addr <= MAX_ADDR); if (addr >= RAM_MAX_ADDR && addr < PPU_MAX_ADDR) { byte reg = (addr - RAM_MAX_ADDR) % PPU_BANK_SIZE; ppu_read_register(&system->ppu, reg); return system->ppu.registers[reg]; } if (addr >= PPU_MAX_ADDR && addr < APU_MAX_ADDR) { byte apu_addr = addr - PPU_MAX_ADDR; return system->apu_registers[apu_addr]; } return system->ram[addr]; } word mem_get_word(System *system, address addr) { assert(addr < MAX_ADDR); if (addr >= RAM_MAX_ADDR && addr < APU_MAX_ADDR) { assert(false); } word word = system->ram[addr]; word += system->ram[addr + 1] << 8; // Little endian return word; } void mem_set_byte(System *system, address addr, byte byte) { assert(addr < MAX_ADDR); log_trace("Writing '%02x' to address 0x%04x", byte, addr); 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; system->ram[ram_addr] = byte; } } else if (addr < PPU_MAX_ADDR) { address reg_addr = (addr - RAM_MAX_ADDR) % PPU_BANK_SIZE; int bank_count = (PPU_MAX_ADDR - RAM_MAX_ADDR) / PPU_BANK_SIZE; for (int i = 0; i < bank_count; i++) { address ram_addr = reg_addr + PPU_BANK_SIZE * i; system->ppu.registers[ram_addr] = byte; } ppu_write_register(&system->ppu, reg_addr); } else { system->ram[addr] = byte; if (addr == PPU_REGISTER_OAM_DMA_ADDR) { // Writing to this address triggers an upload to the PPU memory system->cpu.oam_dma_triggered = true; } } }