コード例 #1
0
        public void SetMemory(byte[] memory)
        {
            this.Memory = memory;

            disassemblyBuffer.Clear();

            ushort   PC       = chip8.core.Chip8.START_PROGRAM_MEMORY;
            TextIter position = disassemblyBuffer.EndIter;

            while (PC < chip8.core.Chip8.MEMORY_SIZE)
            {
                var opCode = (ushort)(Memory[PC++] << 8 | Memory[PC++]);
                var op     = new chip8.core.Chip8.OpCodeData()
                {
                    OpCode      = opCode,
                    Instruction = (ushort)((opCode & 0xF000) >> 12),
                    NNN         = (ushort)(opCode & 0x0FFF),
                    NN          = (byte)(opCode & 0x00FF),
                    N           = (byte)(opCode & 0x00F),
                    X           = (byte)((opCode & 0x0F00) >> 8),
                    Y           = (byte)((opCode & 0x00F0) >> 4)
                };

                DissasembleOpCode(disassemblyBuffer, ref position, op, (ushort)(PC - 2));
            }
        }
コード例 #2
0
        private void DissasembleOpCode(TextBuffer buffer, ref TextIter position, chip8.core.Chip8.OpCodeData op, ushort PC)
        {
            buffer.InsertWithTagsByName(ref position, string.Format($"0x{(PC):x4} "), "address");
            buffer.InsertWithTagsByName(ref position, string.Format($"0x{(op.OpCode):x4} "), "opCode");
            buffer.InsertWithTagsByName(ref position, string.Format($" "), "keyword");

            //Decode the op codes
            switch (op.Instruction)
            {
            //Clear Screen / Return from subroutine
            case 0x0:
            {
                if (op.X == 0x0)
                {
                    if (op.N == 0x0 && op.Y == 0xE)
                    {
                        //Clear screen
                        buffer.InsertWithTagsByName(ref position, "cls", "keyword");
                        buffer.InsertWithTagsByName(ref position, " //Clear Screen;", "comment");
                        break;
                    }
                    else if (op.N == 0xE)
                    {
                        //Return from sub

                        buffer.InsertWithTagsByName(ref position, "return", "keyword");
                        break;
                    }
                    else if (op.NNN == 0x000)
                    {
                        break;
                    }
                }
                break;
            }

            //0x1NNNN - Jumps to address NNN.
            case 0x1:
            {
                buffer.InsertWithTagsByName(ref position, "jump", "keyword");
                buffer.InsertWithTagsByName(ref position, $" 0x{((ushort)(op.NNN)):x3}", "constant");
                break;
            }

            //0x2NNN - Calls subroutine at NNN.
            case 0x2:
            {
                buffer.InsertWithTagsByName(ref position, "call", "keyword");
                buffer.InsertWithTagsByName(ref position, $" 0x{((ushort)(op.NNN)):x3}", "constant");
                break;
            }

            //0x3XNN - Skips the next instruction if VX equals NN. (Usually the next instruction is a jump to skip a code block)
            case 0x3:
            {
                buffer.InsertWithTagsByName(ref position, "sei", "keyword");
                buffer.InsertWithTagsByName(ref position, $" V{op.X:x}", "variable");
                buffer.InsertWithTagsByName(ref position, $" 0x{op.NN:x2}", "constant");
                buffer.InsertWithTagsByName(ref position, $" //if (V{op.X:x} == 0x{op.NN:x2}) {{ PC += 2; }}", "comment");
                break;
            }

            //0x4XNN - Skips the next instruction if VX doesn't equal NN. (Usually the next instruction is a jump to skip a code block)
            case 0x4:
            {
                buffer.InsertWithTagsByName(ref position, "snei", "keyword");
                buffer.InsertWithTagsByName(ref position, $" V{op.X:x}", "variable");
                buffer.InsertWithTagsByName(ref position, $" 0x{op.NN:x2}", "constant");
                buffer.InsertWithTagsByName(ref position, $" //if (V{op.X:x} != 0x{op.NN:x2}) {{ PC += 2; }}", "comment");
                break;
            }

            //0x5XY0 -  Skips the next instruction if VX equals VY. (Usually the next instruction is a jump to skip a code block)
            case 0x5:
            {
                buffer.InsertWithTagsByName(ref position, "ser", "keyword");
                buffer.InsertWithTagsByName(ref position, $" V{op.X:x}", "variable");
                buffer.InsertWithTagsByName(ref position, $" V{op.Y:x}", "variable");
                buffer.InsertWithTagsByName(ref position, $" //if (V{op.X:x} == V{op.Y:x}) {{ PC += 2; }}", "comment");
                break;
            }

            //0x6XNN -  Sets VX to NN.
            case 0x6:
            {
                buffer.InsertWithTagsByName(ref position, "movi", "keyword");
                buffer.InsertWithTagsByName(ref position, $" V{op.X:x}", "variable");
                buffer.InsertWithTagsByName(ref position, $" 0x{op.NN:x2}", "constant");
                buffer.InsertWithTagsByName(ref position, $" //V{op.X:x} = 0x{op.NN:x2}", "comment");
                break;
            }

            //0x7XNN - Adds NN to VX. (Carry flag is not changed)
            case 0x7:
            {
                buffer.InsertWithTagsByName(ref position, "addi", "keyword");
                buffer.InsertWithTagsByName(ref position, $" V{op.X:x}", "variable");
                buffer.InsertWithTagsByName(ref position, $" 0x{op.NN:x2}", "constant");
                buffer.InsertWithTagsByName(ref position, $" //V{op.X:x} += 0x{op.NN:x2}", "comment");
                break;
            }

            //0x8XY? - BitWise / Math operations based on ?
            case 0x8:
            {
                //Switch based on the last nibble of the opcode
                switch (op.N)
                {
                case 0x0:             // 8XY0 - Sets VX to the value of VY.
                {
                    buffer.InsertWithTagsByName(ref position, "movr", "keyword");
                    buffer.InsertWithTagsByName(ref position, $" V{op.X:x}", "variable");
                    buffer.InsertWithTagsByName(ref position, $" V{op.Y:x}", "variable");
                    buffer.InsertWithTagsByName(ref position, $" //V{op.X:x} = V{op.Y:x}", "comment");
                    break;
                }

                case 0x1:             // 8XY1 - Sets VX to VX or VY. (Bitwise OR operation)
                {
                    buffer.InsertWithTagsByName(ref position, "or", "keyword");
                    buffer.InsertWithTagsByName(ref position, $" V{op.X:x}", "variable");
                    buffer.InsertWithTagsByName(ref position, $" V{op.Y:x}", "variable");
                    buffer.InsertWithTagsByName(ref position, $" //V{op.X:x} |= V{op.Y:x} (bitwise OR)", "comment");
                    break;
                }

                case 0x2:             // 8XY2 - Sets VX to VX and VY. (Bitwise AND operation)
                {
                    buffer.InsertWithTagsByName(ref position, "and", "keyword");
                    buffer.InsertWithTagsByName(ref position, $" V{op.X:x}", "variable");
                    buffer.InsertWithTagsByName(ref position, $" V{op.Y:x}", "variable");
                    buffer.InsertWithTagsByName(ref position, $" //V{op.X:x} &= V{op.Y:x} (bitwise AND)", "comment");
                    break;
                }

                case 0x3:             // 8XY3 - Sets VX to VX xor VY.
                {
                    buffer.InsertWithTagsByName(ref position, "xor", "keyword");
                    buffer.InsertWithTagsByName(ref position, $" V{op.X:x}", "variable");
                    buffer.InsertWithTagsByName(ref position, $" V{op.Y:x}", "variable");
                    buffer.InsertWithTagsByName(ref position, $" //V{op.X:x} ^= V{op.Y:x} (bitwise XOR)", "comment");
                    break;
                }

                case 0x4:             // 8XY4 - Adds VY to VX. VF is set to 1 when there's a carry, and to 0 when there isn't.
                {
                    buffer.InsertWithTagsByName(ref position, "addr", "keyword");
                    buffer.InsertWithTagsByName(ref position, $" V{op.X:x}", "variable");
                    buffer.InsertWithTagsByName(ref position, $" V{op.Y:x}", "variable");
                    buffer.InsertWithTagsByName(ref position, $" //V{op.X} = V{op.X} + V{op.Y} Vf set to 1 if there's a carry", "comment");
                    break;
                }

                case 0x5:             // 8XY5 - VY is subtracted from VX. VF is set to 0 when there's a borrow, and 1 when there isn't.
                {
                    buffer.InsertWithTagsByName(ref position, "subr", "keyword");
                    buffer.InsertWithTagsByName(ref position, $" V{op.X:x}", "variable");
                    buffer.InsertWithTagsByName(ref position, $" V{op.Y:x}", "variable");
                    buffer.InsertWithTagsByName(ref position, $" //V{op.X} = V{op.X} - V{op.Y} Vf set to 0 if there's a borrow", "comment");
                    break;
                }

                case 0x6:             // 8XY6 - Stores the least significant bit of VX in VF and then shifts VX to the right by 1.
                {
                    buffer.InsertWithTagsByName(ref position, "shr", "keyword");
                    buffer.InsertWithTagsByName(ref position, $" V{op.X:x}", "variable");
                    buffer.InsertWithTagsByName(ref position, $" //Stores the least significant bit of V{op.X:x} in Vf and then shifts V{op.X:x} to the right by 1", "comment");
                    break;
                }

                case 0x7:             // 8XY7 - Sets VX to VY minus VX. VF is set to 0 when there's a borrow, and 1 when there isn't.
                {
                    buffer.InsertWithTagsByName(ref position, "nsubr", "keyword");
                    buffer.InsertWithTagsByName(ref position, $" V{op.X:x}", "variable");
                    buffer.InsertWithTagsByName(ref position, $" V{op.Y:x}", "variable");
                    buffer.InsertWithTagsByName(ref position, $" //V{op.X} = V{op.Y} - V{op.X} Vf set to 0 if there's a borrow", "comment");
                    break;
                }

                case 0xE:             // 8XYE - Stores the most significant bit of VX in VF and then shifts VX to the left by 1.
                {
                    buffer.InsertWithTagsByName(ref position, "shl", "keyword");
                    buffer.InsertWithTagsByName(ref position, $" V{op.X:x}", "variable");
                    buffer.InsertWithTagsByName(ref position, $" //Stores the most significant bit of V{op.X:x} in Vf and then shifts V{op.X:x} to the left by 1", "comment");
                    break;
                }
                }
                break;
            }

            //0x9XY0 - Skips the next instruction if VX doesn't equal VY. (Usually the next instruction is a jump to skip a code block)
            case 0x9:
            {
                buffer.InsertWithTagsByName(ref position, "sner", "keyword");
                buffer.InsertWithTagsByName(ref position, $" V{op.X:x}", "variable");
                buffer.InsertWithTagsByName(ref position, $" V{op.Y:x}", "variable");
                buffer.InsertWithTagsByName(ref position, $" //if (V{op.X:x} != V{op.Y:x}) {{ PC += 2; }}", "comment");
                break;
            }

            //0xANNN - Sets I to the address NNN.
            case 0xA:
            {
                buffer.InsertWithTagsByName(ref position, "imovi", "keyword");
                buffer.InsertWithTagsByName(ref position, $" I", "variable");
                buffer.InsertWithTagsByName(ref position, $" 0x{op.NNN:x3}", "constant");
                buffer.InsertWithTagsByName(ref position, $" //I = 0x{op.NNN:x3}", "comment");
                break;
            }

            //0xBNNN - Jumps to the address NNN plus V0.
            case 0xB:
            {
                buffer.InsertWithTagsByName(ref position, "jumpoff", "keyword");
                buffer.InsertWithTagsByName(ref position, $" 0x{op.NNN:x3}", "constant");
                buffer.InsertWithTagsByName(ref position, " + ", "keyword");
                buffer.InsertWithTagsByName(ref position, $" V0", "variable");
                buffer.InsertWithTagsByName(ref position, $" //PC = (0x{op.NNN:x3} + V0);", "comment");
                break;
            }

            //0xCXNN - Sets VX to the result of a bitwise and operation on a random number (Typically: 0 to 255) and NN.
            case 0xC:
            {
                buffer.InsertWithTagsByName(ref position, "rnd", "keyword");
                buffer.InsertWithTagsByName(ref position, $" V{op.X:x}", "variable");
                buffer.InsertWithTagsByName(ref position, $" 0x{op.NN:x2}", "constant");
                buffer.InsertWithTagsByName(ref position, $" //V{op.X:x} = RND() & 0x{op.NN:x2}", "comment");
                break;
            }

            //0xDXYN - Draws a sprite at coordinate (VX, VY) that has a width of 8 pixels and a height of N pixels.
            //         Each row of 8 pixels is read as bit-coded starting from memory location I;
            //         I value doesn’t change after the execution of this instruction.
            //         As described above, VF is set to 1 if any screen pixels are flipped from set to unset when the sprite
            //         is drawn, and to 0 if that doesn’t happen
            case 0xD:
            {
                buffer.InsertWithTagsByName(ref position, "sprite", "keyword");
                buffer.InsertWithTagsByName(ref position, $" V{op.X:x}", "variable");
                buffer.InsertWithTagsByName(ref position, $" V{op.Y:x}", "variable");
                buffer.InsertWithTagsByName(ref position, $" 0x{op.N:x}", "constant");
                buffer.InsertWithTagsByName(ref position, $" //VF = DrawSprite(V{op.X:x}, V{op.Y:x}, 0x{op.N:x}, I) DrawSprite(x,y,h,sprite_memaddress)", "comment");
                break;
            }

            //0xEX?? - Handles key presses
            case 0xE:
            {
                //EX9E - Skips the next instruction if the key stored in VX is pressed. (Usually the next instruction is a jump to skip a code block)
                if (op.N == 0xE)
                {
                    buffer.InsertWithTagsByName(ref position, "skr", "keyword");
                    buffer.InsertWithTagsByName(ref position, $" V{op.X:x}", "variable");
                    buffer.InsertWithTagsByName(ref position, $" // if keypress(V{op.X:x}) skip", "comment");
                    break;
                }
                else
                {
                    //EXA1	- Skips the next instruction if the key stored in VX isn't pressed. (Usually the next instruction is a jump to skip a code block)
                    //Check to see if the key stored in VX wasn't pressed
                    buffer.InsertWithTagsByName(ref position, "snkr", "keyword");
                    buffer.InsertWithTagsByName(ref position, $" V{op.X:x}", "variable");
                    buffer.InsertWithTagsByName(ref position, $" // if !keypress(V{op.X:x}) skip", "comment");
                    break;
                }
            }

            case 0xF:
            {
                switch (op.NN)
                {
                //0xFX07 - Sets VX to the value of the delay timer.
                case 0x07:
                {
                    buffer.InsertWithTagsByName(ref position, "rmovt", "keyword");
                    buffer.InsertWithTagsByName(ref position, $" V{op.X:x}", "variable");
                    buffer.InsertWithTagsByName(ref position, $" // V{op.X:x} = DelayTimer", "comment");
                    break;
                }

                //0xF0A - A key press is awaited, and then stored in VX. (Blocking Operation. All instruction halted until next key event)
                case 0x0A:
                {
                    buffer.InsertWithTagsByName(ref position, "waitk", "keyword");
                    buffer.InsertWithTagsByName(ref position, $" V{op.X:x}", "variable");
                    buffer.InsertWithTagsByName(ref position, $" // V{op.X:x} = keypress() -- Block until key pressed", "comment");
                    break;
                }

                //0xFX15 - Sets the delay timer to VX.
                case 0x15:
                {
                    buffer.InsertWithTagsByName(ref position, "movt", "keyword");
                    buffer.InsertWithTagsByName(ref position, $" V{op.X:x}", "variable");
                    buffer.InsertWithTagsByName(ref position, $" // DelayTimer = V{op.X:x}", "comment");
                    break;
                }

                //0xFX18 - Sets the sound timer to VX.
                case 0x18:
                {
                    buffer.InsertWithTagsByName(ref position, "movs", "keyword");
                    buffer.InsertWithTagsByName(ref position, $" V{op.X:x}", "variable");
                    buffer.InsertWithTagsByName(ref position, $" // SoundTimer = V{op.X:x}", "comment");
                    break;
                }

                //0xFX1E - Adds VX to I
                case 0x1E:
                {
                    buffer.InsertWithTagsByName(ref position, "iaddr", "keyword");
                    buffer.InsertWithTagsByName(ref position, $" V{op.X:x}", "variable");
                    buffer.InsertWithTagsByName(ref position, $" // I += V{op.X:x}", "comment");
                    break;
                }

                //0xFX29 - Sets I to the location of the sprite for the character in VX. Characters 0-F (in hexadecimal) are represented by a 4x5 font.
                case 0x29:
                {
                    buffer.InsertWithTagsByName(ref position, "digit", "keyword");
                    buffer.InsertWithTagsByName(ref position, $" V{op.X:x}", "variable");
                    buffer.InsertWithTagsByName(ref position, $" // I is set to the address for the character (0-F) in V{op.X:x}", "comment");
                    break;
                }

                //0xFX33 - Stores the binary-coded decimal representation of VX, with the most significant of three digits at the address in I, the middle digit at I plus 1, and the least significant digit at I plus 2.
                case 0x33:
                {
                    buffer.InsertWithTagsByName(ref position, "bcd", "keyword");
                    buffer.InsertWithTagsByName(ref position, $" V{op.X:x}", "variable");
                    break;
                }

                //0xF55 - Stores V0 to VX (including VX) in memory starting at address I. The offset from I is increased by 1 for each value written, but I itself is left unmodified.
                case 0x55:
                {
                    buffer.InsertWithTagsByName(ref position, "store", "keyword");
                    buffer.InsertWithTagsByName(ref position, $" V{op.X:x}", "variable");
                    break;
                }

                //0xFX65 - Fills V0 to VX (including VX) with values from memory starting at address I. The offset from I is increased by 1 for each value written, but I itself is left unmodified.
                case 0x65:
                {
                    buffer.InsertWithTagsByName(ref position, "load", "keyword");
                    buffer.InsertWithTagsByName(ref position, $" V{op.X:x}", "variable");
                    break;
                }
                }
                break;
            }
            }
            if (position.BytesInLine > 120)
            {
                buffer.InsertWithTagsByName(ref position, "\n", "white");
            }
            else
            {
                var txt = "".PadLeft(120 - position.BytesInLine, ' ') + "\n";
                buffer.InsertWithTagsByName(ref position, txt, "white");
            }
        }