Merge branch 'development' of https://gitlab.lrz.de/lrr-tum/students/eragp-misim...
[Mograsim.git] / plugins / net.mograsim.plugin.core / src / net / mograsim / plugin / tables / mi / InstructionView.java
1 package net.mograsim.plugin.tables.mi;
2
3 import java.io.BufferedReader;
4 import java.io.File;
5 import java.io.FileReader;
6 import java.io.IOException;
7 import java.util.Arrays;
8
9 import org.eclipse.core.runtime.IProgressMonitor;
10 import org.eclipse.jface.viewers.ColumnLabelProvider;
11 import org.eclipse.jface.viewers.EditingSupport;
12 import org.eclipse.jface.viewers.TableViewerColumn;
13 import org.eclipse.swt.SWT;
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.FileDialog;
19 import org.eclipse.swt.widgets.Table;
20 import org.eclipse.swt.widgets.TableColumn;
21 import org.eclipse.ui.IEditorInput;
22 import org.eclipse.ui.IEditorSite;
23 import org.eclipse.ui.IPathEditorInput;
24 import org.eclipse.ui.PartInitException;
25 import org.eclipse.ui.part.EditorPart;
26
27 import net.mograsim.machine.MemoryObserver;
28 import net.mograsim.machine.mi.MicroInstructionDefinition;
29 import net.mograsim.machine.mi.MicroInstructionMemory;
30 import net.mograsim.machine.mi.MicroInstructionMemoryParseException;
31 import net.mograsim.machine.mi.MicroInstructionMemoryParser;
32 import net.mograsim.machine.mi.parameters.MnemonicFamily;
33 import net.mograsim.machine.mi.parameters.ParameterClassification;
34 import net.mograsim.plugin.MachineContext;
35 import net.mograsim.plugin.tables.AddressLabelProvider;
36 import net.mograsim.plugin.tables.DisplaySettings;
37 import net.mograsim.plugin.tables.LazyTableViewer;
38 import net.mograsim.plugin.tables.RadixSelector;
39
40 public class InstructionView extends EditorPart implements MemoryObserver
41 {
42         private LazyTableViewer viewer;
43         private TableViewerColumn[] columns = new TableViewerColumn[0];
44         private MicroInstructionDefinition miDef;
45         private MicroInstructionMemory memory;
46         private DisplaySettings displaySettings;
47         private InstructionTableContentProvider provider;
48         private int highlighted = 0;
49         private boolean dirty = false;
50         private String machineName;
51
52         @SuppressWarnings("unused")
53         @Override
54         public void createPartControl(Composite parent)
55         {
56                 provider = new InstructionTableContentProvider();
57                 GridLayout layout = new GridLayout(3, false);
58                 parent.setLayout(layout);
59
60                 displaySettings = new DisplaySettings();
61                 new RadixSelector(parent, displaySettings);
62
63                 addActivationButton(parent);
64                 viewer = new LazyTableViewer(parent, SWT.MULTI | SWT.H_SCROLL | SWT.V_SCROLL | SWT.FULL_SELECTION | SWT.BORDER | SWT.VIRTUAL);
65
66                 Table table = viewer.getTable();
67                 table.setHeaderVisible(true);
68                 table.setLinesVisible(true);
69                 viewer.setUseHashlookup(true);
70                 viewer.setContentProvider(provider);
71                 setViewerInput(memory);
72                 getSite().setSelectionProvider(viewer);
73
74                 GridData viewerData = new GridData(GridData.GRAB_HORIZONTAL | GridData.GRAB_VERTICAL | GridData.FILL_BOTH);
75                 viewerData.horizontalSpan = 3;
76                 viewer.getTable().setLayoutData(viewerData);
77
78                 displaySettings.addObserver(() -> viewer.refresh());
79         }
80
81         private void addActivationButton(Composite parent)
82         {
83                 Button activationButton = new Button(parent, SWT.PUSH);
84                 activationButton.setText("Set Active");
85                 activationButton.addListener(SWT.Selection,
86                                 e -> MachineContext.getInstance().getMachine().getMicroInstructionMemory().bind(memory));
87         }
88
89         public void highlight(int index)
90         {
91                 viewer.highlightRow(highlighted, false);
92                 viewer.highlightRow(index, true);
93                 viewer.getTable().setTopIndex(index);
94         }
95
96         public void bindMicroInstructionMemory(MicroInstructionMemory memory)
97         {
98                 this.memory = memory;
99                 this.miDef = memory.getDefinition().getMicroInstructionDefinition();
100                 this.memory.registerObserver(this);
101                 setViewerInput(memory);
102         }
103
104         private void setViewerInput(MicroInstructionMemory memory)
105         {
106                 if (viewer != null)
107                 {
108                         deleteColumns();
109                         viewer.setInput(memory);
110                         createColumns();
111                 }
112         }
113
114         private void deleteColumns()
115         {
116                 for (TableViewerColumn col : columns)
117                         col.getColumn().dispose();
118         }
119
120         private void createColumns()
121         {
122                 int size = miDef.size();
123                 columns = new TableViewerColumn[size + 1];
124
125                 TableViewerColumn col = createTableViewerColumn("Address", generateLongestHexStrings(12));
126                 columns[0] = col;
127                 col.setLabelProvider(new AddressLabelProvider());
128
129                 int bit = miDef.sizeInBits();
130                 ParameterClassification[] classes = miDef.getParameterClassifications();
131
132                 for (int i = 0; i < size; i++)
133                 {
134                         int startBit = bit - 1;
135                         int endBit = bit = bit - classes[i].getExpectedBits();
136                         String name = startBit == endBit ? Integer.toString(startBit) : startBit + "..." + endBit;
137
138                         String[] longestPossibleContents;
139                         switch (classes[i].getExpectedType())
140                         {
141                         case INTEGER_IMMEDIATE:
142                                 longestPossibleContents = generateLongestHexStrings(classes[i].getExpectedBits());
143                                 break;
144                         case BOOLEAN_IMMEDIATE:
145                         case MNEMONIC:
146                                 longestPossibleContents = ((MnemonicFamily) classes[i]).getStringValues();
147                                 break;
148                         default:
149                                 longestPossibleContents = new String[0];
150                                 break;
151                         }
152
153                         col = createTableViewerColumn(name, longestPossibleContents);
154                         columns[i + 1] = col;
155                         createEditingAndLabel(col, miDef, i);
156                 }
157         }
158
159         private static final String[] HEX_DIGITS = { "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "A", "B", "C", "D", "E", "F" };
160
161         private static String[] generateLongestHexStrings(int bitWidth)
162         {
163                 return Arrays.stream(HEX_DIGITS).map(s -> "0x" + s.repeat((bitWidth + 3) / 4)).toArray(String[]::new);
164         }
165
166         private void createEditingAndLabel(TableViewerColumn col, MicroInstructionDefinition miDef, int index)
167         {
168                 ParameterClassification parameterClassification = miDef.getParameterClassifications()[index];
169                 EditingSupport support;
170                 ColumnLabelProvider provider;
171                 switch (parameterClassification.getExpectedType())
172                 {
173                 case BOOLEAN_IMMEDIATE:
174                         support = new BooleanEditingSupport(viewer, miDef, index);
175                         provider = new ParameterLabelProvider(index);
176                         break;
177                 case INTEGER_IMMEDIATE:
178                         support = new IntegerEditingSupport(viewer, miDef, index, displaySettings, this.provider);
179                         provider = new IntegerColumnLabelProvider(displaySettings, index);
180                         break;
181                 case MNEMONIC:
182                         support = new MnemonicEditingSupport(viewer, miDef, index, this.provider);
183                         provider = new ParameterLabelProvider(index);
184                         break;
185                 default:
186                         throw new IllegalStateException(
187                                         "Unable to create EditingSupport for unknown ParameterType " + parameterClassification.getExpectedType());
188                 }
189                 col.setEditingSupport(support);
190                 col.setLabelProvider(provider);
191                 col.getColumn().setToolTipText(miDef.getParameterDescription(index).orElse(""));
192         }
193
194         private TableViewerColumn createTableViewerColumn(String title, String... longestPossibleContents)
195         {
196                 TableViewerColumn viewerColumn = new TableViewerColumn(viewer, SWT.NONE);
197                 TableColumn column = viewerColumn.getColumn();
198                 int maxWidth = 0;
199                 for (String s : longestPossibleContents)
200                 {
201                         column.setText(s);
202                         column.pack();
203                         if (column.getWidth() > maxWidth)
204                                 maxWidth = column.getWidth();
205                 }
206                 column.setText(title);
207                 column.pack();
208                 if (column.getWidth() < maxWidth)
209                         column.setWidth(maxWidth);
210                 column.setResizable(true);
211                 column.setMoveable(false);
212                 return viewerColumn;
213         }
214
215         private void open(String file)
216         {
217                 try (BufferedReader bf = new BufferedReader(new FileReader(file)))
218                 {
219                         machineName = bf.readLine();
220                         bindMicroInstructionMemory(MicroInstructionMemoryParser.parseMemory(machineName, bf));
221                 }
222                 catch (IOException | MicroInstructionMemoryParseException e)
223                 {
224                         e.printStackTrace();
225                 }
226         }
227
228         private void save(String file)
229         {
230                 if (memory == null)
231                 {
232                         System.err.println("Failed to write MicroprogrammingMemory to File. No MicroprogrammingMemory assigned.");
233                         return;
234                 }
235                 try
236                 {
237                         MicroInstructionMemoryParser.write(memory, machineName, file);
238                 }
239                 catch (IOException e)
240                 {
241                         e.printStackTrace();
242                 }
243         }
244
245         @Override
246         public void setFocus()
247         {
248                 viewer.getControl().setFocus();
249         }
250
251         @Override
252         public void doSave(IProgressMonitor progressMonitor)
253         {
254                 IEditorInput input = getEditorInput();
255                 if (input instanceof IPathEditorInput)
256                 {
257                         IPathEditorInput pathInput = (IPathEditorInput) input;
258                         save(pathInput.getPath().toOSString());
259                         setDirty(false);
260                 }
261         }
262
263         @Override
264         public void doSaveAs()
265         {
266                 openSaveAsDialog();
267         }
268
269         private void openSaveAsDialog()
270         {
271                 FileDialog d = new FileDialog(viewer.getTable().getShell(), SWT.SAVE);
272                 d.open();
273                 String filename = d.getFileName();
274                 if (!filename.equals(""))
275                 {
276                         save(d.getFilterPath() + File.separator + filename);
277                         setDirty(false);
278                 }
279         }
280
281         @Override
282         public void init(IEditorSite site, IEditorInput input) throws PartInitException
283         {
284                 setSite(site);
285                 setInput(input);
286                 if (input instanceof IPathEditorInput)
287                 {
288                         IPathEditorInput pathInput = (IPathEditorInput) input;
289                         setPartName(pathInput.getName());
290                         open(pathInput.getPath().toOSString());
291                 }
292         }
293
294         @Override
295         public boolean isDirty()
296         {
297                 return dirty;
298         }
299
300         @Override
301         public boolean isSaveAsAllowed()
302         {
303                 return true;
304         }
305
306         @Override
307         public void update(long address)
308         {
309                 setDirty(true);
310         }
311
312         private void setDirty(boolean value)
313         {
314                 dirty = value;
315                 firePropertyChange(PROP_DIRTY);
316         }
317 }