/// <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); }
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); }
/// <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); }