/* * HalfNES by Andrew Hoffman * Licensed under the GNU GPL Version 3. See LICENSE file */ package com.grapeshot.halfnes.mappers; import com.grapeshot.halfnes.*; public class VRC3Mapper extends Mapper { private int irqctr, irqreload = 0; private boolean irqmode, irqenable, irqackenable, interrupted = false; @Override public void loadrom() throws BadMapperException { // needs to be in every mapper. Fill with initial cfg super.loadrom(); //swappable bank for (int i = 0; i < 16; ++i) { prg_map[i] = (1024 * i) & (prgsize - 1); } //fixed bank for (int i = 1; i <= 16; ++i) { prg_map[32 - i] = prgsize - (1024 * i); } for (int i = 0; i < 8; ++i) { chr_map[i] = (1024 * i) & (chrsize - 1); } } @Override public final void cartWrite(int addr, int data) { if (addr < 0x8000 || addr > 0xffff) { super.cartWrite(addr, data); return; } switch (addr >> 12) { case 0x8: //Bits 0-3 of IRQ reload value irqreload = (irqreload & 0xFFF0) | (data & 0xF); break; case 0x9: //Bits 4-7 of IRQ reload value irqreload = (irqreload & 0xFF0F) | (data & 0xF) << 4; break; case 0xA: //Bits 8-11 of IRQ reload value irqreload = (irqreload & 0xF0FF) | (data & 0xF) << 8; break; case 0xB: //Bits 12-15 of IRQ reload value irqreload = (irqreload & 0x0FFF) | (data & 0xF) << 12; break; case 0xC: //IRQ Control irqmode = ((data & (utils.BIT2)) != 0); irqackenable = ((data & (utils.BIT0)) != 0); irqenable = ((data & (utils.BIT1)) != 0); if (irqenable) { if (irqmode) { irqctr &= 0xFF00; irqctr |= (irqreload & 0xFF); } else { irqctr = irqreload; } if (interrupted) { --cpu.interrupt; interrupted = false; } } break; case 0xD: //IRQ Acknowledge irqenable = irqackenable; if (interrupted) { --cpu.interrupt; interrupted = false; } break; case 0xF: //PRG Select for (int i = 0; i < 16; ++i) { prg_map[i] = (1024 * (i + 16 * (data & 0xF))) & (prgsize - 1); } break; } } @Override public void cpucycle(final int cycles) { if (irqenable) { if (irqmode) { //8-bit mode int temp = irqctr; irqctr &= 0xFF00; if (temp >= 0xFF) { irqctr = irqreload; irqctr |= (irqreload & 0xFF); if (!interrupted) { ++cpu.interrupt; interrupted = true; } } else { temp += cycles; irqctr |= temp; } } else { //16-bit mode if (irqctr >= 0xFFFF) { irqctr = irqreload; if (!interrupted) { ++cpu.interrupt; interrupted = true; } } else { irqctr += cycles; } } } } }