Beispiel #1
0
        private void SetCharacterBanks()
        {
            selectedCharacterBank0 = latch0 == 0xFD ? characterBank0 : characterBank1;
            selectedCharacterBank1 = latch1 == 0xFD ? characterBank2 : characterBank3;

            // invalidate address regions
            CharacterBankSwitch?.Invoke(0x0000, 0x2000);
        }
Beispiel #2
0
        // CHR bank 0 (internal, $A000-$BFFF)
        private void WriteCharacterBank0(byte value)
        {
            characterBank0 = value;
            UpdateOffsets();

            CharacterBankSwitch?.Invoke(0x0000, 0x1000);

            // both chr modes
            HandleSxRomVariants(value);
        }
Beispiel #3
0
        private void WriteBankSelect(byte value)
        {
            programBankMode   = (byte)((value >> 6) & 1);
            characterBankMode = (byte)((value >> 7) & 1);
            registerIndex     = (byte)(value & 7);
            UpdateOffsets();

            // invalidate address regions
            CharacterBankSwitch?.Invoke(0x0000, 0x2000);
            ProgramBankSwitch?.Invoke(0x8000, 0x8000);
        }
        public override byte this[ushort address]
        {
            get
            {
                if (address < 0x2000)
                {
                    return(Cartridge.CharacterRom[characterBank * 0x2000 + address]);
                }
                else if (address >= 0x8000 && address < 0xC000)
                {
                    return(flashMemory[(uint)(programBank * 0x4000 + address % 0x4000)]);
                }
                else if (address >= 0xC000)
                {
                    return(flashMemory[(uint)(programLastAddress16k + address % 0x4000)]);
                }
                else
                {
                    Debug.WriteLine(Name + ": Unexpected read from address " + Hex.Format(address));
                    return((byte)(address >> 8));
                }
            }

            set
            {
                flashMemory[address] = value;

                if (address > 0x8000)
                {
                    // MCCP PPPP
                    MirrorMode = (value & 0x80) != 0 ? MirrorMode.Single1 : MirrorMode.Single0;

                    int oldProgramBank = programBank;
                    programBank = value & 0x1F;
                    if (programBank != oldProgramBank)
                    {
                        ProgramBankSwitch?.Invoke(0x8000, 0x4000);
                    }

                    int oldCharacterBank = characterBank;
                    characterBank = (value >> 5) & 0x03;
                    if (characterBank != oldCharacterBank)
                    {
                        CharacterBankSwitch?.Invoke(0x0000, 0x2000);
                    }
                }
                else
                {
                    Debug.WriteLine(Name + ": Unexpected write of value " + Hex.Format(value) + " to address " + Hex.Format(address));
                }
            }
        }
Beispiel #5
0
        // CHR bank 1 (internal, $C000-$DFFF)
        private void WriteCharacterBank1(byte value)
        {
            characterBank1 = value;
            UpdateOffsets();

            CharacterBankSwitch?.Invoke(0x1000, 0x1000);

            // ignored in 8k CHAR mode
            if (characterBankMode == 1)
            {
                HandleSxRomVariants(value);
            }
        }
Beispiel #6
0
        public override byte this[ushort address]
        {
            get
            {
                if (address < 0x2000)
                {
                    return(Cartridge.CharacterRom[characterBank * 0x2000 + address]);
                }

                if (address >= 0xC000)
                {
                    return(Cartridge.ProgramRom[programBank2 * 0x4000 + address - 0xC000]);
                }

                if (address >= 0x8000)
                {
                    return(Cartridge.ProgramRom[programBank1 * 0x4000 + address - 0x8000]);
                }

                if (address >= 0x6000)
                {
                    return(Cartridge.SaveRam[(ushort)(address - 0x6000)]);
                }

                throw new Exception("Unhandled CNROM mapper read at address: " + Hex.Format(address));
            }

            set
            {
                if (address < 0x2000)
                {
                    Cartridge.CharacterRom[characterBank * 0x2000 + address] = value;
                }
                else if (address >= 0x8000)
                {
                    characterBank = value % 3;

                    // invalidate address region
                    CharacterBankSwitch?.Invoke(0x0000, 0x2000);
                }
                else if (address >= 0x6000)
                {
                    Cartridge.SaveRam[(ushort)(address - 0x6000)] = value;
                }
                else
                {
                    throw new Exception("Unhandled CNROM mapper write at address: " + Hex.Format(address));
                }
            }
        }
        public override byte this[ushort address]
        {
            get
            {
                if (address < 0x2000)
                {
                    return(Cartridge.CharacterRom[characterBank * 0x2000 + address]);
                }
                else if (address >= 0x8000)
                {
                    return(Cartridge.ProgramRom[programBank * 0x8000 + address % 0x8000]);
                }
                else
                {
                    Debug.WriteLine(Name + ": Unexpected read from address: " + Hex.Format(address));
                    return((byte)(address >> 8)); // open bus
                }
            }

            set
            {
                if (address >= 0x7000 && address < 0x8000)
                {
                    // .... CCPP

                    int oldProgramBank = programBank;
                    programBank = value & 0x03;

                    // invalidate address region
                    if (programBank != oldProgramBank)
                    {
                        ProgramBankSwitch?.Invoke(0x8000, 0x8000);
                    }

                    int oldCharacterBank = characterBank;
                    characterBank = (value >> 2) & 0x03;

                    // invalidate address region
                    if (characterBank != oldCharacterBank)
                    {
                        CharacterBankSwitch?.Invoke(0x0000, 0x2000);
                    }
                }
                else
                {
                    Debug.WriteLine(Name + ": unexpected write of value " + Hex.Format(value) + " at address: " + Hex.Format(address));
                }
            }
        }
Beispiel #8
0
        public override byte this[ushort address]
        {
            get
            {
                if (address < 0x2000)
                {
                    return(Cartridge.CharacterRom[characterBank * 0x2000 + address]);
                }

                if (address >= 0x8000)
                {
                    return(Cartridge.ProgramRom[programBank * 0x8000 + address - 0x8000]);
                }

                throw new Exception("Unhandled " + Name + " mapper read at address: " + Hex.Format(address));
            }

            set
            {
                if (address < 0x2000)
                {
                    Cartridge.CharacterRom[characterBank * 0x2000 + address] = value;
                }
                else if (address >= 0x8000)
                {
                    int oldProgramBank = programBank;

                    // --PP--CC
                    programBank   = (value >> 4) & 7;
                    characterBank = value & 7;

                    // invalidate address regions
                    CharacterBankSwitch?.Invoke(0x0000, 0x2000);

                    if (programBank != oldProgramBank)
                    {
                        ProgramBankSwitch?.Invoke(0x8000, 0x8000);
                    }
                }
                else if (address >= 0x6000)
                {
                    Cartridge.SaveRam[(ushort)(address - 0x6000)] = value;
                }
                else
                {
                    throw new Exception("Unhandled " + Name + " mapper write at address: " + Hex.Format(address));
                }
            }
        }
Beispiel #9
0
        public override byte this[ushort address]
        {
            get
            {
                if (address < 0x2000)
                {
                    return(Cartridge.CharacterRom[characterBank * 0x2000 + address]);
                }
                else if (address >= 0x8000 && address < 0xC000)
                {
                    return(Cartridge.ProgramRom[programBank * 0x4000 + address % 0x4000]);
                }
                else if (address >= 0xC000)
                {
                    return(Cartridge.ProgramRom[programLastAddress16k + address % 0x4000]);
                }
                else
                {
                    Debug.WriteLine(Name + ": Unexpected read from address " + Hex.Format(address));
                    return((byte)(address >> 8));
                }
            }

            set
            {
                if (address > 0x8000)
                {
                    int oldProgramBank = programBank;
                    programBank = (value >> 2) & 0x07;
                    if (programBank != oldProgramBank)
                    {
                        ProgramBankSwitch?.Invoke(0x8000, 0x4000);
                    }

                    int oldCharacterBank = characterBank;
                    characterBank = value & 0x03;
                    if (characterBank != oldCharacterBank)
                    {
                        CharacterBankSwitch?.Invoke(0x0000, 0x2000);
                    }
                }
                else
                {
                    Debug.WriteLine(Name + ": Unexpected write of value " + Hex.Format(value) + " to address " + Hex.Format(address));
                }
            }
        }
Beispiel #10
0
        public override byte this[ushort address]
        {
            get
            {
                if (address < 0x2000)
                {
                    return(Cartridge.CharacterRom[characterBank * 0x2000 + address]);
                }

                if (address >= 0x8000)
                {
                    return(Cartridge.ProgramRom[programBank * 0x8000 + address - 0x8000]);
                }

                throw new Exception("Unhandled " + Name + " mapper read at address: " + Hex.Format(address));
            }

            set
            {
                if (address >= 0x8000)
                {
                    int oldProgramBank = programBank;

                    // CCCCLLPP
                    // CCCC - CHR bank, LL - CIC chip lockout defeat, PP - PRG bank
                    programBank   = value & 0x3;
                    characterBank = (value >> 4) & 0xF;

                    // invalidate address regions
                    CharacterBankSwitch?.Invoke(0x0000, 0x2000);
                    if (programBank != oldProgramBank)
                    {
                        ProgramBankSwitch?.Invoke(0x8000, 0x8000);
                    }
                }
                else
                {
                    throw new Exception("Unhandled " + Name + " mapper write at address: " + Hex.Format(address));
                }
            }
        }
Beispiel #11
0
        public override byte this[ushort address]
        {
            get
            {
                if (address < 0x2000)
                {
                    return(Cartridge.CharacterRom[characterBank * 0x2000 + address]);
                }
                else if (address >= 0x8000)
                {
                    return(Cartridge.ProgramRom[programBank * 0x8000 + address % 0x8000]);
                }
                else
                {
                    Debug.WriteLine(Name + ": Unexpected read from address " + Hex.Format(address));
                    return((byte)(address >> 8)); // return open bus
                }
            }

            set
            {
                if (address >= 0x6000 && address < 0x8000)
                {
                    // $6000-7FFF:  [CCCC PPPP]   High CHR, PRG bits
                    int oldProgramBank   = programBank;
                    int oldCharacterBank = characterBank;

                    programBank &= 0x01;                  // clear bit1 onwards (preserve PRG low bit)
                    programBank |= (value & 0x0F) << 1;   // set bit1-bit4 PRG high bits

                    characterBank &= 0x07;                // clear bit3 onwards (priserve CHR low bits)
                    characterBank |= ((value >> 4) << 3); // set bit3-bit6 CHR high bits)

                    // invalidate address regions
                    if (programBank != oldProgramBank)
                    {
                        ProgramBankSwitch?.Invoke(0x8000, 0x8000);
                    }
                    if (characterBank != oldCharacterBank)
                    {
                        CharacterBankSwitch?.Invoke(0x0000, 0x2000);
                    }
                }
                if (address >= 0x8000)
                {
                    //  $8000-FFFF:  [.CCC ...P]   Low CHR, PRG bits

                    int oldProgramBank   = programBank;
                    int oldCharacterBank = characterBank;

                    programBank &= 0xFE;                  // clear bit 0
                    programBank |= value & 0x01;          // set PRG low bit

                    characterBank &= 0xF8;                // clear bits 0 - 2
                    characterBank |= (value >> 4) & 0x07; // set CHR low bits

                    // invalidate address regions
                    if (programBank != oldProgramBank)
                    {
                        ProgramBankSwitch?.Invoke(0x8000, 0x8000);
                    }
                    if (characterBank != oldCharacterBank)
                    {
                        CharacterBankSwitch?.Invoke(0x0000, 0x2000);
                    }
                }
                else
                {
                    Debug.WriteLine(Name + ": Unexpected write of value " + Hex.Format(value) + " at address " + Hex.Format(address));
                }
            }
        }
Beispiel #12
0
        public override byte this[ushort address]
        {
            get
            {
                if (address < 0x2000)
                {
                    int bank   = address / 0x1000;
                    int offset = address % 0x1000;
                    return(Cartridge.CharacterRom[characterBankOffsets[bank] + offset]);
                }
                else if (address >= 0x8000)
                {
                    address -= 0x8000;
                    int bank   = address / 0x4000;
                    int offset = address % 0x4000;
                    return(Cartridge.ProgramRom[outerProgramRomBank + programBankOffsets[bank] + offset]);
                }
                else if (address >= 0x6000)
                {
                    ushort offset = (ushort)(address - 0x6000);
                    if (programRamBanksSupported)
                    {
                        return(programRam[programRamBank * 0x2000 + offset]);
                    }
                    else
                    {
                        return(Cartridge.SaveRam[offset]);
                    }
                }
                else
                {
                    return((byte)(address >> 8)); // open bus
                }
            }

            set
            {
                if (address < 0x2000)
                {
                    int bank   = address / 0x1000;
                    int offset = address % 0x1000;
                    Cartridge.CharacterRom[characterBankOffsets[bank] + offset] = value;

                    CharacterBankSwitch?.Invoke((ushort)characterBankOffsets[bank], 0x1000);
                }
                else if (address >= 0x8000)
                {
                    LoadRegister(address, value);
                }
                else if (address >= 0x6000)
                {
                    ushort offset = (ushort)(address - 0x6000);
                    if (programRamBanksSupported)
                    {
                        programRam[programRamBank * 0x2000 + offset] = value;
                    }
                    else
                    {
                        Cartridge.SaveRam[offset] = value;
                    }
                }
            }
        }
Beispiel #13
0
        public override byte this[ushort address]
        {
            get
            {
                if (address < 0x2000)
                {
                    int bank   = address / 0x400;
                    int offset = address % 0x400;
                    return(Cartridge.CharacterRom[characterRomBank[bank] * 0x400 + offset]);
                }
                else if (address >= 0x8000)
                {
                    int bank   = (address - 0x8000) / 0x2000;
                    int offset = address % 0x2000;
                    return(Cartridge.ProgramRom[programRomBank[bank] * 0x2000 + offset]);
                }
                else
                {
                    return((byte)(address >> 8)); // assuming open bus
                }
            }

            set
            {
                if (address >= 0x8000 && address < 0xA000)
                {
                    int offset1000 = address % 0x1000;
                    if (offset1000 >= 4)
                    {
                        return;
                    }

                    int bankIndex1000 = (address - 0x8000) / 0x1000;

                    int programBankIndex = bankIndex1000 * 2 + offset1000 / 2;

                    // last bank must remain fixed
                    if (programBankIndex > 2)
                    {
                        return;
                    }

                    int oldProgramBank = programRomBank[programBankIndex];

                    if (offset1000 % 2 == 0)
                    {
                        programRomBank[programBankIndex] = SetLowerNybble(programRomBank[programBankIndex], value);
                    }
                    else
                    {
                        programRomBank[programBankIndex] = SetHigherNybble(programRomBank[programBankIndex], value);
                    }


                    if (programRomBank[programBankIndex] != oldProgramBank)
                    {
                        Debug.WriteLine("Program Bank " + programBankIndex + " (" + Hex.Format(address) + ") = " + programRomBank[programBankIndex]);
                        ProgramBankSwitch?.Invoke((ushort)(0x8000 + programBankIndex * 0x2000), 0x2000);
                    }
                }
                else if (address >= 0xA000 && address < 0xE000)
                {
                    int offset1000 = address % 0x1000;
                    if (offset1000 >= 4)
                    {
                        return;
                    }

                    int bankIndex1000 = (address - 0xA000) / 0x1000;

                    int characterBankIndex = bankIndex1000 * 2 + offset1000 / 2;

                    int oldCharacterBank = characterRomBank[characterBankIndex];

                    if (offset1000 % 2 == 0)
                    {
                        characterRomBank[characterBankIndex] = SetLowerNybble(characterRomBank[characterBankIndex], value);
                    }
                    else
                    {
                        characterRomBank[characterBankIndex] = SetHigherNybble(characterRomBank[characterBankIndex], value);
                    }

                    if (characterRomBank[characterBankIndex] != oldCharacterBank)
                    {
                        Debug.WriteLine("Character Bank " + characterBankIndex + " (" + Hex.Format(address) + ") = " + characterRomBank[characterBankIndex]);
                        CharacterBankSwitch?.Invoke((ushort)(characterBankIndex * 0x400), 0x400);
                    }
                }
                else if (address == 0xE000)
                {
                    // bits 0..3 of IRQ counter reload
                    irqReload &= 0xFFF0;
                    irqReload |= (ushort)(value & 0x0F);
                }
                else if (address == 0xE001)
                {
                    // bits 4..7 of IRQ counter reload
                    irqReload &= 0xFF0F;
                    irqReload |= (ushort)((value & 0x0F) << 4);
                }
                else if (address == 0xE002)
                {
                    // bits 8..11 of IRQ counter reload
                    irqReload &= 0xF0FF;
                    irqReload |= (ushort)((value & 0x0F) << 8);
                }
                else if (address == 0xE003)
                {
                    // bits 12..15 of IRQ counter reload
                    irqReload &= 0x0FFF;
                    irqReload |= (ushort)((value & 0x0F) << 12);
                }
                else if (address == 0xF000)
                {
                    irqCounter = irqReload;
                    Debug.WriteLine("IRQ Reloaded to " + irqReload);
                    CancelInterruptRequest?.Invoke();
                    irqPrimed = false;
                }
                else if (address == 0xF001)
                {
                    irqCounterEnabled = (value & 0x01) != 0;

                    int counterBits = (value >> 1) & 0x07;

                    switch (counterBits)
                    {
                    case 0: irqFixedMask = 0x0000; break;

                    case 1: irqFixedMask = 0xF000; break;

                    case 2:
                    case 3: irqFixedMask = 0xFF00; break;

                    default: irqFixedMask = 0xFFF0; break;
                    }
                    irqCounterMask = 0xFFFF - irqFixedMask; // complement

                    CancelInterruptRequest?.Invoke();
                    irqPrimed = false;
                }
                else if (address == 0xF002)
                {
                    // mirror mode
                    switch (value & 0x03)
                    {
                    case 0x00: MirrorMode = MirrorMode.Horizontal; break;

                    case 0x01: MirrorMode = MirrorMode.Vertical; break;

                    case 0x02: MirrorMode = MirrorMode.Single0; break;

                    case 0x03: MirrorMode = MirrorMode.Single1; break;
                    }
                }
            }
        }
        public override byte this[ushort address]
        {
            get
            {
                if (address < 0x2000)
                {
                    if (characterBanksSupported)
                    {
                        // get data from corresponding 1K bank
                        int bankindex  = address / 0x400;
                        int bankOffset = address % 0x400;
                        return(Cartridge.CharacterRom[characterBank[bankindex] * 0x400 + bankOffset]);
                    }
                    else
                    {
                        // for Datach Joint ROM System - treat as flat CHR RAM
                        return(Cartridge.CharacterRom[address]);
                    }
                }

                if (address >= 0x6000 && address < 0x7FFF)
                {
                    // return SRAM or open bus depending on variant
                    return(saveRamSupported ? Cartridge.SaveRam[(ushort)(address - 0x6000)] : (byte)(address >> 8));
                }

                if (address >= 0x8000 && address < 0xC000)
                {
                    int bankOffset = address % 0x4000;
                    return(Cartridge.ProgramRom[outerProgramBank + programBank * 0x4000 + bankOffset]);
                }

                if (address >= 0xC000)
                {
                    // fixed at last bank
                    int lastBankOffset = address % 0x4000;
                    return(Cartridge.ProgramRom[outerProgramBank + lastProgramBankBase + lastBankOffset]);
                }

                //if (address >= 0x6000)
                //    return Cartridge.SaveRam[(ushort)(address - 0x6000)];

                //throw new Exception("Unhandled " + Name + " mapper read at address: " + Hex.Format(address));
                // return open bus?
                return((byte)(address >> 8));
            }

            set
            {
                if (address < 0x2000)
                {
                    if (characterBanksSupported)
                    {
                        // CHR bank switches for 8 0x400 ranges
                        // set CHR bank for corresponding 0x400 range
                        int bankindex  = address / 0x400;
                        int bankOffset = address % 0x400;
                        Cartridge.CharacterRom[characterBank[bankindex] * 0x400 + bankOffset] = value;
                    }
                    else
                    {
                        // for Datach Joint ROM System - treat as flat CHR RAM
                        Cartridge.CharacterRom[address] = value;
                    }
                }
                else if (saveRamSupported && address >= 0x6000 && address < 0x8000)
                {
                    Cartridge.SaveRam[(ushort)(address - 0x6000)] = value;
                }
                else if (address >= registerBase)
                {
                    // NOTE: FCG variants vary register base between $6000 and $8000
                    // variants lumped under mapper 16 require mirroring these bases to get most games to work
                    int registerAddress = address % 0x10;
                    if (outerProgramBankSupported && address >= 0x8000 && address < 0x8004)
                    {
                        int oldOuterProgramBank = outerProgramBank;
                        // outer program bank (mapper 153 only)
                        if ((value & 0x01) != 0)
                        {
                            outerProgramBank = 0x40000;
                        }
                        else
                        {
                            outerProgramBank = 0;
                        }

                        if (outerProgramBank != oldOuterProgramBank)
                        {
                            ProgramBankSwitch?.Invoke(0x8000, 0x8000);
                        }
                    }
                    else if (characterBanksSupported && registerAddress < 0x08)
                    {
                        // CHR bank switch
                        int oldCharacterBank = characterBank[registerAddress];
                        characterBank[registerAddress] = value;
                        if (value != oldCharacterBank)
                        {
                            CharacterBankSwitch?.Invoke((ushort)(registerAddress * 0x400), 0x400);
                        }
                    }
                    else if (registerAddress == 0x08)
                    {
                        // program bank switch
                        int oldProgramBank = programBank;
                        programBank  = value & 0x0F;
                        programBank %= programBankCount; // probably not needed, but anyhow

                        // invalidate address region
                        if (programBank != oldProgramBank)
                        {
                            ProgramBankSwitch?.Invoke(0x8000, 0x4000);
                        }
                    }
                    else if (registerAddress == 0x09)
                    {
                        // mirroring mode
                        switch (value & 0x03)
                        {
                        case 0: MirrorMode = MirrorMode.Vertical; break;

                        case 1: MirrorMode = MirrorMode.Horizontal; break;

                        case 2: MirrorMode = MirrorMode.Single0; break;

                        case 3: MirrorMode = MirrorMode.Single1; break;
                        }
                    }
                    else if (registerAddress == 0x0A)
                    {
                        irqEnabled = (value & 0x01) != 0;
                        CancelInterruptRequest?.Invoke();
                    }
                    else if (registerAddress == 0x0B)
                    {
                        irqCounter &= 0xFF00;
                        irqCounter |= value;
                    }
                    else if (registerAddress == 0x0C)
                    {
                        irqCounter &= 0x00FF;
                        irqCounter |= (ushort)(value << 8);
                    }
                    // TODO: D: eeprom/PRG ram enable
                    // TODO: variants
                }
                else
                {
                    throw new Exception("Unhandled " + Name + " mapper write at address: " + Hex.Format(address));
                    //ignore writes?
                }
            }
        }
Beispiel #15
0
        public override byte this[ushort address]
        {
            get
            {
                if (address < 0x1000)
                {
                    return(Cartridge.CharacterRom[address]);
                }

                if (address < 0x2000)
                {
                    int index = address & 0xFFF;
                    if (characterBank < 2)
                    {
                        return(Cartridge.CharacterRom[characterBank * 0x1000 + index]);
                    }
                    else
                    {
                        return(characterRam[(characterBank - 2) * 0x1000 + index]);
                    }
                }

                if (address >= 0x8000)
                {
                    return(Cartridge.ProgramRom[address - 0x8000]);
                }

                throw new Exception("Unhandled " + Name + " mapper read at address: " + Hex.Format(address));
            }

            set
            {
                if (address < 0x1000)
                {
                    Cartridge.CharacterRom[address] = value;
                }
                else if (address < 0x2000)
                {
                    int index = address & 0xFFF;
                    if (characterBank < 2)
                    {
                        Cartridge.CharacterRom[characterBank * 0x1000 + index] = value;
                    }
                    else
                    {
                        characterRam[(characterBank - 2) * 0x1000 + index] = value;
                    }
                }
                else if (address >= 0x8000)
                {
                    characterBank = value & 0x03;

                    // invalidate address regions
                    CharacterBankSwitch?.Invoke(0x0000, 0x1000);
                }
                else
                {
                    throw new Exception("Unhandled " + Name + " mapper write at address: " + Hex.Format(address));
                }
            }
        }