public class MachineDebugTarget extends PlatformObject implements IDebugTarget, IMemoryBlockRetrievalExtension
{
+ private final static boolean USE_PSEUDO_THREAD = true;
+
private final ILaunch launch;
private final Machine machine;
private final LogicExecuter exec;
+ private final MachineThread thread;
private boolean running;
getLaunch().addDebugTarget(this);
fireCreationEvent();
+
+ // create after creating ourself
+ this.thread = USE_PSEUDO_THREAD ? new MachineThread(this) : null;
}
public Machine getMachine()
@Override
public boolean hasThreads() throws DebugException
{
- return false;
+ return USE_PSEUDO_THREAD;
}
@Override
public IThread[] getThreads() throws DebugException
{
- return new IThread[0];
+ return thread == null ? new IThread[0] : new IThread[] { thread };
}
public void addExecutionSpeedListener(Consumer<Double> executionSpeedListener)
--- /dev/null
+package net.mograsim.plugin.launch;
+
+import java.util.Arrays;
+import java.util.function.Consumer;
+
+import org.eclipse.core.runtime.PlatformObject;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.debug.core.DebugEvent;
+import org.eclipse.debug.core.DebugException;
+import org.eclipse.debug.core.DebugPlugin;
+import org.eclipse.debug.core.ILaunch;
+import org.eclipse.debug.core.model.IDebugElement;
+import org.eclipse.debug.core.model.IDebugTarget;
+import org.eclipse.debug.core.model.IRegister;
+import org.eclipse.debug.core.model.IRegisterGroup;
+import org.eclipse.debug.core.model.IValue;
+import org.eclipse.swt.SWT;
+
+import net.mograsim.logic.core.types.BitVector;
+import net.mograsim.machine.Machine;
+import net.mograsim.machine.Register;
+import net.mograsim.plugin.MograsimActivator;
+
+public class MachineRegister extends PlatformObject implements IRegister
+{
+ private final MachineRegisterGroup registerGroup;
+ private final Register machineRegister;
+
+ private final Consumer<BitVector> registerListener;
+
+ public MachineRegister(MachineRegisterGroup registerGroup, Register machineRegister)
+ {
+ this.registerGroup = registerGroup;
+ this.machineRegister = machineRegister;
+
+ this.registerListener = v -> fireChangeEvent();
+ getMachine().addRegisterListener(machineRegister, registerListener);
+
+ DebugPlugin.getDefault().addDebugEventListener(es -> Arrays.stream(es).filter(e -> e.getKind() == DebugEvent.TERMINATE).filter(e ->
+ {
+ Object source = e.getSource();
+ if (!(source instanceof IDebugElement))
+ return false;
+ return ((IDebugElement) source).getDebugTarget() == getDebugTarget();
+ }).forEach(e -> getMachine().removeRegisterListener(machineRegister, registerListener)));
+ }
+
+ public Machine getMachine()
+ {
+ return registerGroup.getMachine();
+ }
+
+ @Override
+ public IValue getValue() throws DebugException
+ {
+ return new MachineValue(this);
+ }
+
+ @Override
+ public String getName() throws DebugException
+ {
+ return machineRegister.id();// TODO name
+ }
+
+ @Override
+ public String getReferenceTypeName() throws DebugException
+ {
+ return "BitVector";
+ }
+
+ @Override
+ public boolean hasValueChanged() throws DebugException
+ {
+ // TODO
+ return false;
+ }
+
+ @Override
+ public String getModelIdentifier()
+ {
+ return MograsimActivator.PLUGIN_ID;
+ }
+
+ @Override
+ public IDebugTarget getDebugTarget()
+ {
+ return registerGroup.getDebugTarget();
+ }
+
+ @Override
+ public ILaunch getLaunch()
+ {
+ return registerGroup.getLaunch();
+ }
+
+ public String getValueString()
+ {
+ return getMachine().getRegister(machineRegister).toString();
+ }
+
+ @Override
+ public void setValue(String expression) throws DebugException
+ {
+ // TODO exception handling
+ getMachine().setRegister(machineRegister, BitVector.parse(expression));
+ }
+
+ @Override
+ public void setValue(IValue value) throws DebugException
+ {
+ if (!"Bitvector".equals(value.getReferenceTypeName()))
+ throw new DebugException(new Status(SWT.ERROR, MograsimActivator.PLUGIN_ID, ""));
+ setValue(value.getValueString());
+ }
+
+ @Override
+ public boolean supportsValueModification()
+ {
+ return true;
+ }
+
+ @Override
+ public boolean verifyValue(String expression) throws DebugException
+ {
+ // TODO do this prettier; also check length too
+ try
+ {
+ BitVector.parse(expression);
+ }
+ catch (@SuppressWarnings("unused") Exception e)
+ {
+ return false;
+ }
+ return true;
+ }
+
+ @Override
+ public boolean verifyValue(IValue value) throws DebugException
+ {
+ return verifyValue(value.getValueString());
+ }
+
+ @Override
+ public IRegisterGroup getRegisterGroup() throws DebugException
+ {
+ return registerGroup;
+ }
+
+ /**
+ * Fires a change event for this debug element.
+ */
+ private void fireChangeEvent()
+ {
+ fireEvent(new DebugEvent(this, DebugEvent.CHANGE));
+ }
+
+ /**
+ * Fires a debug event.
+ *
+ * @param event debug event to fire
+ */
+ private static void fireEvent(DebugEvent event)
+ {
+ DebugPlugin.getDefault().fireDebugEventSet(new DebugEvent[] { event });
+ }
+}
\ No newline at end of file
--- /dev/null
+package net.mograsim.plugin.launch;
+
+import java.util.Collections;
+import java.util.List;
+import java.util.Set;
+import java.util.stream.Collectors;
+
+import org.eclipse.core.runtime.PlatformObject;
+import org.eclipse.debug.core.DebugException;
+import org.eclipse.debug.core.ILaunch;
+import org.eclipse.debug.core.model.IDebugTarget;
+import org.eclipse.debug.core.model.IRegister;
+import org.eclipse.debug.core.model.IRegisterGroup;
+
+import net.mograsim.machine.Machine;
+import net.mograsim.machine.Register;
+import net.mograsim.plugin.MograsimActivator;
+
+public class MachineRegisterGroup extends PlatformObject implements IRegisterGroup
+{
+ private final MachineStackFrame stackFrame;
+ private final List<MachineRegister> registers;
+
+ public MachineRegisterGroup(MachineStackFrame stackFrame)
+ {
+ this.stackFrame = stackFrame;
+ Set<Register> machineRegisters = getMachine().getDefinition().getRegisters();
+ List<MachineRegister> registersModifiable = machineRegisters.stream().map(r -> new MachineRegister(this, r))
+ .collect(Collectors.toList());
+ this.registers = Collections.unmodifiableList(registersModifiable);
+ }
+
+ @Override
+ public String getModelIdentifier()
+ {
+ return MograsimActivator.PLUGIN_ID;
+ }
+
+ public Machine getMachine()
+ {
+ return stackFrame.getMachine();
+ }
+
+ @Override
+ public IDebugTarget getDebugTarget()
+ {
+ return stackFrame.getDebugTarget();
+ }
+
+ @Override
+ public ILaunch getLaunch()
+ {
+ return stackFrame.getLaunch();
+ }
+
+ @Override
+ public String getName() throws DebugException
+ {
+ return "pseudo register group";
+ }
+
+ @Override
+ public IRegister[] getRegisters() throws DebugException
+ {
+ // TODO sort
+ return registers.toArray(IRegister[]::new);
+ }
+
+ @Override
+ public boolean hasRegisters() throws DebugException
+ {
+ return true;
+ }
+}
\ No newline at end of file
--- /dev/null
+package net.mograsim.plugin.launch;
+
+import org.eclipse.core.runtime.PlatformObject;
+import org.eclipse.debug.core.DebugException;
+import org.eclipse.debug.core.ILaunch;
+import org.eclipse.debug.core.model.IDebugTarget;
+import org.eclipse.debug.core.model.IRegisterGroup;
+import org.eclipse.debug.core.model.IStackFrame;
+import org.eclipse.debug.core.model.IThread;
+import org.eclipse.debug.core.model.IVariable;
+
+import net.mograsim.machine.Machine;
+import net.mograsim.plugin.MograsimActivator;
+
+public class MachineStackFrame extends PlatformObject implements IStackFrame
+{
+ private final MachineThread thread;
+ private final MachineRegisterGroup registerGroup;
+
+ public MachineStackFrame(MachineThread thread)
+ {
+ this.thread = thread;
+ this.registerGroup = new MachineRegisterGroup(this);
+ }
+
+ @Override
+ public String getModelIdentifier()
+ {
+ return MograsimActivator.PLUGIN_ID;
+ }
+
+ public Machine getMachine()
+ {
+ return thread.getMachine();
+ }
+
+ @Override
+ public IDebugTarget getDebugTarget()
+ {
+ return thread.getDebugTarget();
+ }
+
+ @Override
+ public ILaunch getLaunch()
+ {
+ return thread.getLaunch();
+ }
+
+ @Override
+ public boolean canStepInto()
+ {
+ return thread.canStepInto();
+ }
+
+ @Override
+ public boolean canStepOver()
+ {
+ return thread.canStepOver();
+ }
+
+ @Override
+ public boolean canStepReturn()
+ {
+ return thread.canStepReturn();
+ }
+
+ @Override
+ public boolean isStepping()
+ {
+ return thread.isStepping();
+ }
+
+ @Override
+ public void stepInto() throws DebugException
+ {
+ thread.stepInto();
+ }
+
+ @Override
+ public void stepOver() throws DebugException
+ {
+ thread.stepOver();
+ }
+
+ @Override
+ public void stepReturn() throws DebugException
+ {
+ thread.stepReturn();
+ }
+
+ @Override
+ public boolean canResume()
+ {
+ return thread.canResume();
+ }
+
+ @Override
+ public boolean canSuspend()
+ {
+ return thread.canSuspend();
+ }
+
+ @Override
+ public boolean isSuspended()
+ {
+ return thread.isSuspended();
+ }
+
+ @Override
+ public void resume() throws DebugException
+ {
+ thread.resume();
+ }
+
+ @Override
+ public void suspend() throws DebugException
+ {
+ thread.suspend();
+ }
+
+ @Override
+ public boolean canTerminate()
+ {
+ return thread.canTerminate();
+ }
+
+ @Override
+ public boolean isTerminated()
+ {
+ return thread.isTerminated();
+ }
+
+ @Override
+ public void terminate() throws DebugException
+ {
+ thread.terminate();
+ }
+
+ @Override
+ public IThread getThread()
+ {
+ return thread;
+ }
+
+ @Override
+ public IVariable[] getVariables() throws DebugException
+ {
+ return new IVariable[0];
+ }
+
+ @Override
+ public boolean hasVariables() throws DebugException
+ {
+ return false;
+ }
+
+ @Override
+ public int getLineNumber() throws DebugException
+ {
+ // TODO could we transmit the active microinstruction address using this?
+ return -1;
+ }
+
+ @Override
+ public int getCharStart() throws DebugException
+ {
+ return -1;
+ }
+
+ @Override
+ public int getCharEnd() throws DebugException
+ {
+ return -1;
+ }
+
+ @Override
+ public String getName() throws DebugException
+ {
+ return "pseudo stack frame";
+ }
+
+ @Override
+ public IRegisterGroup[] getRegisterGroups() throws DebugException
+ {
+ return new IRegisterGroup[] { registerGroup };
+ }
+
+ @Override
+ public boolean hasRegisterGroups() throws DebugException
+ {
+ return true;
+ }
+}
\ No newline at end of file
--- /dev/null
+package net.mograsim.plugin.launch;
+
+import java.util.Arrays;
+
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.PlatformObject;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.debug.core.DebugEvent;
+import org.eclipse.debug.core.DebugException;
+import org.eclipse.debug.core.DebugPlugin;
+import org.eclipse.debug.core.ILaunch;
+import org.eclipse.debug.core.model.IBreakpoint;
+import org.eclipse.debug.core.model.IDebugTarget;
+import org.eclipse.debug.core.model.IStackFrame;
+import org.eclipse.debug.core.model.IThread;
+
+import net.mograsim.machine.Machine;
+import net.mograsim.plugin.MograsimActivator;
+
+public class MachineThread extends PlatformObject implements IThread
+{
+ private final MachineDebugTarget debugTarget;
+ private final MachineStackFrame stackFrame;
+
+ public MachineThread(MachineDebugTarget debugTarget)
+ {
+ this.debugTarget = debugTarget;
+ this.stackFrame = new MachineStackFrame(this);
+
+ DebugPlugin.getDefault().addDebugEventListener(es -> Arrays.stream(es).filter(e -> e.getSource() == debugTarget).forEach(e ->
+ {
+ switch (e.getKind())
+ {
+ case DebugEvent.RESUME:
+ fireResumeEvent(e.getDetail());
+ break;
+ case DebugEvent.SUSPEND:
+ fireSuspendEvent(e.getDetail());
+ break;
+ default:
+ }
+ }));
+
+ fireCreationEvent();
+ }
+
+ @Override
+ public String getModelIdentifier()
+ {
+ return MograsimActivator.PLUGIN_ID;
+ }
+
+ public Machine getMachine()
+ {
+ return debugTarget.getMachine();
+ }
+
+ @Override
+ public IDebugTarget getDebugTarget()
+ {
+ return debugTarget;
+ }
+
+ @Override
+ public ILaunch getLaunch()
+ {
+ return debugTarget.getLaunch();
+ }
+
+ @Override
+ public boolean canResume()
+ {
+ return debugTarget.canResume();
+ }
+
+ @Override
+ public boolean canSuspend()
+ {
+ return debugTarget.canSuspend();
+ }
+
+ @Override
+ public boolean isSuspended()
+ {
+ return debugTarget.isSuspended();
+ }
+
+ @Override
+ public void resume() throws DebugException
+ {
+ debugTarget.resume();
+ }
+
+ @Override
+ public void suspend() throws DebugException
+ {
+ debugTarget.suspend();
+ }
+
+ @Override
+ public boolean canStepInto()
+ {
+ return false;
+ }
+
+ // TODO step over sounds like single-step execution...
+ @Override
+ public boolean canStepOver()
+ {
+ return false;
+ }
+
+ @Override
+ public boolean canStepReturn()
+ {
+ return false;
+ }
+
+ @Override
+ public boolean isStepping()
+ {
+ return false;
+ }
+
+ @Override
+ public void stepInto() throws DebugException
+ {
+ throw new DebugException(new Status(IStatus.ERROR, MograsimActivator.PLUGIN_ID, "Can't step into for a machine thread"));
+ }
+
+ @Override
+ public void stepOver() throws DebugException
+ {
+ throw new DebugException(new Status(IStatus.ERROR, MograsimActivator.PLUGIN_ID, "Can't step over for a machine thread"));
+ }
+
+ @Override
+ public void stepReturn() throws DebugException
+ {
+ throw new DebugException(new Status(IStatus.ERROR, MograsimActivator.PLUGIN_ID, "Can't step return for a machine thread"));
+ }
+
+ @Override
+ public boolean canTerminate()
+ {
+ return debugTarget.canTerminate();
+ }
+
+ @Override
+ public boolean isTerminated()
+ {
+ return debugTarget.isTerminated();
+ }
+
+ @Override
+ public void terminate() throws DebugException
+ {
+ debugTarget.terminate();
+ }
+
+ @Override
+ public IStackFrame[] getStackFrames() throws DebugException
+ {
+ return isSuspended() ? new IStackFrame[] { stackFrame } : new IStackFrame[0];
+ }
+
+ @Override
+ public boolean hasStackFrames() throws DebugException
+ {
+ // required by Eclipse: see javadoc for org.eclipse.debug.core.DebugEvent
+ return isSuspended();
+ }
+
+ @Override
+ public int getPriority() throws DebugException
+ {
+ return 0;
+ }
+
+ @Override
+ public IStackFrame getTopStackFrame() throws DebugException
+ {
+ return stackFrame;
+ }
+
+ @Override
+ public String getName() throws DebugException
+ {
+ return "pseudo thread";
+ }
+
+ @Override
+ public IBreakpoint[] getBreakpoints()
+ {
+ return new IBreakpoint[0];
+ }
+
+ /**
+ * Fires a creation event for this debug element.
+ */
+ private void fireCreationEvent()
+ {
+ fireEvent(new DebugEvent(this, DebugEvent.CREATE));
+ }
+
+ /**
+ * Fires a resume for this debug element with the specified detail code.
+ *
+ * @param detail detail code for the resume event, such as <code>DebugEvent.STEP_OVER</code>
+ */
+ private void fireResumeEvent(int detail)
+ {
+ fireEvent(new DebugEvent(this, DebugEvent.RESUME, detail));
+ }
+
+ /**
+ * Fires a suspend event for this debug element with the specified detail code.
+ *
+ * @param detail detail code for the suspend event, such as <code>DebugEvent.BREAKPOINT</code>
+ */
+ private void fireSuspendEvent(int detail)
+ {
+ fireEvent(new DebugEvent(this, DebugEvent.SUSPEND, detail));
+ }
+
+ /**
+ * Fires a debug event.
+ *
+ * @param event debug event to fire
+ */
+ private static void fireEvent(DebugEvent event)
+ {
+ DebugPlugin.getDefault().fireDebugEventSet(new DebugEvent[] { event });
+ }
+}
\ No newline at end of file
--- /dev/null
+package net.mograsim.plugin.launch;
+
+import org.eclipse.core.runtime.PlatformObject;
+import org.eclipse.debug.core.DebugException;
+import org.eclipse.debug.core.ILaunch;
+import org.eclipse.debug.core.model.IDebugTarget;
+import org.eclipse.debug.core.model.IValue;
+import org.eclipse.debug.core.model.IVariable;
+
+import net.mograsim.machine.Machine;
+import net.mograsim.plugin.MograsimActivator;
+
+public class MachineValue extends PlatformObject implements IValue
+{
+ private final MachineRegister register;
+
+ public MachineValue(MachineRegister register)
+ {
+ this.register = register;
+ }
+
+ @Override
+ public String getModelIdentifier()
+ {
+ return MograsimActivator.PLUGIN_ID;
+ }
+
+ public Machine getMachine()
+ {
+ return register.getMachine();
+ }
+
+ @Override
+ public IDebugTarget getDebugTarget()
+ {
+ return register.getDebugTarget();
+ }
+
+ @Override
+ public ILaunch getLaunch()
+ {
+ return register.getLaunch();
+ }
+
+ @Override
+ public String getReferenceTypeName() throws DebugException
+ {
+ return register.getReferenceTypeName();
+ }
+
+ @Override
+ public String getValueString() throws DebugException
+ {
+ return register.getValueString();
+ }
+
+ @Override
+ public boolean isAllocated() throws DebugException
+ {
+ return false;
+ }
+
+ @Override
+ public IVariable[] getVariables() throws DebugException
+ {
+ return new IVariable[0];
+ }
+
+ @Override
+ public boolean hasVariables() throws DebugException
+ {
+ return false;
+ }
+}
\ No newline at end of file
import org.eclipse.core.runtime.SafeRunner;
import org.eclipse.debug.core.ILaunch;
+import org.eclipse.debug.core.model.IDebugElement;
import org.eclipse.debug.core.model.IDebugTarget;
import org.eclipse.debug.ui.DebugUITools;
import org.eclipse.debug.ui.contexts.IDebugContextListener;
Object[] selectedElements = treeSelection.toArray();
for (Object selectedElement : selectedElements)
{
- MachineDebugTarget debugTarget;
- if (selectedElement instanceof MachineDebugTarget)
- debugTarget = (MachineDebugTarget) selectedElement;
+ IDebugTarget debugTarget;
+ if (selectedElement instanceof IDebugElement)
+ debugTarget = ((IDebugElement) selectedElement).getDebugTarget();
else if (selectedElement instanceof ILaunch)
- {
- ILaunch launch = (ILaunch) selectedElement;
- IDebugTarget genericDebugTarget = launch.getDebugTarget();
- if (genericDebugTarget instanceof MachineDebugTarget)
- debugTarget = (MachineDebugTarget) genericDebugTarget;
- else
- continue;
- } else
+ debugTarget = ((ILaunch) selectedElement).getDebugTarget();
+ else
+ continue;
+ if (!(debugTarget instanceof MachineDebugTarget))
continue;
if (debugTarget.isTerminated())
continue;
// we found a selected MachineDebugTarget
if (this.debugTarget != debugTarget)
- bindToDebugTarget(debugTarget);
+ bindToDebugTarget((MachineDebugTarget) debugTarget);
return;
}
}