mirror of
https://github.com/hneemann/Digital.git
synced 2025-09-10 13:26:43 -04:00
first test to implement a async realtime executer
This commit is contained in:
parent
d48dd576cf
commit
89cf567dde
@ -6,6 +6,7 @@
|
|||||||
package de.neemann.digital.core;
|
package de.neemann.digital.core;
|
||||||
|
|
||||||
import de.neemann.digital.core.io.Button;
|
import de.neemann.digital.core.io.Button;
|
||||||
|
import de.neemann.digital.core.wiring.AsyncSeq;
|
||||||
import de.neemann.digital.core.wiring.Break;
|
import de.neemann.digital.core.wiring.Break;
|
||||||
import de.neemann.digital.core.wiring.Clock;
|
import de.neemann.digital.core.wiring.Clock;
|
||||||
import de.neemann.digital.core.wiring.Reset;
|
import de.neemann.digital.core.wiring.Reset;
|
||||||
@ -41,6 +42,7 @@ import java.util.*;
|
|||||||
* call of the registerNodes method. These lists are necessary to keep track of all elements which are not a node like
|
* call of the registerNodes method. These lists are necessary to keep track of all elements which are not a node like
|
||||||
* inputs and outputs. All elements which are nodes can be obtained by {@link #findNode(Class, NodeFilter)} or
|
* inputs and outputs. All elements which are nodes can be obtained by {@link #findNode(Class, NodeFilter)} or
|
||||||
* {@link #findNode(Class)}.
|
* {@link #findNode(Class)}.
|
||||||
|
*
|
||||||
* @see de.neemann.digital.core.element.Element#registerNodes(Model)
|
* @see de.neemann.digital.core.element.Element#registerNodes(Model)
|
||||||
*/
|
*/
|
||||||
public class Model implements Iterable<Node> {
|
public class Model implements Iterable<Node> {
|
||||||
@ -71,6 +73,7 @@ public class Model implements Iterable<Node> {
|
|||||||
private WindowPosManager windowPosManager;
|
private WindowPosManager windowPosManager;
|
||||||
private HashSet<Node> oscillatingNodes;
|
private HashSet<Node> oscillatingNodes;
|
||||||
private boolean isInvalidSignal = false;
|
private boolean isInvalidSignal = false;
|
||||||
|
private AsyncSeq asyncInfos;
|
||||||
|
|
||||||
private final ArrayList<ModelStateObserver> observers;
|
private final ArrayList<ModelStateObserver> observers;
|
||||||
private ArrayList<ModelStateObserver> observersStep;
|
private ArrayList<ModelStateObserver> observersStep;
|
||||||
@ -715,4 +718,21 @@ public class Model implements Iterable<Node> {
|
|||||||
return i.getValue();
|
return i.getValue();
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets async execution infos
|
||||||
|
*
|
||||||
|
* @param asyncInfos manly the frequency
|
||||||
|
*/
|
||||||
|
public void setAsyncInfos(AsyncSeq asyncInfos) {
|
||||||
|
this.asyncInfos = asyncInfos;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the infos uset for async execution
|
||||||
|
*/
|
||||||
|
public AsyncSeq getAsyncInfos() {
|
||||||
|
return asyncInfos;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
64
src/main/java/de/neemann/digital/core/wiring/AsyncSeq.java
Normal file
64
src/main/java/de/neemann/digital/core/wiring/AsyncSeq.java
Normal file
@ -0,0 +1,64 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2016 Helmut Neemann
|
||||||
|
* Use of this source code is governed by the GPL v3 license
|
||||||
|
* that can be found in the LICENSE file.
|
||||||
|
*/
|
||||||
|
package de.neemann.digital.core.wiring;
|
||||||
|
|
||||||
|
import de.neemann.digital.core.*;
|
||||||
|
import de.neemann.digital.core.element.Element;
|
||||||
|
import de.neemann.digital.core.element.ElementAttributes;
|
||||||
|
import de.neemann.digital.core.element.ElementTypeDescription;
|
||||||
|
import de.neemann.digital.core.element.Keys;
|
||||||
|
import de.neemann.digital.lang.Lang;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*/
|
||||||
|
public class AsyncSeq implements Element {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* the clocks description
|
||||||
|
*/
|
||||||
|
public static final ElementTypeDescription DESCRIPTION = new ElementTypeDescription(AsyncSeq.class)
|
||||||
|
.addAttribute(Keys.RUN_AT_REAL_TIME)
|
||||||
|
.addAttribute(Keys.FREQUENCY);
|
||||||
|
|
||||||
|
private final int frequency;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new instance
|
||||||
|
*
|
||||||
|
* @param attributes the clocks attributes
|
||||||
|
*/
|
||||||
|
public AsyncSeq(ElementAttributes attributes) {
|
||||||
|
if (attributes.get(Keys.RUN_AT_REAL_TIME)) {
|
||||||
|
int f = attributes.get(Keys.FREQUENCY);
|
||||||
|
if (f < 1) f = 1;
|
||||||
|
frequency = f;
|
||||||
|
} else
|
||||||
|
frequency = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setInputs(ObservableValues inputs) throws NodeException {
|
||||||
|
throw new NodeException(Lang.get("err_noInputsAvailable"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ObservableValues getOutputs() {
|
||||||
|
return ObservableValues.EMPTY_LIST;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void registerNodes(Model model) {
|
||||||
|
model.setAsyncInfos(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the clocks frequency
|
||||||
|
*/
|
||||||
|
public int getFrequency() {
|
||||||
|
return frequency;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -190,6 +190,7 @@ public class ElementLibrary implements Iterable<ElementLibrary.ElementContainer>
|
|||||||
.add(TransGate.DESCRIPTION))
|
.add(TransGate.DESCRIPTION))
|
||||||
.add(new LibraryNode(Lang.get("lib_misc"))
|
.add(new LibraryNode(Lang.get("lib_misc"))
|
||||||
.add(TestCaseElement.TESTCASEDESCRIPTION)
|
.add(TestCaseElement.TESTCASEDESCRIPTION)
|
||||||
|
.add(AsyncSeq.DESCRIPTION)
|
||||||
.add(PowerSupply.DESCRIPTION)
|
.add(PowerSupply.DESCRIPTION)
|
||||||
.add(BusSplitter.DESCRIPTION)
|
.add(BusSplitter.DESCRIPTION)
|
||||||
.add(Reset.DESCRIPTION)
|
.add(Reset.DESCRIPTION)
|
||||||
|
@ -0,0 +1,99 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2016 Helmut Neemann
|
||||||
|
* Use of this source code is governed by the GPL v3 license
|
||||||
|
* that can be found in the LICENSE file.
|
||||||
|
*/
|
||||||
|
package de.neemann.digital.draw.model;
|
||||||
|
|
||||||
|
import de.neemann.digital.core.Model;
|
||||||
|
import de.neemann.digital.core.ModelEvent;
|
||||||
|
import de.neemann.digital.core.ModelStateObserverTyped;
|
||||||
|
import de.neemann.digital.core.NodeException;
|
||||||
|
import de.neemann.digital.core.wiring.AsyncSeq;
|
||||||
|
import de.neemann.digital.gui.ErrorStopper;
|
||||||
|
import de.neemann.digital.gui.sync.Sync;
|
||||||
|
import de.neemann.digital.lang.Lang;
|
||||||
|
|
||||||
|
import java.util.concurrent.ScheduledFuture;
|
||||||
|
import java.util.concurrent.ScheduledThreadPoolExecutor;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The real time clock used to clock a circuit in async mode.
|
||||||
|
*/
|
||||||
|
public class AsyncSequentialClock implements ModelStateObserverTyped {
|
||||||
|
private final Model model;
|
||||||
|
private final ScheduledThreadPoolExecutor executor;
|
||||||
|
private final ErrorStopper stopper;
|
||||||
|
private final Sync modelSync;
|
||||||
|
private final int frequency;
|
||||||
|
private RealTimeRunner runner;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new real time clock
|
||||||
|
*
|
||||||
|
* @param model the model
|
||||||
|
* @param asyncSeq the infos used to cofigure the clock
|
||||||
|
* @param executor the executor used to schedule the update
|
||||||
|
* @param stopper used to stop the model if an error is detected
|
||||||
|
* @param modelSync used to access a running model
|
||||||
|
*/
|
||||||
|
public AsyncSequentialClock(Model model, AsyncSeq asyncSeq, ScheduledThreadPoolExecutor executor, ErrorStopper stopper, Sync modelSync) {
|
||||||
|
this.model = model;
|
||||||
|
this.executor = executor;
|
||||||
|
this.stopper = stopper;
|
||||||
|
this.modelSync = modelSync;
|
||||||
|
int f = asyncSeq.getFrequency();
|
||||||
|
if (f < 1) f = 1;
|
||||||
|
this.frequency = f;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void handleEvent(ModelEvent event) {
|
||||||
|
switch (event) {
|
||||||
|
case STARTED:
|
||||||
|
int delayMuS = 1000000 / frequency;
|
||||||
|
if (delayMuS < 50)
|
||||||
|
delayMuS = 50;
|
||||||
|
runner = new RealTimeRunner(delayMuS);
|
||||||
|
break;
|
||||||
|
case STOPPED:
|
||||||
|
if (runner != null)
|
||||||
|
runner.stop();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ModelEvent[] getEvents() {
|
||||||
|
return new ModelEvent[]{ModelEvent.STARTED, ModelEvent.STOPPED};
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* runs with defined rate
|
||||||
|
*/
|
||||||
|
private class RealTimeRunner {
|
||||||
|
|
||||||
|
private final ScheduledFuture<?> timer;
|
||||||
|
|
||||||
|
RealTimeRunner(int delay) {
|
||||||
|
timer = executor.scheduleAtFixedRate(new Runnable() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
try {
|
||||||
|
modelSync.accessNEx(() -> model.doMicroStep(false));
|
||||||
|
} catch (NodeException | RuntimeException e) {
|
||||||
|
stopper.showErrorAndStopModel(Lang.get("msg_clockError"), e);
|
||||||
|
timer.cancel(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, delay, delay, TimeUnit.MICROSECONDS);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void stop() {
|
||||||
|
if (timer != null)
|
||||||
|
timer.cancel(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -15,6 +15,7 @@ import de.neemann.digital.core.element.Keys;
|
|||||||
import de.neemann.digital.core.io.Button;
|
import de.neemann.digital.core.io.Button;
|
||||||
import de.neemann.digital.core.io.*;
|
import de.neemann.digital.core.io.*;
|
||||||
import de.neemann.digital.core.memory.ROM;
|
import de.neemann.digital.core.memory.ROM;
|
||||||
|
import de.neemann.digital.core.wiring.AsyncSeq;
|
||||||
import de.neemann.digital.core.wiring.Clock;
|
import de.neemann.digital.core.wiring.Clock;
|
||||||
import de.neemann.digital.draw.elements.*;
|
import de.neemann.digital.draw.elements.*;
|
||||||
import de.neemann.digital.draw.gif.GifExporter;
|
import de.neemann.digital.draw.gif.GifExporter;
|
||||||
@ -22,6 +23,7 @@ import de.neemann.digital.draw.graphics.*;
|
|||||||
import de.neemann.digital.draw.library.CustomElement;
|
import de.neemann.digital.draw.library.CustomElement;
|
||||||
import de.neemann.digital.draw.library.ElementLibrary;
|
import de.neemann.digital.draw.library.ElementLibrary;
|
||||||
import de.neemann.digital.draw.library.ElementNotFoundException;
|
import de.neemann.digital.draw.library.ElementNotFoundException;
|
||||||
|
import de.neemann.digital.draw.model.AsyncSequentialClock;
|
||||||
import de.neemann.digital.draw.model.ModelCreator;
|
import de.neemann.digital.draw.model.ModelCreator;
|
||||||
import de.neemann.digital.draw.model.RealTimeClock;
|
import de.neemann.digital.draw.model.RealTimeClock;
|
||||||
import de.neemann.digital.draw.shapes.Drawable;
|
import de.neemann.digital.draw.shapes.Drawable;
|
||||||
@ -1188,6 +1190,18 @@ public final class Main extends JFrame implements ClosingWindowListener.ConfirmS
|
|||||||
if (threadRunnerCount > 1)
|
if (threadRunnerCount > 1)
|
||||||
throw new RuntimeException(Lang.get("err_moreThanOneFastClock"));
|
throw new RuntimeException(Lang.get("err_moreThanOneFastClock"));
|
||||||
}
|
}
|
||||||
|
if (!realTimeClockRunning && updateEvent == ModelEvent.MICROSTEP) {
|
||||||
|
// no real clock
|
||||||
|
AsyncSeq ai = model.getAsyncInfos();
|
||||||
|
if (ai != null && ai.getFrequency() > 0) {
|
||||||
|
modelSync = new LockSync();
|
||||||
|
model.addObserver(
|
||||||
|
new AsyncSequentialClock(model, ai, timerExecutor, this, modelSync));
|
||||||
|
realTimeClockRunning = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
if (modelSync == null)
|
if (modelSync == null)
|
||||||
modelSync = NoSync.INST;
|
modelSync = NoSync.INST;
|
||||||
|
|
||||||
@ -1429,9 +1443,11 @@ public final class Main extends JFrame implements ClosingWindowListener.ConfirmS
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void hasChanged() {
|
public void hasChanged() {
|
||||||
|
if (!realTimeClockRunning)
|
||||||
modelCreator.addNodeElementsTo(model.nodesToUpdate(), circuitComponent.getHighLighted());
|
modelCreator.addNodeElementsTo(model.nodesToUpdate(), circuitComponent.getHighLighted());
|
||||||
model.fireManualChangeEvent();
|
model.fireManualChangeEvent();
|
||||||
circuitComponent.repaintNeeded();
|
circuitComponent.repaintNeeded();
|
||||||
|
if (!realTimeClockRunning)
|
||||||
doStep.setEnabled(model.needsUpdate());
|
doStep.setEnabled(model.needsUpdate());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user