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