Exemplo n.º 1
0
        public void Start()
        {
            Console.CursorVisible = false;
            while (true)
            {
                // fetch opcode
                var fetchedOpcode = (ushort)(memory[PC++] << 8 | memory[PC++]);
                var opcode        = new OpcodeData
                {
                    FullOpcode = fetchedOpcode,
                    NNN        = (ushort)(fetchedOpcode & 0x0FFF),
                    X          = (byte)((fetchedOpcode & 0x0F00) >> 8),
                    Y          = (byte)((fetchedOpcode & 0x00F0) >> 4),
                    NN         = (byte)(fetchedOpcode & 0x00FF),
                    N          = (byte)(fetchedOpcode & 0x000F)
                };

                // Console.WriteLine($"{opcode.FullOpcode:X4}");
                _decodeAndExecute(opcode);

                if (Console.KeyAvailable)
                {
                    ConsoleKeyInfo keyInfo = Console.ReadKey(true);
                    if (mappedKeys.TryGetValue(keyInfo.Key, out byte value))
                    {
                        for (int i = 0; i < keys.Length; ++i)
                        {
                            keys[i] = 0;
                        }
                        keys[value] = 0xF;
                    }
                }
                else
                {
                    for (int i = 0; i < keys.Length; ++i)
                    {
                        keys[i] = 0;
                    }
                }

                if (drawFlag)
                {
                    _drawGraphics();
                }

                if (delayTimer > 0)
                {
                    --delayTimer;
                }

                if (soundTimer > 0)
                {
                    if (soundTimer == 1)
                    {
                        Console.Beep();
                    }
                    --soundTimer;
                }
            }
        }
Exemplo n.º 2
0
        private void _decodeAndExecute(OpcodeData opcode)
        {
            // evaluate first nibble (four bits)
            switch (opcode.FullOpcode & 0xF000)
            {
            case 0x0:
                // further evaluate second byte to determine instruction
                _decode0(opcode.NN);
                break;

            case 0x1000:
                // 1NNN - jump to address NNN
                PC = opcode.NNN;
                break;

            case 0x2000:
                // 2NNN - call subroutine at address NNN
                stack[SP++] = PC;
                PC          = opcode.NNN;
                break;

            case 0x3000:
                // 3XNN - skip next instruction if VX equals NN
                if (V[opcode.X] == opcode.NN)
                {
                    PC += 2;
                }
                break;

            case 0x4000:
                // 4XNN - skip next instruction if VX does not equal NN
                if (V[opcode.X] != opcode.NN)
                {
                    PC += 2;
                }
                break;

            case 0x5000:
                // 5XY0 - skip next instruction if VX equals VY
                if (V[opcode.X] == V[opcode.Y])
                {
                    PC += 2;
                }
                break;

            case 0x6000:
                // 6XNN - set VX to NN
                V[opcode.X] = opcode.NN;
                break;

            case 0x7000:
                // 7XNN - add NN to VX
                V[opcode.X] += opcode.NN;
                break;

            case 0x8000:
                // further evaluate last nibble to determine instruction
                _decode8(opcode.N, opcode.X, opcode.Y);
                break;

            case 0x9000:
                // 0x9XY0 - skip next instruction if VX != VY
                if (V[opcode.X] != V[opcode.Y])
                {
                    PC += 2;
                }
                break;

            case 0xA000:
                // ANNN - set index register to address NNN
                I = opcode.NNN;
                break;

            case 0xB000:
                // BNNN - jump to address NNN + V0
                PC = (ushort)(opcode.NNN + V[0]);
                break;

            case 0xC000:
                // CXNN - set VX to result of NN AND (random number from 0 to 255)
                V[opcode.X] = (byte)(opcode.NN & new Random().Next(256));
                break;

            case 0xD000:
                // DXYN - draws a sprite at coordinate (VX, VY) that has a width of 8 pixels and height of N pixels;
                // each row of 8 pixels is read as bit-coded starting from memory location I;
                // VF is set to 1 if any screen pixels are flipped from set to unset when sprite is drawn, 0 if not
                byte x = V[opcode.X];
                byte y = V[opcode.Y];
                V[0xF] = 0;

                for (byte i = 0; i < opcode.N; ++i)
                {
                    byte row  = memory[I + i];
                    byte mask = 0x80;
                    for (byte j = 0; j < 8; ++j)
                    {
                        bool bit = Convert.ToBoolean(row & mask);
                        mask >>= 1;

                        if (bit)
                        {
                            if (graphics[y + i, x + j])
                            {
                                V[0xF] = 1;
                            }
                            graphics[y + i, x + j] ^= true;
                        }
                    }
                }
                drawFlag = true;
                break;

            case 0xE000:
                // further evaluate last byte to determine instruction
                _decodeE(opcode.NN, opcode.X);
                break;

            case 0xF000:
                // further evaluate last byte to determine instruction
                _decodeF(opcode.NN, opcode.X, opcode.Y);
                break;

            default:
                throw new Exception("Invalid instruction!");
            }
        }