/*******************************************************************************
* This file is part of logisim-evolution.
*
* logisim-evolution is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* logisim-evolution is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with logisim-evolution. If not, see <http://www.gnu.org/licenses/>.
*
* Original code by Carl Burch (http://www.cburch.com), 2011.
* Subsequent modifications by :
* + Haute École Spécialisée Bernoise
* http://www.bfh.ch
* + Haute École du paysage, d'ingénierie et d'architecture de Genève
* http://hepia.hesge.ch/
* + Haute École d'Ingénierie et de Gestion du Canton de Vaud
* http://www.heig-vd.ch/
* The project is currently maintained by :
* + REDS Institute - HEIG-VD
* Yverdon-les-Bains, Switzerland
* http://reds.heig-vd.ch
*******************************************************************************/
package com.cburch.logisim.std.hdl;
import java.io.BufferedReader;
import java.io.File;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Scanner;
import javax.swing.JOptionPane;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.cburch.logisim.std.hdl.VhdlSimulator.State;
import com.cburch.logisim.tools.MessageBox;
import com.cburch.logisim.util.FileUtil;
import com.cburch.logisim.util.Softwares;
/**
* The TCL binder is a TCL program creating a socket server. The signals have to
* be written to the binder who will drive the simulation and send back the
* output signals.
* <p/>
* The binder is started when the VHDL simulation is enabled. Once started, it
* writes a ready flag to his stdout that is catched by Logisim to know the
* binder is ready. This way we ensure the socket is started before trying to
* connect.
* <p/>
* To end the binder, we send an "end" flag through the socket and wait for it
* to finish. This causes Logisim to hang if the binder doesn't listen to the
* socker. That can happen when unexpected behavior of the simulation occurs.
*
* @author christian.mueller@heig-vd.ch
*/
class VhdlSimulatorTclBinder {
final static Logger logger = LoggerFactory
.getLogger(VhdlSimulatorTclBinder.class);
private ProcessBuilder builder;
private Process process;
private Boolean running = false;
private VhdlSimulator vhdlSimulator;
public VhdlSimulatorTclBinder(VhdlSimulator vs) {
vhdlSimulator = vs;
List<String> command = new ArrayList<String>();
command.add(FileUtil.correctPath(Softwares.getQuestaPath())
+ Softwares.QUESTA_BIN[Softwares.VSIM]);
command.add("-c");
command.add("-do");
command.add("do ../run.tcl " + vs.getSocketClient().getServerPort());
command.add("-errorfile");
command.add("../questasim_errors.log");
builder = new ProcessBuilder(command);
Map<String, String> env = builder.environment();
env.put("LM_LICENSE_FILE", "1650@eilic01");
builder.directory(new File(VhdlSimulator.SIM_PATH + "comp/"));
/* Redirect error on stdout */
builder.redirectErrorStream(true);
}
public Boolean isRunning() {
return running;
}
public void start() {
try {
process = builder.start();
} catch (IOException e) {
e.printStackTrace();
logger.error("Cannot run TCL binder to Questasim : {}",
e.getMessage());
running = false;
return;
}
/* This thread checks the binder started well, it's run from now */
new Thread(new Runnable() {
@Override
public void run() {
/* Through this we can get the process output */
BufferedReader reader = new BufferedReader(
new InputStreamReader(process.getInputStream()));
String line;
try {
String errorMessage = "You may disable VHDL simulation in the simulation menu if this occurs again\n\n";
/* Here we check that the binder has correctly started */
while ((line = reader.readLine()) != null) {
vhdlSimulator.getProject().getFrame()
.getVhdlSimulatorConsole().append(line + "\n");
errorMessage += "\n" + line;
if (line.contains("TCL_BINDER_RUNNING")) {
running = true;
new Thread(new Runnable() {
public void run() {
Scanner sc = new Scanner(
new InputStreamReader(process
.getInputStream()));
String nextLine;
while (sc.hasNextLine()) {
nextLine = sc.nextLine();
if (nextLine.length() > 0)
vhdlSimulator.getProject()
.getFrame()
.getVhdlSimulatorConsole()
.append(nextLine + "\n");
}
sc.close();
}
}).start();
vhdlSimulator.tclStartCallback();
return;
}
}
MessageBox userInfoBox = new MessageBox(
"Error starting VHDL simulator", errorMessage,
JOptionPane.ERROR_MESSAGE);
userInfoBox.show();
vhdlSimulator.setState(State.ENABLED);
} catch (IOException e) {
e.printStackTrace();
}
}
}).start();
}
public void stop() {
if (!running)
return;
/* We ask the binder to end itself */
vhdlSimulator.getSocketClient().send("end");
/* Wait for the process to end */
/*
* FIXME: this can be a bad idea, it will crash logisim if the binder
* doesn't end
*/
// try {
// process.waitFor();
// } catch (InterruptedException e) {
// e.printStackTrace();
// System.err.println(e.getMessage());
// }
process.destroy();
running = false;
}
}