1 package net.mograsim.plugin.views;
3 import static net.mograsim.logic.model.preferences.RenderPreferences.DRAG_BUTTON;
4 import static net.mograsim.logic.model.preferences.RenderPreferences.ZOOM_BUTTON;
5 import static net.mograsim.plugin.preferences.PluginPreferences.SIMULATION_SPEED_PRECISION;
7 import java.util.HashSet;
8 import java.util.Optional;
10 import java.util.function.Consumer;
12 import org.eclipse.core.runtime.SafeRunner;
13 import org.eclipse.debug.ui.DebugUITools;
14 import org.eclipse.debug.ui.contexts.IDebugContextManager;
15 import org.eclipse.debug.ui.contexts.IDebugContextService;
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.logic.model.preferences.RenderPreferences;
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.MograsimActivator;
38 import net.mograsim.plugin.launch.MachineDebugContextListener;
39 import net.mograsim.plugin.launch.MachineDebugTarget;
40 import net.mograsim.plugin.tables.DisplaySettings;
41 import net.mograsim.plugin.tables.mi.ActiveInstructionPreviewContentProvider;
42 import net.mograsim.plugin.tables.mi.InstructionTable;
43 import net.mograsim.plugin.util.OverlappingFillLayout;
45 public class SimulationView extends ViewPart
47 private static final int SIM_SPEED_SCALE_STEPS = 50;
48 private static final double SIM_SPEED_SCALE_STEP_FACTOR = 1.32;
49 private static final double SIM_SPEED_SCALE_STEP_FACTOR_LOG = Math.log(SIM_SPEED_SCALE_STEP_FACTOR);
51 private final Set<Control> controlsToDisableWhenNoMachinePresent;
52 private Button sbseButton;
53 private Scale simSpeedScale;
54 private DoubleInput simSpeedInput;
55 private Composite contextDependentControlsParent;
56 private Composite canvasParent;
57 private InstructionTable instPreview;
58 private ActiveInstructionPreviewContentProvider contentProvider;
59 private Label noRunningMachineLabel;
61 private MachineDebugTarget debugTarget;
62 private LogicUICanvas canvas;
64 private final MemoryCellModifiedListener memCellListener;
65 private final LogicObserver clockObserver;
66 private final MachineDebugContextListener debugContextListener;
67 private final Consumer<Double> executionSpeedListener;
69 public SimulationView()
71 controlsToDisableWhenNoMachinePresent = new HashSet<>();
72 memCellListener = a -> instPreview.refresh();
73 // TODO use Step Over instead
76 if (((CoreClock) o).isOn())
77 SafeRunner.run(() -> debugTarget.suspend());
79 debugContextListener = new MachineDebugContextListener()
82 public void machineDebugContextChanged(Optional<MachineDebugTarget> oldTarget, Optional<MachineDebugTarget> newTarget)
84 SimulationView.this.debugContextChanged(newTarget);
87 executionSpeedListener = this::speedFactorChanged;
91 public void createPartControl(Composite parent)
94 parent.setLayout(new GridLayout());
96 addSimulationControlWidgets(parent);
98 Composite contextDependentControlsParentParent = new Composite(parent, SWT.NONE);
99 contextDependentControlsParentParent.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
100 contextDependentControlsParentParent.setLayout(new OverlappingFillLayout());
102 noRunningMachineLabel = new Label(contextDependentControlsParentParent, SWT.NONE);
103 noRunningMachineLabel.setText("No machine running && selected in the Debug view...");
105 contextDependentControlsParent = new Composite(contextDependentControlsParentParent, SWT.NONE);
106 GridLayout contexDependentControlsLayout = new GridLayout();
107 contexDependentControlsLayout.marginWidth = 0;
108 contexDependentControlsLayout.marginHeight = 0;
109 contextDependentControlsParent.setLayout(contexDependentControlsLayout);
111 canvasParent = new Composite(contextDependentControlsParent, SWT.NONE);
112 canvasParent.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
113 canvasParent.setLayout(new FillLayout());
115 addInstructionPreviewControlWidgets(contextDependentControlsParent);
117 IDebugContextManager debugCManager = DebugUITools.getDebugContextManager();
118 IDebugContextService contextService = debugCManager.getContextService(PlatformUI.getWorkbench().getActiveWorkbenchWindow());
119 contextService.addDebugContextListener(debugContextListener);
120 debugContextListener.debugContextChanged(contextService.getActiveContext());
123 private void addSimulationControlWidgets(Composite parent)
125 Composite c = new Composite(parent, SWT.NONE);
126 c.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false));
127 c.setLayout(new GridLayout(7, false));
129 sbseButton = new Button(c, SWT.CHECK);
130 controlsToDisableWhenNoMachinePresent.add(sbseButton);
132 sbseButton.setText("Step by step execution");
133 sbseButton.addListener(SWT.Selection, e ->
135 CoreClock cl = debugTarget.getMachine().getClock();
136 if (sbseButton.getSelection())
137 cl.registerObserver(clockObserver);
139 cl.deregisterObserver(clockObserver);
141 sbseButton.setSelection(false);
143 Label simSpeedLabel = new Label(c, SWT.NONE);
144 controlsToDisableWhenNoMachinePresent.add(simSpeedLabel);
145 simSpeedLabel.setText("Simulation Speed: ");
147 simSpeedScale = new Scale(c, SWT.NONE);
148 controlsToDisableWhenNoMachinePresent.add(simSpeedScale);
149 simSpeedScale.setMinimum(0);
150 simSpeedScale.setMaximum(SIM_SPEED_SCALE_STEPS);
151 simSpeedScale.setIncrement(1);
152 simSpeedScale.setSelection(0);
153 simSpeedScale.addListener(SWT.Selection, e ->
155 double speed = Math.pow(SIM_SPEED_SCALE_STEP_FACTOR, simSpeedScale.getSelection() - SIM_SPEED_SCALE_STEPS);
156 debugTarget.setExecutionSpeed(speed);
159 simSpeedInput = new DoubleInput(c, SWT.NONE);
160 controlsToDisableWhenNoMachinePresent.add(simSpeedInput);
161 // TODO add a listener
162 simSpeedInput.setPrecision(MograsimActivator.instance().getPluginPrefs().getInt(SIMULATION_SPEED_PRECISION));
163 simSpeedInput.addChangeListener(speed ->
166 debugTarget.setExecutionSpeed(speed);
168 debugTarget.setExecutionSpeed(Math.pow(10, -simSpeedInput.getPrecision()));
174 private void speedFactorChanged(double speed)
176 simSpeedInput.setValue(speed);
177 int closestScalePos = (int) Math.round(Math.log(speed) / SIM_SPEED_SCALE_STEP_FACTOR_LOG + SIM_SPEED_SCALE_STEPS);
178 simSpeedScale.setSelection(Math.min(Math.max(closestScalePos, 0), SIM_SPEED_SCALE_STEPS));
181 private void addInstructionPreviewControlWidgets(Composite parent)
183 instPreview = new InstructionTable(parent, new DisplaySettings(), getSite().getWorkbenchWindow().getWorkbench().getThemeManager(),
185 instPreview.getTableViewer().getControl().setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false));
186 contentProvider = new ActiveInstructionPreviewContentProvider(instPreview.getTableViewer());
187 instPreview.setContentProvider(contentProvider);
190 private void debugContextChanged(Optional<MachineDebugTarget> newTarget)
192 // call binToDebugTarget even if we didn't find a selected MachineDebugTarget
193 bindToDebugTarget(newTarget.orElse(null));
196 private void bindToDebugTarget(MachineDebugTarget debugTarget)
198 deregisterMachineDependentListeners();
199 this.debugTarget = debugTarget;
201 if (canvasParent == null)
202 // createPartControls has not been called yet
210 offX = canvas.getOffX();
211 offY = canvas.getOffY();
212 zoom = canvas.getZoom();
221 if (debugTarget != null)
223 noRunningMachineLabel.setVisible(false);
224 contextDependentControlsParent.setVisible(true);
225 controlsToDisableWhenNoMachinePresent.forEach(c -> c.setEnabled(true));
227 Machine machine = debugTarget.getMachine();
229 RenderPreferences renderPrefs = MograsimActivator.instance().getRenderPrefs();
230 canvas = new LogicUICanvas(canvasParent, SWT.NONE, machine.getModel(), renderPrefs);
231 canvas.addListener(SWT.MouseDown, e -> canvas.setFocus());
232 ZoomableCanvasUserInput userInput = new ZoomableCanvasUserInput(canvas);
233 // TODO add a listener
234 userInput.buttonDrag = renderPrefs.getInt(DRAG_BUTTON);
235 // TODO add a listener
236 userInput.buttonZoom = renderPrefs.getInt(ZOOM_BUTTON);
237 userInput.enableUserInput();
240 canvas.moveTo(offX, offY, zoom);
241 canvas.commitTransform();
244 AssignableMicroInstructionMemory mIMemory = machine.getMicroInstructionMemory();
245 instPreview.bindMicroInstructionMemory(mIMemory);
246 mIMemory.registerCellModifiedListener(memCellListener);
248 canvasParent.layout();
251 contentProvider.setMachine(machine);
253 // initialize executer
254 debugTarget.addExecutionSpeedListener(executionSpeedListener);
255 speedFactorChanged(debugTarget.getExecutionSpeed());
258 noRunningMachineLabel.setVisible(true);
259 contextDependentControlsParent.setVisible(false);
260 controlsToDisableWhenNoMachinePresent.forEach(c -> c.setEnabled(false));
261 contentProvider.setMachine(null);
265 private void deregisterMachineDependentListeners()
267 if (debugTarget != null)
269 debugTarget.removeExecutionSpeedListener(executionSpeedListener);
270 debugTarget.getMachine().getMicroInstructionMemory().deregisterCellModifiedListener(memCellListener);
271 debugTarget.getMachine().getClock().deregisterObserver(clockObserver);
272 if (sbseButton != null && !sbseButton.isDisposed())
273 sbseButton.setSelection(false);
278 public void setFocus()
280 if (canvas != null && !canvas.isDisposed())
285 public void dispose()
287 deregisterMachineDependentListeners();
288 contentProvider.setMachine(null);
289 DebugUITools.getDebugContextManager().removeDebugContextListener(debugContextListener);