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 could this be a breakpoint?
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 // TODO: disable when debugTarget is not set
152 debugTarget.setExecutionSpeed(speed);
155 simSpeedInput = new DoubleInput(c, SWT.NONE);
156 controlsToDisableWhenNoMachinePresent.add(simSpeedInput);
157 simSpeedInput.setPrecision(Preferences.current().getInt("net.mograsim.plugin.core.simspeedprecision"));
158 simSpeedInput.addChangeListener(speed ->
161 debugTarget.setExecutionSpeed(speed);
163 debugTarget.setExecutionSpeed(Math.pow(10, -simSpeedInput.getPrecision()));
169 private void speedFactorChanged(double speed)
171 simSpeedInput.setValue(speed);
172 int closestScalePos = (int) Math.round(Math.log(speed) / SIM_SPEED_SCALE_STEP_FACTOR_LOG + SIM_SPEED_SCALE_STEPS);
173 simSpeedScale.setSelection(Math.min(Math.max(closestScalePos, 0), SIM_SPEED_SCALE_STEPS));
176 private void addInstructionPreviewControlWidgets(Composite parent)
178 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 // if we didn't find a selected MachineDebugTarget
187 // call binToDebugTarget even if this.debugTarget==null
188 bindToDebugTarget(newTarget.orElse(null));
191 private void bindToDebugTarget(MachineDebugTarget debugTarget)
193 deregisterMachineDependentListeners();
194 this.debugTarget = debugTarget;
196 if (canvasParent == null)
197 // createPartControls has not been called yet
205 offX = canvas.getOffX();
206 offY = canvas.getOffY();
207 zoom = canvas.getZoom();
216 if (debugTarget != null)
218 noRunningMachineLabel.setVisible(false);
219 contextDependentControlsParent.setVisible(true);
220 controlsToDisableWhenNoMachinePresent.forEach(c -> c.setEnabled(true));
222 Machine machine = debugTarget.getMachine();
224 canvas = new LogicUICanvas(canvasParent, SWT.NONE, machine.getModel());
225 canvas.addListener(SWT.MouseDown, e -> canvas.setFocus());
226 ZoomableCanvasUserInput userInput = new ZoomableCanvasUserInput(canvas);
227 userInput.buttonDrag = Preferences.current().getInt("net.mograsim.logic.model.button.drag");
228 userInput.buttonZoom = Preferences.current().getInt("net.mograsim.logic.model.button.zoom");
229 userInput.enableUserInput();
232 canvas.moveTo(offX, offY, zoom);
233 canvas.commitTransform();
236 AssignableMicroInstructionMemory mIMemory = machine.getMicroInstructionMemory();
237 instPreview.bindMicroInstructionMemory(mIMemory);
238 mIMemory.registerCellModifiedListener(memCellListener);
240 canvasParent.layout();
243 contentProvider.setMachine(machine);
245 // initialize executer
246 debugTarget.addExecutionSpeedListener(executionSpeedListener);
247 speedFactorChanged(debugTarget.getExecutionSpeed());
250 noRunningMachineLabel.setVisible(true);
251 contextDependentControlsParent.setVisible(false);
252 controlsToDisableWhenNoMachinePresent.forEach(c -> c.setEnabled(false));
253 contentProvider.setMachine(null);
257 private void deregisterMachineDependentListeners()
259 if (debugTarget != null)
261 debugTarget.removeExecutionSpeedListener(executionSpeedListener);
262 debugTarget.getMachine().getMicroInstructionMemory().deregisterCellModifiedListener(memCellListener);
263 debugTarget.getMachine().getClock().deregisterObserver(clockObserver);
264 if (sbseButton != null && !sbseButton.isDisposed())
265 sbseButton.setSelection(false);
270 public void setFocus()
272 if (canvas != null && !canvas.isDisposed())
277 public void dispose()
279 deregisterMachineDependentListeners();
280 contentProvider.setMachine(null);
281 DebugUITools.getDebugContextManager().removeDebugContextListener(debugContextListener);