Переглянути джерело

Add support for on-cartridge RAM (#3)

master
Ben Kurtovic 7 роки тому
джерело
коміт
d5f9c6950c
2 змінених файлів з 58 додано та 23 видалено
  1. +52
    -21
      src/mmu.c
  2. +6
    -2
      src/mmu.h

+ 52
- 21
src/mmu.c Переглянути файл

@@ -15,9 +15,12 @@
void mmu_init(MMU *mmu)
{
mmu->system_ram = cr_malloc(sizeof(uint8_t) * MMU_SYSTEM_RAM_SIZE);
mmu->cart_ram = cr_malloc(sizeof(uint8_t) * MMU_CART_RAM_SIZE);
mmu->cart_ram_slot = mmu->cart_ram;
mmu->cart_ram_mapped = false;

for (size_t slot = 0; slot < MMU_NUM_SLOTS; slot++)
mmu->map_slots[slot] = NULL;
mmu->rom_slots[slot] = NULL;

for (size_t bank = 0; bank < MMU_NUM_ROM_BANKS; bank++)
mmu->rom_banks[bank] = NULL;
@@ -29,6 +32,7 @@ void mmu_init(MMU *mmu)
void mmu_free(MMU *mmu)
{
free(mmu->system_ram);
free(mmu->cart_ram);
}

/*
@@ -84,10 +88,10 @@ void mmu_load_rom(MMU *mmu, const uint8_t *data, size_t size)
/*
Map the given RAM slot to the given ROM bank.
*/
static inline void map_slot(MMU *mmu, size_t slot, size_t bank)
static inline void map_rom_slot(MMU *mmu, size_t slot, size_t bank)
{
TRACE("MMU mapping memory slot %zu to bank 0x%02zX", slot, bank)
mmu->map_slots[slot] = mmu->rom_banks[bank];
TRACE("MMU mapping memory slot %zu to ROM bank 0x%02zX", slot, bank)
mmu->rom_slots[slot] = mmu->rom_banks[bank];
}

/*
@@ -99,9 +103,10 @@ static inline void map_slot(MMU *mmu, size_t slot, size_t bank)
void mmu_power(MMU *mmu)
{
for (size_t slot = 0; slot < MMU_NUM_SLOTS; slot++)
map_slot(mmu, slot, slot);
map_rom_slot(mmu, slot, slot);

memset(mmu->system_ram, 0xFF, MMU_SYSTEM_RAM_SIZE);
memset(mmu->cart_ram, 0xFF, MMU_CART_RAM_SIZE);
}

/*
@@ -121,18 +126,21 @@ static inline uint8_t bank_byte_read(const uint8_t* bank, uint16_t addr)
*/
uint8_t mmu_read_byte(const MMU *mmu, uint16_t addr)
{
if (addr < 0x0400) // First kilobyte is unpaged, for interrupt handlers
if (addr < 0x0400) { // First kilobyte is unpaged, for interrupt handlers
return bank_byte_read(mmu->rom_banks[0], addr);
else if (addr < 0x4000) // Slot 0 (0x0400 - 0x3FFF)
return bank_byte_read(mmu->map_slots[0], addr);
else if (addr < 0x8000) // Slot 1 (0x4000 - 0x7FFF)
return bank_byte_read(mmu->map_slots[1], addr - 0x4000);
else if (addr < 0xC000) // Slot 2 (0x8000 - 0xBFFF)
return bank_byte_read(mmu->map_slots[2], addr - 0x8000);
else if (addr < 0xE000) // System RAM (0xC000 - 0xDFFF)
} else if (addr < 0x4000) { // Slot 0 (0x0400 - 0x3FFF)
return bank_byte_read(mmu->rom_slots[0], addr);
} else if (addr < 0x8000) { // Slot 1 (0x4000 - 0x7FFF)
return bank_byte_read(mmu->rom_slots[1], addr - 0x4000);
} else if (addr < 0xC000) { // Slot 2 (0x8000 - 0xBFFF)
if (mmu->cart_ram_mapped)
return mmu->cart_ram_slot[addr - 0x8000];
return bank_byte_read(mmu->rom_slots[2], addr - 0x8000);
} else if (addr < 0xE000) { // System RAM (0xC000 - 0xDFFF)
return mmu->system_ram[addr - 0xC000];
else // System RAM, mirrored (0xE000 - 0xFFFF)
} else { // System RAM, mirrored (0xE000 - 0xFFFF)
return mmu->system_ram[addr - 0xE000];
}
}

/*
@@ -156,6 +164,25 @@ uint32_t mmu_read_quad(const MMU *mmu, uint16_t addr)
}

/*
Write to the cartridge RAM mapping control register at 0xFFFC.
*/
static void write_ram_control_register(MMU *mmu, uint8_t value)
{
// TODO: 0x03 = bank shift, 0x10 = 0xC000-0xFFFF enable, 0x80 = ROM write
bool bank_select = value & 0x04;
bool slot2_enable = value & 0x08;

if (slot2_enable)
TRACE("MMU enabling cart RAM bank %d in memory slot 2", bank_select)
else if (!slot2_enable && mmu->cart_ram_mapped)
TRACE("MMU disabling cart RAM in memory slot 2")

mmu->cart_ram_slot =
bank_select ? (mmu->cart_ram + 0x4000) : mmu->cart_ram;
mmu->cart_ram_mapped = slot2_enable;
}

/*
Write a byte of memory to the given address.

Return true if the byte was written, and false if it wasn't. Writes will
@@ -163,20 +190,24 @@ uint32_t mmu_read_quad(const MMU *mmu, uint16_t addr)
*/
bool mmu_write_byte(MMU *mmu, uint16_t addr, uint8_t value)
{
if (addr < 0xC000) { // TODO: implement writes to on-cartridge RAM
if (addr < 0xC000) {
if (addr >= 0x8000 && mmu->cart_ram_mapped) {
mmu->cart_ram_slot[addr - 0x8000] = value;
return true;
}
return false;
} else if (addr < 0xE000) { // System RAM (0xC000 - 0xDFFF)
mmu->system_ram[addr - 0xC000] = value;
return true;
} else { // System RAM, mirrored (0xE000 - 0xFFFF)
if (addr == 0xFFFC) {
// TODO: handle cartridge RAM mapping control
} else if (addr == 0xFFFD)
map_slot(mmu, 0, value & 0x3F);
if (addr == 0xFFFC)
write_ram_control_register(mmu, value);
else if (addr == 0xFFFD)
map_rom_slot(mmu, 0, value & 0x3F);
else if (addr == 0xFFFE)
map_slot(mmu, 1, value & 0x3F);
map_rom_slot(mmu, 1, value & 0x3F);
else if (addr == 0xFFFF)
map_slot(mmu, 2, value & 0x3F);
map_rom_slot(mmu, 2, value & 0x3F);
mmu->system_ram[addr - 0xE000] = value;
return true;
}


+ 6
- 2
src/mmu.h Переглянути файл

@@ -10,14 +10,18 @@
#define MMU_NUM_SLOTS (3)
#define MMU_NUM_ROM_BANKS (64)
#define MMU_ROM_BANK_SIZE (16 * 1024)
#define MMU_SYSTEM_RAM_SIZE (8 * 1024)
#define MMU_SYSTEM_RAM_SIZE ( 8 * 1024)
#define MMU_CART_RAM_SIZE (32 * 1024)

/* Structs */

typedef struct {
uint8_t *system_ram;
const uint8_t *map_slots[MMU_NUM_SLOTS];
uint8_t *cart_ram;
const uint8_t *rom_slots[MMU_NUM_SLOTS];
const uint8_t *rom_banks[MMU_NUM_ROM_BANKS];
uint8_t *cart_ram_slot;
bool cart_ram_mapped;
} MMU;

/* Functions */


Завантаження…
Відмінити
Зберегти