1 package net.mograsim.logic.model.verilog.converter;
3 import java.util.ArrayList;
4 import java.util.Collection;
5 import java.util.HashMap;
6 import java.util.HashSet;
9 import java.util.Map.Entry;
11 import java.util.function.BiFunction;
12 import java.util.function.Function;
13 import java.util.stream.Collectors;
15 import com.google.gson.JsonElement;
17 import net.mograsim.logic.core.types.Bit;
18 import net.mograsim.logic.core.types.BitVector;
19 import net.mograsim.logic.model.model.components.ModelComponent;
20 import net.mograsim.logic.model.model.components.atomic.ModelSplitter;
21 import net.mograsim.logic.model.model.components.submodels.SubmodelComponent;
22 import net.mograsim.logic.model.model.wires.ModelWire;
23 import net.mograsim.logic.model.model.wires.ModelWireCrossPoint;
24 import net.mograsim.logic.model.model.wires.Pin;
25 import net.mograsim.logic.model.serializing.IdentifyParams;
26 import net.mograsim.logic.model.verilog.converter.VerilogEmulatedModelPin.Type;
27 import net.mograsim.logic.model.verilog.model.VerilogComponentDeclaration;
28 import net.mograsim.logic.model.verilog.model.VerilogComponentImplementation;
29 import net.mograsim.logic.model.verilog.model.expressions.SignalReference;
30 import net.mograsim.logic.model.verilog.model.signals.Constant;
31 import net.mograsim.logic.model.verilog.model.signals.IOPort;
32 import net.mograsim.logic.model.verilog.model.signals.Input;
33 import net.mograsim.logic.model.verilog.model.signals.NamedSignal;
34 import net.mograsim.logic.model.verilog.model.signals.Output;
35 import net.mograsim.logic.model.verilog.model.signals.Signal;
36 import net.mograsim.logic.model.verilog.model.signals.Wire;
37 import net.mograsim.logic.model.verilog.model.statements.Assign;
38 import net.mograsim.logic.model.verilog.model.statements.ComponentReference;
39 import net.mograsim.logic.model.verilog.model.statements.Statement;
40 import net.mograsim.logic.model.verilog.model.statements.WireDeclaration;
41 import net.mograsim.logic.model.verilog.utils.IdentifierGenerator;
42 import net.mograsim.logic.model.verilog.utils.UnionFind;
44 public class ModelComponentToVerilogConverter
46 private final String verilogComponentIDPrefix;
47 private final Map<String, Map<JsonElement, ModelComponentToVerilogComponentDeclarationMapping>> componentMappingsPerModelIDPerParams;
48 private final Set<VerilogComponentImplementation> verilogComponents;
49 private final IdentifierGenerator verilogComponentIDGen;
51 public ModelComponentToVerilogConverter(String verilogComponentIDPrefix,
52 Set<ModelComponentToVerilogComponentDeclarationMapping> atomicComponentMappings)
54 this.verilogComponentIDPrefix = verilogComponentIDPrefix;
55 this.componentMappingsPerModelIDPerParams = new HashMap<>(atomicComponentMappings.stream().collect(Collectors
56 .groupingBy(m -> m.getModelComponentID(), Collectors.toMap(m -> m.getModelComponentParams(), Function.identity()))));
57 this.verilogComponents = new HashSet<>();
58 this.verilogComponentIDGen = new IdentifierGenerator(
59 componentMappingsPerModelIDPerParams.values().stream().map(Map::values).flatMap(Collection::stream)
60 .map(ModelComponentToVerilogComponentDeclarationMapping::getVerilogComponentDeclaration)
61 .map(VerilogComponentDeclaration::getID).collect(Collectors.toSet()),
62 ModelComponentToVerilogConverter::sanitizeVerilogID);
65 private void convert(ModelComponent modelComponent)
67 // these are handled elsewhere
68 if (modelComponent instanceof ModelSplitter || modelComponent instanceof ModelWireCrossPoint)
71 String modelID = modelComponent.getIDForSerializing(new IdentifyParams());
72 JsonElement params = modelComponent.getParamsForSerializingJSON(new IdentifyParams());
73 if (componentMappingsPerModelIDPerParams.getOrDefault(modelID, Map.of()).containsKey(params))
74 // we already converted that component, or it was specified externally
77 String verilogID = verilogComponentIDGen.generateID(verilogComponentIDPrefix + modelID + (params.isJsonNull() ? "" : "_" + params));
79 // TODO don't rely on instanceof
80 if (modelComponent instanceof SubmodelComponent)
81 convertSubmodelComponent((SubmodelComponent) modelComponent, modelID, params, verilogID);
83 throw new IllegalArgumentException(
84 "Can only convert SubmodelComponents, tried to convert " + modelID + " with params " + params);
87 private void convertSubmodelComponent(SubmodelComponent modelComponent, String modelID, JsonElement params, String verilogID)
89 for (ModelComponent subcomponent : modelComponent.submodel.getComponentsByName().values())
90 if (!subcomponent.getName().equals(SubmodelComponent.SUBMODEL_INTERFACE_NAME))
91 convert(subcomponent);
93 UnionFind<PinBit> connectedPins = findConnectedPins(modelComponent);
95 ModelComponentToVerilogComponentDeclarationMapping mapping = mapDeclaration(modelComponent, connectedPins, modelID, params,
97 componentMappingsPerModelIDPerParams.computeIfAbsent(modelID, i -> new HashMap<>()).put(params, mapping);
99 verilogComponents.add(mapImplementation(modelComponent, connectedPins, mapping));
102 private UnionFind<PinBit> findConnectedPins(SubmodelComponent modelComponent)
104 UnionFind<PinBit> connectedPins = new UnionFind<>();
105 for (ModelWire w : modelComponent.submodel.getWiresByName().values())
106 for (int bit = 0; bit < w.getPin1().logicWidth; bit++)
107 connectedPins.union(new PinBit(w.getPin1(), bit), new PinBit(w.getPin2(), bit));
109 for (ModelComponent subcomponent : modelComponent.submodel.getComponentsByName().values())
110 if (subcomponent instanceof ModelSplitter)
112 ModelSplitter splitter = (ModelSplitter) subcomponent;
113 for (int bit = 0; bit < splitter.logicWidth; bit++)
114 connectedPins.union(new PinBit(splitter.getInputPin(), bit), new PinBit(splitter.getOutputPin(bit), 0));
115 } else if (!(subcomponent instanceof ModelWireCrossPoint)
116 && !subcomponent.getName().equals(SubmodelComponent.SUBMODEL_INTERFACE_NAME))
118 ModelComponentToVerilogComponentDeclarationMapping subcomponentMapping = getComponentMapping(subcomponent);
119 for (Set<PinNameBit> connected : subcomponentMapping.getInternallyConnectedPins())
120 connectedPins.unionAll(connected.stream().map(p -> p.toPinBit(subcomponent)).collect(Collectors.toList()));
123 return connectedPins;
126 private static ModelComponentToVerilogComponentDeclarationMapping mapDeclaration(SubmodelComponent modelComponent,
127 UnionFind<PinBit> connectedPins, String modelID, JsonElement params, String verilogID)
129 // TODO this is probably slow
130 Map<PinBit, PinNameBit> representantMapping = new HashMap<>();
131 UnionFind<PinNameBit> connectedPinsByName = new UnionFind<>();
132 for (Pin p : modelComponent.getSubmodelPins().values())
133 for (int bit = 0; bit < p.logicWidth; bit++)
135 PinNameBit pinnamebit = new PinNameBit(p.name, bit);
136 PinNameBit representative = representantMapping.computeIfAbsent(connectedPins.find(new PinBit(p, bit)), q -> pinnamebit);
137 connectedPinsByName.union(pinnamebit, representative);
140 return generateCanonicalDeclarationMapping(modelComponent, connectedPinsByName, modelID, params, verilogID);
143 public static ModelComponentToVerilogComponentDeclarationMapping generateCanonicalDeclarationMapping(ModelComponent modelComponent,
144 UnionFind<PinNameBit> connectedPins, String modelID, JsonElement params, String verilogID)
146 IdentifierGenerator ioPortIDGen = new IdentifierGenerator(ModelComponentToVerilogConverter::sanitizeVerilogID);
147 List<IOPort> ioPorts = new ArrayList<>();
148 Map<Type, Map<PinNameBit, VerilogEmulatedModelPinBuilder>> pinMapping = new HashMap<>();
149 for (Type t : Type.values())
150 pinMapping.put(t, new HashMap<>());
151 for (Pin modelPin : modelComponent.getPins().values())
152 for (int bit = 0; bit < modelPin.logicWidth; bit++)
154 PinNameBit pinbit = new PinNameBit(modelPin.name, bit);
155 addPinMapping(ioPortIDGen, ioPorts, connectedPins, pinMapping, pinbit, Input::new, Type.PRE, "pre");
156 addPinMapping(ioPortIDGen, ioPorts, connectedPins, pinMapping, pinbit, Output::new, Type.OUT, "out");
157 addPinMapping(ioPortIDGen, ioPorts, connectedPins, pinMapping, pinbit, Input::new, Type.RES, "res");
160 VerilogComponentDeclaration declaration = new VerilogComponentDeclaration(verilogID, ioPorts);
161 Set<VerilogEmulatedModelPin> finalPinMapping = pinMapping.values().stream().map(Map::values).flatMap(Collection::stream)
162 .map(VerilogEmulatedModelPinBuilder::build).collect(Collectors.toSet());
163 return new ModelComponentToVerilogComponentDeclarationMapping(modelID, params, declaration, finalPinMapping);
166 private static void addPinMapping(IdentifierGenerator ioPortIDGen, List<IOPort> ioPorts, UnionFind<PinNameBit> connectedPins,
167 Map<Type, Map<PinNameBit, VerilogEmulatedModelPinBuilder>> pinMapping, PinNameBit pinbit,
168 BiFunction<String, Integer, IOPort> constr, Type type, String suffix)
170 Map<PinNameBit, VerilogEmulatedModelPinBuilder> pinMappingCorrectType = pinMapping.get(type);
171 pinMappingCorrectType.computeIfAbsent(connectedPins.find(pinbit), p ->
173 String portID = ioPortIDGen.generateID(p.getName() + "_" + p.getBit() + "_" + suffix);
174 IOPort ioPort = constr.apply(portID, 2);
175 int index = ioPorts.size();
177 return new VerilogEmulatedModelPinBuilder(ioPort, index, type);
178 }).addPinbit(pinbit);
181 private static class VerilogEmulatedModelPinBuilder
183 private final IOPort verilogPort;
184 private final int portIndex;
185 private final Set<PinNameBit> pinbits;
186 private final Type type;
188 public VerilogEmulatedModelPinBuilder(IOPort verilogPort, int portIndex, Type type)
190 this.verilogPort = verilogPort;
191 this.portIndex = portIndex;
192 this.pinbits = new HashSet<>();
196 public void addPinbit(PinNameBit pinbit)
201 public VerilogEmulatedModelPin build()
203 return new VerilogEmulatedModelPin(verilogPort, portIndex, pinbits, type);
207 private VerilogComponentImplementation mapImplementation(SubmodelComponent modelComponent, UnionFind<PinBit> connectedPins,
208 ModelComponentToVerilogComponentDeclarationMapping declarationMapping)
210 Map<PinBit, Signal> currentPreSignals = new HashMap<>();
211 Map<PinBit, NamedSignal> finalOutSignals = new HashMap<>();
212 Map<PinBit, NamedSignal> resSignals = new HashMap<>();
213 for (Set<PinNameBit> connectedPinGroup : declarationMapping.getInternallyConnectedPins())
215 PinNameBit pinnamebit = connectedPinGroup.iterator().next();
216 PinBit root = connectedPins.find(pinnamebit.toSubmodelPinBit(modelComponent));
217 resSignals.put(root, declarationMapping.getResPinMapping().get(pinnamebit).getVerilogPort());
218 finalOutSignals.put(root, declarationMapping.getOutPinMapping().get(pinnamebit).getVerilogPort());
219 currentPreSignals.put(root, declarationMapping.getPrePinMapping().get(pinnamebit).getVerilogPort());
222 IdentifierGenerator idGen = new IdentifierGenerator(
223 declarationMapping.getVerilogComponentDeclaration().getIOPorts().stream().map(IOPort::getName).collect(Collectors.toList()),
224 ModelComponentToVerilogConverter::sanitizeVerilogID);
225 List<Statement> statements = new ArrayList<>();
226 for (ModelComponent subcomponent : modelComponent.submodel.getComponentsByName().values())
228 // TODO do we really want to use instanceof?
229 if (subcomponent instanceof ModelSplitter || subcomponent instanceof ModelWireCrossPoint
230 || subcomponent.getName().equals(SubmodelComponent.SUBMODEL_INTERFACE_NAME))
233 String subcomponentVerilogName = idGen.generateID(subcomponent.getName());
234 ModelComponentToVerilogComponentDeclarationMapping subcomponentMapping = getComponentMapping(subcomponent);
235 int parameterCount = subcomponentMapping.getVerilogComponentDeclaration().getIOPorts().size();
236 List<Signal> arguments = new ArrayList<>(parameterCount);
237 for (int i = 0; i < parameterCount; i++)
239 for (Pin pin : subcomponent.getPins().values())
240 for (int bit = 0; bit < pin.logicWidth; bit++)
242 PinBit pinbit = new PinBit(pin, bit);
243 PinBit root = connectedPins.find(pinbit);
244 Wire outSignal = new Wire(idGen.generateID(subcomponentVerilogName + "_" + pin.name + "_" + bit), 2);
245 statements.add(new WireDeclaration(outSignal));
246 Signal preSignal = currentPreSignals.put(root, outSignal);
247 Signal resSignal = resSignals.get(root);
248 if (resSignal == null)
250 preSignal = new Constant(BitVector.of(Bit.ZERO, 2));
251 Wire resWire = new Wire(idGen.generateID(subcomponentVerilogName + "_" + pin.name + "_" + bit + "_res"), 2);
253 statements.add(new WireDeclaration(resWire));
254 finalOutSignals.put(root, resWire);
255 resSignals.put(root, resWire);
257 PinNameBit pinnamebit = pinbit.toPinNameBit();
258 arguments.set(subcomponentMapping.getPrePinMapping().get(pinnamebit).getPortIndex(), preSignal);
259 arguments.set(subcomponentMapping.getOutPinMapping().get(pinnamebit).getPortIndex(), outSignal);
260 arguments.set(subcomponentMapping.getResPinMapping().get(pinnamebit).getPortIndex(), resSignal);
263 .add(new ComponentReference(subcomponentVerilogName, subcomponentMapping.getVerilogComponentDeclaration(), arguments));
266 for (Entry<PinBit, NamedSignal> e : finalOutSignals.entrySet())
267 statements.add(new Assign(e.getValue(), new SignalReference(currentPreSignals.get(e.getKey()))));
269 return new VerilogComponentImplementation(declarationMapping.getVerilogComponentDeclaration(), statements);
272 private ModelComponentToVerilogComponentDeclarationMapping getComponentMapping(ModelComponent component)
274 ModelComponentToVerilogComponentDeclarationMapping subcomponentMapping = componentMappingsPerModelIDPerParams
275 .get(component.getIDForSerializing(new IdentifyParams())).get(component.getParamsForSerializingJSON(new IdentifyParams()));
276 return subcomponentMapping;
279 private Set<VerilogComponentImplementation> getVerilogComponents()
281 return verilogComponents;
284 public static Set<VerilogComponentImplementation> convert(
285 Set<ModelComponentToVerilogComponentDeclarationMapping> atomicComponentMappings, Set<ModelComponent> components,
286 String verilogComponentIDPrefix)
288 ModelComponentToVerilogConverter converter = new ModelComponentToVerilogConverter(verilogComponentIDPrefix,
289 atomicComponentMappings);
290 for (ModelComponent modelComponent : components)
291 converter.convert(modelComponent);
292 return converter.getVerilogComponents();
295 public static String sanitizeVerilogID(String id)
297 return (id.matches("[0-9].*") ? "_" + id : id).replaceAll("[^A-Za-z0-9_]", "_");