Skip to content

Commit

Permalink
Prevent forks after zero delay buffers/inverters
Browse files Browse the repository at this point in the history
  • Loading branch information
danilovesky committed Oct 28, 2024
1 parent 1fba82b commit 4235270
Show file tree
Hide file tree
Showing 11 changed files with 200 additions and 106 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ public Circuit() {

public Circuit(Container root, References refs) {
super(root, new CircuitReferenceManager(refs));
new FunctionConsistencySupervisor().attach(getRoot());
new FunctionConsistencySupervisor(this).attach(getRoot());
new ZeroDelayConsistencySupervisor(this).attach(getRoot());
new IOTypeConsistencySupervisor(this).attach(getRoot());
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -211,23 +211,12 @@ public static void setRefinementIfCompatible(VisualCircuit circuit, VisualFuncti
if (answer == 0) {
RefinementUtils.updateInitialState(component.getReferencedComponent(), refinementOutputInitialState);
}

}

Set<String> constrainedPins = RefinementUtils.getConstrainedPins(component);
if (!constrainedPins.isEmpty()) {
String message = "Component has constrained pins that may conflict with the refinement model."
+ "\n\nRemove set/reset functions for the component pins?";

int answer = DialogUtils.showYesNoCancel(message, title);
if (answer == 2) {
return;
}
if (answer == 0) {
RefinementUtils.removeComponentFunctions(component);
}
RefinementUtils.removeComponentFunctions(component);
}

component.getReferencedComponent().setRefinement(value);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -156,4 +156,8 @@ public boolean isAvoidInitPin() {
return (getParent() instanceof FunctionComponent) && ((FunctionComponent) getParent()).getAvoidInit();
}

public boolean isCellPin() {
return (getParent() instanceof FunctionComponent) && ((FunctionComponent) getParent()).isCell();
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -122,35 +122,48 @@ public void validateConnection(VisualNode first, VisualNode second) throws Inval
if (secondNode == null) {
throw new InvalidConnectionException("Cannot detect connection destination.");
}

Circuit circuit = getMathModel();
Contact driver = CircuitUtils.findDriver(circuit, firstNode, false);
Set<Contact> drivenSet = new HashSet<>(CircuitUtils.findDriven(circuit, secondNode, false));
Collection<Contact> existingDrivenSet = CircuitUtils.findDriven(circuit, driver, false);
Collection<Contact> newDrivenSet = CircuitUtils.findDriven(circuit, secondNode, false);

// Math connection may already be present in the model, e.g. when a default visual layer is created for existing
// math model via createDefaultStructure. Therefore, newDrivenSet should be subtracted from existingDrivenSet.
existingDrivenSet.removeAll(newDrivenSet);

// Forbid zero-delay component to drive another zero-delay component or output port
if ((driver != null) && (driver.isZeroDelayPin())) {
for (Contact driven : drivenSet) {
if (driven.isZeroDelayPin()) {
throw new InvalidConnectionException("Zero delay components cannot drive each other.");
}
if (driven.isOutput() && driven.isPort()) {
throw new InvalidConnectionException("Zero delay component cannot drive output port.");
}
if (!existingDrivenSet.isEmpty() || newDrivenSet.size() > 1) {
throw new InvalidConnectionException("Zero delay component cannot have a fork on its output.");
}
Contact newDriven = newDrivenSet.iterator().next();
if ((newDriven != null) && newDriven.isZeroDelayPin()) {
throw new InvalidConnectionException("Zero delay components cannot drive each other.");
}
if ((newDriven != null) && newDriven.isOutput() && newDriven.isPort()) {
throw new InvalidConnectionException("Zero delay component cannot drive output port.");
}
if ((newDriven != null) && !newDriven.isCellPin()) {
throw new InvalidConnectionException("Zero delay components cannot drive hierarchical components.");
}
}
// Forbid input port to drive output port (zero delay components are forbidden to drive output ports)
if ((driver != null) && driver.isInput() && driver.isPort()) {
for (Contact driven : drivenSet) {
for (Contact driven : newDrivenSet) {
if (driven.isOutput() && driven.isPort()) {
throw new InvalidConnectionException("Input port cannot drive output port.");
}
}
}
// Forbid fork to several output ports (zero delay components are forbidden to drive output ports)
drivenSet.addAll(CircuitUtils.findDriven(circuit, firstNode, false));
Set<Contact> combinedDrivenSet = new HashSet<>(existingDrivenSet);
combinedDrivenSet.addAll(newDrivenSet);
int outputPortCount = 0;
for (Contact driven : drivenSet) {
for (Contact driven : combinedDrivenSet) {
if (driven.isOutput() && driven.isPort()) {
if (outputPortCount > 0) {
throw new InvalidConnectionException("Fork several output ports is not allowed.");
throw new InvalidConnectionException("Fork to several output ports is not allowed.");
}
outputPortCount++;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ public void transformNode(VisualModel model, VisualNode node) {

private boolean isValidContraction(VisualCircuit circuit, VisualCircuitComponent component) {
Collection<VisualContact> inputContacts = component.getVisualInputs();
String componentName = circuit.getMathName(component);
String componentName = circuit.getMathModel().getComponentReference(component.getReferencedComponent());
if (inputContacts.size() > 2) {
LogUtils.logError("Cannot contract component '" + componentName + "' with " + inputContacts.size() + " inputs.");
return false;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
import org.workcraft.plugins.circuit.utils.CircuitUtils;
import org.workcraft.plugins.circuit.utils.ConversionUtils;
import org.workcraft.plugins.circuit.utils.GateUtils;
import org.workcraft.plugins.circuit.utils.ZeroDelayUtils;
import org.workcraft.types.Pair;
import org.workcraft.utils.LogUtils;
import org.workcraft.workspace.ModelEntry;
Expand Down Expand Up @@ -76,6 +77,11 @@ public void transformGate(VisualCircuit circuit, VisualFunctionComponent gate) {
}

private static void splitComplexGate(VisualCircuit circuit, VisualFunctionComponent complexGate, SplitForm functions) {
Set<FunctionComponent> savedZeroDelayComponents = ZeroDelayUtils.getPrecedingZeroDelayComponents(
circuit.getMathModel(), complexGate.getReferencedComponent());

savedZeroDelayComponents.forEach(component -> component.setIsZeroDelay(false));

List<NodeConnectionPair> fromNodeConnections = getComponentDriverNodes(circuit, complexGate);
Set<NodeConnectionPair> toNodeConnections = getComponentNonLoopDrivenNodes(circuit, complexGate);
Container container = (Container) complexGate.getParent();
Expand Down Expand Up @@ -116,6 +122,7 @@ private static void splitComplexGate(VisualCircuit circuit, VisualFunctionCompon
}
propagateInitValues(circuit, nonRootGates);
circuit.remove(complexGate);
ZeroDelayUtils.setZeroDelayIfPossible(circuit.getMathModel(), savedZeroDelayComponents);
}

private static void connectTerminal(VisualCircuit circuit, Iterator<NodeConnectionPair> fromNodeConnectionIterator,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ public static FunctionComponent instantiateGate(Gate gate, String instanceName,
try {
circuit.setName(component, instanceName);
} catch (ArgumentException e) {
String componentName = circuit.getName(component);
String componentName = circuit.getComponentReference(component);
LogUtils.logWarning("Cannot set name '" + instanceName + "' for component '" + componentName + "'");
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,35 +3,74 @@
import org.workcraft.dom.Node;
import org.workcraft.formula.BooleanFormula;
import org.workcraft.formula.FormulaUtils;
import org.workcraft.observation.HierarchyEvent;
import org.workcraft.observation.HierarchySupervisor;
import org.workcraft.observation.NodesDeletingEvent;
import org.workcraft.observation.PropertyChangedEvent;
import org.workcraft.observation.StateEvent;
import org.workcraft.observation.StateSupervisor;
import org.workcraft.plugins.circuit.Circuit;
import org.workcraft.plugins.circuit.Contact;
import org.workcraft.plugins.circuit.FunctionComponent;
import org.workcraft.plugins.circuit.FunctionContact;
import org.workcraft.plugins.circuit.utils.StructureUtils;
import org.workcraft.utils.Hierarchy;

import java.util.ArrayList;

public class FunctionConsistencySupervisor extends HierarchySupervisor {
public class FunctionConsistencySupervisor extends StateSupervisor {

private final Circuit circuit;

public FunctionConsistencySupervisor(Circuit circuit) {
this.circuit = circuit;
}

@Override
public void handleEvent(HierarchyEvent e) {
public void handleEvent(StateEvent e) {
if (e instanceof PropertyChangedEvent) {
PropertyChangedEvent pce = (PropertyChangedEvent) e;
Object sender = e.getSender();
String propertyName = pce.getPropertyName();
if ((sender instanceof FunctionContact)
&& (propertyName.equals(FunctionContact.PROPERTY_FUNCTION))) {

handleFunctionChange((FunctionContact) sender);
}
}
if (e instanceof NodesDeletingEvent) {
for (Node node : e.getAffectedNodes()) {
NodesDeletingEvent nde = (NodesDeletingEvent) e;
for (Node node : nde.getAffectedNodes()) {
if (node instanceof Contact) {
// Update all set/reset functions when a contact is removed
final Contact contact = (Contact) node;
Contact contact = (Contact) node;
handleContactRemoval(contact);
}
}
}
}

private void handleContactRemoval(final Contact contact) {
final ArrayList<FunctionContact> functionContacts = new ArrayList<>(
private void handleFunctionChange(FunctionContact contact) {
Node parent = contact.getParent();
if (parent instanceof FunctionComponent) {
FunctionComponent component = (FunctionComponent) parent;
if (!component.isBuffer() && !component.isInverter()) {
component.setIsZeroDelay(false);
}
if (!component.isBlackbox()) {
component.setRefinement(null);
}
if (!component.isCell()) {
for (FunctionComponent predComponent : StructureUtils.getPresetComponents(circuit, component)) {
predComponent.setIsZeroDelay(false);
}
}
}
}

private void handleContactRemoval(Contact contact) {
ArrayList<FunctionContact> functionContacts = new ArrayList<>(
Hierarchy.getChildrenOfType(getRoot(), FunctionContact.class));

for (final FunctionContact functionContact : functionContacts) {
for (FunctionContact functionContact : functionContacts) {
BooleanFormula setFunction = FormulaUtils.remove(functionContact.getSetFunction(), contact);
BooleanFormula resetFunction = FormulaUtils.remove(functionContact.getResetFunction(), contact);
functionContact.setBothFunctions(setFunction, resetFunction);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,14 +1,15 @@
package org.workcraft.plugins.circuit.observers;

import org.workcraft.dom.Node;
import org.workcraft.exceptions.ArgumentException;
import org.workcraft.observation.PropertyChangedEvent;
import org.workcraft.observation.StateEvent;
import org.workcraft.observation.StateSupervisor;
import org.workcraft.plugins.circuit.*;
import org.workcraft.plugins.circuit.Circuit;
import org.workcraft.plugins.circuit.Contact;
import org.workcraft.plugins.circuit.FunctionComponent;
import org.workcraft.plugins.circuit.utils.CircuitUtils;
import org.workcraft.plugins.circuit.utils.StructureUtils;

import java.util.Set;
import org.workcraft.plugins.circuit.utils.ZeroDelayUtils;

public class ZeroDelayConsistencySupervisor extends StateSupervisor {

Expand All @@ -24,11 +25,6 @@ public void handleEvent(StateEvent e) {
PropertyChangedEvent pce = (PropertyChangedEvent) e;
Object sender = e.getSender();
String propertyName = pce.getPropertyName();
if ((sender instanceof FunctionContact)
&& (propertyName.equals(FunctionContact.PROPERTY_FUNCTION))) {

handleFunctionChange((FunctionContact) sender);
}
if ((sender instanceof FunctionComponent)
&& propertyName.equals(FunctionComponent.PROPERTY_IS_ZERO_DELAY)) {

Expand All @@ -42,55 +38,32 @@ public void handleEvent(StateEvent e) {
}
}

private void handleFunctionChange(FunctionContact contact) {
Node parent = contact.getParent();
if (parent instanceof FunctionComponent) {
FunctionComponent component = (FunctionComponent) parent;
component.setIsZeroDelay(false);
}
}

private void handleZeroDelayChange(FunctionComponent component) {
if (component.getIsZeroDelay()) {
for (Contact contact : component.getOutputs()) {
contact.setForcedInit(false);
contact.setPathBreaker(false);
}
if (!component.isInverter() && !component.isBuffer()) {
component.setIsZeroDelay(false);
throw new ArgumentException("Only inverters and buffers can be zero delay.");
}
Set<CircuitComponent> componentPreset = StructureUtils.getPresetComponents(circuit, component);
for (CircuitComponent predComponent: componentPreset) {
if (predComponent instanceof FunctionComponent) {
FunctionComponent predFunctionComponent = (FunctionComponent) predComponent;
if (predFunctionComponent.getIsZeroDelay()) {
component.setIsZeroDelay(false);
throw new ArgumentException("Zero delay components cannot be connected to each other.");
}
}
if (ZeroDelayUtils.hasAdjacentZeroDelayComponent(circuit, component)) {
component.setIsZeroDelay(false);
throw new ArgumentException("Zero delay components cannot be connected to each other.");
}
Set<CircuitComponent> componentPostset = StructureUtils.getPostsetComponents(circuit, component);
for (CircuitComponent succComponent: componentPostset) {
if (succComponent instanceof FunctionComponent) {
FunctionComponent succFunctionComponent = (FunctionComponent) succComponent;
if (succFunctionComponent.getIsZeroDelay()) {
component.setIsZeroDelay(false);
throw new ArgumentException("Zero delay components cannot be connected to each other.");
}
}
if (ZeroDelayUtils.hasDrivenHierarchicalComponent(circuit, component)) {
component.setIsZeroDelay(false);
throw new ArgumentException("Zero delay component cannot drive hierarchical component.");
}
Set<Contact> portPostset = StructureUtils.getPostsetPorts(circuit, component);
for (Contact succContact: portPostset) {
if (succContact.isPort()) {
component.setIsZeroDelay(false);
throw new ArgumentException("A component connected to an output port cannot be zero delay.");
}
if (!StructureUtils.getPostsetPorts(circuit, component).isEmpty()) {
component.setIsZeroDelay(false);
throw new ArgumentException("A component driving an output port cannot be zero delay.");
}
if (componentPostset.size() + portPostset.size() > 1) {
if (CircuitUtils.findDriven(circuit, component.getGateOutput(), false).size() > 1) {
component.setIsZeroDelay(false);
throw new ArgumentException("A component with a fork at its output cannot be zero delay.");
}
for (Contact contact : component.getOutputs()) {
contact.setForcedInit(false);
contact.setPathBreaker(false);
}
}
}

Expand Down
Loading

0 comments on commit 4235270

Please sign in to comment.