|
- #include "memory.h"
-
- //#define NESE_DEBUG "MMC1"
- #include "log.h"
-
-
- typedef struct {
- uint8_t reg_shift;
- uint8_t reg_n_shift;
- uint8_t reg_control;
- uint8_t reg_chr_0;
- uint8_t reg_chr_1;
- uint8_t reg_prg;
- } map001_data;
-
-
- static inline void mmc1_update_vram(map001_data* data,
- nes_Memory* mem) {
- const nes_Nametable_Mirroring mirror[4] = {
- nes_Mirror_Only_0,
- nes_Mirror_Only_1,
- nes_Mirror_Vertical,
- nes_Mirror_Horizontal,
- };
- LOGD("Mirroring %d", mirror[data->reg_control & 0b11]);
- nes_ppu_set_mirroring(&mem->ppu,
- mirror[data->reg_control & 0b11]);
- }
-
- static inline void mmc1_update_chr(map001_data* data,
- nes_Memory* mem) {
- int n_banks = mem->ppu.n_chr_banks / 4;
- int bank_0 = 0, bank_1 = 0;
- if (!(data->reg_control & 0b10000)) {
- bank_0 = (data->reg_chr_0 & 0b11110) % n_banks;
- bank_1 = bank_0 + 1;
- } else {
- bank_0 = data->reg_chr_0 % n_banks;
- bank_1 = data->reg_chr_1 % n_banks;
- }
-
- LOGD("CHR: %d + %d", bank_0, bank_1);
-
- mem->ppu.bank[0] = chr_page(&mem->ppu, (bank_0 * 4) + 0);
- mem->ppu.bank[1] = chr_page(&mem->ppu, (bank_0 * 4) + 1);
- mem->ppu.bank[2] = chr_page(&mem->ppu, (bank_0 * 4) + 2);
- mem->ppu.bank[3] = chr_page(&mem->ppu, (bank_0 * 4) + 3);
- mem->ppu.bank[4] = chr_page(&mem->ppu, (bank_1 * 4) + 0);
- mem->ppu.bank[5] = chr_page(&mem->ppu, (bank_1 * 4) + 1);
- mem->ppu.bank[6] = chr_page(&mem->ppu, (bank_1 * 4) + 2);
- mem->ppu.bank[7] = chr_page(&mem->ppu, (bank_1 * 4) + 3);
- }
-
- static inline void mmc1_update_prg(map001_data* data,
- nes_Memory* mem) {
- int n_banks = mem->n_rom_banks / 2;
- int mode = (data->reg_control >> 2) & 3;
- int bank_0 = (data->reg_prg & 0b01111) % n_banks;
- int bank_1 = bank_0;
- if (!(mode & 0b10)) {
- bank_0 = (bank_0 & 0b01110);
- bank_1 = bank_0 + 1;
- } else if (mode == 2) {
- bank_0 = 0;
- } else if (mode == 3) {
- bank_1 = n_banks - 1;
- }
-
- LOGD("PRG: %d + %d", bank_0, bank_1);
-
- mem->rom_bank[0] = prg_rom_page(mem, (bank_0 * 2) + 0);
- mem->rom_bank[1] = prg_rom_page(mem, (bank_0 * 2) + 1);
- mem->rom_bank[2] = prg_rom_page(mem, (bank_1 * 2) + 0);
- mem->rom_bank[3] = prg_rom_page(mem, (bank_1 * 2) + 1);
- }
-
- static void map001_reset(nes_Mapper* map, nes_Memory* mem) {
- map001_data* data = (map001_data*)map->data;
- data->reg_shift = 0b10000;
- data->reg_control = 0b01100;
- data->reg_chr_0 = 0;
- data->reg_chr_1 = 0;
- data->reg_prg = 0;
- mmc1_update_prg(data, mem);
- mmc1_update_chr(data, mem);
- mmc1_update_vram(data, mem);
- }
-
- static int map001_init(nes_Mapper* map, const ines_Header* hdr,
- nes_Memory* mem) {
- map001_reset(map, mem);
- return 0;
- }
-
- static int map001_write_rom(nes_Mapper* map, nes_Memory* mem,
- uint16_t addr, uint8_t val) {
- map001_data* data = (map001_data*)map->data;
-
- LOGD("Write $%04x < %02x", addr, val);
-
- if (val & 0x80U) {
- data->reg_shift = 0b10000;
- data->reg_control |= 0b01100;
- mmc1_update_prg(data, mem);
- } else {
- // TODO: Handle consecutive-cycle writes?
- int done = (data->reg_shift & 1);
- data->reg_shift = (data->reg_shift >> 1) |
- ((val & 1) << 4);
- if (done) {
- switch ((addr >> 13) & 3) {
- case 0:
- LOGD("Control %02x", data->reg_shift);
- data->reg_control = data->reg_shift;
- mmc1_update_chr(data, mem);
- mmc1_update_vram(data, mem);
- mmc1_update_prg(data, mem);
- break;
-
- case 1:
- LOGD("CHR_0 %02x", data->reg_shift);
- data->reg_chr_0 = data->reg_shift;
- mmc1_update_chr(data, mem);
- break;
-
- case 2:
- LOGD("CHR_1 %02x", data->reg_shift);
- data->reg_chr_1 = data->reg_shift;
- mmc1_update_chr(data, mem);
- break;
-
- case 3:
- LOGD("PRG %02x", data->reg_shift);
- data->reg_prg = data->reg_shift;
- mmc1_update_prg(data, mem);
- break;
- }
- data->reg_shift = 0b10000;
- }
- }
-
- return 0;
- }
-
-
- const nes_Mapper map001 = {
- .name = "MMC1",
- .max_chr_banks = 128,
- .data_size = sizeof(map001_data),
- .init = map001_init,
- .reset = map001_reset,
- .write_rom = map001_write_rom,
- };
|