-
Notifications
You must be signed in to change notification settings - Fork 3
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #128 from mtrberzi/issue118-netlist-construction
Netlist construction from schematic
Showing
5 changed files
with
435 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,42 @@ | ||
package org.manifold.compiler.back.digital; | ||
|
||
import java.util.HashSet; | ||
import java.util.Set; | ||
|
||
import org.manifold.compiler.PortValue; | ||
import org.manifold.compiler.UndefinedBehaviourError; | ||
|
||
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<PortValue> connectedPorts = new HashSet<>(); | ||
|
||
public Set<PortValue> getConnectedPorts() { | ||
return ImmutableSet.copyOf(connectedPorts); | ||
} | ||
|
||
public void addPort(PortValue port) { | ||
if (connectedPorts.contains(port)) { | ||
throw new UndefinedBehaviourError( | ||
"port is connected to the same net twice"); | ||
} else { | ||
connectedPorts.add(port); | ||
} | ||
} | ||
} |
110 changes: 110 additions & 0 deletions
110
src/main/java/org/manifold/compiler/back/digital/Netlist.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,110 @@ | ||
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; | ||
|
||
import com.google.common.collect.ImmutableMap; | ||
|
||
public class Netlist { | ||
|
||
private ConnectionType digitalWireType; | ||
private PortTypeValue digitalInType; | ||
private PortTypeValue digitalOutType; | ||
|
||
private Map<String, Net> nets = new HashMap<>(); | ||
|
||
public Map<String, Net> getNets() { | ||
return ImmutableMap.copyOf(nets); | ||
} | ||
|
||
private Map<PortValue, Net> connectedNet = new HashMap<>(); | ||
|
||
public Net getConnectedNet(PortValue port) { | ||
if (connectedNet.containsKey(port)) { | ||
return connectedNet.get(port); | ||
} else { | ||
throw new IllegalArgumentException("port not connected to any nets"); | ||
} | ||
} | ||
|
||
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<String, ConnectionValue> connEntry : schematic.getConnections() | ||
.entrySet()) { | ||
String connectionName = connEntry.getKey(); | ||
ConnectionValue connection = connEntry.getValue(); | ||
|
||
verifyConnectionIsDigitalWire(connection); | ||
|
||
// get both ports | ||
PortValue portFrom = connection.getFrom(); | ||
PortValue portTo = connection.getTo(); | ||
|
||
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); | ||
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 verifyConnectionIsDigitalWire(ConnectionValue connection) | ||
throws TypeMismatchException { | ||
if (!connection.getType().equals(digitalWireType)) { | ||
throw new TypeMismatchException(digitalWireType, connection.getType()); | ||
} | ||
} | ||
|
||
private void verifyPortIsDigitalOut(PortValue port) | ||
throws TypeMismatchException { | ||
if (!port.getType().equals(digitalOutType)) { | ||
throw new TypeMismatchException(digitalOutType, port.getType()); | ||
} | ||
} | ||
|
||
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); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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<String, TypeValue>()); | ||
NodeTypeValue nodeType = new NodeTypeValue(new HashMap<String, TypeValue>(), | ||
new HashMap<String, PortTypeValue>()); | ||
Map<String, Map<String, Value>> portAttrMaps = | ||
new HashMap<String, Map<String, Value>>(); | ||
NodeValue parent = new NodeValue(nodeType, new HashMap<String, Value>(), | ||
portAttrMaps); | ||
PortValue p = new PortValue(portType, parent, new HashMap<String, Value>()); | ||
n.addPort(p); | ||
assertTrue(n.getConnectedPorts().contains(p)); | ||
} | ||
|
||
} |
228 changes: 228 additions & 0 deletions
228
src/test/java/org/manifold/compiler/back/TestNetlist.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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<String, TypeValue> noTypeAttributes | ||
= new HashMap<>(); | ||
private static final Map<String, Value> noAttributes | ||
= new HashMap<>(); | ||
|
||
private static Map<String, TypeValue> registerTypeAttributes | ||
= new HashMap<>(); | ||
private static Map<String, PortTypeValue> registerTypePorts | ||
= new HashMap<>(); | ||
private static NodeTypeValue registerType; | ||
|
||
private static Map<String, PortTypeValue> inputPinTypePorts | ||
= new HashMap<>(); | ||
private static NodeTypeValue inputPinType; | ||
|
||
private static Map<String, PortTypeValue> 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<String, Value> 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<String, Map<String, Value>> 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<String, Map<String, Value>> inputPinPortAttrs = new HashMap<>(); | ||
inputPinPortAttrs.put("out", noAttributes); | ||
NodeValue inputPin = new NodeValue( | ||
inputPinType, noAttributes, inputPinPortAttrs); | ||
return inputPin; | ||
} | ||
|
||
public static NodeValue instantiateOutputPin() throws SchematicException { | ||
Map<String, Map<String, Value>> 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<String, Net> 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); | ||
} | ||
|
||
} |