Exemple #1
0
 /// <summary>
 /// Skips the next instruction if VX == VY
 /// </summary>
 private void SkipXEqualsY(OpCodeData data)
 {
     if (_registers[data.X] == _registers[data.Y])
     {
         _pc += 2;
     }
 }
Exemple #2
0
 /// <summary>
 /// Saves all registers from the address in register I
 /// </summary>
 private void SetX(OpCodeData data)
 {
     for (var i = 0; i <= data.X; i++)
     {
         _memory[_index + i] = _registers[i];
     }
 }
Exemple #3
0
 /// <summary>
 /// Skips the next instruction if VX == NN
 /// </summary>
 private void SkipXEqualsNN(OpCodeData data)
 {
     if (_registers[data.X] == data.NN)
     {
         _pc += 2;
     }
 }
Exemple #4
0
 /// <summary>
 /// Executes the opcode beginning with 0xF
 /// </summary>
 private void MiscF(OpCodeData data)
 {
     if (_miscFOpCodes.ContainsKey(data.NN))
     {
         _miscFOpCodes[data.NN](data);
     }
     else
     {
         throw new NotSupportedException($"The opcode F{data.NNN:X3} is not supported");
     }
 }
Exemple #5
0
        /// <summary>
        /// Clears the screen (set all fixels to false/>
        /// </summary>
        private void ClearScreen(OpCodeData data)
        {
            for (int y = 0; y < DISPLAY_HEIGHT; y++)
            {
                for (int x = 0; x < DISPLAY_WIDTH; x++)
                {
                    _displayBuffer[y, x] = false;
                }
            }

            _redrawScreen = true;
        }
Exemple #6
0
        private void AddXToI(OpCodeData data)
        {
            if (_registers[data.X] + _index > 0xFFF)
            {
                _registers[0xF] = 1;
            }
            else
            {
                _registers[0xF] = 0;
            }

            _index += _registers[data.X];
        }
Exemple #7
0
        /// <summary>
        /// Waits for a key to be pressed by looping at the current instruction
        /// </summary>
        private void AwaitAndStoreKeyPress(OpCodeData data)
        {
            var keys = _inputDevice.GetPressedKeys();

            if (keys.Length == 0)
            {
                _pc -= 2;
            }
            else
            {
                _registers[data.X] = keys[0];
            }
        }
Exemple #8
0
        /// <summary>
        /// Draws an N-byte sprite from register I at (VX / VY). Sets VF=1 a collision occures
        /// </summary>
        private void DrawSprite(OpCodeData data)
        {
            byte x      = _registers[data.X];                               // The x coordinate of the sprite
            byte y      = _registers[data.Y];                               // The y coordinate of the sprite
            byte height = data.N;                                           // The height of the sprite

            _registers[0xF] = 0;                                            // Set VF to 0 before we start drawing the sprite

            for (int yline = 0; yline < height; yline++)                    // Loop through all the lines of the sprite (defined by the height)
            {
                var spriteLine = _memory[_index + yline];                   // One horizontal 8bit long line of the sprite.

                for (int xline = 0; xline < 8; xline++)                     // Loop through all individual bits of the line
                {
                    byte xCoord = (byte)((x + xline) % DISPLAY_WIDTH);      // The x xoordinate of the pixel
                    byte yCoord = (byte)((y + yline) % DISPLAY_HEIGHT);     // The y xoordinate of the pixel

                    var spriteBit = (spriteLine >> (7 - xline)) & 1;        // The new pixel
                    var oldBit    = _displayBuffer[yCoord, xCoord] ? 1 : 0; // The current drawn pixel

                    // If the new pixel isn't equal to the old, the screen has to be redrawn ( = refresh it)
                    if (oldBit != spriteBit)
                    {
                        _redrawScreen = true;
                    }

                    // New bit is XOR of existing and new.
                    var newBit = oldBit ^ spriteBit;

                    _displayBuffer[yCoord, xCoord] = newBit == 1;

                    // If we wiped out a pixel, set flag for collission (VF = 1)
                    if (oldBit == 1 && newBit == 0)
                    {
                        _registers[0xF] = 1;
                    }
                }
            }
        }
Exemple #9
0
        /// <summary>
        /// Skips the next instruction based on the key at VX being pressed / not pressed.
        /// </summary>
        private void KeyPressedOps(OpCodeData data)
        {
            var keys = _inputDevice.GetPressedKeys();

            switch (data.NN)
            {
            case 0x9E:
                // If key is pressed
                if (keys.Contains(_registers[data.X]))
                {
                    _pc += 2;
                }
                break;

            case 0xA1:
                // If key is NOT pressed
                if (!keys.Contains(_registers[data.X]))
                {
                    _pc += 2;
                }
                break;
            }
        }
Exemple #10
0
        /// <summary>
        /// Sets I to the correct location of the font sprite VX
        /// Each font sprite is 5 bytes long.
        /// </summary>
        private void SetIToFont(OpCodeData data)
        {
            var font = _registers[data.X];

            _index = (ushort)(FONT_INDEX + (font * 5));
        }
Exemple #11
0
 /// <summary>
 /// Takes the decimal representation of VX and puts each character into memory locations
 /// starting at I (with a maximum of 3)
 /// </summary
 private void SetIToBCD(OpCodeData data)
 {
     _memory[_index]     = (byte)(_registers[data.X] / 100);
     _memory[_index + 1] = (byte)((_registers[data.X] / 10) % 10);
     _memory[_index + 2] = (byte)((_registers[data.X] % 100) % 10);
 }
Exemple #12
0
 /// <summary>
 /// Returns from a subroutine with setting the program-counter to the top most element on the stack
 /// </summary>
 /// <param name="data"></param>
 private void ReturnSubroutine(OpCodeData data)
 {
     _pc = _stack.Pop();
 }
Exemple #13
0
 /// <summary>
 /// Jumps to location NNN + V0
 /// Not a subroutine, so old program counter is not pushed to the stack
 /// </summary>
 private void JumpToNNNPlusV0(OpCodeData data)
 {
     _pc = (ushort)(data.NNN + _registers[0]);
 }
Exemple #14
0
 /// <summary>
 /// Sets the sound timer to the value of VX
 /// </summary>
 private void SetSoundTimer(OpCodeData data)
 {
     _soundTimer = _registers[data.X];
 }
Exemple #15
0
 /// <summary>
 /// ANDs a random number with NN and stores in VX
 /// </summary>
 private void SetRandomX(OpCodeData data)
 {
     _registers[data.X] = (byte)(_rng.Next(0, 0xFF) & data.NN);
 }
Exemple #16
0
 /// <summary>
 /// Sets the value of VX to NN
 /// </summary>
 private void SetXToNN(OpCodeData data)
 {
     _registers[data.X] = data.NN;
 }
Exemple #17
0
 /// <summary>
 /// Adds NN to VX
 /// </summary>
 private void AddXToNN(OpCodeData data)
 {
     _registers[data.X] += data.NN;
 }
Exemple #18
0
        /// <summary>
        /// Performs some kind of math on VX
        /// </summary>
        /// <param name="data"></param>
        private void Arithmetic(OpCodeData data)
        {
            switch (data.N)
            {
            case 0x0:
                // Store the value of register VY in register VX
                _registers[data.X] = _registers[data.Y];
                break;

            case 0x1:
                // Set VX to VX OR VY
                _registers[data.X] |= _registers[data.Y];
                break;

            case 0x2:
                // Set VX to VX AND VY
                _registers[data.X] &= _registers[data.Y];
                break;

            case 0x3:
                // Set VX to VX XOR VY
                _registers[data.X] ^= _registers[data.Y];
                break;

            case 0x4:
                // Add the value of register VY to register VX
                // Set VF to 1 if a carry occurs
                // Set VF to 0 if a carry does not occur
                if (_registers[data.X] + _registers[data.Y] > 0xFF)
                {
                    _registers[0xF] = 1;
                }
                else
                {
                    _registers[0xF] = 0;
                }

                _registers[data.X] += _registers[data.Y];
                break;

            case 0x5:
                // Subtract the value of register VY from register VX
                // Set VF to 00 if a borrow occurs
                // Set VF to 01 if a borrow does not occur
                if (_registers[data.X] - _registers[data.Y] < 0)
                {
                    _registers[0xF] = 0;
                }
                else
                {
                    _registers[0xF] = 1;
                }

                _registers[data.X] -= _registers[data.Y];
                break;

            case 0x6:
                // Store the value of register VX shifted right one bit in register VX
                // Set register VF to the least significant bit prior to the shift
                _registers[0xF]    = (byte)(_registers[data.X] & 0b0000_0001);
                _registers[data.X] = (byte)(_registers[data.X] >> 0x1);
                break;

            case 0x7:
                // Set register VX to the value of VY minus VX
                // Set VF to 00 if a borrow occurs
                // Set VF to 01 if a borrow does not occur
                if (_registers[data.Y] - _registers[data.X] < 0)
                {
                    _registers[0xF] = 0;
                }
                else
                {
                    _registers[0xF] = 1;
                }

                _registers[data.X] = (byte)(_registers[data.Y] - _registers[data.X]);
                break;

            case 0xE:
                // Store the value of register VX shifted left one bit in register VX
                // Set register VF to the most significant bit prior to the shift
                _registers[0xF]    = (byte)(_registers[data.X] >> 7);
                _registers[data.X] = (byte)(_registers[data.X] << 0x1);
                break;

            default:
                throw new NotSupportedException($"{data.N:X1} is not supported");
            }
        }
Exemple #19
0
 /// <summary>
 /// Sets the I register to NNN
 /// </summary>
 private void SetIToNNN(OpCodeData data)
 {
     _index = data.NNN;
 }
Exemple #20
0
 /// <summary>
 /// Sets the delay timer to the value of VX
 /// </summary>
 private void SetDelayTimer(OpCodeData data)
 {
     _delayTimer = _registers[data.X];
 }
Exemple #21
0
 /// <summary>
 /// Jumps to subroutine NNN
 /// Unlike Jump, this pushes the previous program counter to the stack to allow return
 /// </summary>
 private void CallSubroutine(OpCodeData data)
 {
     _stack.Push(_pc);
     _pc = data.NNN;
 }
Exemple #22
0
 /// <summary>
 /// Sets VX to the value of the delay timer
 /// </summary>
 private void SetXToTimer(OpCodeData data)
 {
     _registers[data.X] = (byte)_delayTimer;
 }
Exemple #23
0
 /// <summary>
 /// Jumps to location NNN
 /// Not a subroutine, so old program counter is not pushed to the stack
 /// </summary>
 private void JumpToNNN(OpCodeData data)
 {
     _pc = data.NNN;
 }