/// <summary> /// Tells the module to begin x86 execution at the specified Entry Point /// </summary> /// <param name="entryPoint">Entry Point where execution will begin</param> /// <param name="channelNumber">Channel Number calling for execution</param> /// <param name="simulateCallFar">Are we simulating a CALL FAR? This is usually when we're calling a local function pointer</param> /// <param name="bypassSetState">Should we bypass setting a startup state? This is true for execution of things like Text Variable processing</param> /// <param name="initialStackValues">Initial Stack Values to be pushed to the stack prior to executing (simulating parameters on a method call)</param> /// <param name="initialStackPointer"> /// Initial Stack Pointer Value. Because EU's share the same memory space, including stack space, we need to sometimes need to manually decrement the /// stack pointer enough to where the stack on the nested call won't overlap with the stack on the parent caller. /// </param> /// <returns></returns> public CpuRegisters Execute(FarPtr entryPoint, ushort channelNumber, bool simulateCallFar = false, bool bypassSetState = false, Queue <ushort> initialStackValues = null, ushort initialStackPointer = CpuCore.STACK_BASE) { //Set the proper DLL making the call based on the Segment for (ushort i = 0; i < ModuleDlls.Count; i++) { var dll = ModuleDlls[i]; if (entryPoint.Segment >= dll.SegmentOffset && entryPoint.Segment <= (dll.SegmentOffset + dll.File.SegmentTable.Count)) { foreach (var(_, value) in ExportedModuleDictionary) { ((ExportedModuleBase)value).ModuleDll = i; } } } //Try to dequeue an execution unit, if one doesn't exist, create a new one if (!ExecutionUnits.TryDequeue(out var executionUnit)) { _logger.Debug($"({ModuleIdentifier}) Exhausted execution Units, creating additional"); executionUnit = new ExecutionUnit(Memory, _clock, ExportedModuleDictionary, _logger, ModulePath); } var resultRegisters = executionUnit.Execute(entryPoint, channelNumber, simulateCallFar, bypassSetState, initialStackValues, initialStackPointer); ExecutionUnits.Enqueue(executionUnit); return(resultRegisters); }
/// <summary> /// Tells the module to begin x86 execution at the specified Entry Point /// </summary> /// <param name="entryPoint">Entry Point where execution will begin</param> /// <param name="channelNumber">Channel Number calling for execution</param> /// <param name="simulateCallFar">Are we simulating a CALL FAR? This is usually when we're calling a local function pointer</param> /// <param name="bypassSetState">Should we bypass setting a startup state? This is true for execution of things like Text Variable processing</param> /// <param name="initialStackValues">Initial Stack Values to be pushed to the stack prior to executing (simulating parameters on a method call)</param> /// <param name="initialStackPointer"> /// Initial Stack Pointer Value. Because EU's share the same memory space, including stack space, we need to sometimes need to manually decrement the /// stack pointer enough to where the stack on the nested call won't overlap with the stack on the parent caller. /// </param> /// <returns></returns> public CpuRegisters Execute(IntPtr16 entryPoint, ushort channelNumber, bool simulateCallFar = false, bool bypassSetState = false, Queue <ushort> initialStackValues = null, ushort initialStackPointer = CpuCore.STACK_BASE) { //Try to dequeue an execution unit, if one doesn't exist, create a new one if (!ExecutionUnits.TryDequeue(out var executionUnit)) { _logger.Warn($"{ModuleIdentifier} exhausted execution Units, creating additional"); executionUnit = new ExecutionUnit(Memory, ExportedModuleDictionary); } var resultRegisters = executionUnit.Execute(entryPoint, channelNumber, simulateCallFar, bypassSetState, initialStackValues, initialStackPointer); ExecutionUnits.Enqueue(executionUnit); return(resultRegisters); }