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 ILaunch launch;
35 private final Machine machine;
36 private final LogicExecuter exec;
38 private boolean running;
40 private final List<Consumer<Double>> executionSpeedListeners;
42 private final MachineLaunchParams launchParams;
44 public MachineDebugTarget(ILaunch launch, MachineLaunchParams launchParams, MachineDefinition machineDefinition)
47 this.machine = machineDefinition.createNew();
48 this.exec = new LogicExecuter(machine.getTimeline());
50 this.executionSpeedListeners = new ArrayList<>();
51 this.launchParams = launchParams;
53 exec.startLiveExecution();
56 getLaunch().addDebugTarget(this);
60 public Machine getMachine()
66 public String getName() throws DebugException
68 return "Mograsim machine \"" + machine.getDefinition().getId() + '"';
72 public String getModelIdentifier()
74 return MograsimActivator.PLUGIN_ID;
78 public IDebugTarget getDebugTarget()
84 public ILaunch getLaunch()
89 public MachineLaunchParams getLaunchParams()
94 public double getExecutionSpeed()
96 return exec.getSpeedFactor();
99 public void setExecutionSpeed(double speed)
101 if (getExecutionSpeed() != speed)
103 exec.setSpeedFactor(speed);
104 callExecutionSpeedListener(speed);
109 public boolean isSuspended()
111 return exec.isPaused();
115 public boolean canSuspend()
117 return !isTerminated() && !isSuspended();
121 public void suspend() throws DebugException
124 throwDebugException("Can't suspend a terminated MachineProcess");
126 throwDebugException("Can't suspend a suspended MachineProcess");
128 exec.pauseLiveExecution();
129 fireSuspendEvent(DebugEvent.CLIENT_REQUEST);
133 public boolean canResume()
135 return !isTerminated() && isSuspended();
139 public void resume() throws DebugException
142 throwDebugException("Can't resume a terminated MachineProcess");
144 throwDebugException("Can't resume a non-suspended MachineProcess");
146 exec.unpauseLiveExecution();
147 fireResumeEvent(DebugEvent.CLIENT_REQUEST);
151 public boolean isTerminated()
157 public boolean canTerminate()
159 return !isTerminated();
163 public void terminate() throws DebugException
168 exec.stopLiveExecution();
170 fireTerminateEvent();
174 public boolean supportsBreakpoint(IBreakpoint breakpoint)
180 public void breakpointAdded(IBreakpoint breakpoint)
182 // ignore; we don't support breakpoints
186 public void breakpointRemoved(IBreakpoint breakpoint, IMarkerDelta delta)
188 // ignore; we don't support breakpoints
192 public void breakpointChanged(IBreakpoint breakpoint, IMarkerDelta delta)
194 // ignore; we don't support breakpoints
198 public boolean isDisconnected()
204 public boolean canDisconnect()
210 public void disconnect() throws DebugException
212 throw new DebugException(new Status(IStatus.ERROR, MograsimActivator.PLUGIN_ID, DebugException.NOT_SUPPORTED,
213 "Can't disconnect from a MachineDebugTarget", null));
217 public boolean supportsStorageRetrieval()
222 @SuppressWarnings("deprecation") // TODO can we throw a DebugException instead?
224 public IMemoryBlock getMemoryBlock(long startAddress, long length) throws DebugException
226 return new MainMemoryBlock(this, startAddress, length);
230 public IMemoryBlockExtension getExtendedMemoryBlock(String expression, Object context) throws DebugException
232 return new MainMemoryBlockExtension(this, expression, context);
236 public IProcess getProcess()
242 public boolean hasThreads() throws DebugException
248 public IThread[] getThreads() throws DebugException
250 return new IThread[0];
253 public void addExecutionSpeedListener(Consumer<Double> executionSpeedListener)
255 executionSpeedListeners.add(executionSpeedListener);
258 public void removeExecutionSpeedListener(Consumer<Double> executionSpeedListener)
260 executionSpeedListeners.remove(executionSpeedListener);
263 private void callExecutionSpeedListener(double executionSpeed)
265 executionSpeedListeners.forEach(l -> l.accept(executionSpeed));
268 @SuppressWarnings("unchecked")
270 public <T> T getAdapter(Class<T> adapter)
272 if (adapter == IDebugElement.class)
275 // leave this here; maybe we implement IStepFilters someday
276 if (adapter == IStepFilters.class)
277 if (this instanceof IStepFilters)
278 return (T) getDebugTarget();
280 if (adapter == IDebugTarget.class)
281 return (T) getDebugTarget();
283 if (adapter == ILaunch.class)
284 return (T) getLaunch();
287 if (adapter == ILaunchConfiguration.class)
288 return (T) getLaunch().getLaunchConfiguration();
290 return super.getAdapter(adapter);
294 * Fires a creation event for this debug element.
296 private void fireCreationEvent()
298 fireEvent(new DebugEvent(this, DebugEvent.CREATE));
302 * Fires a resume for this debug element with the specified detail code.
304 * @param detail detail code for the resume event, such as <code>DebugEvent.STEP_OVER</code>
306 private void fireResumeEvent(int detail)
308 fireEvent(new DebugEvent(this, DebugEvent.RESUME, detail));
312 * Fires a suspend event for this debug element with the specified detail code.
314 * @param detail detail code for the suspend event, such as <code>DebugEvent.BREAKPOINT</code>
316 private void fireSuspendEvent(int detail)
318 fireEvent(new DebugEvent(this, DebugEvent.SUSPEND, detail));
322 * Fires a terminate event for this debug element.
324 private void fireTerminateEvent()
326 fireEvent(new DebugEvent(this, DebugEvent.TERMINATE));
330 * Fires a debug event.
332 * @param event debug event to fire
334 private static void fireEvent(DebugEvent event)
336 DebugPlugin.getDefault().fireDebugEventSet(new DebugEvent[] { event });
339 private static void throwDebugException(String message) throws DebugException
341 throw new DebugException(
342 new Status(IStatus.ERROR, MograsimActivator.PLUGIN_ID, DebugException.TARGET_REQUEST_FAILED, message, null));