From 24a3e58e26a7d6516ec9fe6583f9e2c4f11590bd Mon Sep 17 00:00:00 2001 From: MaisiKoleni Date: Sat, 5 Jan 2019 02:11:46 +0100 Subject: [PATCH] Rudimentary JavaFX GUI and small changes --- .classpath | 7 +- .settings/org.eclipse.jdt.core.prefs | 2 +- pom.xml | 49 +- .../net/maisikoleni/am2900me/ui/Main.java | 64 ++- .../am2900me/ui/MappingPromPanel.java | 80 ++- .../am2900me/ui/MicroInstrPanel.java | 501 ++++++++++++++++++ .../net/maisikoleni/am2900me/ui/RAMPanel.java | 65 ++- .../am2900me/ui/am2900me_style.css | 4 - .../am2900me/util/AdvBindings.java | 81 +++ .../am2900me/util/EnumStringConverter.java | 37 ++ .../am2900me/util/HexIntStringConverter.java | 24 +- .../maisikoleni/am2900me/util/NBitsUInt.java | 4 +- .../util/UniversalHexIntStringConverter.java | 34 ++ .../main/resources/icons/\302\265Icon128.png" | Bin 0 -> 9251 bytes "src/main/resources/icons/\302\265Icon16.png" | Bin 0 -> 645 bytes "src/main/resources/icons/\302\265Icon32.png" | Bin 0 -> 1352 bytes src/main/resources/style/am2900me_style.css | 20 + .../am2900me/logic/Am2900MachineTest.java | 2 +- .../am2900me/logic/Am2901Test.java | 2 +- 19 files changed, 942 insertions(+), 34 deletions(-) create mode 100644 src/main/java/net/maisikoleni/am2900me/ui/MicroInstrPanel.java delete mode 100644 src/main/java/net/maisikoleni/am2900me/ui/am2900me_style.css create mode 100644 src/main/java/net/maisikoleni/am2900me/util/AdvBindings.java create mode 100644 src/main/java/net/maisikoleni/am2900me/util/EnumStringConverter.java create mode 100644 src/main/java/net/maisikoleni/am2900me/util/UniversalHexIntStringConverter.java create mode 100644 "src/main/resources/icons/\302\265Icon128.png" create mode 100644 "src/main/resources/icons/\302\265Icon16.png" create mode 100644 "src/main/resources/icons/\302\265Icon32.png" create mode 100644 src/main/resources/style/am2900me_style.css diff --git a/.classpath b/.classpath index d854c6a..c047a52 100644 --- a/.classpath +++ b/.classpath @@ -6,26 +6,27 @@ - + + - - + + diff --git a/.settings/org.eclipse.jdt.core.prefs b/.settings/org.eclipse.jdt.core.prefs index 03356fe..e05a88b 100644 --- a/.settings/org.eclipse.jdt.core.prefs +++ b/.settings/org.eclipse.jdt.core.prefs @@ -52,7 +52,7 @@ org.eclipse.jdt.core.compiler.problem.missingDefaultCase=warning org.eclipse.jdt.core.compiler.problem.missingDeprecatedAnnotation=info org.eclipse.jdt.core.compiler.problem.missingEnumCaseDespiteDefault=disabled org.eclipse.jdt.core.compiler.problem.missingHashCodeMethod=warning -org.eclipse.jdt.core.compiler.problem.missingJavadocComments=info +org.eclipse.jdt.core.compiler.problem.missingJavadocComments=ignore org.eclipse.jdt.core.compiler.problem.missingJavadocCommentsOverriding=disabled org.eclipse.jdt.core.compiler.problem.missingJavadocCommentsVisibility=public org.eclipse.jdt.core.compiler.problem.missingJavadocTagDescription=return_tag diff --git a/pom.xml b/pom.xml index e5e8bbf..532420e 100644 --- a/pom.xml +++ b/pom.xml @@ -4,7 +4,7 @@ 4.0.0 net.maisikoleni.am2900me Am2900ME - 0.0.1-SNAPSHOT + 0.0.1 Am2900ME Emulator for Am2900 Family Microprogramming https://github.com/MaisiKoleni/Am2900ME @@ -22,6 +22,52 @@ 10 + + org.apache.maven.plugins + maven-dependency-plugin + + + copy-dependencies + prepare-package + + copy-dependencies + + + ${project.build.directory}/lib + false + false + true + + + + + + org.apache.maven.plugins + maven-jar-plugin + + + + true + lib/ + net.maisikoleni.am2900me.ui.Main + + + + + + org.apache.maven.plugins + maven-source-plugin + 3.0.1 + + + attach-sources + verify + + jar-no-fork + + + + @@ -33,4 +79,5 @@ test + \ No newline at end of file diff --git a/src/main/java/net/maisikoleni/am2900me/ui/Main.java b/src/main/java/net/maisikoleni/am2900me/ui/Main.java index 38e55fb..67e9fb8 100644 --- a/src/main/java/net/maisikoleni/am2900me/ui/Main.java +++ b/src/main/java/net/maisikoleni/am2900me/ui/Main.java @@ -1,10 +1,13 @@ package net.maisikoleni.am2900me.ui; +import java.util.ArrayList; +import java.util.List; + import javafx.application.Application; import javafx.scene.Scene; +import javafx.scene.image.Image; import javafx.stage.Stage; import net.maisikoleni.am2900me.logic.Am2900Machine; -import net.maisikoleni.am2900me.logic.MicroprogramMemory; /** * JavaFX application entry point. @@ -14,27 +17,64 @@ */ public class Main extends Application { + public static final String DESCRIPTOR = "AM2900ME (v0.0.1)"; + private final Am2900Machine machine; + private final List stylesheets = List.of( + getClass().getResource("/style/am2900me_style.css").toExternalForm(), + "com/sun/javafx/scene/control/skin/modena/modena-embedded-performance.css"); + private final List icons = getImages("/icons/µIcon16.png", "/icons/µIcon32.png", "/icons/µIcon128.png"); public Main() { machine = new Am2900Machine(); } @Override - public void start(Stage primaryStage) { - // TODO: EVERYTHING EXPERIMENTAL!! - primaryStage.setTitle("AM2900ME"); -// Scene scene = new Scene(new MappingPromPanel(machine.getmProm())); - Scene scene = new Scene(new MicroInstrPanel(new MicroprogramMemory())); - scene.getStylesheets().add(getClass().getResource("am2900me_style.css").toExternalForm()); - primaryStage.setScene(scene); - primaryStage.setHeight(600); - primaryStage.setWidth(1050); - primaryStage.show(); + public void start(Stage s) { + s.setTitle(DESCRIPTOR + " - Microinstructions"); + s.getIcons().addAll(icons); + Scene scene = new Scene(new MicroInstrPanel(machine)); + scene.getStylesheets().addAll(stylesheets); + s.setScene(scene); + s.setHeight(800); + s.setWidth(1870); + s.show(); + startMPROM(); + startRAM(); + } + + private void startMPROM() { + Stage s = new Stage(); + s.getIcons().addAll(icons); + s.setTitle(DESCRIPTOR + " - Mapping PROM"); + Scene scene = new Scene(new MappingPromPanel(machine.getmProm())); + scene.getStylesheets().addAll(stylesheets); + s.setScene(scene); + s.setHeight(600); + s.setWidth(450); + s.show(); + } + + private void startRAM() { + Stage s = new Stage(); + s.getIcons().addAll(icons); + s.setTitle(DESCRIPTOR + " - Machine RAM"); + Scene scene = new Scene(new RAMPanel(machine.getMachineRam())); + scene.getStylesheets().addAll(stylesheets); + s.setScene(scene); + s.setHeight(600); + s.setWidth(1050); + s.show(); } - @SuppressWarnings("javadoc") public static void main(String[] args) { launch(args); } + + public List getImages(final String... fileNames) { + final ArrayList images = new ArrayList<>(); + for (int i = 0; i < fileNames.length; i++) + images.add(new Image(getClass().getResource(fileNames[i]).toString())); + return images; + } } diff --git a/src/main/java/net/maisikoleni/am2900me/ui/MappingPromPanel.java b/src/main/java/net/maisikoleni/am2900me/ui/MappingPromPanel.java index b28da35..1d9a619 100644 --- a/src/main/java/net/maisikoleni/am2900me/ui/MappingPromPanel.java +++ b/src/main/java/net/maisikoleni/am2900me/ui/MappingPromPanel.java @@ -1,17 +1,29 @@ package net.maisikoleni.am2900me.ui; +import java.io.File; +import java.nio.file.Files; +import java.nio.file.StandardOpenOption; +import java.util.ArrayList; + import javafx.beans.property.IntegerProperty; import javafx.beans.property.ReadOnlyIntegerProperty; +import javafx.beans.property.ReadOnlyIntegerWrapper; import javafx.beans.property.SimpleIntegerProperty; import javafx.beans.property.SimpleStringProperty; import javafx.beans.property.StringProperty; import javafx.collections.FXCollections; import javafx.collections.ObservableList; +import javafx.scene.control.Alert; +import javafx.scene.control.Alert.AlertType; +import javafx.scene.control.Button; +import javafx.scene.control.ButtonType; import javafx.scene.control.TableColumn; import javafx.scene.control.TableView; +import javafx.scene.control.ToolBar; import javafx.scene.control.cell.PropertyValueFactory; import javafx.scene.control.cell.TextFieldTableCell; import javafx.scene.layout.BorderPane; +import javafx.stage.FileChooser; import net.maisikoleni.am2900me.logic.MappingPROM; import net.maisikoleni.am2900me.util.HexIntStringConverter; @@ -42,6 +54,34 @@ public MappingPromPanel(MappingPROM mprom) { addrTable = new TableView<>(entries); configureTableView(); setCenter(addrTable); + configureToolbar(); + } + + private void configureToolbar() { + Button loadFile = new Button("Load from File"); + loadFile.setOnAction(e -> { + FileChooser fc = new FileChooser(); + File f = fc.showOpenDialog(null); + try { + readCSV(Files.readAllLines(f.toPath())); + } catch (Exception ex) { + Alert a = new Alert(AlertType.ERROR, "Load from File failed:\n" + ex, ButtonType.CLOSE); + a.show(); + } + }); + Button saveFile = new Button("Save to File"); + saveFile.setOnAction(e -> { + FileChooser fc = new FileChooser(); + File f = fc.showSaveDialog(null); + try { + Files.write(f.toPath(), toCSV(), StandardOpenOption.CREATE, StandardOpenOption.TRUNCATE_EXISTING); + } catch (Exception ex) { + Alert a = new Alert(AlertType.ERROR, "Load from File failed:\n" + ex, ButtonType.CLOSE); + a.show(); + } + }); + ToolBar tb = new ToolBar(loadFile, saveFile); + setTop(tb); } private void configureTableView() { @@ -63,29 +103,57 @@ private void configureTableView() { comments.setEditable(true); comments.setReorderable(false); -// addrTable.getSortOrder().add(opCodes); addrTable.getColumns().add(opCodes); addrTable.getColumns().add(mapAddresses); addrTable.getColumns().add(comments); addrTable.setEditable(true); } - @SuppressWarnings("javadoc") + private final Iterable toCSV() { + ArrayList lines = new ArrayList<>(); + for (MappingEntry me : entries) { + lines.add(me.toString()); + } + return lines; + } + + private final void readCSV(Iterable lines) { + for (String line : lines) { + MappingEntry newME = parseME(line); + entries.set(newME.opCode.get(), newME); + } + } + + public MappingEntry parseME(String s) { + String[] parts = s.split(",", 3); + MappingEntry me = new MappingEntry(Integer.decode(parts[0])); + me.mappingAddr.set(Integer.decode(parts[1])); + me.comment.set(parts[2]); + return me; + } + public class MappingEntry implements Comparable { static final String PROP_OP_CODE = "opCode"; static final String PROP_ADDRESS = "mappingAddr"; static final String PROP_COMMENT = "comment"; - private final IntegerProperty opCode; - private final IntegerProperty mappingAddr; - private final StringProperty comment; + final ReadOnlyIntegerProperty opCode; + final IntegerProperty mappingAddr; + final StringProperty comment; @SuppressWarnings("synthetic-access") MappingEntry(int opCode) { - this.opCode = new SimpleIntegerProperty(this, PROP_OP_CODE, opCode); + this.opCode = new ReadOnlyIntegerWrapper(this, PROP_OP_CODE, opCode); this.mappingAddr = new SimpleIntegerProperty(this, PROP_ADDRESS, opCode << 4); this.mappingAddr.addListener((obs, o, n) -> MappingPromPanel.this.mprom.set(opCode, n.intValue())); this.comment = new SimpleStringProperty(this, PROP_COMMENT, ""); + MappingPromPanel.this.mprom.set(opCode, mappingAddr.get()); + } + + @Override + public String toString() { + return HexIntStringConverter.INT_8.toString(opCode.get()) + "," + + HexIntStringConverter.INT_12.toString(mappingAddr.get()) + "," + comment.get(); } public final ReadOnlyIntegerProperty opCodeProperty() { diff --git a/src/main/java/net/maisikoleni/am2900me/ui/MicroInstrPanel.java b/src/main/java/net/maisikoleni/am2900me/ui/MicroInstrPanel.java new file mode 100644 index 0000000..a35bc79 --- /dev/null +++ b/src/main/java/net/maisikoleni/am2900me/ui/MicroInstrPanel.java @@ -0,0 +1,501 @@ +package net.maisikoleni.am2900me.ui; + +import java.io.File; +import java.nio.file.Files; +import java.nio.file.StandardOpenOption; +import java.util.ArrayList; + +import javafx.beans.binding.Bindings; +import javafx.beans.binding.BooleanBinding; +import javafx.beans.property.IntegerProperty; +import javafx.beans.property.ObjectProperty; +import javafx.beans.property.ReadOnlyIntegerProperty; +import javafx.beans.property.ReadOnlyIntegerWrapper; +import javafx.beans.property.SimpleIntegerProperty; +import javafx.beans.property.SimpleObjectProperty; +import javafx.collections.FXCollections; +import javafx.collections.ObservableList; +import javafx.scene.control.Alert; +import javafx.scene.control.Alert.AlertType; +import javafx.scene.control.Button; +import javafx.scene.control.ButtonType; +import javafx.scene.control.TableCell; +import javafx.scene.control.TableColumn; +import javafx.scene.control.TableRow; +import javafx.scene.control.TableView; +import javafx.scene.control.ToolBar; +import javafx.scene.control.cell.ChoiceBoxTableCell; +import javafx.scene.control.cell.PropertyValueFactory; +import javafx.scene.control.cell.TextFieldTableCell; +import javafx.scene.layout.BorderPane; +import javafx.stage.FileChooser; +import net.maisikoleni.am2900me.logic.Am2900Machine; +import net.maisikoleni.am2900me.logic.MicroprogramMemory; +import net.maisikoleni.am2900me.logic.microinstr.ASEL; +import net.maisikoleni.am2900me.logic.microinstr.Am2901_Dest; +import net.maisikoleni.am2900me.logic.microinstr.Am2901_Func; +import net.maisikoleni.am2900me.logic.microinstr.Am2901_Src; +import net.maisikoleni.am2900me.logic.microinstr.Am2904_Carry; +import net.maisikoleni.am2900me.logic.microinstr.Am2904_Inst; +import net.maisikoleni.am2900me.logic.microinstr.Am2904_Shift; +import net.maisikoleni.am2900me.logic.microinstr.Am2910_Inst; +import net.maisikoleni.am2900me.logic.microinstr.BAR; +import net.maisikoleni.am2900me.logic.microinstr.BSEL; +import net.maisikoleni.am2900me.logic.microinstr.IE; +import net.maisikoleni.am2900me.logic.microinstr.Interrupt; +import net.maisikoleni.am2900me.logic.microinstr.KMUX; +import net.maisikoleni.am2900me.logic.microinstr.Konst; +import net.maisikoleni.am2900me.logic.microinstr.MicroInstruction; +import net.maisikoleni.am2900me.logic.microinstr.RA_ADDR; +import net.maisikoleni.am2900me.logic.microinstr.RB_ADDR; +import net.maisikoleni.am2900me.logic.microinstr._ABUS; +import net.maisikoleni.am2900me.logic.microinstr._BZ_EA; +import net.maisikoleni.am2900me.logic.microinstr._BZ_ED; +import net.maisikoleni.am2900me.logic.microinstr._BZ_INC; +import net.maisikoleni.am2900me.logic.microinstr._BZ_LD; +import net.maisikoleni.am2900me.logic.microinstr._CCEN; +import net.maisikoleni.am2900me.logic.microinstr._CE_M; +import net.maisikoleni.am2900me.logic.microinstr._CE_µ; +import net.maisikoleni.am2900me.logic.microinstr._DBUS; +import net.maisikoleni.am2900me.logic.microinstr._IR_LD; +import net.maisikoleni.am2900me.logic.microinstr._MWE; +import net.maisikoleni.am2900me.logic.microinstr.µIField; +import net.maisikoleni.am2900me.util.AdvBindings; +import net.maisikoleni.am2900me.util.HexIntStringConverter; +import net.maisikoleni.am2900me.util.NBitsUInt; +import net.maisikoleni.am2900me.util.UniversalHexIntStringConverter; + +/** + * Panel for viewing and programming the {@link MicroprogramMemory}. + * + * @author MaisiKoleni + */ +public class MicroInstrPanel extends BorderPane { + + private final TableView miTable; + private final ObservableList mis; + private final Am2900Machine m; + private final MicroprogramMemory mpm; + private final IntegerProperty currentMI; + + /** + * Creates a new microprogram memory for programming the microinstructions in + * the machine using the given {@link MicroprogramMemory}. + * + * @author MaisiKoleni + */ + public MicroInstrPanel(Am2900Machine m) { + this.m = m; + this.mpm = m.getMpm(); + this.currentMI = new SimpleIntegerProperty(-1); + this.miTable = new TableView<>(); + configureTableView(); + mis = FXCollections.observableArrayList(); + for (int i = 0; i < mpm.size(); i++) { + MicroInstruction mi = MicroInstruction.DEFAULT; + mpm.setInstruction(i, mi); + mis.add(new MicroInstrItem(mi, i)); + } + miTable.setItems(mis); + setCenter(miTable); + configureToolbar(); + } + + @SuppressWarnings({ "unchecked", "rawtypes" }) + private void configureTableView() { + miTable.setRowFactory(tv -> { + TableRow row = new TableRow<>(); + BooleanBinding isDefault = AdvBindings.map(row.itemProperty(), mii -> mii == null ? null : mii.mi) + .isEqualTo(MicroInstruction.DEFAULT); + BooleanBinding executed = row.indexProperty().isEqualTo(currentMI); + row.styleProperty().bind(Bindings.when(executed).then("-fx-background:lightgreen;") + .otherwise(Bindings.when(isDefault).then("-fx-background:lightgrey;").otherwise(""))); + return row; + }); + TableColumn addrCol = new TableColumn<>("Address"); + addrCol.setCellValueFactory(new PropertyValueFactory<>("address")); + addrCol.setCellFactory(TextFieldTableCell.forTableColumn(HexIntStringConverter.INT_12)); + addrCol.setReorderable(false); + addrCol.setEditable(false); + addrCol.setSortable(false); + miTable.getColumns().add(addrCol); + for (int i = 0; i < MicroInstruction.FIELD_NAMES.size(); i++) { + µIField f = MicroInstruction.FIELD_DEFAULTS.get(i); + TableColumn col; + if (f instanceof Enum) + col = generateColumnFor((Enum) f); // TODO: more elegant enum handling? + else + col = generateColumnFor((NBitsUInt) f); + col.setCellValueFactory(new PropertyValueFactory<>(MicroInstruction.FIELD_NAMES.get(i))); + col.setReorderable(false); + col.setEditable(true); + col.setSortable(false); + miTable.getColumns().add(col); + } + miTable.setEditable(true); + } + + private void configureToolbar() { + Button execNext = new Button(); + execNext.textProperty() + .bind(Bindings.when(currentMI.isEqualTo(-1)).then("Startup Machine").otherwise("Execute Next")); + execNext.setOnAction(e -> executeNext()); + Button loadFile = new Button("Load from File"); + loadFile.setOnAction(e -> { + FileChooser fc = new FileChooser(); + File f = fc.showOpenDialog(null); + try { + readCSV(Files.readAllLines(f.toPath())); + } catch (Exception ex) { + Alert a = new Alert(AlertType.ERROR, "Load from File failed:\n" + ex, ButtonType.CLOSE); + a.show(); + } + }); + Button saveFile = new Button("Save to File"); + saveFile.setOnAction(e -> { + FileChooser fc = new FileChooser(); + File f = fc.showSaveDialog(null); + try { + Files.write(f.toPath(), toCSV(), StandardOpenOption.CREATE, StandardOpenOption.TRUNCATE_EXISTING); + } catch (Exception ex) { + Alert a = new Alert(AlertType.ERROR, "Load from File failed:\n" + ex, ButtonType.CLOSE); + a.show(); + } + }); + ToolBar tb = new ToolBar(execNext, loadFile, saveFile); + setTop(tb); + } + + private void executeNext() { + try { + m.executeNext(); + } catch (Exception ex) { + Alert a = new Alert(AlertType.ERROR, "An error occured during execution:\n" + ex, ButtonType.CLOSE); + a.show(); + } + currentMI.set(m.getCurrentMicroInstruction()); + } + + @SuppressWarnings("unchecked") + static TableColumn generateColumnFor(T defaultVal) { + TableColumn column = new TableColumn<>(defaultVal.getClass().getSimpleName()); + column.setCellFactory(list -> { + TableCell cell = new TextFieldTableCell<>( + new UniversalHexIntStringConverter(t -> t.value, i -> (T) defaultVal.valueOf(i), + HexIntStringConverter.forNibbles(defaultVal.bits / 4))); + cell.itemProperty().addListener((obs, o, n) -> { + if (n == null || n.equals(defaultVal)) + cell.getStyleClass().remove("changed-mi"); + else + cell.getStyleClass().add("changed-mi"); + }); + return cell; + }); + return column; + } + + static > TableColumn generateColumnFor(T defaultVal) { + TableColumn column = new TableColumn<>(defaultVal.getClass().getSimpleName()); + T[] values = defaultVal.getDeclaringClass().getEnumConstants(); + column.setCellFactory(list -> { + TableCell cell = new ChoiceBoxTableCell<>(values); + cell.itemProperty().addListener((obs, o, n) -> { + if (n == null || n.equals(defaultVal)) + cell.getStyleClass().remove("changed-mi"); + else + cell.getStyleClass().add("changed-mi"); + }); + return cell; + }); + return column; + } + + private final Iterable toCSV() { + ArrayList lines = new ArrayList<>(); + for (MicroInstrItem mii : mis) { + lines.add(mii.toString()); + } + return lines; + } + + private final void readCSV(Iterable lines) { + for (String line : lines) { + MicroInstrItem newMII = parseMII(line); + mis.set(newMII.address.get(), newMII); + } + } + + public MicroInstrItem parseMII(String s) { + MicroInstruction newMI = MicroInstruction.DEFAULT; + String[] parts = s.split(","); + newMI = newMI.withMwe(_MWE.valueOf(parts[1])); + newMI = newMI.withIr_ld(_IR_LD.valueOf(parts[2])); + newMI = newMI.withBz_ea(_BZ_EA.valueOf(parts[2])); + newMI = newMI.withBz_inc(_BZ_INC.valueOf(parts[4])); + newMI = newMI.withBz_ed(_BZ_ED.valueOf(parts[5])); + newMI = newMI.withBz_ld(_BZ_LD.valueOf(parts[6])); + newMI = newMI.withBar(new BAR(Integer.decode(parts[7]))); + newMI = newMI.withAm2910_Inst(Am2910_Inst.valueOf(parts[8])); + newMI = newMI.withCcen(_CCEN.valueOf(parts[9])); + newMI = newMI.withAm2904_Inst(Am2904_Inst.valueOf(parts[10])); + newMI = newMI.withCe_m(_CE_M.valueOf(parts[11])); + newMI = newMI.withCe_µ(_CE_µ.valueOf(parts[11])); + newMI = newMI.withAm2904_Shift(new Am2904_Shift(Integer.decode(parts[13]))); + newMI = newMI.withAm2904_Carry(Am2904_Carry.valueOf(parts[14])); + newMI = newMI.withDbus(_DBUS.valueOf(parts[15])); + newMI = newMI.withAbus(_ABUS.valueOf(parts[16])); + newMI = newMI.withBsel(BSEL.valueOf(parts[17])); + newMI = newMI.withRb_addr(new RB_ADDR(Integer.decode(parts[18]))); + newMI = newMI.withAsel(ASEL.valueOf(parts[19])); + newMI = newMI.withRa_addr(new RA_ADDR(Integer.decode(parts[20]))); + newMI = newMI.withAm2901_Dest(Am2901_Dest.valueOf(parts[21])); + newMI = newMI.withAm2901_Func(Am2901_Func.valueOf(parts[22])); + newMI = newMI.withAm2901_Src(Am2901_Src.valueOf(parts[23])); + newMI = newMI.withK(new Konst(Integer.decode(parts[24]))); + newMI = newMI.withKmux(KMUX.valueOf(parts[25])); + newMI = newMI.withInterrupt(new Interrupt(Integer.decode(parts[26]))); + newMI = newMI.withIe(IE.valueOf(parts[27])); + return new MicroInstrItem(newMI, Integer.decode(parts[0])); + } + + public class MicroInstrItem { + private final ObjectProperty<_ABUS> abus; + private final ObjectProperty am2901_Dest; + private final ObjectProperty am2901_Func; + private final ObjectProperty am2901_Src; + private final ObjectProperty am2904_Carry; + private final ObjectProperty am2904_Inst; + private final ObjectProperty am2904_Shift; + private final ObjectProperty am2910_Inst; + private final ObjectProperty asel; + private final ObjectProperty bar; + private final ObjectProperty bsel; + private final ObjectProperty<_BZ_EA> bz_ea; + private final ObjectProperty<_BZ_ED> bz_ed; + private final ObjectProperty<_BZ_INC> bz_inc; + private final ObjectProperty<_BZ_LD> bz_ld; + private final ObjectProperty<_CCEN> ccen; + private final ObjectProperty<_CE_M> ce_m; + private final ObjectProperty<_CE_µ> ce_µ; + private final ObjectProperty<_DBUS> dbus; + private final ObjectProperty ie; + private final ObjectProperty interrupt; + private final ObjectProperty<_IR_LD> ir_ld; + private final ObjectProperty k; + private final ObjectProperty kmux; + private final ObjectProperty<_MWE> mwe; + private final ObjectProperty ra_addr; + private final ObjectProperty rb_addr; + + final ObjectProperty mi; + final ReadOnlyIntegerProperty address; + + @SuppressWarnings("synthetic-access") + public MicroInstrItem(MicroInstruction miInput, int address) { + this.mi = new SimpleObjectProperty<>(miInput); + this.address = new ReadOnlyIntegerWrapper(address); + this.mwe = new SimpleObjectProperty<>(mi.get().mwe); + this.ir_ld = new SimpleObjectProperty<>(mi.get().ir_ld); + this.bz_ea = new SimpleObjectProperty<>(mi.get().bz_ea); + this.bz_inc = new SimpleObjectProperty<>(mi.get().bz_inc); + this.bz_ed = new SimpleObjectProperty<>(mi.get().bz_ed); + this.bz_ld = new SimpleObjectProperty<>(mi.get().bz_ld); + this.bar = new SimpleObjectProperty<>(mi.get().bar); + this.am2910_Inst = new SimpleObjectProperty<>(mi.get().am2910_Inst); + this.ccen = new SimpleObjectProperty<>(mi.get().ccen); + this.am2904_Inst = new SimpleObjectProperty<>(mi.get().am2904_Inst); + this.ce_m = new SimpleObjectProperty<>(mi.get().ce_m); + this.ce_µ = new SimpleObjectProperty<>(mi.get().ce_µ); + this.am2904_Shift = new SimpleObjectProperty<>(mi.get().am2904_Shift); + this.am2904_Carry = new SimpleObjectProperty<>(mi.get().am2904_Carry); + this.dbus = new SimpleObjectProperty<>(mi.get().dbus); + this.abus = new SimpleObjectProperty<>(mi.get().abus); + this.bsel = new SimpleObjectProperty<>(mi.get().bsel); + this.rb_addr = new SimpleObjectProperty<>(mi.get().rb_addr); + this.asel = new SimpleObjectProperty<>(mi.get().asel); + this.ra_addr = new SimpleObjectProperty<>(mi.get().ra_addr); + this.am2901_Dest = new SimpleObjectProperty<>(mi.get().am2901_Dest); + this.am2901_Func = new SimpleObjectProperty<>(mi.get().am2901_Func); + this.am2901_Src = new SimpleObjectProperty<>(mi.get().am2901_Src); + this.k = new SimpleObjectProperty<>(mi.get().k); + this.kmux = new SimpleObjectProperty<>(mi.get().kmux); + this.interrupt = new SimpleObjectProperty<>(mi.get().interrupt); + this.ie = new SimpleObjectProperty<>(mi.get().ie); + dbus.addListener((obs, o, n) -> mi.set(mi.get().withDbus(n))); + mwe.addListener((obs, o, n) -> mi.set(mi.get().withMwe(n))); + bz_ea.addListener((obs, o, n) -> mi.set(mi.get().withBz_ea(n))); + ir_ld.addListener((obs, o, n) -> mi.set(mi.get().withIr_ld(n))); + bz_inc.addListener((obs, o, n) -> mi.set(mi.get().withBz_inc(n))); + bz_ed.addListener((obs, o, n) -> mi.set(mi.get().withBz_ed(n))); + bz_ld.addListener((obs, o, n) -> mi.set(mi.get().withBz_ld(n))); + bar.addListener((obs, o, n) -> mi.set(mi.get().withBar(n))); + am2910_Inst.addListener((obs, o, n) -> mi.set(mi.get().withAm2910_Inst(n))); + ccen.addListener((obs, o, n) -> mi.set(mi.get().withCcen(n))); + am2904_Inst.addListener((obs, o, n) -> mi.set(mi.get().withAm2904_Inst(n))); + ce_m.addListener((obs, o, n) -> mi.set(mi.get().withCe_m(n))); + ce_µ.addListener((obs, o, n) -> mi.set(mi.get().withCe_µ(n))); + am2904_Shift.addListener((obs, o, n) -> mi.set(mi.get().withAm2904_Shift(n))); + am2904_Carry.addListener((obs, o, n) -> mi.set(mi.get().withAm2904_Carry(n))); + abus.addListener((obs, o, n) -> mi.set(mi.get().withAbus(n))); + bsel.addListener((obs, o, n) -> mi.set(mi.get().withBsel(n))); + rb_addr.addListener((obs, o, n) -> mi.set(mi.get().withRb_addr(n))); + asel.addListener((obs, o, n) -> mi.set(mi.get().withAsel(n))); + ra_addr.addListener((obs, o, n) -> mi.set(mi.get().withRa_addr(n))); + am2901_Dest.addListener((obs, o, n) -> mi.set(mi.get().withAm2901_Dest(n))); + am2901_Func.addListener((obs, o, n) -> mi.set(mi.get().withAm2901_Func(n))); + am2901_Src.addListener((obs, o, n) -> mi.set(mi.get().withAm2901_Src(n))); + k.addListener((obs, o, n) -> mi.set(mi.get().withK(n))); + kmux.addListener((obs, o, n) -> mi.set(mi.get().withKmux(n))); + interrupt.addListener((obs, o, n) -> mi.set(mi.get().withInterrupt(n))); + ie.addListener((obs, o, n) -> mi.set(mi.get().withIe(n))); + mi.addListener((obs, o, n) -> mpm.setInstruction(address, n)); + mpm.setInstruction(address, mi.get()); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append(HexIntStringConverter.INT_12.toString(address.get()) + ","); + sb.append(mwe.get() + ","); + sb.append(ir_ld.get() + ","); + sb.append(bz_ea.get() + ","); + sb.append(bz_inc.get() + ","); + sb.append(bz_ed.get() + ","); + sb.append(bz_ld.get() + ","); + sb.append(bar.get() + ","); + sb.append(am2910_Inst.get() + ","); + sb.append(ccen.get() + ","); + sb.append(am2904_Inst.get() + ","); + sb.append(ce_m.get() + ","); + sb.append(ce_µ.get() + ","); + sb.append(am2904_Shift.get() + ","); + sb.append(am2904_Carry.get() + ","); + sb.append(dbus.get() + ","); + sb.append(abus.get() + ","); + sb.append(bsel.get() + ","); + sb.append(rb_addr.get() + ","); + sb.append(asel.get() + ","); + sb.append(ra_addr.get() + ","); + sb.append(am2901_Dest.get() + ","); + sb.append(am2901_Func.get() + ","); + sb.append(am2901_Src.get() + ","); + sb.append(k.get() + ","); + sb.append(kmux.get() + ","); + sb.append(interrupt.get() + ","); + sb.append(ie.get()); + return sb.toString(); + } + + public final ReadOnlyIntegerProperty addressProperty() { + return address; + } + + public final ObjectProperty<_ABUS> abusProperty() { + return abus; + } + + public final ObjectProperty am2901_DestProperty() { + return am2901_Dest; + } + + public final ObjectProperty am2901_FuncProperty() { + return am2901_Func; + } + + public final ObjectProperty am2901_SrcProperty() { + return am2901_Src; + } + + public final ObjectProperty am2904_CarryProperty() { + return am2904_Carry; + } + + public final ObjectProperty am2904_InstProperty() { + return am2904_Inst; + } + + public final ObjectProperty am2904_ShiftProperty() { + return am2904_Shift; + } + + public final ObjectProperty am2910_InstProperty() { + return am2910_Inst; + } + + public final ObjectProperty aselProperty() { + return asel; + } + + public final ObjectProperty barProperty() { + return bar; + } + + public final ObjectProperty bselProperty() { + return bsel; + } + + public final ObjectProperty<_BZ_EA> bz_eaProperty() { + return bz_ea; + } + + public final ObjectProperty<_BZ_ED> bz_edProperty() { + return bz_ed; + } + + public final ObjectProperty<_BZ_INC> bz_incProperty() { + return bz_inc; + } + + public final ObjectProperty<_BZ_LD> bz_ldProperty() { + return bz_ld; + } + + public final ObjectProperty<_CCEN> ccenProperty() { + return ccen; + } + + public final ObjectProperty<_CE_M> ce_mProperty() { + return ce_m; + } + + public final ObjectProperty<_CE_µ> ce_µProperty() { + return ce_µ; + } + + public final ObjectProperty<_DBUS> dbusProperty() { + return dbus; + } + + public final ObjectProperty ieProperty() { + return ie; + } + + public final ObjectProperty interruptProperty() { + return interrupt; + } + + public final ObjectProperty<_IR_LD> ir_ldProperty() { + return ir_ld; + } + + public final ObjectProperty kmuxProperty() { + return kmux; + } + + public final ObjectProperty kProperty() { + return k; + } + + public final ObjectProperty<_MWE> mweProperty() { + return mwe; + } + + public final ObjectProperty ra_addrProperty() { + return ra_addr; + } + + public final ObjectProperty rb_addrProperty() { + return rb_addr; + } + } +} diff --git a/src/main/java/net/maisikoleni/am2900me/ui/RAMPanel.java b/src/main/java/net/maisikoleni/am2900me/ui/RAMPanel.java index 978037a..123e6f2 100644 --- a/src/main/java/net/maisikoleni/am2900me/ui/RAMPanel.java +++ b/src/main/java/net/maisikoleni/am2900me/ui/RAMPanel.java @@ -1,5 +1,9 @@ package net.maisikoleni.am2900me.ui; +import java.io.File; +import java.nio.file.Files; +import java.nio.file.StandardOpenOption; +import java.util.ArrayList; import java.util.stream.Collectors; import java.util.stream.IntStream; @@ -8,7 +12,10 @@ import javafx.beans.property.SimpleIntegerProperty; import javafx.collections.FXCollections; import javafx.collections.ObservableList; +import javafx.scene.control.Alert; +import javafx.scene.control.Alert.AlertType; import javafx.scene.control.Button; +import javafx.scene.control.ButtonType; import javafx.scene.control.ComboBox; import javafx.scene.control.Label; import javafx.scene.control.TableColumn; @@ -19,6 +26,7 @@ import javafx.scene.layout.BorderPane; import javafx.scene.layout.StackPane; import javafx.scene.layout.VBox; +import javafx.stage.FileChooser; import net.maisikoleni.am2900me.logic.MachineRAM; import net.maisikoleni.am2900me.logic.MappingPROM; import net.maisikoleni.am2900me.util.HexIntStringConverter; @@ -67,7 +75,30 @@ private void configureToolBar() { page = IntegerProperty.integerProperty(pageChooser.valueProperty()); Button update = new Button("Update page values"); update.setOnAction(e -> updatePage(false)); - actions = new ToolBar(pageLabel, pageChooser, update); + Button loadFile = new Button("Load from File"); + loadFile.setOnAction(e -> { + FileChooser fc = new FileChooser(); + File f = fc.showOpenDialog(null); + try { + readCSV(Files.readAllLines(f.toPath())); + updatePage(false); + } catch (Exception ex) { + Alert a = new Alert(AlertType.ERROR, "Load from File failed:\n" + ex, ButtonType.CLOSE); + a.show(); + } + }); + Button saveFile = new Button("Save to File"); + saveFile.setOnAction(e -> { + FileChooser fc = new FileChooser(); + File f = fc.showSaveDialog(null); + try { + Files.write(f.toPath(), toCSV(), StandardOpenOption.CREATE, StandardOpenOption.TRUNCATE_EXISTING); + } catch (Exception ex) { + Alert a = new Alert(AlertType.ERROR, "Load from File failed:\n" + ex, ButtonType.CLOSE); + a.show(); + } + }); + actions = new ToolBar(pageLabel, pageChooser, update, loadFile, saveFile); setupListeners(); setTop(actions); } @@ -121,6 +152,36 @@ private void updatePage(boolean doAlloc) { currentPage.setVisible(inUse); } + private final Iterable toCSV() { + ArrayList lines = new ArrayList<>(); + int pageSize = ram.cellCount(); + for (int i = 0; i < ram.pageCount(); i++) { + if (!ram.isPageInUse(i)) + continue; + for (int k = 0; k < pageSize; k += 16) { + int offset = i * pageSize + k; + StringBuilder sb = new StringBuilder(); + sb.append(HexIntStringConverter.INT_16.toString(offset) + ","); + for (int j = 0; j < 15; j++) { + sb.append(HexIntStringConverter.INT_16.toString((int) ram.get(offset + j)) + ","); + } + sb.append(HexIntStringConverter.INT_16.toString((int) ram.get(offset + 15))); + lines.add(sb.toString()); + } + } + return lines; + } + + private final void readCSV(Iterable lines) { + for (String line : lines) { + String[] parts = line.split(","); + int offset = Integer.decode(parts[0]); + for (int i = 0; i < 16; i++) { + ram.set(offset + i, Integer.decode(parts[i + 1])); + } + } + } + private int getValue(int inPageAddress) { return ram.get(page.get() * ram.cellCount() + inPageAddress); } @@ -129,7 +190,7 @@ private void setValue(int inPageAddress, int value) { ram.set(page.get() * ram.cellCount() + inPageAddress, value); } - @SuppressWarnings({ "javadoc", "synthetic-access" }) + @SuppressWarnings("synthetic-access") public class RAM16CellRow { private final IntegerProperty[] columns = new SimpleIntegerProperty[16]; private final IntegerProperty offset; diff --git a/src/main/java/net/maisikoleni/am2900me/ui/am2900me_style.css b/src/main/java/net/maisikoleni/am2900me/ui/am2900me_style.css deleted file mode 100644 index 498b4f0..0000000 --- a/src/main/java/net/maisikoleni/am2900me/ui/am2900me_style.css +++ /dev/null @@ -1,4 +0,0 @@ -.root { - -fx-font-family: "Consolas", "monospaced"; - /*-fx-font-size: 10pt;*/ -} \ No newline at end of file diff --git a/src/main/java/net/maisikoleni/am2900me/util/AdvBindings.java b/src/main/java/net/maisikoleni/am2900me/util/AdvBindings.java new file mode 100644 index 0000000..be0fa54 --- /dev/null +++ b/src/main/java/net/maisikoleni/am2900me/util/AdvBindings.java @@ -0,0 +1,81 @@ +package net.maisikoleni.am2900me.util; + +import java.util.concurrent.Callable; +import java.util.function.Function; + +import javafx.beans.binding.Bindings; +import javafx.beans.binding.ObjectBinding; +import javafx.beans.value.ObservableValue; +import javafx.collections.FXCollections; +import javafx.collections.ObservableList; + +/** + * Some extensions of {@link Bindings} + * + * @author MaisiKoleni + */ +public class AdvBindings { + + private AdvBindings() { + // utility class only + } + + /** + * Creates a {@link ObjectBinding} from an {@link ObservableValue} T that is + * mapped using a given mapping {@link Function} to a type U. The Binding gets + * updated when either observable or the mapped {@link ObservableValue} becomes + * invalid. + * + * @param observable the observable value getting mapped; must not be null + * @param mapping the mapping function gets applied at each invalidation of + * observable, must be null tolerant if observable returns a + * null value. + * + * @see Bindings#createObjectBinding(Callable, javafx.beans.Observable...) + * + * @author MaisiKoleni + */ + public static ObjectBinding map(ObservableValue observable, Function> mapping) { + return new ObjectBinding<>() { + private ObservableValue dependTwo; + { + observable.addListener(e -> updateMapping()); + bind(observable); + updateMapping(); + } + + @Override + protected U computeValue() { + try { + return dependTwo == null ? null : dependTwo.getValue(); + } catch (Exception e) { + e.printStackTrace(); + return null; + } + } + + private void updateMapping() { + if (dependTwo != null) + super.unbind(dependTwo); + dependTwo = mapping.apply(observable.getValue()); + if (dependTwo != null) + super.bind(dependTwo); + } + + @Override + public void dispose() { + super.unbind(observable); + if (dependTwo != null) + super.unbind(dependTwo); + } + + @Override + public ObservableList getDependencies() { + if (dependTwo != null) + return FXCollections.unmodifiableObservableList( + FXCollections.>observableArrayList(observable, dependTwo)); + return FXCollections.singletonObservableList(observable); + } + }; + } +} diff --git a/src/main/java/net/maisikoleni/am2900me/util/EnumStringConverter.java b/src/main/java/net/maisikoleni/am2900me/util/EnumStringConverter.java new file mode 100644 index 0000000..0dda216 --- /dev/null +++ b/src/main/java/net/maisikoleni/am2900me/util/EnumStringConverter.java @@ -0,0 +1,37 @@ +package net.maisikoleni.am2900me.util; + +import javafx.util.StringConverter; + +/** + * {@link StringConverter} for enum types. + * + * @author MaisiKoleni + */ +public class EnumStringConverter> extends StringConverter { + + private final T instance; + + /** + * Requires an instance of the enum for converting because of type erasure. + * + * @author MaisiKoleni + */ + public EnumStringConverter(T instance) { + this.instance = instance; + } + + @Override + public String toString(T object) { + if (object == null) + return ""; + return object.name(); + } + + @Override + public T fromString(String string) { + if (string == null || string.trim().isEmpty()) + return null; + return Enum.valueOf(instance.getDeclaringClass(), string); + } + +} diff --git a/src/main/java/net/maisikoleni/am2900me/util/HexIntStringConverter.java b/src/main/java/net/maisikoleni/am2900me/util/HexIntStringConverter.java index 9922897..9130891 100644 --- a/src/main/java/net/maisikoleni/am2900me/util/HexIntStringConverter.java +++ b/src/main/java/net/maisikoleni/am2900me/util/HexIntStringConverter.java @@ -10,7 +10,6 @@ * * @author MaisiKoleni */ -@SuppressWarnings("javadoc") public class HexIntStringConverter extends StringConverter { public static final HexIntStringConverter INT_4 = new HexIntStringConverter(1); @@ -47,4 +46,27 @@ public String toString(Integer value) { public int cast(int value) { return value & mask; } + + public static HexIntStringConverter forNibbles(int n) { + switch (n) { + case 1: + return INT_4; + case 2: + return INT_8; + case 3: + return INT_12; + case 4: + return INT_16; + case 5: + return INT_20; + case 6: + return INT_24; + case 7: + return INT_28; + case 8: + return INT_32; + default: + throw new IllegalArgumentException("invalid number of int nibbles: " + n); + } + } } \ No newline at end of file diff --git a/src/main/java/net/maisikoleni/am2900me/util/NBitsUInt.java b/src/main/java/net/maisikoleni/am2900me/util/NBitsUInt.java index af8cf58..30c49d4 100644 --- a/src/main/java/net/maisikoleni/am2900me/util/NBitsUInt.java +++ b/src/main/java/net/maisikoleni/am2900me/util/NBitsUInt.java @@ -4,7 +4,7 @@ abstract public class NBitsUInt { public final int value; public final int bits; - public NBitsUInt(int bits, int value) { + protected NBitsUInt(int bits, int value) { if (!BitUtil.isInRange(bits - 1, 5)) throw new IllegalArgumentException("illegal number of bits: " + bits); if (!BitUtil.isInRange(value, bits)) @@ -16,7 +16,7 @@ public NBitsUInt(int bits, int value) { @Override public String toString() { - return BitUtil.toNbitString(value, bits); + return HexIntStringConverter.forNibbles(bits / 4).toString(value); } @Override diff --git a/src/main/java/net/maisikoleni/am2900me/util/UniversalHexIntStringConverter.java b/src/main/java/net/maisikoleni/am2900me/util/UniversalHexIntStringConverter.java new file mode 100644 index 0000000..1310258 --- /dev/null +++ b/src/main/java/net/maisikoleni/am2900me/util/UniversalHexIntStringConverter.java @@ -0,0 +1,34 @@ +package net.maisikoleni.am2900me.util; + +import java.util.function.IntFunction; +import java.util.function.ToIntFunction; + +import javafx.util.StringConverter; + +/** + * Like {@link HexIntStringConverter} but gets supplied with from and to int + * functions to convert any type that can be represented by an integer. + * + * @author MaisiKoleni + */ +public class UniversalHexIntStringConverter extends StringConverter { + private final ToIntFunction toInt; + private final IntFunction fromInt; + private final HexIntStringConverter conv; + + public UniversalHexIntStringConverter(ToIntFunction toInt, IntFunction fromInt, HexIntStringConverter conv) { + this.toInt = toInt; + this.fromInt = fromInt; + this.conv = conv; + } + + @Override + public String toString(T object) { + return conv.toString(toInt.applyAsInt(object)); + } + + @Override + public T fromString(String string) { + return fromInt.apply(conv.fromString(string)); + } +} \ No newline at end of file diff --git "a/src/main/resources/icons/\302\265Icon128.png" "b/src/main/resources/icons/\302\265Icon128.png" new file mode 100644 index 0000000000000000000000000000000000000000..312f8a7c556f3b9525d2cff3717e54abf4a3182b GIT binary patch literal 9251 zcmV+;B;4DHP)d!~C9 z4u>X;MJwtZaOjXzL zvZ`x+_nz%L%RLvZOYac4 z;ZOhSN8a&C$nv;Gwo@YBgce#x5~;RM z^{bs^NgH0h3PaWemLljfL$q3^KZ+6d;AS(YwU(HWEaCF2(Lpw85i>P2wlYQBaYN>* zL(G5>J|Fydc8=#tp<9+sp%*}IUb1M+?La~^mTo3G4%Ycz2;OI<&{s16!VLP}lK5&9 zncy}NQ^0>E?rU)bB<>ayjG7gZcJkOnUM9Xakg3It0mROmO(nW$0E&Cc3>bSx5Qbm| zp#B=a&J2_7ZD@W17=Ts%$}+DGPj;cl#71QZiupOiwjO!$A|7oo?Ow$SF=>t8*H6{f zT9%e9F?^3ZP}Q%;EoyXW)72CK_AY`3Joi2-65T(fZHYb$U^dzG!2RRxEq7!MqdovA}Vz%fDY+TH{^9z`=r{g1KIi-M1m;?n^VpJFk}YUV2~#Z zz{F?UuaY4vXLF+07$E<&GC<cii#o|epvBE6X~sAcSDRh>HwP;nPL;laI@ zrtUjT#Peb%U}4Dm*%UK?az9H-M(R4LnqGqaBH{<@teaFUONC3C9@ zNSu2ak;XMtC@hVOH%$oxh-64|54{A4>y+72YW%-Z`zby%>X4W~6cd;h+gsSHKv1LX ztByAjo28Z{g3y^V<5fKdW~`8W@XT&qh#Oq6OBgv5v9PnC0a9KpwRcH?0mwnBP^VKU zYLTaL0k|(2$C_w&HcmJqAz^sSbp38SklP0Ofq4AvqJEK#*Y_ zQ8fmDHTngvAtJ%fjQ`#M1RP;jC;@Guz5)&CO__KN3L?pyGje!hY8e0vo9PHHHZx-e zFyaE%iAA;O8-|gzzyuS*BySjAun+lS;hf?qLk5gsdH%?h*R{ypTxb?dfJnR|UWx39 z@2u`!9t5(@QY>me$utWn88)j9gkcCVf#_ct2~cMS)&JM)8#)k(xuiE;mS6#O12ac- z5ems`heu`9spLQqouMQRmO$w*2dZ95zKo<;b+GhAB0ZCJ163i#)?brR zP>RL`C4eRfY=umKTG!y58q1ncOu*iQKr;dQJJ-!4{;+_fP@8$gtgdU(=Zr9jsZ6@C z9ZTD$*H-#5Pz^~31)_*Gx79^8Gc9|Z0S%B3%%f(a4(qAl;+~3!RLK

x+#Rd8d~9 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 FV1h2kvn2ok literal 0 HcmV?d00001 diff --git "a/src/main/resources/icons/\302\265Icon16.png" "b/src/main/resources/icons/\302\265Icon16.png" new file mode 100644 index 0000000000000000000000000000000000000000..1c78ee8f3777f621d039dc8279c269967d6b610b GIT binary patch literal 645 zcmV;00($+4P)RCwBaQ_F7CKomW9#*@T}(+W31 zl(4CwNT9G}S73p}53pd%qF;c-k`+I|C-4F6kl3&&0twL#iYkFnOQedHAOcO|JnY1e z8OC;-H@)^q_V}K2&%JX@QU)L*0P$+CBXri4A1Wzmp9?lX5=tOaHxUUQP`+gtYlksL zDG6f&WU%kj)Z8JoBJ%&VatM#apuS%K<73PWK{y;KIT|L?G`&ofQF1Gi5~C3U zH$htz?86C!9kdb)Djhz)EL$R|O>tVQEbc+fUgA$|gO~ zZ2m$E+AuIT^0@fD_r%%ReUzh0cN9Rgre5U`q%n zCgA8EbWpf*>BXJL8*g+^abK|Q)jhyM!zn;XwOoNPv&2|lyEg!jU?Q1XG<8052E0HJ z6-(rvtYVZIz$2gcdalNV6Z@RKWe*z2u#c}c;O7pnm00000NkvXXu0mjfX9XgA literal 0 HcmV?d00001 diff --git "a/src/main/resources/icons/\302\265Icon32.png" "b/src/main/resources/icons/\302\265Icon32.png" new file mode 100644 index 0000000000000000000000000000000000000000..3d6f2e1a504f22dbcd607b03426ca75b47fe69e5 GIT binary patch literal 1352 zcmV-O1-JT%P)PbXFRCwB?S4(djRTTcty)zTLiQ^p&B;s+oE3l<<{!M+G}0jiJ?Yd}b_E?{i5h7yTFUuk8IMTv}uBqW)iL?e#rw z^yea&$g!Z-SE0y)N6@|l#Y{XQZ&^tr3;6vAPry^F+GPf?K!yp$oXYmx^@-G}UGRSg z!1c8N8BDf2i^|1+P*6#ouR&MxDBat@*PHsY*WP~a4X7%s)k#Bvn#~##WCh1n^>)=2 ztU2ZaPrRr^3PO4;Ev@0Z^=k)+*#5Jlp9<2OUZsDXMkjgJKXWHf>`8 zglQ9M6xje2b5v6cN!unmqK^R(>w-}8E(244?R(!-6KsQ;Mg*WcL`QZIJpg(?NADF| zqiJ^C8MAt57exM4P19;Q*b)?Jt|7bJpmnSV4sk)qgxXJ%U7B`RK@n{Rpj!Z_yZ+Fy z79i?Kx=z8J&!&S!dkfj+zPM!^7KH6sXb7Z0h{d}WYTL<*f`f)ZI%)Kz?BEzUf(zRD zZI}k6(q>rqx$(84Tt^K|dz6tG)1;&f3G@+K^`QW$1IT#VLfUa3s=8ceMTTFV;yuZG zB6OFsb8E(2Ae(U1btr&nnux4zOqqD*q(0E9T5fS&L$ahl-UZbs2=29v~w5J<4*+rQn1%nM9EH3wnJC_5R9*2i!` z%bdDVYo<-mk^$qq1?#*CYr#Z{gD!h>10Q}-&OwgVt!foAx5p!aht$L4FcPC$fTCIu zYSKV!aSo`83xB%?X-WR<TfW^X;v#wnFm6{21gJKNy%2BLSdB z1cntr@L$&K*K1om9x8J0y4Wcz+|GNu#ijJscRqjN(&Oi5A6(ljzno1^2k8M}XzZ1W z*ec@pkqc1>f}I%1ckLR!{}bOl`_jt$wdMMJLZJT26H|XYb}pTbMkpH>UOaoX9r^IxC|r2{%nc6p=HSLY@!Dn1%mwUIsBUUvib1YCf1KQlti_oC}Os?tDN`!6*B7uZ#^d}lZ5DgEY*?Q!75|rSy z3oOC2J_X11u)=9n3lOaNB_e}wK*24DK_oLN7$rAGF*+ceNW_AO0U$`HXU0{Ln@qmM zrN4m03g3XT<)rVIf{_`6+g(F*X~1#nsMqVm0ibZeNEW|aU$~t6*L@W3SuUvyTu>zT zl=st>E2+Wvldjt}p=QrwW#!3s+dk6ev{{CFuII;DgRbZQ3orn|c^nflCk8tJ0000< KMNUMnLSTYb9DvyX literal 0 HcmV?d00001 diff --git a/src/main/resources/style/am2900me_style.css b/src/main/resources/style/am2900me_style.css new file mode 100644 index 0000000..4e6941c --- /dev/null +++ b/src/main/resources/style/am2900me_style.css @@ -0,0 +1,20 @@ +.root { + -fx-font-family: "Consolas", "monospaced"; + /*-fx-base: rgb(50,50,50); + -fx-background: -fx-base; + -fx-control-inner-background: rgb(40,40,40); + -fx-control-inner-background-alt: rgb(45,45,45); + -fx-faint-focus-color: -fx-accent; + -fx-hover-base: rgb(180,180,180); + -fx-pressed-base: derive(-fx-hover-base, -15%); + -fx-box-border: -fx-hover-base; + -fx-text-box-border: -fx-hover-base; + -fx-shadow-highlight-color: rgb(120,30,30); + -fx-outer-border: -fx-hover-base; + -fx-focus-color: rgb(120,30,30);*/ + -fx-accent: rgb(250,100,60); +} + +.changed-mi { + -fx-background-color: lightsteelblue; +} \ No newline at end of file diff --git a/src/test/java/net/maisikoleni/am2900me/logic/Am2900MachineTest.java b/src/test/java/net/maisikoleni/am2900me/logic/Am2900MachineTest.java index b3c3f06..a40ea25 100644 --- a/src/test/java/net/maisikoleni/am2900me/logic/Am2900MachineTest.java +++ b/src/test/java/net/maisikoleni/am2900me/logic/Am2900MachineTest.java @@ -10,7 +10,7 @@ import net.maisikoleni.am2900me.logic.microinstr._BZ_INC; import net.maisikoleni.am2900me.logic.microinstr._IR_LD; -@SuppressWarnings({ "static-method", "javadoc" }) +@SuppressWarnings({ "static-method" }) public class Am2900MachineTest { @Test(priority = 1) diff --git a/src/test/java/net/maisikoleni/am2900me/logic/Am2901Test.java b/src/test/java/net/maisikoleni/am2900me/logic/Am2901Test.java index 74f5ed2..c659cf4 100644 --- a/src/test/java/net/maisikoleni/am2900me/logic/Am2901Test.java +++ b/src/test/java/net/maisikoleni/am2900me/logic/Am2901Test.java @@ -11,7 +11,7 @@ import net.maisikoleni.am2900me.logic.microinstr.Am2901_Src; import net.maisikoleni.am2900me.util.BitUtil; -@SuppressWarnings({ "static-method", "javadoc" }) +@SuppressWarnings({ "static-method" }) public class Am2901Test { @Test