1 package net.mograsim.plugin.launch;
3 import java.util.ArrayList;
5 import java.util.function.Consumer;
7 import org.eclipse.core.resources.IMarkerDelta;
8 import org.eclipse.core.runtime.IStatus;
9 import org.eclipse.core.runtime.PlatformObject;
10 import org.eclipse.core.runtime.Status;
11 import org.eclipse.debug.core.DebugEvent;
12 import org.eclipse.debug.core.DebugException;
13 import org.eclipse.debug.core.DebugPlugin;
14 import org.eclipse.debug.core.ILaunch;
15 import org.eclipse.debug.core.ILaunchConfiguration;
16 import org.eclipse.debug.core.model.IBreakpoint;
17 import org.eclipse.debug.core.model.IDebugElement;
18 import org.eclipse.debug.core.model.IDebugTarget;
19 import org.eclipse.debug.core.model.IMemoryBlock;
20 import org.eclipse.debug.core.model.IMemoryBlockExtension;
21 import org.eclipse.debug.core.model.IMemoryBlockRetrievalExtension;
22 import org.eclipse.debug.core.model.IProcess;
23 import org.eclipse.debug.core.model.IStepFilters;
24 import org.eclipse.debug.core.model.IThread;
26 import net.mograsim.logic.model.LogicExecuter;
27 import net.mograsim.machine.Machine;
28 import net.mograsim.machine.MachineDefinition;
29 import net.mograsim.plugin.MograsimActivator;
30 import net.mograsim.plugin.launch.MachineLaunchConfigType.MachineLaunchParams;
32 public class MachineDebugTarget extends PlatformObject implements IDebugTarget, IMemoryBlockRetrievalExtension
34 private final static boolean USE_PSEUDO_THREAD = true;
36 private final ILaunch launch;
37 private final Machine machine;
38 private final LogicExecuter exec;
39 private final MachineThread thread;
41 private boolean running;
43 private final List<Consumer<Double>> executionSpeedListeners;
45 private final MachineLaunchParams launchParams;
47 public MachineDebugTarget(ILaunch launch, MachineLaunchParams launchParams, MachineDefinition machineDefinition)
50 this.machine = machineDefinition.createNew();
51 this.exec = new LogicExecuter(machine.getTimeline());
53 this.executionSpeedListeners = new ArrayList<>();
54 this.launchParams = launchParams;
56 exec.startLiveExecution();
59 getLaunch().addDebugTarget(this);
62 // create after creating ourself
63 this.thread = USE_PSEUDO_THREAD ? new MachineThread(this) : null;
66 public Machine getMachine()
72 public String getName() throws DebugException
74 return "Mograsim machine \"" + machine.getDefinition().getId() + '"';
78 public String getModelIdentifier()
80 return MograsimActivator.PLUGIN_ID;
84 public IDebugTarget getDebugTarget()
90 public ILaunch getLaunch()
95 public MachineLaunchParams getLaunchParams()
100 public double getExecutionSpeed()
102 return exec.getSpeedFactor();
105 public void setExecutionSpeed(double speed)
107 if (getExecutionSpeed() != speed)
109 exec.setSpeedFactor(speed);
110 callExecutionSpeedListener(speed);
115 public boolean isSuspended()
117 return exec.isPaused();
121 public boolean canSuspend()
123 return !isTerminated() && !isSuspended();
127 public void suspend() throws DebugException
130 throwDebugException("Can't suspend a terminated MachineProcess");
132 throwDebugException("Can't suspend a suspended MachineProcess");
134 exec.pauseLiveExecution();
135 fireSuspendEvent(DebugEvent.CLIENT_REQUEST);
139 public boolean canResume()
141 return !isTerminated() && isSuspended();
145 public void resume() throws DebugException
148 throwDebugException("Can't resume a terminated MachineProcess");
150 throwDebugException("Can't resume a non-suspended MachineProcess");
152 exec.unpauseLiveExecution();
153 fireResumeEvent(DebugEvent.CLIENT_REQUEST);
157 public boolean isTerminated()
163 public boolean canTerminate()
165 return !isTerminated();
169 public void terminate() throws DebugException
174 exec.stopLiveExecution();
176 fireTerminateEvent();
180 public boolean supportsBreakpoint(IBreakpoint breakpoint)
186 public void breakpointAdded(IBreakpoint breakpoint)
188 // ignore; we don't support breakpoints
192 public void breakpointRemoved(IBreakpoint breakpoint, IMarkerDelta delta)
194 // ignore; we don't support breakpoints
198 public void breakpointChanged(IBreakpoint breakpoint, IMarkerDelta delta)
200 // ignore; we don't support breakpoints
204 public boolean isDisconnected()
210 public boolean canDisconnect()
216 public void disconnect() throws DebugException
218 throw new DebugException(new Status(IStatus.ERROR, MograsimActivator.PLUGIN_ID, DebugException.NOT_SUPPORTED,
219 "Can't disconnect from a MachineDebugTarget", null));
223 public boolean supportsStorageRetrieval()
228 @SuppressWarnings("deprecation") // TODO can we throw a DebugException instead?
230 public IMemoryBlock getMemoryBlock(long startAddress, long length) throws DebugException
232 return new MainMemoryBlock(this, startAddress, length);
236 public IMemoryBlockExtension getExtendedMemoryBlock(String expression, Object context) throws DebugException
238 return new MainMemoryBlockExtension(this, expression, context);
242 public IProcess getProcess()
248 public boolean hasThreads() throws DebugException
250 return USE_PSEUDO_THREAD;
254 public IThread[] getThreads() throws DebugException
256 return thread == null ? new IThread[0] : new IThread[] { thread };
259 public void addExecutionSpeedListener(Consumer<Double> executionSpeedListener)
261 executionSpeedListeners.add(executionSpeedListener);
264 public void removeExecutionSpeedListener(Consumer<Double> executionSpeedListener)
266 executionSpeedListeners.remove(executionSpeedListener);
269 private void callExecutionSpeedListener(double executionSpeed)
271 executionSpeedListeners.forEach(l -> l.accept(executionSpeed));
274 @SuppressWarnings("unchecked")
276 public <T> T getAdapter(Class<T> adapter)
278 if (adapter == IDebugElement.class)
281 // leave this here; maybe we implement IStepFilters someday
282 if (adapter == IStepFilters.class)
283 if (this instanceof IStepFilters)
284 return (T) getDebugTarget();
286 if (adapter == IDebugTarget.class)
287 return (T) getDebugTarget();
289 if (adapter == ILaunch.class)
290 return (T) getLaunch();
293 if (adapter == ILaunchConfiguration.class)
294 return (T) getLaunch().getLaunchConfiguration();
296 return super.getAdapter(adapter);
300 * Fires a creation event for this debug element.
302 private void fireCreationEvent()
304 fireEvent(new DebugEvent(this, DebugEvent.CREATE));
308 * Fires a resume for this debug element with the specified detail code.
310 * @param detail detail code for the resume event, such as <code>DebugEvent.STEP_OVER</code>
312 private void fireResumeEvent(int detail)
314 fireEvent(new DebugEvent(this, DebugEvent.RESUME, detail));
318 * Fires a suspend event for this debug element with the specified detail code.
320 * @param detail detail code for the suspend event, such as <code>DebugEvent.BREAKPOINT</code>
322 private void fireSuspendEvent(int detail)
324 fireEvent(new DebugEvent(this, DebugEvent.SUSPEND, detail));
328 * Fires a terminate event for this debug element.
330 private void fireTerminateEvent()
332 fireEvent(new DebugEvent(this, DebugEvent.TERMINATE));
336 * Fires a debug event.
338 * @param event debug event to fire
340 private static void fireEvent(DebugEvent event)
342 DebugPlugin.getDefault().fireDebugEventSet(new DebugEvent[] { event });
345 private static void throwDebugException(String message) throws DebugException
347 throw new DebugException(
348 new Status(IStatus.ERROR, MograsimActivator.PLUGIN_ID, DebugException.TARGET_REQUEST_FAILED, message, null));