mirror of
https://github.com/hneemann/Digital.git
synced 2025-09-09 12:56:02 -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;
|
||||
|
||||
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.Clock;
|
||||
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
|
||||
* inputs and outputs. All elements which are nodes can be obtained by {@link #findNode(Class, NodeFilter)} or
|
||||
* {@link #findNode(Class)}.
|
||||
*
|
||||
* @see de.neemann.digital.core.element.Element#registerNodes(Model)
|
||||
*/
|
||||
public class Model implements Iterable<Node> {
|
||||
@ -71,6 +73,7 @@ public class Model implements Iterable<Node> {
|
||||
private WindowPosManager windowPosManager;
|
||||
private HashSet<Node> oscillatingNodes;
|
||||
private boolean isInvalidSignal = false;
|
||||
private AsyncSeq asyncInfos;
|
||||
|
||||
private final ArrayList<ModelStateObserver> observers;
|
||||
private ArrayList<ModelStateObserver> observersStep;
|
||||
@ -715,4 +718,21 @@ public class Model implements Iterable<Node> {
|
||||
return i.getValue();
|
||||
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(new LibraryNode(Lang.get("lib_misc"))
|
||||
.add(TestCaseElement.TESTCASEDESCRIPTION)
|
||||
.add(AsyncSeq.DESCRIPTION)
|
||||
.add(PowerSupply.DESCRIPTION)
|
||||
.add(BusSplitter.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.*;
|
||||
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.draw.elements.*;
|
||||
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.ElementLibrary;
|
||||
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.RealTimeClock;
|
||||
import de.neemann.digital.draw.shapes.Drawable;
|
||||
@ -1188,6 +1190,18 @@ public final class Main extends JFrame implements ClosingWindowListener.ConfirmS
|
||||
if (threadRunnerCount > 1)
|
||||
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)
|
||||
modelSync = NoSync.INST;
|
||||
|
||||
@ -1429,10 +1443,12 @@ public final class Main extends JFrame implements ClosingWindowListener.ConfirmS
|
||||
|
||||
@Override
|
||||
public void hasChanged() {
|
||||
modelCreator.addNodeElementsTo(model.nodesToUpdate(), circuitComponent.getHighLighted());
|
||||
if (!realTimeClockRunning)
|
||||
modelCreator.addNodeElementsTo(model.nodesToUpdate(), circuitComponent.getHighLighted());
|
||||
model.fireManualChangeEvent();
|
||||
circuitComponent.repaintNeeded();
|
||||
doStep.setEnabled(model.needsUpdate());
|
||||
if (!realTimeClockRunning)
|
||||
doStep.setEnabled(model.needsUpdate());
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user