Example #1
0
        private void DispatchOpcode(ParsedOpCode parsedOpCode)
        {
            switch (parsedOpCode.Instruction)
            {
            case 0x0:
                // 0xE0 Clear Display
                if (parsedOpCode.NN == 0xE0)
                {
                    DisplayModel.Clear();
                }
                // 0xEE Return from Subroutine
                else if (parsedOpCode.NN == 0xEE)
                {
                    CPU.Ret();
                }
                break;

            case 0x01:
                // 0x1NNN Jump to address NNN
                CPU.Jump(parsedOpCode.NNN);
                break;

            case 0x02:
                // 0x2NNN Execute subroutine at address NNN
                CPU.Subroutine(parsedOpCode.NNN);
                break;

            case 0x03:
                // 0x3XNN Skip the next instruction if regoster VX == NN
                CPU.SkipIfEqual(parsedOpCode.X, parsedOpCode.NN);
                break;

            case 0x04:
                // 0x4XNN Skip the next instruction if register VX != NN
                CPU.SkipIfNotEqual(parsedOpCode.X, parsedOpCode.NN);
                break;

            case 0x05:
                // 0x5XY0 Skip the next instruction if register VX == VY
                CPU.SkipIfXEqY(parsedOpCode.X, parsedOpCode.Y);
                break;

            case 0x06:
                // 0x6XNN Store the number NN in register VX
                CPU.StoreInRegister(parsedOpCode.X, parsedOpCode.NN);
                break;

            case 0x07:
                // 0x7XNN Add the number NN to register VX
                CPU.AddToRegister(parsedOpCode.X, parsedOpCode.NN);
                break;

            case 0x08:
                // Handle opcodes starting with 0x08 in a separate function
                Dispatch0x08(parsedOpCode);
                break;

            case 0x09:
                // 0x9XY0 Skip the next instruction if register VX != VY
                if (parsedOpCode.N == 0)
                {
                    CPU.SkipNextInstructionIfVXneVY(parsedOpCode.X, parsedOpCode.Y);
                }
                break;

            case 0x0A:
                // 0xANNN Store memeory at address NNN in register I
                CPU.Index = parsedOpCode.NNN;
                break;

            case 0x0B:
                // 0xBNNN Jump to address NNN plus V0
                CPU.JumpToAddressPlusV0(parsedOpCode.NNN);
                break;

            case 0x0C:
                // 0xCXNN Set VX to a random number with a mask of NN
                byte number = (byte)(random.Next(parsedOpCode.NN));
                CPU.V[parsedOpCode.X] = number;
                break;

            case 0x0D:
                // 0xDXYN Draw sprite at position VX, VY with N bytes of data at the address stored in I
                // Set VF to 1 if any set pixels become unset. Set VF to 0 otherwise.
                var unsetPixels = DisplayModel.DrawSprite(CPU.V[parsedOpCode.X], CPU.V[parsedOpCode.Y], Memory, CPU.Index, parsedOpCode.N);
                CPU.V[0x0F] = (byte)(unsetPixels ? 1 : 0);
                break;

            case 0x0E:
                // Handle opcodes begining with 0xE
                Dispatch0x0E(parsedOpCode);
                break;

            case 0x0F:
                // Handle opcodes begining with 0xF
                Dispatch0x0F(parsedOpCode);
                break;
            }
        }
Example #2
0
        static void Main(string[] args)
        {
            if (SDL.SDL_Init(SDL.SDL_INIT_EVERYTHING) < 0)
            {
                Console.WriteLine("SDL failed to init.");
                return;
            }

            IntPtr window = SDL.SDL_CreateWindow("Chip-8 Interpreter", 128, 128, 64 * 8, 32 * 8, 0);

            if (window == IntPtr.Zero)
            {
                Console.WriteLine("SDL could not create a window.");
                return;
            }

            IntPtr renderer = SDL.SDL_CreateRenderer(window, -1, SDL.SDL_RendererFlags.SDL_RENDERER_ACCELERATED);

            if (renderer == IntPtr.Zero)
            {
                Console.WriteLine("SDL could not create a valid renderer.");
                return;
            }

            CPU cpu = new CPU();

            using (BinaryReader reader = new BinaryReader(new FileStream("../../spaceInvaders.ch8", FileMode.Open)))
            {
                List <byte> program = new List <byte>();

                while (reader.BaseStream.Position < reader.BaseStream.Length)
                {
                    program.Add(reader.ReadByte());
                }

                cpu.LoadProgram(program.ToArray());
            }

            SDL.SDL_Event sdlEvent;
            bool          running = true;

            int sample      = 0;
            int beepSamples = 0;

            SDL.SDL_AudioSpec audioSpec = new SDL.SDL_AudioSpec();
            audioSpec.channels = 1;
            audioSpec.freq     = 44100;
            audioSpec.samples  = 256;
            audioSpec.format   = SDL.AUDIO_S8;
            audioSpec.callback = new SDL.SDL_AudioCallback((userdata, stream, length) =>
            {
                if (cpu == null)
                {
                    return;
                }

                sbyte[] waveData = new sbyte[length];

                for (int i = 0; i < waveData.Length && cpu.SoundTimer > 0; i++, beepSamples++)
                {
                    if (beepSamples == 730)
                    {
                        beepSamples = 0;
                        cpu.SoundTimer--;
                    }

                    waveData[i] = (sbyte)(127 * Math.Sin(sample * Math.PI * 2 * 604.1 / 44100));
                    sample++;
                }

                byte[] byteData = (byte[])(Array)waveData;

                Marshal.Copy(byteData, 0, stream, byteData.Length);
            });

            SDL.SDL_OpenAudio(ref audioSpec, IntPtr.Zero);
            SDL.SDL_PauseAudio(0);

            IntPtr    sdlSurface, sdlTexture = IntPtr.Zero;
            Stopwatch frameTimer   = Stopwatch.StartNew();
            int       ticksPer60hz = (int)(Stopwatch.Frequency * 0.016);

            while (running)
            {
                try
                {
                    if (!cpu.WaitingForKeyPress)
                    {
                        cpu.Step();
                    }

                    if (frameTimer.ElapsedTicks > ticksPer60hz)
                    {
                        while (SDL.SDL_PollEvent(out sdlEvent) != 0)
                        {
                            if (sdlEvent.type == SDL.SDL_EventType.SDL_QUIT)
                            {
                                running = false;
                            }
                            else if (sdlEvent.type == SDL.SDL_EventType.SDL_KEYDOWN)
                            {
                                var key = KeyCodeToKey((int)sdlEvent.key.keysym.sym);
                                cpu.Keyboard |= (ushort)(1 << key);

                                if (cpu.WaitingForKeyPress)
                                {
                                    cpu.KeyPressed((byte)key);
                                }
                            }
                            else if (sdlEvent.type == SDL.SDL_EventType.SDL_KEYUP)
                            {
                                var key = KeyCodeToKey((int)sdlEvent.key.keysym.sym);
                                cpu.Keyboard &= (ushort)~(1 << key);
                            }
                        }

                        var displayHandle = GCHandle.Alloc(cpu.Display, GCHandleType.Pinned);

                        if (sdlTexture != IntPtr.Zero)
                        {
                            SDL.SDL_DestroyTexture(sdlTexture);
                        }

                        sdlSurface = SDL.SDL_CreateRGBSurfaceFrom(displayHandle.AddrOfPinnedObject(), 64, 32, 32, 64 * 4, 0x000000ff, 0x0000ff00, 0x00ff0000, 0xff000000);
                        sdlTexture = SDL.SDL_CreateTextureFromSurface(renderer, sdlSurface);

                        displayHandle.Free();

                        SDL.SDL_RenderClear(renderer);
                        SDL.SDL_RenderCopy(renderer, sdlTexture, IntPtr.Zero, IntPtr.Zero);
                        SDL.SDL_RenderPresent(renderer);

                        frameTimer.Restart();
                    }

                    Thread.Sleep(1);
                }
                catch (Exception e)
                {
                    Console.WriteLine(e.Message);
                }
            }

            SDL.SDL_DestroyRenderer(renderer);
            SDL.SDL_DestroyWindow(window);
        }