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.IDebugTarget;
10 import org.eclipse.debug.ui.DebugUITools;
11 import org.eclipse.debug.ui.contexts.IDebugContextListener;
12 import org.eclipse.debug.ui.contexts.IDebugContextManager;
13 import org.eclipse.debug.ui.contexts.IDebugContextService;
14 import org.eclipse.jface.viewers.ISelection;
15 import org.eclipse.jface.viewers.TreeSelection;
16 import org.eclipse.swt.SWT;
17 import org.eclipse.swt.layout.FillLayout;
18 import org.eclipse.swt.layout.GridData;
19 import org.eclipse.swt.layout.GridLayout;
20 import org.eclipse.swt.widgets.Button;
21 import org.eclipse.swt.widgets.Composite;
22 import org.eclipse.swt.widgets.Control;
23 import org.eclipse.swt.widgets.Label;
24 import org.eclipse.swt.widgets.Scale;
25 import org.eclipse.ui.PlatformUI;
26 import org.eclipse.ui.part.ViewPart;
28 import net.haspamelodica.swt.helper.input.DoubleInput;
29 import net.haspamelodica.swt.helper.zoomablecanvas.helper.ZoomableCanvasUserInput;
30 import net.mograsim.logic.core.LogicObserver;
31 import net.mograsim.logic.core.components.CoreClock;
32 import net.mograsim.logic.model.LogicUICanvas;
33 import net.mograsim.machine.Machine;
34 import net.mograsim.machine.Memory.MemoryCellModifiedListener;
35 import net.mograsim.machine.mi.AssignableMicroInstructionMemory;
36 import net.mograsim.plugin.launch.MachineDebugTarget;
37 import net.mograsim.plugin.tables.DisplaySettings;
38 import net.mograsim.plugin.tables.mi.ActiveInstructionPreviewContentProvider;
39 import net.mograsim.plugin.tables.mi.InstructionTable;
40 import net.mograsim.plugin.util.OverlappingFillLayout;
41 import net.mograsim.preferences.Preferences;
43 public class SimulationView extends ViewPart
45 private static final int SIM_SPEED_SCALE_STEPS = 50;
46 private static final double SIM_SPEED_SCALE_STEP_FACTOR = 1.32;
47 private static final double SIM_SPEED_SCALE_STEP_FACTOR_LOG = Math.log(SIM_SPEED_SCALE_STEP_FACTOR);
49 private final Set<Control> controlsToDisableWhenNoMachinePresent;
50 private Scale simSpeedScale;
51 private DoubleInput simSpeedInput;
52 private Composite contextDependentControlsParent;
53 private Composite canvasParent;
54 private InstructionTable instPreview;
55 private ActiveInstructionPreviewContentProvider contentProvider;
56 private Label noRunningMachineLabel;
58 private MachineDebugTarget debugTarget;
59 private LogicUICanvas canvas;
61 private final MemoryCellModifiedListener memCellListener;
62 private final LogicObserver clockObserver;
63 private final IDebugContextListener debugContextListener;
64 private final Consumer<Double> executionSpeedListener;
66 public SimulationView()
68 controlsToDisableWhenNoMachinePresent = new HashSet<>();
69 memCellListener = a -> instPreview.refresh();
70 // TODO could this be a breakpoint?
73 if (((CoreClock) o).isOn())
74 SafeRunner.run(() -> debugTarget.suspend());
76 debugContextListener = e -> debugContextChanged(e.getContext());
77 executionSpeedListener = this::speedFactorChanged;
81 public void createPartControl(Composite parent)
84 parent.setLayout(new GridLayout());
86 addSimulationControlWidgets(parent);
88 Composite contextDependentControlsParentParent = new Composite(parent, SWT.NONE);
89 contextDependentControlsParentParent.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
90 contextDependentControlsParentParent.setLayout(new OverlappingFillLayout());
92 noRunningMachineLabel = new Label(contextDependentControlsParentParent, SWT.NONE);
93 noRunningMachineLabel.setText("No machine running && selected in the Debug view...");
95 contextDependentControlsParent = new Composite(contextDependentControlsParentParent, SWT.NONE);
96 GridLayout contexDependentControlsLayout = new GridLayout();
97 contexDependentControlsLayout.marginWidth = 0;
98 contexDependentControlsLayout.marginHeight = 0;
99 contextDependentControlsParent.setLayout(contexDependentControlsLayout);
101 canvasParent = new Composite(contextDependentControlsParent, SWT.NONE);
102 canvasParent.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
103 canvasParent.setLayout(new FillLayout());
105 addInstructionPreviewControlWidgets(contextDependentControlsParent);
107 IDebugContextManager debugCManager = DebugUITools.getDebugContextManager();
108 IDebugContextService contextService = debugCManager.getContextService(PlatformUI.getWorkbench().getActiveWorkbenchWindow());
109 contextService.addDebugContextListener(debugContextListener);
110 debugContextChanged(contextService.getActiveContext());
113 private void addSimulationControlWidgets(Composite parent)
115 Composite c = new Composite(parent, SWT.NONE);
116 c.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false));
117 c.setLayout(new GridLayout(7, false));
119 Button sbseButton = new Button(c, SWT.CHECK);
120 controlsToDisableWhenNoMachinePresent.add(sbseButton);
122 sbseButton.setText("Step by step execution");
123 sbseButton.addListener(SWT.Selection, e ->
125 CoreClock cl = debugTarget.getMachine().getClock();
126 if (sbseButton.getSelection())
127 cl.registerObserver(clockObserver);
129 cl.deregisterObserver(clockObserver);
131 sbseButton.setSelection(false);
133 Label simSpeedLabel = new Label(c, SWT.NONE);
134 controlsToDisableWhenNoMachinePresent.add(simSpeedLabel);
135 simSpeedLabel.setText("Simulation Speed: ");
137 simSpeedScale = new Scale(c, SWT.NONE);
138 controlsToDisableWhenNoMachinePresent.add(simSpeedScale);
139 simSpeedScale.setMinimum(0);
140 simSpeedScale.setMaximum(SIM_SPEED_SCALE_STEPS);
141 simSpeedScale.setIncrement(1);
142 simSpeedScale.setSelection(0);
143 simSpeedScale.addListener(SWT.Selection, e ->
145 double speed = Math.pow(SIM_SPEED_SCALE_STEP_FACTOR, simSpeedScale.getSelection() - SIM_SPEED_SCALE_STEPS);
146 debugTarget.setExecutionSpeed(speed);
149 simSpeedInput = new DoubleInput(c, SWT.NONE);
150 controlsToDisableWhenNoMachinePresent.add(simSpeedInput);
151 simSpeedInput.setPrecision(Preferences.current().getInt("net.mograsim.plugin.core.simspeedprecision"));
152 simSpeedInput.addChangeListener(speed ->
155 debugTarget.setExecutionSpeed(speed);
157 debugTarget.setExecutionSpeed(Math.pow(10, -simSpeedInput.getPrecision()));
163 private void speedFactorChanged(double speed)
165 simSpeedInput.setValue(speed);
166 int closestScalePos = (int) Math.round(Math.log(speed) / SIM_SPEED_SCALE_STEP_FACTOR_LOG + SIM_SPEED_SCALE_STEPS);
167 simSpeedScale.setSelection(Math.min(Math.max(closestScalePos, 0), SIM_SPEED_SCALE_STEPS));
170 private void addInstructionPreviewControlWidgets(Composite parent)
172 instPreview = new InstructionTable(parent, new DisplaySettings(), getSite().getWorkbenchWindow().getWorkbench().getThemeManager());
173 instPreview.getTableViewer().getControl().setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false));
174 contentProvider = new ActiveInstructionPreviewContentProvider(instPreview.getTableViewer());
175 instPreview.setContentProvider(contentProvider);
178 private void debugContextChanged(ISelection selection)
180 if (selection != null && selection instanceof TreeSelection)
182 TreeSelection treeSelection = (TreeSelection) selection;
183 Object[] selectedElements = treeSelection.toArray();
184 for (Object selectedElement : selectedElements)
186 MachineDebugTarget debugTarget;
187 if (selectedElement instanceof MachineDebugTarget)
188 debugTarget = (MachineDebugTarget) selectedElement;
189 else if (selectedElement instanceof ILaunch)
191 ILaunch launch = (ILaunch) selectedElement;
192 IDebugTarget genericDebugTarget = launch.getDebugTarget();
193 if (genericDebugTarget instanceof MachineDebugTarget)
194 debugTarget = (MachineDebugTarget) genericDebugTarget;
199 if (debugTarget.isTerminated())
201 // we found a selected MachineDebugTarget
202 if (this.debugTarget != debugTarget)
203 bindToDebugTarget(debugTarget);
207 // we didn't find a selected MachineDebugTarget
208 // call binToDebugTarget even if this.debugTarget==null
209 bindToDebugTarget(null);
212 private void bindToDebugTarget(MachineDebugTarget debugTarget)
214 this.debugTarget = debugTarget;
216 if (canvasParent == null)
217 // createPartControls has not been called yet
223 deregisterMachineDependentListeners();
226 offX = canvas.getOffX();
227 offY = canvas.getOffY();
228 zoom = canvas.getZoom();
237 if (debugTarget != null)
239 noRunningMachineLabel.setVisible(false);
240 contextDependentControlsParent.setVisible(true);
241 controlsToDisableWhenNoMachinePresent.forEach(c -> c.setEnabled(true));
243 Machine machine = debugTarget.getMachine();
245 canvas = new LogicUICanvas(canvasParent, SWT.NONE, machine.getModel());
246 canvas.addListener(SWT.MouseDown, e -> canvas.setFocus());
247 ZoomableCanvasUserInput userInput = new ZoomableCanvasUserInput(canvas);
248 userInput.buttonDrag = Preferences.current().getInt("net.mograsim.logic.model.button.drag");
249 userInput.buttonZoom = Preferences.current().getInt("net.mograsim.logic.model.button.zoom");
250 userInput.enableUserInput();
253 canvas.moveTo(offX, offY, zoom);
254 canvas.commitTransform();
257 AssignableMicroInstructionMemory mIMemory = machine.getMicroInstructionMemory();
258 instPreview.bindMicroInstructionMemory(mIMemory);
259 mIMemory.registerCellModifiedListener(memCellListener);
261 canvasParent.layout();
264 contentProvider.setMachine(machine);
266 // initialize executer
267 debugTarget.addExecutionSpeedListener(executionSpeedListener);
268 speedFactorChanged(debugTarget.getExecutionSpeed());
271 noRunningMachineLabel.setVisible(true);
272 contextDependentControlsParent.setVisible(false);
273 controlsToDisableWhenNoMachinePresent.forEach(c -> c.setEnabled(false));
274 contentProvider.setMachine(null);
278 private void deregisterMachineDependentListeners()
280 if (debugTarget != null)
282 debugTarget.removeExecutionSpeedListener(executionSpeedListener);
283 debugTarget.getMachine().getMicroInstructionMemory().deregisterCellModifiedListener(memCellListener);
284 debugTarget.getMachine().getClock().deregisterObserver(clockObserver);
289 public void setFocus()
291 if (canvas != null && !canvas.isDisposed())
296 public void dispose()
298 deregisterMachineDependentListeners();
299 contentProvider.setMachine(null);
300 DebugUITools.getDebugContextManager().removeDebugContextListener(debugContextListener);