Esempio n. 1
0
        /// <summary>
        /// Get the amount of ticks to be run before the opcode execution
        /// </summary>
        /// <returns>cpu ticks</returns>
        private byte GetPreClocks()
        {
            byte ticks = 0;

            // We return the ticks that the instruction took
            if (!_state.CurrentInstruction.CB)
            {
                ticks = CPUInstructionPreClocks.Get((byte)_state.CurrentInstruction.OpCode);
            }
            else
            {
                ticks = CPUCBInstructionPreClocks.Get((byte)_state.CurrentInstruction.OpCode);
            }
            return(ticks);
        }
Esempio n. 2
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);
        }
Esempio n. 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);
        }