/******************************************************************************* * 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.settings; import java.io.File; import java.util.ArrayList; import java.util.Collection; import java.util.HashMap; import java.util.Map; import javax.swing.JOptionPane; import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; import javax.xml.parsers.ParserConfigurationException; import javax.xml.transform.OutputKeys; import javax.xml.transform.Result; import javax.xml.transform.Source; import javax.xml.transform.Transformer; import javax.xml.transform.TransformerFactory; import javax.xml.transform.dom.DOMSource; import javax.xml.transform.stream.StreamResult; import com.bfh.logisim.fpgaboardeditor.FPGAClass; import org.w3c.dom.Attr; import org.w3c.dom.Document; import org.w3c.dom.Element; import org.w3c.dom.NamedNodeMap; import org.w3c.dom.Node; import org.w3c.dom.NodeList; public class Settings { private static String WorkSpace = "WorkSpace"; private static String DirectoryName = "WorkPath"; private static String XilinxName = "XilinxToolsPath"; private static String AlteraName = "AlteraToolsPath"; private static String VivadoName = "VivadoToolsPath"; private static String HdlName = "GenerateHDLOnly"; private static String HdlTypeName = "HDLTypeToGenerate"; public static String Unknown = "Unknown"; public static String VHDL = "VHDL"; public static String VERILOG = "Verilog"; private static String Boards = "FPGABoards"; private static String SelectedBoard = "SelectedBoard"; private static String ExternalBoard = "ExternalBoardFile"; private String HomePath; private String SettingsFileName = ".LogisimFPGASettings"; private Document SettingsDocument; boolean modified = false; private BoardList KnownBoards = new BoardList(); public static final Map<Character, VendorSoftware> vendors = new HashMap<>(); /* big TODO: add language support */ public Settings() { String[] alteraBin = load(FPGAClass.VendorAltera); VendorSoftware altera = new VendorSoftware(FPGAClass.VendorAltera, AlteraName, alteraBin); vendors.put(FPGAClass.VendorAltera, altera); String[] iseBin = load(FPGAClass.VendorXilinx); VendorSoftware ise = new VendorSoftware(FPGAClass.VendorXilinx, XilinxName, iseBin); vendors.put(FPGAClass.VendorXilinx, ise); String[] vivadoBin = load(FPGAClass.VendorVivado); VendorSoftware vivado = new VendorSoftware(FPGAClass.VendorVivado, VivadoName, vivadoBin); vendors.put(FPGAClass.VendorVivado, vivado); HomePath = System.getProperty("user.home"); if (!HomePath.endsWith(File.separator)) HomePath += File.separator; File SettingsFile = new File(HomePath + SettingsFileName + ".xml"); if (SettingsFile.exists()) { try { // Create instance of DocumentBuilderFactory DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); // Get the DocumentBuilder DocumentBuilder parser = factory.newDocumentBuilder(); // Create blank DOM Document SettingsDocument = parser.parse(SettingsFile); } catch (Exception e) { JOptionPane.showMessageDialog(null, "Fatal Error: Cannot read FPGA settings file: " + SettingsFile.getPath()); System.exit(-1); } NodeList SettingsList = SettingsDocument.getElementsByTagName(Boards); if (SettingsList.getLength() != 1) { return; } Node ThisWorkspace = SettingsList.item(0); NamedNodeMap WorkspaceParameters = ThisWorkspace.getAttributes(); for (int i = 0; i < WorkspaceParameters.getLength(); i++) { if (WorkspaceParameters.item(i).getNodeName().contains(ExternalBoard)) { File TestFile = new File(WorkspaceParameters.item(i).getNodeValue()); if (TestFile.exists()) KnownBoards.AddExternalBoard(WorkspaceParameters.item(i).getNodeValue()); } } } if (!SettingsComplete()) { if (!WriteXml(SettingsFile)) { JOptionPane.showMessageDialog(null, "Fatal Error: Cannot write FPGA settings file: " + SettingsFile.getPath()); System.exit(-1); } } } private static String[] load(char vendor) { ArrayList<String> progs = new ArrayList<>(); String windowsExtension = ".exe"; if (vendor == FPGAClass.VendorAltera) { progs.add("quartus_sh"); progs.add("quartus_pgm"); progs.add("quartus_map"); } else if (vendor == FPGAClass.VendorXilinx) { progs.add("xst"); progs.add("ngdbuild"); progs.add("map"); progs.add("par"); progs.add("bitgen"); progs.add("impact"); progs.add("cpldfit"); progs.add("hprep6"); } else if (vendor == FPGAClass.VendorVivado) { progs.add("vivado"); windowsExtension = ".bat"; } String[] progsArray = progs.toArray(new String[0]); String osname = System.getProperty("os.name"); if (osname == null) throw new IllegalArgumentException("no os.name"); else { if (osname.toLowerCase().contains("windows")) { for (int i=0; i<progsArray.length; i++) { progsArray[i] += windowsExtension; } } } return progsArray; } private boolean toolFound(VendorSoftware vendor, String path) { for (int i = 0; i < vendor.getBinaries().length; i++) { File test = new File(CorrectPath(path) + vendor.getBinaries()[i]); if (!test.exists()) return false; } return true; } private String CorrectPath(String path) { if (path.endsWith(File.separator)) return path; else return path + File.separator; } public Collection<String> GetBoardNames() { return KnownBoards.GetBoardNames(); } public boolean GetHDLOnly() { NodeList SettingsList = SettingsDocument .getElementsByTagName(WorkSpace); if (SettingsList.getLength() != 1) { return true; } Node ThisWorkspace = SettingsList.item(0); NamedNodeMap WorkspaceParameters = ThisWorkspace.getAttributes(); for (int i = 0; i < WorkspaceParameters.getLength(); i++) { if (WorkspaceParameters.item(i).getNodeName().equals(HdlName)) return WorkspaceParameters.item(i).getNodeValue() .equals(Boolean.TRUE.toString()); } /* The attribute does not exists so add it */ Attr hdl = SettingsDocument.createAttribute(HdlName); hdl.setNodeValue(Boolean.TRUE.toString()); Element workspace = (Element) SettingsList.item(0); workspace.setAttributeNode(hdl); modified = true; return true; } public String GetHDLType() { NodeList SettingsList = SettingsDocument .getElementsByTagName(WorkSpace); if (SettingsList.getLength() != 1) { return VHDL; } Node ThisWorkspace = SettingsList.item(0); NamedNodeMap WorkspaceParameters = ThisWorkspace.getAttributes(); for (int i = 0; i < WorkspaceParameters.getLength(); i++) { if (WorkspaceParameters.item(i).getNodeName().equals(HdlTypeName)) { if (!WorkspaceParameters.item(i).getNodeValue().equals(VHDL) && !WorkspaceParameters.item(i).getNodeValue() .equals(VERILOG)) { WorkspaceParameters.item(i).setNodeValue(VHDL); modified = true; } return WorkspaceParameters.item(i).getNodeValue(); } } /* The attribute does not exists so add it */ Attr hdl = SettingsDocument.createAttribute(HdlTypeName); hdl.setNodeValue(VHDL); Element workspace = (Element) SettingsList.item(0); workspace.setAttributeNode(hdl); modified = true; return VHDL; } public String GetSelectedBoard() { NodeList SettingsList = SettingsDocument.getElementsByTagName(Boards); if (SettingsList.getLength() != 1) { return null; } Node ThisWorkspace = SettingsList.item(0); NamedNodeMap WorkspaceParameters = ThisWorkspace.getAttributes(); for (int i = 0; i < WorkspaceParameters.getLength(); i++) { if (WorkspaceParameters.item(i).getNodeName().equals(SelectedBoard)) { if (!KnownBoards.BoardInCollection(WorkspaceParameters.item(i) .getNodeValue())) { WorkspaceParameters.item(i) .setNodeValue( KnownBoards.GetBoardNames().toArray()[0] .toString()); modified = true; } return WorkspaceParameters.item(i).getNodeValue(); } } /* The attribute does not exists so add it */ Attr selboard = SettingsDocument.createAttribute(SelectedBoard); selboard.setNodeValue(KnownBoards.GetBoardNames().toArray()[0] .toString()); Element workspace = (Element) SettingsList.item(0); workspace.setAttributeNode(selboard); modified = true; return KnownBoards.GetBoardNames().toArray()[0].toString(); } public String GetSelectedBoardFileName() { String SelectedBoardName = GetSelectedBoard(); return KnownBoards.GetBoardFilePath(SelectedBoardName); } public String GetWorkspacePath() { NodeList SettingsList = SettingsDocument .getElementsByTagName(WorkSpace); if (SettingsList.getLength() != 1) { return HomePath; } Node ThisWorkspace = SettingsList.item(0); NamedNodeMap WorkspaceParameters = ThisWorkspace.getAttributes(); for (int i = 0; i < WorkspaceParameters.getLength(); i++) { if (WorkspaceParameters.item(i).getNodeName().equals(DirectoryName)) return WorkspaceParameters.item(i).getNodeValue(); } return HomePath; } private void loadToolPath(VendorSoftware vendor) { NodeList SettingsList = SettingsDocument.getElementsByTagName(WorkSpace); if (SettingsList.getLength() != 1) { return; } Node ThisWorkspace = SettingsList.item(0); NamedNodeMap WorkspaceParameters = ThisWorkspace.getAttributes(); for (int i = 0; i < WorkspaceParameters.getLength(); i++) { if (WorkspaceParameters.item(i).getNodeName().equals(vendor.getName())) { if (toolFound(vendor, WorkspaceParameters.item(i).getNodeValue())) { vendor.setToolPath(WorkspaceParameters.item(i).getNodeValue()); return; } else { WorkspaceParameters.item(i).setNodeValue("Unknown"); vendor.setToolPath("Unknown"); modified = true; return; } } } /* The attribute does not exists so add it */ Attr attr = SettingsDocument.createAttribute(vendor.getName()); attr.setNodeValue(Unknown); Element workspace = (Element) SettingsList.item(0); workspace.setAttributeNode(attr); modified = true; } public boolean SetHdlOnly(boolean only) { NodeList SettingsList = SettingsDocument .getElementsByTagName(WorkSpace); if (SettingsList.getLength() != 1) { return false; } Node ThisWorkspace = SettingsList.item(0); NamedNodeMap WorkspaceParameters = ThisWorkspace.getAttributes(); for (int i = 0; i < WorkspaceParameters.getLength(); i++) { if (WorkspaceParameters.item(i).getNodeName().equals(HdlName)) { WorkspaceParameters.item(i) .setNodeValue(Boolean.toString(only)); modified = true; return true; } } return false; } public boolean SetHDLType(String hdl) { NodeList SettingsList = SettingsDocument .getElementsByTagName(WorkSpace); if (SettingsList.getLength() != 1) { return false; } if (!hdl.equals(VHDL) && !hdl.equals(VERILOG)) return false; Node ThisWorkspace = SettingsList.item(0); NamedNodeMap WorkspaceParameters = ThisWorkspace.getAttributes(); for (int i = 0; i < WorkspaceParameters.getLength(); i++) { if (WorkspaceParameters.item(i).getNodeName().equals(HdlTypeName)) { WorkspaceParameters.item(i).setNodeValue(hdl); modified = true; return true; } } return false; } public boolean SetSelectedBoard(String BoardName) { NodeList SettingsList = SettingsDocument.getElementsByTagName(Boards); if (SettingsList.getLength() != 1) { return false; } if (!KnownBoards.BoardInCollection(BoardName)) return false; if (GetSelectedBoard().equals(BoardName)) return true; Node ThisWorkspace = SettingsList.item(0); NamedNodeMap WorkspaceParameters = ThisWorkspace.getAttributes(); for (int i = 0; i < WorkspaceParameters.getLength(); i++) { if (WorkspaceParameters.item(i).getNodeName().equals(SelectedBoard)) { WorkspaceParameters.item(i).setNodeValue(BoardName); modified = true; return true; } } return false; } private boolean SettingsComplete() { boolean result = true; if (SettingsDocument == null) { result = false; try { // Create instance of DocumentBuilderFactory DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); // Get the DocumentBuilder DocumentBuilder parser; parser = factory.newDocumentBuilder(); // Create blank DOM Document SettingsDocument = parser.newDocument(); } catch (ParserConfigurationException e) { JOptionPane.showMessageDialog(null, "Fatal Error: Cannot create settings Document!"); System.exit(-4); } Element root = SettingsDocument.createElement(SettingsFileName.replace('.', '_')); SettingsDocument.appendChild(root); } NodeList RootList = SettingsDocument.getChildNodes(); if (RootList.getLength() != 1) { JOptionPane.showMessageDialog(null, "Fatal Error: Settings file corrupted; please delete the file:" + HomePath + SettingsFileName + ".xml"); System.exit(-5); } NodeList SettingsList = SettingsDocument .getElementsByTagName(WorkSpace); if (SettingsList.getLength() > 1) { JOptionPane.showMessageDialog(null, "Fatal Error: Settings file corrupted; please delete the file:" + HomePath + SettingsFileName + ".xml"); System.exit(-5); } if (SettingsList.getLength() == 0) { Element workspace = SettingsDocument.createElement(WorkSpace); workspace.setAttribute(DirectoryName, HomePath + "logisim_workspace" + File.separator); RootList.item(0).appendChild(workspace); SettingsList = SettingsDocument.getElementsByTagName(WorkSpace); result = false; } loadToolPath(vendors.get(FPGAClass.VendorXilinx)); loadToolPath(vendors.get(FPGAClass.VendorAltera)); loadToolPath(vendors.get(FPGAClass.VendorVivado)); GetHDLOnly(); GetHDLType(); SettingsList = SettingsDocument.getElementsByTagName(Boards); if (SettingsList.getLength() > 1) { JOptionPane.showMessageDialog(null, "Fatal Error: Settings file corrupted; please delete the file:" + HomePath + SettingsFileName + ".xml"); System.exit(-5); } if (SettingsList.getLength() == 0) { Element workspace = SettingsDocument.createElement(Boards); workspace.setAttribute(SelectedBoard, KnownBoards.GetBoardNames() .toArray()[0].toString()); RootList.item(0).appendChild(workspace); SettingsList = SettingsDocument.getElementsByTagName(Boards); result = false; } GetSelectedBoard(); result &= !modified; return result; } public boolean AddExternalBoard(String CompleteFileName) { NodeList SettingsList = SettingsDocument .getElementsByTagName(Boards); if (SettingsList.getLength() != 1) { return false; } Node ThisWorkspace = SettingsList.item(0); int NrOfBoards = 0; NamedNodeMap WorkspaceParameters = ThisWorkspace.getAttributes(); for (int j = 0; j < WorkspaceParameters.getLength();j++) { if (WorkspaceParameters.item(j).getNodeName().contains(ExternalBoard)) { String[] Items = WorkspaceParameters.item(j).getNodeName().split("_"); if (Items.length == 2) { if (Integer.parseInt(Items[1])>NrOfBoards) NrOfBoards = Integer.parseInt(Items[1]); } } } NrOfBoards += 1; /* The attribute does not exists so add it */ Attr extBoard = SettingsDocument.createAttribute(ExternalBoard+"_"+Integer.toString(NrOfBoards)); extBoard.setNodeValue(CompleteFileName); Element workspace = (Element) SettingsList.item(0); workspace.setAttributeNode(extBoard); KnownBoards.AddExternalBoard(CompleteFileName); modified = true; return true; } public boolean SetWorkspacePath(String path) { NodeList SettingsList = SettingsDocument .getElementsByTagName(WorkSpace); if (SettingsList.getLength() != 1) { return false; } Node ThisWorkspace = SettingsList.item(0); NamedNodeMap WorkspaceParameters = ThisWorkspace.getAttributes(); for (int i = 0; i < WorkspaceParameters.getLength(); i++) { if (WorkspaceParameters.item(i).getNodeName().equals(DirectoryName)) { WorkspaceParameters.item(i).setNodeValue(path); modified = true; return true; } } return false; } public boolean setToolPath(char vendor, String path) { VendorSoftware vendorSoftware = vendors.get(vendor); if (!toolFound(vendorSoftware, path)) return false; NodeList SettingsList = SettingsDocument.getElementsByTagName(WorkSpace); if (SettingsList.getLength() != 1) { return false; } Node ThisWorkspace = SettingsList.item(0); NamedNodeMap WorkspaceParameters = ThisWorkspace.getAttributes(); for (int i = 0; i < WorkspaceParameters.getLength(); i++) { if (WorkspaceParameters.item(i).getNodeName().equals(vendorSoftware.getName())) { WorkspaceParameters.item(i).setNodeValue(path); vendorSoftware.setToolPath(path); modified = true; return true; } } return false; } public boolean UpdateSettingsFile() { if (!modified) return true; File target = new File(HomePath + SettingsFileName + ".xml"); return WriteXml(target); } private boolean WriteXml(File target) { try { TransformerFactory tranFactory = TransformerFactory.newInstance(); tranFactory.setAttribute("indent-number", 3); Transformer aTransformer = tranFactory.newTransformer(); aTransformer.setOutputProperty(OutputKeys.INDENT, "yes"); Source src = new DOMSource(SettingsDocument); Result dest = new StreamResult(target); aTransformer.transform(src, dest); modified = false; return true; } catch (Exception e) { JOptionPane.showMessageDialog(null, e.getMessage()); return false; } } }