diff --git a/src/kyupy/circuit.py b/src/kyupy/circuit.py index cacc5b5..b81904a 100644 --- a/src/kyupy/circuit.py +++ b/src/kyupy/circuit.py @@ -314,6 +314,41 @@ class Circuit: def get_or_add_fork(self, name): return self.forks[name] if name in self.forks else Node(self, name) + def substitute(self, node, impl): + """Replaces a given node with the given implementation circuit. + + The given node will be removed, the implementation is copied in and + the signal lines are connected appropriately. The number and arrangement + of the input and output ports must match the pins of the replaced node. + """ + node_in_lines = [l for l in node.ins if l] + node_out_lines = [l for l in node.outs if l] + impl_in_lines = [n.outs[0] for n in impl.io_nodes if len(n.outs) > 0] + impl_out_lines = [n.ins[0] for n in impl.io_nodes if len(n.ins) > 0] + assert len(node_in_lines) == len(impl_in_lines) + assert len(node_out_lines) == len(impl_out_lines) + in_lines_map = dict(zip(impl_in_lines, node_in_lines)) + out_lines_map = dict(zip(impl_out_lines, node_out_lines)) + node.remove() + node_map = dict() + ios = set(impl.io_nodes) + for n in impl.nodes: + if n not in ios: + node_map[n] = Node(self, node.name + '~' + n.name, n.kind) + for l in impl.lines: + if l in in_lines_map: + ll = in_lines_map[l] + ll.reader = node_map[l.reader] + ll.reader_pin = l.reader_pin + ll.reader.ins[ll.reader_pin] = ll + elif l in out_lines_map: + ll = out_lines_map[l] + ll.driver = node_map[l.driver] + ll.driver_pin = l.driver_pin + ll.driver.outs[ll.driver_pin] = ll + else: + Line(self, (node_map[l.driver], l.driver_pin), (node_map[l.reader], l.reader_pin)) + def copy(self): """Returns a deep copy of the circuit. """ diff --git a/src/kyupy/techlib.py b/src/kyupy/techlib.py index 5e8e843..f8b3a19 100644 --- a/src/kyupy/techlib.py +++ b/src/kyupy/techlib.py @@ -1,5 +1,5 @@ from .circuit import Node, Line - +from . import bench def add_and_connect(circuit, name, kind, in1=None, in2=None, out=None): n = Node(circuit, name, kind) @@ -66,6 +66,23 @@ class TechLib: if 'MUX' in kind and pin == 'S': return False return pin in ('Q', 'QN', 'Z', 'ZN', 'Y', 'CO', 'S', 'SO', 'C1') + @staticmethod + def substitute_nonsim_cells(circuit): + tmap = {'ISOLAND': bench.parse('input(iso, d) output(q) not_iso=not(iso) q=and(not_iso, d)'), + 'AO221' : bench.parse('input(in1, in2, in3, in4, in5) output(q) a=ao22(in1, in2, in3, in4) q=or(a, in5)'), + 'AOI221' : bench.parse('input(in1, in2, in3, in4, in5) output(qn) a=ao22(in1, in2, in3, in4) qn=nor(a, in5)'), + 'OA221' : bench.parse('input(in1, in2, in3, in4, in5) output(q) a=oa22(in1, in2, in3, in4) q=and(a, in5)'), + 'OAI221' : bench.parse('input(in1, in2, in3, in4, in5) output(qn) a=oa22(in1, in2, in3, in4) qn=nand(a, in5)'), + 'AO222' : bench.parse('input(in1, in2, in3, in4, in5, in6) output(q) a=ao22(in1, in2, in3, in4) q=ao21(in5, in6, a)'), + 'AOI222' : bench.parse('input(in1, in2, in3, in4, in5, in6) output(qn) a=ao22(in1, in2, in3, in4) qn=aoi21(in5, in6, a)'), + 'OA222' : bench.parse('input(in1, in2, in3, in4, in5, in6) output(q) a=oa22(in1, in2, in3, in4) q=oa21(in5, in6, a)'), + 'OAI222' : bench.parse('input(in1, in2, in3, in4, in5, in6) output(qn) a=oa22(in1, in2, in3, in4) qn=oai21(in5, in6, a)'), + } + for n in list(circuit.nodes): + for k, v in tmap.items(): + if n.kind.startswith(k): + circuit.substitute(n, v) + @staticmethod def split_complex_gates(circuit): node_list = circuit.nodes diff --git a/tests/test_circuit.py b/tests/test_circuit.py index 8eb4e01..64da48c 100644 --- a/tests/test_circuit.py +++ b/tests/test_circuit.py @@ -1,7 +1,8 @@ import pickle from kyupy.circuit import Circuit, Node, Line -from kyupy import verilog +from kyupy import verilog, bench +from kyupy.techlib import TechLib def test_lines(): c = Circuit() @@ -104,9 +105,26 @@ def test_circuit(): def test_pickle(mydir): - c = verilog.load(mydir / 'b14.v.gz') + c = verilog.load(mydir / 'b15_4ig.v.gz') assert c is not None cs = pickle.dumps(c) assert cs is not None c2 = pickle.loads(cs) assert c == c2 + +def test_substitute(): + c = bench.parse('input(i1, i2, i3, i4, i5) output(o1) aoi=AOI221(i1, i2, i3, i4, i5) o1=not(aoi)') + assert len(c.cells) == 2 + assert len(c.io_nodes) == 6 + aoi221_impl = bench.parse('input(in1, in2, in3, in4, in5) output(q) a1=and(in1, in2) a2=and(in3, in4) q=or(a1, a2, in5)') + assert len(aoi221_impl.cells) == 3 + assert len(aoi221_impl.io_nodes) == 6 + c.substitute(c.cells['aoi'], aoi221_impl) + assert len(c.cells) == 4 + assert len(c.io_nodes) == 6 + + c = bench.parse('input(i1, i2, i3, i4, i5) output(o1) aoi221=AOI221(i1, i2, i3, i4, i5) o1=not(aoi221)') + assert len(c.cells) == 2 + TechLib.substitute_nonsim_cells(c) + assert len(c.cells) == 3 + print('\n'.join(map(str, c.nodes))) \ No newline at end of file