Example #1
0
        private void recursiveTranversal(ushort addr, byte[] rom)
        {
            while (addr >= 0 && addr <= rom.Length)
            {
                if (!addrDecodeCheck[addr])
                {
                    DecodedInstruction instruct = dissaembleInstruc((ushort)((rom[addr] << 8) | rom[addr + 1]), addr);
                    decodedRom.Add(instruct);
                    addrDecodeCheck[addr] = true;

                    byte opcode = Utli.getUpperByteHighNibble(instruct.Opcode);

                    //branch instruction check
                    if (opcode == 1) //non conditional jump
                    {
                        recursiveTranversal((ushort)((instruct.Opcode & 0x0FFF) - Chip8.ROM_BASE_ADDR), rom);
                        return;
                    }
                    else if (opcode == 2)// subroutine call,
                    {
                        //2 brances. first branch is the call, second is the return branch
                        recursiveTranversal((ushort)((instruct.Opcode & 0x0FFF) - Chip8.ROM_BASE_ADDR), rom);
                        recursiveTranversal((ushort)((instruct.AddrOfInstruc + 2)), rom);
                        return;
                    }
                    else if (instruct.Opcode == 0x00EE) //end subroutine
                    {
                        return;
                    }//3,5,4,9
                    else if (opcode == 3 || opcode == 5 || opcode == 4 || opcode == 9 || opcode == 0xE) //primitive conditional branching
                    {
                        recursiveTranversal((ushort)((instruct.AddrOfInstruc + 2)), rom);
                        recursiveTranversal((ushort)((instruct.AddrOfInstruc + 4)), rom);
                        return;
                    }
                    else
                    {
                        addr = (ushort)(addr + 2);
                    }
                }
                else
                {
                    return;
                }
            }
        }
Example #2
0
        public DecodedInstruction dissaembleInstruc(ushort opcode, ushort addr)
        {
            DecodedInstruction instruction = new DecodedInstruction();

            //disassemble instruction params

            string nnn = "0x" + ((opcode & 0x0FFF)).ToString("x2").ToUpper();                  // address - 0nnn
            string nn  = "0x" + (Utli.getLowerByte(opcode)).ToString("x2").ToUpper();          // constant - 00nn
            string n   = "0x" + (Utli.getLowerByteLowNibble(opcode)).ToString("x2").ToUpper(); // constant - 000n
            string x   = (Utli.getUpperByteLowNibble(opcode)).ToString("x2").ToUpper();        // register # - 0x00
            string y   = (Utli.getLowerByteHighNibble(opcode)).ToString("x2").ToUpper();       // register # - 00y0

            if (x.Substring(0, 1).Equals("0"))
            {
                x = x.Substring(1);
            }
            if (y.Substring(0, 1).Equals("0"))
            {
                y = y.Substring(1);
            }

            //decode
            switch (Utli.getUpperByteHighNibble(opcode))
            {
            case 0x0:
            {
                if (Utli.getLowerByteHighNibble(opcode) == 0xE)
                {
                    switch (Utli.getLowerByteLowNibble(opcode))
                    {
                    case 0x0:            //	Clears the screen.
                        instruction.AddrOfInstruc  = addr;
                        instruction.Opcode         = opcode;
                        instruction.MnemonicInstuc = "CLS";
                        instruction.Description    = "Clears the screen.";
                        break;

                    case 0xE:            //Returns from a subroutine.
                        instruction.AddrOfInstruc  = addr;
                        instruction.Opcode         = opcode;
                        instruction.MnemonicInstuc = "RET";
                        instruction.Description    = "Returns from a subroutine.";
                        break;

                    default:
                        Console.WriteLine("Unknown Opcode - " + "0x" + opcode.ToString("x2"));
                        break;
                    }
                }
                else
                {
                    if ((opcode & 0x0FFF) == 0)
                    {
                        instruction.AddrOfInstruc  = addr;
                        instruction.Opcode         = opcode;
                        instruction.MnemonicInstuc = "SYS";
                        instruction.Description    = "Calls RCA 1802 program at address " + addr + " Not necessary for most ROMs.";
                    }
                    else
                    {
                        instruction.AddrOfInstruc = addr;
                    }
                    instruction.Opcode         = opcode;
                    instruction.MnemonicInstuc = "UNKNOWN";
                    instruction.Description    = "Unimplemented Opcode - " + "0x" + opcode.ToString("x2");
                }
            }
            break;

            case 0x1:    //Jumps to address NNN.
                instruction.AddrOfInstruc  = addr;
                instruction.Opcode         = opcode;
                instruction.MnemonicInstuc = "JP " + nnn;
                instruction.Description    = "Jumps to address " + nnn;
                break;

            case 0x2:    //Calls subroutine at NNN.
                instruction.AddrOfInstruc  = addr;
                instruction.Opcode         = opcode;
                instruction.MnemonicInstuc = "CALL " + nnn;
                instruction.Description    = "Calls subroutine at " + nnn;
                break;

            case 0x3:    //3XNN	Skips the next instruction if VX equals NN.
                instruction.AddrOfInstruc  = addr;
                instruction.Opcode         = opcode;
                instruction.MnemonicInstuc = "SE V" + x + ", " + nn;
                instruction.Description    = "Skips the next instruction if V" + x + " equals " + nn;
                break;

            case 0x4:    //4XNN	Skips the next instruction if VX doesn't equal NN.
                instruction.AddrOfInstruc  = addr;
                instruction.Opcode         = opcode;
                instruction.MnemonicInstuc = "SNE V" + x + ", " + nn;
                instruction.Description    = "Skips the next instruction if V" + x + " doesn't equal " + nn;
                break;

            case 0x5:    //5XY0	Skips the next instruction if VX equals VY.
                instruction.AddrOfInstruc  = addr;
                instruction.Opcode         = opcode;
                instruction.MnemonicInstuc = "SE V" + x + ", " + "V" + y;
                instruction.Description    = "Skips the next instruction if V" + x + " equals " + "V" + y;
                break;

            case 0x6:    //6XNN Sets VX to NNX to NN.
                instruction.AddrOfInstruc  = addr;
                instruction.Opcode         = opcode;
                instruction.MnemonicInstuc = "LD V" + x + ", " + nn;
                instruction.Description    = "Sets V" + x + " to " + nn;
                break;

            case 0x7:    //7XNN	Adds NN to VX.
                instruction.AddrOfInstruc  = addr;
                instruction.Opcode         = opcode;
                instruction.MnemonicInstuc = "ADD V" + x + ", " + nn;
                instruction.Description    = "Adds " + nn + " to " + "V" + x;
                break;

            case 0x8:
            {
                switch (Utli.getLowerByteLowNibble(opcode))
                {
                case 0x0:            //	8XY0 Sets VX to the value of VY.
                    instruction.AddrOfInstruc  = addr;
                    instruction.Opcode         = opcode;
                    instruction.MnemonicInstuc = "LD V" + x + ", " + "V" + y;
                    instruction.Description    = "Sets V" + x + " to the value " + "V" + y;
                    break;

                case 0x1:            //	8XY1 Sets VX to VX or VY.
                    instruction.AddrOfInstruc  = addr;
                    instruction.Opcode         = opcode;
                    instruction.MnemonicInstuc = "OR V" + x + ", " + "V" + y;
                    instruction.Description    = "Sets V" + x + " to " + "V" + x + " or " + "V" + y;
                    break;

                case 0x2:            //	8XY2 Sets VX to VX and VY.
                    instruction.AddrOfInstruc  = addr;
                    instruction.Opcode         = opcode;
                    instruction.MnemonicInstuc = "AND V" + x + ", " + "V" + y;
                    instruction.Description    = "Sets V" + x + " to " + "V" + x + " and " + "V" + y;
                    break;

                case 0x3:            //	8XY3 Sets VX to VX xor VY.
                    instruction.AddrOfInstruc  = addr;
                    instruction.Opcode         = opcode;
                    instruction.MnemonicInstuc = "XOR V" + x + ", " + "V" + y;
                    instruction.Description    = "Sets V" + x + " to " + "V" + x + " xor " + "V" + y;
                    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.
                {
                    instruction.AddrOfInstruc  = addr;
                    instruction.Opcode         = opcode;
                    instruction.MnemonicInstuc = "ADD V" + x + ", " + "V" + y;
                    instruction.Description    = "Adds V" + y + " to " + "V" + x;
                }
                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.
                {
                    instruction.AddrOfInstruc  = addr;
                    instruction.Opcode         = opcode;
                    instruction.MnemonicInstuc = "SUB V" + x + ", " + "V" + y;
                    instruction.Description    = "V" + y + " is subtracted from " + "V" + x;
                }
                break;

                case 0x6:            //8XY6 Shifts VX right by one.
                                     // VF is set to the value of the least significant bit of VX before the shift.
                {
                    instruction.AddrOfInstruc  = addr;
                    instruction.Opcode         = opcode;
                    instruction.MnemonicInstuc = "SHR V" + x + "{, " + "V" + y + "}";
                    instruction.Description    = "Shifts " + "V" + x + "right by one. " + " VF is set to the value of the least significant bit of "
                                                 + "V" + x + " before the shift";
                }
                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.
                {
                    instruction.AddrOfInstruc  = addr;
                    instruction.Opcode         = opcode;
                    instruction.MnemonicInstuc = "SUBN V" + x + ", " + "V" + y;
                    instruction.Description    = "Sets V" + x + " to " + "V" + y + " minus " + "V" + x;
                }
                break;

                case 0xE:            //8XYE	Shifts VX left by one. VF is set to the value of the
                                     // most significant bit of VX before the shift.
                {
                    instruction.AddrOfInstruc  = addr;
                    instruction.Opcode         = opcode;
                    instruction.MnemonicInstuc = "SHL V" + x + "{, " + "V" + y + "}";
                    instruction.Description    = "Shifts " + "V" + x + "left by one. " + " VF is set to the value of the most significant bit of "
                                                 + "V" + x + " before the shift";
                }
                break;

                default:
                    instruction.AddrOfInstruc  = addr;
                    instruction.Opcode         = opcode;
                    instruction.MnemonicInstuc = "UNKNOWN";
                    instruction.Description    = "Unimplemented Opcode - " + "0x" + opcode.ToString("x2");
                    break;
                }
            }
            break;

            case 0x9:    //9XY0	Skips the next instruction if VX doesn't equal VY.
                instruction.AddrOfInstruc  = addr;
                instruction.Opcode         = opcode;
                instruction.MnemonicInstuc = "SNE V" + x + ", " + "V" + y;
                instruction.Description    = "Skips the next instruction if V" + x + " dosen't equal " + "V" + y;
                break;

            case 0xA:    //ANNN	Sets Ireg to the address NNN.
                instruction.AddrOfInstruc  = addr;
                instruction.Opcode         = opcode;
                instruction.MnemonicInstuc = "LD I, " + nnn;
                instruction.Description    = "Sets Ireg to the address " + nnn;
                break;

            case 0xB:    //BNNN	Jumps to the address NNN plus V0.
                instruction.AddrOfInstruc  = addr;
                instruction.Opcode         = opcode;
                instruction.MnemonicInstuc = "JP V0, " + nnn;
                instruction.Description    = "Jumps to the address " + nnn + " plus V0";
                break;

            case 0xC:    //CXNN	Sets VX to the result of a bitwise and operation on a random number and NN.
                instruction.AddrOfInstruc  = addr;
                instruction.Opcode         = opcode;
                instruction.MnemonicInstuc = "RND V" + x + ", " + nn;
                instruction.Description    = "Sets V" + x + " to the result of a bitwise and operation on a random number and " + nn;
                break;

            case 0xD:
            {
                //DXYN	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 Ireg;
                // Ireg 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
                instruction.AddrOfInstruc  = addr;
                instruction.Opcode         = opcode;
                instruction.MnemonicInstuc = "DRW V" + x + ", " + "V" + y + ", " + n;
                instruction.Description    = "Draws a spirte at (V" + x + ", V" + y + ")" + " that has a width of 8 pixels and a height of " + n + "pixels";
            }
            break;

            case 0xE:
            {
                switch (Utli.getLowerByte(opcode))
                {
                case 0x9E:            //EX9E Skips the next instruction if the key stored in VX is pressed.
                    instruction.AddrOfInstruc  = addr;
                    instruction.Opcode         = opcode;
                    instruction.MnemonicInstuc = "SKP V" + x;
                    instruction.Description    = "Skips the next instruction if the key stored in V" + x + " is pressed";
                    break;

                case 0xA1:            //EXA1 Skips the next instruction if the key stored in VX isn't pressed.
                    instruction.AddrOfInstruc  = addr;
                    instruction.Opcode         = opcode;
                    instruction.MnemonicInstuc = "SKNP V" + x;
                    instruction.Description    = "Skips the next instruction if the key stored in V" + x + " isn't pressed";
                    break;

                default:
                    instruction.AddrOfInstruc  = addr;
                    instruction.Opcode         = opcode;
                    instruction.MnemonicInstuc = "UNKNOWN";
                    instruction.Description    = "Unimplemented Opcode - " + "0x" + opcode.ToString("x2");
                    break;
                }
            }
            break;

            case 0xF:
            {
                switch (Utli.getLowerByte(opcode))
                {
                case 0x07:            //FX07  Sets VX to the value of the delay timer.
                    instruction.AddrOfInstruc  = addr;
                    instruction.Opcode         = opcode;
                    instruction.MnemonicInstuc = "LD V" + x + ", DT";
                    instruction.Description    = "Sets V" + x + " to the value of the delay timer.";
                    break;

                case 0x0A:            //FX0A  A key press is awaited, and then stored in VX.
                {
                    instruction.AddrOfInstruc  = addr;
                    instruction.Opcode         = opcode;
                    instruction.MnemonicInstuc = "LD V" + x + ", K";
                    instruction.Description    = "All execution stops until a key is pressed, then the value of that key is stored in V" + x;
                }
                break;

                case 0x15:            //	FX15 Sets the delay timer to VX.
                    instruction.AddrOfInstruc  = addr;
                    instruction.Opcode         = opcode;
                    instruction.MnemonicInstuc = "LD DT, V" + x;
                    instruction.Description    = "Sets the delay timer to V" + x;
                    break;

                case 0x18:            //	FX18 Sets the sound timer to VX.
                    instruction.AddrOfInstruc  = addr;
                    instruction.Opcode         = opcode;
                    instruction.MnemonicInstuc = "LD ST, V" + x;
                    instruction.Description    = "Sets the sound timer to V" + x;
                    break;

                case 0x1E:             //FX1E Adds VX to Ireg.
                    instruction.AddrOfInstruc  = addr;
                    instruction.Opcode         = opcode;
                    instruction.MnemonicInstuc = "ADD I, V" + x;
                    instruction.Description    = "Adds V" + x + " to Ireg.";
                    break;

                case 0x29:            //FX29 Sets Ireg to the location of the sprite for the character in VX.
                                      // Characters 0-F (in hexadecimal) are represented by a 4x5 font.
                    instruction.AddrOfInstruc  = addr;
                    instruction.Opcode         = opcode;
                    instruction.MnemonicInstuc = "LD F, V" + x;
                    instruction.Description    = "Sets Ireg to the location of the sprite for character in V" + x;
                    break;

                case 0x33:            //FX33 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.
                    instruction.AddrOfInstruc  = addr;
                    instruction.Opcode         = opcode;
                    instruction.MnemonicInstuc = "LD B, V" + x;
                    instruction.Description    = "Stores the binary-coded decimal representation of V" + x + "(I, I+1, I+2)";
                    break;

                case 0x55:            //FX55 Stores V0 to VX (including VX) in memory starting at address Ireg.
                                      //I is set to I + X + 1 after operation
                    instruction.AddrOfInstruc  = addr;
                    instruction.Opcode         = opcode;
                    instruction.MnemonicInstuc = "LD [I], V" + x;
                    instruction.Description    = "Stores V0 to V" + x + " (including V" + x + ") in memory starting at address Ireg";
                    break;

                case 0x65:            //FX65 Fills V0 to VX (including VX) with values from memory starting at address Ireg.
                    instruction.AddrOfInstruc  = addr;
                    instruction.Opcode         = opcode;
                    instruction.MnemonicInstuc = "LD V" + x + ", [I]";
                    instruction.Description    = "Fills V0 to V" + x + " (including V" + x + ") with values from memory starting at address Ireg";
                    break;

                default:
                    instruction.AddrOfInstruc  = addr;
                    instruction.Opcode         = opcode;
                    instruction.MnemonicInstuc = "UNKNOWN";
                    instruction.Description    = "Unimplemented Opcode - " + "0x" + opcode.ToString("x2");
                    break;
                }
            }
            break;

            default:
                instruction.AddrOfInstruc  = addr;
                instruction.Opcode         = opcode;
                instruction.MnemonicInstuc = "UNKNOWN";
                instruction.Description    = "Unimplemented Opcode - " + "0x" + opcode.ToString("x2");
                break;
            }

            return(instruction);
        }