nesemu/cpu/memory.c

77 lines
2.1 KiB
C

//
// Created by william on 10/15/23.
//
#include <assert.h>
#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;
}
}
}