1 package net.mograsim.logic.model.examples;
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;
15 import java.util.Map.Entry;
16 import java.util.Scanner;
18 import java.util.stream.Collectors;
20 import com.google.gson.JsonElement;
21 import com.google.gson.JsonNull;
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;
36 //TODO clean this mess
37 public class VerilogExporter
39 private static final String COMPONENT_PREFIX = "mgs_";
41 public static void main(String[] args) throws IOException
44 try (Scanner sysin = new Scanner(System.in))
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");
53 System.out.print("Component ID to serialize recursively >");
54 String rootComponentID = sysin.nextLine();
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);
72 private static Map<String, SubmodelComponentParams> readComponentIncludingDependencies(String rootComponentID)
74 Map<String, SubmodelComponentParams> result = new HashMap<>();
75 readComponentIncludingDependenciesRecursively(rootComponentID, null, result);
79 private static void readComponentIncludingDependenciesRecursively(String id, JsonElement params,
80 Map<String, SubmodelComponentParams> result)
82 if (result.containsKey(id))
85 ModelComponent component = IndirectModelComponentCreator.createComponent(new LogicModelModifiable(), id, params);
86 if (component instanceof SubmodelComponent)
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);
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)
98 Map<String, Map<String, Set<String>>> connectedInnerPinNamesPerComponentID = new HashMap<>();
100 generateConnectedInnerPins(componentsById, pinIdentifierGeneratorsPerComponentID, connectedInnerPinNamesPerComponentID);
102 Map<String, Map<String, String>> combinedInterfacePinNamesPerComponentID = new HashMap<>();
104 for (boolean anyChange = true; anyChange;)
107 for (Entry<String, SubmodelComponentParams> e : componentsById.entrySet())
108 anyChange |= checkForConnectedPins(e.getKey(), e.getValue(), componentsById, pinIdentifierGeneratorsPerComponentID,
109 connectedInnerPinNamesPerComponentID, combinedInterfacePinNamesPerComponentID);
112 return new Tuple2<>(combinedInterfacePinNamesPerComponentID, connectedInnerPinNamesPerComponentID);
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)
120 PinIdentifierGenerator pinIdentifierGenerator = pinIdentifierGeneratorsPerComponentID.get(componentID);
121 Map<String, Set<String>> connectedInnerPinNames = connectedInnerPinNamesPerComponentID.get(componentID);
122 Map<String, String> pinNameRemapping = combinedPinNamesPerComponentID.computeIfAbsent(componentID, k ->
124 Map<String, String> result = new HashMap<>();
125 for (InterfacePinParams pinParams : componentJson.interfacePins)
126 result.put(pinParams.name, pinParams.name);
130 for (InterfacePinParams pin1Params : componentJson.interfacePins)
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)
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))
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);
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)
159 for (Entry<String, SubmodelComponentParams> e : componentsById.entrySet())
161 String superComponentID = e.getKey();
162 SubmodelComponentParams superComponentJson = e.getValue();
164 PinIdentifierGenerator pinIdentifierGenerator = pinIdentifierGeneratorsPerComponentID.get(superComponentID);
165 Map<String, Set<String>> connectedPinNames = connectedInnerPinNamesPerComponentID.get(superComponentID);
167 for (ComponentParams subcomponentParams : superComponentJson.submodel.components)
168 if (subcomponentParams.id.equals(componentID))
170 String pin1ID = pinIdentifierGenerator.getPinID(subcomponentParams.name, pin1Name);
171 String pin2ID = pinIdentifierGenerator.getPinID(subcomponentParams.name, pin2Name);
173 Set<String> connectedPinNamesPin1 = connectedPinNames.get(pin1ID);
174 Set<String> connectedPinNamesPin2 = connectedPinNames.get(pin2ID);
176 if (connectedPinNamesPin2 != null)
178 connectedPinNamesPin2.remove(pin2ID);
179 if (connectedPinNamesPin1 != null)
181 connectedPinNamesPin2.addAll(connectedPinNamesPin1);
182 for (String pinNameToRewriteMapping : connectedPinNamesPin1)
183 connectedPinNames.put(pinNameToRewriteMapping, connectedPinNamesPin2);
190 private static void generateConnectedInnerPins(Map<String, SubmodelComponentParams> componentsById,
191 Map<String, PinIdentifierGenerator> pinIdentifierGeneratorsPerComponentID,
192 Map<String, Map<String, Set<String>>> connectedInnerPinNamesPerComponentID)
194 for (Entry<String, SubmodelComponentParams> e : componentsById.entrySet())
196 String componentID = e.getKey();
197 SubmodelComponentParams componentJson = e.getValue();
199 PinIdentifierGenerator pinIdentifierGenerator = new PinIdentifierGenerator();
200 Map<String, Set<String>> connectedInnerPinNames = new HashMap<>();
201 pinIdentifierGeneratorsPerComponentID.put(componentID, pinIdentifierGenerator);
202 connectedInnerPinNamesPerComponentID.put(componentID, connectedInnerPinNames);
204 for (WireParams wireJson : componentJson.submodel.wires)
206 String pin1Name = pinIdentifierGenerator.getPinID(wireJson.pin1);
207 String pin2Name = pinIdentifierGenerator.getPinID(wireJson.pin2);
209 Set<String> oldConnectedPins1 = connectedInnerPinNames.get(pin1Name);
210 Set<String> oldConnectedPins2 = connectedInnerPinNames.get(pin2Name);
212 if (oldConnectedPins1 == null)
213 oldConnectedPins1 = Set.of(pin1Name);
214 if (oldConnectedPins2 == null)
216 oldConnectedPins2 = new HashSet<>(Arrays.asList(pin2Name));
217 connectedInnerPinNames.put(pin2Name, oldConnectedPins2);
220 oldConnectedPins2.addAll(oldConnectedPins1);
221 for (String pinNameToRewriteMapping : oldConnectedPins1)
222 connectedInnerPinNames.put(pinNameToRewriteMapping, oldConnectedPins2);
227 private static Map<String, Tuple2<List<String>, List<Integer>>> generateSortedInterfacePinNamesAndWidthesPerComponentID(
228 Map<String, SubmodelComponentParams> componentsById, Map<String, Map<String, String>> combinedInterfacePinsPerComponentID)
230 return combinedInterfacePinsPerComponentID.entrySet().stream().collect(Collectors.toMap(Entry::getKey, e ->
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);
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)
245 componentsById.forEach((componentID, componentJson) ->
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());
258 catch (IOException e)
260 throw new UncheckedIOException(e);
265 private final String componentID;
266 private final SubmodelComponentParams componentJson;
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;
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)
278 this.componentID = componentID;
279 this.componentJson = componentJson;
281 this.pinIdentifierGenerator = pinIdentifierGeneratorsPerComponentID.get(componentID);
282 this.combinedInnerPinNames = combinedPinNames.e2.get(componentID);
283 this.sortedInterfacePinNames = sortedInterfacePinNamesAndWidthsPerComponentID.get(componentID).e1;
284 this.sortedInterfacePinNamesAndWidthsPerComponentID = sortedInterfacePinNamesAndWidthsPerComponentID;
287 public String generateVerilog()
289 StringBuilder result = new StringBuilder();
291 result.append("module ");
292 result.append(COMPONENT_PREFIX);
293 result.append(sanitizeVerilog(componentID));
296 appendInterface(result);
297 result.append(");\n\n");
299 appendComponents(result);
301 result.append("endmodule\n");
303 return result.toString();
306 private void appendInterface(StringBuilder result)
308 if (!sortedInterfacePinNames.isEmpty())
310 Map<String, Integer> logicWidthsPerInterfacePinName = Arrays.stream(componentJson.interfacePins)
311 .collect(Collectors.toMap(p -> p.name, p -> p.logicWidth));
313 for (int i = 0; i < sortedInterfacePinNames.size(); i++)
315 String interfacePinName = sortedInterfacePinNames.get(i);
316 int logicWidth = logicWidthsPerInterfacePinName.get(interfacePinName);
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)
335 private void appendComponents(StringBuilder result)
337 Map<Set<String>, String> currentWireNamePerCombinedInnerPinNames = new HashMap<>();
338 Map<Set<String>, String> resultWireNamePerCombinedInnerPinNames = new HashMap<>();
339 for (Set<String> s : combinedInnerPinNames.values())
341 currentWireNamePerCombinedInnerPinNames.put(s, "2'b00");
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);
348 for (String interfacePinName : sortedInterfacePinNames)
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");
356 for (ComponentParams subcomponentParams : componentJson.submodel.components)
357 appendComponent(result, currentWireNamePerCombinedInnerPinNames, resultWireNamePerCombinedInnerPinNames, subcomponentParams);
359 for (String interfacePinName : sortedInterfacePinNames)
361 String innerPinID = pinIdentifierGenerator.getPinID(SubmodelComponent.SUBMODEL_INTERFACE_NAME, interfacePinName);
362 Set<String> connectedPins = combinedInnerPinNames.get(innerPinID);
363 String lastWireName = currentWireNamePerCombinedInnerPinNames.remove(connectedPins);
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");
372 for (Set<String> s : currentWireNamePerCombinedInnerPinNames.keySet())
374 String lastWireName = currentWireNamePerCombinedInnerPinNames.get(s);
375 String resultWireName = resultWireNamePerCombinedInnerPinNames.get(s);
377 result.append("wire ");
379 outer: for (ComponentParams subcomponentJson : componentJson.submodel.components)
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))))
388 logicWidth = subcomponentInterfacePinWidths.get(i);
392 appendLogicWidth(result, logicWidth);
393 result.append(sanitizeVerilog(resultWireName));
394 result.append(";\n");
396 result.append("assign ");
397 result.append(sanitizeVerilog(resultWireName));
398 result.append(" = ");
399 result.append(sanitizeVerilog(lastWireName));
400 result.append(";\n");
404 private void appendComponent(StringBuilder result, Map<Set<String>, String> currentWireNamePerCombinedInnerPinNames,
405 Map<Set<String>, String> resultWireNamePerCombinedInnerPinNames, ComponentParams subcomponentParams)
408 String subcomponentID = subcomponentParams.id;
409 String subcomponentName = subcomponentParams.name;
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++)
417 result.append("wire ");
418 appendLogicWidth(result, subcomponentInterfacePinWidths.get(i));
419 result.append(pinIdentifierGenerator.getPinID(subcomponentName, subcomponentInterfacePinNames.get(i)));
420 result.append(";\n");
423 result.append(COMPONENT_PREFIX);
424 String paramsString = subcomponentParams.params == JsonNull.INSTANCE ? "" : subcomponentParams.params.toString();
425 result.append(sanitizeVerilog(subcomponentID + paramsString));
427 for (int i = 0; i < subcomponentInterfacePinNames.size(); i++)
429 String innerPinID = pinIdentifierGenerator.getPinID(subcomponentName, subcomponentInterfacePinNames.get(i));
432 String nextWireName = innerPinID;
433 String resultWireName;
434 Set<String> combinedInnerPinsGroup = combinedInnerPinNames.get(innerPinID);
435 if (combinedInnerPinsGroup != null)
437 lastWireName = currentWireNamePerCombinedInnerPinNames.get(combinedInnerPinsGroup);
438 resultWireName = resultWireNamePerCombinedInnerPinNames.get(combinedInnerPinsGroup);
440 currentWireNamePerCombinedInnerPinNames.put(combinedInnerPinsGroup, nextWireName);
443 lastWireName = "2'b00";
444 resultWireName = nextWireName;
447 result.append(sanitizeVerilog(lastWireName));
449 result.append(sanitizeVerilog(nextWireName));
451 result.append(sanitizeVerilog(resultWireName));
452 if (i != subcomponentInterfacePinNames.size() - 1)
453 result.append(", \n ");
455 result.append(");\n\n");
459 private Tuple2<List<String>, List<Integer>> getSubcomponentInterfacePinNamesAndWidths(String subcomponentID,
460 JsonElement subcomponentParams)
462 Tuple2<List<String>, List<Integer>> result = sortedInterfacePinNamesAndWidthsPerComponentID.get(subcomponentID);
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);
475 private static void appendLogicWidth(StringBuilder result, int logicWidth)
478 String logicWidthStr = Integer.toString(logicWidth * 2 - 1);
479 for (int spaces = logicWidthStr.length(); spaces < 3; spaces++)
481 result.append(logicWidthStr);
482 result.append(":0] ");
485 private static class PinIdentifierGenerator
487 private final Map<String, Map<String, String>> wireNamesPerPinAndComponentName;
488 private final Set<String> usedWireNames;
490 public PinIdentifierGenerator()
492 wireNamesPerPinAndComponentName = new HashMap<>();
493 usedWireNames = new HashSet<>();
496 private String getPinID(PinParams pin)
498 return getPinID(pin.compName, pin.pinName);
501 private String getPinID(String component, String pin)
503 String componentSan = sanitizeVerilog(component);
504 String pinSan = sanitizeVerilog(pin);
506 Map<String, String> wireNamesPerPinName = wireNamesPerPinAndComponentName.computeIfAbsent(componentSan, k -> new HashMap<>());
508 if (wireNamesPerPinName.containsKey(pinSan))
509 return wireNamesPerPinName.get(pinSan);
511 String baseName = componentSan + '_' + pinSan;
513 if (usedWireNames.add(baseName))
514 combinedName = baseName;
519 combinedName = baseName + "#" + i++;
520 while (!usedWireNames.add(combinedName));
522 wireNamesPerPinName.put(pinSan, combinedName);
527 private static class Tuple2<E1, E2>
532 public Tuple2(E1 e1, E2 e2)
539 private static String sanitizeVerilog(String str)
541 return str.replace('#', '_').replace('+', '_').replace('-', '_').replace('=', '_').replace('{', '_').replace('}', '_')
542 .replace(':', '_').replace('"', '_').replace(',', '_').replace('[', '_').replace(']', '_').replace(' ', '_');