1 package net.mograsim.plugin.views;
3 import java.util.HashSet;
4 import java.util.Optional;
6 import java.util.function.Consumer;
8 import org.eclipse.core.runtime.SafeRunner;
9 import org.eclipse.debug.ui.DebugUITools;
10 import org.eclipse.debug.ui.contexts.IDebugContextManager;
11 import org.eclipse.debug.ui.contexts.IDebugContextService;
12 import org.eclipse.swt.SWT;
13 import org.eclipse.swt.layout.FillLayout;
14 import org.eclipse.swt.layout.GridData;
15 import org.eclipse.swt.layout.GridLayout;
16 import org.eclipse.swt.widgets.Button;
17 import org.eclipse.swt.widgets.Composite;
18 import org.eclipse.swt.widgets.Control;
19 import org.eclipse.swt.widgets.Label;
20 import org.eclipse.swt.widgets.Scale;
21 import org.eclipse.ui.PlatformUI;
22 import org.eclipse.ui.part.ViewPart;
24 import net.haspamelodica.swt.helper.input.DoubleInput;
25 import net.haspamelodica.swt.helper.zoomablecanvas.helper.ZoomableCanvasUserInput;
26 import net.mograsim.logic.core.LogicObserver;
27 import net.mograsim.logic.core.components.CoreClock;
28 import net.mograsim.logic.model.LogicUICanvas;
29 import net.mograsim.machine.Machine;
30 import net.mograsim.machine.Memory.MemoryCellModifiedListener;
31 import net.mograsim.machine.mi.AssignableMicroInstructionMemory;
32 import net.mograsim.plugin.launch.MachineDebugContextListener;
33 import net.mograsim.plugin.launch.MachineDebugTarget;
34 import net.mograsim.plugin.tables.DisplaySettings;
35 import net.mograsim.plugin.tables.mi.ActiveInstructionPreviewContentProvider;
36 import net.mograsim.plugin.tables.mi.InstructionTable;
37 import net.mograsim.plugin.util.OverlappingFillLayout;
38 import net.mograsim.preferences.Preferences;
40 public class SimulationView extends ViewPart
42 private static final int SIM_SPEED_SCALE_STEPS = 50;
43 private static final double SIM_SPEED_SCALE_STEP_FACTOR = 1.32;
44 private static final double SIM_SPEED_SCALE_STEP_FACTOR_LOG = Math.log(SIM_SPEED_SCALE_STEP_FACTOR);
46 private final Set<Control> controlsToDisableWhenNoMachinePresent;
47 private Button sbseButton;
48 private Scale simSpeedScale;
49 private DoubleInput simSpeedInput;
50 private Composite contextDependentControlsParent;
51 private Composite canvasParent;
52 private InstructionTable instPreview;
53 private ActiveInstructionPreviewContentProvider contentProvider;
54 private Label noRunningMachineLabel;
56 private MachineDebugTarget debugTarget;
57 private LogicUICanvas canvas;
59 private final MemoryCellModifiedListener memCellListener;
60 private final LogicObserver clockObserver;
61 private final MachineDebugContextListener debugContextListener;
62 private final Consumer<Double> executionSpeedListener;
64 public SimulationView()
66 controlsToDisableWhenNoMachinePresent = new HashSet<>();
67 memCellListener = a -> instPreview.refresh();
68 // TODO use Step Over instead
71 if (((CoreClock) o).isOn())
72 SafeRunner.run(() -> debugTarget.suspend());
74 debugContextListener = new MachineDebugContextListener()
77 public void machineDebugContextChanged(Optional<MachineDebugTarget> oldTarget, Optional<MachineDebugTarget> newTarget)
79 SimulationView.this.debugContextChanged(newTarget);
82 executionSpeedListener = this::speedFactorChanged;
86 public void createPartControl(Composite parent)
89 parent.setLayout(new GridLayout());
91 addSimulationControlWidgets(parent);
93 Composite contextDependentControlsParentParent = new Composite(parent, SWT.NONE);
94 contextDependentControlsParentParent.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
95 contextDependentControlsParentParent.setLayout(new OverlappingFillLayout());
97 noRunningMachineLabel = new Label(contextDependentControlsParentParent, SWT.NONE);
98 noRunningMachineLabel.setText("No machine running && selected in the Debug view...");
100 contextDependentControlsParent = new Composite(contextDependentControlsParentParent, SWT.NONE);
101 GridLayout contexDependentControlsLayout = new GridLayout();
102 contexDependentControlsLayout.marginWidth = 0;
103 contexDependentControlsLayout.marginHeight = 0;
104 contextDependentControlsParent.setLayout(contexDependentControlsLayout);
106 canvasParent = new Composite(contextDependentControlsParent, SWT.NONE);
107 canvasParent.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
108 canvasParent.setLayout(new FillLayout());
110 addInstructionPreviewControlWidgets(contextDependentControlsParent);
112 IDebugContextManager debugCManager = DebugUITools.getDebugContextManager();
113 IDebugContextService contextService = debugCManager.getContextService(PlatformUI.getWorkbench().getActiveWorkbenchWindow());
114 contextService.addDebugContextListener(debugContextListener);
115 debugContextListener.debugContextChanged(contextService.getActiveContext());
118 private void addSimulationControlWidgets(Composite parent)
120 Composite c = new Composite(parent, SWT.NONE);
121 c.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false));
122 c.setLayout(new GridLayout(7, false));
124 sbseButton = new Button(c, SWT.CHECK);
125 controlsToDisableWhenNoMachinePresent.add(sbseButton);
127 sbseButton.setText("Step by step execution");
128 sbseButton.addListener(SWT.Selection, e ->
130 CoreClock cl = debugTarget.getMachine().getClock();
131 if (sbseButton.getSelection())
132 cl.registerObserver(clockObserver);
134 cl.deregisterObserver(clockObserver);
136 sbseButton.setSelection(false);
138 Label simSpeedLabel = new Label(c, SWT.NONE);
139 controlsToDisableWhenNoMachinePresent.add(simSpeedLabel);
140 simSpeedLabel.setText("Simulation Speed: ");
142 simSpeedScale = new Scale(c, SWT.NONE);
143 controlsToDisableWhenNoMachinePresent.add(simSpeedScale);
144 simSpeedScale.setMinimum(0);
145 simSpeedScale.setMaximum(SIM_SPEED_SCALE_STEPS);
146 simSpeedScale.setIncrement(1);
147 simSpeedScale.setSelection(0);
148 simSpeedScale.addListener(SWT.Selection, e ->
150 double speed = Math.pow(SIM_SPEED_SCALE_STEP_FACTOR, simSpeedScale.getSelection() - SIM_SPEED_SCALE_STEPS);
151 debugTarget.setExecutionSpeed(speed);
154 simSpeedInput = new DoubleInput(c, SWT.NONE);
155 controlsToDisableWhenNoMachinePresent.add(simSpeedInput);
156 simSpeedInput.setPrecision(Preferences.current().getInt("net.mograsim.plugin.core.simspeedprecision"));
157 simSpeedInput.addChangeListener(speed ->
160 debugTarget.setExecutionSpeed(speed);
162 debugTarget.setExecutionSpeed(Math.pow(10, -simSpeedInput.getPrecision()));
168 private void speedFactorChanged(double speed)
170 simSpeedInput.setValue(speed);
171 int closestScalePos = (int) Math.round(Math.log(speed) / SIM_SPEED_SCALE_STEP_FACTOR_LOG + SIM_SPEED_SCALE_STEPS);
172 simSpeedScale.setSelection(Math.min(Math.max(closestScalePos, 0), SIM_SPEED_SCALE_STEPS));
175 private void addInstructionPreviewControlWidgets(Composite parent)
177 instPreview = new InstructionTable(parent, new DisplaySettings(), getSite().getWorkbenchWindow().getWorkbench().getThemeManager(),
179 instPreview.getTableViewer().getControl().setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false));
180 contentProvider = new ActiveInstructionPreviewContentProvider(instPreview.getTableViewer());
181 instPreview.setContentProvider(contentProvider);
184 private void debugContextChanged(Optional<MachineDebugTarget> newTarget)
186 // call binToDebugTarget even if we didn't find a selected MachineDebugTarget
187 bindToDebugTarget(newTarget.orElse(null));
190 private void bindToDebugTarget(MachineDebugTarget debugTarget)
192 deregisterMachineDependentListeners();
193 this.debugTarget = debugTarget;
195 if (canvasParent == null)
196 // createPartControls has not been called yet
204 offX = canvas.getOffX();
205 offY = canvas.getOffY();
206 zoom = canvas.getZoom();
215 if (debugTarget != null)
217 noRunningMachineLabel.setVisible(false);
218 contextDependentControlsParent.setVisible(true);
219 controlsToDisableWhenNoMachinePresent.forEach(c -> c.setEnabled(true));
221 Machine machine = debugTarget.getMachine();
223 canvas = new LogicUICanvas(canvasParent, SWT.NONE, machine.getModel());
224 canvas.addListener(SWT.MouseDown, e -> canvas.setFocus());
225 ZoomableCanvasUserInput userInput = new ZoomableCanvasUserInput(canvas);
226 userInput.buttonDrag = Preferences.current().getInt("net.mograsim.logic.model.button.drag");
227 userInput.buttonZoom = Preferences.current().getInt("net.mograsim.logic.model.button.zoom");
228 userInput.enableUserInput();
231 canvas.moveTo(offX, offY, zoom);
232 canvas.commitTransform();
235 AssignableMicroInstructionMemory mIMemory = machine.getMicroInstructionMemory();
236 instPreview.bindMicroInstructionMemory(mIMemory);
237 mIMemory.registerCellModifiedListener(memCellListener);
239 canvasParent.layout();
242 contentProvider.setMachine(machine);
244 // initialize executer
245 debugTarget.addExecutionSpeedListener(executionSpeedListener);
246 speedFactorChanged(debugTarget.getExecutionSpeed());
249 noRunningMachineLabel.setVisible(true);
250 contextDependentControlsParent.setVisible(false);
251 controlsToDisableWhenNoMachinePresent.forEach(c -> c.setEnabled(false));
252 contentProvider.setMachine(null);
256 private void deregisterMachineDependentListeners()
258 if (debugTarget != null)
260 debugTarget.removeExecutionSpeedListener(executionSpeedListener);
261 debugTarget.getMachine().getMicroInstructionMemory().deregisterCellModifiedListener(memCellListener);
262 debugTarget.getMachine().getClock().deregisterObserver(clockObserver);
263 if (sbseButton != null && !sbseButton.isDisposed())
264 sbseButton.setSelection(false);
269 public void setFocus()
271 if (canvas != null && !canvas.isDisposed())
276 public void dispose()
278 deregisterMachineDependentListeners();
279 contentProvider.setMachine(null);
280 DebugUITools.getDebugContextManager().removeDebugContextListener(debugContextListener);