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;
31 public class MachineDebugTarget extends PlatformObject implements IDebugTarget, IMemoryBlockRetrievalExtension
33 private final ILaunch launch;
34 private final Machine machine;
35 private final LogicExecuter exec;
37 private boolean running;
39 private final List<Consumer<Double>> executionSpeedListeners;
41 public MachineDebugTarget(ILaunch launch, MachineDefinition machineDefinition)
44 this.machine = machineDefinition.createNew();
45 this.exec = new LogicExecuter(machine.getTimeline());
47 this.executionSpeedListeners = new ArrayList<>();
49 exec.startLiveExecution();
52 getLaunch().addDebugTarget(this);
56 public Machine getMachine()
62 public String getName() throws DebugException
64 return "Mograsim machine \"" + machine.getDefinition().getId() + '"';
68 public String getModelIdentifier()
70 return MograsimActivator.PLUGIN_ID;
74 public IDebugTarget getDebugTarget()
80 public ILaunch getLaunch()
85 public double getExecutionSpeed()
87 return exec.getSpeedFactor();
90 public void setExecutionSpeed(double speed)
92 if (getExecutionSpeed() != speed)
94 exec.setSpeedFactor(speed);
95 callExecutionSpeedListener(speed);
100 public boolean isSuspended()
102 return exec.isPaused();
106 public boolean canSuspend()
108 return !isTerminated() && !isSuspended();
112 public void suspend() throws DebugException
115 throwDebugException("Can't suspend a terminated MachineProcess");
117 throwDebugException("Can't suspend a suspended MachineProcess");
119 exec.pauseLiveExecution();
120 fireSuspendEvent(DebugEvent.CLIENT_REQUEST);
124 public boolean canResume()
126 return !isTerminated() && isSuspended();
130 public void resume() throws DebugException
133 throwDebugException("Can't resume a terminated MachineProcess");
135 throwDebugException("Can't resume a non-suspended MachineProcess");
137 exec.unpauseLiveExecution();
138 fireResumeEvent(DebugEvent.CLIENT_REQUEST);
142 public boolean isTerminated()
148 public boolean canTerminate()
150 return !isTerminated();
154 public void terminate() throws DebugException
159 exec.stopLiveExecution();
161 fireTerminateEvent();
165 public boolean supportsBreakpoint(IBreakpoint breakpoint)
171 public void breakpointAdded(IBreakpoint breakpoint)
173 // ignore; we don't support breakpoints
177 public void breakpointRemoved(IBreakpoint breakpoint, IMarkerDelta delta)
179 // ignore; we don't support breakpoints
183 public void breakpointChanged(IBreakpoint breakpoint, IMarkerDelta delta)
185 // ignore; we don't support breakpoints
189 public boolean isDisconnected()
195 public boolean canDisconnect()
201 public void disconnect() throws DebugException
203 throw new DebugException(new Status(IStatus.ERROR, MograsimActivator.PLUGIN_ID, DebugException.NOT_SUPPORTED,
204 "Can't disconnect from a MachineDebugTarget", null));
208 public boolean supportsStorageRetrieval()
213 @SuppressWarnings("deprecation") // TODO can we throw a DebugException instead?
215 public IMemoryBlock getMemoryBlock(long startAddress, long length) throws DebugException
217 return new MainMemoryBlock(this, startAddress, length);
221 public IMemoryBlockExtension getExtendedMemoryBlock(String expression, Object context) throws DebugException
223 return new MainMemoryBlockExtension(this, expression, context);
227 public IProcess getProcess()
233 public boolean hasThreads() throws DebugException
239 public IThread[] getThreads() throws DebugException
241 return new IThread[0];
244 public void addExecutionSpeedListener(Consumer<Double> executionSpeedListener)
246 executionSpeedListeners.add(executionSpeedListener);
249 public void removeExecutionSpeedListener(Consumer<Double> executionSpeedListener)
251 executionSpeedListeners.remove(executionSpeedListener);
254 private void callExecutionSpeedListener(double executionSpeed)
256 executionSpeedListeners.forEach(l -> l.accept(executionSpeed));
259 @SuppressWarnings("unchecked")
261 public <T> T getAdapter(Class<T> adapter)
263 if (adapter == IDebugElement.class)
266 // leave this here; maybe we implement IStepFilters someday
267 if (adapter == IStepFilters.class)
268 if (this instanceof IStepFilters)
269 return (T) getDebugTarget();
271 if (adapter == IDebugTarget.class)
272 return (T) getDebugTarget();
274 if (adapter == ILaunch.class)
275 return (T) getLaunch();
278 if (adapter == ILaunchConfiguration.class)
279 return (T) getLaunch().getLaunchConfiguration();
281 return super.getAdapter(adapter);
285 * Fires a creation event for this debug element.
287 private void fireCreationEvent()
289 fireEvent(new DebugEvent(this, DebugEvent.CREATE));
293 * Fires a resume for this debug element with the specified detail code.
295 * @param detail detail code for the resume event, such as <code>DebugEvent.STEP_OVER</code>
297 private void fireResumeEvent(int detail)
299 fireEvent(new DebugEvent(this, DebugEvent.RESUME, detail));
303 * Fires a suspend event for this debug element with the specified detail code.
305 * @param detail detail code for the suspend event, such as <code>DebugEvent.BREAKPOINT</code>
307 private void fireSuspendEvent(int detail)
309 fireEvent(new DebugEvent(this, DebugEvent.SUSPEND, detail));
313 * Fires a terminate event for this debug element.
315 private void fireTerminateEvent()
317 fireEvent(new DebugEvent(this, DebugEvent.TERMINATE));
321 * Fires a debug event.
323 * @param event debug event to fire
325 private static void fireEvent(DebugEvent event)
327 DebugPlugin.getDefault().fireDebugEventSet(new DebugEvent[] { event });
330 private static void throwDebugException(String message) throws DebugException
332 throw new DebugException(
333 new Status(IStatus.ERROR, MograsimActivator.PLUGIN_ID, DebugException.TARGET_REQUEST_FAILED, message, null));