6c12a07b86c8d5856bf6769d4ed3a97a10a33d98
[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.Comparator;
6 import java.util.HashMap;
7 import java.util.HashSet;
8 import java.util.List;
9 import java.util.Map;
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.model.model.components.ModelComponent;
18 import net.mograsim.logic.model.model.components.atomic.ModelSplitter;
19 import net.mograsim.logic.model.model.components.atomic.ModelTriStateBuffer;
20 import net.mograsim.logic.model.model.components.submodels.SubmodelComponent;
21 import net.mograsim.logic.model.model.wires.ModelWireCrossPoint;
22 import net.mograsim.logic.model.model.wires.Pin;
23 import net.mograsim.logic.model.serializing.IdentifyParams;
24 import net.mograsim.logic.model.verilog.converter.VerilogEmulatedModelPin.Type;
25 import net.mograsim.logic.model.verilog.converter.components.SubmodelComponentConverter;
26 import net.mograsim.logic.model.verilog.converter.components.TriStateBufferConverter;
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.signals.IOPort;
30 import net.mograsim.logic.model.verilog.model.signals.Input;
31 import net.mograsim.logic.model.verilog.model.signals.Output;
32 import net.mograsim.logic.model.verilog.utils.IdentifierGenerator;
33 import net.mograsim.logic.model.verilog.utils.UnionFind;
34
35 public class ModelComponentToVerilogConverter
36 {
37         private final String verilogComponentIDPrefix;
38         private final Map<String, Map<JsonElement, ModelComponentToVerilogComponentDeclarationMapping>> componentMappingsPerModelIDPerParams;
39         private final Set<VerilogComponentImplementation> verilogComponents;
40         private final IdentifierGenerator verilogComponentIDGen;
41
42         public ModelComponentToVerilogConverter(String verilogComponentIDPrefix,
43                         Set<ModelComponentToVerilogComponentDeclarationMapping> atomicComponentMappings)
44         {
45                 this.verilogComponentIDPrefix = verilogComponentIDPrefix;
46                 this.componentMappingsPerModelIDPerParams = new HashMap<>(atomicComponentMappings.stream().collect(Collectors
47                                 .groupingBy(m -> m.getModelComponentID(), Collectors.toMap(m -> m.getModelComponentParams(), Function.identity()))));
48                 this.verilogComponents = new HashSet<>();
49                 this.verilogComponentIDGen = new IdentifierGenerator(
50                                 componentMappingsPerModelIDPerParams.values().stream().map(Map::values).flatMap(Collection::stream)
51                                                 .map(ModelComponentToVerilogComponentDeclarationMapping::getVerilogComponentDeclaration)
52                                                 .map(VerilogComponentDeclaration::getID).collect(Collectors.toSet()),
53                                 ModelComponentToVerilogConverter::sanitizeVerilogID);
54         }
55
56         public void convert(ModelComponent modelComponent)
57         {
58                 // these are handled elsewhere
59                 if (modelComponent instanceof ModelSplitter || modelComponent instanceof ModelWireCrossPoint)
60                         return;
61
62                 String modelID = modelComponent.getIDForSerializing(new IdentifyParams());
63                 JsonElement params = modelComponent.getParamsForSerializingJSON(new IdentifyParams());
64                 if (componentMappingsPerModelIDPerParams.getOrDefault(modelID, Map.of()).containsKey(params))
65                         // we already converted that component, or it was specified externally
66                         return;
67
68                 String verilogID = verilogComponentIDGen.generateID(verilogComponentIDPrefix + modelID + (params.isJsonNull() ? "" : "_" + params));
69
70                 ComponentConversionResult result;
71                 // TODO don't rely on instanceof
72                 // TODO improve!
73                 if (modelComponent instanceof SubmodelComponent)
74                         result = new SubmodelComponentConverter(this).convert((SubmodelComponent) modelComponent, modelID, params, verilogID);
75                 else if (modelComponent instanceof ModelTriStateBuffer)
76                         result = new TriStateBufferConverter().convert((ModelTriStateBuffer) modelComponent, modelID, params, verilogID);
77                 else
78                         throw new IllegalArgumentException(
79                                         "Can only convert SubmodelComponents, tried to convert " + modelID + " with params " + params);
80
81                 componentMappingsPerModelIDPerParams.computeIfAbsent(modelID, i -> new HashMap<>()).put(params, result.getMapping());
82                 verilogComponents.add(result.getImplementation());
83         }
84
85         public static ModelComponentToVerilogComponentDeclarationMapping generateCanonicalDeclarationMapping(ModelComponent modelComponent,
86                         UnionFind<PinNameBit> connectedPins, String modelID, JsonElement params, String verilogID)
87         {
88                 IdentifierGenerator ioPortIDGen = new IdentifierGenerator(ModelComponentToVerilogConverter::sanitizeVerilogID);
89                 List<IOPort> ioPorts = new ArrayList<>();
90                 Map<Type, Map<PinNameBit, VerilogEmulatedModelPinBuilder>> pinMapping = new HashMap<>();
91                 for (Type t : Type.values())
92                         pinMapping.put(t, new HashMap<>());
93                 for (Pin modelPin : (Iterable<Pin>) () -> modelComponent.getPins().values().stream().sorted(Comparator.comparing(p -> p.name))
94                                 .iterator())
95                         for (int bit = 0; bit < modelPin.logicWidth; bit++)
96                         {
97                                 PinNameBit pinbit = new PinNameBit(modelPin.name, bit);
98                                 addPinMapping(ioPortIDGen, ioPorts, connectedPins, pinMapping, pinbit, Input::new, Type.PRE, "pre");
99                                 addPinMapping(ioPortIDGen, ioPorts, connectedPins, pinMapping, pinbit, Output::new, Type.OUT, "out");
100                                 addPinMapping(ioPortIDGen, ioPorts, connectedPins, pinMapping, pinbit, Input::new, Type.RES, "res");
101                         }
102
103                 VerilogComponentDeclaration declaration = new VerilogComponentDeclaration(verilogID, ioPorts);
104                 Set<VerilogEmulatedModelPin> finalPinMapping = pinMapping.values().stream().map(Map::values).flatMap(Collection::stream)
105                                 .map(VerilogEmulatedModelPinBuilder::build).collect(Collectors.toSet());
106                 return new ModelComponentToVerilogComponentDeclarationMapping(modelID, params, declaration, finalPinMapping);
107         }
108
109         private static void addPinMapping(IdentifierGenerator ioPortIDGen, List<IOPort> ioPorts, UnionFind<PinNameBit> connectedPins,
110                         Map<Type, Map<PinNameBit, VerilogEmulatedModelPinBuilder>> pinMapping, PinNameBit pinbit,
111                         BiFunction<String, Integer, IOPort> constr, Type type, String suffix)
112         {
113                 Map<PinNameBit, VerilogEmulatedModelPinBuilder> pinMappingCorrectType = pinMapping.get(type);
114                 pinMappingCorrectType.computeIfAbsent(connectedPins.find(pinbit), p ->
115                 {
116                         String portID = ioPortIDGen.generateID(pinbit.getName() + "_" + pinbit.getBit() + "_" + suffix);
117                         IOPort ioPort = constr.apply(portID, 2);
118                         int index = ioPorts.size();
119                         ioPorts.add(ioPort);
120                         return new VerilogEmulatedModelPinBuilder(ioPort, index, type);
121                 }).addPinbit(pinbit);
122         }
123
124         private static class VerilogEmulatedModelPinBuilder
125         {
126                 private final IOPort verilogPort;
127                 private final int portIndex;
128                 private final Set<PinNameBit> pinbits;
129                 private final Type type;
130
131                 public VerilogEmulatedModelPinBuilder(IOPort verilogPort, int portIndex, Type type)
132                 {
133                         this.verilogPort = verilogPort;
134                         this.portIndex = portIndex;
135                         this.pinbits = new HashSet<>();
136                         this.type = type;
137                 }
138
139                 public void addPinbit(PinNameBit pinbit)
140                 {
141                         pinbits.add(pinbit);
142                 }
143
144                 public VerilogEmulatedModelPin build()
145                 {
146                         return new VerilogEmulatedModelPin(verilogPort, portIndex, pinbits, type);
147                 }
148         }
149
150         public ModelComponentToVerilogComponentDeclarationMapping getComponentMapping(ModelComponent component)
151         {
152                 ModelComponentToVerilogComponentDeclarationMapping subcomponentMapping = componentMappingsPerModelIDPerParams
153                                 .get(component.getIDForSerializing(new IdentifyParams())).get(component.getParamsForSerializingJSON(new IdentifyParams()));
154                 return subcomponentMapping;
155         }
156
157         public Set<VerilogComponentImplementation> getVerilogComponents()
158         {
159                 return verilogComponents;
160         }
161
162         public static Set<VerilogComponentImplementation> convert(
163                         Set<ModelComponentToVerilogComponentDeclarationMapping> atomicComponentMappings, Set<ModelComponent> components,
164                         String verilogComponentIDPrefix)
165         {
166                 ModelComponentToVerilogConverter converter = new ModelComponentToVerilogConverter(verilogComponentIDPrefix,
167                                 atomicComponentMappings);
168                 for (ModelComponent modelComponent : components)
169                         converter.convert(modelComponent);
170                 return converter.getVerilogComponents();
171         }
172
173         public static IdentifierGenerator generateIdentifierGenerator(VerilogComponentDeclaration declaration)
174         {
175                 IdentifierGenerator idGen = new IdentifierGenerator(
176                                 declaration.getIOPorts().stream().map(IOPort::getName).collect(Collectors.toList()),
177                                 ModelComponentToVerilogConverter::sanitizeVerilogID);
178                 return idGen;
179         }
180
181         public static String sanitizeVerilogID(String id)
182         {
183                 return (id.matches("[0-9].*") ? "_" + id : id).replaceAll("[^A-Za-z0-9_]", "_");
184         }
185 }