Repository: workcraft/workcraft
Issue: Error on Verilog export

When exporting verilog from a circuit with standard C-gates, the resulting file does not
import correctly. The reason is that the assignments representing C-gates are wrong. The
C-gate output has been concatenated to onto the previous variable instead of being ORed.

From the example:
```
    assign gn = assign_gn_SET__o & assign_gn_nRESET__ogn& (~~(assign_gn_SET__o | assign_gn_nRESET__o));
```
should be
```
    assign gn = assign_gn_SET__o & assign_gn_nRESET__o | gn & (~~(assign_gn_SET__o | assign_gn_nRESET__o));
```
Clearly importing the incorrect verilog will give the wrong answer as there is no signal called `assign_gn_nRESET__ogn`.

Having corrected the verilog the import works in that the circuit is conformant with the original STG, but the
C-gate isn't recognised as a C-gate and is represented by a complex gate with loop-back.

Note that I have included .work files created from the imported verilog. However they won't open again. I've also
noticed that saving the .work and opening it again works. Closing the circuit window then opening the .work fails.

So there are three problems where
  1. Output verilog for a C-gate is incorrect.
  2. C-gate isn't recognised when importing assignment based verilog.
  3. Saving the imported verilog results in a corrupt .work file.

Files:
  * [all_zc.work.zip](https://github.com/tuura/workcraft/files/668935/all_zc.work.zip) - original STG.

  * [all_zc_circuit.work.zip](https://github.com/tuura/workcraft/files/668934/all_zc_circuit.work.zip) - result of synthesis with "Standard C-element [MpSat]"

  * [all_zc_circuit.v.txt](https://github.com/tuura/workcraft/files/668944/all_zc_circuit.v.txt) - result of exporting verilog from all_zc_cicuit.work

  * [all_zc_circuit.v.work.zip](https://github.com/tuura/workcraft/files/668936/all_zc_circuit.v.work.zip)        result of importing all_zc_circuit.v, will not read in.

  * [all_zc_circuit_fixed.v.txt](https://github.com/tuura/workcraft/files/668945/all_zc_circuit_fixed.v.txt) - fixed version of all_zc_circuit.v

  * [all_zc_circuit_fixed.v.work.zip](https://github.com/tuura/workcraft/files/668937/all_zc_circuit_fixed.v.work.zip) - result of importing all_zc_circuit_fixed.v, will not read in.

Changed files:
WorkcraftCore/src/org/workcraft/Framework.java
CircuitPlugin/src/org/workcraft/plugins/circuit/CircuitUtils.java
CircuitPlugin/src/org/workcraft/plugins/circuit/interop/VerilogImporter.java
CircuitPlugin/src/org/workcraft/plugins/circuit/serialisation/VerilogSerialiser.java

diff --git a/CircuitPlugin/src/org/workcraft/plugins/circuit/CircuitUtils.java b/CircuitPlugin/src/org/workcraft/plugins/circuit/CircuitUtils.java
index 29d4d8b30..0be3e1293 100644
--- a/CircuitPlugin/src/org/workcraft/plugins/circuit/CircuitUtils.java
+++ b/CircuitPlugin/src/org/workcraft/plugins/circuit/CircuitUtils.java
@@ -183,19 +183,6 @@ public class CircuitUtils {
         return circuit.getVisualComponent(mathSignal, VisualContact.class);
     }
 
-    public static String getWireName(Circuit circuit, Contact contact) {
-        String result = null;
-        if (!circuit.getPreset(contact).isEmpty() || !circuit.getPostset(contact).isEmpty()) {
-            Contact signal = findSignal(circuit, contact, false);
-            result = getContactName(circuit, signal);
-        }
-        return result;
-    }
-
-    public static String getWireName(VisualCircuit circuit, VisualContact contact) {
-        return getWireName((Circuit) circuit.getMathModel(), contact.getReferencedContact());
-    }
-
     public static String getSignalName(Circuit circuit, Contact contact) {
         String result = null;
         if (contact.isPort() || contact.isInput()) {
diff --git a/CircuitPlugin/src/org/workcraft/plugins/circuit/interop/VerilogImporter.java b/CircuitPlugin/src/org/workcraft/plugins/circuit/interop/VerilogImporter.java
index 565e47129..5f4ab6e1d 100644
--- a/CircuitPlugin/src/org/workcraft/plugins/circuit/interop/VerilogImporter.java
+++ b/CircuitPlugin/src/org/workcraft/plugins/circuit/interop/VerilogImporter.java
@@ -39,7 +39,10 @@ import java.util.Set;
 import org.workcraft.Framework;
 import org.workcraft.dom.Connection;
 import org.workcraft.dom.Node;
+import org.workcraft.dom.hierarchy.NamespaceProvider;
 import org.workcraft.dom.math.MathNode;
+import org.workcraft.dom.references.HierarchicalUniqueNameReferenceManager;
+import org.workcraft.dom.references.NameManager;
 import org.workcraft.exceptions.ArgumentException;
 import org.workcraft.exceptions.DeserialisationException;
 import org.workcraft.exceptions.FormatException;
@@ -93,7 +96,6 @@ public class VerilogImporter implements Importer {
 
     private static final String PRIMITIVE_GATE_INPUT_PREFIX = "i";
     private static final String PRIMITIVE_GATE_OUTPUT_NAME = "o";
-    private static final String ASSIGN_GATE_PREFIX = "assign_";
 
     private final boolean sequentialAssign;
 
@@ -252,12 +254,7 @@ public class VerilogImporter implements Importer {
     private FunctionComponent createAssignGate(Circuit circuit, Assign assign, HashMap<String, Wire> wires) {
         final FunctionComponent component = new FunctionComponent();
         circuit.add(component);
-        String componentName = getAssignComponentName(assign.name);
-        try {
-            circuit.setName(component, componentName);
-        } catch (ArgumentException e) {
-            LogUtils.logWarningLine("Cannot set name '" + componentName + "' for component '" + circuit.getName(component) + "'.");
-        }
+        setAssignComponentName(circuit, component, assign.name);
 
         AssignGate assignGate = null;
         if (sequentialAssign && isSequentialAssign(assign)) {
@@ -300,8 +297,19 @@ public class VerilogImporter implements Importer {
         return component;
     }
 
-    private String getAssignComponentName(String name) {
-        return ASSIGN_GATE_PREFIX + removeLeadingAndTrailingSymbol(name, '_');
+    private void setAssignComponentName(Circuit circuit, FunctionComponent component, String name) {
+        HierarchicalUniqueNameReferenceManager refManager
+                = (HierarchicalUniqueNameReferenceManager) circuit.getReferenceManager();
+
+        NamespaceProvider namespaceProvider = refManager.getNamespaceProvider(circuit.getRoot());
+        NameManager nameManagerer = refManager.getNameManager(namespaceProvider);
+        String candidateName = removeLeadingAndTrailingSymbol(name, '_');
+        String componentName = nameManagerer.getDerivedName(component, candidateName);
+        try {
+            circuit.setName(component, componentName);
+        } catch (ArgumentException e) {
+            LogUtils.logWarningLine("Cannot set name '" + componentName + "' for component '" + circuit.getName(component) + "'.");
+        }
     }
 
     private String removeLeadingAndTrailingSymbol(String s, char c) {
diff --git a/CircuitPlugin/src/org/workcraft/plugins/circuit/serialisation/VerilogSerialiser.java b/CircuitPlugin/src/org/workcraft/plugins/circuit/serialisation/VerilogSerialiser.java
index 7f9aed23e..216f1a040 100644
--- a/CircuitPlugin/src/org/workcraft/plugins/circuit/serialisation/VerilogSerialiser.java
+++ b/CircuitPlugin/src/org/workcraft/plugins/circuit/serialisation/VerilogSerialiser.java
@@ -29,6 +29,7 @@ import java.util.LinkedList;
 import java.util.UUID;
 
 import org.workcraft.dom.Model;
+import org.workcraft.dom.Node;
 import org.workcraft.dom.hierarchy.NamespaceHelper;
 import org.workcraft.exceptions.ArgumentException;
 import org.workcraft.formula.BooleanFormula;
@@ -58,6 +59,7 @@ public class VerilogSerialiser implements ModelSerialiser {
     private static final String KEYWORD_INPUT = "input";
     private static final String KEYWORD_MODULE = "module";
     private static final String KEYWORD_ENDMODULE = "endmodule";
+    private static final String KEYWORD_ASSIGN = "assign";
 
     class ReferenceResolver implements ReferenceProducer {
         HashMap<Object, String> refMap = new HashMap<>();
@@ -101,7 +103,34 @@ public class VerilogSerialiser implements ModelSerialiser {
         return Format.VERILOG;
     }
 
+    private final HashMap<Contact, String> contactWires = new HashMap<>();
+
+    private String getWireName(Circuit circuit, Contact contact) {
+        String result = contactWires.get(contact);
+        if (result == null) {
+            if (!circuit.getPreset(contact).isEmpty() || !circuit.getPostset(contact).isEmpty()) {
+                Contact signal = CircuitUtils.findSignal(circuit, contact, false);
+                Node parent = signal.getParent();
+                boolean isAssignOutput = false;
+                if (parent instanceof FunctionComponent) {
+                    FunctionComponent component = (FunctionComponent) parent;
+                    isAssignOutput = signal.isOutput() && !component.isMapped();
+                }
+                if (isAssignOutput) {
+                    result = CircuitUtils.getSignalName(circuit, signal);
+                } else {
+                    result = CircuitUtils.getContactName(circuit, signal);
+                }
+            }
+            if (result != null) {
+                contactWires.put(contact, result);
+            }
+        }
+        return result;
+    }
+
     private void writeCircuit(PrintWriter out, Circuit circuit) {
+        contactWires.clear();
         writeHeader(out, circuit);
         writeInstances(out, circuit);
         writeInitialState(out, circuit);
@@ -184,7 +213,7 @@ public class VerilogSerialiser implements ModelSerialiser {
         LinkedList<BooleanFormula> values = new LinkedList<>();
         for (FunctionContact contact: component.getFunctionContacts()) {
             if (contact.isOutput()) continue;
-            String wireName = CircuitUtils.getWireName(circuit, contact);
+            String wireName = getWireName(circuit, contact);
             BooleanFormula wire = signals.get(wireName);
             if (wire != null) {
                 variables.add(contact);
@@ -194,7 +223,12 @@ public class VerilogSerialiser implements ModelSerialiser {
         for (FunctionContact contact: component.getFunctionContacts()) {
             if (contact.isInput()) continue;
             String formula = null;
-            String wireName = CircuitUtils.getWireName(circuit, contact);
+            String wireName = getWireName(circuit, contact);
+            if ((wireName == null) || wireName.isEmpty()) {
+                String contactName = contact.getName();
+                LogUtils.logWarningLine("In component '" + instanceFlatName + "' contact '" + contactName + "' is disconnected.");
+                continue;
+            }
             BooleanFormula setFunction = BooleanUtils.cleverReplace(contact.getSetFunction(), variables, values);
             String setFormula = FormulaToString.toString(setFunction, Style.VERILOG);
             BooleanFormula resetFunction = BooleanUtils.cleverReplace(contact.getResetFunction(), variables, values);
@@ -203,14 +237,14 @@ public class VerilogSerialiser implements ModelSerialiser {
             }
             String resetFormula = FormulaToString.toString(resetFunction, Style.VERILOG);
             if (!setFormula.isEmpty() && !resetFormula.isEmpty()) {
-                formula = setFormula + wireName + "& (" + resetFormula + ")";
+                formula = setFormula + " | " + wireName + " & (" + resetFormula + ")";
             } else if (!setFormula.isEmpty()) {
                 formula = setFormula;
             } else if (!resetFormula.isEmpty()) {
                 formula = resetFormula;
             }
             if ((formula != null) && !formula.isEmpty()) {
-                out.println("    assign " + wireName + " = " + formula + ";");
+                out.println("    " + KEYWORD_ASSIGN + " " + wireName + " = " + formula + ";");
                 result = true;
             }
         }
@@ -223,7 +257,7 @@ public class VerilogSerialiser implements ModelSerialiser {
             String signalName = null;
             BooleanFormula signal = null;
             if (contact.isDriver()) {
-                signalName = CircuitUtils.getWireName(circuit, contact);
+                signalName = getWireName(circuit, contact);
                 if (contact.isPort()) {
                     signal = contact;
                 } else {
@@ -261,7 +295,7 @@ public class VerilogSerialiser implements ModelSerialiser {
             } else {
                 out.print(", ");
             }
-            String wireName = CircuitUtils.getWireName(circuit, contact);
+            String wireName = getWireName(circuit, contact);
             if ((wireName == null) || wireName.isEmpty()) {
                 String contactName = contact.getName();
                 LogUtils.logWarningLine("In component '" + instanceFlatName + "' contact '" + contactName + "' is disconnected.");
@@ -287,7 +321,7 @@ public class VerilogSerialiser implements ModelSerialiser {
         out.println("    // signal values at the initial state:");
         out.print("    //");
         for (Contact contact: contacts) {
-            String wireName = CircuitUtils.getWireName(circuit, contact);
+            String wireName = getWireName(circuit, contact);
             if ((wireName != null) && !wireName.isEmpty()) {
                 out.print(" ");
                 if (!contact.getInitToOne()) {
diff --git a/WorkcraftCore/src/org/workcraft/Framework.java b/WorkcraftCore/src/org/workcraft/Framework.java
index e69ea8e70..f17470a30 100644
--- a/WorkcraftCore/src/org/workcraft/Framework.java
+++ b/WorkcraftCore/src/org/workcraft/Framework.java
@@ -579,27 +579,29 @@ public final class Framework {
         return null;
     }
 
-    public WorkspaceEntry createWork(ModelEntry me, Path<String> path) {
+    public WorkspaceEntry createWork(ModelEntry me, Path<String> directory, String desiredName) {
+        final Path<String> path = getWorkspace().createWorkPath(directory, desiredName);
+        boolean open = me.isVisual() || CommonEditorSettings.getOpenNonvisual();
+        return createWork(me, path, open, true);
+    }
+
+    private WorkspaceEntry createWork(ModelEntry me, Path<String> path, boolean open, boolean changed) {
         WorkspaceEntry we = new WorkspaceEntry(getWorkspace());
-        we.setChanged(true);
+        we.setChanged(changed);
         we.setModelEntry(createVisual(me));
         getWorkspace().addWork(path, we);
-        boolean openInEditor = me.isVisual() || CommonEditorSettings.getOpenNonvisual();
-        if (openInEditor && isInGuiMode()) {
+        if (open && isInGuiMode()) {
             getMainWindow().createEditorWindow(we);
         }
         return we;
     }
 
-    public WorkspaceEntry createWork(ModelEntry me, Path<String> directory, String desiredName) {
-        final Path<String> path = getWorkspace().createWorkPath(directory, desiredName);
-        return createWork(me, path);
-    }
-
     private ModelEntry createVisual(ModelEntry me) {
         ModelEntry result = me;
         VisualModel visualModel = me.getVisualModel();
-        if (visualModel == null) {
+        if (visualModel != null) {
+            visualModel.selectNone();
+        } else {
             ModelDescriptor descriptor = me.getDescriptor();
             VisualModelDescriptor vmd = descriptor.getVisualModelDescriptor();
             if (vmd == null) {
@@ -642,33 +644,35 @@ public final class Framework {
 
     public WorkspaceEntry loadWork(File file) throws DeserialisationException {
         // Check if work is already loaded
-        Path<String> workspacePath = getWorkspace().getPath(file);
+        Path<String> path = getWorkspace().getPath(file);
         for (WorkspaceEntry we : getWorkspace().getWorks()) {
-            if (we.getWorkspacePath().equals(workspacePath)) {
+            if (we.getWorkspacePath().equals(path)) {
                 return we;
             }
         }
 
         // Load (from *.work) or import (other extensions) work
-        WorkspaceEntry we = new WorkspaceEntry(getWorkspace());
-        we.setChanged(false);
+        ModelEntry me = null;
         if (file.getName().endsWith(FileFilters.DOCUMENT_EXTENSION)) {
-            we.setModelEntry(loadModel(file));
-            if (workspacePath == null) {
-                workspacePath = getWorkspace().tempMountExternalFile(file);
+            if (path == null) {
+                path = getWorkspace().tempMountExternalFile(file);
             }
+            me = loadModel(file);
         } else {
-            we.setModelEntry(importModel(file));
             Path<String> parent;
-            if (workspacePath == null) {
+            if (path == null) {
                 parent = Path.empty();
             } else {
-                parent = workspacePath.getParent();
+                parent = path.getParent();
             }
             String desiredName = FileUtils.getFileNameWithoutExtension(file);
-            workspacePath = getWorkspace().createWorkPath(parent, desiredName);
+            path = getWorkspace().createWorkPath(parent, desiredName);
+            me = importModel(file);
+        }
+        WorkspaceEntry we = null;
+        if (me != null) {
+            we = createWork(me, path, false, false);
         }
-        getWorkspace().addWork(workspacePath, we);
         return we;
     }