Ejemplo n.º 1
0
        public override void write(ushort address, byte val)
        {
            if (address < 0x6000)
            {
                // A couple of games have tried to write here. It's undefined behavior as far as I know.
                return;
            }

            // First handle RAM. Everything else uses the shift register
            if (address < 0x8000)
            {
                int offset = address - 0x6000;
                PRG_RAM[offset] = val;
                return;
            }


            // Writing with bit 7 set, this write just resets the shift register
            if ((val & 0x80) != 0)
            {
                shift_register   = 0x00;
                ControlRegister |= 0x0C;
                shift_register_write_counter = 0;

                updateOffsets();
                return;
            }

            // We're shifting in a bit to the shift register..
            shift_register >>= 1;
            shift_register  |= (byte)((val & 1) << 4);
            shift_register_write_counter++;

            // Should we do an actual write?
            if (shift_register_write_counter == 5)
            {
                if (address < 0xA000)
                {
                    ControlRegister = shift_register;

                    NametableMirroringMode oldMode = cartridge.NametableMirroring;

                    switch (ControlRegister & 3)
                    {
                    case 0: cartridge.NametableMirroring = NametableMirroringMode.OneScreenLowBank; break;

                    case 1: cartridge.NametableMirroring = NametableMirroringMode.OneScreenHighBank; break;

                    case 2: cartridge.NametableMirroring = NametableMirroringMode.Vertical; break;

                    case 3: cartridge.NametableMirroring = NametableMirroringMode.Horizontal; break;
                    }

                    if (oldMode != cartridge.NametableMirroring)
                    {
                        Console.WriteLine("Switched to {0}", cartridge.NametableMirroring.ToString());
                    }
                }
                else if (address < 0xC000)
                {
                    CHR0Select = shift_register;
                }
                else if (address < 0xE000)
                {
                    CHR1Select = shift_register;
                }
                else
                {
                    Console.WriteLine("Switched to PRG {0}", shift_register & 0x0F);
                    PRGSelect = shift_register;
                }

                // Update offsets
                updateOffsets();

                shift_register = 0x00;
                shift_register_write_counter = 0;
            }
        }
Ejemplo n.º 2
0
        /// <summary>
        /// Load a rom file using the iNES file format, the de facto NES rom file format.
        /// http://wiki.nesdev.com/w/index.php/INES
        /// </summary>
        /// <param name="romPath"></param>
        private void loadRomData(string romPath)
        {
            byte[] fullRomData = File.ReadAllBytes(romPath);
            byte[] header      = new ArraySegment <byte>(fullRomData, 0, 16).ToArray();

            // First confirm this is actually an iNES rom...
            uint fileSignature = BitConverter.ToUInt32(header, 0);

            if (fileSignature != INES_FILE_SIGNATURE)
            {
                log.error("Did not find expected iNES Rom File Signature");
                throw new InvalidDataException();
            }

            PRGROM_16KBankCount = header[4];
            PRGRAM_8KBankCount  = header[8];
            CHRROM_8KBankCount  = header[5];

            // iNES has a number of flags all rolled up into 4 flag bytes.
            int flag6  = header[6];
            int flag7  = header[7];
            int flag9  = header[9];
            int flag10 = header[10];

            NametableMirroring = (flag6 & 1) == 1 ? NametableMirroringMode.Vertical : NametableMirroringMode.Horizontal;

            bool usesTrainer = (flag6 & 4) != 0;

            if (usesTrainer)
            {
                log.error("ROM uses a trainer. This is unsupported.");
                throw new NotImplementedException();
            }

            isNTSC = (flag10 & 1) == 0;
            if (!isNTSC)
            {
                log.error("ROM is PAL. This is unsupported...");
                throw new NotImplementedException();
            }

            if ((flag6 & 2) == 1)
            {
                BatteryBackedRAM = true;
            }

            MapperNumber = flag6 >> 4 | (flag7 & 0xf0);

            // Now that we know all the 'metadata' about the file, load the actual data.
            int prgStart = 16 + (usesTrainer ? 512 : 0);
            int prgBytes = 0x4000 * PRGROM_16KBankCount;

            PRGRomData = new ArraySegment <byte>(fullRomData, prgStart, prgBytes).ToArray();

            int chrStart = prgStart + prgBytes;
            int chrBytes = 0x2000 * CHRROM_8KBankCount;

            CHRRomData = new ArraySegment <byte>(fullRomData, chrStart, chrBytes).ToArray();

            log.info("ROM Details --");
            log.info(" * Mapper #{0}", MapperNumber);
            log.info(" * Nametable mirroring mode is {0}.", NametableMirroring.ToString());
            log.info(" * {0} Output", isNTSC ? "NTSC" : "PAL");
            if (BatteryBackedRAM)
            {
                log.info(" * Battery-backed RAM ('Game Saves' supported)");
            }

            log.info(" * ROM Bank Data");
            log.info("   - {0}x 16 KB PRG ROM", PRGROM_16KBankCount);
            log.info("   - {0}x 8 KB PRG RAM", PRGRAM_8KBankCount);
            log.info("   - {0}x 8 KB CHR ROM", CHRROM_8KBankCount);

            log.info("Finished loading '{0}'.", romPath);
        }