/******************************************************************************* * 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.fpgagui; import java.util.ArrayList; import java.util.Collection; import java.util.HashMap; import java.util.Iterator; import java.util.Map; import java.util.Set; import java.util.SortedSet; import java.util.TreeSet; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.bfh.logisim.designrulecheck.Netlist; import com.bfh.logisim.designrulecheck.NetlistComponent; import com.bfh.logisim.fpgaboardeditor.BoardInformation; import com.bfh.logisim.fpgaboardeditor.BoardRectangle; import com.bfh.logisim.fpgaboardeditor.FPGAIOInformationContainer; import com.bfh.logisim.fpgaboardeditor.FPGAIOInformationContainer.IOComponentTypes; import com.bfh.logisim.fpgaboardeditor.PinActivity; import com.cburch.logisim.std.io.DipSwitch; import com.cburch.logisim.std.io.PortIO; import com.cburch.logisim.std.wiring.Pin; public class MappableResourcesContainer { final static Logger logger = LoggerFactory .getLogger(MappableResourcesContainer.class); private Map<ArrayList<String>, NetlistComponent> myMappableResources; public String currentBoardName; private BoardInformation currentUsedBoard; private Map<String, BoardRectangle> mappedList; private String toplevelName; private Map<String, Integer> fpgaInputsList; private Map<String, Integer> fpgaInOutsList; private Map<String, Integer> fpgaOutputsList; private Integer nrOfFPGAInputPins = 0; private Integer nrOfFPGAInOutPins = 0; private Integer nrOfFPGAOutputPins = 0; /* * We differentiate two notation for each component, namely: 1) The display * name: "LED: /LED1". This name can be augmented with alternates, e.g. a * 7-segment display could either be: "SEVENSEGMENT: /DS1" or * "SEVENSEGMENT: /DS1#Segment_A",etc. * * 2) The map name: "FPGA4U:/LED1" or "FPGA4U:/DS1#Segment_A", etc. * * The MappedList keeps track of the display names. */ public MappableResourcesContainer(BoardInformation CurrentBoard, Netlist RootNetlist) { ArrayList<String> Toplevel = new ArrayList<String>(); Toplevel.add(CurrentBoard.getBoardName()); myMappableResources = RootNetlist.GetMappableResources(Toplevel, true); currentBoardName = CurrentBoard.getBoardName(); currentUsedBoard = CurrentBoard; toplevelName = RootNetlist.getCircuitName(); mappedList = new HashMap<String, BoardRectangle>(); rebuildMappedLists(); } public void BuildIOMappingInformation() { if (fpgaInputsList == null) { fpgaInputsList = new HashMap<String, Integer>(); } else { fpgaInputsList.clear(); } if (fpgaInOutsList == null) { fpgaInOutsList = new HashMap<String, Integer>(); } else { fpgaInOutsList.clear(); } if (fpgaOutputsList == null) { fpgaOutputsList = new HashMap<String, Integer>(); } else { fpgaOutputsList.clear(); } nrOfFPGAInputPins = 0; nrOfFPGAInOutPins = 0; nrOfFPGAOutputPins = 0; for (ArrayList<String> key : myMappableResources.keySet()) { NetlistComponent comp = myMappableResources.get(key); for (String Map : GetMapNamesList(key, comp)) { FPGAIOInformationContainer BoardComp = currentUsedBoard .GetComponent(comp.getMap(Map)); if (BoardComp.GetType().equals(IOComponentTypes.Pin)) { if (comp.getEnd(0).IsOutputEnd()) { fpgaInputsList.put(Map, nrOfFPGAInputPins); nrOfFPGAInputPins++; } else { fpgaOutputsList.put(Map, nrOfFPGAOutputPins); nrOfFPGAOutputPins++; } } else { int NrOfPins = IOComponentTypes .GetFPGAInputRequirement(BoardComp.GetType()); if (NrOfPins != 0) { fpgaInputsList.put(Map, nrOfFPGAInputPins); if (BoardComp.GetType().equals( IOComponentTypes.DIPSwitch)) { nrOfFPGAInputPins += BoardComp.getNrOfPins(); } else if (BoardComp.GetType().equals( IOComponentTypes.PortIO)) { nrOfFPGAInputPins += BoardComp.getNrOfPins(); } else { nrOfFPGAInputPins += NrOfPins; } } NrOfPins = IOComponentTypes .GetFPGAOutputRequirement(BoardComp.GetType()); if (NrOfPins != 0) { fpgaOutputsList.put(Map, nrOfFPGAOutputPins); nrOfFPGAOutputPins += NrOfPins; } NrOfPins = IOComponentTypes .GetFPGAInOutRequirement(BoardComp.GetType()); if (NrOfPins != 0) { fpgaInOutsList.put(Map, nrOfFPGAInOutPins); if (BoardComp.GetType().equals(IOComponentTypes.PortIO)) { nrOfFPGAInOutPins += BoardComp.getNrOfPins(); } else { nrOfFPGAInOutPins += NrOfPins; } } } } } } private String DisplayNametoMapName(String item) { String[] parts = item.split(" "); if (parts.length != 2) { logger.error("Internal error"); return ""; } return currentBoardName + ":" + parts[1]; } private int getBestComponent(ArrayList<Integer> list, int requiredPin) { int delta = 999; int bestMatch = -1; for (Integer comp : list) { if (comp.equals(requiredPin)) { return list.indexOf(comp); } if (requiredPin < comp && ((comp - requiredPin) < delta)) { bestMatch = comp; } } return list.indexOf(bestMatch); } public NetlistComponent GetComponent(ArrayList<String> hiername) { if (myMappableResources.containsKey(hiername)) { return myMappableResources.get(hiername); } else { return null; } } public Set<ArrayList<String>> GetComponents() { return myMappableResources.keySet(); } public String GetDisplayName(BoardRectangle rect) { for (String Map : mappedList.keySet()) { if (mappedList.get(Map).equals(rect)) { return MapNametoDisplayName(Map); } } return ""; } public int GetFPGAInOutPinId(String MapName) { if (fpgaInOutsList.containsKey(MapName)) { return fpgaInOutsList.get(MapName); } return -1; } public int GetFPGAInputPinId(String MapName) { if (fpgaInputsList.containsKey(MapName)) { return fpgaInputsList.get(MapName); } return -1; } public int GetFPGAOutputPinId(String MapName) { if (fpgaOutputsList.containsKey(MapName)) { return fpgaOutputsList.get(MapName); } return -1; } public ArrayList<String> GetFPGAPinLocs(int FPGAVendor) { ArrayList<String> Contents = new ArrayList<String>(); for (String Map : fpgaInputsList.keySet()) { int InputId = fpgaInputsList.get(Map); if (!mappedList.containsKey(Map)) { logger.warn("No mapping found for {}", Map); return Contents; } BoardRectangle rect = mappedList.get(Map); FPGAIOInformationContainer Comp = currentUsedBoard .GetComponent(rect); Contents.addAll(Comp.GetPinlocStrings(FPGAVendor, "in", InputId)); } for (String Map : fpgaInOutsList.keySet()) { int InOutId = fpgaInOutsList.get(Map); if (!mappedList.containsKey(Map)) { logger.warn("No mapping found for {}", Map); return Contents; } BoardRectangle rect = mappedList.get(Map); FPGAIOInformationContainer Comp = currentUsedBoard .GetComponent(rect); Contents.addAll(Comp.GetPinlocStrings(FPGAVendor, "inout", InOutId)); } for (String Map : fpgaOutputsList.keySet()) { int OutputId = fpgaOutputsList.get(Map); if (!mappedList.containsKey(Map)) { logger.warn("No mapping found for {}", Map); return Contents; } BoardRectangle rect = mappedList.get(Map); FPGAIOInformationContainer Comp = currentUsedBoard .GetComponent(rect); Contents.addAll(Comp.GetPinlocStrings(FPGAVendor, "out", OutputId)); } return Contents; } private ArrayList<String> GetHierarchyKey(String str) { ArrayList<String> result = new ArrayList<String>(); String[] subtype = str.split("#"); String[] iotype = subtype[0].split(" "); String[] parts = iotype[iotype.length - 1].split("/"); result.add(currentBoardName); for (int i = 1; i < parts.length; i++) { result.add(parts[i]); } return result; } public BoardRectangle GetMap(String id) { ArrayList<String> key = GetHierarchyKey(id); NetlistComponent MapComp = myMappableResources.get(key); if (MapComp == null) { logger.error("Internal error!"); return null; } return MapComp.getMap(DisplayNametoMapName(id)); } public ArrayList<String> GetMapNamesList(ArrayList<String> HierName) { if (myMappableResources.containsKey(HierName)) { NetlistComponent comp = myMappableResources.get(HierName); return GetMapNamesList(HierName, comp); } return null; } private ArrayList<String> GetMapNamesList(ArrayList<String> hiername, NetlistComponent comp) { ArrayList<String> result = new ArrayList<String>(); StringBuffer name = new StringBuffer(); /* we strip off the board name and add the component type */ name.append(currentBoardName + ":"); for (int i = 1; i < hiername.size(); i++) { name.append("/"); name.append(hiername.get(i)); } if (comp.AlternateMappingEnabled(hiername)) { for (int i = 0; i < comp.GetIOInformationContainer() .GetNrOfInports(); i++) { result.add(name.toString() + "#" + comp.GetIOInformationContainer().GetInportLabel(i)); } for (int i = 0; i < comp.GetIOInformationContainer() .GetNrOfInOutports(); i++) { result.add(name.toString() + "#" + comp.GetIOInformationContainer().GetInOutportLabel(i)); } for (int i = 0; i < comp.GetIOInformationContainer() .GetNrOfOutports(); i++) { result.add(name.toString() + "#" + comp.GetIOInformationContainer().GetOutportLabel(i)); } } else { result.add(name.toString()); } return result; } public Collection<BoardRectangle> GetMappedRectangles() { return mappedList.values(); } public int GetNrOfPins(String MapName) { if (mappedList.containsKey(MapName)) { FPGAIOInformationContainer BoardComp = currentUsedBoard .GetComponent(mappedList.get(MapName)); if (BoardComp.GetType().equals(IOComponentTypes.DIPSwitch)) { return BoardComp.getNrOfPins(); } else if (BoardComp.GetType().equals(IOComponentTypes.PortIO)) { return BoardComp.getNrOfPins(); } else { return IOComponentTypes.GetNrOfFPGAPins(BoardComp.GetType()); } } return 0; } public int GetNrOfToplevelInOutPins() { return nrOfFPGAInOutPins; } public int GetNrOfToplevelInputPins() { return nrOfFPGAInputPins; } public int GetNrOfToplevelOutputPins() { return nrOfFPGAOutputPins; } public ArrayList<BoardRectangle> GetSelectableItemsList(String DisplayName, BoardInformation BoardInfo) { ArrayList<BoardRectangle> List; ArrayList<String> key = GetHierarchyKey(DisplayName); NetlistComponent comp = myMappableResources.get(key); int pinNeeded = comp.GetIOInformationContainer().GetNrOfInOutports() + comp.GetIOInformationContainer().GetNrOfInports() + comp.GetIOInformationContainer().GetNrOfOutports(); /* first check main map type */ if (!comp.AlternateMappingEnabled(key)) { List = BoardInfo.GetIoComponentsOfType(comp .GetIOInformationContainer().GetMainMapType(), pinNeeded); if (!List.isEmpty()) { return RemoveUsedItems(List, 0); } } List = new ArrayList<BoardRectangle>(); int MapId = 0; IOComponentTypes MapType; do { MapType = comp.GetIOInformationContainer().GetAlternateMapType( MapId); List.addAll(BoardInfo.GetIoComponentsOfType(MapType, 0)); MapId++; } while (MapType != IOComponentTypes.Unknown); return RemoveUsedItems(List, pinNeeded); } public String GetToplevelName() { return toplevelName; } public boolean hasMappedComponents() { return !mappedList.isEmpty(); } public boolean IsMappable(Map<String, ArrayList<Integer>> BoardComponents, FPGAReport MyReporter) { for (ArrayList<String> key : myMappableResources.keySet()) { NetlistComponent comp = myMappableResources.get(key); /* * we have a special case: a pinbus of the toplevel, this one has * never a mainmaptype, so we should skip the test */ if (!((comp.GetComponent().getFactory() instanceof Pin) && (comp .GetComponent().getEnd(0).getWidth().getWidth() > 1))) { /* for each component we first check the main map type */ String MainMapType = comp.GetIOInformationContainer() .GetMainMapType().toString(); if (BoardComponents.containsKey(MainMapType)) { /* okay it exists lets see if we have enough of those */ if (BoardComponents.get(MainMapType).size() > 0) { if (comp.GetComponent().getFactory() instanceof PortIO || comp.GetComponent().getFactory() instanceof DipSwitch) { /* Care of Port and Dip as their size may vary */ int NrOfBCRequired = comp .GetIOInformationContainer() .GetNrOfInports() + comp.GetIOInformationContainer() .GetNrOfOutports() + comp.GetIOInformationContainer() .GetNrOfInOutports(); int bestComponentIdx = getBestComponent( BoardComponents.get(MainMapType), NrOfBCRequired); if (bestComponentIdx > -1) { BoardComponents.get(MainMapType).remove( bestComponentIdx); continue; } } else { /* * no Problem, we have enough of those , we allocate * and decrease */ BoardComponents.get(MainMapType) .remove(BoardComponents.get(MainMapType) .size() - 1); continue; } } } else { /* * The board does not have the main type, hence we have * anyways to use alternate mapping */ comp.ToggleAlternateMapping(key); comp.LockAlternateMapping(key); } } /* Here we check if the component can be mapped to an alternate map */ int AltMapId = 0; String AltMapType; boolean found = false; do { AltMapType = comp.GetIOInformationContainer() .GetAlternateMapType(AltMapId).toString(); if (!AltMapType.equals(IOComponentTypes.Unknown.toString())) { if (BoardComponents.containsKey(AltMapType)) { int NrOfBCRequired = comp.GetIOInformationContainer() .GetNrOfInports() + comp.GetIOInformationContainer() .GetNrOfOutports() + comp.GetIOInformationContainer() .GetNrOfInOutports(); if (NrOfBCRequired <= BoardComponents.get(AltMapType) .size()) { // BoardComponents.put(AltMapType, // BoardComponents.get(AltMapType) - // NrOfBCRequired); for (int i = 0; i < NrOfBCRequired; i++) { BoardComponents.get(AltMapType) .remove(BoardComponents.get(AltMapType) .size() - 1); } found = true; break; } } } AltMapId++; } while (!AltMapType.equals(IOComponentTypes.Unknown.toString())); if (!found) { if (comp.AlternateMappingEnabled(key)) { comp.UnlockAlternateMapping(key); comp.ToggleAlternateMapping(key); } MyReporter .AddError("The Target board " + currentBoardName + " does not have enough IO resources to map the design!"); MyReporter.AddError("The component \"" + MapNametoDisplayName(GetMapNamesList(key, comp) .get(0)) + "\" cannot be placed!"); return false; } } return true; } public void Map(String comp, BoardRectangle item, String Maptype) { ArrayList<String> key = GetHierarchyKey(comp); NetlistComponent MapComp = myMappableResources.get(key); if (MapComp == null) { logger.error("Internal error! comp: {}, key: {}", comp, key); return; } MapComp.addMap(DisplayNametoMapName(comp), item, Maptype); rebuildMappedLists(); } private String MapNametoDisplayName(String item) { String[] parts = item.split(":"); if (parts.length != 2) { logger.error("Internal error!"); return ""; } ArrayList<String> key = GetHierarchyKey(parts[1]); if (key != null) { return myMappableResources.get(key).GetIOInformationContainer() .GetMainMapType().toString().toUpperCase() + ": " + parts[1]; } return ""; } public Set<String> MappedList() { SortedSet<String> result = new TreeSet<String>(); for (String MapName : mappedList.keySet()) { result.add(MapNametoDisplayName(MapName)); } return result; } public void rebuildMappedLists() { mappedList.clear(); for (ArrayList<String> key : myMappableResources.keySet()) { if (key.get(0).equals(currentBoardName)) { NetlistComponent comp = myMappableResources.get(key); /* * we can have two different situations: 1) A multipin component * is mapped to a multipin resource. 2) A multipin component is * mapped to multiple singlepin resources. */ /* first we handle the single pin version */ boolean hasmap = false; for (String MapName : GetMapNamesList(key, comp)) { if (comp.getMap(MapName) != null) { hasmap = true; mappedList.put(MapName, comp.getMap(MapName)); } } if (!hasmap) { comp.ToggleAlternateMapping(key); for (String MapName : GetMapNamesList(key, comp)) { if (comp.getMap(MapName) != null) { hasmap = true; mappedList.put(MapName, comp.getMap(MapName)); } } if (!hasmap) { comp.ToggleAlternateMapping(key); } } } } } /** * ************************************************************************* * ************************************** */ /** * Here all private handles are defined * */ /** * ************************************************************************* * ************************************** */ private ArrayList<BoardRectangle> RemoveUsedItems( ArrayList<BoardRectangle> List, int pinNeeded) { int used = pinNeeded; Iterator<BoardRectangle> ListIterator = List.iterator(); while (ListIterator.hasNext()) { BoardRectangle current = ListIterator.next(); if (mappedList.containsValue(current)) { ListIterator.remove(); used--; } } /* We dont want to list Pin if they are not enough */ if (List.size() < used) { List.clear(); } return List; } public boolean RequiresToplevelInversion( ArrayList<String> ComponentIdentifier, String MapName) { if (!mappedList.containsKey(MapName)) { return false; } if (!myMappableResources.containsKey(ComponentIdentifier)) { return false; } FPGAIOInformationContainer BoardComp = currentUsedBoard .GetComponent(mappedList.get(MapName)); NetlistComponent Comp = myMappableResources.get(ComponentIdentifier); boolean BoardActiveHigh = (BoardComp.GetActivityLevel() == PinActivity.ActiveHigh); boolean CompActiveHigh = Comp.GetComponent().getFactory() .ActiveOnHigh(Comp.GetComponent().getAttributeSet()); boolean Invert = BoardActiveHigh ^ CompActiveHigh; return Invert; } public void ToggleAlternateMapping(String item) { ArrayList<String> key = GetHierarchyKey(item); NetlistComponent comp = myMappableResources.get(key); if (comp != null) { if (comp.AlternateMappingEnabled(key)) { for (String MapName : GetMapNamesList(key, comp)) { if (mappedList.containsKey(MapName)) { return; } } } comp.ToggleAlternateMapping(key); } } public void TryMap(String DisplayName, BoardRectangle rect, String Maptype) { ArrayList<String> key = GetHierarchyKey(DisplayName); if (!myMappableResources.containsKey(key)) { return; } if (UnmappedList().contains(DisplayName)) { Map(DisplayName, rect, Maptype); return; } myMappableResources.get(key).ToggleAlternateMapping(key); if (UnmappedList().contains(DisplayName)) { Map(DisplayName, rect, Maptype); return; } myMappableResources.get(key).ToggleAlternateMapping(key); } public void UnMap(String comp) { ArrayList<String> key = GetHierarchyKey(comp); NetlistComponent MapComp = myMappableResources.get(key); if (MapComp == null) { logger.error("Internal error!"); return; } MapComp.removeMap(DisplayNametoMapName(comp)); rebuildMappedLists(); } public void UnmapAll() { for (ArrayList<String> key : myMappableResources.keySet()) { if (key.get(0).equals(currentBoardName)) { NetlistComponent comp = myMappableResources.get(key); for (String MapName : GetMapNamesList(key, comp)) { comp.removeMap(MapName); } } } } public Set<String> UnmappedList() { SortedSet<String> result = new TreeSet<String>(); for (ArrayList<String> key : myMappableResources.keySet()) { for (String MapName : GetMapNamesList(key, myMappableResources.get(key))) { if (!mappedList.containsKey(MapName)) { result.add(MapNametoDisplayName(MapName)); } } } return result; } }