Beispiel #1
0
 public void LoadTo(NES nes)
 {
     nes.SetMapper(this.Mapper);
     nes.ppu.SetMapper(this.Mapper);
     nes.cpu.SetMapper(this.Mapper);
     this.fs.Close();
 }
Beispiel #2
0
        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);
        }
Beispiel #3
0
        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;
        }
Beispiel #4
0
        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);
        }
Beispiel #5
0
        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;
        }
Beispiel #6
0
        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);
                }
            }
        }