From d0b8526bd6efa55eae79a1bc826ff2d919b5e3ee Mon Sep 17 00:00:00 2001 From: Murphy Berzish Date: Fri, 11 Jul 2014 14:36:06 -0400 Subject: [PATCH 1/3] simple netlist-building --- .../manifold/compiler/back/digital/Net.java | 34 +++++++ .../compiler/back/digital/Netlist.java | 90 +++++++++++++++++++ .../manifold/compiler/middle/Schematic.java | 6 ++ 3 files changed, 130 insertions(+) create mode 100644 src/main/java/org/manifold/compiler/back/digital/Net.java create mode 100644 src/main/java/org/manifold/compiler/back/digital/Netlist.java diff --git a/src/main/java/org/manifold/compiler/back/digital/Net.java b/src/main/java/org/manifold/compiler/back/digital/Net.java new file mode 100644 index 0000000..5920575 --- /dev/null +++ b/src/main/java/org/manifold/compiler/back/digital/Net.java @@ -0,0 +1,34 @@ +package org.manifold.compiler.back.digital; + +import java.util.HashSet; +import java.util.Set; + +import org.manifold.compiler.PortValue; + +import com.google.common.collect.ImmutableSet; + +// In digital design, a "net" is a wire that connects multiple ports together. +// Because the connections supported by the compiler are +// traditional graph edges, which connect only two ports at a time, +// Nets make it easier to work with instances where one port +// is connected to two or more other ports to supply them with signal. + +public class Net { + private String name; + public String getName() { + return name; + } + + public Net(String name) { + this.name = name; + } + + private Set connectedPorts = new HashSet<>(); + public Set getConnectedPorts() { + return ImmutableSet.copyOf(connectedPorts); + } + public void addPort(PortValue port){ + // TODO(murphy) what happens if the port is already connected to this net? + connectedPorts.add(port); + } +} diff --git a/src/main/java/org/manifold/compiler/back/digital/Netlist.java b/src/main/java/org/manifold/compiler/back/digital/Netlist.java new file mode 100644 index 0000000..95c5770 --- /dev/null +++ b/src/main/java/org/manifold/compiler/back/digital/Netlist.java @@ -0,0 +1,90 @@ +package org.manifold.compiler.back.digital; + +import java.util.HashMap; +import java.util.Map; +import java.util.Map.Entry; + +import org.manifold.compiler.ConnectionType; +import org.manifold.compiler.ConnectionValue; +import org.manifold.compiler.PortTypeValue; +import org.manifold.compiler.PortValue; +import org.manifold.compiler.TypeMismatchException; +import org.manifold.compiler.UndeclaredIdentifierException; +import org.manifold.compiler.middle.Schematic; + +public class Netlist { + + private ConnectionType digitalWireType; + private PortTypeValue digitalInType; + private PortTypeValue digitalOutType; + + private Map nets = new HashMap<>(); + private Map connectedNet = new HashMap<>(); + + public Netlist(Schematic schematic) + throws UndeclaredIdentifierException, TypeMismatchException { + digitalWireType = schematic.getConnectionType("digitalWire"); + digitalInType = schematic.getPortType("digitalIn"); + digitalOutType = schematic.getPortType("digitalOut"); + + // iterate over connections in the schematic and build nets + for (Entry connEntry + : schematic.getConnections().entrySet()) { + String connectionName = connEntry.getKey(); + ConnectionValue connection = connEntry.getValue(); + + verify_ConnectionIsDigitalWire(connection); + + // get both ports + PortValue portFrom = connection.getFrom(); + PortValue portTo = connection.getTo(); + + verify_PortIsDigitalIO(portFrom); + verify_PortIsDigitalIO(portTo); + + // now we can take both ports and attach them to a net + if (connectedNet.containsKey(portFrom)) { + Net existingNet = connectedNet.get(portFrom); + if (connectedNet.containsKey(portTo)) { + // both ports already connected to a net + } else { + connectToNet(portTo, existingNet); + } + } else { + // portFrom not connected to a net + if (connectedNet.containsKey(portTo)) { + Net existingNet = connectedNet.get(portTo); + connectToNet(portFrom, existingNet); + } else { + // neither port is connected to a net, so create a new one + String netName = "n_" + connectionName; + Net newNet = new Net(netName); + nets.put(netName, newNet); + connectToNet(portFrom, newNet); + connectToNet(portTo, newNet); + } + } + } + } + + private void verify_ConnectionIsDigitalWire(ConnectionValue connection) + throws TypeMismatchException { + if (!connection.getType().equals(digitalWireType)) { + throw new TypeMismatchException(digitalWireType, connection.getType()); + } + } + + private void verify_PortIsDigitalIO(PortValue port) + throws TypeMismatchException { + if (!(port.getType().equals(digitalInType) + || port.getType().equals(digitalOutType))) { + // TODO this exception is inaccurate because there are two valid types + throw new TypeMismatchException(digitalInType, port.getType()); + } + } + + private void connectToNet(PortValue port, Net net){ + net.addPort(port); + connectedNet.put(port, net); + } +} diff --git a/src/main/java/org/manifold/compiler/middle/Schematic.java b/src/main/java/org/manifold/compiler/middle/Schematic.java index d35a430..fe4171d 100644 --- a/src/main/java/org/manifold/compiler/middle/Schematic.java +++ b/src/main/java/org/manifold/compiler/middle/Schematic.java @@ -15,6 +15,8 @@ import org.manifold.compiler.UndefinedBehaviourError; import org.manifold.compiler.BooleanTypeValue; import org.manifold.compiler.IntegerTypeValue; + +import com.google.common.collect.ImmutableMap; import com.google.gson.Gson; import com.google.gson.GsonBuilder; @@ -215,6 +217,10 @@ public ConnectionValue getConnection(String instanceName) } } + public Map getConnections() { + return ImmutableMap.copyOf(connections); + } + public void addConstraint(String instanceName, ConstraintValue constraint) throws MultipleAssignmentException { if (constraints.containsKey(instanceName)){ From 47656e53905ce83e1714f412040da14d14e05b73 Mon Sep 17 00:00:00 2001 From: Murphy Berzish Date: Sat, 12 Jul 2014 16:34:43 -0400 Subject: [PATCH 2/3] test cases for Net and Netlist --- .../compiler/back/digital/Netlist.java | 13 + .../org/manifold/compiler/back/TestNet.java | 49 ++++ .../manifold/compiler/back/TestNetlist.java | 228 ++++++++++++++++++ 3 files changed, 290 insertions(+) create mode 100644 src/test/java/org/manifold/compiler/back/TestNet.java create mode 100644 src/test/java/org/manifold/compiler/back/TestNetlist.java diff --git a/src/main/java/org/manifold/compiler/back/digital/Netlist.java b/src/main/java/org/manifold/compiler/back/digital/Netlist.java index 95c5770..ed88e97 100644 --- a/src/main/java/org/manifold/compiler/back/digital/Netlist.java +++ b/src/main/java/org/manifold/compiler/back/digital/Netlist.java @@ -12,6 +12,8 @@ import org.manifold.compiler.UndeclaredIdentifierException; import org.manifold.compiler.middle.Schematic; +import com.google.common.collect.ImmutableMap; + public class Netlist { private ConnectionType digitalWireType; @@ -19,7 +21,18 @@ public class Netlist { private PortTypeValue digitalOutType; private Map nets = new HashMap<>(); + public Map getNets() { + return ImmutableMap.copyOf(nets); + } private Map connectedNet = new HashMap<>(); + public Net getConnectedNet(PortValue port) { + if (connectedNet.containsKey(port)) { + return connectedNet.get(port); + } else { + // TODO(murphy) throw an exception? + return null; + } + } public Netlist(Schematic schematic) throws UndeclaredIdentifierException, TypeMismatchException { diff --git a/src/test/java/org/manifold/compiler/back/TestNet.java b/src/test/java/org/manifold/compiler/back/TestNet.java new file mode 100644 index 0000000..f3b8d16 --- /dev/null +++ b/src/test/java/org/manifold/compiler/back/TestNet.java @@ -0,0 +1,49 @@ +package org.manifold.compiler.back; + +import static org.junit.Assert.*; + +import java.util.HashMap; +import java.util.Map; + +import org.junit.Test; +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.Value; +import org.manifold.compiler.back.digital.Net; +import org.manifold.compiler.middle.SchematicException; + +public class TestNet { + + @Test + public void testGetName() { + String name = "asdf"; + Net n = new Net(name); + assertEquals(name, n.getName()); + } + + @Test + public void testGetConnectedPorts_initiallyEmpty() { + Net n = new Net("asdf"); + assertTrue(n.getConnectedPorts().isEmpty()); + } + + @Test + public void testAddPort() throws SchematicException { + Net n = new Net("asdf"); + PortTypeValue portType = new PortTypeValue( + new HashMap()); + NodeTypeValue nodeType = new NodeTypeValue(new HashMap(), + new HashMap()); + Map> portAttrMaps = + new HashMap>(); + NodeValue parent = new NodeValue(nodeType, new HashMap(), + portAttrMaps); + PortValue p = new PortValue(portType, parent, new HashMap()); + n.addPort(p); + assertTrue(n.getConnectedPorts().contains(p)); + } + +} diff --git a/src/test/java/org/manifold/compiler/back/TestNetlist.java b/src/test/java/org/manifold/compiler/back/TestNetlist.java new file mode 100644 index 0000000..e617130 --- /dev/null +++ b/src/test/java/org/manifold/compiler/back/TestNetlist.java @@ -0,0 +1,228 @@ +package org.manifold.compiler.back; + +import static org.junit.Assert.*; + +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; +import org.manifold.compiler.middle.SchematicException; + +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); + } + + /** + * 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( + 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( + 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()); + // and this net should contain both ports + Net n_in_to_out = (Net) nets.values().toArray()[0]; + 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( + 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); + Net n_out = netlist.getConnectedNet(out.getPort("in")); + assertNotNull(n_out); + assertEquals(n_in, n_out); + } + +} From c614351533060e6b33f8526e038ed07895d0d627 Mon Sep 17 00:00:00 2001 From: Murphy Berzish Date: Mon, 21 Jul 2014 14:00:57 -0400 Subject: [PATCH 3/3] exception-throwing nits --- .../manifold/compiler/back/digital/Net.java | 20 ++++-- .../compiler/back/digital/Netlist.java | 61 +++++++++++-------- 2 files changed, 48 insertions(+), 33 deletions(-) diff --git a/src/main/java/org/manifold/compiler/back/digital/Net.java b/src/main/java/org/manifold/compiler/back/digital/Net.java index 5920575..530bcbb 100644 --- a/src/main/java/org/manifold/compiler/back/digital/Net.java +++ b/src/main/java/org/manifold/compiler/back/digital/Net.java @@ -4,6 +4,7 @@ import java.util.Set; import org.manifold.compiler.PortValue; +import org.manifold.compiler.UndefinedBehaviourError; import com.google.common.collect.ImmutableSet; @@ -15,20 +16,27 @@ public class Net { private String name; + public String getName() { return name; } - + public Net(String name) { this.name = name; } - - private Set connectedPorts = new HashSet<>(); + + private Set connectedPorts = new HashSet<>(); + public Set getConnectedPorts() { return ImmutableSet.copyOf(connectedPorts); } - public void addPort(PortValue port){ - // TODO(murphy) what happens if the port is already connected to this net? - connectedPorts.add(port); + + public void addPort(PortValue port) { + if (connectedPorts.contains(port)) { + throw new UndefinedBehaviourError( + "port is connected to the same net twice"); + } else { + connectedPorts.add(port); + } } } diff --git a/src/main/java/org/manifold/compiler/back/digital/Netlist.java b/src/main/java/org/manifold/compiler/back/digital/Netlist.java index ed88e97..7f0076f 100644 --- a/src/main/java/org/manifold/compiler/back/digital/Netlist.java +++ b/src/main/java/org/manifold/compiler/back/digital/Netlist.java @@ -15,46 +15,48 @@ import com.google.common.collect.ImmutableMap; public class Netlist { - + private ConnectionType digitalWireType; private PortTypeValue digitalInType; private PortTypeValue digitalOutType; - + private Map nets = new HashMap<>(); + public Map getNets() { return ImmutableMap.copyOf(nets); } + private Map connectedNet = new HashMap<>(); + public Net getConnectedNet(PortValue port) { if (connectedNet.containsKey(port)) { return connectedNet.get(port); } else { - // TODO(murphy) throw an exception? - return null; + throw new IllegalArgumentException("port not connected to any nets"); } } - - public Netlist(Schematic schematic) - throws UndeclaredIdentifierException, TypeMismatchException { + + public Netlist(Schematic schematic) throws UndeclaredIdentifierException, + TypeMismatchException { digitalWireType = schematic.getConnectionType("digitalWire"); digitalInType = schematic.getPortType("digitalIn"); digitalOutType = schematic.getPortType("digitalOut"); - + // iterate over connections in the schematic and build nets - for (Entry connEntry - : schematic.getConnections().entrySet()) { + for (Entry connEntry : schematic.getConnections() + .entrySet()) { String connectionName = connEntry.getKey(); ConnectionValue connection = connEntry.getValue(); - - verify_ConnectionIsDigitalWire(connection); - + + verifyConnectionIsDigitalWire(connection); + // get both ports PortValue portFrom = connection.getFrom(); PortValue portTo = connection.getTo(); - - verify_PortIsDigitalIO(portFrom); - verify_PortIsDigitalIO(portTo); - + + verifyPortIsDigitalOut(portFrom); + verifyPortIsDigitalIn(portTo); + // now we can take both ports and attach them to a net if (connectedNet.containsKey(portFrom)) { Net existingNet = connectedNet.get(portFrom); @@ -79,24 +81,29 @@ public Netlist(Schematic schematic) } } } - - private void verify_ConnectionIsDigitalWire(ConnectionValue connection) + + private void verifyConnectionIsDigitalWire(ConnectionValue connection) throws TypeMismatchException { if (!connection.getType().equals(digitalWireType)) { throw new TypeMismatchException(digitalWireType, connection.getType()); } } - - private void verify_PortIsDigitalIO(PortValue port) + + private void verifyPortIsDigitalOut(PortValue port) throws TypeMismatchException { - if (!(port.getType().equals(digitalInType) - || port.getType().equals(digitalOutType))) { - // TODO this exception is inaccurate because there are two valid types - throw new TypeMismatchException(digitalInType, port.getType()); + if (!port.getType().equals(digitalOutType)) { + throw new TypeMismatchException(digitalOutType, port.getType()); } } - - private void connectToNet(PortValue port, Net net){ + + private void verifyPortIsDigitalIn(PortValue port) + throws TypeMismatchException { + if (!port.getType().equals(digitalInType)) { + throw new TypeMismatchException(digitalInType, port.getType()); + } + } + + private void connectToNet(PortValue port, Net net) { net.addPort(port); connectedNet.put(port, net); }