/// <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; }
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(); }
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(); }
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(); } }
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); }
public Condition Equals(U8 v) { if (v != 0 || Flags.Zero.LastReg != this) { CPU6502.CPX(v); } return(Condition.EqualsZero); }
public VByte SetASL() { if (Index is RegisterY) { throw new Exception("Cannot SetASL with index Y"); } CPU6502.ASL(this); return(this); }
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)); });
public IndexingRegister Inc() { if (this is RegisterX) { CPU6502.INX(); } else { CPU6502.INY(); } return(this); }
public IndexingRegister Dec() { if (this is RegisterX) { CPU6502.DEX(); } else { CPU6502.DEY(); } return(this); }
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; } }
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]); }); }
/// <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); }
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; } }
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"); } }
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); }
/// <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; }
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; }
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); }
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); }
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()); } }
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); }
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(); } }
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); }
//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); }
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 }); }
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); }
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(); } }
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(); } }