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