public void LoadTo(NES nes) { nes.SetMapper(this.Mapper); nes.ppu.SetMapper(this.Mapper); nes.cpu.SetMapper(this.Mapper); this.fs.Close(); }
public Visual(NES nes) { InitializeComponent(); this.ClientSize = new Size((int)(scale * width), (int)(scale * height + MenuStripHeight)); this.nes = nes; this.rawBitmap = nes.display; // disable resizing this.FormBorderStyle = FormBorderStyle.FixedSingle; this.MinimizeBox = false; this.MaximizeBox = false; this.SetStyle( ControlStyles.UserPaint | ControlStyles.AllPaintingInWmPaint | ControlStyles.DoubleBuffer, true ); this.Text = "NES Emulator"; System.Windows.Forms.Timer timer = new System.Windows.Forms.Timer(); timer.Interval = 17; timer.Tick += new EventHandler(Tick); timer.Start(); MenuStrip ms = new MenuStrip(); ToolStripMenuItem GameMenu = new ToolStripMenuItem("Game"); ToolStripMenuItem GameOpenItem = new ToolStripMenuItem("Open", null, new EventHandler(LoadGame)); ToolStripMenuItem GameDebugItem = new ToolStripMenuItem("Debug", null, new EventHandler(OpenDebug)); GameMenu.DropDownItems.Add(GameOpenItem); GameMenu.DropDownItems.Add(GameDebugItem); ((ToolStripDropDownMenu)(GameMenu.DropDown)).ShowImageMargin = false; ((ToolStripDropDownMenu)(GameMenu.DropDown)).ShowCheckMargin = false; // Assign the ToolStripMenuItem that displays // the list of child forms. ms.MdiWindowListItem = GameMenu; // Add the window ToolStripMenuItem to the MenuStrip. ms.Items.Add(GameMenu); // Dock the MenuStrip to the top of the form. ms.Dock = DockStyle.Top; // The Form.MainMenuStrip property determines the merge target. this.MainMenuStrip = ms; // Add the MenuStrip last. // This is important for correct placement in the z-order. this.Controls.Add(ms); this.Load += new EventHandler(Visual_CreateBackBuffer); this.Paint += new PaintEventHandler(Visual_Paint); this.KeyDown += new KeyEventHandler(Visual_KeyDown); }
public APU(NES nes) { this.pulse1 = new Pulse(amplitude); this.pulse2 = new Pulse(amplitude); this.noise = new Noise(amplitude); this.triangle = new Triangle(amplitude); this.dmc = new DMC(amplitude, nes); this.nes = nes; }
static void Main() { int[] rawBitmap = new int[0x100 * 0xf0 * 3]; NES nes = new NES(rawBitmap); Application.EnableVisualStyles(); Application.SetCompatibleTextRenderingDefault(false); Visual vis = new Visual(nes); Application.Run(vis); }
public void UpdateVisual(NES nes) { if (nes.ppu == null) { return; } else if (nes.ppu.Mapper == null) { return; } int i, j; // Copy Spritetables byte lower, upper; bool changed; for (i = 0; i < 2; i++) { // Check if updating spritetable is necessary changed = false; for (int SampleY = 0; SampleY < 0x10; SampleY++) { for (int SampleX = 0; SampleX < 0x10; SampleX++) { lower = (byte)(nes.ppu[(i * 0x1000) + (SampleY * 0x100) + (SampleX * 0x10) + 4] >> 4); upper = (byte)(nes.ppu[(i * 0x1000) + (SampleY * 0x100) + (SampleX * 0x10) + 4 + 8] >> 4); if (this.PatternTablesRaw[i][(8 * SampleX + 3) + 128 * (8 * SampleY + 4)] != PPU.palette[nes.ppu[0x3f00 | (PaletteSelected << 2) | 2 * (upper & 0x01) | (lower & 0x01)] & 0x3f]) { changed = true; break; } } if (changed) { break; } } if (!changed) { continue; } for (int SpriteTableTileY = 0; SpriteTableTileY < 0x10; SpriteTableTileY++) { for (int SpriteTableTileX = 0; SpriteTableTileX < 0x10; SpriteTableTileX++) { for (int row = 0; row < 8; row++) { lower = nes.ppu[(i * 0x1000) + (SpriteTableTileY * 0x100) + (SpriteTableTileX * 0x10) + row]; upper = nes.ppu[(i * 0x1000) + (SpriteTableTileY * 0x100) + (SpriteTableTileX * 0x10) + row + 8]; for (byte bit = 0; bit < 8; bit++) { this.PatternTablesRaw[i][(8 * SpriteTableTileX + (7 - bit)) + 128 * (8 * SpriteTableTileY + row)] = PPU.palette[nes.ppu[0x3f00 | (PaletteSelected << 2) | 2 * (upper & 0x01) | (lower & 0x01)] & 0x3f]; upper >>= 1; lower >>= 1; } } } } if (i == 0) { this.PatternTable0Bmp?.Dispose(); rawBitmap = GCHandle.Alloc(this.PatternTablesRaw[0], GCHandleType.Pinned); this.PatternTable0Bmp = new Bitmap(128, 128, 128 * 4, PixelFormat.Format32bppRgb, rawBitmap.AddrOfPinnedObject()); this.PatternTable0.Image = PatternTable0Bmp; rawBitmap.Free(); } else { this.PatternTable1Bmp?.Dispose(); rawBitmap = GCHandle.Alloc(this.PatternTablesRaw[1], GCHandleType.Pinned); this.PatternTable1Bmp = new Bitmap(128, 128, 128 * 4, PixelFormat.Format32bppRgb, rawBitmap.AddrOfPinnedObject()); this.PatternTable1.Image = PatternTable1Bmp; rawBitmap.Free(); } } // Copy Palette for (i = 0; i < 8; i++) { changed = false; for (j = 0; j < 4; j++) { if (this.PalettesRaw[i][j] != PPU.palette[nes.ppu[0x3f00 | (i << 2) | j] & 0x3f]) { this.PalettesRaw[i][j] = PPU.palette[nes.ppu[0x3f00 | (i << 2) | j] & 0x3f]; changed = true; } } if (!changed) { continue; } Graphics g = Graphics.FromImage(this.Palettes[i]); g.Clear(Color.White); for (j = 0; j < 4; j++) { g.FillRectangle(new SolidBrush(Color.FromArgb((int)(this.PalettesRaw[i][j] | 0xff00_0000))), 31 * j, 0, 31, 31); } this.PaletteBoxes[i].Image = this.Palettes[i]; } // Copy OAM StringBuilder sb = new StringBuilder(64 * 23); for (i = 0; i < 64; i++) { sb.AppendLine(string.Format("{0:d2}: Y:{1:x2} T:{2:x2} A:{3:x2} X:{4:x2}", i, nes.ppu.oam[4 * i], nes.ppu.oam[4 * i + 1], nes.ppu.oam[4 * i + 2], nes.ppu.oam[4 * i + 3])); } this.OAMText.Text = sb.ToString(); // Update CPU values this.AContent.Text = nes.cpu.ac.ToString("X2"); this.XContent.Text = nes.cpu.x.ToString("X2"); this.YContent.Text = nes.cpu.y.ToString("X2"); this.PCContent.Text = nes.cpu.getPc().ToString("X4"); this.NFlag.ForeColor = nes.cpu.getFlag('N') == 1 ? Color.Green : Color.Red; this.VFlag.ForeColor = nes.cpu.getFlag('V') == 1 ? Color.Green : Color.Red; this.BFlag.ForeColor = nes.cpu.getFlag('B') == 1 ? Color.Green : Color.Red; this.IFlag.ForeColor = nes.cpu.getFlag('I') == 1 ? Color.Green : Color.Red; this.ZFlag.ForeColor = nes.cpu.getFlag('Z') == 1 ? Color.Green : Color.Red; this.CFlag.ForeColor = nes.cpu.getFlag('C') == 1 ? Color.Green : Color.Red; }
public CPU(NES nes) { // initialize memory this.nes = nes; this.storage = new byte[0x4020]; // memory map from https://wiki.nesdev.com/w/index.php/CPU_memory_map this.pc = new byte[2]; this.pc[0] = new byte(); this.pc[1] = new byte(); this.ac = 0; this.x = 0; this.y = 0; this.sr = 0x24; this.sp = 0x00; this.cycle = 0; // load opcodes string opcodeJson = File.ReadAllText("../../data/AllOpcodes.json"); Dictionary <string, string> opcodes = JsonConvert.DeserializeObject <Dictionary <string, string> >(opcodeJson); this.instructions = new InstructionCaller[0x100]; foreach (KeyValuePair <string, string> entry in opcodes) { string[] instructionString = entry.Value.Split(' '); Func <InstructionMode, int> instruction; switch (instructionString[0]) { case "ADC": instruction = this.ADC; break; case "ALR": instruction = this.ALR; break; case "AND": instruction = this.AND; break; case "ARR": instruction = this.ARR; break; case "ASL": instruction = this.ASL; break; case "BCC": instruction = this.BCC; break; case "BCS": instruction = this.BCS; break; case "BEQ": instruction = this.BEQ; break; case "BIT": instruction = this.BIT; break; case "BMI": instruction = this.BMI; break; case "BNE": instruction = this.BNE; break; case "BPL": instruction = this.BPL; break; case "BRK": instruction = this.BRK; break; case "BVC": instruction = this.BVC; break; case "BVS": instruction = this.BVS; break; case "CLC": instruction = this.CLC; break; case "CLD": instruction = this.CLD; break; case "CLI": instruction = this.CLI; break; case "CLV": instruction = this.CLV; break; case "CMP": instruction = this.CMP; break; case "CPX": instruction = this.CPX; break; case "CPY": instruction = this.CPY; break; case "DCP": instruction = this.DCP; break; case "DEC": instruction = this.DEC; break; case "DEX": instruction = this.DEX; break; case "DEY": instruction = this.DEY; break; case "EOR": instruction = this.EOR; break; case "INC": instruction = this.INC; break; case "INX": instruction = this.INX; break; case "INY": instruction = this.INY; break; case "ISC": instruction = this.ISC; break; case "LAX": instruction = this.LAX; break; case "LDA": instruction = this.LDA; break; case "LDX": instruction = this.LDX; break; case "LDY": instruction = this.LDY; break; case "LSR": instruction = this.LSR; break; case "NOP": instruction = this.NOP; break; case "ORA": instruction = this.ORA; break; case "PHA": instruction = this.PHA; break; case "PHP": instruction = this.PHP; break; case "PLA": instruction = this.PLA; break; case "PLP": instruction = this.PLP; break; case "RLA": instruction = this.RLA; break; case "ROL": instruction = this.ROL; break; case "ROR": instruction = this.ROR; break; case "RRA": instruction = this.RRA; break; case "RTI": instruction = this.RTI; break; case "RTS": instruction = this.RTS; break; case "SAX": instruction = this.SAX; break; case "SBC": instruction = this.SBC; break; case "SEC": instruction = this.SEC; break; case "SED": instruction = this.SED; break; case "SEI": instruction = this.SEI; break; case "SLO": instruction = this.SLO; break; case "SRE": instruction = this.SRE; break; case "STA": instruction = this.STA; break; case "STX": instruction = this.STX; break; case "STY": instruction = this.STY; break; case "TAX": instruction = this.TAX; break; case "TAY": instruction = this.TAY; break; case "TSX": instruction = this.TSX; break; case "TXA": instruction = this.TXA; break; case "TXS": instruction = this.TXS; break; case "TYA": instruction = this.TYA; break; case "XAA": instruction = this.XAA; break; case "JSR": instruction = this.JSR; break; case "JMP": instruction = this.JMP; break; default: throw new Exception("Unknown instruction: " + instructionString[0]); } InstructionMode mode; switch (instructionString[1]) { case "A": mode = InstructionMode.A; break; case "abs": mode = InstructionMode.abs; break; case "abs,X": mode = InstructionMode.absX; break; case "abs,Y": mode = InstructionMode.absY; break; case "#": mode = InstructionMode.imm; break; case "impl": mode = InstructionMode.impl; break; case "ind": mode = InstructionMode.ind; break; case "X,ind": mode = InstructionMode.Xind; break; case "ind,Y": mode = InstructionMode.indY; break; case "rel": mode = InstructionMode.rel; break; case "zpg": mode = InstructionMode.zpg; break; case "zpg,X": mode = InstructionMode.zpgX; break; case "zpg,Y": mode = InstructionMode.zpgY; break; default: throw new Exception("Unknown mode: " + instructionString[1]); } if (instruction != null) { this.instructions[int.Parse(entry.Key, NumberStyles.HexNumber)] = new InstructionCaller(instruction, mode); } } }