diff --git a/Demo.ipynb b/Demo.ipynb index 0da44a0..805c60c 100644 --- a/Demo.ipynb +++ b/Demo.ipynb @@ -44,7 +44,7 @@ { "data": { "text/plain": [ - "" + "" ] }, "execution_count": 2, @@ -64,7 +64,7 @@ { "data": { "text/plain": [ - "" + "" ] }, "execution_count": 3, @@ -362,7 +362,7 @@ { "data": { "text/plain": [ - "" + "" ] }, "execution_count": 13, @@ -445,7 +445,7 @@ { "data": { "text/plain": [ - "" + "" ] }, "execution_count": 15, @@ -591,7 +591,7 @@ { "data": { "text/plain": [ - "" + "" ] }, "execution_count": 19, @@ -697,7 +697,7 @@ { "data": { "text/plain": [ - "" + "" ] }, "execution_count": 23, @@ -829,7 +829,7 @@ { "data": { "text/plain": [ - "" + "" ] }, "execution_count": 29, @@ -962,10 +962,9 @@ "outputs": [], "source": [ "from kyupy import sdf\n", - "from kyupy.saed import pin_index\n", "\n", "df = sdf.load('tests/b14.sdf.gz')\n", - "lt = df.annotation(b14, pin_index, dataset=0, interconnect=False)" + "lt = df.annotation(b14, dataset=0, interconnect=False)" ] }, { diff --git a/docs/miscellaneous.rst b/docs/miscellaneous.rst index 2fe4394..08da343 100644 --- a/docs/miscellaneous.rst +++ b/docs/miscellaneous.rst @@ -1,6 +1,10 @@ Miscellaneous ============= +.. automodule:: kyupy.techlib + :members: .. automodule:: kyupy :members: + + diff --git a/src/kyupy/bench.py b/src/kyupy/bench.py index f63deac..21310d5 100644 --- a/src/kyupy/bench.py +++ b/src/kyupy/bench.py @@ -29,7 +29,7 @@ class BenchTransformer(Transformer): name, cell_type, drivers = args cell = Node(self.c, str(name), str(cell_type)) Line(self.c, cell, self.c.get_or_add_fork(str(name))) - [Line(self.c, d, cell) for d in drivers] + for d in drivers: Line(self.c, d, cell) GRAMMAR = r""" diff --git a/src/kyupy/circuit.py b/src/kyupy/circuit.py index 68d65ec..5801f0c 100644 --- a/src/kyupy/circuit.py +++ b/src/kyupy/circuit.py @@ -262,8 +262,8 @@ class Circuit: for line in n.outs: if line is None: continue succ = line.reader - visit_count[succ.index] += 1 - if visit_count[succ.index] == len(succ.ins) and 'DFF' not in succ.kind: + visit_count[succ] += 1 + if visit_count[succ] == len(succ.ins) and 'DFF' not in succ.kind: queue.append(succ) yield n @@ -287,8 +287,8 @@ class Circuit: n = queue.popleft() for line in n.ins: pred = line.driver - visit_count[pred.index] += 1 - if visit_count[pred.index] == len(pred.outs) and 'DFF' not in pred.kind: + visit_count[pred] += 1 + if visit_count[pred] == len(pred.outs) and 'DFF' not in pred.kind: queue.append(pred) yield n @@ -299,13 +299,13 @@ class Circuit: """ marks = [False] * len(self.nodes) for n in origin_nodes: - marks[n.index] = True + marks[n] = True for n in self.reversed_topological_order(): - if not marks[n.index]: + if not marks[n]: for line in n.outs: if line is not None: - marks[n.index] |= marks[line.reader.index] - if marks[n.index]: + marks[n] |= marks[line.reader] + if marks[n]: yield n def fanout_free_regions(self): diff --git a/src/kyupy/logic.py b/src/kyupy/logic.py index 9cf1067..7b0c149 100644 --- a/src/kyupy/logic.py +++ b/src/kyupy/logic.py @@ -116,7 +116,7 @@ class MVArray: if isinstance(a, MVArray): self.data = a.data.copy() """The wrapped 2-dimensional ndarray of logic values. - + * Axis 0 is PI/PO/FF position, the length of this axis is called "width". * Axis 1 is vector/pattern, the length of this axis is called "length". """ diff --git a/src/kyupy/saed.py b/src/kyupy/saed.py deleted file mode 100644 index d75be0b..0000000 --- a/src/kyupy/saed.py +++ /dev/null @@ -1,289 +0,0 @@ -from kyupy.circuit import Node, Line - - -def pin_index(cell_type, pin): - if cell_type.startswith('HADD') and pin == 'B0': return 1 - if cell_type.startswith('HADD') and pin == 'SO': return 1 - if cell_type.startswith('MUX21') and pin == 'S': return 2 - if cell_type.startswith('SDFF') and pin == 'QN': return 1 - if cell_type.startswith('DFF') and pin == 'QN': return 1 - if cell_type.startswith('DFF') and pin == 'CLK': return 1 - if cell_type.startswith('DFF') and pin == 'RSTB': return 2 - if cell_type.startswith('DFF') and pin == 'SETB': return 3 - if pin in ('A2', 'IN2', 'SE', 'B', 'CO'): return 1 - if pin in ('A3', 'IN3', 'SI', 'CI'): return 2 - if pin in ('A4', 'IN4', 'CLK'): return 3 # CLK for scan cells SDFF - if pin in ('A5', 'IN5', 'RSTB'): return 4 - if pin in ('A6', 'IN6', 'SETB'): return 5 - return 0 - - -def pin_is_output(kind, pin): - if 'MUX' in kind and pin == 'S': - return False - return pin in ('Q', 'QN', 'Z', 'ZN', 'Y', 'CO', 'S', 'SO', 'C1') - - -def add_and_connect(circuit, name, kind, in1=None, in2=None, out=None): - n = Node(circuit, name, kind) - if in1 is not None: - n.ins[0] = in1 - in1.reader = n - in1.reader_pin = 0 - if in2 is not None: - n.ins[1] = in2 - in2.reader = n - in2.reader_pin = 1 - if out is not None: - n.outs[0] = out - out.driver = n - out.driver_pin = 0 - return n - - -def split_complex_gates(circuit): - node_list = circuit.nodes - for n in node_list: - name = n.name - ins = n.ins - outs = n.outs - if n.kind.startswith('AO21X'): - n.remove() - n_and = add_and_connect(circuit, name+'~and', 'AND2', ins[0], ins[1], None) - n_or = add_and_connect(circuit, name+'~or', 'OR2', None, ins[2], outs[0]) - Line(circuit, n_and, n_or) - elif n.kind.startswith('AOI21X'): - n.remove() - n_and = add_and_connect(circuit, name+'~and', 'AND2', ins[0], ins[1], None) - n_nor = add_and_connect(circuit, name+'~nor', 'NOR2', None, ins[2], outs[0]) - Line(circuit, n_and, n_nor) - elif n.kind.startswith('OA21X'): - n.remove() - n_or = add_and_connect(circuit, name+'~or', 'OR2', ins[0], ins[1], None) - n_and = add_and_connect(circuit, name+'~and', 'AND2', None, ins[2], outs[0]) - Line(circuit, n_or, n_and) - elif n.kind.startswith('OAI21X'): - n.remove() - n_or = add_and_connect(circuit, name+'~or', 'OR2', ins[0], ins[1], None) - n_nand = add_and_connect(circuit, name+'~nand', 'NAND2', None, ins[2], outs[0]) - Line(circuit, n_or, n_nand) - elif n.kind.startswith('OA22X'): - n.remove() - n_or0 = add_and_connect(circuit, name+'~or0', 'OR2', ins[0], ins[1], None) - n_or1 = add_and_connect(circuit, name+'~or1', 'OR2', ins[2], ins[3], None) - n_and = add_and_connect(circuit, name+'~and', 'AND2', None, None, outs[0]) - Line(circuit, n_or0, n_and) - Line(circuit, n_or1, n_and) - elif n.kind.startswith('OAI22X'): - n.remove() - n_or0 = add_and_connect(circuit, name+'~or0', 'OR2', ins[0], ins[1], None) - n_or1 = add_and_connect(circuit, name+'~or1', 'OR2', ins[2], ins[3], None) - n_nand = add_and_connect(circuit, name+'~nand', 'NAND2', None, None, outs[0]) - Line(circuit, n_or0, n_nand) - Line(circuit, n_or1, n_nand) - elif n.kind.startswith('AO22X'): - n.remove() - n_and0 = add_and_connect(circuit, name+'~and0', 'AND2', ins[0], ins[1], None) - n_and1 = add_and_connect(circuit, name+'~and1', 'AND2', ins[2], ins[3], None) - n_or = add_and_connect(circuit, name+'~or', 'OR2', None, None, outs[0]) - Line(circuit, n_and0, n_or) - Line(circuit, n_and1, n_or) - elif n.kind.startswith('AOI22X'): - n.remove() - n_and0 = add_and_connect(circuit, name+'~and0', 'AND2', ins[0], ins[1], None) - n_and1 = add_and_connect(circuit, name+'~and1', 'AND2', ins[2], ins[3], None) - n_nor = add_and_connect(circuit, name+'~nor', 'NOR2', None, None, outs[0]) - Line(circuit, n_and0, n_nor) - Line(circuit, n_and1, n_nor) - elif n.kind.startswith('AO221X'): - n.remove() - n_and0 = add_and_connect(circuit, name+'~and0', 'AND2', ins[0], ins[1], None) - n_and1 = add_and_connect(circuit, name+'~and1', 'AND2', ins[2], ins[3], None) - n_or0 = add_and_connect(circuit, name+'~or0', 'OR2', None, None, None) - n_or1 = add_and_connect(circuit, name+'~or1', 'OR2', None, ins[4], outs[0]) - Line(circuit, n_and0, n_or0) - Line(circuit, n_and1, n_or0) - Line(circuit, n_or0, n_or1) - elif n.kind.startswith('AOI221X'): - n.remove() - n_and0 = add_and_connect(circuit, name+'~and0', 'AND2', ins[0], ins[1], None) - n_and1 = add_and_connect(circuit, name+'~and1', 'AND2', ins[2], ins[3], None) - n_or = add_and_connect(circuit, name+'~or', 'OR2', None, None, None) - n_nor = add_and_connect(circuit, name+'~nor', 'NOR2', None, ins[4], outs[0]) - Line(circuit, n_and0, n_or) - Line(circuit, n_and1, n_or) - Line(circuit, n_or, n_nor) - elif n.kind.startswith('OA221X'): - n.remove() - n_or0 = add_and_connect(circuit, name+'~or0', 'OR2', ins[0], ins[1], None) - n_or1 = add_and_connect(circuit, name+'~or1', 'OR2', ins[2], ins[3], None) - n_and0 = add_and_connect(circuit, name+'~and0', 'AND2', None, None, None) - n_and1 = add_and_connect(circuit, name+'~and1', 'AND2', None, ins[4], outs[0]) - Line(circuit, n_or0, n_and0) - Line(circuit, n_or1, n_and0) - Line(circuit, n_and0, n_and1) - elif n.kind.startswith('OAI221X'): - n.remove() - n_or0 = add_and_connect(circuit, name+'~or0', 'OR2', ins[0], ins[1], None) - n_or1 = add_and_connect(circuit, name+'~or1', 'OR2', ins[2], ins[3], None) - n_and0 = add_and_connect(circuit, name+'~and0', 'AND2', None, None, None) - n_nand1 = add_and_connect(circuit, name+'~nand1', 'NAND2', None, ins[4], outs[0]) - Line(circuit, n_or0, n_and0) - Line(circuit, n_or1, n_and0) - Line(circuit, n_and0, n_nand1) - elif n.kind.startswith('AO222X'): - n.remove() - n_and0 = add_and_connect(circuit, name+'~and0', 'AND2', ins[0], ins[1], None) - n_and1 = add_and_connect(circuit, name+'~and1', 'AND2', ins[2], ins[3], None) - n_and2 = add_and_connect(circuit, name+'~and2', 'AND2', ins[4], ins[5], None) - n_or0 = add_and_connect(circuit, name+'~or0', 'OR2', None, None, None) - n_or1 = add_and_connect(circuit, name+'~or1', 'OR2', None, None, outs[0]) - Line(circuit, n_and0, n_or0) - Line(circuit, n_and1, n_or0) - Line(circuit, n_and2, n_or1) - Line(circuit, n_or0, n_or1) - elif n.kind.startswith('AOI222X'): - n.remove() - n_and0 = add_and_connect(circuit, name+'~and0', 'AND2', ins[0], ins[1], None) - n_and1 = add_and_connect(circuit, name+'~and1', 'AND2', ins[2], ins[3], None) - n_and2 = add_and_connect(circuit, name+'~and2', 'AND2', ins[4], ins[5], None) - n_or0 = add_and_connect(circuit, name+'~or0', 'OR2', None, None, None) - n_nor1 = add_and_connect(circuit, name+'~nor1', 'NOR2', None, None, outs[0]) - Line(circuit, n_and0, n_or0) - Line(circuit, n_and1, n_or0) - Line(circuit, n_and2, n_nor1) - Line(circuit, n_or0, n_nor1) - elif n.kind.startswith('OA222X'): - n.remove() - n_or0 = add_and_connect(circuit, name+'~or0', 'OR2', ins[0], ins[1], None) - n_or1 = add_and_connect(circuit, name+'~or1', 'OR2', ins[2], ins[3], None) - n_or2 = add_and_connect(circuit, name+'~or2', 'OR2', ins[4], ins[5], None) - n_and0 = add_and_connect(circuit, name+'~and0', 'AND2', None, None, None) - n_and1 = add_and_connect(circuit, name+'~and1', 'AND2', None, None, outs[0]) - Line(circuit, n_or0, n_and0) - Line(circuit, n_or1, n_and0) - Line(circuit, n_or2, n_and1) - Line(circuit, n_and0, n_and1) - elif n.kind.startswith('OAI222X'): - n.remove() - n0 = add_and_connect(circuit, name+'~or0', 'OR2', ins[0], ins[1], None) - n1 = add_and_connect(circuit, name+'~or1', 'OR2', ins[2], ins[3], None) - n2 = add_and_connect(circuit, name+'~or2', 'OR2', ins[4], ins[5], None) - n3 = add_and_connect(circuit, name+'~and0', 'AND2', None, None, None) - n4 = add_and_connect(circuit, name+'~nand1', 'NAND2', None, None, outs[0]) - Line(circuit, n0, n3) - Line(circuit, n1, n3) - Line(circuit, n2, n4) - Line(circuit, n3, n4) - elif n.kind.startswith('AND3X'): - n.remove() - n0 = add_and_connect(circuit, name+'~and0', 'AND2', ins[0], ins[1], None) - n1 = add_and_connect(circuit, name+'~and1', 'AND2', None, ins[2], outs[0]) - Line(circuit, n0, n1) - elif n.kind.startswith('OR3X'): - n.remove() - n0 = add_and_connect(circuit, name+'~or0', 'OR2', ins[0], ins[1], None) - n1 = add_and_connect(circuit, name+'~or1', 'OR2', None, ins[2], outs[0]) - Line(circuit, n0, n1) - elif n.kind.startswith('XOR3X'): - n.remove() - n0 = add_and_connect(circuit, name+'~xor0', 'XOR2', ins[0], ins[1], None) - n1 = add_and_connect(circuit, name+'~xor1', 'XOR2', None, ins[2], outs[0]) - Line(circuit, n0, n1) - elif n.kind.startswith('NAND3X'): - n.remove() - n0 = add_and_connect(circuit, name+'~and', 'AND2', ins[0], ins[1], None) - n1 = add_and_connect(circuit, name+'~nand', 'NAND2', None, ins[2], outs[0]) - Line(circuit, n0, n1) - elif n.kind.startswith('NOR3X'): - n.remove() - n0 = add_and_connect(circuit, name+'~or', 'OR2', ins[0], ins[1], None) - n1 = add_and_connect(circuit, name+'~nor', 'NOR2', None, ins[2], outs[0]) - Line(circuit, n0, n1) - elif n.kind.startswith('XNOR3X'): - n.remove() - n0 = add_and_connect(circuit, name+'~xor', 'XOR2', ins[0], ins[1], None) - n1 = add_and_connect(circuit, name+'~xnor', 'XNOR2', None, ins[2], outs[0]) - Line(circuit, n0, n1) - elif n.kind.startswith('AND4X'): - n.remove() - n0 = add_and_connect(circuit, name+'~and0', 'AND2', ins[0], ins[1], None) - n1 = add_and_connect(circuit, name+'~and1', 'AND2', ins[2], ins[3], None) - n2 = add_and_connect(circuit, name+'~and2', 'AND2', None, None, outs[0]) - Line(circuit, n0, n2) - Line(circuit, n1, n2) - elif n.kind.startswith('OR4X'): - n.remove() - n0 = add_and_connect(circuit, name+'~or0', 'OR2', ins[0], ins[1], None) - n1 = add_and_connect(circuit, name+'~or1', 'OR2', ins[2], ins[3], None) - n2 = add_and_connect(circuit, name+'~or2', 'OR2', None, None, outs[0]) - Line(circuit, n0, n2) - Line(circuit, n1, n2) - elif n.kind.startswith('NAND4X'): - n.remove() - n0 = add_and_connect(circuit, name+'~and0', 'AND2', ins[0], ins[1], None) - n1 = add_and_connect(circuit, name+'~and1', 'AND2', ins[2], ins[3], None) - n2 = add_and_connect(circuit, name+'~nand2', 'NAND2', None, None, outs[0]) - Line(circuit, n0, n2) - Line(circuit, n1, n2) - elif n.kind.startswith('NOR4X'): - n.remove() - n0 = add_and_connect(circuit, name+'~or0', 'OR2', ins[0], ins[1], None) - n1 = add_and_connect(circuit, name+'~or1', 'OR2', ins[2], ins[3], None) - n2 = add_and_connect(circuit, name+'~nor2', 'NOR2', None, None, outs[0]) - Line(circuit, n0, n2) - Line(circuit, n1, n2) - elif n.kind.startswith('FADDX'): - n.remove() - # forks for fan-outs - f_a = add_and_connect(circuit, name + '~fork0', '__fork__', ins[0]) - f_b = add_and_connect(circuit, name + '~fork1', '__fork__', ins[1]) - f_ci = add_and_connect(circuit, name + '~fork2', '__fork__', ins[2]) - f_ab = Node(circuit, name + '~fork3') - # sum-block - n_xor0 = Node(circuit, name + '~xor0', 'XOR2') - Line(circuit, f_a, n_xor0) - Line(circuit, f_b, n_xor0) - Line(circuit, n_xor0, f_ab) - if len(outs) > 0 and outs[0] is not None: - n_xor1 = add_and_connect(circuit, name + '~xor1', 'XOR2', None, None, outs[0]) - Line(circuit, f_ab, n_xor1) - Line(circuit, f_ci, n_xor1) - # carry-block - if len(outs) > 1 and outs[1] is not None: - n_and0 = Node(circuit, name + '~and0', 'AND2') - Line(circuit, f_ab, n_and0) - Line(circuit, f_ci, n_and0) - n_and1 = Node(circuit, name + '~and1', 'AND2') - Line(circuit, f_a, n_and1) - Line(circuit, f_b, n_and1) - n_or = add_and_connect(circuit, name + '~or0', 'OR2', None, None, outs[1]) - Line(circuit, n_and0, n_or) - Line(circuit, n_and1, n_or) - elif n.kind.startswith('HADDX'): - n.remove() - # forks for fan-outs - f_a = add_and_connect(circuit, name + '~fork0', '__fork__', ins[0]) - f_b = add_and_connect(circuit, name + '~fork1', '__fork__', ins[1]) - n_xor0 = add_and_connect(circuit, name + '~xor0', 'XOR2', None, None, outs[1]) - Line(circuit, f_a, n_xor0) - Line(circuit, f_b, n_xor0) - n_and0 = add_and_connect(circuit, name + '~and0', 'AND2', None, None, outs[0]) - Line(circuit, f_a, n_and0) - Line(circuit, f_b, n_and0) - elif n.kind.startswith('MUX21X'): - n.remove() - f_s = add_and_connect(circuit, name + '~fork0', '__fork__', ins[2]) - n_not = Node(circuit, name + '~not', 'INV') - Line(circuit, f_s, n_not) - n_and0 = add_and_connect(circuit, name + '~and0', 'AND2', ins[0]) - n_and1 = add_and_connect(circuit, name + '~and1', 'AND2', ins[1]) - n_or0 = add_and_connect(circuit, name + '~or0', 'OR2', None, None, outs[0]) - Line(circuit, n_not, n_and0) - Line(circuit, f_s, n_and1) - Line(circuit, n_and0, n_or0) - Line(circuit, n_and1, n_or0) - elif n.kind.startswith('DFFSSR'): - n.kind = 'DFFX1' - n_and0 = add_and_connect(circuit, name + '~and0', 'AND2', ins[0], ins[2], None) - Line(circuit, n_and0, (n, 0)) diff --git a/src/kyupy/sdf.py b/src/kyupy/sdf.py index d26c6ee..f89d7b3 100644 --- a/src/kyupy/sdf.py +++ b/src/kyupy/sdf.py @@ -14,6 +14,7 @@ import numpy as np from lark import Lark, Transformer from . import log, readtext +from .techlib import TechLib Interconnect = namedtuple('Interconnect', ['orig', 'dest', 'r', 'f']) @@ -35,7 +36,7 @@ class DelayFile: return '\n'.join(f'{n}: {l}' for n, l in self.cells.items()) + '\n' + \ '\n'.join(str(i) for i in self.interconnects) - def annotation(self, circuit, pin_index_f, dataset=1, interconnect=True, ffdelays=True): + def annotation(self, circuit, tlib=TechLib(), dataset=1, interconnect=True, ffdelays=True): """Constructs an 3-dimensional ndarray with timing data for each line in ``circuit``. An IOPATH delay for a node is annotated to the line connected to the input pin specified in the IOPATH. @@ -45,7 +46,8 @@ class DelayFile: :param circuit: The circuit to annotate. Names from the STIL file are matched to the node names. :type circuit: :class:`~kyupy.circuit.Circuit` - :param pin_index_f: A function that returns a pin position by node type and pin name. + :param tlib: A technology library object that provides pin name mappings. + :type tlib: :py:class:`~kyupy.techlib.TechLib` :param dataset: SDFs store multiple values for each delay (e.g. minimum, typical, maximum). An integer selects the dataset to use (default is 1 for 'typical'). If a tuple is given, the annotator will calculate the average of multiple datasets. @@ -91,8 +93,8 @@ class DelayFile: if cell is None: log.warn(f'Cell from SDF not found in circuit: {cn}') continue - ipin = pin_index_f(cell.kind, ipn) - opin = pin_index_f(cell.kind, opn) + ipin = tlib.pin_index(cell.kind, ipn) + opin = tlib.pin_index(cell.kind, opn) kind = cell.kind.lower() ipn2 = ipn.replace('(posedge A1)', 'A1').replace('(negedge A1)', 'A1')\ @@ -100,8 +102,8 @@ class DelayFile: def add_delays(_line): if _line is not None: - timing[_line.index, :, 0] += select_del(delvals, 0) - timing[_line.index, :, 1] += select_del(delvals, 1) + timing[_line, :, 0] += select_del(delvals, 0) + timing[_line, :, 1] += select_del(delvals, 1) take_avg = False if kind.startswith('sdff'): @@ -111,12 +113,12 @@ class DelayFile: add_delays(cell.outs[opin]) else: if kind.startswith(('xor', 'xnor')): - ipin = pin_index_f(cell.kind, ipn2) - # print(ipn, ipin, times[cell.i_lines[ipin].index, 0, 0]) - take_avg = timing[cell.ins[ipin].index].sum() > 0 + ipin = tlib.pin_index(cell.kind, ipn2) + # print(ipn, ipin, times[cell.i_lines[ipin], 0, 0]) + take_avg = timing[cell.ins[ipin]].sum() > 0 add_delays(cell.ins[ipin]) if take_avg: - timing[cell.ins[ipin].index] /= 2 + timing[cell.ins[ipin]] /= 2 if not interconnect or self.interconnects is None: return timing @@ -145,7 +147,7 @@ class DelayFile: if c2 is None: log.warn(f'Cell from SDF not found in circuit: {cn2}') continue - p1, p2 = pin_index_f(c1.kind, pn1), pin_index_f(c2.kind, pn2) + p1, p2 = tlib.pin_index(c1.kind, pn1), tlib.pin_index(c2.kind, pn2) line = None f1, f2 = c1.outs[p1].reader, c2.ins[p2].driver if f1 != f2: # possible branchfork @@ -155,8 +157,8 @@ class DelayFile: elif len(f2.outs) == 1: # no fanout? line = f2.ins[0] if line is not None: - timing[line.index, :, 0] += select_del(delvals, 0) - timing[line.index, :, 1] += select_del(delvals, 1) + timing[line, :, 0] += select_del(delvals, 0) + timing[line, :, 1] += select_del(delvals, 1) else: log.warn(f'No branchfork for annotating interconnect delay {c1.name}/{p1}->{c2.name}/{p2}') return timing diff --git a/src/kyupy/techlib.py b/src/kyupy/techlib.py new file mode 100644 index 0000000..5a5a01b --- /dev/null +++ b/src/kyupy/techlib.py @@ -0,0 +1,301 @@ +from .circuit import Node, Line + + +def add_and_connect(circuit, name, kind, in1=None, in2=None, out=None): + n = Node(circuit, name, kind) + if in1 is not None: + n.ins[0] = in1 + in1.reader = n + in1.reader_pin = 0 + if in2 is not None: + n.ins[1] = in2 + in2.reader = n + in2.reader_pin = 1 + if out is not None: + n.outs[0] = out + out.driver = n + out.driver_pin = 0 + return n + + +class TechLib: + """Provides some information specific to standard cell libraries necessary + for loading gate-level designs. :py:class:`~kyupy.circuit.Node` objects do not + have pin names. The methods defined here map pin names to pin directions and defined + positions in the ``node.ins`` and ``node.outs`` lists. The default implementation + provides mappings for SAED-inspired standard cell libraries. + """ + + @staticmethod + def pin_index(kind, pin): + """Returns a pin list position for a given node kind and pin name.""" + for prefix, pins, index in [('HADD', ('B0', 'SO'), 1), + ('MUX21', ('S',), 2), + ('DFF', ('QN',), 1), + ('SDFF', ('QN',), 1), + ('SDFF', ('CLK',), 3), + ('SDFF', ('RSTB',), 4), + ('SDFF', ('SETB',), 5)]: + if kind.startswith(prefix) and pin in pins: return index + for index, pins in enumerate([('A1', 'IN1', 'D', 'S', 'INP', 'A', 'Q', 'QN', 'Y', 'Z', 'ZN'), + ('A2', 'IN2', 'CLK', 'CO', 'SE', 'B'), + ('A3', 'IN3', 'RSTB', 'CI', 'SI'), + ('A4', 'IN4', 'SETB'), + ('A5', 'IN5'), + ('A6', 'IN6')]): + if pin in pins: return index + raise ValueError(f'Unknown pin index for {kind}.{pin}') + + @staticmethod + def pin_is_output(kind, pin): + """Returns True, if given pin name of a node kind is an output.""" + if 'MUX' in kind and pin == 'S': return False + return pin in ('Q', 'QN', 'Z', 'ZN', 'Y', 'CO', 'S', 'SO', 'C1') + + @staticmethod + def split_complex_gates(circuit): + node_list = circuit.nodes + for n in node_list: + name = n.name + ins = n.ins + outs = n.outs + if n.kind.startswith('AO21X'): + n.remove() + n_and = add_and_connect(circuit, name+'~and', 'AND2', ins[0], ins[1], None) + n_or = add_and_connect(circuit, name+'~or', 'OR2', None, ins[2], outs[0]) + Line(circuit, n_and, n_or) + elif n.kind.startswith('AOI21X'): + n.remove() + n_and = add_and_connect(circuit, name+'~and', 'AND2', ins[0], ins[1], None) + n_nor = add_and_connect(circuit, name+'~nor', 'NOR2', None, ins[2], outs[0]) + Line(circuit, n_and, n_nor) + elif n.kind.startswith('OA21X'): + n.remove() + n_or = add_and_connect(circuit, name+'~or', 'OR2', ins[0], ins[1], None) + n_and = add_and_connect(circuit, name+'~and', 'AND2', None, ins[2], outs[0]) + Line(circuit, n_or, n_and) + elif n.kind.startswith('OAI21X'): + n.remove() + n_or = add_and_connect(circuit, name+'~or', 'OR2', ins[0], ins[1], None) + n_nand = add_and_connect(circuit, name+'~nand', 'NAND2', None, ins[2], outs[0]) + Line(circuit, n_or, n_nand) + elif n.kind.startswith('OA22X'): + n.remove() + n_or0 = add_and_connect(circuit, name+'~or0', 'OR2', ins[0], ins[1], None) + n_or1 = add_and_connect(circuit, name+'~or1', 'OR2', ins[2], ins[3], None) + n_and = add_and_connect(circuit, name+'~and', 'AND2', None, None, outs[0]) + Line(circuit, n_or0, n_and) + Line(circuit, n_or1, n_and) + elif n.kind.startswith('OAI22X'): + n.remove() + n_or0 = add_and_connect(circuit, name+'~or0', 'OR2', ins[0], ins[1], None) + n_or1 = add_and_connect(circuit, name+'~or1', 'OR2', ins[2], ins[3], None) + n_nand = add_and_connect(circuit, name+'~nand', 'NAND2', None, None, outs[0]) + Line(circuit, n_or0, n_nand) + Line(circuit, n_or1, n_nand) + elif n.kind.startswith('AO22X'): + n.remove() + n_and0 = add_and_connect(circuit, name+'~and0', 'AND2', ins[0], ins[1], None) + n_and1 = add_and_connect(circuit, name+'~and1', 'AND2', ins[2], ins[3], None) + n_or = add_and_connect(circuit, name+'~or', 'OR2', None, None, outs[0]) + Line(circuit, n_and0, n_or) + Line(circuit, n_and1, n_or) + elif n.kind.startswith('AOI22X'): + n.remove() + n_and0 = add_and_connect(circuit, name+'~and0', 'AND2', ins[0], ins[1], None) + n_and1 = add_and_connect(circuit, name+'~and1', 'AND2', ins[2], ins[3], None) + n_nor = add_and_connect(circuit, name+'~nor', 'NOR2', None, None, outs[0]) + Line(circuit, n_and0, n_nor) + Line(circuit, n_and1, n_nor) + elif n.kind.startswith('AO221X'): + n.remove() + n_and0 = add_and_connect(circuit, name+'~and0', 'AND2', ins[0], ins[1], None) + n_and1 = add_and_connect(circuit, name+'~and1', 'AND2', ins[2], ins[3], None) + n_or0 = add_and_connect(circuit, name+'~or0', 'OR2', None, None, None) + n_or1 = add_and_connect(circuit, name+'~or1', 'OR2', None, ins[4], outs[0]) + Line(circuit, n_and0, n_or0) + Line(circuit, n_and1, n_or0) + Line(circuit, n_or0, n_or1) + elif n.kind.startswith('AOI221X'): + n.remove() + n_and0 = add_and_connect(circuit, name+'~and0', 'AND2', ins[0], ins[1], None) + n_and1 = add_and_connect(circuit, name+'~and1', 'AND2', ins[2], ins[3], None) + n_or = add_and_connect(circuit, name+'~or', 'OR2', None, None, None) + n_nor = add_and_connect(circuit, name+'~nor', 'NOR2', None, ins[4], outs[0]) + Line(circuit, n_and0, n_or) + Line(circuit, n_and1, n_or) + Line(circuit, n_or, n_nor) + elif n.kind.startswith('OA221X'): + n.remove() + n_or0 = add_and_connect(circuit, name+'~or0', 'OR2', ins[0], ins[1], None) + n_or1 = add_and_connect(circuit, name+'~or1', 'OR2', ins[2], ins[3], None) + n_and0 = add_and_connect(circuit, name+'~and0', 'AND2', None, None, None) + n_and1 = add_and_connect(circuit, name+'~and1', 'AND2', None, ins[4], outs[0]) + Line(circuit, n_or0, n_and0) + Line(circuit, n_or1, n_and0) + Line(circuit, n_and0, n_and1) + elif n.kind.startswith('OAI221X'): + n.remove() + n_or0 = add_and_connect(circuit, name+'~or0', 'OR2', ins[0], ins[1], None) + n_or1 = add_and_connect(circuit, name+'~or1', 'OR2', ins[2], ins[3], None) + n_and0 = add_and_connect(circuit, name+'~and0', 'AND2', None, None, None) + n_nand1 = add_and_connect(circuit, name+'~nand1', 'NAND2', None, ins[4], outs[0]) + Line(circuit, n_or0, n_and0) + Line(circuit, n_or1, n_and0) + Line(circuit, n_and0, n_nand1) + elif n.kind.startswith('AO222X'): + n.remove() + n_and0 = add_and_connect(circuit, name+'~and0', 'AND2', ins[0], ins[1], None) + n_and1 = add_and_connect(circuit, name+'~and1', 'AND2', ins[2], ins[3], None) + n_and2 = add_and_connect(circuit, name+'~and2', 'AND2', ins[4], ins[5], None) + n_or0 = add_and_connect(circuit, name+'~or0', 'OR2', None, None, None) + n_or1 = add_and_connect(circuit, name+'~or1', 'OR2', None, None, outs[0]) + Line(circuit, n_and0, n_or0) + Line(circuit, n_and1, n_or0) + Line(circuit, n_and2, n_or1) + Line(circuit, n_or0, n_or1) + elif n.kind.startswith('AOI222X'): + n.remove() + n_and0 = add_and_connect(circuit, name+'~and0', 'AND2', ins[0], ins[1], None) + n_and1 = add_and_connect(circuit, name+'~and1', 'AND2', ins[2], ins[3], None) + n_and2 = add_and_connect(circuit, name+'~and2', 'AND2', ins[4], ins[5], None) + n_or0 = add_and_connect(circuit, name+'~or0', 'OR2', None, None, None) + n_nor1 = add_and_connect(circuit, name+'~nor1', 'NOR2', None, None, outs[0]) + Line(circuit, n_and0, n_or0) + Line(circuit, n_and1, n_or0) + Line(circuit, n_and2, n_nor1) + Line(circuit, n_or0, n_nor1) + elif n.kind.startswith('OA222X'): + n.remove() + n_or0 = add_and_connect(circuit, name+'~or0', 'OR2', ins[0], ins[1], None) + n_or1 = add_and_connect(circuit, name+'~or1', 'OR2', ins[2], ins[3], None) + n_or2 = add_and_connect(circuit, name+'~or2', 'OR2', ins[4], ins[5], None) + n_and0 = add_and_connect(circuit, name+'~and0', 'AND2', None, None, None) + n_and1 = add_and_connect(circuit, name+'~and1', 'AND2', None, None, outs[0]) + Line(circuit, n_or0, n_and0) + Line(circuit, n_or1, n_and0) + Line(circuit, n_or2, n_and1) + Line(circuit, n_and0, n_and1) + elif n.kind.startswith('OAI222X'): + n.remove() + n0 = add_and_connect(circuit, name+'~or0', 'OR2', ins[0], ins[1], None) + n1 = add_and_connect(circuit, name+'~or1', 'OR2', ins[2], ins[3], None) + n2 = add_and_connect(circuit, name+'~or2', 'OR2', ins[4], ins[5], None) + n3 = add_and_connect(circuit, name+'~and0', 'AND2', None, None, None) + n4 = add_and_connect(circuit, name+'~nand1', 'NAND2', None, None, outs[0]) + Line(circuit, n0, n3) + Line(circuit, n1, n3) + Line(circuit, n2, n4) + Line(circuit, n3, n4) + elif n.kind.startswith('AND3X'): + n.remove() + n0 = add_and_connect(circuit, name+'~and0', 'AND2', ins[0], ins[1], None) + n1 = add_and_connect(circuit, name+'~and1', 'AND2', None, ins[2], outs[0]) + Line(circuit, n0, n1) + elif n.kind.startswith('OR3X'): + n.remove() + n0 = add_and_connect(circuit, name+'~or0', 'OR2', ins[0], ins[1], None) + n1 = add_and_connect(circuit, name+'~or1', 'OR2', None, ins[2], outs[0]) + Line(circuit, n0, n1) + elif n.kind.startswith('XOR3X'): + n.remove() + n0 = add_and_connect(circuit, name+'~xor0', 'XOR2', ins[0], ins[1], None) + n1 = add_and_connect(circuit, name+'~xor1', 'XOR2', None, ins[2], outs[0]) + Line(circuit, n0, n1) + elif n.kind.startswith('NAND3X'): + n.remove() + n0 = add_and_connect(circuit, name+'~and', 'AND2', ins[0], ins[1], None) + n1 = add_and_connect(circuit, name+'~nand', 'NAND2', None, ins[2], outs[0]) + Line(circuit, n0, n1) + elif n.kind.startswith('NOR3X'): + n.remove() + n0 = add_and_connect(circuit, name+'~or', 'OR2', ins[0], ins[1], None) + n1 = add_and_connect(circuit, name+'~nor', 'NOR2', None, ins[2], outs[0]) + Line(circuit, n0, n1) + elif n.kind.startswith('XNOR3X'): + n.remove() + n0 = add_and_connect(circuit, name+'~xor', 'XOR2', ins[0], ins[1], None) + n1 = add_and_connect(circuit, name+'~xnor', 'XNOR2', None, ins[2], outs[0]) + Line(circuit, n0, n1) + elif n.kind.startswith('AND4X'): + n.remove() + n0 = add_and_connect(circuit, name+'~and0', 'AND2', ins[0], ins[1], None) + n1 = add_and_connect(circuit, name+'~and1', 'AND2', ins[2], ins[3], None) + n2 = add_and_connect(circuit, name+'~and2', 'AND2', None, None, outs[0]) + Line(circuit, n0, n2) + Line(circuit, n1, n2) + elif n.kind.startswith('OR4X'): + n.remove() + n0 = add_and_connect(circuit, name+'~or0', 'OR2', ins[0], ins[1], None) + n1 = add_and_connect(circuit, name+'~or1', 'OR2', ins[2], ins[3], None) + n2 = add_and_connect(circuit, name+'~or2', 'OR2', None, None, outs[0]) + Line(circuit, n0, n2) + Line(circuit, n1, n2) + elif n.kind.startswith('NAND4X'): + n.remove() + n0 = add_and_connect(circuit, name+'~and0', 'AND2', ins[0], ins[1], None) + n1 = add_and_connect(circuit, name+'~and1', 'AND2', ins[2], ins[3], None) + n2 = add_and_connect(circuit, name+'~nand2', 'NAND2', None, None, outs[0]) + Line(circuit, n0, n2) + Line(circuit, n1, n2) + elif n.kind.startswith('NOR4X'): + n.remove() + n0 = add_and_connect(circuit, name+'~or0', 'OR2', ins[0], ins[1], None) + n1 = add_and_connect(circuit, name+'~or1', 'OR2', ins[2], ins[3], None) + n2 = add_and_connect(circuit, name+'~nor2', 'NOR2', None, None, outs[0]) + Line(circuit, n0, n2) + Line(circuit, n1, n2) + elif n.kind.startswith('FADDX'): + n.remove() + # forks for fan-outs + f_a = add_and_connect(circuit, name + '~fork0', '__fork__', ins[0]) + f_b = add_and_connect(circuit, name + '~fork1', '__fork__', ins[1]) + f_ci = add_and_connect(circuit, name + '~fork2', '__fork__', ins[2]) + f_ab = Node(circuit, name + '~fork3') + # sum-block + n_xor0 = Node(circuit, name + '~xor0', 'XOR2') + Line(circuit, f_a, n_xor0) + Line(circuit, f_b, n_xor0) + Line(circuit, n_xor0, f_ab) + if len(outs) > 0 and outs[0] is not None: + n_xor1 = add_and_connect(circuit, name + '~xor1', 'XOR2', None, None, outs[0]) + Line(circuit, f_ab, n_xor1) + Line(circuit, f_ci, n_xor1) + # carry-block + if len(outs) > 1 and outs[1] is not None: + n_and0 = Node(circuit, name + '~and0', 'AND2') + Line(circuit, f_ab, n_and0) + Line(circuit, f_ci, n_and0) + n_and1 = Node(circuit, name + '~and1', 'AND2') + Line(circuit, f_a, n_and1) + Line(circuit, f_b, n_and1) + n_or = add_and_connect(circuit, name + '~or0', 'OR2', None, None, outs[1]) + Line(circuit, n_and0, n_or) + Line(circuit, n_and1, n_or) + elif n.kind.startswith('HADDX'): + n.remove() + # forks for fan-outs + f_a = add_and_connect(circuit, name + '~fork0', '__fork__', ins[0]) + f_b = add_and_connect(circuit, name + '~fork1', '__fork__', ins[1]) + n_xor0 = add_and_connect(circuit, name + '~xor0', 'XOR2', None, None, outs[1]) + Line(circuit, f_a, n_xor0) + Line(circuit, f_b, n_xor0) + n_and0 = add_and_connect(circuit, name + '~and0', 'AND2', None, None, outs[0]) + Line(circuit, f_a, n_and0) + Line(circuit, f_b, n_and0) + elif n.kind.startswith('MUX21X'): + n.remove() + f_s = add_and_connect(circuit, name + '~fork0', '__fork__', ins[2]) + n_not = Node(circuit, name + '~not', 'INV') + Line(circuit, f_s, n_not) + n_and0 = add_and_connect(circuit, name + '~and0', 'AND2', ins[0]) + n_and1 = add_and_connect(circuit, name + '~and1', 'AND2', ins[1]) + n_or0 = add_and_connect(circuit, name + '~or0', 'OR2', None, None, outs[0]) + Line(circuit, n_not, n_and0) + Line(circuit, f_s, n_and1) + Line(circuit, n_and0, n_or0) + Line(circuit, n_and1, n_or0) + elif n.kind.startswith('DFFSSR'): + n.kind = 'DFFX1' + n_and0 = add_and_connect(circuit, name + '~and0', 'AND2', ins[0], ins[2], None) + Line(circuit, n_and0, (n, 0)) diff --git a/src/kyupy/verilog.py b/src/kyupy/verilog.py index c0f3636..c6b5ab0 100644 --- a/src/kyupy/verilog.py +++ b/src/kyupy/verilog.py @@ -10,7 +10,7 @@ from lark import Lark, Transformer from . import readtext from .circuit import Circuit, Node, Line -from .saed import pin_index, pin_is_output +from .techlib import TechLib Instantiation = namedtuple('Instantiation', ['type', 'name', 'pins']) @@ -41,10 +41,11 @@ class SignalDeclaration: class VerilogTransformer(Transformer): - def __init__(self, branchforks=False): + def __init__(self, branchforks=False, tlib=TechLib()): super().__init__() self._signal_declarations = {} self.branchforks = branchforks + self.tlib = tlib @staticmethod def name(args): @@ -87,8 +88,8 @@ class VerilogTransformer(Transformer): if isinstance(stmt, Instantiation): n = Node(c, stmt.name, kind=stmt.type) for p, s in stmt.pins.items(): - if pin_is_output(n.kind, p): - Line(c, (n, pin_index(stmt.type, p)), Node(c, s)) + if self.tlib.pin_is_output(n.kind, p): + Line(c, (n, self.tlib.pin_index(stmt.type, p)), Node(c, s)) elif stmt is not None and stmt.data == 'assign': assignments.append((stmt.children[0], stmt.children[1])) for sd in self._signal_declarations.values(): @@ -110,7 +111,7 @@ class VerilogTransformer(Transformer): if isinstance(stmt, Instantiation): for p, s in stmt.pins.items(): n = c.cells[stmt.name] - if pin_is_output(n.kind, p): continue + if self.tlib.pin_is_output(n.kind, p): continue if s.startswith("1'b"): const = f'__const{s[3]}__' if const not in c.cells: @@ -120,7 +121,7 @@ class VerilogTransformer(Transformer): branchfork = Node(c, fork.name + "~" + n.name + "/" + p) Line(c, fork, branchfork) fork = branchfork - Line(c, fork, (n, pin_index(stmt.type, p))) + Line(c, fork, (n, self.tlib.pin_index(stmt.type, p))) for sd in self._signal_declarations.values(): if sd.kind == 'output': for name in sd.names: @@ -153,16 +154,18 @@ GRAMMAR = """ """ -def parse(text, *, branchforks=False): +def parse(text, *, branchforks=False, tlib=TechLib()): """Parses the given ``text`` as Verilog code. :param text: A string with Verilog code. :param branchforks: If set to ``True``, the returned circuit will include additional `forks` on each fanout branch. These forks are needed to correctly annotate interconnect delays (see :py:func:`kyupy.sdf.DelayFile.annotation`). + :param tlib: A technology library object that provides pin name mappings. + :type tlib: :py:class:`~kyupy.techlib.TechLib` :return: A :class:`~kyupy.circuit.Circuit` object. """ - return Lark(GRAMMAR, parser="lalr", transformer=VerilogTransformer(branchforks)).parse(text) + return Lark(GRAMMAR, parser="lalr", transformer=VerilogTransformer(branchforks, tlib)).parse(text) def load(file, *args, **kwargs): diff --git a/src/kyupy/wave_sim.py b/src/kyupy/wave_sim.py index cea2202..bd04f10 100644 --- a/src/kyupy/wave_sim.py +++ b/src/kyupy/wave_sim.py @@ -192,7 +192,7 @@ class WaveSim: prev_line = prev_line.driver.ins[0] stem_idx = prev_line.index for ol in f.outs: - stems[ol.index] = stem_idx + stems[ol] = stem_idx # calculate level (distance from PI/PPI) and reference count for each line levels = np.zeros(self.sat_length, dtype='int32') @@ -230,7 +230,7 @@ class WaveSim: self.sat[self.ppi_offset + i] = h.alloc(intf_wavecap), intf_wavecap, 0 ref_count[self.ppi_offset + i] += 1 if len(n.ins) > 0: - i0_idx = stems[n.ins[0].index] if stems[n.ins[0].index] >= 0 else n.ins[0].index + i0_idx = stems[n.ins[0]] if stems[n.ins[0]] >= 0 else n.ins[0] ref_count[i0_idx] += 1 # allocate memory for the rest of the circuit @@ -259,7 +259,7 @@ class WaveSim: # copy memory location to PO/PPO area for i, n in enumerate(self.interface): if len(n.ins) > 0: - self.sat[self.ppo_offset + i] = self.sat[n.ins[0].index] + self.sat[self.ppo_offset + i] = self.sat[n.ins[0]] # pad timing self.timing = np.zeros((self.sat_length, 2, 2)) diff --git a/tests/test_sdf.py b/tests/test_sdf.py index 8b30b68..b09469e 100644 --- a/tests/test_sdf.py +++ b/tests/test_sdf.py @@ -1,5 +1,4 @@ from kyupy import sdf, verilog -from kyupy.saed import pin_index def test_parse(): @@ -81,20 +80,20 @@ def test_b14(mydir): def test_gates(mydir): c = verilog.load(mydir / 'gates.v') df = sdf.load(mydir / 'gates.sdf') - lt = df.annotation(c, pin_index, dataset=1) + lt = df.annotation(c, dataset=1) nand_a = c.cells['nandgate'].ins[0] nand_b = c.cells['nandgate'].ins[1] and_a = c.cells['andgate'].ins[0] and_b = c.cells['andgate'].ins[1] - assert lt[nand_a.index, 0, 0] == 0.103 - assert lt[nand_a.index, 0, 1] == 0.127 + assert lt[nand_a, 0, 0] == 0.103 + assert lt[nand_a, 0, 1] == 0.127 - assert lt[nand_b.index, 0, 0] == 0.086 - assert lt[nand_b.index, 0, 1] == 0.104 + assert lt[nand_b, 0, 0] == 0.086 + assert lt[nand_b, 0, 1] == 0.104 - assert lt[and_a.index, 0, 0] == 0.378 - assert lt[and_a.index, 0, 1] == 0.377 + assert lt[and_a, 0, 0] == 0.378 + assert lt[and_a, 0, 1] == 0.377 - assert lt[and_b.index, 0, 0] == 0.375 - assert lt[and_b.index, 0, 1] == 0.370 + assert lt[and_b, 0, 0] == 0.375 + assert lt[and_b, 0, 1] == 0.370 diff --git a/tests/test_wave_sim.py b/tests/test_wave_sim.py index 6240ace..8ddb94d 100644 --- a/tests/test_wave_sim.py +++ b/tests/test_wave_sim.py @@ -3,7 +3,6 @@ import numpy as np from kyupy.wave_sim import WaveSim, WaveSimCuda, wave_eval, TMIN, TMAX from kyupy.logic_sim import LogicSim from kyupy import verilog, sdf, logic -from kyupy.saed import pin_index from kyupy.logic import MVArray, BPArray @@ -128,7 +127,7 @@ def compare_to_logic_sim(wsim): def test_b14(mydir): c = verilog.load(mydir / 'b14.v.gz', branchforks=True) df = sdf.load(mydir / 'b14.sdf.gz') - lt = df.annotation(c, pin_index) + lt = df.annotation(c) wsim = WaveSim(c, lt, 8) compare_to_logic_sim(wsim) @@ -136,7 +135,7 @@ def test_b14(mydir): def test_b14_strip_forks(mydir): c = verilog.load(mydir / 'b14.v.gz', branchforks=True) df = sdf.load(mydir / 'b14.sdf.gz') - lt = df.annotation(c, pin_index) + lt = df.annotation(c) wsim = WaveSim(c, lt, 8, strip_forks=True) compare_to_logic_sim(wsim) @@ -144,6 +143,6 @@ def test_b14_strip_forks(mydir): def test_b14_cuda(mydir): c = verilog.load(mydir / 'b14.v.gz', branchforks=True) df = sdf.load(mydir / 'b14.sdf.gz') - lt = df.annotation(c, pin_index) + lt = df.annotation(c) wsim = WaveSimCuda(c, lt, 8) compare_to_logic_sim(wsim)