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