Example #1
0
        private Instruction InterruptHandler(Interrupts interrupt)
        {
            // Handle interrupt with a CALL instruction to the interrupt handler
            Instruction instruction = new Instruction();

            instruction.OpCode = 0xCD; // CALL!
            byte lowOpcode = (byte)instruction.OpCode;

            instruction.Length      = CPUInstructionLengths.Get(lowOpcode);
            instruction.Literal     = this.interruptHandlers[(Interrupts)interrupt];
            instruction.Ticks       = CPUInstructionPreClocks.Get(lowOpcode);
            instruction.Name        = CPUInstructionNames.Get(lowOpcode);
            instruction.Description = CPUInstructionDescriptions.Get(lowOpcode);

            // Disable interrupts during interrupt handling and clear the current one
            this._interruptController.InterruptMasterEnable = false;
            byte IF = this._memory.LowLevelRead((ushort)MMR.IF);

            IF &= (byte)~(byte)interrupt;
            this._memory.LowLevelWrite((ushort)MMR.IF, IF);
            return(instruction);
        }
Example #2
0
        /// <summary>
        /// Poor man's dissambly (for now)
        /// </summary>
        /// <returns></returns>
        public IEnumerable <IInstruction> Disassamble(ushort startAddress, bool permissive = true)
        {
            // TODO(Cristian): Complete the on-demand disassembly
            var stoppers = GetShowStoppers();
            var dirJumps = GetDirectJumps();
            var relJumps = GetRelativeJumps();
            var restarts = GetRestarts();

            _disAddressToVisit.Push(startAddress); // Initial address

            while (_disAddressToVisit.Count > 0)
            {
                ushort address = _disAddressToVisit.Pop();
                // If we already saw this address, we move on
                if (_disVisitedAddresses.Contains(address))
                {
                    continue;
                }
                _disVisitedAddresses.Add(address);

                // NOTE(Cristian): The 0xCB external opcodes all exists, so we just need to check
                //                 that the first byte is 0xCB to know that the instruction is valid
                if (CPUInstructionLengths.Get((byte)_memory.Read(address)) != 0)
                {
                    try
                    {
                        // Get the instruction and added to the instruction list
                        //var inst = _cpu.FetchAndDecode(address);
                        // TODO(Cristian): This code will NOT work!
                        Instruction inst = null;
                        _disInstructions.Add(inst);

                        // We get a list of possible next addresses to check
                        var candidates = new List <ushort>();

                        // A show-stopper doesn't add any more instructions
                        if (stoppers.Contains(inst.OpCode))
                        {
                            continue;
                        }

                        if (dirJumps.ContainsKey(inst.OpCode))
                        {
                            //if(dirJumps[inst.OpCode])
                            //{
                            //  candidates.Add(inst.Literal);
                            //}
                            //// If permissive, we also permit conditional jumps (ant the next inst)
                            //else if(permissive)
                            //{
                            //  candidates.Add(inst.Literal);
                            //  var next = (ushort)(address + inst.Length);
                            //  candidates.Add(next);
                            //}
                        }

                        else if (relJumps.ContainsKey(inst.OpCode))
                        {
                            //if(relJumps[inst.OpCode])
                            //{
                            //  sbyte signedLiteral;
                            //  unchecked { signedLiteral = (sbyte)inst.Literal; }
                            //  ushort target = (ushort)(inst.Address + signedLiteral + inst.Length);
                            //  candidates.Add(target);
                            //}
                            //else if(permissive)
                            //{
                            //  sbyte signedLiteral;
                            //  unchecked { signedLiteral = (sbyte)inst.Literal; }
                            //  ushort target = (ushort)(inst.Address + signedLiteral + inst.Length);
                            //  candidates.Add(target);

                            //  var next = (ushort)(address + inst.Length);
                            //  candidates.Add(next);
                            //}
                        }
                        else if (restarts.ContainsKey(inst.OpCode))
                        {
                            candidates.Add(restarts[inst.OpCode]);
                        }
                        else // It's an instruction that continues
                        {
                            ushort target = (ushort)(address + inst.Length);
                            candidates.Add(target);
                        }

                        // We add the candidate instructions into the list
                        foreach (var candidateNextInstruction in candidates)
                        {
                            // If any of the candidates was already visited, we do not visit it
                            if (_disVisitedAddresses.Contains(candidateNextInstruction))
                            {
                                continue;
                            }
                            _disAddressToVisit.Push(candidateNextInstruction);
                        }
                    }
                    catch (Exception)
                    {
                    }
                }
            }
            return(_disInstructions.OrderBy(i => i.Address));
        }
Example #3
0
        /// <summary>
        /// Fetches and Decodes an instruction
        /// </summary>
        /// <param name="instruction">
        /// As FetchAndDecode gets called *several* times a frame (and many times during
        /// disassembly), it is better to have a pre-allocated instruction and to replace
        /// the values, instead of getting the overhead of allocating a new Instrucion
        /// everytime.
        /// </param>
        /// <param name="instructionAddress"></param>
        /// <param name="haltLoad"></param>
        /// <returns></returns>
        internal Instruction FetchAndDecode(ref Instruction instruction,
                                            ushort instructionAddress, bool haltLoad = false)
        {
            instruction.Address = instructionAddress;
            byte opcode = this._memory.LowLevelRead(instructionAddress);

            instruction.OpCode = opcode;

            if (instruction.OpCode != 0xCB)
            {
                instruction.CB = false;
                byte lowOpcode = (byte)instruction.OpCode;
                if (_instructionHistogram[lowOpcode] < ushort.MaxValue)
                {
                    _instructionHistogram[lowOpcode]++;
                }
                // Normal instructions
                instruction.Length = CPUInstructionLengths.Get(lowOpcode);

                // Extract literal
                if (instruction.Length == 2)
                {
                    // 8 bit literal
                    instruction.Operands[0] = this._memory.LowLevelRead((ushort)(instructionAddress + 1));
                    if (haltLoad)
                    {
                        instruction.Operands[0] = opcode;
                    }
                    instruction.Literal = (byte)instruction.Operands[0];
                }
                else if (instruction.Length == 3)
                {
                    // 16 bit literal, little endian
                    instruction.Operands[0] = this._memory.LowLevelRead((ushort)(instructionAddress + 2));
                    instruction.Operands[1] = this._memory.LowLevelRead((ushort)(instructionAddress + 1));

                    if (haltLoad)
                    {
                        instruction.Operands[1] = instruction.Operands[0];
                        instruction.Operands[0] = opcode;
                    }

                    instruction.Literal  = (byte)instruction.Operands[1];
                    instruction.Literal += (ushort)(instruction.Operands[0] << 8);
                }

                instruction.Ticks       = CPUInstructionPreClocks.Get(lowOpcode);
                instruction.Name        = CPUInstructionNames.Get(lowOpcode);
                instruction.Description = CPUInstructionDescriptions.Get(lowOpcode);
            }
            else
            {
                instruction.CB = true;
                // CB instructions block
                instruction.OpCode <<= 8;
                if (!haltLoad)
                {
                    instruction.OpCode += this._memory.LowLevelRead((ushort)(instructionAddress + 1));
                }
                else
                {
                    instruction.OpCode += 0xCB; // The first byte is duplicated
                }

                byte lowOpcode = (byte)instruction.OpCode;

                if (_cbInstructionHistogram[lowOpcode] < ushort.MaxValue)
                {
                    _cbInstructionHistogram[lowOpcode]++;
                }
                instruction.Length = CPUCBInstructionLengths.Get(lowOpcode);
                // There is no literal in CB instructions!

                //instruction.Lambda = this.CBInstructionLambdas[lowOpcode];
                instruction.Ticks       = CPUCBInstructionPreClocks.Get(lowOpcode);
                instruction.Name        = CPUCBInstructionNames.Get(lowOpcode);
                instruction.Description = CPUCBInstructionDescriptions.Get(lowOpcode);
            }

            // NOTE(Cristian): On haltLoad (HALT with IME disabled), the next byte after the HALT opcode
            //                 is "duplicated". This is a hardware bug.
            if (haltLoad)
            {
                instruction.Length--;
            }

            return(instruction);
        }