private static ushort GetOperandRawValue(SimulationContext context, Operand operand) { if (operand is Operand <Register8> ) { return(context.GetRegister8(((Operand <Register8>)operand).Value)); } else if (operand is Operand <Register16> ) { return(context.GetRegister16(((Operand <Register16>)operand).Value)); } else if (operand is Operand <byte> ) { return(((Operand <byte>)operand).Value); } else if (operand is Operand <ushort> ) { return(((Operand <ushort>)operand).Value); } else if (operand is Operand <sbyte> ) { if (operand.IsDirect) { return((ushort)(context.SP + ((Operand <sbyte>)operand).Value)); } else { return((ushort)(short)((Operand <sbyte>)operand).Value); } } else { throw new InvalidOperationException(); } }
public SimulationContext(SimulationContext source) { a = source.a; b = source.b; c = source.c; d = source.d; e = source.e; f = source.f; h = source.h; l = source.l; sp = source.sp; pc = source.pc; romBank = source.romBank; }
private static ushort GetOperandRawValue(SimulationContext context, Operand operand) { if (operand is Operand<Register8>) return context.GetRegister8(((Operand<Register8>)operand).Value); else if (operand is Operand<Register16>) return context.GetRegister16(((Operand<Register16>)operand).Value); else if (operand is Operand<byte>) return ((Operand<byte>)operand).Value; else if (operand is Operand<ushort>) return ((Operand<ushort>)operand).Value; else if (operand is Operand<sbyte>) { if (operand.IsDirect) return (ushort)(context.SP + ((Operand<sbyte>)operand).Value); else return (ushort)(short)((Operand<sbyte>)operand).Value; } else throw new InvalidOperationException(); }
/// <summary> /// Runs a dynamic analyzis. /// This is currently implemented as a dumb simulation process /// Every memory operations are ignored except for ROM and HRAM /// Reads on ROM will work as expected /// Memory bank switching will work as expected, and unresolved ROM calls will be resolved when possible /// Memory copies between ROM and HRAM will be tracked, and thus HRAM calls will be remapped to ROM calls /// </summary> /// <remarks>The analyzis ends once all jumps are resolved</remarks> /// <param name="functionPointerStack">Stack containing the entry points to analyze</param> private void DynamicAnalyze(Stack<Label> entryPointStack) { Stack<SimulationContext> contextStack = new Stack<SimulationContext>(); while (entryPointStack.Count > 0) { SimulationContext currentContext = new SimulationContext(); Label entryPointLabel = entryPointStack.Pop(); int instructionIndex = -1; currentContext.PC = entryPointLabel.Offset; contextStack.Push(currentContext); while (contextStack.Count > 0) { Instruction instruction; Operand operand1, operand2; ushort rawValue1, rawValue2; ushort value1, value2; bool byteOperation; currentContext = contextStack.Peek(); if (instructionIndex < 0) instructionIndex = instructionList.FindIndex(i => i.Offset == currentContext.PC); instruction = instructionList[instructionIndex]; currentContext.PC = instruction.Offset; if (instruction is FlowControlInstruction) { Condition condition = ((FlowControlInstruction)instruction).Condition; // Skips conditional instructions when the condition is false if (condition == Condition.Never || condition == Condition.NotZero && currentContext.ZeroFlag || condition == Condition.Zero && !currentContext.ZeroFlag || condition == Condition.CarryClear && currentContext.CarryFlag || condition == Condition.CarrySet && !currentContext.CarryFlag) goto NextInstruction; } else if (instruction is BinaryInstruction) { operand1 = ((BinaryInstruction)instruction).Destination; operand2 = ((BinaryInstruction)instruction).Source; rawValue1 = GetOperandRawValue(currentContext, operand1); rawValue2 = GetOperandRawValue(currentContext, operand1); byteOperation = Operand.IsByteOperand(operand1) && Operand.IsByteOperand(operand2); } else if (instruction is UnaryInstruction) { operand1 = ((BinaryInstruction)instruction).Destination; byteOperation = Operand.IsByteOperand(operand1); } if (instruction is LoadInstruction) { } else if (instruction is JumpInstruction) { } else if (instruction is ReturnInstruction) { if (((ReturnInstruction)instruction).Condition == Condition.Always) contextStack.Pop(); } NextInstruction: if (instructionIndex > 0) { instructionIndex++; if (instructionIndex >= instructionList.Count) throw new InvalidOperationException(); } } } }
/// <summary> /// Runs a dynamic analyzis. /// This is currently implemented as a dumb simulation process /// Every memory operations are ignored except for ROM and HRAM /// Reads on ROM will work as expected /// Memory bank switching will work as expected, and unresolved ROM calls will be resolved when possible /// Memory copies between ROM and HRAM will be tracked, and thus HRAM calls will be remapped to ROM calls /// </summary> /// <remarks>The analyzis ends once all jumps are resolved</remarks> /// <param name="functionPointerStack">Stack containing the entry points to analyze</param> private void DynamicAnalyze(Stack <Label> entryPointStack) { Stack <SimulationContext> contextStack = new Stack <SimulationContext>(); while (entryPointStack.Count > 0) { SimulationContext currentContext = new SimulationContext(); Label entryPointLabel = entryPointStack.Pop(); int instructionIndex = -1; currentContext.PC = entryPointLabel.Offset; contextStack.Push(currentContext); while (contextStack.Count > 0) { Instruction instruction; Operand operand1, operand2; ushort rawValue1, rawValue2; ushort value1, value2; bool byteOperation; currentContext = contextStack.Peek(); if (instructionIndex < 0) { instructionIndex = instructionList.FindIndex(i => i.Offset == currentContext.PC); } instruction = instructionList[instructionIndex]; currentContext.PC = instruction.Offset; if (instruction is FlowControlInstruction) { Condition condition = ((FlowControlInstruction)instruction).Condition; // Skips conditional instructions when the condition is false if (condition == Condition.Never || condition == Condition.NotZero && currentContext.ZeroFlag || condition == Condition.Zero && !currentContext.ZeroFlag || condition == Condition.CarryClear && currentContext.CarryFlag || condition == Condition.CarrySet && !currentContext.CarryFlag) { goto NextInstruction; } } else if (instruction is BinaryInstruction) { operand1 = ((BinaryInstruction)instruction).Destination; operand2 = ((BinaryInstruction)instruction).Source; rawValue1 = GetOperandRawValue(currentContext, operand1); rawValue2 = GetOperandRawValue(currentContext, operand1); byteOperation = Operand.IsByteOperand(operand1) && Operand.IsByteOperand(operand2); } else if (instruction is UnaryInstruction) { operand1 = ((BinaryInstruction)instruction).Destination; byteOperation = Operand.IsByteOperand(operand1); } if (instruction is LoadInstruction) { } else if (instruction is JumpInstruction) { } else if (instruction is ReturnInstruction) { if (((ReturnInstruction)instruction).Condition == Condition.Always) { contextStack.Pop(); } } NextInstruction: if (instructionIndex > 0) { instructionIndex++; if (instructionIndex >= instructionList.Count) { throw new InvalidOperationException(); } } } } }