Browse Source

Add support for on-cartridge RAM (#3)

master
Ben Kurtovic 6 years ago
parent
commit
d5f9c6950c
2 changed files with 58 additions and 23 deletions
  1. +52
    -21
      src/mmu.c
  2. +6
    -2
      src/mmu.h

+ 52
- 21
src/mmu.c View File

@@ -15,9 +15,12 @@
void mmu_init(MMU *mmu) void mmu_init(MMU *mmu)
{ {
mmu->system_ram = cr_malloc(sizeof(uint8_t) * MMU_SYSTEM_RAM_SIZE); 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++) 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++) for (size_t bank = 0; bank < MMU_NUM_ROM_BANKS; bank++)
mmu->rom_banks[bank] = NULL; mmu->rom_banks[bank] = NULL;
@@ -29,6 +32,7 @@ void mmu_init(MMU *mmu)
void mmu_free(MMU *mmu) void mmu_free(MMU *mmu)
{ {
free(mmu->system_ram); 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. 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) void mmu_power(MMU *mmu)
{ {
for (size_t slot = 0; slot < MMU_NUM_SLOTS; slot++) 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->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) 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); 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]; return mmu->system_ram[addr - 0xC000];
else // System RAM, mirrored (0xE000 - 0xFFFF)
} else { // System RAM, mirrored (0xE000 - 0xFFFF)
return mmu->system_ram[addr - 0xE000]; 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. Write a byte of memory to the given address.


Return true if the byte was written, and false if it wasn't. Writes will 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) 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; return false;
} else if (addr < 0xE000) { // System RAM (0xC000 - 0xDFFF) } else if (addr < 0xE000) { // System RAM (0xC000 - 0xDFFF)
mmu->system_ram[addr - 0xC000] = value; mmu->system_ram[addr - 0xC000] = value;
return true; return true;
} else { // System RAM, mirrored (0xE000 - 0xFFFF) } 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) else if (addr == 0xFFFE)
map_slot(mmu, 1, value & 0x3F);
map_rom_slot(mmu, 1, value & 0x3F);
else if (addr == 0xFFFF) else if (addr == 0xFFFF)
map_slot(mmu, 2, value & 0x3F);
map_rom_slot(mmu, 2, value & 0x3F);
mmu->system_ram[addr - 0xE000] = value; mmu->system_ram[addr - 0xE000] = value;
return true; return true;
} }


+ 6
- 2
src/mmu.h View File

@@ -10,14 +10,18 @@
#define MMU_NUM_SLOTS (3) #define MMU_NUM_SLOTS (3)
#define MMU_NUM_ROM_BANKS (64) #define MMU_NUM_ROM_BANKS (64)
#define MMU_ROM_BANK_SIZE (16 * 1024) #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 */ /* Structs */


typedef struct { typedef struct {
uint8_t *system_ram; 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]; const uint8_t *rom_banks[MMU_NUM_ROM_BANKS];
uint8_t *cart_ram_slot;
bool cart_ram_mapped;
} MMU; } MMU;


/* Functions */ /* Functions */


Loading…
Cancel
Save