From e6565c6da050c719d4cb69185f420aafed449f67 Mon Sep 17 00:00:00 2001 From: Fabian Stemmler Date: Mon, 2 Sep 2019 17:14:24 +0200 Subject: [PATCH] Added View for micro instruction editor --- net.mograsim.machine/META-INF/MANIFEST.MF | 2 + .../mograsim/machine/MemoryDefinition.java | 2 +- .../mi/MicroprogramMemoryParseException.java | 28 +++ .../machine/mi/MicroprogramMemoryParser.java | 80 ++++++-- .../mi/StandardMicroprogramMemory.java | 2 +- .../OSGI-INF/l10n/bundle_de.properties | 1 + .../OSGI-INF/l10n/bundle.properties | 1 + net.mograsim.plugin.core/plugin.xml | 11 +- .../tables/mi/BooleanEditingSupport.java | 50 +++++ .../mi/InstructionTableContentProvider.java | 28 +++ .../plugin/tables/mi/InstructionView.java | 194 ++++++++++++++++++ .../tables/mi/IntegerEditingSupport.java | 38 ++++ .../mi/MnemonicCellEditorValidator.java | 24 +++ .../tables/mi/MnemonicEditingSupport.java | 56 +++++ .../tables/mi/ParameterLabelProvider.java | 22 ++ .../mograsim/plugin/util/DropDownMenu.java | 86 ++++++++ 16 files changed, 599 insertions(+), 26 deletions(-) create mode 100644 net.mograsim.machine/src/net/mograsim/machine/mi/MicroprogramMemoryParseException.java create mode 100644 net.mograsim.plugin.core/src/net/mograsim/plugin/tables/mi/BooleanEditingSupport.java create mode 100644 net.mograsim.plugin.core/src/net/mograsim/plugin/tables/mi/InstructionTableContentProvider.java create mode 100644 net.mograsim.plugin.core/src/net/mograsim/plugin/tables/mi/InstructionView.java create mode 100644 net.mograsim.plugin.core/src/net/mograsim/plugin/tables/mi/IntegerEditingSupport.java create mode 100644 net.mograsim.plugin.core/src/net/mograsim/plugin/tables/mi/MnemonicCellEditorValidator.java create mode 100644 net.mograsim.plugin.core/src/net/mograsim/plugin/tables/mi/MnemonicEditingSupport.java create mode 100644 net.mograsim.plugin.core/src/net/mograsim/plugin/tables/mi/ParameterLabelProvider.java create mode 100644 net.mograsim.plugin.core/src/net/mograsim/plugin/util/DropDownMenu.java diff --git a/net.mograsim.machine/META-INF/MANIFEST.MF b/net.mograsim.machine/META-INF/MANIFEST.MF index 518b6a13..dfdcb05d 100644 --- a/net.mograsim.machine/META-INF/MANIFEST.MF +++ b/net.mograsim.machine/META-INF/MANIFEST.MF @@ -12,4 +12,6 @@ Require-Bundle: net.mograsim.logic.core;bundle-version="0.1.0", Export-Package: net.mograsim.machine, net.mograsim.machine.isa, net.mograsim.machine.isa.types, + net.mograsim.machine.mi, + net.mograsim.machine.mi.parameters, net.mograsim.machine.standard.memory diff --git a/net.mograsim.machine/src/net/mograsim/machine/MemoryDefinition.java b/net.mograsim.machine/src/net/mograsim/machine/MemoryDefinition.java index 5f42d10c..78e1e4e2 100644 --- a/net.mograsim.machine/src/net/mograsim/machine/MemoryDefinition.java +++ b/net.mograsim.machine/src/net/mograsim/machine/MemoryDefinition.java @@ -34,7 +34,7 @@ public interface MemoryDefinition { */ default long size() { - return getMaximalAddress() - getMinimalAddress(); + return getMaximalAddress() - getMinimalAddress() + 1; } public static MemoryDefinition create(int memoryAddressBits, long minimalAddress, long maximalAddress) diff --git a/net.mograsim.machine/src/net/mograsim/machine/mi/MicroprogramMemoryParseException.java b/net.mograsim.machine/src/net/mograsim/machine/mi/MicroprogramMemoryParseException.java new file mode 100644 index 00000000..eea81af6 --- /dev/null +++ b/net.mograsim.machine/src/net/mograsim/machine/mi/MicroprogramMemoryParseException.java @@ -0,0 +1,28 @@ +package net.mograsim.machine.mi; + +import net.mograsim.machine.MachineException; + +public class MicroprogramMemoryParseException extends MachineException +{ + + /** + * + */ + private static final long serialVersionUID = 6820101808901789906L; + + public MicroprogramMemoryParseException() + { + super(); + } + + public MicroprogramMemoryParseException(String message) + { + super(message); + } + + public MicroprogramMemoryParseException(Throwable cause) + { + super(cause); + } + +} diff --git a/net.mograsim.machine/src/net/mograsim/machine/mi/MicroprogramMemoryParser.java b/net.mograsim.machine/src/net/mograsim/machine/mi/MicroprogramMemoryParser.java index 065ba152..1e34762b 100644 --- a/net.mograsim.machine/src/net/mograsim/machine/mi/MicroprogramMemoryParser.java +++ b/net.mograsim.machine/src/net/mograsim/machine/mi/MicroprogramMemoryParser.java @@ -7,6 +7,8 @@ import java.io.IOException; import java.io.InputStreamReader; import java.io.OutputStreamWriter; import java.math.BigInteger; +import java.util.ArrayList; +import java.util.List; import net.mograsim.logic.core.types.BitVector; import net.mograsim.machine.MemoryDefinition; @@ -21,28 +23,34 @@ import net.mograsim.machine.mi.parameters.ParameterClassification; public class MicroprogramMemoryParser { - public static void parse(MicroprogramMemory memory, long startAddress, MicroInstructionDefinition definition, String input) throws IOException + public static MicroprogramMemory parseMemory(MicroInstructionDefinition definition, String input) throws IOException { try (BufferedReader reader = new BufferedReader(new InputStreamReader(new FileInputStream(input)))) { - parse(memory, startAddress, definition, reader); + return parseMemory(definition, reader); } } - public static void parse(MicroprogramMemory memory, long startAddress, MicroInstructionDefinition definition, - BufferedReader input) + public static MicroprogramMemory parseMemory(MicroInstructionDefinition definition, BufferedReader input) { - MemoryDefinition def = memory.getDefinition(); - long minAddress = Long.max(startAddress, def.getMinimalAddress()), maxAddress = def.getMaximalAddress(); + List instructions = new ArrayList<>(); try { String line; - for (long i = minAddress; i < maxAddress && input.ready() && !"".equals((line = input.readLine())); i++) - memory.setCell(i, parse(definition, line)); + while (input.ready() && !"".equals((line = input.readLine()))) + instructions.add(parse(definition, line)); } catch (IOException e) { e.printStackTrace(); } + + int maxAddress = instructions.size() - 1; + MicroprogramMemory memory = MicroprogramMemory + .create(MemoryDefinition.create((int) Math.ceil(Math.log(maxAddress)), 0, maxAddress)); + int i = 0; + for (MicroInstruction inst : instructions) + memory.setCell(i++, inst); + return memory; } public static MicroInstruction parse(MicroInstructionDefinition definition, String toParse) @@ -50,40 +58,46 @@ public class MicroprogramMemoryParser int size = definition.size(); String[] strings = toParse.split(","); if (size != strings.length) - throw new IllegalArgumentException( + throw new MicroprogramMemoryParseException( "String does not match definition! The number of parameters does not match."); MicroInstructionParameter[] params = new MicroInstructionParameter[size]; ParameterClassification[] classes = definition.getParameterClassifications(); - for (int i = 0; i < size; i++) + try { - params[i] = classes[i].parse(strings[i]); + for (int i = 0; i < size; i++) + { + params[i] = classes[i].parse(strings[i]); + } + return new StandardMicroInstruction(params); + } catch (Exception e) + { + throw new MicroprogramMemoryParseException(e.getCause()); } - return new StandardMicroInstruction(params); } - - public static void write(MicroprogramMemory memory, long startAddress, long endAddress, String output) throws IOException + + public static void write(MicroprogramMemory memory, String output) throws IOException { - try(OutputStreamWriter writer = new OutputStreamWriter(new FileOutputStream(output))) + try (OutputStreamWriter writer = new OutputStreamWriter(new FileOutputStream(output))) { - write(memory, startAddress, endAddress, writer); + write(memory, writer); } } - - public static void write(MicroprogramMemory memory, long startAddress, long endAddress, OutputStreamWriter output) throws IOException + + public static void write(MicroprogramMemory memory, OutputStreamWriter output) throws IOException { MemoryDefinition def = memory.getDefinition(); - long min = Long.max(def.getMinimalAddress(), startAddress), max = Long.min(def.getMaximalAddress(), endAddress) + 1; - for(long i = min; i < max; i++) + long min = def.getMinimalAddress(), max = def.getMaximalAddress() + 1; + for (long i = min; i < max; i++) { output.write(toCSV(memory.getCell(i)) + "\n"); } } - + private static String toCSV(MicroInstruction inst) { int max = inst.getSize() - 1; StringBuilder sb = new StringBuilder(); - for(int i = 0; i < max; i++) + for (int i = 0; i < max; i++) { sb.append(inst.getParameter(i).toString()); sb.append(","); @@ -91,4 +105,26 @@ public class MicroprogramMemoryParser sb.append(inst.getParameter(max).toString()); return sb.toString(); } + + public static void main(String[] args) + { + MnemonicFamily family = new MnemonicFamily(new MnemonicPair("ZERO", BitVector.SINGLE_0), + new MnemonicPair("ONE", BitVector.SINGLE_1)); + MicroInstructionDefinition def = MicroInstructionDefinition.create(new BooleanClassification(), + new IntegerClassification(8), family); + MicroprogramMemory memory = new StandardMicroprogramMemory(MemoryDefinition.create(4, 0, 16)); + for (int i = 0; i < 17; i++) + memory.setCell(i, new StandardMicroInstruction(new BooleanImmediate(false), + new IntegerImmediate(BigInteger.valueOf(i), 8), family.get(i % 2))); + try + { + write(memory, "test.txt"); + MicroprogramMemory newMemory = parseMemory(def, "test.txt"); + write(newMemory, "test2.txt"); + } catch (IOException e) + { + e.printStackTrace(); + } + + } } diff --git a/net.mograsim.machine/src/net/mograsim/machine/mi/StandardMicroprogramMemory.java b/net.mograsim.machine/src/net/mograsim/machine/mi/StandardMicroprogramMemory.java index a253f22d..e06a94da 100644 --- a/net.mograsim.machine/src/net/mograsim/machine/mi/StandardMicroprogramMemory.java +++ b/net.mograsim.machine/src/net/mograsim/machine/mi/StandardMicroprogramMemory.java @@ -10,7 +10,7 @@ class StandardMicroprogramMemory implements MicroprogramMemory { private MicroInstruction[] data; private MemoryDefinition definition; - private HashSet observers; + private HashSet observers = new HashSet<>(); StandardMicroprogramMemory(MemoryDefinition definition) { diff --git a/net.mograsim.plugin.core.nl_de/OSGI-INF/l10n/bundle_de.properties b/net.mograsim.plugin.core.nl_de/OSGI-INF/l10n/bundle_de.properties index 6297d7d7..5f8222d7 100644 --- a/net.mograsim.plugin.core.nl_de/OSGI-INF/l10n/bundle_de.properties +++ b/net.mograsim.plugin.core.nl_de/OSGI-INF/l10n/bundle_de.properties @@ -30,4 +30,5 @@ colorDefinition.label.10 = Simulation Textfarbe fontDefinition.label = Assembler Operation Textstil view.name.0 = Simulation View view.name.1 = Speicher +view.name.2 = Instruktionseditor themeElementCategory.label.0 = Simulation \ No newline at end of file diff --git a/net.mograsim.plugin.core/OSGI-INF/l10n/bundle.properties b/net.mograsim.plugin.core/OSGI-INF/l10n/bundle.properties index 87fc3eef..856144a6 100644 --- a/net.mograsim.plugin.core/OSGI-INF/l10n/bundle.properties +++ b/net.mograsim.plugin.core/OSGI-INF/l10n/bundle.properties @@ -30,5 +30,6 @@ colorDefinition.label.10 = Simulation text color fontDefinition.label = Assembler Operation Style view.name.0 = Simulation View view.name.1 = Memory +view.name.1 = Instruction Editor themeElementCategory.label.0 = Simulation Bundle-Vendor.0 = Mograsim Team \ No newline at end of file diff --git a/net.mograsim.plugin.core/plugin.xml b/net.mograsim.plugin.core/plugin.xml index 5932f6d2..dccf76c8 100644 --- a/net.mograsim.plugin.core/plugin.xml +++ b/net.mograsim.plugin.core/plugin.xml @@ -90,10 +90,17 @@ + + + { + FileDialog d = new FileDialog(parent.getShell(), SWT.NONE); + d.open(); + String filename = d.getFileName(); + if (!filename.equals("")) + open(d.getFilterPath() + File.separator + filename); + }); + + DropDownEntry save = new DropDownEntry("Save", (e) -> + { + if (saveLoc == null) + openSaveAsDialog(parent); + save(saveLoc); + }); + DropDownEntry saveAs = new DropDownEntry("SaveAs", (e) -> + { + openSaveAsDialog(parent); + save(saveLoc); + }); + new DropDownMenu(parent, "File", open, save, saveAs); + } + + private void openSaveAsDialog(Composite parent) + { + FileDialog d = new FileDialog(parent.getShell(), SWT.SAVE); + d.open(); + String filename = d.getFileName(); + if (!filename.equals("")) + saveLoc = d.getFilterPath() + File.separator + filename; + } + + public void bindMicroprogramMemory(MicroprogramMemory memory) + { + this.memory = memory; + viewer.setInput(memory); + } + + public void bindMicroInstructionDef(MicroInstructionDefinition miDef) + { + this.miDef = miDef; + createColumns(); + } + + private void createColumns() + { + for (TableViewerColumn col : columns) + col.getColumn().dispose(); + int size = miDef.size(); + int bit = 0; + columns = new TableViewerColumn[size]; + ParameterClassification[] classes = miDef.getParameterClassifications(); + + for (int i = 0; i < size; i++) + { + int startBit = bit; + int endBit = (bit = bit + classes[i].getExpectedBits()) - 1; + String name = startBit == endBit ? Integer.toString(startBit) : startBit + "..." + endBit; + int bounds = 20 + 20 * classes[i].getExpectedBits(); + + TableViewerColumn col = createTableViewerColumn(name, bounds); + col.setLabelProvider(new ParameterLabelProvider(i)); + col.setEditingSupport(createEditingSupport(miDef, i)); + } + + } + + private EditingSupport createEditingSupport(MicroInstructionDefinition miDef, int index) + { + ParameterClassification parameterClassification = miDef.getParameterClassifications()[index]; + switch (parameterClassification.getExpectedType()) + { + case BOOLEAN_IMMEDIATE: + return new BooleanEditingSupport(viewer, index); + case INTEGER_IMMEDIATE: + return new IntegerEditingSupport(viewer, miDef, index, new DisplaySettings(NumberType.DECIMAL)); + case MNEMONIC: + return new MnemonicEditingSupport(viewer, miDef, index); + default: + throw new IllegalStateException( + "Unable to create EditingSupport for unknown ParameterType " + parameterClassification.getExpectedType()); + } + } + + private TableViewerColumn createTableViewerColumn(String title, int bound) + { + TableViewerColumn viewerColumn = new TableViewerColumn(viewer, SWT.NONE); + TableColumn column = viewerColumn.getColumn(); + column.setText(title); + column.setWidth(bound); + column.setResizable(true); + column.setMoveable(false); + return viewerColumn; + } + + private void open(String file) + { + if (miDef == null) + { + System.err.println("Failed to parse MicroprogrammingMemory from File. No MicroInstructionDefinition assigned."); + return; + } + try + { + MicroprogramMemory newMemory = MicroprogramMemoryParser.parseMemory(miDef, file); + bindMicroprogramMemory(newMemory); + saveLoc = file; + } + catch (IOException | MicroprogramMemoryParseException e) + { + e.printStackTrace(); + } + } + + private void save(String file) + { + if (memory == null) + { + System.err.println("Failed to write MicroprogrammingMemory to File. No MicroprogrammingMemory assigned."); + } + if (saveLoc != null) + { + try + { + MicroprogramMemoryParser.write(memory, file); + } + catch (IOException e) + { + e.printStackTrace(); + } + } + } + + @Override + public void setFocus() + { + viewer.getControl().setFocus(); + } +} diff --git a/net.mograsim.plugin.core/src/net/mograsim/plugin/tables/mi/IntegerEditingSupport.java b/net.mograsim.plugin.core/src/net/mograsim/plugin/tables/mi/IntegerEditingSupport.java new file mode 100644 index 00000000..43d6041e --- /dev/null +++ b/net.mograsim.plugin.core/src/net/mograsim/plugin/tables/mi/IntegerEditingSupport.java @@ -0,0 +1,38 @@ +package net.mograsim.plugin.tables.mi; + +import java.math.BigInteger; + +import org.eclipse.jface.viewers.TableViewer; + +import net.mograsim.machine.mi.MicroInstruction; +import net.mograsim.machine.mi.MicroInstructionDefinition; +import net.mograsim.machine.mi.parameters.IntegerClassification; +import net.mograsim.machine.mi.parameters.IntegerImmediate; +import net.mograsim.plugin.tables.NumberCellEditingSupport; +import net.mograsim.plugin.tables.memory.DisplaySettings; + +public class IntegerEditingSupport extends NumberCellEditingSupport +{ + private IntegerClassification classification; + private int index; + + public IntegerEditingSupport(TableViewer viewer, MicroInstructionDefinition miDef, int index, DisplaySettings displaySettings) + { + super(viewer, displaySettings); + classification = (IntegerClassification) miDef.getParameterClassifications()[index]; + this.index = index; + } + + @Override + protected void setAsBigInteger(Object element, BigInteger value) + { + ((MicroInstruction) element).setParameter(index, new IntegerImmediate(value, classification.getExpectedBits())); + } + + @Override + protected BigInteger getAsBigInteger(Object element) + { + return ((IntegerImmediate) ((MicroInstruction) element).getParameter(index)).getValueAsBigInteger(); + } + +} diff --git a/net.mograsim.plugin.core/src/net/mograsim/plugin/tables/mi/MnemonicCellEditorValidator.java b/net.mograsim.plugin.core/src/net/mograsim/plugin/tables/mi/MnemonicCellEditorValidator.java new file mode 100644 index 00000000..98181c46 --- /dev/null +++ b/net.mograsim.plugin.core/src/net/mograsim/plugin/tables/mi/MnemonicCellEditorValidator.java @@ -0,0 +1,24 @@ +package net.mograsim.plugin.tables.mi; + +import org.eclipse.jface.viewers.ICellEditorValidator; + +import net.mograsim.machine.mi.parameters.MnemonicFamily; + +public class MnemonicCellEditorValidator implements ICellEditorValidator +{ + private MnemonicFamily family; + + public MnemonicCellEditorValidator(MnemonicFamily family) + { + this.family = family; + } + + @Override + public String isValid(Object value) + { + int index = (Integer) value; + return index >= 0 && index < family.size() ? null + : String.format("MnemonicFamily has %s elements, index %s is out of bounds", family.size(), value.toString()); + } + +} diff --git a/net.mograsim.plugin.core/src/net/mograsim/plugin/tables/mi/MnemonicEditingSupport.java b/net.mograsim.plugin.core/src/net/mograsim/plugin/tables/mi/MnemonicEditingSupport.java new file mode 100644 index 00000000..9530c209 --- /dev/null +++ b/net.mograsim.plugin.core/src/net/mograsim/plugin/tables/mi/MnemonicEditingSupport.java @@ -0,0 +1,56 @@ +package net.mograsim.plugin.tables.mi; + +import org.eclipse.jface.viewers.CellEditor; +import org.eclipse.jface.viewers.ComboBoxCellEditor; +import org.eclipse.jface.viewers.EditingSupport; +import org.eclipse.jface.viewers.TableViewer; +import org.eclipse.swt.SWT; + +import net.mograsim.machine.mi.MicroInstruction; +import net.mograsim.machine.mi.MicroInstructionDefinition; +import net.mograsim.machine.mi.parameters.Mnemonic; +import net.mograsim.machine.mi.parameters.MnemonicFamily; + +public class MnemonicEditingSupport extends EditingSupport +{ + private final ComboBoxCellEditor editor; + private final MnemonicFamily family; + private final TableViewer viewer; + private final int index; + + public MnemonicEditingSupport(TableViewer viewer, MicroInstructionDefinition definition, int index) + { + super(viewer); + this.viewer = viewer; + family = (MnemonicFamily) definition.getParameterClassifications()[index]; + editor = new ComboBoxCellEditor(viewer.getTable(), family.getStringValues(), SWT.READ_ONLY); + this.index = index; + editor.setValidator(new MnemonicCellEditorValidator(family)); + } + + @Override + protected boolean canEdit(Object element) + { + return true; + } + + @Override + protected CellEditor getCellEditor(Object element) + { + return editor; + } + + @Override + protected Object getValue(Object element) + { + return ((Mnemonic) ((MicroInstruction) element).getParameter(index)).ordinal(); + } + + @Override + protected void setValue(Object element, Object value) + { + ((MicroInstruction) element).setParameter(index, family.get((Integer) value)); + viewer.update(element, null); + } + +} diff --git a/net.mograsim.plugin.core/src/net/mograsim/plugin/tables/mi/ParameterLabelProvider.java b/net.mograsim.plugin.core/src/net/mograsim/plugin/tables/mi/ParameterLabelProvider.java new file mode 100644 index 00000000..b4acd155 --- /dev/null +++ b/net.mograsim.plugin.core/src/net/mograsim/plugin/tables/mi/ParameterLabelProvider.java @@ -0,0 +1,22 @@ +package net.mograsim.plugin.tables.mi; + +import org.eclipse.jface.viewers.ColumnLabelProvider; + +import net.mograsim.machine.mi.MicroInstruction; + +public class ParameterLabelProvider extends ColumnLabelProvider +{ + private final int index; + + public ParameterLabelProvider(int index) + { + super(); + this.index = index; + } + + @Override + public String getText(Object element) + { + return ((MicroInstruction) element).getParameter(index).toString(); + } +} diff --git a/net.mograsim.plugin.core/src/net/mograsim/plugin/util/DropDownMenu.java b/net.mograsim.plugin.core/src/net/mograsim/plugin/util/DropDownMenu.java new file mode 100644 index 00000000..ffa18575 --- /dev/null +++ b/net.mograsim.plugin.core/src/net/mograsim/plugin/util/DropDownMenu.java @@ -0,0 +1,86 @@ +package net.mograsim.plugin.util; + +import org.eclipse.swt.SWT; +import org.eclipse.swt.events.SelectionEvent; +import org.eclipse.swt.events.SelectionListener; +import org.eclipse.swt.graphics.Point; +import org.eclipse.swt.graphics.Rectangle; +import org.eclipse.swt.widgets.Button; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Event; +import org.eclipse.swt.widgets.Listener; +import org.eclipse.swt.widgets.Menu; +import org.eclipse.swt.widgets.MenuItem; + +public class DropDownMenu +{ + private Button button; + + public DropDownMenu(Composite parent, String label, DropDownEntry... entries) + { + button = new Button(parent, SWT.PUSH); + button.setText(label); + setupDrowpDownMenu(entries); + } + + private void setupDrowpDownMenu(DropDownEntry[] entries) + { + Menu menu = new Menu(button); + for (DropDownEntry entry : entries) + { + MenuItem item = new MenuItem(menu, SWT.PUSH); + item.addSelectionListener(new SelectionListener() + { + @Override + public void widgetSelected(SelectionEvent e) + { + entry.listener.widgetSelected(e); + } + + @Override + public void widgetDefaultSelected(SelectionEvent e) + { + widgetSelected(e); + } + }); + item.setText(entry.title); + } + + button.addListener(SWT.Selection, new Listener() + { + @Override + public void handleEvent(Event event) + { + Rectangle rect = button.getBounds(); + Point pt = new Point(rect.x, rect.y + rect.height); + pt = button.getParent().toDisplay(pt); + menu.setLocation(pt.x, pt.y); + menu.setVisible(true); + } + }); + } + + public Button getButton() + { + return button; + } + + public static class DropDownEntry + { + public final String title; + public final EntrySelectedListener listener; + + public DropDownEntry(String title, EntrySelectedListener listener) + { + super(); + this.title = title; + this.listener = listener; + } + } + + @FunctionalInterface + public static interface EntrySelectedListener + { + public void widgetSelected(SelectionEvent e); + } +} -- 2.17.1