daef1aac52a577c3431e0b36ee325b49bedd607e
[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                 result.append("input rst, input clk");
309                 if (!sortedInterfacePinNames.isEmpty())
310                 {
311                         Map<String, Integer> logicWidthsPerInterfacePinName = Arrays.stream(componentJson.interfacePins)
312                                         .collect(Collectors.toMap(p -> p.name, p -> p.logicWidth));
313                         for (int i = 0; i < sortedInterfacePinNames.size(); i++)
314                         {
315                                 result.append(",\n");
316                                 String interfacePinName = sortedInterfacePinNames.get(i);
317                                 int logicWidth = logicWidthsPerInterfacePinName.get(interfacePinName);
318
319                                 result.append("  input ");
320                                 appendLogicWidth(result, logicWidth);
321                                 result.append(sanitizeVerilog(interfacePinName));
322                                 result.append("_pre, output ");
323                                 appendLogicWidth(result, logicWidth);
324                                 result.append(sanitizeVerilog(interfacePinName));
325                                 result.append("_out, input ");
326                                 appendLogicWidth(result, logicWidth);
327                                 result.append(sanitizeVerilog(interfacePinName));
328                                 result.append("_res");
329                         }
330                         result.append('\n');
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(" = rst ? ");
398                         result.append(logicWidth * 2);
399                         result.append("'b");
400                         for (int i = 0; i < logicWidth; i++)
401                                 result.append("10");
402                         result.append(" : ");
403                         result.append(sanitizeVerilog(lastWireName));
404                         result.append(";\n");
405                 }
406         }
407
408         private void appendComponent(StringBuilder result, Map<Set<String>, String> currentWireNamePerCombinedInnerPinNames,
409                         Map<Set<String>, String> resultWireNamePerCombinedInnerPinNames, ComponentParams subcomponentParams)
410         {
411                 {
412                         String subcomponentID = subcomponentParams.id;
413                         String subcomponentName = subcomponentParams.name;
414
415                         Tuple2<List<String>, List<Integer>> subcomponentInterfacePinNamesAndWidths = getSubcomponentInterfacePinNamesAndWidths(
416                                         subcomponentID, subcomponentParams.params);
417                         List<String> subcomponentInterfacePinNames = subcomponentInterfacePinNamesAndWidths.e1;
418                         List<Integer> subcomponentInterfacePinWidths = subcomponentInterfacePinNamesAndWidths.e2;
419                         for (int i = 0; i < subcomponentInterfacePinNames.size(); i++)
420                         {
421                                 result.append("wire ");
422                                 appendLogicWidth(result, subcomponentInterfacePinWidths.get(i));
423                                 result.append(pinIdentifierGenerator.getPinID(subcomponentName, subcomponentInterfacePinNames.get(i)));
424                                 result.append(";\n");
425                         }
426
427                         result.append(COMPONENT_PREFIX);
428                         String paramsString = subcomponentParams.params == JsonNull.INSTANCE ? "" : subcomponentParams.params.toString();
429                         result.append(sanitizeVerilog(subcomponentID + paramsString));
430                         result.append(' ');
431                         // abuse the pinIdentifierGenerator for making these unique
432                         result.append(pinIdentifierGenerator.getPinID("comp", subcomponentName));
433                         result.append(" (rst, clk");
434                         for (int i = 0; i < subcomponentInterfacePinNames.size(); i++)
435                         {
436                                 result.append(",\n  ");
437                                 String innerPinID = pinIdentifierGenerator.getPinID(subcomponentName, subcomponentInterfacePinNames.get(i));
438
439                                 String lastWireName;
440                                 String nextWireName = innerPinID;
441                                 String resultWireName;
442                                 Set<String> combinedInnerPinsGroup = combinedInnerPinNames.get(innerPinID);
443                                 if (combinedInnerPinsGroup != null)
444                                 {
445                                         lastWireName = currentWireNamePerCombinedInnerPinNames.get(combinedInnerPinsGroup);
446                                         resultWireName = resultWireNamePerCombinedInnerPinNames.get(combinedInnerPinsGroup);
447
448                                         currentWireNamePerCombinedInnerPinNames.put(combinedInnerPinsGroup, nextWireName);
449                                 } else
450                                 {
451                                         lastWireName = "2'b00";
452                                         resultWireName = nextWireName;
453                                 }
454
455                                 result.append(sanitizeVerilog(lastWireName));
456                                 result.append(", ");
457                                 result.append(sanitizeVerilog(nextWireName));
458                                 result.append(", ");
459                                 result.append(sanitizeVerilog(resultWireName));
460                         }
461                         result.append(");\n\n");
462                 }
463         }
464
465         private Tuple2<List<String>, List<Integer>> getSubcomponentInterfacePinNamesAndWidths(String subcomponentID,
466                         JsonElement subcomponentParams)
467         {
468                 Tuple2<List<String>, List<Integer>> result = sortedInterfacePinNamesAndWidthsPerComponentID.get(subcomponentID);
469                 if (result != null)
470                         return result;
471
472                 Map<String, Pin> pins = IndirectModelComponentCreator
473                                 .createComponent(new LogicModelModifiable(), subcomponentID, subcomponentParams).getPins();
474                 List<String> names = pins.keySet().stream().sorted().collect(Collectors.toList());
475                 List<Integer> widthes = pins.entrySet().stream().sorted(Comparator.comparing(e -> e.getKey())).map(Entry::getValue)
476                                 .map(p -> p.logicWidth).collect(Collectors.toList());
477                 System.out.println("Assuming following order for interface pins of " + subcomponentID + ": " + names);
478                 return new Tuple2<>(names, widthes);
479         }
480
481         private static void appendLogicWidth(StringBuilder result, int logicWidth)
482         {
483                 result.append('[');
484                 String logicWidthStr = Integer.toString(logicWidth * 2 - 1);
485                 for (int spaces = logicWidthStr.length(); spaces < 3; spaces++)
486                         result.append(' ');
487                 result.append(logicWidthStr);
488                 result.append(":0] ");
489         }
490
491         private static class PinIdentifierGenerator
492         {
493                 private final Map<String, Map<String, String>> wireNamesPerPinAndComponentName;
494                 private final Set<String> usedWireNames;
495
496                 public PinIdentifierGenerator()
497                 {
498                         wireNamesPerPinAndComponentName = new HashMap<>();
499                         usedWireNames = new HashSet<>();
500                 }
501
502                 private String getPinID(PinParams pin)
503                 {
504                         return getPinID(pin.compName, pin.pinName);
505                 }
506
507                 private String getPinID(String component, String pin)
508                 {
509                         String componentSan = sanitizeVerilog(component);
510                         String pinSan = sanitizeVerilog(pin);
511
512                         Map<String, String> wireNamesPerPinName = wireNamesPerPinAndComponentName.computeIfAbsent(componentSan, k -> new HashMap<>());
513
514                         if (wireNamesPerPinName.containsKey(pinSan))
515                                 return wireNamesPerPinName.get(pinSan);
516
517                         String baseName = componentSan + '_' + pinSan;
518                         String combinedName;
519                         if (usedWireNames.add(baseName))
520                                 combinedName = baseName;
521                         else
522                         {
523                                 int i = 0;
524                                 do
525                                         combinedName = baseName + "#" + i++;
526                                 while (!usedWireNames.add(combinedName));
527                         }
528                         wireNamesPerPinName.put(pinSan, combinedName);
529                         return combinedName;
530                 }
531         }
532
533         private static class Tuple2<E1, E2>
534         {
535                 public final E1 e1;
536                 public final E2 e2;
537
538                 public Tuple2(E1 e1, E2 e2)
539                 {
540                         this.e1 = e1;
541                         this.e2 = e2;
542                 }
543         }
544
545         private static String sanitizeVerilog(String str)
546         {
547                 return str.replace('#', '_').replace('+', '_').replace('-', '_').replace('=', '_').replace('{', '_').replace('}', '_')
548                                 .replace(':', '_').replace('"', '_').replace(',', '_').replace('[', '_').replace(']', '_').replace(' ', '_');
549         }
550 }