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); }
public void Dissasemble(ushort currentAddress) { _addressToInstruction = new Dictionary <ushort, InstructionViewModel>(); _addressWithBreakpoints = new Dictionary <ushort, InstructionViewModel>(); _disassembler.PoorManDisassemble(currentAddress); _instructions.Clear(); byte[][] matrix = _disassembler.DisassembledMatrix; int instCount = 0xFFFF; for (int address = 0; address < instCount; ++address) { byte[] entry = matrix[address]; int intLength = entry[0]; bool CB = false; if (intLength == 0) { searchStrings[address] = ""; continue; } string searchString = ""; var vm = new InstructionViewModel(_cpu); // We check the length if (intLength == 1) { vm.Address = "0x" + address.ToString("x2"); vm.originalOpcode = entry[1]; vm.Opcode = "0x" + entry[1].ToString("x2"); vm.Name = CPUInstructionNames.Get(entry[1]); vm.Description = CPUInstructionDescriptions.Get(entry[1]); } else if (intLength == 2) { if (entry[1] != 0xCB) { vm.Address = "0x" + address.ToString("x2"); vm.originalOpcode = entry[1]; vm.Opcode = "0x" + entry[1].ToString("x2"); vm.Name = CPUInstructionNames.Get(entry[1]); vm.Literal = "0x" + entry[2].ToString("x2"); vm.Description = CPUInstructionDescriptions.Get(entry[1]); } else { CB = true; vm.Address = "0x" + address.ToString("x2"); int instOpcode = ((entry[1] << 8) | entry[2]); vm.originalOpcode = (ushort)instOpcode; vm.Opcode = "0x" + instOpcode.ToString("x2"); vm.Name = CPUCBInstructionNames.Get(entry[2]); vm.Literal = "0x" + entry[2].ToString("x2"); vm.Description = CPUCBInstructionDescriptions.Get(entry[2]); } } else { vm.Address = "0x" + address.ToString("x2"); vm.originalOpcode = entry[1]; vm.Opcode = "0x" + entry[1].ToString("x2"); vm.Name = CPUInstructionNames.Get(entry[1]); int literal = ((entry[2] << 8) | entry[3]); vm.Literal = "0x" + literal.ToString("x2"); vm.Description = CPUInstructionDescriptions.Get(entry[1]); } vm.originalAddress = (ushort)address; if (!CB) { vm.Ticks = CPUSpace.Dictionaries.CPUInstructionClocks.Get((byte)vm.originalOpcode); } else { vm.Ticks = CPUSpace.Dictionaries.CPUCBInstructionClocks.Get((byte)vm.originalOpcode); } _instructions.Add(vm); _addressToInstruction[(ushort)address] = vm; vm.BreakpointChanged += Vm_BreakpointChanged; searchString += vm.Address + "_"; searchString += vm.Opcode + "_"; searchString += vm.Name + "_"; searchString += vm.Literal; searchStrings[address] = searchString; if (address == currentAddress) { SelectedInstruction = vm; SetCurrentInstruction(vm); } } // We update the breakpoints List <ushort> execBreakpoints = _cpu.GetBreakpoints(BreakpointKinds.EXECUTION); foreach (ushort breakpointAddress in execBreakpoints) { if (!_addressToInstruction.ContainsKey(breakpointAddress)) { continue; } InstructionViewModel inst = _addressToInstruction[breakpointAddress]; _addressWithBreakpoints[breakpointAddress] = inst; inst.HasBreakpoint = true; } }
/// <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); }