/*******************************************************************************
* 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.bfh.logisim.download;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Rectangle;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.List;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JProgressBar;
import com.bfh.logisim.designrulecheck.Netlist;
import com.bfh.logisim.fpgaboardeditor.BoardInformation;
import com.bfh.logisim.fpgaboardeditor.FPGAClass;
import com.bfh.logisim.fpgaboardeditor.IoStandards;
import com.bfh.logisim.fpgaboardeditor.PullBehaviors;
import com.bfh.logisim.fpgagui.FPGAReport;
import com.bfh.logisim.fpgagui.MappableResourcesContainer;
import com.bfh.logisim.hdlgenerator.FileWriter;
import com.bfh.logisim.hdlgenerator.TickComponentHDLGeneratorFactory;
import com.bfh.logisim.hdlgenerator.ToplevelHDLGeneratorFactory;
import com.bfh.logisim.settings.Settings;
import com.bfh.logisim.settings.VendorSoftware;
import com.cburch.logisim.proj.Projects;
public class XilinxDownload {
public static boolean Download(Settings MySettings,
BoardInformation BoardInfo, String scriptPath, String UcfPath,
String ProjectPath, String SandboxPath, FPGAReport MyReporter) {
VendorSoftware xilinxVendor = Settings.vendors.get(FPGAClass.VendorXilinx);
boolean IsCPLD = BoardInfo.fpga.getPart().toUpperCase()
.startsWith("XC2C")
|| BoardInfo.fpga.getPart().toUpperCase().startsWith("XA2C")
|| BoardInfo.fpga.getPart().toUpperCase().startsWith("XCR3")
|| BoardInfo.fpga.getPart().toUpperCase().startsWith("XC9500")
|| BoardInfo.fpga.getPart().toUpperCase().startsWith("XA9500");
String BitfileExt = (IsCPLD) ? "jed" : "bit";
boolean BitFileExists = new File(SandboxPath
+ ToplevelHDLGeneratorFactory.FPGAToplevelName + "."
+ BitfileExt).exists();
GridBagConstraints gbc = new GridBagConstraints();
JFrame panel = new JFrame("Xilinx 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, xilinxVendor.getBinaries().length);
progres.setValue(0);
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);
List<String> command = new ArrayList<String>();
if (!BitFileExists) {
try {
LocText.setText("Synthesizing Project");
labelRect = LocText.getBounds();
labelRect.x = 0;
labelRect.y = 0;
LocText.paintImmediately(labelRect);
Rectangle ProgRect = progres.getBounds();
ProgRect.x = 0;
ProgRect.y = 0;
progres.paintImmediately(ProgRect);
command.clear();
command.add(xilinxVendor.getBinaryPath(0));
command.add("-ifn");
command.add(scriptPath.replace(ProjectPath, "../")
+ File.separator + script_file);
command.add("-ofn");
command.add("logisim.log");
ProcessBuilder Xilinx = new ProcessBuilder(command);
Xilinx.directory(new File(SandboxPath));
final Process CreateProject = Xilinx.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 Synthesize Xilinx project; cannot download");
panel.dispose();
return false;
}
} catch (IOException e) {
MyReporter
.AddFatalError("Internal Error during Xilinx download");
panel.dispose();
return false;
} catch (InterruptedException e) {
MyReporter
.AddFatalError("Internal Error during Xilinx download");
panel.dispose();
return false;
}
}
if (!BitFileExists) {
try {
LocText.setText("Adding contraints");
labelRect = LocText.getBounds();
labelRect.x = 0;
labelRect.y = 0;
LocText.paintImmediately(labelRect);
progres.setValue(1);
Rectangle ProgRect = progres.getBounds();
ProgRect.x = 0;
ProgRect.y = 0;
progres.paintImmediately(ProgRect);
command.clear();
command.add(xilinxVendor.getBinaryPath(1));
command.add("-intstyle");
command.add("ise");
command.add("-uc");
command.add(UcfPath.replace(ProjectPath, "../")
+ File.separator + ucf_file);
command.add("logisim.ngc");
command.add("logisim.ngd");
ProcessBuilder Xilinx = new ProcessBuilder(command);
Xilinx.directory(new File(SandboxPath));
final Process CreateProject = Xilinx.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 add Xilinx constraints; cannot download");
panel.dispose();
return false;
}
} catch (IOException e) {
MyReporter
.AddFatalError("Internal Error during Xilinx download");
panel.dispose();
return false;
} catch (InterruptedException e) {
MyReporter
.AddFatalError("Internal Error during Xilinx download");
panel.dispose();
return false;
}
}
if (!BitFileExists && !IsCPLD) {
try {
LocText.setText("Mapping Design");
labelRect = LocText.getBounds();
labelRect.x = 0;
labelRect.y = 0;
LocText.paintImmediately(labelRect);
progres.setValue(2);
Rectangle ProgRect = progres.getBounds();
ProgRect.x = 0;
ProgRect.y = 0;
progres.paintImmediately(ProgRect);
command.clear();
command.add(xilinxVendor.getBinaryPath(2));
command.add("-intstyle");
command.add("ise");
command.add("-o");
command.add("logisim_map");
command.add("logisim.ngd");
ProcessBuilder Xilinx = new ProcessBuilder(command);
Xilinx.directory(new File(SandboxPath));
final Process CreateProject = Xilinx.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 map Xilinx design; cannot download");
panel.dispose();
return false;
}
} catch (IOException e) {
MyReporter
.AddFatalError("Internal Error during Xilinx download");
panel.dispose();
return false;
} catch (InterruptedException e) {
MyReporter
.AddFatalError("Internal Error during Xilinx download");
panel.dispose();
return false;
}
}
if (!BitFileExists) {
try {
LocText.setText("Place and routing Design");
labelRect = LocText.getBounds();
labelRect.x = 0;
labelRect.y = 0;
LocText.paintImmediately(labelRect);
progres.setValue(3);
Rectangle ProgRect = progres.getBounds();
ProgRect.x = 0;
ProgRect.y = 0;
progres.paintImmediately(ProgRect);
command.clear();
if (!IsCPLD) {
command.add(xilinxVendor.getBinaryPath(3));
command.add("-w");
command.add("-intstyle");
command.add("ise");
command.add("-ol");
command.add("high");
command.add("logisim_map");
command.add("logisim_par");
command.add("logisim_map.pcf");
} else {
command.add(xilinxVendor.getBinaryPath(6));
command.add("-p");
command.add(BoardInfo.fpga.getPart().toUpperCase() + "-"
+ BoardInfo.fpga.getSpeedGrade() + "-"
+ BoardInfo.fpga.getPackage().toUpperCase());
command.add("-intstyle");
command.add("ise");
/* TODO: do correct termination type */
command.add("-terminate");
if (BoardInfo.fpga.getUnusedPinsBehavior() == PullBehaviors.PullUp) {
command.add("pullup");
} else if (BoardInfo.fpga.getUnusedPinsBehavior() == PullBehaviors.PullDown) {
command.add("pulldown");
} else {
command.add("float");
}
command.add("-loc");
command.add("on");
command.add("-log");
command.add("logisim_cpldfit.log");
command.add("logisim.ngd");
}
ProcessBuilder Xilinx = new ProcessBuilder(command);
Xilinx.directory(new File(SandboxPath));
final Process CreateProject = Xilinx.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 P&R Xilinx design; cannot download");
panel.dispose();
return false;
}
} catch (IOException e) {
MyReporter
.AddFatalError("Internal Error during Xilinx download");
panel.dispose();
return false;
} catch (InterruptedException e) {
MyReporter
.AddFatalError("Internal Error during Xilinx download");
panel.dispose();
return false;
}
}
if (!BitFileExists) {
try {
LocText.setText("Generating Bitfile");
labelRect = LocText.getBounds();
labelRect.x = 0;
labelRect.y = 0;
LocText.paintImmediately(labelRect);
progres.setValue(4);
Rectangle ProgRect = progres.getBounds();
ProgRect.x = 0;
ProgRect.y = 0;
progres.paintImmediately(ProgRect);
command.clear();
if (!IsCPLD) {
command.add(xilinxVendor.getBinaryPath(4));
command.add("-w");
if (BoardInfo.fpga.getUnusedPinsBehavior() == PullBehaviors.PullUp) {
command.add("-g");
command.add("UnusedPin:PULLUP");
}
if (BoardInfo.fpga.getUnusedPinsBehavior() == PullBehaviors.PullDown) {
command.add("-g");
command.add("UnusedPin:PULLDOWN");
}
command.add("-g");
command.add("StartupClk:CCLK");
command.add("logisim_par");
command.add(ToplevelHDLGeneratorFactory.FPGAToplevelName
+ ".bit");
} else {
command.add(xilinxVendor.getBinaryPath(7));
command.add("-i");
command.add("logisim.vm6");
}
ProcessBuilder Xilinx = new ProcessBuilder(command);
Xilinx.directory(new File(SandboxPath));
final Process CreateProject = Xilinx.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 generate bitfile; cannot download");
panel.dispose();
return false;
}
} catch (IOException e) {
MyReporter
.AddFatalError("Internal Error during Xilinx download");
panel.dispose();
return false;
} catch (InterruptedException e) {
MyReporter
.AddFatalError("Internal Error during Xilinx download");
panel.dispose();
return false;
}
}
try {
LocText.setText("Downloading Bitfile");
labelRect = LocText.getBounds();
labelRect.x = 0;
labelRect.y = 0;
LocText.paintImmediately(labelRect);
progres.setValue(5);
Rectangle ProgRect = progres.getBounds();
ProgRect.x = 0;
ProgRect.y = 0;
progres.paintImmediately(ProgRect);
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;
}
/* Until here update of status window */
if (!BoardInfo.fpga.USBTMCDownloadRequired()) {
command.clear();
command.add(xilinxVendor.getBinaryPath(5));
command.add("-batch");
command.add(scriptPath.replace(ProjectPath, "../")
+ File.separator + download_file);
ProcessBuilder Xilinx = new ProcessBuilder(command);
Xilinx.directory(new File(SandboxPath));
final Process CreateProject = Xilinx.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 in downloading");
panel.dispose();
return false;
}
/* Until here is the standard download with programmer */
} else {
MyReporter.ClsScr();
/* Here we do the USBTMC Download */
boolean usbtmcdevice = new File("/dev/usbtmc0").exists();
if (!usbtmcdevice) {
MyReporter.AddFatalError("Could not find usbtmc device");
panel.dispose();
return false;
}
File bitfile = new File(SandboxPath
+ ToplevelHDLGeneratorFactory.FPGAToplevelName + "."
+ BitfileExt);
byte[] bitfile_buffer = new byte[BUFFER_SIZE];
int bitfile_buffer_size;
BufferedInputStream bitfile_in = new BufferedInputStream(
new FileInputStream(bitfile));
File usbtmc = new File("/dev/usbtmc0");
BufferedOutputStream usbtmc_out = new BufferedOutputStream(
new FileOutputStream(usbtmc));
usbtmc_out.write("FPGA ".getBytes());
bitfile_buffer_size = bitfile_in.read(bitfile_buffer, 0,
BUFFER_SIZE);
while (bitfile_buffer_size > 0) {
usbtmc_out.write(bitfile_buffer, 0, bitfile_buffer_size);
bitfile_buffer_size = bitfile_in.read(bitfile_buffer, 0,
BUFFER_SIZE);
}
usbtmc_out.close();
bitfile_in.close();
}
} catch (IOException e) {
MyReporter.AddFatalError("Internal Error during Xilinx download");
panel.dispose();
return false;
} catch (InterruptedException e) {
MyReporter.AddFatalError("Internal Error during Xilinx download");
panel.dispose();
return false;
}
panel.dispose();
return true;
}
public static boolean GenerateISEScripts(FPGAReport MyReporter,
String ProjectPath, String ScriptPath, String UcfPath,
Netlist RootNetlist, MappableResourcesContainer MapInfo,
BoardInformation BoardInfo, ArrayList<String> Entities,
ArrayList<String> Architectures, String HDLType,
boolean writeToFlash) {
boolean IsCPLD = BoardInfo.fpga.getPart().toUpperCase()
.startsWith("XC2C")
|| BoardInfo.fpga.getPart().toUpperCase().startsWith("XA2C")
|| BoardInfo.fpga.getPart().toUpperCase().startsWith("XCR3")
|| BoardInfo.fpga.getPart().toUpperCase().startsWith("XC9500")
|| BoardInfo.fpga.getPart().toUpperCase().startsWith("XA9500");
String JTAGPos = String.valueOf(BoardInfo.fpga.getFpgaJTAGChainPosition());
String BitfileExt = (IsCPLD) ? "jed" : "bit";
File ScriptFile = FileWriter.GetFilePointer(ScriptPath, script_file,
MyReporter);
File VhdlListFile = FileWriter.GetFilePointer(ScriptPath,
vhdl_list_file, MyReporter);
File UcfFile = FileWriter.GetFilePointer(UcfPath, ucf_file, MyReporter);
File DownloadFile = FileWriter.GetFilePointer(ScriptPath,
download_file, MyReporter);
if (ScriptFile == null || VhdlListFile == null || UcfFile == null
|| DownloadFile == null) {
ScriptFile = new File(ScriptPath + script_file);
VhdlListFile = new File(ScriptPath + vhdl_list_file);
UcfFile = new File(UcfPath + ucf_file);
DownloadFile = new File(ScriptPath + download_file);
return ScriptFile.exists() && VhdlListFile.exists()
&& UcfFile.exists() && DownloadFile.exists();
}
ArrayList<String> Contents = new ArrayList<String>();
for (int i = 0; i < Entities.size(); i++) {
Contents.add(HDLType.toUpperCase() + " work \"" + Entities.get(i)
+ "\"");
}
for (int i = 0; i < Architectures.size(); i++) {
Contents.add(HDLType.toUpperCase() + " work \""
+ Architectures.get(i) + "\"");
}
if (!FileWriter.WriteContents(VhdlListFile, Contents, MyReporter))
return false;
Contents.clear();
Contents.add("run -top " + ToplevelHDLGeneratorFactory.FPGAToplevelName
+ " -ofn logisim.ngc -ofmt NGC -ifn "
+ ScriptPath.replace(ProjectPath, "../") + vhdl_list_file
+ " -ifmt mixed -p " + GetFPGADeviceString(BoardInfo));
if (!FileWriter.WriteContents(ScriptFile, Contents, MyReporter))
return false;
Contents.clear();
Contents.add("setmode -bscan");
if (writeToFlash && BoardInfo.fpga.isFlashDefined()) {
if (BoardInfo.fpga.getFlashName() == null) {
MyReporter.AddFatalError("Unable to find the flash on " + BoardInfo.getBoardName());
}
String FlashPos = String.valueOf(BoardInfo.fpga.getFlashJTAGChainPosition());
String McsFile = ScriptPath + File.separator + mcs_file;
Contents.add("setmode -pff");
Contents.add("setSubMode -pffserial");
Contents.add("addPromDevice -p " + JTAGPos + " -size 0 -name " + BoardInfo.fpga.getFlashName());
Contents.add("addDesign -version 0 -name \"0\"");
Contents.add("addDeviceChain -index 0");
Contents.add("addDevice -p " + JTAGPos + " -file " + ToplevelHDLGeneratorFactory.FPGAToplevelName + "." + BitfileExt);
Contents.add("generate -format mcs -fillvalue FF -output " + McsFile);
Contents.add("setMode -bs");
Contents.add("setCable -port auto");
Contents.add("identify");
Contents.add("assignFile -p " + FlashPos + " -file " + McsFile);
Contents.add("program -p " + FlashPos + " -e -v");
} else {
Contents.add("setcable -p auto");
Contents.add("identify");
if (!IsCPLD) {
Contents.add("assignFile -p " + JTAGPos + " -file "
+ ToplevelHDLGeneratorFactory.FPGAToplevelName + "."
+ BitfileExt);
Contents.add("program -p " + JTAGPos + " -onlyFpga");
} else {
Contents.add("assignFile -p " + JTAGPos + " -file logisim."
+ BitfileExt);
Contents.add("program -p " + JTAGPos + " -e");
}
}
Contents.add("quit");
if (!FileWriter.WriteContents(DownloadFile, Contents, MyReporter))
return false;
Contents.clear();
if (RootNetlist.NumberOfClockTrees() > 0) {
Contents.add("NET \"" + TickComponentHDLGeneratorFactory.FPGAClock
+ "\" " + GetXilinxClockPin(BoardInfo) + " ;");
Contents.add("NET \"" + TickComponentHDLGeneratorFactory.FPGAClock
+ "\" TNM_NET = \""
+ TickComponentHDLGeneratorFactory.FPGAClock + "\" ;");
Contents.add("TIMESPEC \"TS_"
+ TickComponentHDLGeneratorFactory.FPGAClock
+ "\" = PERIOD \""
+ TickComponentHDLGeneratorFactory.FPGAClock + "\" "
+ GetClockFrequencyString(BoardInfo) + " HIGH 50 % ;");
Contents.add("");
}
Contents.addAll(MapInfo.GetFPGAPinLocs(FPGAClass.VendorXilinx));
return FileWriter.WriteContents(UcfFile, Contents, MyReporter);
}
private static String GetClockFrequencyString(BoardInformation CurrentBoard) {
long clkfreq = CurrentBoard.fpga.getClockFrequency();
if (clkfreq % 1000000 == 0) {
clkfreq /= 1000000;
return Long.toString(clkfreq) + " MHz ";
} else if (clkfreq % 1000 == 0) {
clkfreq /= 1000;
return Long.toString(clkfreq) + " kHz ";
}
return Long.toString(clkfreq);
}
private static String GetFPGADeviceString(BoardInformation CurrentBoard) {
StringBuffer result = new StringBuffer();
result.append(CurrentBoard.fpga.getPart());
result.append("-");
result.append(CurrentBoard.fpga.getPackage());
result.append("-");
result.append(CurrentBoard.fpga.getSpeedGrade());
return result.toString();
}
private static String GetXilinxClockPin(BoardInformation CurrentBoard) {
StringBuffer result = new StringBuffer();
result.append("LOC = \"" + CurrentBoard.fpga.getClockPinLocation()
+ "\"");
if (CurrentBoard.fpga.getClockPull() == PullBehaviors.PullUp) {
result.append(" | PULLUP");
}
if (CurrentBoard.fpga.getClockPull() == PullBehaviors.PullDown) {
result.append(" | PULLDOWN");
}
if (CurrentBoard.fpga.getClockStandard() != IoStandards.DefaulStandard
&& CurrentBoard.fpga.getClockStandard() != IoStandards.Unknown) {
result.append(" | IOSTANDARD = "
+ IoStandards.Behavior_strings[CurrentBoard.fpga
.getClockStandard()]);
}
return result.toString();
}
private final static String vhdl_list_file = "XilinxVHDLList.prj";
private final static String script_file = "XilinxScript.cmd";
private final static String ucf_file = "XilinxConstraints.ucf";
private final static String download_file = "XilinxDownload";
private final static String mcs_file = "XilinxProm.mcs";
private final static Integer BUFFER_SIZE = 16 * 1024;
}