Beispiel #1
0
        public void Tick()
        {
            var opCode       = CPU.GetNextInstruction();
            var parsedOpCode = new ParsedOpCode(opCode);

            DispatchOpcode(parsedOpCode);
        }
Beispiel #2
0
        private void Dispatch0x08(ParsedOpCode parsedOpCode)
        {
            switch (parsedOpCode.N)
            {
            case 0x0:
                // 0x8XY0 Store the value of register VY in VX
                CPU.CopyRegisterYtoX(parsedOpCode.X, parsedOpCode.Y);
                break;

            case 0x01:
                // 0x8XY1 Set VX to VX OR VY
                CPU.OrRegisterXY(parsedOpCode.X, parsedOpCode.Y);
                break;

            case 0x02:
                // 0x8XY2 Set VX to VX AND VY
                CPU.AndRegisterXY(parsedOpCode.X, parsedOpCode.Y);
                break;

            case 0x03:
                // 0x8XY3 Set VX to VX XOR VY
                CPU.XorRegisterXY(parsedOpCode.X, parsedOpCode.Y);
                break;

            case 0x04:
                // 0x8XY4 Add the value of VY to VX.
                CPU.AddRegisterYtoX(parsedOpCode.X, parsedOpCode.Y);
                break;

            case 0x05:
                // 0x8XY5 Subtract the value of VY from VX
                CPU.SubtractRegisterYfromX(parsedOpCode.X, parsedOpCode.Y);
                break;

            case 0x06:
                // 0x8XY6 Store the value of register VY shifted to the right by one bit in register VX
                CPU.ShiftVxBy1Right(parsedOpCode.X);
                break;

            case 0x07:
                // Set register VX to the value of VY minus VX
                CPU.SubtractRegisterXFromY(parsedOpCode.X, parsedOpCode.Y);
                break;

            case 0x0E:
                // Store the value of register VY shifted left one bit in register VX.
                // Set VF to the MSB prior to the shift
                CPU.ShiftVxBy1Left(parsedOpCode.X);
                break;
            }
        }
Beispiel #3
0
        private void Dispatch0x0E(ParsedOpCode parsedOpCode)
        {
            switch (parsedOpCode.NN)
            {
            case 0x9E:
                // Skip the next instruction if the key mapped to the hex value in register VX is pressed
                if (KeyboardInput.IsKeyPressed(CPU.V[parsedOpCode.X]))
                {
                    CPU.ProgramCounter += 2;
                }
                break;

            case 0xA1:
                // Skip the next instruction if the key mapped to the hex value in register VX is not pressed
                if (!KeyboardInput.IsKeyPressed(CPU.V[parsedOpCode.X]))
                {
                    CPU.ProgramCounter += 2;
                }
                break;

            default:
                throw new NotSupportedException();
            }
        }
Beispiel #4
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;
            }
        }
Beispiel #5
0
        private void Dispatch0x0F(ParsedOpCode parsedOpCode)
        {
            switch (parsedOpCode.NN)
            {
            case 0x07:
                // Store the current value of the delay timer in register VX
                CPU.V[parsedOpCode.X] = CPU.DelayTimer.Value;
                break;

            case 0x0A:
                // Wait for a keypress and store the result in register VX
                var hexKey = KeyboardInput.WaitForKey();
                CPU.V[parsedOpCode.X] = hexKey;

                break;

            case 0x15:
                // Set the delay timer to the value of register VX
                CPU.DelayTimer.Value = parsedOpCode.X;
                break;

            case 0x18:
                // Set the sound timer to the value of register VX
                CPU.SoundTimer.Value = parsedOpCode.X;
                break;

            case 0x1E:
                // Add the value stored in register VX to register I
                CPU.Index += CPU.V[parsedOpCode.X];
                break;

            case 0x29:
                // Set I to the memory address of the sprite data stored in register VX
                CPU.Index = (UInt16)(CPU.V[parsedOpCode.X] * 5 + Memory.StartFontLocation);
                break;

            case 0x33:
                // Store the binary-coded decimal equivalent of the value stored in register VX at addresses I, I + 1, and I + 2
                var decimalNum = CPU.V[parsedOpCode.X];

                Memory[CPU.Index]     = (byte)(decimalNum / 100);
                Memory[CPU.Index + 1] = (byte)((decimalNum % 100) / 10);
                Memory[CPU.Index + 2] = (byte)((decimalNum % 10) % 10);
                break;

            case 0x55:
                // Store the values of registers V0 to VX inclusive in memory starting at address I.
                // X + 1 is added to I after completion
                for (int i = 0; i <= parsedOpCode.X; i += 1)
                {
                    Memory[CPU.Index + i] = CPU.V[i];
                }

                CPU.Index += (UInt16)(parsedOpCode.X + 1);
                break;

            case 0x65:
                // Fill registers V0 to VX inclusive with the values stored in memory starting at address I
                // X + 1 is added to I after operation
                for (int i = 0; i <= parsedOpCode.X; i += 1)
                {
                    CPU.V[i] = Memory[CPU.Index + i];
                }

                CPU.Index += (UInt16)(parsedOpCode.X + 1);
                break;

            default:
                throw new NotSupportedException();
            }
        }