Esempio n. 1
0
        public MBC3(CartHeader header, byte[] gameROM, MemoryMappedFile file, Func <long>?getClock = null)
        {
            this.gameROM = gameROM;
            RAMBanks     = file.CreateViewAccessor(0, header.RAM_Size);


            //0x800 is the only alternative bank size
            if (header.RAM_Size == 0)
            {
                RAMBankSize = 0;
            }

            //0x800 is the only alternative bank size
            if (header.RAM_Size == 0x800)
            {
                RAMBankSize = 0x800;
            }

            if (getClock is not null)
            {
                ClockStorage = file.CreateViewAccessor(header.RAM_Size, 16);
                hasClock     = true;
                var InitialOffsetFromSave = ClockStorage.ReadInt64(0);
                var timeOfLastSave        = ClockStorage.ReadInt64(8);
                var DotNetTicksElapsed    = DateTime.Now.Ticks - timeOfLastSave;
                var GameboyTicksElapsed   = (long)(DotNetTicksElapsed * (TicksPerSecond / 10000000.0));
                InitialOffsetFromSave += GameboyTicksElapsed;

                GetRTC = () => getClock() + InitialOffsetFromSave;
            }
        }
Esempio n. 2
0
        public MBC1(CartHeader header, byte[] gameROM)
        {
            this.gameROM = gameROM;
            ROMBankCount = this.gameROM.Length / 0x4000;

            RAMBankCount = Math.Max(1, header.RAM_Size / RAMBankSize);
            RAMBankSize  = Math.Min(header.RAM_Size, 0x2000);

            RAMBanks = new byte[Math.Max(0x2000, header.RAM_Size)];
        }
        public MBC1WithBatteryBackedRAM(CartHeader header, byte[] gameROM, MemoryMappedFile file)
        {
            this.gameROM = gameROM;
            ROMBankCount = this.gameROM.Length / 0x4000;

            RAMBankCount = Math.Max(1, header.RAM_Size / RAMBankSize);
            RAMBankSize  = Math.Min(header.RAM_Size, 0x2000);

            RAMBanks = file.CreateViewAccessor(0, header.RAM_Size);
        }
Esempio n. 4
0
        public MBC5(CartHeader header, byte[] gameROM)
        {
            this.gameROM = gameROM;

            ROMBankCount = this.gameROM.Length / 0x4000;
            RAMBankCount = Math.Max(1, header.RAM_Size / RAMBankSize);
            RAMBanks     = null;

            //0x800 is the only alternative bank size
            if (header.RAM_Size == 0)
            {
                RAMBankSize = 0;
            }

            //0x800 is the only alternative bank size
            if (header.RAM_Size == 0x800)
            {
                RAMBankSize = 0x800;
            }
        }
Esempio n. 5
0
        public MBC5(CartHeader header, byte[] gameROM, System.IO.MemoryMappedFiles.MemoryMappedFile file)
        {
            this.gameROM = gameROM;

            ROMBankCount = this.gameROM.Length / 0x4000;
            RAMBankCount = Math.Max(1, header.RAM_Size / RAMBankSize);
            RAMBanks     = file.CreateViewAccessor(0, header.RAM_Size);

            //0x800 is the only alternative bank size
            if (header.RAM_Size == 0)
            {
                RAMBankSize = 0;
            }

            //0x800 is the only alternative bank size
            if (header.RAM_Size == 0x800)
            {
                RAMBankSize = 0x800;
            }
        }
Esempio n. 6
0
 public MBC5WithRumble(CartHeader cartHeader, byte[] gameROM, MemoryMappedFile memoryMappedFile) : base(cartHeader, gameROM, memoryMappedFile)
 {
 }
Esempio n. 7
0
        public Core(byte[] gameROM, byte[]?bootROM, Keypad Keypad, FrameSink frameSink)
        {
            if (gameROM.Length < 0x8000)
            {
                throw new Exception("Cartridge file has to be at least 8kb in size");
            }
            PC = new();

            InterruptRegisters        = new InterruptRegisters();
            Keypad.Input.KeyWentDown += InterruptRegisters.TriggerEvent;

            APU = new APU(32768);
            PPU = new PPU(InterruptRegisters.EnableVBlankInterrupt, InterruptRegisters.EnableLCDSTATInterrupt, frameSink);

            Timers = new Timers(InterruptRegisters.EnableTimerInterrupt);

            var ioRegisters = SetupControlRegisters(Keypad);

            CartHeader Header = new CartHeader(gameROM);

            MBC Card;

            if (Header.HasBattery())
            {
                var mmf = Header.MakeMemoryMappedFile();
                Card = Header.HasClock() ? Header.MakeMBC(gameROM, mmf, () => masterclock) : Header.MakeMBC(gameROM, mmf);
            }
            else
            {
                Card = Header.MakeMBC(gameROM);
            }

            //Writing out the RTC too often would be very heavy. This writes it out once per frame.
            //
            if (Header.Type == CartType.MBC3_TIMER_RAM_BATTERY)
            {
                var SaveRTC = ((MBC3)Card).SaveRTC();

                void h(object?x, EventArgs y) => SaveRTC();

                frameSink.FramePushed += h;
            }

            if (Card is MBC5WithRumble rumble)
            {
                rumble.RumbleStateChange += Keypad.ToggleRumble;
            }

            Memory = new MMU(
                bootROM,
                Card,
                PPU.VRAM,
                PPU.OAM,
                ioRegisters,
                (x => InterruptRegisters.InterruptControlRegister = x,
                 () => InterruptRegisters.InterruptControlRegister),
                PC
                );

            CPU = new CPU(Memory, InterruptRegisters, PC);
            ioRegisters[0x0f] = InterruptRegisters.HookUp();

            ioRegisters[0x50] = Memory.HookUpMemory();

            //We have to replicate the state of the system post boot without running the bootrom
            if (bootROM == null)
            {
                //registers
                CPU.SetStateWithoutBootrom();

                //timers
                Timers.SetStateWithoutBootrom();


                //sound
                APU.SetStateWithoutBootrom();

                //graphics TODO: we can't really set up the graphics environment correctly
                //because we will have to also initialize the internal renderer state correctly
                PPU.SetStateWithoutBootrom();


                InterruptRegisters.SetStateWithoutBootrom();
            }
        }