mirror of
https://github.com/hneemann/Digital.git
synced 2025-09-19 01:44:44 -04:00
ghdl is working
This commit is contained in:
parent
b89bdc41e4
commit
2a6c3d6ab5
@ -531,10 +531,5 @@ public final class Keys {
|
||||
*/
|
||||
public static final Key.LongString EXTERNAL_CODE
|
||||
= new Key.LongString("Code").setRows(20).setColumns(40);
|
||||
/**
|
||||
* The parameters to be used by the external process
|
||||
*/
|
||||
public static final Key.KeyFile EXTERNAL_EXECUTABLE
|
||||
= new Key.KeyFile("externalExecutable", new File(""));
|
||||
|
||||
}
|
||||
|
@ -11,7 +11,6 @@ import de.neemann.digital.lang.Lang;
|
||||
import de.neemann.gui.ErrorMessage;
|
||||
|
||||
import javax.swing.*;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
@ -38,15 +37,13 @@ public class External extends Node implements Element {
|
||||
.addAttribute(Keys.EXTERNAL_INPUTS)
|
||||
.addAttribute(Keys.EXTERNAL_OUTPUTS)
|
||||
.addAttribute(Keys.EXTERNAL_CODE)
|
||||
.addAttribute(Keys.PROCESS_TYPE)
|
||||
.addAttribute(Keys.EXTERNAL_EXECUTABLE);
|
||||
.addAttribute(Keys.PROCESS_TYPE);
|
||||
|
||||
private final ProcessFactory.Type type;
|
||||
private final PortDefinition ins;
|
||||
private final PortDefinition outs;
|
||||
private final ObservableValues outputs;
|
||||
private final String code;
|
||||
private final File executable;
|
||||
private final String label;
|
||||
private ObservableValues inputs;
|
||||
private ProcessHandler processHandler;
|
||||
@ -64,7 +61,6 @@ public class External extends Node implements Element {
|
||||
label = attr.getCleanLabel();
|
||||
type = attr.get(Keys.PROCESS_TYPE);
|
||||
code = attr.get(Keys.EXTERNAL_CODE);
|
||||
executable = attr.get(Keys.EXTERNAL_EXECUTABLE);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -101,7 +97,7 @@ public class External extends Node implements Element {
|
||||
@Override
|
||||
public void init(Model model) throws NodeException {
|
||||
try {
|
||||
processHandler = ProcessFactory.create(type, label, code, ins, outs, executable);
|
||||
processHandler = ProcessFactory.create(type, label, code, ins, outs);
|
||||
} catch (IOException e) {
|
||||
throw new NodeException(Lang.get("err_errorCreatingProcess"), this, -1, null, e);
|
||||
}
|
||||
|
@ -9,7 +9,6 @@ import de.neemann.digital.core.extern.handler.GHDLProcess;
|
||||
import de.neemann.digital.core.extern.handler.Generic;
|
||||
import de.neemann.digital.lang.Lang;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
@ -43,16 +42,15 @@ public final class ProcessFactory {
|
||||
* @param code the code to use
|
||||
* @param inputs the inputs to use
|
||||
* @param outputs the outputs to use
|
||||
* @param executable the parameters to use
|
||||
* @return the created process handler
|
||||
* @throws IOException IOException
|
||||
*/
|
||||
public static ProcessHandler create(Type type, String label, String code, PortDefinition inputs, PortDefinition outputs, File executable) throws IOException {
|
||||
public static ProcessHandler create(Type type, String label, String code, PortDefinition inputs, PortDefinition outputs) throws IOException {
|
||||
switch (type) {
|
||||
case Generic:
|
||||
return new Generic(executable);
|
||||
return new Generic(code);
|
||||
case GHDL:
|
||||
return new GHDLProcess(executable, label, code, inputs, outputs);
|
||||
return new GHDLProcess(label, code, inputs, outputs);
|
||||
default:
|
||||
throw new IOException(Lang.get("err_processType_N_notFound", type.name()));
|
||||
}
|
||||
|
@ -11,20 +11,28 @@ import java.io.File;
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* Can use GHDL as VHDL simulator
|
||||
* Can use GHDL as VHDL simulator.
|
||||
*/
|
||||
public class GHDLProcess extends VHDLProcess {
|
||||
|
||||
/**
|
||||
* Creates a new instance
|
||||
*
|
||||
* @param executable the executable
|
||||
* @param label the label
|
||||
* @param code the code
|
||||
* @param inputs th inputs to use
|
||||
* @param outputs the outputs to use
|
||||
* @throws IOException IOException
|
||||
*/
|
||||
public GHDLProcess(File executable, String label, String code, PortDefinition inputs, PortDefinition outputs) throws IOException {
|
||||
public GHDLProcess(String label, String code, PortDefinition inputs, PortDefinition outputs) throws IOException {
|
||||
super(label, code, inputs, outputs);
|
||||
|
||||
String ghdl = "ghdl";
|
||||
|
||||
File file = getVHDLFile();
|
||||
ProcessStarter.start(file.getParentFile(), ghdl, "-a", "--ieee=synopsys", file.getName());
|
||||
ProcessStarter.start(file.getParentFile(), ghdl, "-e", "--ieee=synopsys", "stdIOInterface");
|
||||
ProcessBuilder pb = new ProcessBuilder(ghdl, "-r", "--ieee=synopsys", "stdIOInterface").redirectErrorStream(true).directory(file.getParentFile());
|
||||
setProcess(pb.start());
|
||||
}
|
||||
}
|
||||
|
@ -5,7 +5,6 @@
|
||||
*/
|
||||
package de.neemann.digital.core.extern.handler;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
@ -18,8 +17,9 @@ public class Generic extends StdIOProcess {
|
||||
* @param file the name of the application to start
|
||||
* @throws IOException IOException
|
||||
*/
|
||||
public Generic(File file) throws IOException {
|
||||
ProcessBuilder pb = new ProcessBuilder(file.getPath());
|
||||
public Generic(String file) throws IOException {
|
||||
String[] args = file.split(" ");
|
||||
ProcessBuilder pb = new ProcessBuilder(args).redirectErrorStream(true);
|
||||
setProcess(pb.start());
|
||||
}
|
||||
}
|
||||
|
88
src/main/java/de/neemann/digital/core/extern/handler/ProcessStarter.java
vendored
Normal file
88
src/main/java/de/neemann/digital/core/extern/handler/ProcessStarter.java
vendored
Normal file
@ -0,0 +1,88 @@
|
||||
/*
|
||||
* Copyright (c) 2018 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.extern.handler;
|
||||
|
||||
import de.neemann.digital.lang.Lang;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.Arrays;
|
||||
|
||||
/**
|
||||
* Helper to start and wait for a process.
|
||||
*/
|
||||
public final class ProcessStarter {
|
||||
|
||||
private ProcessStarter() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper to start a process.
|
||||
* If result value is not null an exception is thrown.
|
||||
*
|
||||
* @param dir the folder in which the process is started
|
||||
* @param args the argument
|
||||
* @return the console output
|
||||
* @throws IOException IOException
|
||||
*/
|
||||
public static String start(File dir, String... args) throws IOException {
|
||||
ProcessBuilder pb = new ProcessBuilder(args).redirectErrorStream(true).directory(dir);
|
||||
Process p;
|
||||
try {
|
||||
p = pb.start();
|
||||
} catch (IOException e) {
|
||||
throw new IOException(Lang.get("err_couldNotStartProcess_N", Arrays.toString(args)));
|
||||
}
|
||||
ReaderThread rt = new ReaderThread(p.getInputStream());
|
||||
rt.start();
|
||||
try {
|
||||
int exitValue = p.waitFor();
|
||||
rt.join();
|
||||
|
||||
String output = rt.toString();
|
||||
|
||||
if (exitValue != 0)
|
||||
throw new IOException(Lang.get("err_exitValueNotNull_N_O", exitValue, output));
|
||||
|
||||
return output;
|
||||
} catch (InterruptedException e) {
|
||||
throw new IOException(e);
|
||||
}
|
||||
}
|
||||
|
||||
private static final class ReaderThread extends Thread {
|
||||
private final ByteArrayOutputStream baos;
|
||||
private final InputStream in;
|
||||
|
||||
private ReaderThread(InputStream in) {
|
||||
this.in = in;
|
||||
baos = new ByteArrayOutputStream();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
try {
|
||||
byte[] buffer = new byte[4096];
|
||||
int len;
|
||||
while ((len = in.read(buffer)) > 0)
|
||||
baos.write(buffer, 0, len);
|
||||
} finally {
|
||||
in.close();
|
||||
}
|
||||
} catch (IOException e) {
|
||||
// do nothing, simply end the thread
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return baos.toString();
|
||||
}
|
||||
}
|
||||
}
|
@ -11,15 +11,18 @@ import de.neemann.digital.core.extern.ProcessHandler;
|
||||
import de.neemann.digital.lang.Lang;
|
||||
|
||||
import java.io.*;
|
||||
import java.util.LinkedList;
|
||||
|
||||
/**
|
||||
* The generic process description
|
||||
* Communicates with an external process by sending values and receiving results via the stdio.
|
||||
*/
|
||||
public class StdIOProcess implements ProcessHandler {
|
||||
private static final String PREFIX = "Digital:";
|
||||
private static final int MAX_CONSOLE_LINES = 30;
|
||||
private Process process;
|
||||
private BufferedWriter writer;
|
||||
private Thread thread;
|
||||
private LinkedList<String> consoleOut;
|
||||
|
||||
private final Object lock = new Object();
|
||||
private String dataFound;
|
||||
@ -56,11 +59,14 @@ public class StdIOProcess implements ProcessHandler {
|
||||
*/
|
||||
private void setReaderWriter(BufferedReader reader, BufferedWriter writer) {
|
||||
this.writer = writer;
|
||||
|
||||
consoleOut = new LinkedList<>();
|
||||
thread = new Thread(() -> {
|
||||
try {
|
||||
String line;
|
||||
while ((line = reader.readLine()) != null) {
|
||||
consoleOut.add(line);
|
||||
while (consoleOut.size() > MAX_CONSOLE_LINES)
|
||||
consoleOut.removeFirst();
|
||||
if (line.startsWith(PREFIX)) {
|
||||
synchronized (lock) {
|
||||
while (dataFound != null)
|
||||
@ -161,8 +167,12 @@ public class StdIOProcess implements ProcessHandler {
|
||||
}
|
||||
v.set(value, highZ);
|
||||
}
|
||||
} else
|
||||
throw new IOException(Lang.get("err_processTerminatedUnexpected"));
|
||||
} else {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
for (String s : consoleOut)
|
||||
sb.append(s).append("\n");
|
||||
throw new IOException(Lang.get("err_processTerminatedUnexpected_O", sb.toString()));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -9,12 +9,15 @@ import de.neemann.digital.core.extern.Port;
|
||||
import de.neemann.digital.core.extern.PortDefinition;
|
||||
|
||||
import java.io.*;
|
||||
import java.nio.file.Files;
|
||||
|
||||
/**
|
||||
* Creates a VHDL process
|
||||
* Creates a VHDL file which is able to cummunicate via stdio.
|
||||
* The given code is used as VHDL code.
|
||||
*/
|
||||
public class VHDLProcess extends StdIOProcess {
|
||||
private final File file;
|
||||
private final File dir;
|
||||
|
||||
private static class InstanceHolder {
|
||||
private static final String TEMPLATE = loadTemplate();
|
||||
@ -49,14 +52,16 @@ public class VHDLProcess extends StdIOProcess {
|
||||
public VHDLProcess(String label, String code, PortDefinition inputs, PortDefinition outputs) throws IOException {
|
||||
String t = InstanceHolder.TEMPLATE;
|
||||
t = t.replace("%name%", label);
|
||||
t = t.replace("%incount%", Integer.toString(inputs.getBits()));
|
||||
t = t.replace("%outcount%", Integer.toString(outputs.getBits()));
|
||||
t = t.replace("%incount%", Integer.toString(inputs.getBits() - 1));
|
||||
t = t.replace("%outcount%", Integer.toString(outputs.getBits() - 1));
|
||||
t = t.replace("%ports%", createPorts(inputs, outputs));
|
||||
t = t.replace("%signals%", createSignals(inputs, outputs));
|
||||
t = t.replace("%map%", createMap(inputs, outputs));
|
||||
t = t.replace("%inOutMapping%", createInOutMapping(inputs, outputs));
|
||||
|
||||
file = File.createTempFile(label, ".vhdl");
|
||||
dir = Files.createTempDirectory("digital_vhdl_").toFile();
|
||||
|
||||
file = new File(dir, label + ".vhdl");
|
||||
try (Writer w = new FileWriter(file)) {
|
||||
w.write(code);
|
||||
w.write("\n\n\n");
|
||||
@ -67,7 +72,7 @@ public class VHDLProcess extends StdIOProcess {
|
||||
/**
|
||||
* @return the created vhdl file
|
||||
*/
|
||||
public File getFile() {
|
||||
public File getVHDLFile() {
|
||||
return file;
|
||||
}
|
||||
|
||||
@ -145,6 +150,20 @@ public class VHDLProcess extends StdIOProcess {
|
||||
@Override
|
||||
public void close() throws IOException {
|
||||
super.close();
|
||||
//if (file != null) file.delete();
|
||||
if (dir != null)
|
||||
removeFolder(dir);
|
||||
}
|
||||
|
||||
private static void removeFolder(File dir) {
|
||||
File[] list = dir.listFiles();
|
||||
if (list != null) {
|
||||
for (File f : list) {
|
||||
if (f.isDirectory())
|
||||
removeFolder(f);
|
||||
else
|
||||
f.delete();
|
||||
}
|
||||
}
|
||||
dir.delete();
|
||||
}
|
||||
}
|
||||
|
@ -846,9 +846,13 @@ Sind evtl. die Namen der Variablen nicht eindeutig?</string>
|
||||
<string name="err_errorCreatingProcess">Der externe Prozess konnte nicht gestartet werden!</string>
|
||||
<string name="err_timeoutReadingData">Zeitüberschreitung beim Lesen von Daten!</string>
|
||||
<string name="err_notEnoughDataReceived">Es wurden nicht genug Daten empfangen!</string>
|
||||
<string name="err_invalidCharacterReceived_N">Der empfangene Text enthielt ein ungültiges Zeichen: {0}!</string>
|
||||
<string name="err_processTerminatedUnexpected">Der Prozess wurde unerwartet beendet!</string>
|
||||
<string name="err_invalidCharacterReceived_N">Der Prozess sendete ein ungültiges Zeichen: {0}!</string>
|
||||
<string name="err_processTerminatedUnexpected_O">Der Prozess wurde unerwartet beendet!
|
||||
{0}</string>
|
||||
<string name="err_couldNotTerminateProcess">Der Prozess konnte nicht beendet werden!</string>
|
||||
<string name="err_couldNotStartProcess_N">Prozess konnte nicht gestartet werden: {0}</string>
|
||||
<string name="err_exitValueNotNull_N_O">Rückgabewert war nicht 0 sondern {0}:
|
||||
{1}</string>
|
||||
|
||||
<string name="key_AddrBits">Adress-Bits</string><!-- ROM, RAMDualPort, RAMSinglePort, RAMSinglePortSel, EEPROM -->
|
||||
<string name="key_AddrBits_tt">Anzahl der Adress-Bits, die verwendet werden.</string>
|
||||
|
@ -842,8 +842,13 @@ The names of the variables may not be unique.</string>
|
||||
<string name="err_timeoutReadingData">Timeout reading data from external process!</string>
|
||||
<string name="err_notEnoughDataReceived">Not enough data received!</string>
|
||||
<string name="err_invalidCharacterReceived_N">The received text contains an invalid character: {0}!</string>
|
||||
<string name="err_processTerminatedUnexpected">The process has terminated unexpected!</string>
|
||||
<string name="err_processTerminatedUnexpected_O">The process has terminated unexpected!
|
||||
{0}</string>
|
||||
<string name="err_couldNotTerminateProcess">Could not terminate the process!</string>
|
||||
<string name="err_couldNotStartProcess_N">Could not start process: {0}</string>
|
||||
<string name="err_exitValueNotNull_N_O">Result value was not 0 but {0}:
|
||||
{1}</string>
|
||||
|
||||
|
||||
<string name="key_AddrBits">Address Bits</string><!-- ROM, RAMDualPort, RAMSinglePort, RAMSinglePortSel, EEPROM -->
|
||||
<string name="key_AddrBits_tt">Number of address bits used.</string>
|
||||
|
@ -27,10 +27,10 @@ architecture top_sim_a of stdIOInterface is
|
||||
variable result : string (1 to slv'length);
|
||||
variable r : integer;
|
||||
begin
|
||||
r := 1;
|
||||
r := slv'length;
|
||||
for i in slv'range loop
|
||||
result(r) := chr(slv(i));
|
||||
r := r + 1;
|
||||
r := r - 1;
|
||||
end loop;
|
||||
return result;
|
||||
end str;
|
||||
|
Loading…
x
Reference in New Issue
Block a user