673018ed8fd8f765e952a0ed9d6a354e851558c1
[Mograsim.git] / plugins / net.mograsim.logic.model.verilog / src / net / mograsim / logic / model / verilog / converter / ModelComponentToVerilogConverter.java
1 package net.mograsim.logic.model.verilog.converter;
2
3 import java.util.ArrayList;
4 import java.util.Collection;
5 import java.util.HashMap;
6 import java.util.HashSet;
7 import java.util.List;
8 import java.util.Map;
9 import java.util.Map.Entry;
10 import java.util.Set;
11 import java.util.function.BiFunction;
12 import java.util.function.Function;
13 import java.util.stream.Collectors;
14
15 import com.google.gson.JsonElement;
16
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;
43
44 public class ModelComponentToVerilogConverter
45 {
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;
50
51         public ModelComponentToVerilogConverter(String verilogComponentIDPrefix,
52                         Set<ModelComponentToVerilogComponentDeclarationMapping> atomicComponentMappings)
53         {
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);
63         }
64
65         private void convert(ModelComponent modelComponent)
66         {
67                 // these are handled elsewhere
68                 if (modelComponent instanceof ModelSplitter || modelComponent instanceof ModelWireCrossPoint)
69                         return;
70
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
75                         return;
76
77                 String verilogID = verilogComponentIDGen.generateID(verilogComponentIDPrefix + modelID + (params.isJsonNull() ? "" : "_" + params));
78
79                 // TODO don't rely on instanceof
80                 if (modelComponent instanceof SubmodelComponent)
81                         convertSubmodelComponent((SubmodelComponent) modelComponent, modelID, params, verilogID);
82                 else
83                         throw new IllegalArgumentException(
84                                         "Can only convert SubmodelComponents, tried to convert " + modelID + " with params " + params);
85         }
86
87         private void convertSubmodelComponent(SubmodelComponent modelComponent, String modelID, JsonElement params, String verilogID)
88         {
89                 for (ModelComponent subcomponent : modelComponent.submodel.getComponentsByName().values())
90                         if (!subcomponent.getName().equals(SubmodelComponent.SUBMODEL_INTERFACE_NAME))
91                                 convert(subcomponent);
92
93                 UnionFind<PinBit> connectedPins = findConnectedPins(modelComponent);
94
95                 ModelComponentToVerilogComponentDeclarationMapping mapping = mapDeclaration(modelComponent, connectedPins, modelID, params,
96                                 verilogID);
97                 componentMappingsPerModelIDPerParams.computeIfAbsent(modelID, i -> new HashMap<>()).put(params, mapping);
98
99                 verilogComponents.add(mapImplementation(modelComponent, connectedPins, mapping));
100         }
101
102         private UnionFind<PinBit> findConnectedPins(SubmodelComponent modelComponent)
103         {
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));
108
109                 for (ModelComponent subcomponent : modelComponent.submodel.getComponentsByName().values())
110                         if (subcomponent instanceof ModelSplitter)
111                         {
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))
117                         {
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()));
121                         }
122
123                 return connectedPins;
124         }
125
126         private static ModelComponentToVerilogComponentDeclarationMapping mapDeclaration(SubmodelComponent modelComponent,
127                         UnionFind<PinBit> connectedPins, String modelID, JsonElement params, String verilogID)
128         {
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++)
134                         {
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);
138                         }
139
140                 return generateCanonicalDeclarationMapping(modelComponent, connectedPinsByName, modelID, params, verilogID);
141         }
142
143         public static ModelComponentToVerilogComponentDeclarationMapping generateCanonicalDeclarationMapping(ModelComponent modelComponent,
144                         UnionFind<PinNameBit> connectedPins, String modelID, JsonElement params, String verilogID)
145         {
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++)
153                         {
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");
158                         }
159
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);
164         }
165
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)
169         {
170                 Map<PinNameBit, VerilogEmulatedModelPinBuilder> pinMappingCorrectType = pinMapping.get(type);
171                 pinMappingCorrectType.computeIfAbsent(connectedPins.find(pinbit), p ->
172                 {
173                         String portID = ioPortIDGen.generateID(p.getName() + "_" + p.getBit() + "_" + suffix);
174                         IOPort ioPort = constr.apply(portID, 2);
175                         int index = ioPorts.size();
176                         ioPorts.add(ioPort);
177                         return new VerilogEmulatedModelPinBuilder(ioPort, index, type);
178                 }).addPinbit(pinbit);
179         }
180
181         private static class VerilogEmulatedModelPinBuilder
182         {
183                 private final IOPort verilogPort;
184                 private final int portIndex;
185                 private final Set<PinNameBit> pinbits;
186                 private final Type type;
187
188                 public VerilogEmulatedModelPinBuilder(IOPort verilogPort, int portIndex, Type type)
189                 {
190                         this.verilogPort = verilogPort;
191                         this.portIndex = portIndex;
192                         this.pinbits = new HashSet<>();
193                         this.type = type;
194                 }
195
196                 public void addPinbit(PinNameBit pinbit)
197                 {
198                         pinbits.add(pinbit);
199                 }
200
201                 public VerilogEmulatedModelPin build()
202                 {
203                         return new VerilogEmulatedModelPin(verilogPort, portIndex, pinbits, type);
204                 }
205         }
206
207         private VerilogComponentImplementation mapImplementation(SubmodelComponent modelComponent, UnionFind<PinBit> connectedPins,
208                         ModelComponentToVerilogComponentDeclarationMapping declarationMapping)
209         {
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())
214                 {
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());
220                 }
221
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())
227                 {
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))
231                                 continue;
232
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++)
238                                 arguments.add(null);
239                         for (Pin pin : subcomponent.getPins().values())
240                                 for (int bit = 0; bit < pin.logicWidth; bit++)
241                                 {
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)
249                                         {
250                                                 preSignal = new Constant(BitVector.of(Bit.ZERO, 2));
251                                                 Wire resWire = new Wire(idGen.generateID(subcomponentVerilogName + "_" + pin.name + "_" + bit + "_res"), 2);
252                                                 resSignal = resWire;
253                                                 statements.add(new WireDeclaration(resWire));
254                                                 finalOutSignals.put(root, resWire);
255                                                 resSignals.put(root, resWire);
256                                         }
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);
261                                 }
262                         statements
263                                         .add(new ComponentReference(subcomponentVerilogName, subcomponentMapping.getVerilogComponentDeclaration(), arguments));
264                 }
265
266                 for (Entry<PinBit, NamedSignal> e : finalOutSignals.entrySet())
267                         statements.add(new Assign(e.getValue(), new SignalReference(currentPreSignals.get(e.getKey()))));
268
269                 return new VerilogComponentImplementation(declarationMapping.getVerilogComponentDeclaration(), statements);
270         }
271
272         private ModelComponentToVerilogComponentDeclarationMapping getComponentMapping(ModelComponent component)
273         {
274                 ModelComponentToVerilogComponentDeclarationMapping subcomponentMapping = componentMappingsPerModelIDPerParams
275                                 .get(component.getIDForSerializing(new IdentifyParams())).get(component.getParamsForSerializingJSON(new IdentifyParams()));
276                 return subcomponentMapping;
277         }
278
279         private Set<VerilogComponentImplementation> getVerilogComponents()
280         {
281                 return verilogComponents;
282         }
283
284         public static Set<VerilogComponentImplementation> convert(
285                         Set<ModelComponentToVerilogComponentDeclarationMapping> atomicComponentMappings, Set<ModelComponent> components,
286                         String verilogComponentIDPrefix)
287         {
288                 ModelComponentToVerilogConverter converter = new ModelComponentToVerilogConverter(verilogComponentIDPrefix,
289                                 atomicComponentMappings);
290                 for (ModelComponent modelComponent : components)
291                         converter.convert(modelComponent);
292                 return converter.getVerilogComponents();
293         }
294
295         public static String sanitizeVerilogID(String id)
296         {
297                 return (id.matches("[0-9].*") ? "_" + id : id).replaceAll("[^A-Za-z0-9_]", "_");
298         }
299 }