예제 #1
0
        /// <summary>
        /// Start the nes machine
        /// </summary>
        public void InitializeEngine()
        {
            myCartridge = new Cart();
            my6502      = new CPU6502(this);
            myMapper    = new Mappers(this, ref myCartridge);
            myPPU       = new PPU(this);//, myVideo);

            myAPU.Reset();

            scratchRam    = new byte[4][];
            scratchRam[0] = new byte[0x800];
            scratchRam[1] = new byte[0x800];
            scratchRam[2] = new byte[0x800];
            scratchRam[3] = new byte[0x800];
            saveRam       = new byte[0x2000];

            isSaveRAMReadonly = false;
            isDebugging       = false;
            isQuitting        = false;
            isPaused          = false;
            hasQuit           = false;
            //fix_bgchange = false;
            //fix_spritehit = false;
            fix_scrolloffset1 = false;
            fix_scrolloffset2 = false;
            fix_scrolloffset3 = false;
        }
예제 #2
0
        public async Task Setup()
        {
            mem = _serviceProvider.GetService <IAddressMap>();
            mem.Install(new Ram(0x0000, 0x10000));

            _display = _serviceProvider.GetService <IMemoryMappedDisplay>();
            _display.Locate(DISPLAY_BASE_ADDR, DISPLAY_SIZE);
            mem.Install(_display);
            await _display.Initialise();

            _display.Clear();

            _cpu          = (CPU6502)_serviceProvider.GetService <IDebuggableCpu>();
            _cpu.LogLevel = LogLevel.Trace;

            mem.WriteWord(_cpu.RESET_VECTOR, PROG_START);

            _persistence = new MemoryFilePersistence
            {
                WorkingDirectory = "~/6502Programs"
            };

            mem.Labels.Add("DISPLAY_CONTROL_ADDR", MemoryMappedDisplay.DISPLAY_CONTROL_BLOCK_ADDR);
            mem.Labels.Add("DISPLAY_BASE_ADDR", DISPLAY_BASE_ADDR);
            mem.Labels.Add("DISPLAY_SIZE", DISPLAY_SIZE);
            mem.Labels.Add("RESET_VECTOR", _cpu.RESET_VECTOR);
            mem.Labels.Add("IRQ_VECTOR", _cpu.IRQ_VECTOR);
            mem.Labels.Add("NMI_VECTOR", _cpu.NMI_VECTOR);

            mem.Labels.Push();
        }
예제 #3
0
        public void Setup()
        {
            _logger = (UnitTestLogger <CPU6502>)_serviceProvider.GetService <ILogger <CPU6502> >();
            _logger.GetOutput(); // Clear any buffered output

            mem = _serviceProvider.GetService <IAddressMap>();
            mem.Install(new Ram(0x0000, 0x10000));

            _display = _serviceProvider.GetService <IMemoryMappedDisplay>();
            _display.Locate(DISPLAY_BASE_ADDR, DISPLAY_SIZE);
            mem.Install(_display);
            AsyncUtil.RunSync(mem.Initialise);
            _display.Clear();
            _cpu          = (CPU6502)_serviceProvider.GetService <IDebuggableCpu>();
            _cpu.LogLevel = LogLevel.Trace;
            mem.WriteWord(_cpu.RESET_VECTOR, PROG_START);
            mem.Labels.Clear();
            mem.Labels.Add("DISPLAY_CONTROL_ADDR", MemoryMappedDisplay.DISPLAY_CONTROL_BLOCK_ADDR);
            mem.Labels.Add("DISPLAY_BASE_ADDR", DISPLAY_BASE_ADDR);
            mem.Labels.Add("DISPLAY_SIZE", DISPLAY_SIZE);
            mem.Labels.Add("RESET_VECTOR", _cpu.RESET_VECTOR);
            mem.Labels.Add("IRQ_VECTOR", _cpu.IRQ_VECTOR);
            mem.Labels.Add("NMI_VECTOR", _cpu.NMI_VECTOR);
            _cpuHoldEvent             = _serviceProvider.GetService <ICpuHoldEvent>();
            _cpuStepEvent             = _serviceProvider.GetService <ICpuStepEvent>();
            _cancellationTokenWrapper = _serviceProvider.GetService <CancellationTokenWrapper>();
            _cancellationTokenWrapper.Reset();
        }
예제 #4
0
 public static void Backup(Register registers = Register.All, bool statusFlags = false)
 {
     if (statusFlags)
     {
         CPU6502.PHP();
     }
     if (registers.HasFlag(Register.A))
     {
         CPU6502.PHA();
         A.State.Push();
     }
     if (registers.HasFlag(Register.X))
     {
         CPU6502.TXA();
         //Use(Asm.TXA);
         CPU6502.PHA();
         X.State.Push();
     }
     if (registers.HasFlag(Register.Y))
     {
         CPU6502.TYA();
         //Use(Asm.TYA);
         CPU6502.PHA();
         Y.State.Push();
     }
 }
예제 #5
0
        public async Task Setup()
        {
            mem = _serviceProvider.GetService <IAddressMap>();
            mem.Install(new Ram(0x0000, 0x10000));
            _display = _serviceProvider.GetService <IMemoryMappedDisplay>();
            _display.Locate(DISPLAY_BASE_ADDR, DISPLAY_SIZE);
            mem.Install(_display);
            _keyboard = _serviceProvider.GetService <IMemoryMappedKeyboard>();
            _keyboard.StartAddress = KEYBOARD_BASE_ADDR;
            mem.Install((IAddressAssignment)_keyboard);
            await mem.Initialise();

            _display.Clear();
            _cpu          = (CPU6502)_serviceProvider.GetService <IDebuggableCpu>();
            _cpu.LogLevel = LogLevel.Trace;
            _keyboard.RequestInterrupt += async(s, e) => { await _cpu.Interrupt(s, e); };

            mem.WriteWord(_cpu.RESET_VECTOR, PROG_START);

            mem.Labels.Add("DISPLAY_CONTROL_ADDR", MemoryMappedDisplay.DISPLAY_CONTROL_BLOCK_ADDR);
            mem.Labels.Add("DISPLAY_BASE_ADDR", DISPLAY_BASE_ADDR);
            mem.Labels.Add("DISPLAY_SIZE", DISPLAY_SIZE);
            mem.Labels.Add("KEYBOARD_STATUS_REGISTER", MemoryMappedKeyboard.STATUS_REGISTER + KEYBOARD_BASE_ADDR);
            mem.Labels.Add("KEYBOARD_CONTROL_REGISTER", MemoryMappedKeyboard.CONTROL_REGISTER + KEYBOARD_BASE_ADDR);
            mem.Labels.Add("KEYBOARD_DATA_REGISTER", MemoryMappedKeyboard.DATA_REGISTER + KEYBOARD_BASE_ADDR);
            mem.Labels.Add("KEYBOARD_SCAN_CODE_REGISTER", MemoryMappedKeyboard.SCAN_CODE_REGISTER + KEYBOARD_BASE_ADDR);
            mem.Labels.Add("RESET_VECTOR", _cpu.RESET_VECTOR);
            mem.Labels.Add("IRQ_VECTOR", _cpu.IRQ_VECTOR);
            mem.Labels.Add("NMI_VECTOR", _cpu.NMI_VECTOR);
        }
예제 #6
0
 public Condition Equals(U8 v)
 {
     if (v != 0 || Flags.Zero.LastReg != this)
     {
         CPU6502.CPX(v);
     }
     return(Condition.EqualsZero);
 }
예제 #7
0
 public VByte SetASL()
 {
     if (Index is RegisterY)
     {
         throw new Exception("Cannot SetASL with index Y");
     }
     CPU6502.ASL(this);
     return(this);
 }
예제 #8
0
 public static void Init()
 {
     //Copy funcs to those RAM chunks
     Y.Set(0);
     Loop.Do_old(_ => {
         AddrWriteVerify[Y].Set(A.Set(LabelFor(_WriteVerify)[Y]));
         Y.Increment();
         CPU6502.CPY(_lenTotalRamLength);
     }).While(() => Y.NotEquals(0));
 }
 public VByte UpdateSingleTile(Func <IOperand> x, Func <IOperand> y, Func <IOperand> color, VByte temp)
 {
     CPU6502.CLD(); CPU6502.CLD(); CPU6502.CLD(); CPU6502.CLD(); CPU6502.CLD();
     temp.Set(A.Set(x()).Divide(32));
     temp.Set(z => A.Set(y()).Divide(4).And(0b00111000).Or(z));
     Stack.Preserve(A, () => {                   //preserve attr index, wait to put into X, because X is needed as an index to X() and Y() values
         Comment("temp = attr tile mask index");
         temp.Set(A.Set(x()).Divide(16).And(1));
         temp.Set(z => A.Set(y()).Divide(8).And(0b10).Or(z));
     });
예제 #10
0
 public IndexingRegister Inc()
 {
     if (this is RegisterX)
     {
         CPU6502.INX();
     }
     else
     {
         CPU6502.INY();
     }
     return(this);
 }
예제 #11
0
 public IndexingRegister Dec()
 {
     if (this is RegisterX)
     {
         CPU6502.DEX();
     }
     else
     {
         CPU6502.DEY();
     }
     return(this);
 }
예제 #12
0
파일: Bus.cs 프로젝트: icaroNZ/Nes
 public Bus()
 {
     _cpu = new CPU6502();
     _ppu = new PPU2c02();
     _cpu.ConnectBus(this);
     // Ram 2Kb
     CpuRam = new byte[2048];
     for (var i = 0; i < CpuRam.Length - 1; i++)
     {
         CpuRam[i] = 0;
     }
 }
예제 #13
0
 public static void ClearRAM()
 {
     Loop.Repeat(X.Set(0), 256, _ => {
         A.Set(0);
         CPU6502.STA(Addr(0x0000)[X]);
         CPU6502.STA(Addr(0x0100)[X]);
         CPU6502.STA(Addr(0x0300)[X]);
         CPU6502.STA(Addr(0x0400)[X]);
         CPU6502.STA(Addr(0x0500)[X]);
         CPU6502.STA(Addr(0x0600)[X]);
         CPU6502.STA(Addr(0x0700)[X]);
         A.Set(0xFE);
         CPU6502.STA(Addr(0x0200)[X]);
     });
 }
예제 #14
0
        /// <summary>
        ///
        /// </summary>
        /// <param name="start">Inclusive</param>
        /// <param name="length">Exclusive</param>
        /// <param name="block"></param>
        public static void Repeat(IndexingRegister reg, int length, Action <LoopLabels> block)
        {
            var labels = new LoopLabels();
            //X.Reset();
            var lblStart = Labels.New();

            Context.Write(lblStart);
            Context.New(() => {
                var before = reg.State.Hash;
                block.Invoke(labels);
                reg.State.Verify(before);
                Context.Write(labels.ContinueLabel);
                reg.Inc();
                if (Context.StartBranchable)
                {
                    if (length < 256)
                    {
                        if (reg is RegisterX)
                        {
                            CPU6502.CPX((U8)length);
                        }
                        else
                        {
                            CPU6502.CPY((U8)length);
                        }
                    }
                    CPU6502.BNE(Context.Start);
                }
                else
                {
                    //TODO: verify this works!
                    if (length < 256)
                    {
                        if (reg is RegisterX)
                        {
                            CPU6502.CPX((U8)length);
                        }
                        else
                        {
                            CPU6502.CPY((U8)length);
                        }
                    }
                    CPU6502.BEQ(3);
                    GoTo(lblStart);
                }
            });
            Context.Write(labels.BreakLabel);
        }
예제 #15
0
        public NESCore()
        {
            isROMLoaded = false;

            _cpu = new CPU6502();
            _ppu = new PPU2C02();

            // Connect the Cpu and bus
            _cpu.ConnectBus(this);

            _cpuRam = new byte[totalMemoryInBytes];
            for (int i = 0; i < totalMemoryInBytes; i++)
            {
                _cpuRam[i] = 0x00;
            }
        }
예제 #16
0
파일: Program.cs 프로젝트: Maritims/NESsie
        static void DrawCPU(CPU6502 cpu)
        {
            Console.SetCursorPosition(0, 2);
            var flags = typeof(FLAGS6502).GetFields(BindingFlags.Public | BindingFlags.Static);

            Console.Write($"Cycles: {cpu.Cycles} - Opcode: {cpu.Opcode}, Instruction: {cpu.InstructionSetOpcodeMatrix[cpu.Opcode + 1]} - X: {cpu.X}, Y: {cpu.Y}, A: {cpu.A} - Flags: ");
            for (var i = 0; i < flags.Length; i++)
            {
                var flagName  = flags[i].Name;
                var flagValue = (byte)flags[i].GetValue(null);
                Console.ForegroundColor = ((cpu.ProcessorStatus & flagValue) > 0) ? ConsoleColor.Green : ConsoleColor.Red;
                Console.Write(flagName);
                Console.ForegroundColor = ConsoleColor.Gray;
                Console.Write((i + 1) < flags.Length ? " | " : "\r\n");
            }
        }
예제 #17
0
 public VByte Set(IndexingRegister reg)
 {
     if (Index != null && Index == reg)
     {
         throw new NotImplementedException();
     }
     if (reg is RegisterX)
     {
         CPU6502.STX(this);
     }
     else
     {
         CPU6502.STY(this);
     }
     return(this);
 }
예제 #18
0
파일: NES.cs 프로젝트: hmahal/NESharp
        /// <summary>
        /// Contructor for the NES console object. Uses Dependency Injection to create components.
        /// Mainly used for testing in this form.
        /// </summary>
        public NES()
        {
            Cart = new Cartridge();
            const string FileName = @"C:\Users\panda\Downloads\Super Mario Bros. 3 (USA).nes";
            Input        input1   = new Input();
            Input        input2   = new Input();

            ppu    = PPU.Instance;
            Cart   = Cart.getCart(FileName);
            Mapper = new MMC3(Cart);
            //Create and pass the mapper to the memory
            Memory.Create(2048, Mapper, input1, input2);
            RAM = Memory.Instance;
            //Pass the memory to the CPU & PPU
            CPU6502.Create(RAM);
            CPU = CPU6502.Instance;
        }
예제 #19
0
 public ReplHost(
     ILabelMap labels,
     CancellationTokenWrapper cancellationToken,
     // CpuHoldEvent debuggerSyncEvent,
     IDebuggableCpu cpu,
     IAddressMap addressMap,
     IMemoryMappedKeyboard keyboard,
     IMemoryMappedDisplay memoryMappedDisplay)
 {
     Labels             = labels;
     _cancellationToken = cancellationToken;
     // _debuggerSyncEvent = debuggerSyncEvent;
     _cpu      = (CPU6502)cpu;
     mem       = addressMap;
     _keyboard = keyboard;
     _display  = memoryMappedDisplay;
 }
예제 #20
0
 private RegisterY LDY(IOperand o)
 {
     if (o is RegisterA)
     {
         CPU6502.TAY();
     }
     else if (o is RegisterX)
     {
         CPU6502.TXA();
         CPU6502.TAY();
     }
     else
     {
         CPU6502.LDY(o);
     }
     return(this);
 }
예제 #21
0
 public RegisterX Set(IOperand o)
 {
     if (o is RegisterA)
     {
         CPU6502.TAX();
     }
     else if (o is RegisterY)
     {
         CPU6502.TYA();
         CPU6502.TAX();
     }
     else
     {
         CPU6502.LDX(o);
     }
     return(this);
 }
예제 #22
0
        static void Main(string[] args)
        {
            var bus       = new Bus();
            var cpu       = new CPU6502();
            var cartridge = new Cartridge("nestest.nes");

            //var cartridge = new Cartridge("Super Mario Bros.nes");

            bus.InsertCartridge(cartridge);

            var asm = bus._cpu.Disassemble(0x0000, 0xFFFF);

            bus._cpu.Reset();


            // var ss =  "A2 0A 8E 00 00 A2 03 8E 01 00 AC 00 00 A9 00 18 6D 01 00 88 D0 FA 8D 02 00 EA EA EA";
            // ushort nOffset = 0x8000;
            //
            // for (var i = 0; i < ss.Length -1; i += 3)
            // {
            //
            //     var temp = "0x"+ ss[i] + ss[i + 1];
            //    var b = (byte) Convert.ToInt32(temp, 16);
            //    bus.CpuRam[nOffset] = b;
            //    Console.WriteLine(temp);
            //    Console.WriteLine(b);
            //    Console.WriteLine(nOffset);
            //    Console.WriteLine(bus.CpuRam[nOffset]);
            //    nOffset++;
            // }
            //


            // var asm = bus._cpu.Disassemble(0x0000, 0xFFFF);
            //bus._cpu.Reset();

            while (true)
            {
                do
                {
                    bus._cpu.Clock();
                } while (!bus._cpu.Complete());
            }
        }
예제 #23
0
        public static T Module <T>(T obj)
        {
            Module(obj.GetType());             //add all static methods from this type

            //TODO: Each of these should change a context, so all classes within a bank can fill up "code sections", "subs" etc,
            //then they can be written all at once.
            var methods = obj.GetType().GetMethods(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance);

            foreach (var m in methods.WithAttribute <Dependencies>().Select(x => x.method))
            {
                AL.Reset();
                m.Invoke(obj, null);
            }
            foreach (var m in methods.WithAttribute <DataSection>().Select(x => x.method))
            {
                AL.Reset();
                Context.Write(m.ToLabel());
                m.Invoke(obj, null);
            }
            foreach (var m in methods.WithAttribute <CodeSection>().Select(x => x.method))
            {
                AL.Reset();
                Context.Write(m.ToLabel());
                m.Invoke(obj, null);
            }
            foreach (var m in methods.WithAttribute <Subroutine>().Select(x => x.method))
            {
                //TODO: store all of these labels along with their bank ID in a structure to allow for bank-switch calls.
                //Regular calls and bank-switch calls should be stored as object instances, so they can be expanded by the compiler!
                AL.Reset();
                Context.Write(m.ToLabel());
                m.Invoke(obj, null);
                AL.Return();
            }
            foreach (var m in methods.WithAttribute <Interrupt>().Select(x => x.method))
            {
                AL.Reset();
                Context.Write(m.ToLabel());
                m.Invoke(obj, null);
                CPU6502.RTI();
            }
            return(obj);
        }
예제 #24
0
 public static void Restore(RegisterBase reg)
 {
     if (reg is RegisterA)
     {
         CPU6502.PLA();
         A.State.Pop();
     }
     else if (reg is RegisterX)
     {
         CPU6502.PLA();
         X.Set(A);
         X.State.Pop();
     }
     else if (reg is RegisterY)
     {
         CPU6502.PLA();
         Y.Set(A);
         Y.State.Pop();
     }
 }
예제 #25
0
 public RegisterA Set(IOperand operand)
 {
     if (operand is RegisterA)
     {
         return(this);                                                //do nothing, this should be okay to support IOperands this way //throw new Exception("Attempting to set A to A");
     }
     else if (operand is RegisterX)
     {
         CPU6502.TXA();
     }
     else if (operand is RegisterY)
     {
         CPU6502.TYA();
     }
     else
     {
         CPU6502.LDA(operand);
     }
     return(this);
 }
예제 #26
0
        //For reference:
        //(byte)(-128)==(byte)0x80
        //(byte)(127)==(byte)0x7F

        //TODO: implement AL.LastUsedRegister for determining if a CMP is still needed before a branch operation
        public void While(Func <Condition> condition)
        {
            //An outer context to account for conditions that output some code
            Context.Write(_labels.ContinueLabel);
            Context.New(() => {
                _block?.Invoke(_labels);
                var c   = condition.Invoke();
                var len = -Context.Length - 2;                 //-2 is to account for the branch instruction
                if (len >= LOWEST_BRANCH_VAL)
                {
                    Branch(c, len);
                }
                else
                {
                    Branch(c, CPU6502.Asm.OC["JMP"][CPU6502.Asm.Mode.Absolute].Length, true);
                    CPU6502.JMP(Context.StartLabel);
                }
            });
            Context.Write(_labels.BreakLabel);
        }
예제 #27
0
        public void Reset()
        {
            NES.IRQ.Disable();
            CPU6502.CLD();
            NES.APU.FrameCounter.Set(0x40);
            Stack.Reset();
            NES.PPU.Control.Set(0);
            NES.PPU.Mask.Set(0);
            NES.APU.DMC.Disable();
            //NES.APU.SetChannelsEnabled(NES.APU.Channels.DMC | NES.APU.Channels.Pulse1);

            Hardware.WaitForVBlank();
            Hardware.ClearRAM();
            Hardware.WaitForVBlank();

            ////TODO: move this to title, along with datasection
            //Comment("Load palettes");
            //Hardware.LoadPalettes(Palettes);

            Module <SceneManager>().Load(Module <Scenes.Title>());
            Hardware.WaitForVBlank();
            NES.PPU.Control.Set(NES.PPU.LazyControl);
            NES.PPU.Mask.Set(NES.PPU.LazyMask);
            ScrollUtil.Update();
            Loop.Infinite(_ => {
                Comment("Main Loop");

                Module <Gamepads>().Update();

                Module <SceneManager>().Step();

                A.Set(nmiCount);
                Loop.Do_old().While(() => nmiCount.Equals(A));

                Module <SceneManager>().CheckLoadNeeded();

                //Set shadow OAM address
                NES.PPU.OAM.Address.Set(0x00);                  //low byte of RAM address
                NES.PPU.OAM.DMA.Set(0x02);                      //high byte of RAM address
            });
        }
예제 #28
0
 public Address Set(IOperand operand)
 {
     //These must be in here for things like generic IndexingRegister refs, which wouldn't get picked up by Set(RegisterX/Y)
     if (operand is RegisterA)
     {
         A.STA(this);
     }
     else if (operand is RegisterX)
     {
         CPU6502.STX(this);
     }
     else if (operand is RegisterY)
     {
         CPU6502.STY(this);
     }
     else
     {
         A.Set(operand).STA(this);
     }
     return(this);
 }
예제 #29
0
 public static void Backup(RegisterBase reg)
 {
     if (reg is RegisterA)
     {
         CPU6502.PHA();
         A.State.Push();
     }
     else if (reg is RegisterX)
     {
         CPU6502.TXA();
         //Use(Asm.TXA);
         CPU6502.PHA();
         X.State.Push();
     }
     else if (reg is RegisterY)
     {
         CPU6502.TYA();
         //Use(Asm.TYA);
         CPU6502.PHA();
         Y.State.Push();
     }
 }
예제 #30
0
 public static void Restore(Register registers = Register.All, bool statusFlags = false)
 {
     if (registers.HasFlag(Register.Y))
     {
         CPU6502.PLA();
         Y.Set(A);
         Y.State.Pop();
     }
     if (registers.HasFlag(Register.X))
     {
         CPU6502.PLA();
         X.Set(A);
         X.State.Pop();
     }
     if (registers.HasFlag(Register.A))
     {
         CPU6502.PLA();
         A.State.Pop();
     }
     if (statusFlags)
     {
         CPU6502.PLP();
     }
 }