diff --git a/src/main/java/de/neemann/digital/analyse/TruthTableTableModel.java b/src/main/java/de/neemann/digital/analyse/TruthTableTableModel.java index 891b4cfce..4f9b15a21 100644 --- a/src/main/java/de/neemann/digital/analyse/TruthTableTableModel.java +++ b/src/main/java/de/neemann/digital/analyse/TruthTableTableModel.java @@ -17,7 +17,7 @@ public class TruthTableTableModel implements TableModel { public static final String[] STATENAMES = new String[]{"0", "1", "x"}; private final TruthTable truthTable; - private ArrayList listeners = new ArrayList<>(); + private final ArrayList listeners = new ArrayList<>(); /** * Creates a new instance diff --git a/src/main/java/de/neemann/digital/core/memory/DataField.java b/src/main/java/de/neemann/digital/core/memory/DataField.java index c45d54a95..6545628a3 100644 --- a/src/main/java/de/neemann/digital/core/memory/DataField.java +++ b/src/main/java/de/neemann/digital/core/memory/DataField.java @@ -20,7 +20,7 @@ public class DataField { private long[] data; private final int bits; - private transient ArrayList listeners; + private final transient ArrayList listeners = new ArrayList<>(); /** * Creates a new DataField @@ -158,9 +158,9 @@ public class DataField { * @param l the listener */ public void addListener(DataListener l) { - if (listeners == null) - listeners = new ArrayList<>(); - listeners.add(l); + synchronized (listeners) { + listeners.add(l); + } } /** @@ -169,12 +169,9 @@ public class DataField { * @param l the listener to remove */ public void removeListener(DataListener l) { - if (listeners == null) - return; - - listeners.remove(l); - if (listeners.isEmpty()) - listeners = null; + synchronized (listeners) { + listeners.remove(l); + } } /** @@ -183,11 +180,10 @@ public class DataField { * @param addr the address which value has changed */ public void fireChanged(int addr) { - if (listeners == null) - return; - - for (DataListener l : listeners) - l.valueChanged(addr); + synchronized (listeners) { + for (DataListener l : listeners) + l.valueChanged(addr); + } } /** diff --git a/src/main/java/de/neemann/digital/draw/model/RealTimeClock.java b/src/main/java/de/neemann/digital/draw/model/RealTimeClock.java index 0aa7fe3a8..92d79f697 100644 --- a/src/main/java/de/neemann/digital/draw/model/RealTimeClock.java +++ b/src/main/java/de/neemann/digital/draw/model/RealTimeClock.java @@ -4,6 +4,7 @@ import de.neemann.digital.core.*; import de.neemann.digital.core.wiring.Clock; import de.neemann.digital.gui.ErrorStopper; import de.neemann.digital.gui.GuiModelObserver; +import de.neemann.digital.gui.StatusInterface; import de.neemann.digital.gui.sync.Sync; import de.neemann.digital.lang.Lang; @@ -21,6 +22,7 @@ public class RealTimeClock implements ModelStateObserver { private final ScheduledThreadPoolExecutor executor; private final ErrorStopper stopper; private final Sync modelSync; + private final StatusInterface status; private final int frequency; private final ObservableValue output; private Runner runner; @@ -31,12 +33,14 @@ public class RealTimeClock implements ModelStateObserver { * @param model the model * @param clock the clock element which is modify * @param executor the executor used to schedule the update + * @param status allows sending messages to the status line */ - public RealTimeClock(Model model, Clock clock, ScheduledThreadPoolExecutor executor, ErrorStopper stopper, Sync modelSync) { + public RealTimeClock(Model model, Clock clock, ScheduledThreadPoolExecutor executor, ErrorStopper stopper, Sync modelSync, StatusInterface status) { this.model = model; this.executor = executor; this.stopper = stopper; this.modelSync = modelSync; + this.status = status; int f = clock.getFrequency(); if (f < 1) f = 1; this.frequency = f; @@ -48,7 +52,7 @@ public class RealTimeClock implements ModelStateObserver { switch (event) { case STARTED: if (frequency > 50) // if frequency is high it is not necessary to update the GUI at every clock change - output.removeObserver(GuiModelObserver.class); + modelSync.access(() -> output.removeObserver(GuiModelObserver.class)); int delay = 500000 / frequency; if (delay < 10) @@ -110,8 +114,8 @@ public class RealTimeClock implements ModelStateObserver { @Override public void run() { System.out.println("thread start"); - long time= System.currentTimeMillis(); - long counter=0; + long time = System.currentTimeMillis(); + long counter = 0; try { while (!interrupted()) { modelSync.accessNEx(() -> { @@ -123,9 +127,9 @@ public class RealTimeClock implements ModelStateObserver { } catch (NodeException e1) { stopper.showErrorAndStopModel(Lang.get("msg_clockError"), e1); } - time=System.currentTimeMillis()-time; + time = System.currentTimeMillis() - time; - System.out.println(counter/time/2+"kHz"); + status.setStatus(counter / time / 2 + "kHz"); System.out.println("thread end"); } diff --git a/src/main/java/de/neemann/digital/gui/Main.java b/src/main/java/de/neemann/digital/gui/Main.java index 048846688..c1931d4c1 100644 --- a/src/main/java/de/neemann/digital/gui/Main.java +++ b/src/main/java/de/neemann/digital/gui/Main.java @@ -59,7 +59,7 @@ import java.util.concurrent.ScheduledThreadPoolExecutor; * * @author hneemann */ -public class Main extends JFrame implements ClosingWindowListener.ConfirmSave, ErrorStopper, FileHistory.OpenInterface, DigitalRemoteInterface { +public class Main extends JFrame implements ClosingWindowListener.ConfirmSave, ErrorStopper, FileHistory.OpenInterface, DigitalRemoteInterface, StatusInterface { private static final ArrayList ATTR_LIST = new ArrayList<>(); private static boolean experimental; @@ -678,17 +678,17 @@ public class Main extends JFrame implements ClosingWindowListener.ConfirmSave, E statusLabel.setText(Lang.get("msg_N_nodes", model.size())); realtimeClockRunning = false; - modelSync=null; + modelSync = null; if (globalRunClock) for (Clock c : model.getClocks()) if (c.getFrequency() > 0) { - if (modelSync==null) - modelSync=new LockSync(); - model.addObserver(new RealTimeClock(model, c, timerExecuter, this, modelSync)); + if (modelSync == null) + modelSync = new LockSync(); + model.addObserver(new RealTimeClock(model, c, timerExecuter, this, modelSync, this)); realtimeClockRunning = true; } - if (modelSync==null) - modelSync= NoSync.INST; + if (modelSync == null) + modelSync = NoSync.INST; circuitComponent.setModeAndReset(true, modelSync); @@ -841,6 +841,11 @@ public class Main extends JFrame implements ClosingWindowListener.ConfirmSave, E return windowPosManager; } + @Override + public void setStatus(String message) { + SwingUtilities.invokeLater(() -> statusLabel.setText(message)); + } + private class FullStepObserver implements Observer { private final Model model; diff --git a/src/main/java/de/neemann/digital/gui/StatusInterface.java b/src/main/java/de/neemann/digital/gui/StatusInterface.java new file mode 100644 index 000000000..0f73606b0 --- /dev/null +++ b/src/main/java/de/neemann/digital/gui/StatusInterface.java @@ -0,0 +1,15 @@ +package de.neemann.digital.gui; + +/** + * Interface to acess the status line + * + * @author hneemann + */ +public interface StatusInterface { + /** + * Set message to the status line + * + * @param message the message + */ + void setStatus(String message); +} diff --git a/src/main/java/de/neemann/digital/gui/components/graphics/GraphicCard.java b/src/main/java/de/neemann/digital/gui/components/graphics/GraphicCard.java index d8ba1ca30..388a184f6 100644 --- a/src/main/java/de/neemann/digital/gui/components/graphics/GraphicCard.java +++ b/src/main/java/de/neemann/digital/gui/components/graphics/GraphicCard.java @@ -17,6 +17,10 @@ import javax.swing.*; import static de.neemann.digital.core.element.PinInfo.input; /** + * Graphic card. + * Mostly a RAM module with an additional input bit which selects the visible bank. + * So you can use double buffering. + * * @author hneemann */ public class GraphicCard extends Node implements Element, RAMInterface { diff --git a/src/main/java/de/neemann/digital/gui/components/listing/ROMListingDialog.java b/src/main/java/de/neemann/digital/gui/components/listing/ROMListingDialog.java index f7d6fcaf9..f4bfdaa22 100644 --- a/src/main/java/de/neemann/digital/gui/components/listing/ROMListingDialog.java +++ b/src/main/java/de/neemann/digital/gui/components/listing/ROMListingDialog.java @@ -83,7 +83,6 @@ public class ROMListingDialog extends JDialog implements Observer { list.setSelectedIndex(line); }); } - lastAddr = addr; } }