Example #1
0
        public void _2nnn_CALL()
        {
            var instructions = new byte[]
            {
                0x21,
                0xEF
            };

            var expectedAddress = (ushort)(0x21EF & 0x0FFF);

            var stackModule = new StackModule();

            var chip = CHIP8Factory.GetChip8(stack: stackModule);

            chip.LoadProgram(instructions);

            chip.Tick += (c,
                          e) =>
            {
                chip.Stop();
            };

            chip.Start();

            var programCounter = GetProgramCounter(chip);

            Assert.Equal(expectedAddress,
                         programCounter);

            var itemOnStack = stackModule.Pop();

            // Stack should have the program counter which has only moved up one past the start at 512
            Assert.Equal(514,
                         itemOnStack);
        }
Example #2
0
        public void _8xy3_XOR_vx_vy(byte x,
                                    byte y)
        {
            /*
             * 8xy3 - Performs a bitwise exclusive OR on the values of Vx and Vy, then stores the result in Vx.
             */
            var registers = new RegisterModule();

            var emulator = CHIP8Factory.GetChip8(registers: registers);

            var instructions = new byte[]
            {
                0x60,                    //LD v0 with x,
                x,
                0x61,                    //LD v1 with y
                y,
                0x80,                    //Bitwise xor, store in v0
                0x13
            };

            emulator.LoadProgram(instructions);

            emulator.Start();

            var expectedResult = x ^ y;

            Assert.Equal(expectedResult,
                         registers.GetGeneralValue(0));
        }
Example #3
0
        public void _1nnn_JP()
        {
            var instructions = new byte[]
            {
                0x11,
                0xEF
            };

            var expectedAddress = (ushort)(0x11EF & 0x0FFF);

            var chip = CHIP8Factory.GetChip8();

            chip.LoadProgram(instructions);

            chip.Tick += (c,
                          e) =>
            {
                chip.Stop();
            };

            chip.Start();

            var programCounter = GetProgramCounter(chip);

            Assert.Equal(expectedAddress,
                         programCounter);
        }
Example #4
0
        public void _Bnnn_JP_v0_addr()
        {
            var registers = new RegisterModule();

            registers.SetGeneralValue(0,
                                      0x12);

            var emulator = CHIP8Factory.GetChip8(registers: registers);

            var instructions = new byte[]
            {
                0xB1,
                0x23
            };

            emulator.LoadProgram(instructions);

            emulator.Tick += (e,
                              a) =>
            {
                emulator.Stop();
            };

            emulator.Start();

            Assert.Equal(0x123 + 0x12,
                         GetProgramCounter(emulator));
        }
Example #5
0
        public void _00EE_RET(ushort addr)
        {
            // Make sure it's a valid address and doesn't cause an infinite loop
            Assert.InRange(addr,
                           514,
                           4094);

            var stackModule = new StackModule();

            stackModule.Push(addr);

            var instructions = new byte[]
            {
                0x00,
                0xEE
            };

            var chip = CHIP8Factory.GetChip8(stack: stackModule);

            chip.LoadProgram(instructions);

            chip.Tick += (c,
                          e) =>
            {
                chip.Stop();
            };

            chip.Start();

            var programCounter = GetProgramCounter(chip);

            Assert.Equal(addr,
                         programCounter);
        }
Example #6
0
        public void _Fx1E_add_I_Vx()
        {
            var registers = new RegisterModule();

            registers.SetGeneralValue(0,
                                      0x12);

            registers.SetI(0x123);

            var emulator = CHIP8Factory.GetChip8(registers: registers);

            var instructions = new byte[]
            {
                0xF0,                    //Add v0 and I, store in I
                0x1E
            };

            emulator.LoadProgram(instructions);

            emulator.Tick += (e,
                              a) =>
            {
                emulator.Stop();
            };

            emulator.Start();

            Assert.Equal(0x123 + 0x12,
                         registers.GetI());
        }
Example #7
0
        public MainWindow()
        {
            displayDictionary = new Dictionary <Point, Rectangle>();

            for (var x = 0; x < 64; x++)
            {
                for (var y = 0; y < 32; y++)
                {
                    var point = new Point(x,
                                          y);

                    displayDictionary[point] = null;
                }
            }

            var registers = new RegisterModule();

            emulator = CHIP8Factory.GetChip8(DisplayEmulatorScreen,
                                             registers,
                                             new StackModule(),
                                             new MemoryModule(Enumerable.Repeat <byte>(0x0,
                                                                                       4096)));

            emulator.ToneOn  += this.ToneOn;
            emulator.ToneOff += this.ToneOff;

            var bytes = File.ReadAllBytes("pong.ch8");

            emulator.LoadProgram(bytes);

            InitializeComponent();

            this.KeyDown += MainWindow_KeyDown;
            this.KeyUp   += MainWindow_KeyUp;
        }
Example #8
0
        public void _Cxkk_RND_vx_byte(byte kk,
                                      byte rand)
        {
            var registers = new RegisterModule();

            var random = new TestRandom(rand);


            var emulator = CHIP8Factory.GetChip8(registers: registers,
                                                 random: random);

            var instructions = new byte[]
            {
                0xC0,                    //Set v0 = kk & random byte
                kk
            };

            emulator.LoadProgram(instructions);

            emulator.Tick += (e,
                              a) =>
            {
                emulator.Stop();
            };

            emulator.Start();

            Assert.Equal(rand & kk,
                         registers.GetGeneralValue(0));
        }
Example #9
0
        public void _Fx33_LD_B_Vx()
        {
            /*
             * Stores the BCD of vx in I, I+1, and I+2 of memory
             * 125:
             * Hex: 0x7D
             * BCD: 0001 0010 0101
             */

            var registers = new RegisterModule();

            registers.SetGeneralValue(0,
                                      0x7D);

            registers.SetI(0x123);

            var memory = new MemoryModule(Enumerable.Repeat((byte)0x0,
                                                            4096));

            var emulator = CHIP8Factory.GetChip8(registers: registers,
                                                 mem: memory);

            var instructions = new byte[]
            {
                0xF0,                    //Store BCD of v0 in memory
                0x33
            };

            emulator.LoadProgram(instructions);

            emulator.Tick += (e,
                              a) =>
            {
                emulator.Stop();
            };

            emulator.Start();

            var startPoint = registers.GetI();

            var hundreds = memory[startPoint];

            startPoint++;

            var tens = memory[startPoint];

            startPoint++;

            var ones = memory[startPoint];

            Assert.Equal(0x1,
                         hundreds);

            Assert.Equal(0x2,
                         tens);

            Assert.Equal(0x5,
                         ones);
        }
Example #10
0
        public void Correctly_Clears_Display_CLS()
        {
            var registers = new RegisterModule();

            bool[,] display = null;

            Task WriteDisplay(bool[,] values)
            {
                display = values;
                return(Task.CompletedTask);
            }

            var emulator = CHIP8Factory.GetChip8(WriteDisplay,
                                                 registers);

            registers.SetGeneralValue(0,
                                      0x0);

            var instructions = new byte[]
            {
                /* Load location of sprite for '0' to I */
                0xF0,
                0x29,
                /* Draw 5 byte sized sprite at 0,0 */
                0xD0,
                0x05,
                /* Clear screen */
                0x00,
                0xE0
            };

            emulator.LoadProgram(instructions);

            emulator.Start();

            Assert.NotNull(display);

            for (var x = 0; x < display.GetLength(0); x++)
            {
                for (var y = 0; y < display.GetLength(1); y++)
                {
                    Assert.False(display[x,
                                         y]);
                }
            }
        }
Example #11
0
        public void _Annn_LD_I_addr()
        {
            var registers = new RegisterModule();

            var emulator = CHIP8Factory.GetChip8(registers: registers);

            var instructions = new byte[]
            {
                0xA1,
                0x23
            };

            emulator.LoadProgram(instructions);

            emulator.Start();

            Assert.Equal(0x123,
                         registers.GetI());
        }
Example #12
0
        public void _9xy0_SNE_vx_vy(byte vx,
                                    byte vy)
        {
            var registerModule = new RegisterModule();

            registerModule.SetGeneralValue(0,
                                           vx);

            registerModule.SetGeneralValue(1,
                                           vy);

            var instructions = new byte[]
            {
                0x90,                    //Inc program counter by 2 if v0 == v1
                0x10
            };

            var chip = CHIP8Factory.GetChip8(registers: registerModule);

            chip.LoadProgram(instructions);

            chip.Tick += (c,
                          e) =>
            {
                chip.Stop();
            };

            chip.Start();

            var nextInstruction = 514;

            var expectedAddress = nextInstruction;

            if (vx != vy)
            {
                expectedAddress += 2;
            }

            var programCounter = GetProgramCounter(chip);

            Assert.Equal(expectedAddress,
                         programCounter);
        }
Example #13
0
        public void _6xkk_LD_vx_byte()
        {
            /*
             * 6xkk - LD Vx, byte Set Vx = kk. The interpreter puts the value kk into register Vx.
             */
            var registers = new RegisterModule();

            var emulator = CHIP8Factory.GetChip8(registers: registers);

            var instructions = new byte[]
            {
                0x60,                    //LD v0 with byte 0x12
                0x12
            };

            emulator.LoadProgram(instructions);

            emulator.Start();

            Assert.Equal(0x12,
                         registers.GetGeneralValue(0));
        }
Example #14
0
        public void _8xy0_LD_vx_vy()
        {
            /*
             * 8xy0 - Stores the value of register Vy in register Vx.
             */
            var registers = new RegisterModule();

            var emulator = CHIP8Factory.GetChip8(registers: registers);

            var instructions = new byte[]
            {
                0x61,                    //LD v1 with byte 0x12
                0x12,
                0x80,                    // Store value at v1 in v0
                0x10
            };

            emulator.LoadProgram(instructions);

            emulator.Start();

            Assert.Equal(0x12,
                         registers.GetGeneralValue(0));
        }
Example #15
0
        public void _7xkk_LD_vx_byte()
        {
            /*
             * 7xkk - Adds the value kk to the value of register Vx, then stores the result in Vx.
             */
            var registers = new RegisterModule();

            var emulator = CHIP8Factory.GetChip8(registers: registers);

            var instructions = new byte[]
            {
                0x60,                    //LD v0 with byte 0x12
                0x12,
                0x70,                    // Add 0x10 to v0 and save it in v0
                0x10
            };

            emulator.LoadProgram(instructions);

            emulator.Start();

            Assert.Equal(0x22,
                         registers.GetGeneralValue(0));
        }
Example #16
0
        public void _Fx65_LD_Vx_I()
        {
            /*
             * Set registers v0 through vx from memory starting at I
             */

            var registers = new RegisterModule();

            registers.SetI(0x278);

            var startPoint = registers.GetI();

            var memory = new MemoryModule(Enumerable.Repeat((byte)0x0,
                                                            4096));

            memory[startPoint] = 0x7D;

            startPoint++;

            memory[startPoint] = 0x55;

            startPoint++;

            memory[startPoint] = 0x18;

            startPoint++;

            memory[startPoint] = 0x90;

            var emulator = CHIP8Factory.GetChip8(registers: registers,
                                                 mem: memory);

            var instructions = new byte[]
            {
                0xF3,                    //Set v0 - v3 from memory
                0x65
            };

            emulator.LoadProgram(instructions);

            emulator.Tick += (e,
                              a) =>
            {
                emulator.Stop();
            };

            emulator.Start();

            var v0 = registers.GetGeneralValue(0);

            var v1 = registers.GetGeneralValue(1);

            var v2 = registers.GetGeneralValue(2);

            var v3 = registers.GetGeneralValue(3);

            Assert.Equal(0x7D,
                         v0);
            Assert.Equal(0x55,
                         v1);
            Assert.Equal(0x18,
                         v2);
            Assert.Equal(0x90,
                         v3);
        }
Example #17
0
        public void _Fx55_LD_I_Vx()
        {
            /*
             * Stores registers v0 through vx in memory starting at I
             */

            var registers = new RegisterModule();

            registers.SetGeneralValue(0,
                                      0x7D);

            registers.SetGeneralValue(1,
                                      0x55);

            registers.SetGeneralValue(2,
                                      0x18);

            registers.SetGeneralValue(3,
                                      0x90);

            registers.SetI(0x278);

            var memory = new MemoryModule(Enumerable.Repeat((byte)0x0,
                                                            4096));

            var emulator = CHIP8Factory.GetChip8(registers: registers,
                                                 mem: memory);

            var instructions = new byte[]
            {
                0xF3,                    //Store v0 - v3 in memory
                0x55
            };

            emulator.LoadProgram(instructions);

            emulator.Tick += (e,
                              a) =>
            {
                emulator.Stop();
            };

            emulator.Start();

            var startPoint = 0x278;

            var v0 = memory[startPoint];

            startPoint++;

            var v1 = memory[startPoint];

            startPoint++;

            var v2 = memory[startPoint];

            startPoint++;

            var v3 = memory[startPoint];

            Assert.Equal(0x7D,
                         v0);
            Assert.Equal(0x55,
                         v1);
            Assert.Equal(0x18,
                         v2);
            Assert.Equal(0x90,
                         v3);
        }
Example #18
0
        public void Correctly_Draws_Manual_Zero_Sprite_Dxyn()
        {
            /*
             * Dxyn - DRW Vx, Vy, nibble
             *  Display n-byte sprite starting at memory location I at (Vx, Vy), set VF = collision.
             */

            // Copy of the 0 sprite data we load
            var zeroSpriteData = new byte[]
            {
                0xF0,
                0x90,
                0x90,
                0x90,
                0xF0
            };

            // Set I to start of sprite
            var setIInstruction = new byte[]
            {
                0xAD,
                0xDD
            };

            // Draw 5 bytes at 0,0 from mem address I
            var drawInstruction = new byte[]
            {
                0xD0,
                0x05
            };

            var registers = new RegisterModule();

            bool[,] display = null;

            Task WriteDisplay(bool[,] values)
            {
                display = values;
                return(Task.CompletedTask);
            }

            var ram = Enumerable.Repeat <byte>(0x0,
                                               4096)
                      .ToArray();

            const int spriteStart = 0xDDD;

            // Copy the data starting at FFF
            for (var i = spriteStart; i < spriteStart + zeroSpriteData.Length; i++)
            {
                ram[i] = zeroSpriteData[i - spriteStart];
            }

            var memory = new MemoryModule(ram);

            var emulator = CHIP8Factory.GetChip8(WriteDisplay,
                                                 registers,
                                                 new StackModule(),
                                                 memory);

            registers.SetGeneralValue(0,
                                      0x0);

            var instructions = setIInstruction.Concat(drawInstruction)
                               .ToArray();

            emulator.LoadProgram(instructions);

            emulator.Start();

            void AssertDisplay(int x,
                               int y,
                               bool pixelValue)
            {
                var validY = false;

                switch (x)
                {
                case 0:
                case 3:
                    // Column 1 & 4 all on
                    validY = pixelValue;
                    break;

                case 1:
                case 2:
                    // For the middle 2 columns only the top and bottom should be on
                    if (y == 0 ||
                        y == 4)
                    {
                        validY = pixelValue;
                    }
                    else
                    {
                        validY = !pixelValue;
                    }

                    break;

                default:
                    // Everything past 4 should be off
                    validY = !pixelValue;
                    break;
                }

                Assert.True(validY,
                            $"Invalid pixel at {x},{y}. {pixelValue}.");
            }

            Assert.NotNull(display);

            // Check the 8x5 area the sprite displays in
            for (var x = 0; x < 8; x++)
            {
                for (var y = 0; y < 5; y++)
                {
                    AssertDisplay(x,
                                  y,
                                  display[x,
                                          y]);
                }
            }
        }
Example #19
0
        public void Correctly_Draws_Zero_Sprite_Dxyn(byte xOffset,
                                                     byte yOffset)
        {
            var registers = new RegisterModule();

            bool[,] display = null;

            Task WriteDisplay(bool[,] values)
            {
                display = values;
                return(Task.CompletedTask);
            }

            var emulator = CHIP8Factory.GetChip8(WriteDisplay,
                                                 registers);

            registers.SetGeneralValue(3,
                                      0x0);

            registers.SetGeneralValue(0,
                                      xOffset);
            registers.SetGeneralValue(1,
                                      yOffset);

            var instructions = new byte[]
            {
                /* Load location of sprite for '0' to I */
                0xF3,
                0x29,
                /* Draw 5 byte sized sprite at (v0, v1) */
                0xD0,
                0x15
            };

            emulator.LoadProgram(instructions);

            emulator.Start();

            void AssertDisplay(int x,
                               int y,
                               bool pixelValue)
            {
                var validY = false;

                x = x - xOffset;
                y = y - yOffset;

                switch (x)
                {
                case 0:
                case 3:
                    // Column 1 & 4 all on
                    validY = pixelValue;
                    break;

                case 1:
                case 2:
                    // For the middle 2 columns only the top and bottom should be on
                    if (y == 0 ||
                        y == 4)
                    {
                        validY = pixelValue;
                    }
                    else
                    {
                        validY = !pixelValue;
                    }

                    break;

                default:
                    // Everything past 4 should be off
                    validY = !pixelValue;
                    break;
                }

                Assert.True(validY,
                            $"Invalid pixel at sprite coordinate ({x},{y}), true coordinate({x + xOffset}, {y + yOffset}). {pixelValue}.");
            }

            Assert.NotNull(display);

            // Check the 8x5 area the sprite displays in
            for (var x = xOffset; x < 8 + xOffset; x++)
            {
                for (var y = yOffset; y < 5 + yOffset; y++)
                {
                    AssertDisplay(x,
                                  y,
                                  display[x,
                                          y]);
                }
            }
        }