mirror of
https://github.com/hneemann/Digital.git
synced 2025-09-09 12:56:02 -04:00
added a run command to the cli; closes #1246
This commit is contained in:
parent
b1650bd007
commit
61cdd9db3c
@ -1,6 +1,7 @@
|
||||
Release Notes
|
||||
|
||||
HEAD, planned as v0.31
|
||||
- Added a run command to the cli to run circuit headless
|
||||
- Main open dialog is able to open FSM and Truth Tables
|
||||
- FSM editor highlights the current transition
|
||||
- Adds drivers with inverted output
|
||||
|
@ -20,6 +20,7 @@ public class Main extends Muxer {
|
||||
addCommand(new CommandLineTester.TestCommand());
|
||||
addCommand(new SVGExport());
|
||||
addCommand(new StatsExport());
|
||||
addCommand(new Runner());
|
||||
}
|
||||
|
||||
/**
|
||||
|
100
src/main/java/de/neemann/digital/cli/Runner.java
Normal file
100
src/main/java/de/neemann/digital/cli/Runner.java
Normal file
@ -0,0 +1,100 @@
|
||||
/*
|
||||
* Copyright (c) 2024 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.cli;
|
||||
|
||||
import de.neemann.digital.FileLocator;
|
||||
import de.neemann.digital.cli.cli.Argument;
|
||||
import de.neemann.digital.cli.cli.BasicCommand;
|
||||
import de.neemann.digital.cli.cli.CLIException;
|
||||
import de.neemann.digital.core.Model;
|
||||
import de.neemann.digital.core.ModelEventType;
|
||||
import de.neemann.digital.core.element.ElementAttributes;
|
||||
import de.neemann.digital.core.element.Keys;
|
||||
import de.neemann.digital.core.wiring.Clock;
|
||||
import de.neemann.digital.draw.elements.Circuit;
|
||||
import de.neemann.digital.draw.model.ModelCreator;
|
||||
import de.neemann.digital.draw.model.RealTimeClock;
|
||||
import de.neemann.digital.gui.ProgramMemoryLoader;
|
||||
import de.neemann.digital.lang.Lang;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.ArrayList;
|
||||
import java.util.concurrent.ScheduledThreadPoolExecutor;
|
||||
|
||||
/**
|
||||
* Is used to run a circuit headless
|
||||
*/
|
||||
public class Runner extends BasicCommand {
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger(Runner.class);
|
||||
private final Argument<String> digFile;
|
||||
|
||||
/**
|
||||
* Creates the run command
|
||||
*/
|
||||
public Runner() {
|
||||
super("run");
|
||||
digFile = addArgument(new Argument<>("dig", "", false));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void execute() throws CLIException {
|
||||
try {
|
||||
final CircuitLoader circuitLoader = new CircuitLoader(digFile.get(), false);
|
||||
final Circuit circuit = circuitLoader.getCircuit();
|
||||
|
||||
long time = System.currentTimeMillis();
|
||||
ModelCreator modelCreator = new ModelCreator(circuit, circuitLoader.getLibrary());
|
||||
Model model = modelCreator.createModel(true);
|
||||
|
||||
time = System.currentTimeMillis() - time;
|
||||
LOGGER.debug("model creation: " + time + " ms, " + model.getNodes().size() + " nodes");
|
||||
|
||||
ArrayList<Clock> clocks = model.getClocks();
|
||||
if (clocks.size() == 0)
|
||||
throw new CLIException(Lang.get("cli_run_noClock"), null);
|
||||
|
||||
ScheduledThreadPoolExecutor timerExecutor = new ScheduledThreadPoolExecutor(1);
|
||||
|
||||
int threadRunnerCount = 0;
|
||||
boolean realTimeClockRunning = false;
|
||||
for (Clock c : clocks) {
|
||||
int frequency = c.getFrequency();
|
||||
if (frequency > 0) {
|
||||
final RealTimeClock realTimeClock = new RealTimeClock(model, c, timerExecutor, null);
|
||||
if (realTimeClock.isThreadRunner()) threadRunnerCount++;
|
||||
realTimeClockRunning = true;
|
||||
}
|
||||
}
|
||||
if (threadRunnerCount > 1)
|
||||
throw new CLIException(Lang.get("err_moreThanOneFastClock"), null);
|
||||
|
||||
if (!realTimeClockRunning) {
|
||||
throw new CLIException(Lang.get("cli_run_noClock"), null);
|
||||
}
|
||||
|
||||
ElementAttributes settings = circuit.getAttributes();
|
||||
if (settings.get(Keys.PRELOAD_PROGRAM)) {
|
||||
File romHex = new FileLocator(settings.get(Keys.PROGRAM_TO_PRELOAD))
|
||||
.setBaseFile(new File(digFile.get()))
|
||||
.locate();
|
||||
new ProgramMemoryLoader(romHex, settings.get(Keys.BIG_ENDIAN_SETTING))
|
||||
.preInit(model);
|
||||
}
|
||||
|
||||
model.addObserver(event -> {
|
||||
if (event.getType() == ModelEventType.POSTCLOSED) {
|
||||
timerExecutor.shutdownNow();
|
||||
}
|
||||
}, ModelEventType.POSTCLOSED);
|
||||
|
||||
model.init();
|
||||
} catch (Exception e) {
|
||||
throw new CLIException(Lang.get("cli_errorRunningCircuit"), e);
|
||||
}
|
||||
}
|
||||
}
|
@ -92,7 +92,7 @@ public class RealTimeClock implements ModelStateObserverTyped {
|
||||
|
||||
RealTimeRunner(int delay) {
|
||||
FrequencyCalculator frequencyCalculator;
|
||||
if (frequency > 2000)
|
||||
if (frequency > 2000 && status != null)
|
||||
frequencyCalculator = new FrequencyCalculator(status, frequency);
|
||||
else
|
||||
frequencyCalculator = null;
|
||||
@ -120,10 +120,13 @@ public class RealTimeClock implements ModelStateObserverTyped {
|
||||
ThreadRunner() {
|
||||
thread = new Thread(() -> {
|
||||
LOGGER.debug("thread start");
|
||||
FrequencyCalculator frequencyCalculator = new FrequencyCalculator(status, frequency);
|
||||
FrequencyCalculator frequencyCalculator = null;
|
||||
if (status != null)
|
||||
frequencyCalculator = new FrequencyCalculator(status, frequency);
|
||||
while (!Thread.interrupted()) {
|
||||
model.modify(() -> output.setValue(1 - output.getValue()));
|
||||
frequencyCalculator.calc();
|
||||
if (frequencyCalculator != null)
|
||||
frequencyCalculator.calc();
|
||||
}
|
||||
});
|
||||
thread.setDaemon(true);
|
||||
|
@ -31,9 +31,10 @@ public class ProgramMemoryLoader implements ModelModifier {
|
||||
/**
|
||||
* Creates a new rom modifier
|
||||
*
|
||||
* @param romHex the file to load
|
||||
* @param romHex the file to load
|
||||
* @param bigEndian reads the file in big endian mode
|
||||
*/
|
||||
ProgramMemoryLoader(File romHex, boolean bigEndian) {
|
||||
public ProgramMemoryLoader(File romHex, boolean bigEndian) {
|
||||
this.romHex = romHex;
|
||||
this.bigEndian = bigEndian;
|
||||
}
|
||||
|
@ -1813,6 +1813,11 @@ Sind evtl. die Namen der Variablen nicht eindeutig?</string>
|
||||
</string>
|
||||
<string name="cli_errorCreatingStats">Fehler bei der Erzeugung der CSV Datei!</string>
|
||||
|
||||
<string name="cli_run_noClock">Kein aktivierter Takt in der Schaltung gefunden!</string>
|
||||
<string name="cli_errorRunningCircuit">Fehler beim Starten der Schaltung!</string>
|
||||
<string name="cli_help_run">Start eine Schaltung headless.</string>
|
||||
<string name="cli_help_run_dig">Der Dateiname der Schaltung.</string>
|
||||
|
||||
<string name="menu_window">Fenster</string>
|
||||
<string name="menu_about">Über Digital</string>
|
||||
<string name="menu_analyse">Analyse</string>
|
||||
|
@ -1793,6 +1793,11 @@
|
||||
</string>
|
||||
<string name="cli_errorCreatingStats">Error while creating the stats file!</string>
|
||||
|
||||
<string name="cli_run_noClock">No running clock found in circuit!</string>
|
||||
<string name="cli_errorRunningCircuit">Error running the circuit!</string>
|
||||
<string name="cli_help_run">Runs a circuit headless.</string>
|
||||
<string name="cli_help_run_dig">File name of the circuit.</string>
|
||||
|
||||
<string name="menu_window">Windows</string>
|
||||
<string name="menu_about">About</string>
|
||||
<string name="menu_analyse">Analysis</string>
|
||||
|
Loading…
x
Reference in New Issue
Block a user