ghdl is working

This commit is contained in:
hneemann 2018-03-08 14:39:39 +01:00
parent b89bdc41e4
commit 2a6c3d6ab5
11 changed files with 160 additions and 37 deletions

View File

@ -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(""));
}

View 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);
}

View File

@ -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()));
}

View File

@ -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());
}
}

View File

@ -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());
}
}

View 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();
}
}
}

View File

@ -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

View File

@ -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();
}
}

View File

@ -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>

View File

@ -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>

View File

@ -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;