package com.bfh.logisim.download;
import com.bfh.logisim.designrulecheck.Netlist;
import com.bfh.logisim.fpgaboardeditor.BoardInformation;
import com.bfh.logisim.fpgaboardeditor.FPGAClass;
import com.bfh.logisim.fpgagui.FPGAReport;
import com.bfh.logisim.fpgagui.MappableResourcesContainer;
import com.bfh.logisim.hdlgenerator.FileWriter;
import com.bfh.logisim.hdlgenerator.ToplevelHDLGeneratorFactory;
import com.bfh.logisim.settings.Settings;
import com.bfh.logisim.settings.VendorSoftware;
import com.cburch.logisim.proj.Projects;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JProgressBar;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Rectangle;
import java.io.BufferedReader;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.List;
public class VivadoDownload {
public static boolean Download(String scriptPath, String sandboxPath, FPGAReport myReporter, boolean downloadOnly) {
GridBagConstraints gbc = new GridBagConstraints();
JFrame panel = new JFrame("Vivado Downloading");
panel.setResizable(false);
panel.setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE);
GridBagLayout thisLayout = new GridBagLayout();
panel.setLayout(thisLayout);
// PointerInfo mouseloc = MouseInfo.getPointerInfo();
// Point mlocation = mouseloc.getLocation();
// panel.setLocation(mlocation.x, mlocation.y);
JLabel locText = new JLabel("Generating FPGA files and performing download; this may take a while");
gbc.gridx = 0;
gbc.gridy = 0;
gbc.fill = GridBagConstraints.HORIZONTAL;
panel.add(locText, gbc);
JProgressBar progres = new JProgressBar(0, 3);
progresVal = 0;
progres.setValue(progresVal);
progres.setStringPainted(true);
gbc.gridx = 0;
gbc.gridy = 1;
gbc.fill = GridBagConstraints.HORIZONTAL;
panel.add(progres, gbc);
panel.pack();
panel.setLocation(Projects.getCenteredLoc(panel.getWidth(), panel.getHeight() * 4));
panel.setVisible(true);
Rectangle labelRect = locText.getBounds();
labelRect.x = 0;
labelRect.y = 0;
locText.paintImmediately(labelRect);
VendorSoftware vivadoVendor = Settings.vendors.get(FPGAClass.VendorVivado);
// Create Vivado project
if (!downloadOnly) {
boolean status = executeTclScript(vivadoVendor.getBinaryPath(0),
scriptPath + File.separator + CREATE_PROJECT_TCL,
"Create Vivado project",
sandboxPath, myReporter, locText, progres);
if (!status) {
panel.dispose();
return false;
}
}
// Generate bitstream
if (!downloadOnly) {
boolean status = executeTclScript(vivadoVendor.getBinaryPath(0),
scriptPath + File.separator + GENERATE_BITSTREAM_FILE,
"Generate bitstream",
sandboxPath, myReporter, locText, progres);
if (!status) {
panel.dispose();
return false;
}
boolean bitFileExists = new File(_bitStreamPath).exists();
if (!bitFileExists) {
myReporter.AddFatalError("Could not generate bitfile! Check Console tab for more details.");
panel.dispose();
return false;
}
}
// Download to board
// only if the bitfile exists
boolean bitFileExists = new File(_bitStreamPath).exists();
if (bitFileExists) {
Object[] options = { "Yes, download","No, abort" };
if (JOptionPane.showOptionDialog(
progres,
"Verify that your board is connected and you are ready to download.",
"Ready to download ?", JOptionPane.YES_NO_OPTION,
JOptionPane.WARNING_MESSAGE, null, options, options[0]) != JOptionPane.YES_OPTION) {
myReporter.AddWarning("Download aborted.");
panel.dispose();
return false;
}
boolean status = executeTclScript(vivadoVendor.getBinaryPath(0),
scriptPath + File.separator + LOAD_BITSTEAM_FILE,
"Downloading bitfile",
sandboxPath, myReporter, locText, progres);
panel.dispose();
return status;
} else {
myReporter.AddFatalError("No bitfile found!");
panel.dispose();
return false;
}
}
private static int progresVal = 0;
private static boolean executeTclScript(String binary, String tclScript, String message, String sandboxPath,
FPGAReport myReporter, JLabel locText, JProgressBar progres) {
try {
locText.setText(message);
Rectangle labelRect = locText.getBounds();
labelRect.x = 0;
labelRect.y = 0;
locText.paintImmediately(labelRect);
progres.setValue(progresVal++);
Rectangle progRect = progres.getBounds();
progRect.x = 0;
progRect.y = 0;
progres.paintImmediately(progRect);
List<String> command = new ArrayList<String>();
command.add(binary);
command.add("-mode");
command.add("batch");
command.add("-source");
command.add(tclScript);
ProcessBuilder vivado1 = new ProcessBuilder(command);
vivado1.directory(new File(sandboxPath));
final Process createProject = vivado1.start();
InputStream is = createProject.getInputStream();
InputStreamReader isr = new InputStreamReader(is);
BufferedReader br = new BufferedReader(isr);
String line;
myReporter.ClsScr();
while ((line = br.readLine()) != null) {
myReporter.print(line);
}
createProject.waitFor();
if (createProject.exitValue() != 0) {
myReporter.AddFatalError("Failed to run tcl script, see Console tab for more details");
return false;
}
} catch (IOException e) {
myReporter.AddFatalError("Internal Error during Vivado download");
return false;
} catch (InterruptedException e) {
myReporter.AddFatalError("Internal Error during Vivado download");
return false;
}
return true;
}
public static boolean GenerateScripts(FPGAReport myReporter,
String projectPath, String scriptPath, String xdcPath,
String sandBoxPath, Netlist rootNetlist, MappableResourcesContainer mapInfo,
BoardInformation boardInfo, ArrayList<String> entities,
ArrayList<String> architectures, String HDLType,
boolean writeToFlash) {
// create project files
File createProjectFile = FileWriter.GetFilePointer(scriptPath, CREATE_PROJECT_TCL, myReporter);
File xdcFile = FileWriter.GetFilePointer(xdcPath, XDC_FILE, myReporter);
File generateBitstreamFile = FileWriter.GetFilePointer(scriptPath, GENERATE_BITSTREAM_FILE, myReporter);
File loadBitstreamFile = FileWriter.GetFilePointer(scriptPath, LOAD_BITSTEAM_FILE, myReporter);
if (createProjectFile == null || xdcFile == null || generateBitstreamFile == null || loadBitstreamFile == null) {
createProjectFile = new File(scriptPath + CREATE_PROJECT_TCL);
xdcFile = new File(xdcPath, XDC_FILE);
generateBitstreamFile = new File(scriptPath, GENERATE_BITSTREAM_FILE);
loadBitstreamFile = new File(scriptPath, LOAD_BITSTEAM_FILE);
return createProjectFile.exists() && xdcFile.exists() && generateBitstreamFile.exists() && loadBitstreamFile.exists();
}
String vivadoProjectPath = sandBoxPath + File.separator + VIVADO_PROJECT_NAME;
// fill create project TCL script
ArrayList<String> contents = new ArrayList<String>();
contents.add("create_project " + VIVADO_PROJECT_NAME + " \"" + vivadoProjectPath.replace("\\", "/") + "\"");
contents.add("set_property part " +
boardInfo.fpga.getPart() +
boardInfo.fpga.getPackage() +
boardInfo.fpga.getSpeedGrade() +
" [current_project]");
contents.add("set_property target_language VHDL [current_project]");
// add all entities and architectures
for (String entity : entities) {
contents.add("add_files \"" + entity + "\"");
}
for (String architecture : architectures) {
contents.add("add_files \"" + architecture + "\"");
}
// add xdc constraints
contents.add("add_files -fileset constrs_1 \"" + xdcFile.getAbsolutePath().replace("\\", "/") + "\"");
contents.add("exit");
if (!FileWriter.WriteContents(createProjectFile, contents, myReporter))
return false;
contents.clear();
// fill the UCF file
contents.addAll(mapInfo.GetFPGAPinLocs(FPGAClass.VendorVivado));
if (!FileWriter.WriteContents(xdcFile, contents, myReporter))
return false;
contents.clear();
// generate bitstream
String openProjectPath = vivadoProjectPath + File.separator + VIVADO_PROJECT_NAME + ".xpr";
openProjectPath = openProjectPath.replace("\\", "/");
contents.add("open_project -verbose " + openProjectPath);
contents.add("update_compile_order -fileset sources_1");
contents.add("launch_runs synth_1");
contents.add("wait_on_run synth_1");
contents.add("launch_runs impl_1 -to_step write_bitstream -jobs 8");
contents.add("wait_on_run impl_1");
contents.add("exit");
if (!FileWriter.WriteContents(generateBitstreamFile, contents, myReporter))
return false;
contents.clear();
// load bitstream
String lindex = "[lindex [get_hw_devices] 0]";
contents.add("open_hw");
contents.add("connect_hw_server");
contents.add("open_hw_target");
_bitStreamPath = vivadoProjectPath + File.separator + VIVADO_PROJECT_NAME + ".runs"
+ File.separator + "impl_1" + File.separator + ToplevelHDLGeneratorFactory.FPGAToplevelName + ".bit";
_bitStreamPath = _bitStreamPath.replace("\\", "/");
contents.add("set_property PROGRAM.FILE {" + _bitStreamPath + "} " + lindex);
contents.add("current_hw_device " + lindex);
contents.add("refresh_hw_device -update_hw_probes false " + lindex);
contents.add("program_hw_device " + lindex);
contents.add("exit");
return FileWriter.WriteContents(loadBitstreamFile, contents, myReporter);
}
private static String _bitStreamPath = "";
private final static String CREATE_PROJECT_TCL = "vivadoCreateProject.tcl";
private final static String GENERATE_BITSTREAM_FILE = "vivadoGenerateBitStream.tcl";
private final static String LOAD_BITSTEAM_FILE = "vivadoLoadBitStream.tcl";
private final static String XDC_FILE = "vivadoConstraints.xdc";
private final static String VIVADO_PROJECT_NAME = "vp";
}