diff --git a/src/main/java/org/manifold/compiler/back/digital/Check.java b/src/main/java/org/manifold/compiler/back/digital/Check.java new file mode 100644 index 0000000..f028ad4 --- /dev/null +++ b/src/main/java/org/manifold/compiler/back/digital/Check.java @@ -0,0 +1,22 @@ +package org.manifold.compiler.back.digital; + +import org.manifold.compiler.UndefinedBehaviourError; + +public abstract class Check { + protected abstract void verify(); + + protected Boolean result = null; + + public boolean run() { + if (result == null) { + verify(); + // ensure that the check set a result + if (result == null) { + throw new UndefinedBehaviourError( + "Design rule check run produced no result"); + } + } + return result; + } + // TODO(murphy) get list of failures +} diff --git a/src/main/java/org/manifold/compiler/back/digital/NoMultipleDriversCheck.java b/src/main/java/org/manifold/compiler/back/digital/NoMultipleDriversCheck.java new file mode 100644 index 0000000..2332d8b --- /dev/null +++ b/src/main/java/org/manifold/compiler/back/digital/NoMultipleDriversCheck.java @@ -0,0 +1,64 @@ +package org.manifold.compiler.back.digital; + +import java.util.Map; + +import org.manifold.compiler.PortTypeValue; +import org.manifold.compiler.PortValue; +import org.manifold.compiler.UndeclaredIdentifierException; +import org.manifold.compiler.UndefinedBehaviourError; +import org.manifold.compiler.middle.Schematic; + + +public class NoMultipleDriversCheck extends Check { + + private Schematic schematic; + private Netlist netlist; + private PortTypeValue digitalOutType; + + public NoMultipleDriversCheck(Schematic schematic, Netlist netlist) { + this.schematic = schematic; + this.netlist = netlist; + try { + this.digitalOutType = schematic.getPortType("digitalOut"); + } catch (UndeclaredIdentifierException e) { + throw new UndefinedBehaviourError( + "schematic does not define digitalOut port type"); + } + } + + @Override + protected void verify() { + System.err.println("expected digital out type = " + + digitalOutType.toString()); + Map allNets = netlist.getNets(); + boolean noMultipleDrivers = true; + for (Net net : allNets.values()) { + int nDrivers = 0; + // a driver is any Port of type `digitalOutType` + for (PortValue port : net.getConnectedPorts()) { + System.err.println("port type = " + + port.getType().toString()); + if (port.getType() == digitalOutType) { + nDrivers += 1; + } + } + /* + * after checking all ports on this net, if there are at least 2 drivers + * then this net is multiply-driven and DRC fails + */ + if (nDrivers >= 2) { + noMultipleDrivers = false; + } + /* + * TODO(murphy) If all we care about is the decision, we can break here. + * However, we should keep processing in order to collect a list of which + * nets are multiply driven, and the ports that are driving them. This + * will be useful when showing the user the results of DRC so they can + * correct the design. + * This is described in Issue #131. + */ + } + this.result = noMultipleDrivers; + } + +} diff --git a/src/test/java/org/manifold/compiler/back/TestNetlist.java b/src/test/java/org/manifold/compiler/back/TestNetlist.java index e617130..5b4453e 100644 --- a/src/test/java/org/manifold/compiler/back/TestNetlist.java +++ b/src/test/java/org/manifold/compiler/back/TestNetlist.java @@ -1,25 +1,15 @@ package org.manifold.compiler.back; -import static org.junit.Assert.*; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; -import java.util.HashMap; import java.util.Map; import org.junit.BeforeClass; import org.junit.Test; -import org.manifold.compiler.BooleanTypeValue; -import org.manifold.compiler.BooleanValue; -import org.manifold.compiler.ConnectionType; import org.manifold.compiler.ConnectionValue; -import org.manifold.compiler.InvalidAttributeException; -import org.manifold.compiler.MultipleDefinitionException; -import org.manifold.compiler.NodeTypeValue; import org.manifold.compiler.NodeValue; -import org.manifold.compiler.PortTypeValue; -import org.manifold.compiler.PortValue; -import org.manifold.compiler.TypeValue; -import org.manifold.compiler.UndeclaredAttributeException; -import org.manifold.compiler.Value; import org.manifold.compiler.back.digital.Net; import org.manifold.compiler.back.digital.Netlist; import org.manifold.compiler.middle.Schematic; @@ -27,173 +17,40 @@ public class TestNetlist { - private static PortTypeValue digitalInPortType; - private static PortTypeValue digitalOutPortType; - - private static final Map noTypeAttributes - = new HashMap<>(); - private static final Map noAttributes - = new HashMap<>(); - - private static Map registerTypeAttributes - = new HashMap<>(); - private static Map registerTypePorts - = new HashMap<>(); - private static NodeTypeValue registerType; - - private static Map inputPinTypePorts - = new HashMap<>(); - private static NodeTypeValue inputPinType; - - private static Map outputPinTypePorts - = new HashMap<>(); - private static NodeTypeValue outputPinType; - - private static ConnectionType digitalWireType; - - @BeforeClass - public static void setupIntermediateTypes(){ - - digitalInPortType = new PortTypeValue(noTypeAttributes); - digitalOutPortType = new PortTypeValue(noTypeAttributes); - - registerTypeAttributes.put("initialValue", - BooleanTypeValue.getInstance()); - registerTypeAttributes.put("resetActiveHigh", - BooleanTypeValue.getInstance()); - registerTypeAttributes.put("resetAsynchronous", - BooleanTypeValue.getInstance()); - registerTypeAttributes.put("clockActiveHigh", - BooleanTypeValue.getInstance()); - registerTypePorts.put("in", digitalInPortType); - registerTypePorts.put("out", digitalOutPortType); - registerTypePorts.put("clock", digitalInPortType); - registerTypePorts.put("reset", digitalInPortType); - registerType = new NodeTypeValue(registerTypeAttributes, registerTypePorts); - - inputPinTypePorts.put("out", digitalOutPortType); - inputPinType = new NodeTypeValue(noTypeAttributes, inputPinTypePorts); - - outputPinTypePorts.put("in", digitalInPortType); - outputPinType = new NodeTypeValue(noTypeAttributes, outputPinTypePorts); - - digitalWireType = new ConnectionType(noTypeAttributes); + public static void setupClass() { + UtilSchematicConstruction.setupIntermediateTypes(); } - - /** - * Instantiate a Schematic, but with varying degrees of "completeness" - * in terms of what object types are included. If types are missing, - * it will not be possible to construct a Netlist. - * @throws MultipleDefinitionException - */ - public static Schematic instantiateSchematic(String name, - boolean includePortTypes, boolean includeNodeTypes, - boolean includeConnectionTypes) - throws MultipleDefinitionException { - Schematic s = new Schematic(name); - if (includePortTypes) { - s.addPortType("digitalIn", digitalInPortType); - s.addPortType("digitalOut", digitalOutPortType); - } - - if (includeNodeTypes) { - s.addNodeType("register", registerType); - s.addNodeType("inputPin", inputPinType); - s.addNodeType("outputPin", outputPinType); - } - - if (includeConnectionTypes) { - s.addConnectionType("digitalWire", digitalWireType); - } - - return s; - } - - /** - * Instantiate a Schematic and include all object types. - */ - public static Schematic instantiateSchematic(String name) - throws MultipleDefinitionException { - return instantiateSchematic(name, true, true, true); - } - - public static NodeValue instantiateRegister(boolean initialValue, - boolean resetActiveHigh, boolean resetAsynchronous, - boolean clockActiveHigh) - throws SchematicException { - Map registerAttrs = new HashMap<>(); - registerAttrs.put("initialValue", - BooleanValue.getInstance(initialValue)); - registerAttrs.put("resetActiveHigh", - BooleanValue.getInstance(resetActiveHigh)); - registerAttrs.put("resetAsynchronous", - BooleanValue.getInstance(resetAsynchronous)); - registerAttrs.put("clockActiveHigh", - BooleanValue.getInstance(clockActiveHigh)); - Map> registerPortAttrs = new HashMap<>(); - registerPortAttrs.put("in", noAttributes); - registerPortAttrs.put("out", noAttributes); - registerPortAttrs.put("clock", noAttributes); - registerPortAttrs.put("reset", noAttributes); - NodeValue register = new NodeValue( - registerType, registerAttrs, registerPortAttrs); - return register; - } - - public static NodeValue instantiateInputPin() throws SchematicException { - Map> inputPinPortAttrs = new HashMap<>(); - inputPinPortAttrs.put("out", noAttributes); - NodeValue inputPin = new NodeValue( - inputPinType, noAttributes, inputPinPortAttrs); - return inputPin; - } - - public static NodeValue instantiateOutputPin() throws SchematicException { - Map> outputPinPortAttrs = new HashMap<>(); - outputPinPortAttrs.put("in", noAttributes); - NodeValue outputPin = new NodeValue( - outputPinType, noAttributes, outputPinPortAttrs); - return outputPin; - } - - public static ConnectionValue instantiateWire( - PortValue from, PortValue to) - throws UndeclaredAttributeException, InvalidAttributeException{ - ConnectionValue wire = new ConnectionValue( - digitalWireType, from, to, noAttributes); - return wire; - } - + @Test public void testConstruction() throws SchematicException { // [digitalIn] -> [digitalOut] - Schematic sch = instantiateSchematic("case0"); - NodeValue in = instantiateInputPin(); - NodeValue out = instantiateOutputPin(); - ConnectionValue in_to_out = instantiateWire( + Schematic sch = UtilSchematicConstruction.instantiateSchematic("case0"); + NodeValue in = UtilSchematicConstruction.instantiateInputPin(); + NodeValue out = UtilSchematicConstruction.instantiateOutputPin(); + ConnectionValue in_to_out = UtilSchematicConstruction.instantiateWire( in.getPort("out"), out.getPort("in")); sch.addNode("in", in); sch.addNode("out", out); sch.addConnection("in_to_out", in_to_out); - + Netlist netlist = new Netlist(sch); } - + @Test public void testGetNets() throws SchematicException { // [digitalIn] -> [digitalOut] - Schematic sch = instantiateSchematic("case0"); - NodeValue in = instantiateInputPin(); - NodeValue out = instantiateOutputPin(); - ConnectionValue in_to_out = instantiateWire( + Schematic sch = UtilSchematicConstruction.instantiateSchematic("case0"); + NodeValue in = UtilSchematicConstruction.instantiateInputPin(); + NodeValue out = UtilSchematicConstruction.instantiateOutputPin(); + ConnectionValue in_to_out = UtilSchematicConstruction.instantiateWire( in.getPort("out"), out.getPort("in")); sch.addNode("in", in); sch.addNode("out", out); sch.addConnection("in_to_out", in_to_out); - + Netlist netlist = new Netlist(sch); - + Map nets = netlist.getNets(); // there should be exactly one net assertEquals(1, nets.values().size()); @@ -202,21 +59,21 @@ public void testGetNets() throws SchematicException { assertTrue(n_in_to_out.getConnectedPorts().contains(in.getPort("out"))); assertTrue(n_in_to_out.getConnectedPorts().contains(out.getPort("in"))); } - + @Test public void testGetConnectedNet() throws SchematicException { // [digitalIn] -> [digitalOut] - Schematic sch = instantiateSchematic("case0"); - NodeValue in = instantiateInputPin(); - NodeValue out = instantiateOutputPin(); - ConnectionValue in_to_out = instantiateWire( + Schematic sch = UtilSchematicConstruction.instantiateSchematic("case0"); + NodeValue in = UtilSchematicConstruction.instantiateInputPin(); + NodeValue out = UtilSchematicConstruction.instantiateOutputPin(); + ConnectionValue in_to_out = UtilSchematicConstruction.instantiateWire( in.getPort("out"), out.getPort("in")); sch.addNode("in", in); sch.addNode("out", out); sch.addConnection("in_to_out", in_to_out); - + Netlist netlist = new Netlist(sch); - + // `in` and `out` should both be connected to the same net Net n_in = netlist.getConnectedNet(in.getPort("out")); assertNotNull(n_in); diff --git a/src/test/java/org/manifold/compiler/back/TestNoMultipleDriversCheck.java b/src/test/java/org/manifold/compiler/back/TestNoMultipleDriversCheck.java new file mode 100644 index 0000000..e9913ab --- /dev/null +++ b/src/test/java/org/manifold/compiler/back/TestNoMultipleDriversCheck.java @@ -0,0 +1,99 @@ +package org.manifold.compiler.back; + +import static org.junit.Assert.assertEquals; + +import java.util.Collection; +import java.util.LinkedList; +import java.util.List; + +import org.junit.BeforeClass; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.Parameterized; +import org.junit.runners.Parameterized.Parameters; +import org.manifold.compiler.ConnectionValue; +import org.manifold.compiler.NodeValue; +import org.manifold.compiler.back.digital.Check; +import org.manifold.compiler.back.digital.Netlist; +import org.manifold.compiler.back.digital.NoMultipleDriversCheck; +import org.manifold.compiler.middle.Schematic; +import org.manifold.compiler.middle.SchematicException; + +@RunWith(Parameterized.class) +public class TestNoMultipleDriversCheck { + + @BeforeClass + public static void setupClass() { + UtilSchematicConstruction.setupIntermediateTypes(); + } + + @Parameters + public static Collection data() throws SchematicException { + List testData = new LinkedList<>(); + + // BEGIN CASE 0 + // |in0> --- -+- -| + // no multiple drivers: FALSE + { + Schematic case1 = UtilSchematicConstruction.instantiateSchematic("case1"); + NodeValue in0 = UtilSchematicConstruction.instantiateInputPin(); + case1.addNode("in0", in0); + NodeValue in1 = UtilSchematicConstruction.instantiateInputPin(); + case1.addNode("in1", in1); + NodeValue out0 = UtilSchematicConstruction.instantiateOutputPin(); + case1.addNode("out0", out0); + ConnectionValue in0_to_out0 = UtilSchematicConstruction.instantiateWire( + in0.getPort("out"), out0.getPort("in")); + case1.addConnection("in0_to_out0", in0_to_out0); + ConnectionValue in1_to_out0 = UtilSchematicConstruction.instantiateWire( + in1.getPort("out"), out0.getPort("in")); + case1.addConnection("in1_to_out0", in1_to_out0); + + Netlist netlist_case1 = new Netlist(case1); + Object[] case1_data = new Object[] { case1, netlist_case1, false }; + testData.add(case1_data); + } + // END CASE 1 + return testData; + } + + // test inputs + private Schematic schematic; + private Netlist netlist; + private boolean expectedCheckResult; + + public TestNoMultipleDriversCheck(Schematic schematic, Netlist netlist, + Boolean expectedCheckResult) { + this.schematic = schematic; + this.netlist = netlist; + this.expectedCheckResult = expectedCheckResult; + } + + @Test + public void testDRC() { + Check drc = new NoMultipleDriversCheck(schematic, netlist); + boolean actualCheckResult = drc.run(); + assertEquals(expectedCheckResult, actualCheckResult); + } + +} diff --git a/src/test/java/org/manifold/compiler/back/UtilSchematicConstruction.java b/src/test/java/org/manifold/compiler/back/UtilSchematicConstruction.java new file mode 100644 index 0000000..d6c158f --- /dev/null +++ b/src/test/java/org/manifold/compiler/back/UtilSchematicConstruction.java @@ -0,0 +1,160 @@ +package org.manifold.compiler.back; + +import java.util.HashMap; +import java.util.Map; + +import org.manifold.compiler.BooleanTypeValue; +import org.manifold.compiler.BooleanValue; +import org.manifold.compiler.ConnectionType; +import org.manifold.compiler.ConnectionValue; +import org.manifold.compiler.InvalidAttributeException; +import org.manifold.compiler.MultipleDefinitionException; +import org.manifold.compiler.NodeTypeValue; +import org.manifold.compiler.NodeValue; +import org.manifold.compiler.PortTypeValue; +import org.manifold.compiler.PortValue; +import org.manifold.compiler.TypeValue; +import org.manifold.compiler.UndeclaredAttributeException; +import org.manifold.compiler.Value; +import org.manifold.compiler.middle.Schematic; +import org.manifold.compiler.middle.SchematicException; + +// Utility class for quickly setting up Schematics in test cases. +public class UtilSchematicConstruction { + + private static boolean setUp = false; + + public static PortTypeValue digitalInPortType; + public static PortTypeValue digitalOutPortType; + + private static final Map noTypeAttributes + = new HashMap<>(); + private static final Map noAttributes = new HashMap<>(); + + private static Map registerTypeAttributes + = new HashMap<>(); + private static Map registerTypePorts = new HashMap<>(); + private static NodeTypeValue registerType; + + private static Map inputPinTypePorts = new HashMap<>(); + private static NodeTypeValue inputPinType; + + private static Map outputPinTypePorts + = new HashMap<>(); + private static NodeTypeValue outputPinType; + + private static ConnectionType digitalWireType; + + public static void setupIntermediateTypes() { + + digitalInPortType = new PortTypeValue(noTypeAttributes); + digitalOutPortType = new PortTypeValue(noTypeAttributes); + + registerTypeAttributes.put("initialValue", BooleanTypeValue.getInstance()); + registerTypeAttributes.put("resetActiveHigh", + BooleanTypeValue.getInstance()); + registerTypeAttributes.put("resetAsynchronous", + BooleanTypeValue.getInstance()); + registerTypeAttributes.put("clockActiveHigh", + BooleanTypeValue.getInstance()); + registerTypePorts.put("in", digitalInPortType); + registerTypePorts.put("out", digitalOutPortType); + registerTypePorts.put("clock", digitalInPortType); + registerTypePorts.put("reset", digitalInPortType); + registerType = new NodeTypeValue(registerTypeAttributes, registerTypePorts); + + inputPinTypePorts.put("out", digitalOutPortType); + inputPinType = new NodeTypeValue(noTypeAttributes, inputPinTypePorts); + + outputPinTypePorts.put("in", digitalInPortType); + outputPinType = new NodeTypeValue(noTypeAttributes, outputPinTypePorts); + + digitalWireType = new ConnectionType(noTypeAttributes); + + setUp = true; + } + + /** + * Instantiate a Schematic, but with varying degrees of "completeness" in + * terms of what object types are included. If types are missing, it will not + * be possible to construct a Netlist. + * + * @throws MultipleDefinitionException + */ + public static Schematic instantiateSchematic(String name, + boolean includePortTypes, boolean includeNodeTypes, + boolean includeConnectionTypes) throws MultipleDefinitionException { + if (!setUp) { + setupIntermediateTypes(); + } + Schematic s = new Schematic(name); + if (includePortTypes) { + s.addPortType("digitalIn", digitalInPortType); + s.addPortType("digitalOut", digitalOutPortType); + } + + if (includeNodeTypes) { + s.addNodeType("register", registerType); + s.addNodeType("inputPin", inputPinType); + s.addNodeType("outputPin", outputPinType); + } + + if (includeConnectionTypes) { + s.addConnectionType("digitalWire", digitalWireType); + } + + return s; + } + + /** + * Instantiate a Schematic and include all object types. + */ + public static Schematic instantiateSchematic(String name) + throws MultipleDefinitionException { + return instantiateSchematic(name, true, true, true); + } + + public static NodeValue instantiateRegister(boolean initialValue, + boolean resetActiveHigh, boolean resetAsynchronous, + boolean clockActiveHigh) throws SchematicException { + Map registerAttrs = new HashMap<>(); + registerAttrs.put("initialValue", BooleanValue.getInstance(initialValue)); + registerAttrs.put("resetActiveHigh", + BooleanValue.getInstance(resetActiveHigh)); + registerAttrs.put("resetAsynchronous", + BooleanValue.getInstance(resetAsynchronous)); + registerAttrs.put("clockActiveHigh", + BooleanValue.getInstance(clockActiveHigh)); + Map> registerPortAttrs = new HashMap<>(); + registerPortAttrs.put("in", noAttributes); + registerPortAttrs.put("out", noAttributes); + registerPortAttrs.put("clock", noAttributes); + registerPortAttrs.put("reset", noAttributes); + NodeValue register = new NodeValue(registerType, registerAttrs, + registerPortAttrs); + return register; + } + + public static NodeValue instantiateInputPin() throws SchematicException { + Map> inputPinPortAttrs = new HashMap<>(); + inputPinPortAttrs.put("out", noAttributes); + NodeValue inputPin = new NodeValue(inputPinType, noAttributes, + inputPinPortAttrs); + return inputPin; + } + + public static NodeValue instantiateOutputPin() throws SchematicException { + Map> outputPinPortAttrs = new HashMap<>(); + outputPinPortAttrs.put("in", noAttributes); + NodeValue outputPin = new NodeValue(outputPinType, noAttributes, + outputPinPortAttrs); + return outputPin; + } + + public static ConnectionValue instantiateWire(PortValue from, PortValue to) + throws UndeclaredAttributeException, InvalidAttributeException { + ConnectionValue wire = new ConnectionValue(digitalWireType, from, to, + noAttributes); + return wire; + } +}