ModelComponentToVerilogConverter can now convert TriStateBuffers
[Mograsim.git] / plugins / net.mograsim.logic.model.verilog / src / net / mograsim / logic / model / verilog / converter / ModelComponentToVerilogConverter.java
index d2a7e57..4e05a22 100644 (file)
@@ -6,7 +6,6 @@ import java.util.HashMap;
 import java.util.HashSet;
 import java.util.List;
 import java.util.Map;
-import java.util.Map.Entry;
 import java.util.Set;
 import java.util.function.BiFunction;
 import java.util.function.Function;
@@ -14,29 +13,23 @@ import java.util.stream.Collectors;
 
 import com.google.gson.JsonElement;
 
-import net.mograsim.logic.core.types.Bit;
-import net.mograsim.logic.core.types.BitVector;
 import net.mograsim.logic.model.model.components.ModelComponent;
 import net.mograsim.logic.model.model.components.atomic.ModelSplitter;
+import net.mograsim.logic.model.model.components.atomic.ModelTriStateBuffer;
 import net.mograsim.logic.model.model.components.submodels.SubmodelComponent;
-import net.mograsim.logic.model.model.wires.ModelWire;
+import net.mograsim.logic.model.model.wires.ModelWireCrossPoint;
 import net.mograsim.logic.model.model.wires.Pin;
 import net.mograsim.logic.model.serializing.IdentifyParams;
 import net.mograsim.logic.model.verilog.converter.VerilogEmulatedModelPin.Type;
-import net.mograsim.logic.model.verilog.helper.IdentifierGenerator;
-import net.mograsim.logic.model.verilog.helper.UnionFind;
-import net.mograsim.logic.model.verilog.helper.UnionFind.UnionFindElement;
-import net.mograsim.logic.model.verilog.model.Assign;
-import net.mograsim.logic.model.verilog.model.ComponentReference;
-import net.mograsim.logic.model.verilog.model.Constant;
-import net.mograsim.logic.model.verilog.model.IOPort;
-import net.mograsim.logic.model.verilog.model.Input;
-import net.mograsim.logic.model.verilog.model.NamedSignal;
-import net.mograsim.logic.model.verilog.model.Output;
-import net.mograsim.logic.model.verilog.model.Signal;
+import net.mograsim.logic.model.verilog.converter.components.SubmodelComponentConverter;
+import net.mograsim.logic.model.verilog.converter.components.TriStateBufferConverter;
 import net.mograsim.logic.model.verilog.model.VerilogComponentDeclaration;
 import net.mograsim.logic.model.verilog.model.VerilogComponentImplementation;
-import net.mograsim.logic.model.verilog.model.Wire;
+import net.mograsim.logic.model.verilog.model.signals.IOPort;
+import net.mograsim.logic.model.verilog.model.signals.Input;
+import net.mograsim.logic.model.verilog.model.signals.Output;
+import net.mograsim.logic.model.verilog.utils.IdentifierGenerator;
+import net.mograsim.logic.model.verilog.utils.UnionFind;
 
 public class ModelComponentToVerilogConverter
 {
@@ -59,145 +52,107 @@ public class ModelComponentToVerilogConverter
                                ModelComponentToVerilogConverter::sanitizeVerilogID);
        }
 
-       private void convert(ModelComponent modelComponent)
+       public void convert(ModelComponent modelComponent)
        {
+               // these are handled elsewhere
+               if (modelComponent instanceof ModelSplitter || modelComponent instanceof ModelWireCrossPoint)
+                       return;
+
                String modelID = modelComponent.getIDForSerializing(new IdentifyParams());
                JsonElement params = modelComponent.getParamsForSerializingJSON(new IdentifyParams());
                if (componentMappingsPerModelIDPerParams.getOrDefault(modelID, Map.of()).containsKey(params))
                        // we already converted that component, or it was specified externally
                        return;
 
-               if (!(modelComponent instanceof SubmodelComponent))
+               String verilogID = verilogComponentIDGen.generateID(verilogComponentIDPrefix + modelID + (params.isJsonNull() ? "" : "_" + params));
+
+               ComponentConversionResult result;
+               // TODO don't rely on instanceof
+               // TODO improve!
+               if (modelComponent instanceof SubmodelComponent)
+                       result = new SubmodelComponentConverter(this).convert((SubmodelComponent) modelComponent, modelID, params, verilogID);
+               else if (modelComponent instanceof ModelTriStateBuffer)
+                       result = new TriStateBufferConverter(this).convert((ModelTriStateBuffer) modelComponent, modelID, params, verilogID);
+               else
                        throw new IllegalArgumentException(
                                        "Can only convert SubmodelComponents, tried to convert " + modelID + " with params " + params);
-               SubmodelComponent modelComponentC = (SubmodelComponent) modelComponent;
-
-               ModelComponentToVerilogComponentDeclarationMapping mapping = mapDeclaration(modelComponentC, modelID, params);
-               componentMappingsPerModelIDPerParams.computeIfAbsent(modelID, i -> new HashMap<>()).put(params, mapping);
 
-               for (ModelComponent subcomponent : modelComponentC.submodel.getComponentsByName().values())
-                       if (!subcomponent.getName().equals(SubmodelComponent.SUBMODEL_INTERFACE_NAME))
-                               convert(subcomponent);
-
-               verilogComponents.add(mapImplementation(modelComponentC, mapping));
-       }
-
-       private ModelComponentToVerilogComponentDeclarationMapping mapDeclaration(ModelComponent modelComponent, String modelID,
-                       JsonElement params)
-       {
-               return generateCanonicalDeclarationMapping(modelComponent, modelID, params,
-                               verilogComponentIDGen.generateID(verilogComponentIDPrefix + modelID + (params.isJsonNull() ? "" : "_" + params)));
+               componentMappingsPerModelIDPerParams.computeIfAbsent(modelID, i -> new HashMap<>()).put(params, result.getMapping());
+               verilogComponents.add(result.getImplementation());
        }
 
        public static ModelComponentToVerilogComponentDeclarationMapping generateCanonicalDeclarationMapping(ModelComponent modelComponent,
-                       String modelID, JsonElement params, String verilogID)
+                       UnionFind<PinNameBit> connectedPins, String modelID, JsonElement params, String verilogID)
        {
                IdentifierGenerator ioPortIDGen = new IdentifierGenerator(ModelComponentToVerilogConverter::sanitizeVerilogID);
                List<IOPort> ioPorts = new ArrayList<>();
-               Set<VerilogEmulatedModelPin> pinMapping = new HashSet<>();
+               Map<Type, Map<PinNameBit, VerilogEmulatedModelPinBuilder>> pinMapping = new HashMap<>();
+               for (Type t : Type.values())
+                       pinMapping.put(t, new HashMap<>());
                for (Pin modelPin : modelComponent.getPins().values())
                        for (int bit = 0; bit < modelPin.logicWidth; bit++)
                        {
-                               addPinMapping(ioPortIDGen, ioPorts, pinMapping, modelPin, bit, Input::new, Type.PRE, "pre");
-                               addPinMapping(ioPortIDGen, ioPorts, pinMapping, modelPin, bit, Output::new, Type.OUT, "out");
-                               addPinMapping(ioPortIDGen, ioPorts, pinMapping, modelPin, bit, Input::new, Type.RES, "res");
+                               PinNameBit pinbit = new PinNameBit(modelPin.name, bit);
+                               addPinMapping(ioPortIDGen, ioPorts, connectedPins, pinMapping, pinbit, Input::new, Type.PRE, "pre");
+                               addPinMapping(ioPortIDGen, ioPorts, connectedPins, pinMapping, pinbit, Output::new, Type.OUT, "out");
+                               addPinMapping(ioPortIDGen, ioPorts, connectedPins, pinMapping, pinbit, Input::new, Type.RES, "res");
                        }
 
                VerilogComponentDeclaration declaration = new VerilogComponentDeclaration(verilogID, ioPorts);
-               return new ModelComponentToVerilogComponentDeclarationMapping(modelID, params, declaration, pinMapping);
+               Set<VerilogEmulatedModelPin> finalPinMapping = pinMapping.values().stream().map(Map::values).flatMap(Collection::stream)
+                               .map(VerilogEmulatedModelPinBuilder::build).collect(Collectors.toSet());
+               return new ModelComponentToVerilogComponentDeclarationMapping(modelID, params, declaration, finalPinMapping);
        }
 
-       private static void addPinMapping(IdentifierGenerator ioPortIDGen, List<IOPort> ioPorts, Set<VerilogEmulatedModelPin> pinMapping,
-                       Pin modelPin, int bit, BiFunction<String, Integer, IOPort> constr, Type type, String suffix)
+       private static void addPinMapping(IdentifierGenerator ioPortIDGen, List<IOPort> ioPorts, UnionFind<PinNameBit> connectedPins,
+                       Map<Type, Map<PinNameBit, VerilogEmulatedModelPinBuilder>> pinMapping, PinNameBit pinbit,
+                       BiFunction<String, Integer, IOPort> constr, Type type, String suffix)
        {
-               String portID = ioPortIDGen.generateID(modelPin.name + "_" + bit + "_" + suffix);
-               IOPort ioPort = constr.apply(portID, 2);
-               int index = ioPorts.size();
-               ioPorts.add(ioPort);
-               pinMapping.add(new VerilogEmulatedModelPin(ioPort, index, new PinNameBit(modelPin.name, bit), type));
+               Map<PinNameBit, VerilogEmulatedModelPinBuilder> pinMappingCorrectType = pinMapping.get(type);
+               pinMappingCorrectType.computeIfAbsent(connectedPins.find(pinbit), p ->
+               {
+                       String portID = ioPortIDGen.generateID(p.getName() + "_" + p.getBit() + "_" + suffix);
+                       IOPort ioPort = constr.apply(portID, 2);
+                       int index = ioPorts.size();
+                       ioPorts.add(ioPort);
+                       return new VerilogEmulatedModelPinBuilder(ioPort, index, type);
+               }).addPinbit(pinbit);
        }
 
-       private VerilogComponentImplementation mapImplementation(SubmodelComponent modelComponent,
-                       ModelComponentToVerilogComponentDeclarationMapping declarationMapping)
+       private static class VerilogEmulatedModelPinBuilder
        {
-               UnionFind<PinBit> connectedPins = new UnionFind<>();
-               for (ModelWire w : modelComponent.submodel.getWiresByName().values())
-                       for (int bit = 0; bit < w.getPin1().logicWidth; bit++)
-                               connectedPins.union(new PinBit(w.getPin1(), bit), new PinBit(w.getPin2(), bit));
-
-               Map<UnionFindElement<PinBit>, Signal> currentPreSignals = new HashMap<>();
-               Map<UnionFindElement<PinBit>, NamedSignal> finalOutSignals = new HashMap<>();
-               Map<UnionFindElement<PinBit>, NamedSignal> resSignals = new HashMap<>();
-               for (Pin submodelPin : modelComponent.getSubmodelPins().values())
-                       for (int bit = 0; bit < submodelPin.logicWidth; bit++)
-                       {
-                               PinBit pinbit = new PinBit(submodelPin, bit);
-                               PinNameBit pinnamebit = pinbit.toPinNameBit();
-                               UnionFindElement<PinBit> root = UnionFind.find(connectedPins.getElement(pinbit));
-                               resSignals.put(root, declarationMapping.getResPinMapping().get(pinnamebit).getVerilogPort());
-                               finalOutSignals.put(root, declarationMapping.getOutPinMapping().get(pinnamebit).getVerilogPort());
-                               Signal prePort = declarationMapping.getPrePinMapping().get(pinnamebit).getVerilogPort();
-                               Signal previousPrePort = currentPreSignals.put(root, prePort);
-                               if (previousPrePort != null)
-                                       // TODO implement this
-                                       throw new IllegalArgumentException("Can't convert components with connected pins");
-                       }
+               private final IOPort verilogPort;
+               private final int portIndex;
+               private final Set<PinNameBit> pinbits;
+               private final Type type;
 
-               IdentifierGenerator idGen = new IdentifierGenerator(
-                               declarationMapping.getVerilogComponentDeclaration().getIOPorts().stream().map(IOPort::getName).collect(Collectors.toList()),
-                               ModelComponentToVerilogConverter::sanitizeVerilogID);
-               Set<Wire> internalWires = new HashSet<>();
-               Set<ComponentReference> subcomponents = new HashSet<>();
-               for (ModelComponent subcomponent : modelComponent.submodel.getComponentsByName().values())
+               public VerilogEmulatedModelPinBuilder(IOPort verilogPort, int portIndex, Type type)
                {
-                       // TODO do we really want to use instanceof?
-                       if (subcomponent instanceof ModelSplitter || subcomponent.getName().equals(SubmodelComponent.SUBMODEL_INTERFACE_NAME))
-                               continue;
-
-                       String subcomponentVerilogName = idGen.generateID(subcomponent.getName());
-                       ModelComponentToVerilogComponentDeclarationMapping subcomponentMapping = componentMappingsPerModelIDPerParams
-                                       .get(subcomponent.getIDForSerializing(new IdentifyParams()))
-                                       .get(subcomponent.getParamsForSerializingJSON(new IdentifyParams()));
-                       int parameterCount = subcomponentMapping.getVerilogComponentDeclaration().getIOPorts().size();
-                       List<Signal> arguments = new ArrayList<>(parameterCount);
-                       for (int i = 0; i < parameterCount; i++)
-                               arguments.add(null);
-                       for (Pin pin : subcomponent.getPins().values())
-                               for (int bit = 0; bit < pin.logicWidth; bit++)
-                               {
-                                       PinBit pinbit = new PinBit(pin, bit);
-                                       UnionFindElement<PinBit> root = UnionFind.find(connectedPins.getElement(pinbit));
-                                       Wire outSignal = new Wire(idGen.generateID(subcomponentVerilogName + "_" + pin.name + "_" + bit), 2);
-                                       internalWires.add(outSignal);
-                                       Signal preSignal = currentPreSignals.put(root, outSignal);
-                                       Signal resSignal = resSignals.get(root);
-                                       if (resSignal == null)
-                                       {
-                                               preSignal = new Constant(BitVector.of(Bit.ZERO, 2));
-                                               Wire resWire = new Wire(idGen.generateID(subcomponentVerilogName + "_" + pin.name + "_" + bit + "_res"), 2);
-                                               resSignal = resWire;
-                                               internalWires.add(resWire);
-                                               finalOutSignals.put(root, resWire);
-                                               resSignals.put(root, resWire);
-                                       }
-                                       PinNameBit pinnamebit = pinbit.toPinNameBit();
-                                       arguments.set(subcomponentMapping.getPrePinMapping().get(pinnamebit).getPortIndex(), preSignal);
-                                       arguments.set(subcomponentMapping.getOutPinMapping().get(pinnamebit).getPortIndex(), outSignal);
-                                       arguments.set(subcomponentMapping.getResPinMapping().get(pinnamebit).getPortIndex(), resSignal);
-                               }
-                       subcomponents
-                                       .add(new ComponentReference(subcomponentVerilogName, subcomponentMapping.getVerilogComponentDeclaration(), arguments));
+                       this.verilogPort = verilogPort;
+                       this.portIndex = portIndex;
+                       this.pinbits = new HashSet<>();
+                       this.type = type;
                }
 
-               Set<Assign> assigns = new HashSet<>();
-               for (Entry<UnionFindElement<PinBit>, NamedSignal> e : finalOutSignals.entrySet())
-                       assigns.add(new Assign(currentPreSignals.get(e.getKey()), e.getValue()));
+               public void addPinbit(PinNameBit pinbit)
+               {
+                       pinbits.add(pinbit);
+               }
+
+               public VerilogEmulatedModelPin build()
+               {
+                       return new VerilogEmulatedModelPin(verilogPort, portIndex, pinbits, type);
+               }
+       }
 
-               return new VerilogComponentImplementation(declarationMapping.getVerilogComponentDeclaration(), internalWires, assigns,
-                               subcomponents);
+       public ModelComponentToVerilogComponentDeclarationMapping getComponentMapping(ModelComponent component)
+       {
+               ModelComponentToVerilogComponentDeclarationMapping subcomponentMapping = componentMappingsPerModelIDPerParams
+                               .get(component.getIDForSerializing(new IdentifyParams())).get(component.getParamsForSerializingJSON(new IdentifyParams()));
+               return subcomponentMapping;
        }
 
-       private Set<VerilogComponentImplementation> getVerilogComponents()
+       public Set<VerilogComponentImplementation> getVerilogComponents()
        {
                return verilogComponents;
        }
@@ -213,6 +168,14 @@ public class ModelComponentToVerilogConverter
                return converter.getVerilogComponents();
        }
 
+       public static IdentifierGenerator generateIdentifierGenerator(VerilogComponentDeclaration declaration)
+       {
+               IdentifierGenerator idGen = new IdentifierGenerator(
+                               declaration.getIOPorts().stream().map(IOPort::getName).collect(Collectors.toList()),
+                               ModelComponentToVerilogConverter::sanitizeVerilogID);
+               return idGen;
+       }
+
        public static String sanitizeVerilogID(String id)
        {
                return (id.matches("[0-9].*") ? "_" + id : id).replaceAll("[^A-Za-z0-9_]", "_");