ModelComponentToVerilogConverter can now convert TriStateBuffers
[Mograsim.git] / plugins / net.mograsim.logic.model.verilog / src / net / mograsim / logic / model / verilog / converter / components / SubmodelComponentConverter.java
1 package net.mograsim.logic.model.verilog.converter.components;
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.stream.Collectors;
13
14 import com.google.gson.JsonElement;
15
16 import net.mograsim.logic.core.types.Bit;
17 import net.mograsim.logic.core.types.BitVector;
18 import net.mograsim.logic.model.model.components.ModelComponent;
19 import net.mograsim.logic.model.model.components.atomic.ModelSplitter;
20 import net.mograsim.logic.model.model.components.submodels.SubmodelComponent;
21 import net.mograsim.logic.model.model.wires.ModelWire;
22 import net.mograsim.logic.model.model.wires.ModelWireCrossPoint;
23 import net.mograsim.logic.model.model.wires.Pin;
24 import net.mograsim.logic.model.verilog.converter.ComponentConversionResult;
25 import net.mograsim.logic.model.verilog.converter.ModelComponentToVerilogComponentDeclarationMapping;
26 import net.mograsim.logic.model.verilog.converter.ModelComponentToVerilogConverter;
27 import net.mograsim.logic.model.verilog.converter.PinBit;
28 import net.mograsim.logic.model.verilog.converter.PinNameBit;
29 import net.mograsim.logic.model.verilog.converter.VerilogEmulatedModelPin;
30 import net.mograsim.logic.model.verilog.converter.VerilogEmulatedModelPin.Type;
31 import net.mograsim.logic.model.verilog.model.VerilogComponentDeclaration;
32 import net.mograsim.logic.model.verilog.model.VerilogComponentImplementation;
33 import net.mograsim.logic.model.verilog.model.expressions.Constant;
34 import net.mograsim.logic.model.verilog.model.expressions.Expression;
35 import net.mograsim.logic.model.verilog.model.expressions.SignalReference;
36 import net.mograsim.logic.model.verilog.model.signals.IOPort;
37 import net.mograsim.logic.model.verilog.model.signals.Input;
38 import net.mograsim.logic.model.verilog.model.signals.Output;
39 import net.mograsim.logic.model.verilog.model.signals.Signal;
40 import net.mograsim.logic.model.verilog.model.signals.Wire;
41 import net.mograsim.logic.model.verilog.model.statements.Assign;
42 import net.mograsim.logic.model.verilog.model.statements.ComponentReference;
43 import net.mograsim.logic.model.verilog.model.statements.Statement;
44 import net.mograsim.logic.model.verilog.model.statements.WireDeclaration;
45 import net.mograsim.logic.model.verilog.utils.IdentifierGenerator;
46 import net.mograsim.logic.model.verilog.utils.UnionFind;
47
48 public class SubmodelComponentConverter implements ComponentConverter<SubmodelComponent>
49 {
50         private final ModelComponentToVerilogConverter converter;
51
52         public SubmodelComponentConverter(ModelComponentToVerilogConverter converter)
53         {
54                 this.converter = converter;
55         }
56
57         @Override
58         public ComponentConversionResult convert(SubmodelComponent modelComponent, String modelID, JsonElement params, String verilogID)
59         {
60                 for (ModelComponent subcomponent : modelComponent.submodel.getComponentsByName().values())
61                         if (!subcomponent.getName().equals(SubmodelComponent.SUBMODEL_INTERFACE_NAME))
62                                 converter.convert(subcomponent);
63
64                 UnionFind<PinBit> connectedPins = findConnectedPins(modelComponent);
65
66                 ModelComponentToVerilogComponentDeclarationMapping mapping = mapDeclaration(modelComponent, connectedPins, modelID, params,
67                                 verilogID);
68
69                 VerilogComponentImplementation implementation = mapImplementation(modelComponent, connectedPins, mapping);
70
71                 return new ComponentConversionResult(mapping, implementation);
72         }
73
74         private UnionFind<PinBit> findConnectedPins(SubmodelComponent modelComponent)
75         {
76                 UnionFind<PinBit> connectedPins = new UnionFind<>();
77                 for (ModelWire w : modelComponent.submodel.getWiresByName().values())
78                         for (int bit = 0; bit < w.getPin1().logicWidth; bit++)
79                                 connectedPins.union(new PinBit(w.getPin1(), bit), new PinBit(w.getPin2(), bit));
80
81                 for (ModelComponent subcomponent : modelComponent.submodel.getComponentsByName().values())
82                         if (subcomponent instanceof ModelSplitter)
83                         {
84                                 ModelSplitter splitter = (ModelSplitter) subcomponent;
85                                 for (int bit = 0; bit < splitter.logicWidth; bit++)
86                                         connectedPins.union(new PinBit(splitter.getInputPin(), bit), new PinBit(splitter.getOutputPin(bit), 0));
87                         } else if (!(subcomponent instanceof ModelWireCrossPoint)
88                                         && !subcomponent.getName().equals(SubmodelComponent.SUBMODEL_INTERFACE_NAME))
89                         {
90                                 ModelComponentToVerilogComponentDeclarationMapping subcomponentMapping = converter.getComponentMapping(subcomponent);
91                                 for (Set<PinNameBit> connected : subcomponentMapping.getInternallyConnectedPins())
92                                         connectedPins.unionAll(connected.stream().map(p -> p.toPinBit(subcomponent)).collect(Collectors.toList()));
93                         }
94
95                 return connectedPins;
96         }
97
98         private static ModelComponentToVerilogComponentDeclarationMapping mapDeclaration(SubmodelComponent modelComponent,
99                         UnionFind<PinBit> connectedPins, String modelID, JsonElement params, String verilogID)
100         {
101                 // TODO this is probably slow
102                 Map<PinBit, PinNameBit> representantMapping = new HashMap<>();
103                 UnionFind<PinNameBit> connectedPinsByName = new UnionFind<>();
104                 for (Pin p : modelComponent.getSubmodelPins().values())
105                         for (int bit = 0; bit < p.logicWidth; bit++)
106                         {
107                                 PinNameBit pinnamebit = new PinNameBit(p.name, bit);
108                                 PinNameBit representative = representantMapping.computeIfAbsent(connectedPins.find(new PinBit(p, bit)), q -> pinnamebit);
109                                 connectedPinsByName.union(pinnamebit, representative);
110                         }
111
112                 return generateCanonicalDeclarationMapping(modelComponent, connectedPinsByName, modelID, params, verilogID);
113         }
114
115         public static ModelComponentToVerilogComponentDeclarationMapping generateCanonicalDeclarationMapping(ModelComponent modelComponent,
116                         UnionFind<PinNameBit> connectedPins, String modelID, JsonElement params, String verilogID)
117         {
118                 IdentifierGenerator ioPortIDGen = new IdentifierGenerator(ModelComponentToVerilogConverter::sanitizeVerilogID);
119                 List<IOPort> ioPorts = new ArrayList<>();
120                 Map<Type, Map<PinNameBit, VerilogEmulatedModelPinBuilder>> pinMapping = new HashMap<>();
121                 for (Type t : Type.values())
122                         pinMapping.put(t, new HashMap<>());
123                 for (Pin modelPin : modelComponent.getPins().values())
124                         for (int bit = 0; bit < modelPin.logicWidth; bit++)
125                         {
126                                 PinNameBit pinbit = new PinNameBit(modelPin.name, bit);
127                                 addPinMapping(ioPortIDGen, ioPorts, connectedPins, pinMapping, pinbit, Input::new, Type.PRE, "pre");
128                                 addPinMapping(ioPortIDGen, ioPorts, connectedPins, pinMapping, pinbit, Output::new, Type.OUT, "out");
129                                 addPinMapping(ioPortIDGen, ioPorts, connectedPins, pinMapping, pinbit, Input::new, Type.RES, "res");
130                         }
131
132                 VerilogComponentDeclaration declaration = new VerilogComponentDeclaration(verilogID, ioPorts);
133                 Set<VerilogEmulatedModelPin> finalPinMapping = pinMapping.values().stream().map(Map::values).flatMap(Collection::stream)
134                                 .map(VerilogEmulatedModelPinBuilder::build).collect(Collectors.toSet());
135                 return new ModelComponentToVerilogComponentDeclarationMapping(modelID, params, declaration, finalPinMapping);
136         }
137
138         private static void addPinMapping(IdentifierGenerator ioPortIDGen, List<IOPort> ioPorts, UnionFind<PinNameBit> connectedPins,
139                         Map<Type, Map<PinNameBit, VerilogEmulatedModelPinBuilder>> pinMapping, PinNameBit pinbit,
140                         BiFunction<String, Integer, IOPort> constr, Type type, String suffix)
141         {
142                 Map<PinNameBit, VerilogEmulatedModelPinBuilder> pinMappingCorrectType = pinMapping.get(type);
143                 pinMappingCorrectType.computeIfAbsent(connectedPins.find(pinbit), p ->
144                 {
145                         String portID = ioPortIDGen.generateID(p.getName() + "_" + p.getBit() + "_" + suffix);
146                         IOPort ioPort = constr.apply(portID, 2);
147                         int index = ioPorts.size();
148                         ioPorts.add(ioPort);
149                         return new VerilogEmulatedModelPinBuilder(ioPort, index, type);
150                 }).addPinbit(pinbit);
151         }
152
153         private static class VerilogEmulatedModelPinBuilder
154         {
155                 private final IOPort verilogPort;
156                 private final int portIndex;
157                 private final Set<PinNameBit> pinbits;
158                 private final Type type;
159
160                 public VerilogEmulatedModelPinBuilder(IOPort verilogPort, int portIndex, Type type)
161                 {
162                         this.verilogPort = verilogPort;
163                         this.portIndex = portIndex;
164                         this.pinbits = new HashSet<>();
165                         this.type = type;
166                 }
167
168                 public void addPinbit(PinNameBit pinbit)
169                 {
170                         pinbits.add(pinbit);
171                 }
172
173                 public VerilogEmulatedModelPin build()
174                 {
175                         return new VerilogEmulatedModelPin(verilogPort, portIndex, pinbits, type);
176                 }
177         }
178
179         private VerilogComponentImplementation mapImplementation(SubmodelComponent modelComponent, UnionFind<PinBit> connectedPins,
180                         ModelComponentToVerilogComponentDeclarationMapping declarationMapping)
181         {
182                 Map<PinBit, Expression> currentPreExprs = new HashMap<>();
183                 Map<PinBit, Signal> finalOutSignals = new HashMap<>();
184                 Map<PinBit, Expression> resExprs = new HashMap<>();
185                 for (Set<PinNameBit> connectedPinGroup : declarationMapping.getInternallyConnectedPins())
186                 {
187                         PinNameBit pinnamebit = connectedPinGroup.iterator().next();
188                         PinBit root = connectedPins.find(pinnamebit.toSubmodelPinBit(modelComponent));
189                         resExprs.put(root, new SignalReference(declarationMapping.getResPinMapping().get(pinnamebit).getVerilogPort()));
190                         finalOutSignals.put(root, declarationMapping.getOutPinMapping().get(pinnamebit).getVerilogPort());
191                         currentPreExprs.put(root, new SignalReference(declarationMapping.getPrePinMapping().get(pinnamebit).getVerilogPort()));
192                 }
193
194                 IdentifierGenerator idGen = ModelComponentToVerilogConverter
195                                 .generateIdentifierGenerator(declarationMapping.getVerilogComponentDeclaration());
196                 List<Statement> statements = new ArrayList<>();
197                 for (ModelComponent subcomponent : modelComponent.submodel.getComponentsByName().values())
198                 {
199                         // TODO do we really want to use instanceof?
200                         if (subcomponent instanceof ModelSplitter || subcomponent instanceof ModelWireCrossPoint
201                                         || subcomponent.getName().equals(SubmodelComponent.SUBMODEL_INTERFACE_NAME))
202                                 continue;
203
204                         String subcomponentVerilogName = idGen.generateID(subcomponent.getName());
205                         ModelComponentToVerilogComponentDeclarationMapping subcomponentMapping = converter.getComponentMapping(subcomponent);
206                         int parameterCount = subcomponentMapping.getVerilogComponentDeclaration().getIOPorts().size();
207                         List<Expression> arguments = new ArrayList<>(parameterCount);
208                         for (int i = 0; i < parameterCount; i++)
209                                 arguments.add(null);
210                         for (Pin pin : subcomponent.getPins().values())
211                                 for (int bit = 0; bit < pin.logicWidth; bit++)
212                                 {
213                                         PinBit pinbit = new PinBit(pin, bit);
214                                         PinBit root = connectedPins.find(pinbit);
215                                         Wire outSignal = new Wire(idGen.generateID(subcomponentVerilogName + "_" + pin.name + "_" + bit), 2);
216                                         statements.add(new WireDeclaration(outSignal));
217                                         Expression preExpr = currentPreExprs.put(root, new SignalReference(outSignal));
218                                         Expression outExpr = new SignalReference(outSignal);
219                                         Expression resExpr = resExprs.get(root);
220                                         if (resExpr == null)
221                                         {
222                                                 preExpr = new Constant(BitVector.of(Bit.ZERO, 2));
223                                                 Wire resWire = new Wire(idGen.generateID(subcomponentVerilogName + "_" + pin.name + "_" + bit + "_res"), 2);
224                                                 resExpr = new SignalReference(resWire);
225                                                 statements.add(new WireDeclaration(resWire));
226                                                 finalOutSignals.put(root, resWire);
227                                                 resExprs.put(root, resExpr);
228                                         }
229                                         PinNameBit pinnamebit = pinbit.toPinNameBit();
230                                         arguments.set(subcomponentMapping.getPrePinMapping().get(pinnamebit).getPortIndex(), preExpr);
231                                         arguments.set(subcomponentMapping.getOutPinMapping().get(pinnamebit).getPortIndex(), outExpr);
232                                         arguments.set(subcomponentMapping.getResPinMapping().get(pinnamebit).getPortIndex(), resExpr);
233                                 }
234                         statements
235                                         .add(new ComponentReference(subcomponentVerilogName, subcomponentMapping.getVerilogComponentDeclaration(), arguments));
236                 }
237
238                 for (Entry<PinBit, Signal> e : finalOutSignals.entrySet())
239                         statements.add(new Assign(e.getValue(), currentPreExprs.get(e.getKey())));
240
241                 return new VerilogComponentImplementation(declarationMapping.getVerilogComponentDeclaration(), statements);
242         }
243 }