1 package net.mograsim.plugin.views;
3 import java.util.HashSet;
5 import java.util.function.Consumer;
7 import org.eclipse.core.runtime.SafeRunner;
8 import org.eclipse.debug.core.ILaunch;
9 import org.eclipse.debug.core.model.IDebugElement;
10 import org.eclipse.debug.core.model.IDebugTarget;
11 import org.eclipse.debug.ui.DebugUITools;
12 import org.eclipse.debug.ui.contexts.IDebugContextListener;
13 import org.eclipse.debug.ui.contexts.IDebugContextManager;
14 import org.eclipse.debug.ui.contexts.IDebugContextService;
15 import org.eclipse.jface.viewers.ISelection;
16 import org.eclipse.jface.viewers.TreeSelection;
17 import org.eclipse.swt.SWT;
18 import org.eclipse.swt.layout.FillLayout;
19 import org.eclipse.swt.layout.GridData;
20 import org.eclipse.swt.layout.GridLayout;
21 import org.eclipse.swt.widgets.Button;
22 import org.eclipse.swt.widgets.Composite;
23 import org.eclipse.swt.widgets.Control;
24 import org.eclipse.swt.widgets.Label;
25 import org.eclipse.swt.widgets.Scale;
26 import org.eclipse.ui.PlatformUI;
27 import org.eclipse.ui.part.ViewPart;
29 import net.haspamelodica.swt.helper.input.DoubleInput;
30 import net.haspamelodica.swt.helper.zoomablecanvas.helper.ZoomableCanvasUserInput;
31 import net.mograsim.logic.core.LogicObserver;
32 import net.mograsim.logic.core.components.CoreClock;
33 import net.mograsim.logic.model.LogicUICanvas;
34 import net.mograsim.machine.Machine;
35 import net.mograsim.machine.Memory.MemoryCellModifiedListener;
36 import net.mograsim.machine.mi.AssignableMicroInstructionMemory;
37 import net.mograsim.plugin.launch.MachineDebugTarget;
38 import net.mograsim.plugin.tables.DisplaySettings;
39 import net.mograsim.plugin.tables.mi.ActiveInstructionPreviewContentProvider;
40 import net.mograsim.plugin.tables.mi.InstructionTable;
41 import net.mograsim.plugin.util.OverlappingFillLayout;
42 import net.mograsim.preferences.Preferences;
44 public class SimulationView extends ViewPart
46 private static final int SIM_SPEED_SCALE_STEPS = 50;
47 private static final double SIM_SPEED_SCALE_STEP_FACTOR = 1.32;
48 private static final double SIM_SPEED_SCALE_STEP_FACTOR_LOG = Math.log(SIM_SPEED_SCALE_STEP_FACTOR);
50 private final Set<Control> controlsToDisableWhenNoMachinePresent;
51 private Scale simSpeedScale;
52 private DoubleInput simSpeedInput;
53 private Composite contextDependentControlsParent;
54 private Composite canvasParent;
55 private InstructionTable instPreview;
56 private ActiveInstructionPreviewContentProvider contentProvider;
57 private Label noRunningMachineLabel;
59 private MachineDebugTarget debugTarget;
60 private LogicUICanvas canvas;
62 private final MemoryCellModifiedListener memCellListener;
63 private final LogicObserver clockObserver;
64 private final IDebugContextListener debugContextListener;
65 private final Consumer<Double> executionSpeedListener;
67 public SimulationView()
69 controlsToDisableWhenNoMachinePresent = new HashSet<>();
70 memCellListener = a -> instPreview.refresh();
71 // TODO could this be a breakpoint?
74 if (((CoreClock) o).isOn())
75 SafeRunner.run(() -> debugTarget.suspend());
77 debugContextListener = e -> debugContextChanged(e.getContext());
78 executionSpeedListener = this::speedFactorChanged;
82 public void createPartControl(Composite parent)
85 parent.setLayout(new GridLayout());
87 addSimulationControlWidgets(parent);
89 Composite contextDependentControlsParentParent = new Composite(parent, SWT.NONE);
90 contextDependentControlsParentParent.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
91 contextDependentControlsParentParent.setLayout(new OverlappingFillLayout());
93 noRunningMachineLabel = new Label(contextDependentControlsParentParent, SWT.NONE);
94 noRunningMachineLabel.setText("No machine running && selected in the Debug view...");
96 contextDependentControlsParent = new Composite(contextDependentControlsParentParent, SWT.NONE);
97 GridLayout contexDependentControlsLayout = new GridLayout();
98 contexDependentControlsLayout.marginWidth = 0;
99 contexDependentControlsLayout.marginHeight = 0;
100 contextDependentControlsParent.setLayout(contexDependentControlsLayout);
102 canvasParent = new Composite(contextDependentControlsParent, SWT.NONE);
103 canvasParent.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
104 canvasParent.setLayout(new FillLayout());
106 addInstructionPreviewControlWidgets(contextDependentControlsParent);
108 IDebugContextManager debugCManager = DebugUITools.getDebugContextManager();
109 IDebugContextService contextService = debugCManager.getContextService(PlatformUI.getWorkbench().getActiveWorkbenchWindow());
110 contextService.addDebugContextListener(debugContextListener);
111 debugContextChanged(contextService.getActiveContext());
114 private void addSimulationControlWidgets(Composite parent)
116 Composite c = new Composite(parent, SWT.NONE);
117 c.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false));
118 c.setLayout(new GridLayout(7, false));
120 Button sbseButton = new Button(c, SWT.CHECK);
121 controlsToDisableWhenNoMachinePresent.add(sbseButton);
123 sbseButton.setText("Step by step execution");
124 sbseButton.addListener(SWT.Selection, e ->
126 CoreClock cl = debugTarget.getMachine().getClock();
127 if (sbseButton.getSelection())
128 cl.registerObserver(clockObserver);
130 cl.deregisterObserver(clockObserver);
132 sbseButton.setSelection(false);
134 Label simSpeedLabel = new Label(c, SWT.NONE);
135 controlsToDisableWhenNoMachinePresent.add(simSpeedLabel);
136 simSpeedLabel.setText("Simulation Speed: ");
138 simSpeedScale = new Scale(c, SWT.NONE);
139 controlsToDisableWhenNoMachinePresent.add(simSpeedScale);
140 simSpeedScale.setMinimum(0);
141 simSpeedScale.setMaximum(SIM_SPEED_SCALE_STEPS);
142 simSpeedScale.setIncrement(1);
143 simSpeedScale.setSelection(0);
144 simSpeedScale.addListener(SWT.Selection, e ->
146 double speed = Math.pow(SIM_SPEED_SCALE_STEP_FACTOR, simSpeedScale.getSelection() - SIM_SPEED_SCALE_STEPS);
147 debugTarget.setExecutionSpeed(speed);
150 simSpeedInput = new DoubleInput(c, SWT.NONE);
151 controlsToDisableWhenNoMachinePresent.add(simSpeedInput);
152 simSpeedInput.setPrecision(Preferences.current().getInt("net.mograsim.plugin.core.simspeedprecision"));
153 simSpeedInput.addChangeListener(speed ->
156 debugTarget.setExecutionSpeed(speed);
158 debugTarget.setExecutionSpeed(Math.pow(10, -simSpeedInput.getPrecision()));
164 private void speedFactorChanged(double speed)
166 simSpeedInput.setValue(speed);
167 int closestScalePos = (int) Math.round(Math.log(speed) / SIM_SPEED_SCALE_STEP_FACTOR_LOG + SIM_SPEED_SCALE_STEPS);
168 simSpeedScale.setSelection(Math.min(Math.max(closestScalePos, 0), SIM_SPEED_SCALE_STEPS));
171 private void addInstructionPreviewControlWidgets(Composite parent)
173 instPreview = new InstructionTable(parent, new DisplaySettings(), getSite().getWorkbenchWindow().getWorkbench().getThemeManager());
174 instPreview.getTableViewer().getControl().setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false));
175 contentProvider = new ActiveInstructionPreviewContentProvider(instPreview.getTableViewer());
176 instPreview.setContentProvider(contentProvider);
179 private void debugContextChanged(ISelection selection)
181 if (selection != null && selection instanceof TreeSelection)
183 TreeSelection treeSelection = (TreeSelection) selection;
184 Object[] selectedElements = treeSelection.toArray();
185 for (Object selectedElement : selectedElements)
187 IDebugTarget debugTarget;
188 if (selectedElement instanceof IDebugElement)
189 debugTarget = ((IDebugElement) selectedElement).getDebugTarget();
190 else if (selectedElement instanceof ILaunch)
191 debugTarget = ((ILaunch) selectedElement).getDebugTarget();
194 if (!(debugTarget instanceof MachineDebugTarget))
196 if (debugTarget.isTerminated())
198 // we found a selected MachineDebugTarget
199 if (this.debugTarget != debugTarget)
200 bindToDebugTarget((MachineDebugTarget) debugTarget);
204 // we didn't find a selected MachineDebugTarget
205 // call binToDebugTarget even if this.debugTarget==null
206 bindToDebugTarget(null);
209 private void bindToDebugTarget(MachineDebugTarget debugTarget)
211 this.debugTarget = debugTarget;
213 if (canvasParent == null)
214 // createPartControls has not been called yet
220 deregisterMachineDependentListeners();
223 offX = canvas.getOffX();
224 offY = canvas.getOffY();
225 zoom = canvas.getZoom();
234 if (debugTarget != null)
236 noRunningMachineLabel.setVisible(false);
237 contextDependentControlsParent.setVisible(true);
238 controlsToDisableWhenNoMachinePresent.forEach(c -> c.setEnabled(true));
240 Machine machine = debugTarget.getMachine();
242 canvas = new LogicUICanvas(canvasParent, SWT.NONE, machine.getModel());
243 canvas.addListener(SWT.MouseDown, e -> canvas.setFocus());
244 ZoomableCanvasUserInput userInput = new ZoomableCanvasUserInput(canvas);
245 userInput.buttonDrag = Preferences.current().getInt("net.mograsim.logic.model.button.drag");
246 userInput.buttonZoom = Preferences.current().getInt("net.mograsim.logic.model.button.zoom");
247 userInput.enableUserInput();
250 canvas.moveTo(offX, offY, zoom);
251 canvas.commitTransform();
254 AssignableMicroInstructionMemory mIMemory = machine.getMicroInstructionMemory();
255 instPreview.bindMicroInstructionMemory(mIMemory);
256 mIMemory.registerCellModifiedListener(memCellListener);
258 canvasParent.layout();
261 contentProvider.setMachine(machine);
263 // initialize executer
264 debugTarget.addExecutionSpeedListener(executionSpeedListener);
265 speedFactorChanged(debugTarget.getExecutionSpeed());
268 noRunningMachineLabel.setVisible(true);
269 contextDependentControlsParent.setVisible(false);
270 controlsToDisableWhenNoMachinePresent.forEach(c -> c.setEnabled(false));
271 contentProvider.setMachine(null);
275 private void deregisterMachineDependentListeners()
277 if (debugTarget != null)
279 debugTarget.removeExecutionSpeedListener(executionSpeedListener);
280 debugTarget.getMachine().getMicroInstructionMemory().deregisterCellModifiedListener(memCellListener);
281 debugTarget.getMachine().getClock().deregisterObserver(clockObserver);
286 public void setFocus()
288 if (canvas != null && !canvas.isDisposed())
293 public void dispose()
295 deregisterMachineDependentListeners();
296 DebugUITools.getDebugContextManager().removeDebugContextListener(debugContextListener);