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;
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;
35 //TODO clean this mess
36 public class VerilogExporter
38 private static final String COMPONENT_PREFIX = "mgs_";
40 public static void main(String[] args) throws IOException
43 try (Scanner sysin = new Scanner(System.in))
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");
52 System.out.print("Component ID to serialize recursively >");
53 String rootComponentID = sysin.nextLine();
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);
71 private static Map<String, SubmodelComponentParams> readComponentIncludingDependencies(String rootComponentID)
73 Map<String, SubmodelComponentParams> result = new HashMap<>();
74 readComponentIncludingDependenciesRecursively(rootComponentID, null, result);
78 private static void readComponentIncludingDependenciesRecursively(String id, JsonElement params,
79 Map<String, SubmodelComponentParams> result)
81 if (result.containsKey(id))
84 ModelComponent component = IndirectModelComponentCreator.createComponent(new LogicModelModifiable(), id, params);
85 if (component instanceof SubmodelComponent)
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);
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)
97 Map<String, Map<String, Set<String>>> connectedInnerPinNamesPerComponentID = new HashMap<>();
99 generateConnectedInnerPins(componentsById, pinIdentifierGeneratorsPerComponentID, connectedInnerPinNamesPerComponentID);
101 Map<String, Map<String, String>> combinedInterfacePinNamesPerComponentID = new HashMap<>();
103 for (boolean anyChange = true; anyChange;)
106 for (Entry<String, SubmodelComponentParams> e : componentsById.entrySet())
107 anyChange |= checkForConnectedPins(e.getKey(), e.getValue(), componentsById, pinIdentifierGeneratorsPerComponentID,
108 connectedInnerPinNamesPerComponentID, combinedInterfacePinNamesPerComponentID);
111 return new Tuple2<>(combinedInterfacePinNamesPerComponentID, connectedInnerPinNamesPerComponentID);
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)
119 PinIdentifierGenerator pinIdentifierGenerator = pinIdentifierGeneratorsPerComponentID.get(componentID);
120 Map<String, Set<String>> connectedInnerPinNames = connectedInnerPinNamesPerComponentID.get(componentID);
121 Map<String, String> pinNameRemapping = combinedPinNamesPerComponentID.computeIfAbsent(componentID, k ->
123 Map<String, String> result = new HashMap<>();
124 for (InterfacePinParams pinParams : componentJson.interfacePins)
125 result.put(pinParams.name, pinParams.name);
129 for (InterfacePinParams pin1Params : componentJson.interfacePins)
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)
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))
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);
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)
158 for (Entry<String, SubmodelComponentParams> e : componentsById.entrySet())
160 String superComponentID = e.getKey();
161 SubmodelComponentParams superComponentJson = e.getValue();
163 PinIdentifierGenerator pinIdentifierGenerator = pinIdentifierGeneratorsPerComponentID.get(superComponentID);
164 Map<String, Set<String>> connectedPinNames = connectedInnerPinNamesPerComponentID.get(superComponentID);
166 for (ComponentParams subcomponentParams : superComponentJson.submodel.components)
167 if (subcomponentParams.id.equals(componentID))
169 String pin1ID = pinIdentifierGenerator.getPinID(subcomponentParams.name, pin1Name);
170 String pin2ID = pinIdentifierGenerator.getPinID(subcomponentParams.name, pin2Name);
172 Set<String> connectedPinNamesPin1 = connectedPinNames.get(pin1ID);
173 Set<String> connectedPinNamesPin2 = connectedPinNames.get(pin2ID);
175 if (connectedPinNamesPin2 != null)
177 connectedPinNamesPin2.remove(pin2ID);
178 if (connectedPinNamesPin1 != null)
180 connectedPinNamesPin2.addAll(connectedPinNamesPin1);
181 for (String pinNameToRewriteMapping : connectedPinNamesPin1)
182 connectedPinNames.put(pinNameToRewriteMapping, connectedPinNamesPin2);
189 private static void generateConnectedInnerPins(Map<String, SubmodelComponentParams> componentsById,
190 Map<String, PinIdentifierGenerator> pinIdentifierGeneratorsPerComponentID,
191 Map<String, Map<String, Set<String>>> connectedInnerPinNamesPerComponentID)
193 for (Entry<String, SubmodelComponentParams> e : componentsById.entrySet())
195 String componentID = e.getKey();
196 SubmodelComponentParams componentJson = e.getValue();
198 PinIdentifierGenerator pinIdentifierGenerator = new PinIdentifierGenerator();
199 Map<String, Set<String>> connectedInnerPinNames = new HashMap<>();
200 pinIdentifierGeneratorsPerComponentID.put(componentID, pinIdentifierGenerator);
201 connectedInnerPinNamesPerComponentID.put(componentID, connectedInnerPinNames);
203 for (WireParams wireJson : componentJson.submodel.wires)
205 String pin1Name = pinIdentifierGenerator.getPinID(wireJson.pin1);
206 String pin2Name = pinIdentifierGenerator.getPinID(wireJson.pin2);
208 Set<String> oldConnectedPins1 = connectedInnerPinNames.get(pin1Name);
209 Set<String> oldConnectedPins2 = connectedInnerPinNames.get(pin2Name);
211 if (oldConnectedPins1 == null)
212 oldConnectedPins1 = Set.of(pin1Name);
213 if (oldConnectedPins2 == null)
215 oldConnectedPins2 = new HashSet<>(Arrays.asList(pin2Name));
216 connectedInnerPinNames.put(pin2Name, oldConnectedPins2);
219 oldConnectedPins2.addAll(oldConnectedPins1);
220 for (String pinNameToRewriteMapping : oldConnectedPins1)
221 connectedInnerPinNames.put(pinNameToRewriteMapping, oldConnectedPins2);
226 private static Map<String, Tuple2<List<String>, List<Integer>>> generateSortedInterfacePinNamesAndWidthesPerComponentID(
227 Map<String, SubmodelComponentParams> componentsById, Map<String, Map<String, String>> combinedInterfacePinsPerComponentID)
229 return combinedInterfacePinsPerComponentID.entrySet().stream().collect(Collectors.toMap(Entry::getKey, e ->
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);
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)
244 componentsById.forEach((componentID, componentJson) ->
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());
257 catch (IOException e)
259 throw new UncheckedIOException(e);
264 private final String componentID;
265 private final SubmodelComponentParams componentJson;
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;
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)
277 this.componentID = componentID;
278 this.componentJson = componentJson;
280 this.pinIdentifierGenerator = pinIdentifierGeneratorsPerComponentID.get(componentID);
281 this.combinedInnerPinNames = combinedPinNames.e2.get(componentID);
282 this.sortedInterfacePinNames = sortedInterfacePinNamesAndWidthsPerComponentID.get(componentID).e1;
283 this.sortedInterfacePinNamesAndWidthsPerComponentID = sortedInterfacePinNamesAndWidthsPerComponentID;
286 public String generateVerilog()
288 StringBuilder result = new StringBuilder();
290 result.append("module ");
291 result.append(COMPONENT_PREFIX);
292 result.append(sanitizeVerilog(componentID));
295 appendInterface(result);
296 result.append(");\n\n");
298 appendComponents(result);
300 result.append("endmodule\n");
302 return result.toString();
305 private void appendInterface(StringBuilder result)
307 if (!sortedInterfacePinNames.isEmpty())
309 Map<String, Integer> logicWidthsPerInterfacePinName = Arrays.stream(componentJson.interfacePins)
310 .collect(Collectors.toMap(p -> p.name, p -> p.logicWidth));
312 for (int i = 0; i < sortedInterfacePinNames.size(); i++)
314 String interfacePinName = sortedInterfacePinNames.get(i);
315 int logicWidth = logicWidthsPerInterfacePinName.get(interfacePinName);
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)
334 private void appendComponents(StringBuilder result)
336 Map<Set<String>, String> currentWireNamePerCombinedInnerPinNames = new HashMap<>();
337 Map<Set<String>, String> resultWireNamePerCombinedInnerPinNames = new HashMap<>();
338 for (Set<String> s : combinedInnerPinNames.values())
340 currentWireNamePerCombinedInnerPinNames.put(s, "2'b00");
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);
347 for (String interfacePinName : sortedInterfacePinNames)
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");
355 for (ComponentParams subcomponentParams : componentJson.submodel.components)
356 appendComponent(result, currentWireNamePerCombinedInnerPinNames, resultWireNamePerCombinedInnerPinNames, subcomponentParams);
358 for (String interfacePinName : sortedInterfacePinNames)
360 String innerPinID = pinIdentifierGenerator.getPinID(SubmodelComponent.SUBMODEL_INTERFACE_NAME, interfacePinName);
361 Set<String> connectedPins = combinedInnerPinNames.get(innerPinID);
362 String lastWireName = currentWireNamePerCombinedInnerPinNames.remove(connectedPins);
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");
371 for (Set<String> s : currentWireNamePerCombinedInnerPinNames.keySet())
373 String lastWireName = currentWireNamePerCombinedInnerPinNames.get(s);
374 String resultWireName = resultWireNamePerCombinedInnerPinNames.get(s);
376 result.append("wire ");
378 outer: for (ComponentParams subcomponentJson : componentJson.submodel.components)
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))))
387 logicWidth = subcomponentInterfacePinWidths.get(i);
391 appendLogicWidth(result, logicWidth);
392 result.append(sanitizeVerilog(resultWireName));
393 result.append(";\n");
395 result.append("assign ");
396 result.append(sanitizeVerilog(resultWireName));
397 result.append(" = ");
398 result.append(sanitizeVerilog(lastWireName));
399 result.append(";\n");
403 private void appendComponent(StringBuilder result, Map<Set<String>, String> currentWireNamePerCombinedInnerPinNames,
404 Map<Set<String>, String> resultWireNamePerCombinedInnerPinNames, ComponentParams subcomponentParams)
407 String subcomponentID = subcomponentParams.id;
408 String subcomponentName = subcomponentParams.name;
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++)
416 result.append("wire ");
417 appendLogicWidth(result, subcomponentInterfacePinWidths.get(i));
418 result.append(pinIdentifierGenerator.getPinID(subcomponentName, subcomponentInterfacePinNames.get(i)));
419 result.append(";\n");
422 result.append(COMPONENT_PREFIX);
423 result.append(sanitizeVerilog(subcomponentID + subcomponentParams.params));
425 for (int i = 0; i < subcomponentInterfacePinNames.size(); i++)
427 String innerPinID = pinIdentifierGenerator.getPinID(subcomponentName, subcomponentInterfacePinNames.get(i));
430 String nextWireName = innerPinID;
431 String resultWireName;
432 Set<String> combinedInnerPinsGroup = combinedInnerPinNames.get(innerPinID);
433 if (combinedInnerPinsGroup != null)
435 lastWireName = currentWireNamePerCombinedInnerPinNames.get(combinedInnerPinsGroup);
436 resultWireName = resultWireNamePerCombinedInnerPinNames.get(combinedInnerPinsGroup);
438 currentWireNamePerCombinedInnerPinNames.put(combinedInnerPinsGroup, nextWireName);
441 lastWireName = "2'b00";
442 resultWireName = nextWireName;
445 result.append(sanitizeVerilog(lastWireName));
447 result.append(sanitizeVerilog(nextWireName));
449 result.append(sanitizeVerilog(resultWireName));
450 if (i != subcomponentInterfacePinNames.size() - 1)
451 result.append(", \n ");
453 result.append(");\n\n");
457 private Tuple2<List<String>, List<Integer>> getSubcomponentInterfacePinNamesAndWidths(String subcomponentID,
458 JsonElement subcomponentParams)
460 Tuple2<List<String>, List<Integer>> result = sortedInterfacePinNamesAndWidthsPerComponentID.get(subcomponentID);
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);
473 private static void appendLogicWidth(StringBuilder result, int logicWidth)
476 String logicWidthStr = Integer.toString(logicWidth * 2 - 1);
477 for (int spaces = logicWidthStr.length(); spaces < 3; spaces++)
479 result.append(logicWidthStr);
480 result.append(":0] ");
483 private static class PinIdentifierGenerator
485 private final Map<String, Map<String, String>> wireNamesPerPinAndComponentName;
486 private final Set<String> usedWireNames;
488 public PinIdentifierGenerator()
490 wireNamesPerPinAndComponentName = new HashMap<>();
491 usedWireNames = new HashSet<>();
494 private String getPinID(PinParams pin)
496 return getPinID(pin.compName, pin.pinName);
499 private String getPinID(String component, String pin)
501 String componentSan = sanitizeVerilog(component);
502 String pinSan = sanitizeVerilog(pin);
504 Map<String, String> wireNamesPerPinName = wireNamesPerPinAndComponentName.computeIfAbsent(componentSan, k -> new HashMap<>());
506 if (wireNamesPerPinName.containsKey(pinSan))
507 return wireNamesPerPinName.get(pinSan);
509 String baseName = componentSan + '_' + pinSan;
511 if (usedWireNames.add(baseName))
512 combinedName = baseName;
517 combinedName = baseName + "#" + i++;
518 while (!usedWireNames.add(combinedName));
520 wireNamesPerPinName.put(pinSan, combinedName);
525 private static class Tuple2<E1, E2>
530 public Tuple2(E1 e1, E2 e2)
537 private static String sanitizeVerilog(String str)
539 return str.replace('#', '_').replace('+', '_').replace('-', '_').replace('=', '_').replace('{', '_').replace('}', '_')
540 .replace(':', '_').replace('"', '_').replace(',', '_').replace('[', '_').replace(']', '_').replace(' ', '_');