1f9c72f02fe2c39c3e82bf780a5bfc33d4d1ca81
[Mograsim.git] / plugins / net.mograsim.logic.model.am2900 / src / net / mograsim / logic / model / examples / VerilogExporter.java
1 package net.mograsim.logic.model.examples;
2
3 import java.io.File;
4 import java.io.IOException;
5 import java.io.UncheckedIOException;
6 import java.nio.file.Files;
7 import java.nio.file.Path;
8 import java.nio.file.Paths;
9 import java.util.Arrays;
10 import java.util.Comparator;
11 import java.util.HashMap;
12 import java.util.HashSet;
13 import java.util.List;
14 import java.util.Map;
15 import java.util.Map.Entry;
16 import java.util.Scanner;
17 import java.util.Set;
18 import java.util.stream.Collectors;
19
20 import com.google.gson.JsonElement;
21
22 import net.mograsim.logic.model.am2900.Am2900Loader;
23 import net.mograsim.logic.model.model.LogicModelModifiable;
24 import net.mograsim.logic.model.model.components.ModelComponent;
25 import net.mograsim.logic.model.model.components.submodels.SubmodelComponent;
26 import net.mograsim.logic.model.model.wires.Pin;
27 import net.mograsim.logic.model.serializing.IndirectModelComponentCreator;
28 import net.mograsim.logic.model.serializing.LogicModelParams.ComponentParams;
29 import net.mograsim.logic.model.serializing.LogicModelParams.WireParams;
30 import net.mograsim.logic.model.serializing.LogicModelParams.WireParams.PinParams;
31 import net.mograsim.logic.model.serializing.SubmodelComponentParams;
32 import net.mograsim.logic.model.serializing.SubmodelComponentParams.InterfacePinParams;
33 import net.mograsim.logic.model.serializing.SubmodelComponentSerializer;
34
35 //TODO clean this mess
36 public class VerilogExporter
37 {
38         private static final String COMPONENT_PREFIX = "mgs_";
39
40         public static void main(String[] args) throws IOException
41         {
42                 Am2900Loader.setup();
43                 try (Scanner sysin = new Scanner(System.in))
44                 {
45                         System.out.print("Directory to export Verilog into >");
46                         Path target = Paths.get(sysin.nextLine());
47                         if (!Files.exists(target))
48                                 Files.createDirectories(target);
49                         else if (!Files.isDirectory(target))
50                                 throw new IllegalArgumentException("Target exists and is not a directory");
51
52                         System.out.print("Component ID to serialize recursively >");
53                         String rootComponentID = sysin.nextLine();
54                         {
55                                 if (!Files.exists(target))
56                                         Files.createDirectories(target);
57                                 else if (!Files.isDirectory(target))
58                                         throw new IllegalArgumentException("Target exists and is not a directory");
59                                 Map<String, SubmodelComponentParams> componentsById = readComponentIncludingDependencies(rootComponentID);
60                                 Map<String, PinIdentifierGenerator> pinIdentifierGeneratorsPerComponentID = new HashMap<>();
61                                 Tuple2<Map<String, Map<String, String>>, Map<String, Map<String, Set<String>>>> combinedPinNames = generateCombinedPinNames(
62                                                 componentsById, pinIdentifierGeneratorsPerComponentID);
63                                 Map<String, Tuple2<List<String>, List<Integer>>> sortedInterfacePinNamesAndWidthsPerComponentID = generateSortedInterfacePinNamesAndWidthesPerComponentID(
64                                                 componentsById, combinedPinNames.e1);
65                                 writeComponentsVerilog(target, componentsById, pinIdentifierGeneratorsPerComponentID,
66                                                 sortedInterfacePinNamesAndWidthsPerComponentID, combinedPinNames);
67                         }
68                 }
69         }
70
71         private static Map<String, SubmodelComponentParams> readComponentIncludingDependencies(String rootComponentID)
72         {
73                 Map<String, SubmodelComponentParams> result = new HashMap<>();
74                 readComponentIncludingDependenciesRecursively(rootComponentID, null, result);
75                 return result;
76         }
77
78         private static void readComponentIncludingDependenciesRecursively(String id, JsonElement params,
79                         Map<String, SubmodelComponentParams> result)
80         {
81                 if (result.containsKey(id))
82                         return;
83
84                 ModelComponent component = IndirectModelComponentCreator.createComponent(new LogicModelModifiable(), id, params);
85                 if (component instanceof SubmodelComponent)
86                 {
87                         SubmodelComponentParams componentJson = SubmodelComponentSerializer.serialize((SubmodelComponent) component);
88                         result.put(id, componentJson);
89                         for (ComponentParams subcomponentParams : componentJson.submodel.components)
90                                 readComponentIncludingDependenciesRecursively(subcomponentParams.id, subcomponentParams.params, result);
91                 }
92         }
93
94         private static Tuple2<Map<String, Map<String, String>>, Map<String, Map<String, Set<String>>>> generateCombinedPinNames(
95                         Map<String, SubmodelComponentParams> componentsById, Map<String, PinIdentifierGenerator> pinIdentifierGeneratorsPerComponentID)
96         {
97                 Map<String, Map<String, Set<String>>> connectedInnerPinNamesPerComponentID = new HashMap<>();
98
99                 generateConnectedInnerPins(componentsById, pinIdentifierGeneratorsPerComponentID, connectedInnerPinNamesPerComponentID);
100
101                 Map<String, Map<String, String>> combinedInterfacePinNamesPerComponentID = new HashMap<>();
102
103                 for (boolean anyChange = true; anyChange;)
104                 {
105                         anyChange = false;
106                         for (Entry<String, SubmodelComponentParams> e : componentsById.entrySet())
107                                 anyChange |= checkForConnectedPins(e.getKey(), e.getValue(), componentsById, pinIdentifierGeneratorsPerComponentID,
108                                                 connectedInnerPinNamesPerComponentID, combinedInterfacePinNamesPerComponentID);
109                 }
110
111                 return new Tuple2<>(combinedInterfacePinNamesPerComponentID, connectedInnerPinNamesPerComponentID);
112         }
113
114         private static boolean checkForConnectedPins(String componentID, SubmodelComponentParams componentJson,
115                         Map<String, SubmodelComponentParams> componentsById, Map<String, PinIdentifierGenerator> pinIdentifierGeneratorsPerComponentID,
116                         Map<String, Map<String, Set<String>>> connectedInnerPinNamesPerComponentID,
117                         Map<String, Map<String, String>> combinedPinNamesPerComponentID)
118         {
119                 PinIdentifierGenerator pinIdentifierGenerator = pinIdentifierGeneratorsPerComponentID.get(componentID);
120                 Map<String, Set<String>> connectedInnerPinNames = connectedInnerPinNamesPerComponentID.get(componentID);
121                 Map<String, String> pinNameRemapping = combinedPinNamesPerComponentID.computeIfAbsent(componentID, k ->
122                 {
123                         Map<String, String> result = new HashMap<>();
124                         for (InterfacePinParams pinParams : componentJson.interfacePins)
125                                 result.put(pinParams.name, pinParams.name);
126                         return result;
127                 });
128
129                 for (InterfacePinParams pin1Params : componentJson.interfacePins)
130                 {
131                         String pin1Name = pinNameRemapping.get(pin1Params.name);
132                         Set<String> connectedInnerPinNamesPin1 = connectedInnerPinNames
133                                         .get(pinIdentifierGenerator.getPinID(SubmodelComponent.SUBMODEL_INTERFACE_NAME, pin1Name));
134                         if (connectedInnerPinNamesPin1 != null)
135                                 for (InterfacePinParams pin2Params : componentJson.interfacePins)
136                                 {
137                                         String pin2Name = pinNameRemapping.get(pin2Params.name);
138                                         String pin2InnerPinName = pinIdentifierGenerator.getPinID(SubmodelComponent.SUBMODEL_INTERFACE_NAME, pin2Name);
139                                         if (connectedInnerPinNamesPin1.contains(pin2InnerPinName) && !pin1Name.equals(pin2Name))
140                                         {
141                                                 System.out.println("These pins of component " + componentID + " are connected: " + pin1Name + " and " + pin2Name);
142                                                 for (Entry<String, String> e : pinNameRemapping.entrySet())
143                                                         if (e.getValue().equals(pin2Name))
144                                                                 e.setValue(pin1Name);
145                                                 connectPinsInSupercomponents(componentID, pin1Name, pin2Name, componentsById, pinIdentifierGeneratorsPerComponentID,
146                                                                 connectedInnerPinNamesPerComponentID);
147                                                 return true;
148                                         }
149                                 }
150                 }
151                 return false;
152         }
153
154         private static void connectPinsInSupercomponents(String componentID, String pin1Name, String pin2Name,
155                         Map<String, SubmodelComponentParams> componentsById, Map<String, PinIdentifierGenerator> pinIdentifierGeneratorsPerComponentID,
156                         Map<String, Map<String, Set<String>>> connectedInnerPinNamesPerComponentID)
157         {
158                 for (Entry<String, SubmodelComponentParams> e : componentsById.entrySet())
159                 {
160                         String superComponentID = e.getKey();
161                         SubmodelComponentParams superComponentJson = e.getValue();
162
163                         PinIdentifierGenerator pinIdentifierGenerator = pinIdentifierGeneratorsPerComponentID.get(superComponentID);
164                         Map<String, Set<String>> connectedPinNames = connectedInnerPinNamesPerComponentID.get(superComponentID);
165
166                         for (ComponentParams subcomponentParams : superComponentJson.submodel.components)
167                                 if (subcomponentParams.id.equals(componentID))
168                                 {
169                                         String pin1ID = pinIdentifierGenerator.getPinID(subcomponentParams.name, pin1Name);
170                                         String pin2ID = pinIdentifierGenerator.getPinID(subcomponentParams.name, pin2Name);
171
172                                         Set<String> connectedPinNamesPin1 = connectedPinNames.get(pin1ID);
173                                         Set<String> connectedPinNamesPin2 = connectedPinNames.get(pin2ID);
174
175                                         if (connectedPinNamesPin2 != null)
176                                         {
177                                                 connectedPinNamesPin2.remove(pin2ID);
178                                                 if (connectedPinNamesPin1 != null)
179                                                 {
180                                                         connectedPinNamesPin2.addAll(connectedPinNamesPin1);
181                                                         for (String pinNameToRewriteMapping : connectedPinNamesPin1)
182                                                                 connectedPinNames.put(pinNameToRewriteMapping, connectedPinNamesPin2);
183                                                 }
184                                         }
185                                 }
186                 }
187         }
188
189         private static void generateConnectedInnerPins(Map<String, SubmodelComponentParams> componentsById,
190                         Map<String, PinIdentifierGenerator> pinIdentifierGeneratorsPerComponentID,
191                         Map<String, Map<String, Set<String>>> connectedInnerPinNamesPerComponentID)
192         {
193                 for (Entry<String, SubmodelComponentParams> e : componentsById.entrySet())
194                 {
195                         String componentID = e.getKey();
196                         SubmodelComponentParams componentJson = e.getValue();
197
198                         PinIdentifierGenerator pinIdentifierGenerator = new PinIdentifierGenerator();
199                         Map<String, Set<String>> connectedInnerPinNames = new HashMap<>();
200                         pinIdentifierGeneratorsPerComponentID.put(componentID, pinIdentifierGenerator);
201                         connectedInnerPinNamesPerComponentID.put(componentID, connectedInnerPinNames);
202
203                         for (WireParams wireJson : componentJson.submodel.wires)
204                         {
205                                 String pin1Name = pinIdentifierGenerator.getPinID(wireJson.pin1);
206                                 String pin2Name = pinIdentifierGenerator.getPinID(wireJson.pin2);
207
208                                 Set<String> oldConnectedPins1 = connectedInnerPinNames.get(pin1Name);
209                                 Set<String> oldConnectedPins2 = connectedInnerPinNames.get(pin2Name);
210
211                                 if (oldConnectedPins1 == null)
212                                         oldConnectedPins1 = Set.of(pin1Name);
213                                 if (oldConnectedPins2 == null)
214                                 {
215                                         oldConnectedPins2 = new HashSet<>(Arrays.asList(pin2Name));
216                                         connectedInnerPinNames.put(pin2Name, oldConnectedPins2);
217                                 }
218
219                                 oldConnectedPins2.addAll(oldConnectedPins1);
220                                 for (String pinNameToRewriteMapping : oldConnectedPins1)
221                                         connectedInnerPinNames.put(pinNameToRewriteMapping, oldConnectedPins2);
222                         }
223                 }
224         }
225
226         private static Map<String, Tuple2<List<String>, List<Integer>>> generateSortedInterfacePinNamesAndWidthesPerComponentID(
227                         Map<String, SubmodelComponentParams> componentsById, Map<String, Map<String, String>> combinedInterfacePinsPerComponentID)
228         {
229                 return combinedInterfacePinsPerComponentID.entrySet().stream().collect(Collectors.toMap(Entry::getKey, e ->
230                 {
231                         List<String> names = e.getValue().values().stream().distinct().collect(Collectors.toList());
232                         Map<String, Integer> widthesPerName = Arrays.stream(componentsById.get(e.getKey()).interfacePins)
233                                         .collect(Collectors.toMap(p -> p.name, p -> p.logicWidth));
234                         List<Integer> widthes = names.stream().map(widthesPerName::get).collect(Collectors.toList());
235                         return new Tuple2<>(names, widthes);
236                 }));
237         }
238
239         private static void writeComponentsVerilog(Path target, Map<String, SubmodelComponentParams> componentsById,
240                         Map<String, PinIdentifierGenerator> pinIdentifierGeneratorsPerComponentID,
241                         Map<String, Tuple2<List<String>, List<Integer>>> sortedInterfacePinNamesAndWidthsPerComponentID,
242                         Tuple2<Map<String, Map<String, String>>, Map<String, Map<String, Set<String>>>> combinedPinNames)
243         {
244                 componentsById.forEach((componentID, componentJson) ->
245                 {
246                         try
247                         {
248                                 String componentPathStr = componentID.replace(File.separator, "_").replace('.', '_');
249                                 Path componentPathWithoutPrefix = target.resolve(componentPathStr + ".v");
250                                 Path componentParent = componentPathWithoutPrefix.getParent();
251                                 String componentName = componentPathWithoutPrefix.getFileName().toString();
252                                 Files.createDirectories(componentParent);
253                                 Files.writeString(componentParent.resolve(COMPONENT_PREFIX + componentName),
254                                                 new VerilogExporter(componentID, componentJson, pinIdentifierGeneratorsPerComponentID,
255                                                                 sortedInterfacePinNamesAndWidthsPerComponentID, combinedPinNames).generateVerilog());
256                         }
257                         catch (IOException e)
258                         {
259                                 throw new UncheckedIOException(e);
260                         }
261                 });
262         }
263
264         private final String componentID;
265         private final SubmodelComponentParams componentJson;
266
267         private final PinIdentifierGenerator pinIdentifierGenerator;
268         private final Map<String, Set<String>> combinedInnerPinNames;
269         private final List<String> sortedInterfacePinNames;
270         private final Map<String, Tuple2<List<String>, List<Integer>>> sortedInterfacePinNamesAndWidthsPerComponentID;
271
272         public VerilogExporter(String componentID, SubmodelComponentParams componentJson,
273                         Map<String, PinIdentifierGenerator> pinIdentifierGeneratorsPerComponentID,
274                         Map<String, Tuple2<List<String>, List<Integer>>> sortedInterfacePinNamesAndWidthsPerComponentID,
275                         Tuple2<Map<String, Map<String, String>>, Map<String, Map<String, Set<String>>>> combinedPinNames)
276         {
277                 this.componentID = componentID;
278                 this.componentJson = componentJson;
279
280                 this.pinIdentifierGenerator = pinIdentifierGeneratorsPerComponentID.get(componentID);
281                 this.combinedInnerPinNames = combinedPinNames.e2.get(componentID);
282                 this.sortedInterfacePinNames = sortedInterfacePinNamesAndWidthsPerComponentID.get(componentID).e1;
283                 this.sortedInterfacePinNamesAndWidthsPerComponentID = sortedInterfacePinNamesAndWidthsPerComponentID;
284         }
285
286         public String generateVerilog()
287         {
288                 StringBuilder result = new StringBuilder();
289
290                 result.append("module ");
291                 result.append(COMPONENT_PREFIX);
292                 result.append(sanitizeVerilog(componentID));
293
294                 result.append(" (");
295                 appendInterface(result);
296                 result.append(");\n\n");
297
298                 appendComponents(result);
299
300                 result.append("endmodule\n");
301
302                 return result.toString();
303         }
304
305         private void appendInterface(StringBuilder result)
306         {
307                 if (!sortedInterfacePinNames.isEmpty())
308                 {
309                         Map<String, Integer> logicWidthsPerInterfacePinName = Arrays.stream(componentJson.interfacePins)
310                                         .collect(Collectors.toMap(p -> p.name, p -> p.logicWidth));
311                         result.append('\n');
312                         for (int i = 0; i < sortedInterfacePinNames.size(); i++)
313                         {
314                                 String interfacePinName = sortedInterfacePinNames.get(i);
315                                 int logicWidth = logicWidthsPerInterfacePinName.get(interfacePinName);
316
317                                 result.append("  input ");
318                                 appendLogicWidth(result, logicWidth);
319                                 result.append(sanitizeVerilog(interfacePinName));
320                                 result.append("_pre, output ");
321                                 appendLogicWidth(result, logicWidth);
322                                 result.append(sanitizeVerilog(interfacePinName));
323                                 result.append("_out, input ");
324                                 appendLogicWidth(result, logicWidth);
325                                 result.append(sanitizeVerilog(interfacePinName));
326                                 result.append("_res");
327                                 if (i != sortedInterfacePinNames.size() - 1)
328                                         result.append(',');
329                                 result.append('\n');
330                         }
331                 }
332         }
333
334         private void appendComponents(StringBuilder result)
335         {
336                 Map<Set<String>, String> currentWireNamePerCombinedInnerPinNames = new HashMap<>();
337                 Map<Set<String>, String> resultWireNamePerCombinedInnerPinNames = new HashMap<>();
338                 for (Set<String> s : combinedInnerPinNames.values())
339                 {
340                         currentWireNamePerCombinedInnerPinNames.put(s, "2'b00");
341
342                         String anyInnerPinName = s.iterator().next();
343                         // abuse the pinIdentifierGenerator for generating an unique wire name
344                         String uniqueWireName = pinIdentifierGenerator.getPinID(anyInnerPinName, "res");
345                         resultWireNamePerCombinedInnerPinNames.put(s, uniqueWireName);
346                 }
347                 for (String interfacePinName : sortedInterfacePinNames)
348                 {
349                         String innerPinID = pinIdentifierGenerator.getPinID(SubmodelComponent.SUBMODEL_INTERFACE_NAME, interfacePinName);
350                         Set<String> connectedPins = combinedInnerPinNames.get(innerPinID);
351                         currentWireNamePerCombinedInnerPinNames.put(connectedPins, interfacePinName + "_pre");
352                         resultWireNamePerCombinedInnerPinNames.put(connectedPins, interfacePinName + "_res");
353                 }
354
355                 for (ComponentParams subcomponentParams : componentJson.submodel.components)
356                         appendComponent(result, currentWireNamePerCombinedInnerPinNames, resultWireNamePerCombinedInnerPinNames, subcomponentParams);
357
358                 for (String interfacePinName : sortedInterfacePinNames)
359                 {
360                         String innerPinID = pinIdentifierGenerator.getPinID(SubmodelComponent.SUBMODEL_INTERFACE_NAME, interfacePinName);
361                         Set<String> connectedPins = combinedInnerPinNames.get(innerPinID);
362                         String lastWireName = currentWireNamePerCombinedInnerPinNames.remove(connectedPins);
363
364                         result.append("assign ");
365                         result.append(sanitizeVerilog(interfacePinName));
366                         result.append("_out");
367                         result.append(" = ");
368                         result.append(sanitizeVerilog(lastWireName));
369                         result.append(";\n");
370                 }
371                 for (Set<String> s : currentWireNamePerCombinedInnerPinNames.keySet())
372                 {
373                         String lastWireName = currentWireNamePerCombinedInnerPinNames.get(s);
374                         String resultWireName = resultWireNamePerCombinedInnerPinNames.get(s);
375
376                         result.append("wire ");
377                         int logicWidth = -1;
378                         outer: for (ComponentParams subcomponentJson : componentJson.submodel.components)
379                         {
380                                 Tuple2<List<String>, List<Integer>> subcomponentInterfacePinNamesAndWidths = getSubcomponentInterfacePinNamesAndWidths(
381                                                 subcomponentJson.id, subcomponentJson.params);
382                                 List<String> subcomponentInterfacePinNames = subcomponentInterfacePinNamesAndWidths.e1;
383                                 List<Integer> subcomponentInterfacePinWidths = subcomponentInterfacePinNamesAndWidths.e2;
384                                 for (int i = 0; i < subcomponentInterfacePinNames.size(); i++)
385                                         if (s.contains(pinIdentifierGenerator.getPinID(subcomponentJson.name, subcomponentInterfacePinNames.get(i))))
386                                         {
387                                                 logicWidth = subcomponentInterfacePinWidths.get(i);
388                                                 break outer;
389                                         }
390                         }
391                         appendLogicWidth(result, logicWidth);
392                         result.append(sanitizeVerilog(resultWireName));
393                         result.append(";\n");
394
395                         result.append("assign ");
396                         result.append(sanitizeVerilog(resultWireName));
397                         result.append(" = ");
398                         result.append(sanitizeVerilog(lastWireName));
399                         result.append(";\n");
400                 }
401         }
402
403         private void appendComponent(StringBuilder result, Map<Set<String>, String> currentWireNamePerCombinedInnerPinNames,
404                         Map<Set<String>, String> resultWireNamePerCombinedInnerPinNames, ComponentParams subcomponentParams)
405         {
406                 {
407                         String subcomponentID = subcomponentParams.id;
408                         String subcomponentName = subcomponentParams.name;
409
410                         Tuple2<List<String>, List<Integer>> subcomponentInterfacePinNamesAndWidths = getSubcomponentInterfacePinNamesAndWidths(
411                                         subcomponentID, subcomponentParams.params);
412                         List<String> subcomponentInterfacePinNames = subcomponentInterfacePinNamesAndWidths.e1;
413                         List<Integer> subcomponentInterfacePinWidths = subcomponentInterfacePinNamesAndWidths.e2;
414                         for (int i = 0; i < subcomponentInterfacePinNames.size(); i++)
415                         {
416                                 result.append("wire ");
417                                 appendLogicWidth(result, subcomponentInterfacePinWidths.get(i));
418                                 result.append(pinIdentifierGenerator.getPinID(subcomponentName, subcomponentInterfacePinNames.get(i)));
419                                 result.append(";\n");
420                         }
421
422                         result.append(COMPONENT_PREFIX);
423                         result.append(sanitizeVerilog(subcomponentID + subcomponentParams.params));
424                         result.append(" (");
425                         for (int i = 0; i < subcomponentInterfacePinNames.size(); i++)
426                         {
427                                 String innerPinID = pinIdentifierGenerator.getPinID(subcomponentName, subcomponentInterfacePinNames.get(i));
428
429                                 String lastWireName;
430                                 String nextWireName = innerPinID;
431                                 String resultWireName;
432                                 Set<String> combinedInnerPinsGroup = combinedInnerPinNames.get(innerPinID);
433                                 if (combinedInnerPinsGroup != null)
434                                 {
435                                         lastWireName = currentWireNamePerCombinedInnerPinNames.get(combinedInnerPinsGroup);
436                                         resultWireName = resultWireNamePerCombinedInnerPinNames.get(combinedInnerPinsGroup);
437
438                                         currentWireNamePerCombinedInnerPinNames.put(combinedInnerPinsGroup, nextWireName);
439                                 } else
440                                 {
441                                         lastWireName = "2'b00";
442                                         resultWireName = nextWireName;
443                                 }
444
445                                 result.append(sanitizeVerilog(lastWireName));
446                                 result.append(", ");
447                                 result.append(sanitizeVerilog(nextWireName));
448                                 result.append(", ");
449                                 result.append(sanitizeVerilog(resultWireName));
450                                 if (i != subcomponentInterfacePinNames.size() - 1)
451                                         result.append(", \n  ");
452                         }
453                         result.append(");\n\n");
454                 }
455         }
456
457         private Tuple2<List<String>, List<Integer>> getSubcomponentInterfacePinNamesAndWidths(String subcomponentID,
458                         JsonElement subcomponentParams)
459         {
460                 Tuple2<List<String>, List<Integer>> result = sortedInterfacePinNamesAndWidthsPerComponentID.get(subcomponentID);
461                 if (result != null)
462                         return result;
463
464                 Map<String, Pin> pins = IndirectModelComponentCreator
465                                 .createComponent(new LogicModelModifiable(), subcomponentID, subcomponentParams).getPins();
466                 List<String> names = pins.keySet().stream().sorted().collect(Collectors.toList());
467                 List<Integer> widthes = pins.entrySet().stream().sorted(Comparator.comparing(e -> e.getKey())).map(Entry::getValue)
468                                 .map(p -> p.logicWidth).collect(Collectors.toList());
469                 System.out.println("Assuming following order for interface pins of " + subcomponentID + ": " + names);
470                 return new Tuple2<>(names, widthes);
471         }
472
473         private static void appendLogicWidth(StringBuilder result, int logicWidth)
474         {
475                 result.append('[');
476                 String logicWidthStr = Integer.toString(logicWidth * 2 - 1);
477                 for (int spaces = logicWidthStr.length(); spaces < 3; spaces++)
478                         result.append(' ');
479                 result.append(logicWidthStr);
480                 result.append(":0] ");
481         }
482
483         private static class PinIdentifierGenerator
484         {
485                 private final Map<String, Map<String, String>> wireNamesPerPinAndComponentName;
486                 private final Set<String> usedWireNames;
487
488                 public PinIdentifierGenerator()
489                 {
490                         wireNamesPerPinAndComponentName = new HashMap<>();
491                         usedWireNames = new HashSet<>();
492                 }
493
494                 private String getPinID(PinParams pin)
495                 {
496                         return getPinID(pin.compName, pin.pinName);
497                 }
498
499                 private String getPinID(String component, String pin)
500                 {
501                         String componentSan = sanitizeVerilog(component);
502                         String pinSan = sanitizeVerilog(pin);
503
504                         Map<String, String> wireNamesPerPinName = wireNamesPerPinAndComponentName.computeIfAbsent(componentSan, k -> new HashMap<>());
505
506                         if (wireNamesPerPinName.containsKey(pinSan))
507                                 return wireNamesPerPinName.get(pinSan);
508
509                         String baseName = componentSan + '_' + pinSan;
510                         String combinedName;
511                         if (usedWireNames.add(baseName))
512                                 combinedName = baseName;
513                         else
514                         {
515                                 int i = 0;
516                                 do
517                                         combinedName = baseName + "#" + i++;
518                                 while (!usedWireNames.add(combinedName));
519                         }
520                         wireNamesPerPinName.put(pinSan, combinedName);
521                         return combinedName;
522                 }
523         }
524
525         private static class Tuple2<E1, E2>
526         {
527                 public final E1 e1;
528                 public final E2 e2;
529
530                 public Tuple2(E1 e1, E2 e2)
531                 {
532                         this.e1 = e1;
533                         this.e2 = e2;
534                 }
535         }
536
537         private static String sanitizeVerilog(String str)
538         {
539                 return str.replace('#', '_').replace('+', '_').replace('-', '_').replace('=', '_').replace('{', '_').replace('}', '_')
540                                 .replace(':', '_').replace('"', '_').replace(',', '_').replace('[', '_').replace(']', '_').replace(' ', '_');
541         }
542 }