b7e87723a07e467422f8139455944b7fd577be0c
[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.Pin;
24 import net.mograsim.logic.model.serializing.IdentifyParams;
25 import net.mograsim.logic.model.verilog.converter.VerilogEmulatedModelPin.Type;
26 import net.mograsim.logic.model.verilog.helper.IdentifierGenerator;
27 import net.mograsim.logic.model.verilog.helper.UnionFind;
28 import net.mograsim.logic.model.verilog.model.Assign;
29 import net.mograsim.logic.model.verilog.model.ComponentReference;
30 import net.mograsim.logic.model.verilog.model.Constant;
31 import net.mograsim.logic.model.verilog.model.IOPort;
32 import net.mograsim.logic.model.verilog.model.Input;
33 import net.mograsim.logic.model.verilog.model.NamedSignal;
34 import net.mograsim.logic.model.verilog.model.Output;
35 import net.mograsim.logic.model.verilog.model.Signal;
36 import net.mograsim.logic.model.verilog.model.VerilogComponentDeclaration;
37 import net.mograsim.logic.model.verilog.model.VerilogComponentImplementation;
38 import net.mograsim.logic.model.verilog.model.Wire;
39
40 public class ModelComponentToVerilogConverter
41 {
42         private final String verilogComponentIDPrefix;
43         private final Map<String, Map<JsonElement, ModelComponentToVerilogComponentDeclarationMapping>> componentMappingsPerModelIDPerParams;
44         private final Set<VerilogComponentImplementation> verilogComponents;
45         private final IdentifierGenerator verilogComponentIDGen;
46
47         public ModelComponentToVerilogConverter(String verilogComponentIDPrefix,
48                         Set<ModelComponentToVerilogComponentDeclarationMapping> atomicComponentMappings)
49         {
50                 this.verilogComponentIDPrefix = verilogComponentIDPrefix;
51                 this.componentMappingsPerModelIDPerParams = new HashMap<>(atomicComponentMappings.stream().collect(Collectors
52                                 .groupingBy(m -> m.getModelComponentID(), Collectors.toMap(m -> m.getModelComponentParams(), Function.identity()))));
53                 this.verilogComponents = new HashSet<>();
54                 this.verilogComponentIDGen = new IdentifierGenerator(
55                                 componentMappingsPerModelIDPerParams.values().stream().map(Map::values).flatMap(Collection::stream)
56                                                 .map(ModelComponentToVerilogComponentDeclarationMapping::getVerilogComponentDeclaration)
57                                                 .map(VerilogComponentDeclaration::getID).collect(Collectors.toSet()),
58                                 ModelComponentToVerilogConverter::sanitizeVerilogID);
59         }
60
61         private void convert(ModelComponent modelComponent)
62         {
63                 String modelID = modelComponent.getIDForSerializing(new IdentifyParams());
64                 JsonElement params = modelComponent.getParamsForSerializingJSON(new IdentifyParams());
65                 if (componentMappingsPerModelIDPerParams.getOrDefault(modelID, Map.of()).containsKey(params))
66                         // we already converted that component, or it was specified externally
67                         return;
68
69                 if (!(modelComponent instanceof SubmodelComponent))
70                         throw new IllegalArgumentException(
71                                         "Can only convert SubmodelComponents, tried to convert " + modelID + " with params " + params);
72                 SubmodelComponent modelComponentC = (SubmodelComponent) modelComponent;
73
74                 UnionFind<PinBit> connectedPins = findConnectedPins(modelComponentC);
75
76                 ModelComponentToVerilogComponentDeclarationMapping mapping = mapDeclaration(modelComponentC, connectedPins, modelID, params);
77                 componentMappingsPerModelIDPerParams.computeIfAbsent(modelID, i -> new HashMap<>()).put(params, mapping);
78
79                 for (ModelComponent subcomponent : modelComponentC.submodel.getComponentsByName().values())
80                         if (!(subcomponent instanceof ModelSplitter) && !subcomponent.getName().equals(SubmodelComponent.SUBMODEL_INTERFACE_NAME))
81                                 convert(subcomponent);
82
83                 verilogComponents.add(mapImplementation(modelComponentC, connectedPins, mapping));
84         }
85
86         private static UnionFind<PinBit> findConnectedPins(SubmodelComponent modelComponent)
87         {
88                 UnionFind<PinBit> connectedPins = new UnionFind<>();
89                 for (ModelWire w : modelComponent.submodel.getWiresByName().values())
90                         for (int bit = 0; bit < w.getPin1().logicWidth; bit++)
91                                 connectedPins.union(new PinBit(w.getPin1(), bit), new PinBit(w.getPin2(), bit));
92
93                 for (ModelComponent subcomponent : modelComponent.submodel.getComponentsByName().values())
94                         if (subcomponent instanceof ModelSplitter)
95                         {
96                                 ModelSplitter splitter = (ModelSplitter) subcomponent;
97                                 for (int bit = 0; bit < splitter.logicWidth; bit++)
98                                         connectedPins.union(new PinBit(splitter.getInputPin(), bit), new PinBit(splitter.getOutputPin(bit), 0));
99                         }
100
101                 // TODO connected pins of subcomponents
102
103                 return connectedPins;
104         }
105
106         private ModelComponentToVerilogComponentDeclarationMapping mapDeclaration(SubmodelComponent modelComponent,
107                         UnionFind<PinBit> connectedPins, String modelID, JsonElement params)
108         {
109                 // TODO this is probably slow
110                 Map<PinBit, PinNameBit> representantMapping = new HashMap<>();
111                 UnionFind<PinNameBit> connectedPinsByName = new UnionFind<>();
112                 for (Pin p : modelComponent.getSubmodelPins().values())
113                         for (int bit = 0; bit < p.logicWidth; bit++)
114                         {
115                                 PinNameBit pinnamebit = new PinNameBit(p.name, bit);
116                                 PinNameBit representative = representantMapping.computeIfAbsent(connectedPins.find(new PinBit(p, bit)), q -> pinnamebit);
117                                 connectedPinsByName.union(pinnamebit, representative);
118                         }
119
120                 return generateCanonicalDeclarationMapping(modelComponent, connectedPinsByName, modelID, params,
121                                 verilogComponentIDGen.generateID(verilogComponentIDPrefix + modelID + (params.isJsonNull() ? "" : "_" + params)));
122         }
123
124         public static ModelComponentToVerilogComponentDeclarationMapping generateCanonicalDeclarationMapping(ModelComponent modelComponent,
125                         UnionFind<PinNameBit> connectedPins, String modelID, JsonElement params, String verilogID)
126         {
127                 IdentifierGenerator ioPortIDGen = new IdentifierGenerator(ModelComponentToVerilogConverter::sanitizeVerilogID);
128                 List<IOPort> ioPorts = new ArrayList<>();
129                 Map<Type, Map<PinNameBit, VerilogEmulatedModelPinBuilder>> pinMapping = new HashMap<>();
130                 for (Type t : Type.values())
131                         pinMapping.put(t, new HashMap<>());
132                 for (Pin modelPin : modelComponent.getPins().values())
133                         for (int bit = 0; bit < modelPin.logicWidth; bit++)
134                         {
135                                 PinNameBit pinbit = new PinNameBit(modelPin.name, bit);
136                                 addPinMapping(ioPortIDGen, ioPorts, connectedPins, pinMapping, pinbit, Input::new, Type.PRE, "pre");
137                                 addPinMapping(ioPortIDGen, ioPorts, connectedPins, pinMapping, pinbit, Output::new, Type.OUT, "out");
138                                 addPinMapping(ioPortIDGen, ioPorts, connectedPins, pinMapping, pinbit, Input::new, Type.RES, "res");
139                         }
140
141                 VerilogComponentDeclaration declaration = new VerilogComponentDeclaration(verilogID, ioPorts);
142                 Set<VerilogEmulatedModelPin> finalPinMapping = pinMapping.values().stream().map(Map::values).flatMap(Collection::stream)
143                                 .map(VerilogEmulatedModelPinBuilder::build).collect(Collectors.toSet());
144                 return new ModelComponentToVerilogComponentDeclarationMapping(modelID, params, declaration, finalPinMapping);
145         }
146
147         private static void addPinMapping(IdentifierGenerator ioPortIDGen, List<IOPort> ioPorts, UnionFind<PinNameBit> connectedPins,
148                         Map<Type, Map<PinNameBit, VerilogEmulatedModelPinBuilder>> pinMapping, PinNameBit pinbit,
149                         BiFunction<String, Integer, IOPort> constr, Type type, String suffix)
150         {
151                 Map<PinNameBit, VerilogEmulatedModelPinBuilder> pinMappingCorrectType = pinMapping.get(type);
152                 pinMappingCorrectType.computeIfAbsent(connectedPins.find(pinbit), p ->
153                 {
154                         String portID = ioPortIDGen.generateID(p.getName() + "_" + p.getBit() + "_" + suffix);
155                         IOPort ioPort = constr.apply(portID, 2);
156                         int index = ioPorts.size();
157                         ioPorts.add(ioPort);
158                         return new VerilogEmulatedModelPinBuilder(ioPort, index, type);
159                 }).addPinbit(pinbit);
160         }
161
162         private static class VerilogEmulatedModelPinBuilder
163         {
164                 private final IOPort verilogPort;
165                 private final int portIndex;
166                 private final Set<PinNameBit> pinbits;
167                 private final Type type;
168
169                 public VerilogEmulatedModelPinBuilder(IOPort verilogPort, int portIndex, Type type)
170                 {
171                         this.verilogPort = verilogPort;
172                         this.portIndex = portIndex;
173                         this.pinbits = new HashSet<>();
174                         this.type = type;
175                 }
176
177                 public void addPinbit(PinNameBit pinbit)
178                 {
179                         pinbits.add(pinbit);
180                 }
181
182                 public VerilogEmulatedModelPin build()
183                 {
184                         return new VerilogEmulatedModelPin(verilogPort, portIndex, pinbits, type);
185                 }
186         }
187
188         private VerilogComponentImplementation mapImplementation(SubmodelComponent modelComponent, UnionFind<PinBit> connectedPins,
189                         ModelComponentToVerilogComponentDeclarationMapping declarationMapping)
190         {
191                 Map<PinBit, Signal> currentPreSignals = new HashMap<>();
192                 Map<PinBit, NamedSignal> finalOutSignals = new HashMap<>();
193                 Map<PinBit, NamedSignal> resSignals = new HashMap<>();
194                 for (Pin submodelPin : modelComponent.getSubmodelPins().values())
195                         for (int bit = 0; bit < submodelPin.logicWidth; bit++)
196                         {
197                                 PinBit pinbit = new PinBit(submodelPin, bit);
198                                 PinNameBit pinnamebit = pinbit.toPinNameBit();
199                                 PinBit root = connectedPins.find(pinbit);
200                                 resSignals.put(root, declarationMapping.getResPinMapping().get(pinnamebit).getVerilogPort());
201                                 finalOutSignals.put(root, declarationMapping.getOutPinMapping().get(pinnamebit).getVerilogPort());
202                                 Signal prePort = declarationMapping.getPrePinMapping().get(pinnamebit).getVerilogPort();
203                                 Signal previousPrePort = currentPreSignals.put(root, prePort);
204                                 assert previousPrePort != null && !previousPrePort.equals(prePort);
205                         }
206
207                 IdentifierGenerator idGen = new IdentifierGenerator(
208                                 declarationMapping.getVerilogComponentDeclaration().getIOPorts().stream().map(IOPort::getName).collect(Collectors.toList()),
209                                 ModelComponentToVerilogConverter::sanitizeVerilogID);
210                 Set<Wire> internalWires = new HashSet<>();
211                 Set<ComponentReference> subcomponents = new HashSet<>();
212                 for (ModelComponent subcomponent : modelComponent.submodel.getComponentsByName().values())
213                 {
214                         // TODO do we really want to use instanceof?
215                         if (subcomponent instanceof ModelSplitter || subcomponent.getName().equals(SubmodelComponent.SUBMODEL_INTERFACE_NAME))
216                                 continue;
217
218                         String subcomponentVerilogName = idGen.generateID(subcomponent.getName());
219                         ModelComponentToVerilogComponentDeclarationMapping subcomponentMapping = componentMappingsPerModelIDPerParams
220                                         .get(subcomponent.getIDForSerializing(new IdentifyParams()))
221                                         .get(subcomponent.getParamsForSerializingJSON(new IdentifyParams()));
222                         int parameterCount = subcomponentMapping.getVerilogComponentDeclaration().getIOPorts().size();
223                         List<Signal> arguments = new ArrayList<>(parameterCount);
224                         for (int i = 0; i < parameterCount; i++)
225                                 arguments.add(null);
226                         for (Pin pin : subcomponent.getPins().values())
227                                 for (int bit = 0; bit < pin.logicWidth; bit++)
228                                 {
229                                         PinBit pinbit = new PinBit(pin, bit);
230                                         PinBit root = connectedPins.find(pinbit);
231                                         Wire outSignal = new Wire(idGen.generateID(subcomponentVerilogName + "_" + pin.name + "_" + bit), 2);
232                                         internalWires.add(outSignal);
233                                         Signal preSignal = currentPreSignals.put(root, outSignal);
234                                         Signal resSignal = resSignals.get(root);
235                                         if (resSignal == null)
236                                         {
237                                                 preSignal = new Constant(BitVector.of(Bit.ZERO, 2));
238                                                 Wire resWire = new Wire(idGen.generateID(subcomponentVerilogName + "_" + pin.name + "_" + bit + "_res"), 2);
239                                                 resSignal = resWire;
240                                                 internalWires.add(resWire);
241                                                 finalOutSignals.put(root, resWire);
242                                                 resSignals.put(root, resWire);
243                                         }
244                                         PinNameBit pinnamebit = pinbit.toPinNameBit();
245                                         arguments.set(subcomponentMapping.getPrePinMapping().get(pinnamebit).getPortIndex(), preSignal);
246                                         arguments.set(subcomponentMapping.getOutPinMapping().get(pinnamebit).getPortIndex(), outSignal);
247                                         arguments.set(subcomponentMapping.getResPinMapping().get(pinnamebit).getPortIndex(), resSignal);
248                                 }
249                         subcomponents
250                                         .add(new ComponentReference(subcomponentVerilogName, subcomponentMapping.getVerilogComponentDeclaration(), arguments));
251                 }
252
253                 Set<Assign> assigns = new HashSet<>();
254                 for (Entry<PinBit, NamedSignal> e : finalOutSignals.entrySet())
255                         assigns.add(new Assign(currentPreSignals.get(e.getKey()), e.getValue()));
256
257                 return new VerilogComponentImplementation(declarationMapping.getVerilogComponentDeclaration(), internalWires, assigns,
258                                 subcomponents);
259         }
260
261         private Set<VerilogComponentImplementation> getVerilogComponents()
262         {
263                 return verilogComponents;
264         }
265
266         public static Set<VerilogComponentImplementation> convert(
267                         Set<ModelComponentToVerilogComponentDeclarationMapping> atomicComponentMappings, Set<ModelComponent> components,
268                         String verilogComponentIDPrefix)
269         {
270                 ModelComponentToVerilogConverter converter = new ModelComponentToVerilogConverter(verilogComponentIDPrefix,
271                                 atomicComponentMappings);
272                 for (ModelComponent modelComponent : components)
273                         converter.convert(modelComponent);
274                 return converter.getVerilogComponents();
275         }
276
277         public static String sanitizeVerilogID(String id)
278         {
279                 return (id.matches("[0-9].*") ? "_" + id : id).replaceAll("[^A-Za-z0-9_]", "_");
280         }
281 }