static uint8_t mapper_001_0_prg_rom_read(struct nes_state *state, uint32_t addr) { struct mapper_001_0 *mapper = &state->mapper_data.m001_0; if(addr >= 0x8000) { if(addr < 0xc000) { return mapper->prg_rom_0[addr & 0x3fff]; } else { return mapper->prg_rom_1[addr & 0x3fff]; } } return 0; } static void mapper_001_0_prg_rom_write(struct nes_state *state, uint32_t addr, uint8_t value) { struct mapper_001_0 *mapper = &state->mapper_data.m001_0; printf("MMC1 write: addr=%04x val=%02x\n", addr, value); if(addr < 0x8000) { return; } if(value & 0x80) { mapper->shift = 0; mapper->shift_count = 0; mapper->control |= 0x0c; return; } mapper->shift |= (value & 1) << mapper->shift_count; mapper->shift_count++; if(mapper->shift_count == 5) { uint8_t reg = (addr >> 13) & 3; switch(reg) { case 0: { mapper->control = mapper->shift; switch(mapper->control & 3) { case 0: { state->ines.mirroring = MIRROR_ONESCREEN_LOW; } break; case 1: { state->ines.mirroring = MIRROR_ONESCREEN_HIGH; } break; case 2: { state->ines.mirroring = MIRROR_VERTICAL; } break; case 3: { state->ines.mirroring = MIRROR_HORIZONTAL; } break; } } break; case 1: { mapper->chr_bank0 = mapper->shift; mapper->chr_bank_0 = state->chr_rom + (mapper->chr_bank0 * 0x1000); } break; case 2: { mapper->chr_bank1 = mapper->shift; mapper->chr_bank_1 = state->chr_rom + (mapper->chr_bank1 * 0x1000); } break; case 3: { mapper->prg_bank = mapper->shift & 0x0f; if(mapper->control & 0x08) { if(mapper->control & 0x04) { mapper->prg_rom_0 = state->prg_rom; mapper->prg_rom_1 = state->prg_rom + (mapper->prg_bank * 0x4000); } else { mapper->prg_rom_0 = state->prg_rom + (mapper->prg_bank * 0x4000); mapper->prg_rom_1 = state->prg_rom + (state->ines.prg_size - 0x4000); } } else { uint32_t base = (mapper->prg_bank & 0x0e) * 0x4000; mapper->prg_rom_0 = state->prg_rom + base; mapper->prg_rom_1 = state->prg_rom + base + 0x4000; } } break; } mapper->shift = 0; mapper->shift_count = 0; } } static uint8_t mapper_001_0_chr_read(struct nes_state *state, uint32_t addr) { struct mapper_001_0 *mapper = &state->mapper_data.m001_0; if(mapper->control & 0x10) { if(addr < 0x1000) { return mapper->chr_bank_0[addr & 0xfff]; } else { return mapper->chr_bank_1[addr & 0xfff]; } } else { return mapper->chr_bank_0[addr & 0x1fff]; } } static void mapper_001_0_chr_write(struct nes_state *state, uint32_t addr, uint8_t value) { state->chr_ram[addr] = value; } static uint8_t mapper_001_0_ciram_read(struct nes_state *state, uint32_t addr) { // MMC1 can set mirroring mode dynamically via control register switch(state->ines.mirroring) { case MIRROR_ONESCREEN_LOW: addr = addr & 0x3ff; break; case MIRROR_ONESCREEN_HIGH: addr = 0x400 | (addr & 0x3ff); break; case MIRROR_HORIZONTAL: // Horizontal: NT0↔NT1, NT2↔NT3 addr = ((addr >> 1) & 0x400) | (addr & 0x3ff); break; case MIRROR_VERTICAL: // Vertical: NT0↔NT2, NT1↔NT3 addr = addr & 0x7ff; break; } return state->ciram[addr]; } static void mapper_001_0_ciram_write(struct nes_state *state, uint32_t addr, uint8_t value) { // MMC1 can set mirroring mode dynamically via control register switch(state->ines.mirroring) { case MIRROR_ONESCREEN_LOW: addr = addr & 0x3ff; break; case MIRROR_ONESCREEN_HIGH: addr = 0x400 | (addr & 0x3ff); break; case MIRROR_HORIZONTAL: // Horizontal: NT0↔NT1, NT2↔NT3 addr = ((addr >> 1) & 0x400) | (addr & 0x3ff); break; case MIRROR_VERTICAL: // Vertical: NT0↔NT2, NT1↔NT3 addr = addr & 0x7ff; break; } state->ciram[addr] = value; } static void mapper_001_0_init(struct nes_state *state) { struct mapper_001_0 *mapper = &state->mapper_data.m001_0; mapper->shift = 0; mapper->shift_count = 0; mapper->control = 0x0c; mapper->prg_bank = 0; mapper->chr_bank0 = 0; mapper->chr_bank1 = 0; mapper->prg_rom_0 = state->prg_rom; mapper->prg_rom_1 = state->prg_rom + (state->ines.prg_size - 0x4000); if(state->ines.chr_size) { mapper->chr_bank_0 = state->chr_rom; mapper->chr_bank_1 = state->chr_rom + 0x1000; } else { mapper->chr_bank_0 = state->chr_ram; mapper->chr_bank_1 = state->chr_ram + 0x1000; } state->mapper_function.prg_rom_read = mapper_001_0_prg_rom_read; state->mapper_function.prg_rom_write = mapper_001_0_prg_rom_write; state->mapper_function.chr_read = mapper_001_0_chr_read; state->mapper_function.chr_write = mapper_001_0_chr_write; state->mapper_function.ciram_read = mapper_001_0_ciram_read; state->mapper_function.ciram_write = mapper_001_0_ciram_write; }