__attribute__((always_inline)) static inline void mapper_001_0_apply_chr_banks(struct nes_state *state) { struct mapper_001_0 *mapper = &state->mapper_data.m001_0; if(!state->ines.chr_size) { return; } if(mapper->control & 0x10) { // 4KB CHR mode mapper->chr_bank_0 = state->chr_rom + (mapper->chr_bank0 * 0x1000); mapper->chr_bank_1 = state->chr_rom + (mapper->chr_bank1 * 0x1000); } else { // 8KB CHR mode - ignore bit 0 of bank number mapper->chr_bank_0 = state->chr_rom + ((mapper->chr_bank0 & 0xfe) * 0x1000); mapper->chr_bank_1 = state->chr_rom + ((mapper->chr_bank0 & 0xfe) * 0x1000) + 0x1000; } } __attribute__((always_inline)) static inline void mapper_001_0_apply_prg_banks(struct nes_state *state) { struct mapper_001_0 *mapper = &state->mapper_data.m001_0; if(mapper->control & 0x08) { // 16KB PRG mode if(mapper->control & 0x04) { // Fix last bank at $C000, switch first bank at $8000 mapper->prg_rom_0 = state->prg_rom + (mapper->prg_bank * 0x4000); mapper->prg_rom_1 = state->prg_rom + (state->ines.prg_size - 0x4000); } else { // Fix first bank at $8000, switch last bank at $C000 mapper->prg_rom_0 = state->prg_rom; mapper->prg_rom_1 = state->prg_rom + (mapper->prg_bank * 0x4000); } } else { // 32KB PRG mode - ignore bit 0 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; } } __attribute__((always_inline)) static inline void mapper_001_0_write_control(struct nes_state *state, uint8_t value) { struct mapper_001_0 *mapper = &state->mapper_data.m001_0; mapper->control = value; mapper_001_0_apply_chr_banks(state); mapper_001_0_apply_prg_banks(state); } 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 < 0xc000) { return mapper->prg_rom_0[addr & 0x3fff]; } return mapper->prg_rom_1[addr & 0x3fff]; } 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; if(value & 0x80) { mapper->shift_accumulator = 0; mapper->shift_count = 0; mapper_001_0_write_control(state, mapper->control | 0x0c); return; } mapper->shift_accumulator |= (value & 1) << mapper->shift_count; mapper->shift_count++; if(mapper->shift_count == 5) { uint8_t reg = (addr >> 13) & 3; switch(reg) { case 0: mapper_001_0_write_control(state, mapper->shift_accumulator); break; case 1: mapper->chr_bank0 = mapper->shift_accumulator; mapper_001_0_apply_chr_banks(state); break; case 2: mapper->chr_bank1 = mapper->shift_accumulator; mapper_001_0_apply_chr_banks(state); break; case 3: mapper->prg_bank = mapper->shift_accumulator & 0x0f; mapper_001_0_apply_prg_banks(state); break; } mapper->shift_accumulator = 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(state->ines.chr_size == 0) { // CHR-RAM - no banking return state->chr_ram[addr]; } // CHR-ROM - use banking uint8_t val; if(mapper->control & 0x10) { // 4KB CHR mode if(addr < 0x1000) { val = mapper->chr_bank_0[addr & 0xfff]; } else { val = mapper->chr_bank_1[addr & 0xfff]; } } else { // 8KB CHR mode val = mapper->chr_bank_0[addr & 0x1fff]; } return val; } 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_prg_ram_read(struct nes_state *state, uint32_t addr) { return state->sram[addr & 0x1fff]; } static void mapper_001_0_prg_ram_write(struct nes_state *state, uint32_t addr, uint8_t value) { state->sram[addr & 0x1fff] = value; } static uint8_t mapper_001_0_ciram_read(struct nes_state *state, uint32_t addr) { struct mapper_001_0 *mapper = &state->mapper_data.m001_0; switch(mapper->control & 3) { case 0: return state->ciram[addr & 0x3ff]; // one-screen lower case 1: return state->ciram[0x400 | (addr & 0x3ff)]; // one-screen upper case 2: return state->ciram[addr & 0x7ff]; // vertical case 3: return state->ciram[((addr >> 1) & 0x400) | (addr & 0x3ff)]; // horizontal } return 0; } static void mapper_001_0_ciram_write(struct nes_state *state, uint32_t addr, uint8_t value) { struct mapper_001_0 *mapper = &state->mapper_data.m001_0; switch(mapper->control & 3) { case 0: { // one-screen lower state->ciram[addr & 0x3ff] = value; } break; case 1: { // one-screen upper state->ciram[0x400 | (addr & 0x3ff)] = value; } break; case 2: { // vertical state->ciram[addr & 0x7ff] = value; } break; case 3: { // horizontal state->ciram[((addr >> 1) & 0x400) | (addr & 0x3ff)] = value; } break; } } static void mapper_001_0_init(struct nes_state *state) { struct mapper_001_0 *mapper = &state->mapper_data.m001_0; memset(mapper, 0, sizeof(struct mapper_001_0)); mapper->control = 0x0c; mapper_001_0_apply_prg_banks(state); if(state->ines.chr_size) { // CHR-ROM - apply banking mapper_001_0_apply_chr_banks(state); } else { // CHR-RAM - no banking, point directly to RAM 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.prg_ram_read = mapper_001_0_prg_ram_read; state->mapper_function.prg_ram_write = mapper_001_0_prg_ram_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; }