Browse Source

TechLib class, remove unnecessary .index

devel
Stefan Holst 4 years ago
parent
commit
62cf56e98a
  1. 17
      Demo.ipynb
  2. 4
      docs/miscellaneous.rst
  3. 2
      src/kyupy/bench.py
  4. 16
      src/kyupy/circuit.py
  5. 2
      src/kyupy/logic.py
  6. 289
      src/kyupy/saed.py
  7. 28
      src/kyupy/sdf.py
  8. 301
      src/kyupy/techlib.py
  9. 19
      src/kyupy/verilog.py
  10. 6
      src/kyupy/wave_sim.py
  11. 19
      tests/test_sdf.py
  12. 7
      tests/test_wave_sim.py

17
Demo.ipynb

@ -44,7 +44,7 @@
{ {
"data": { "data": {
"text/plain": [ "text/plain": [
"<Circuit 'tests/b01.bench' with 92 nodes, 130 lines, 4 ports>" "<Circuit tests/b01.bench cells=45 forks=47 lines=130 ports=4>"
] ]
}, },
"execution_count": 2, "execution_count": 2,
@ -64,7 +64,7 @@
{ {
"data": { "data": {
"text/plain": [ "text/plain": [
"<Circuit with 10 nodes, 8 lines, 5 ports>" "<Circuit cells=4 forks=6 lines=8 ports=5>"
] ]
}, },
"execution_count": 3, "execution_count": 3,
@ -362,7 +362,7 @@
{ {
"data": { "data": {
"text/plain": [ "text/plain": [
"<Circuit 'b14' with 31715 nodes, 46891 lines, 91 ports>" "<Circuit b14 cells=15873 forks=15842 lines=46891 ports=91>"
] ]
}, },
"execution_count": 13, "execution_count": 13,
@ -445,7 +445,7 @@
{ {
"data": { "data": {
"text/plain": [ "text/plain": [
"<Circuit 'b14' with 31715 nodes, 46891 lines, 91 ports>" "<Circuit b14 cells=15873 forks=15842 lines=46891 ports=91>"
] ]
}, },
"execution_count": 15, "execution_count": 15,
@ -591,7 +591,7 @@
{ {
"data": { "data": {
"text/plain": [ "text/plain": [
"<MVArray length=1081 width=306 m=8 nbytes=330786>" "<MVArray length=1081 width=306 m=8 mem=323.0kiB>"
] ]
}, },
"execution_count": 19, "execution_count": 19,
@ -697,7 +697,7 @@
{ {
"data": { "data": {
"text/plain": [ "text/plain": [
"<BPArray length=1081 width=306 m=8 bytes=124848>" "<BPArray length=1081 width=306 m=8 mem=121.9kiB>"
] ]
}, },
"execution_count": 23, "execution_count": 23,
@ -829,7 +829,7 @@
{ {
"data": { "data": {
"text/plain": [ "text/plain": [
"<MVArray length=1392 width=306 m=8 nbytes=425952>" "<MVArray length=1392 width=306 m=8 mem=416.0kiB>"
] ]
}, },
"execution_count": 29, "execution_count": 29,
@ -962,10 +962,9 @@
"outputs": [], "outputs": [],
"source": [ "source": [
"from kyupy import sdf\n", "from kyupy import sdf\n",
"from kyupy.saed import pin_index\n",
"\n", "\n",
"df = sdf.load('tests/b14.sdf.gz')\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)"
] ]
}, },
{ {

4
docs/miscellaneous.rst

@ -1,6 +1,10 @@
Miscellaneous Miscellaneous
============= =============
.. automodule:: kyupy.techlib
:members:
.. automodule:: kyupy .. automodule:: kyupy
:members: :members:

2
src/kyupy/bench.py

@ -29,7 +29,7 @@ class BenchTransformer(Transformer):
name, cell_type, drivers = args name, cell_type, drivers = args
cell = Node(self.c, str(name), str(cell_type)) cell = Node(self.c, str(name), str(cell_type))
Line(self.c, cell, self.c.get_or_add_fork(str(name))) 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""" GRAMMAR = r"""

16
src/kyupy/circuit.py

@ -262,8 +262,8 @@ class Circuit:
for line in n.outs: for line in n.outs:
if line is None: continue if line is None: continue
succ = line.reader succ = line.reader
visit_count[succ.index] += 1 visit_count[succ] += 1
if visit_count[succ.index] == len(succ.ins) and 'DFF' not in succ.kind: if visit_count[succ] == len(succ.ins) and 'DFF' not in succ.kind:
queue.append(succ) queue.append(succ)
yield n yield n
@ -287,8 +287,8 @@ class Circuit:
n = queue.popleft() n = queue.popleft()
for line in n.ins: for line in n.ins:
pred = line.driver pred = line.driver
visit_count[pred.index] += 1 visit_count[pred] += 1
if visit_count[pred.index] == len(pred.outs) and 'DFF' not in pred.kind: if visit_count[pred] == len(pred.outs) and 'DFF' not in pred.kind:
queue.append(pred) queue.append(pred)
yield n yield n
@ -299,13 +299,13 @@ class Circuit:
""" """
marks = [False] * len(self.nodes) marks = [False] * len(self.nodes)
for n in origin_nodes: for n in origin_nodes:
marks[n.index] = True marks[n] = True
for n in self.reversed_topological_order(): for n in self.reversed_topological_order():
if not marks[n.index]: if not marks[n]:
for line in n.outs: for line in n.outs:
if line is not None: if line is not None:
marks[n.index] |= marks[line.reader.index] marks[n] |= marks[line.reader]
if marks[n.index]: if marks[n]:
yield n yield n
def fanout_free_regions(self): def fanout_free_regions(self):

2
src/kyupy/logic.py

@ -116,7 +116,7 @@ class MVArray:
if isinstance(a, MVArray): if isinstance(a, MVArray):
self.data = a.data.copy() self.data = a.data.copy()
"""The wrapped 2-dimensional ndarray of logic values. """The wrapped 2-dimensional ndarray of logic values.
* Axis 0 is PI/PO/FF position, the length of this axis is called "width". * 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". * Axis 1 is vector/pattern, the length of this axis is called "length".
""" """

289
src/kyupy/saed.py

@ -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))

28
src/kyupy/sdf.py

@ -14,6 +14,7 @@ import numpy as np
from lark import Lark, Transformer from lark import Lark, Transformer
from . import log, readtext from . import log, readtext
from .techlib import TechLib
Interconnect = namedtuple('Interconnect', ['orig', 'dest', 'r', 'f']) 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' + \ return '\n'.join(f'{n}: {l}' for n, l in self.cells.items()) + '\n' + \
'\n'.join(str(i) for i in self.interconnects) '\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``. """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. 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. :param circuit: The circuit to annotate. Names from the STIL file are matched to the node names.
:type circuit: :class:`~kyupy.circuit.Circuit` :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). :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'). 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. If a tuple is given, the annotator will calculate the average of multiple datasets.
@ -91,8 +93,8 @@ class DelayFile:
if cell is None: if cell is None:
log.warn(f'Cell from SDF not found in circuit: {cn}') log.warn(f'Cell from SDF not found in circuit: {cn}')
continue continue
ipin = pin_index_f(cell.kind, ipn) ipin = tlib.pin_index(cell.kind, ipn)
opin = pin_index_f(cell.kind, opn) opin = tlib.pin_index(cell.kind, opn)
kind = cell.kind.lower() kind = cell.kind.lower()
ipn2 = ipn.replace('(posedge A1)', 'A1').replace('(negedge A1)', 'A1')\ ipn2 = ipn.replace('(posedge A1)', 'A1').replace('(negedge A1)', 'A1')\
@ -100,8 +102,8 @@ class DelayFile:
def add_delays(_line): def add_delays(_line):
if _line is not None: if _line is not None:
timing[_line.index, :, 0] += select_del(delvals, 0) timing[_line, :, 0] += select_del(delvals, 0)
timing[_line.index, :, 1] += select_del(delvals, 1) timing[_line, :, 1] += select_del(delvals, 1)
take_avg = False take_avg = False
if kind.startswith('sdff'): if kind.startswith('sdff'):
@ -111,12 +113,12 @@ class DelayFile:
add_delays(cell.outs[opin]) add_delays(cell.outs[opin])
else: else:
if kind.startswith(('xor', 'xnor')): if kind.startswith(('xor', 'xnor')):
ipin = pin_index_f(cell.kind, ipn2) ipin = tlib.pin_index(cell.kind, ipn2)
# print(ipn, ipin, times[cell.i_lines[ipin].index, 0, 0]) # print(ipn, ipin, times[cell.i_lines[ipin], 0, 0])
take_avg = timing[cell.ins[ipin].index].sum() > 0 take_avg = timing[cell.ins[ipin]].sum() > 0
add_delays(cell.ins[ipin]) add_delays(cell.ins[ipin])
if take_avg: if take_avg:
timing[cell.ins[ipin].index] /= 2 timing[cell.ins[ipin]] /= 2
if not interconnect or self.interconnects is None: if not interconnect or self.interconnects is None:
return timing return timing
@ -145,7 +147,7 @@ class DelayFile:
if c2 is None: if c2 is None:
log.warn(f'Cell from SDF not found in circuit: {cn2}') log.warn(f'Cell from SDF not found in circuit: {cn2}')
continue 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 line = None
f1, f2 = c1.outs[p1].reader, c2.ins[p2].driver f1, f2 = c1.outs[p1].reader, c2.ins[p2].driver
if f1 != f2: # possible branchfork if f1 != f2: # possible branchfork
@ -155,8 +157,8 @@ class DelayFile:
elif len(f2.outs) == 1: # no fanout? elif len(f2.outs) == 1: # no fanout?
line = f2.ins[0] line = f2.ins[0]
if line is not None: if line is not None:
timing[line.index, :, 0] += select_del(delvals, 0) timing[line, :, 0] += select_del(delvals, 0)
timing[line.index, :, 1] += select_del(delvals, 1) timing[line, :, 1] += select_del(delvals, 1)
else: else:
log.warn(f'No branchfork for annotating interconnect delay {c1.name}/{p1}->{c2.name}/{p2}') log.warn(f'No branchfork for annotating interconnect delay {c1.name}/{p1}->{c2.name}/{p2}')
return timing return timing

301
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))

19
src/kyupy/verilog.py

@ -10,7 +10,7 @@ from lark import Lark, Transformer
from . import readtext from . import readtext
from .circuit import Circuit, Node, Line from .circuit import Circuit, Node, Line
from .saed import pin_index, pin_is_output from .techlib import TechLib
Instantiation = namedtuple('Instantiation', ['type', 'name', 'pins']) Instantiation = namedtuple('Instantiation', ['type', 'name', 'pins'])
@ -41,10 +41,11 @@ class SignalDeclaration:
class VerilogTransformer(Transformer): class VerilogTransformer(Transformer):
def __init__(self, branchforks=False): def __init__(self, branchforks=False, tlib=TechLib()):
super().__init__() super().__init__()
self._signal_declarations = {} self._signal_declarations = {}
self.branchforks = branchforks self.branchforks = branchforks
self.tlib = tlib
@staticmethod @staticmethod
def name(args): def name(args):
@ -87,8 +88,8 @@ class VerilogTransformer(Transformer):
if isinstance(stmt, Instantiation): if isinstance(stmt, Instantiation):
n = Node(c, stmt.name, kind=stmt.type) n = Node(c, stmt.name, kind=stmt.type)
for p, s in stmt.pins.items(): for p, s in stmt.pins.items():
if pin_is_output(n.kind, p): if self.tlib.pin_is_output(n.kind, p):
Line(c, (n, pin_index(stmt.type, p)), Node(c, s)) Line(c, (n, self.tlib.pin_index(stmt.type, p)), Node(c, s))
elif stmt is not None and stmt.data == 'assign': elif stmt is not None and stmt.data == 'assign':
assignments.append((stmt.children[0], stmt.children[1])) assignments.append((stmt.children[0], stmt.children[1]))
for sd in self._signal_declarations.values(): for sd in self._signal_declarations.values():
@ -110,7 +111,7 @@ class VerilogTransformer(Transformer):
if isinstance(stmt, Instantiation): if isinstance(stmt, Instantiation):
for p, s in stmt.pins.items(): for p, s in stmt.pins.items():
n = c.cells[stmt.name] 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"): if s.startswith("1'b"):
const = f'__const{s[3]}__' const = f'__const{s[3]}__'
if const not in c.cells: if const not in c.cells:
@ -120,7 +121,7 @@ class VerilogTransformer(Transformer):
branchfork = Node(c, fork.name + "~" + n.name + "/" + p) branchfork = Node(c, fork.name + "~" + n.name + "/" + p)
Line(c, fork, branchfork) Line(c, fork, branchfork)
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(): for sd in self._signal_declarations.values():
if sd.kind == 'output': if sd.kind == 'output':
for name in sd.names: 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. """Parses the given ``text`` as Verilog code.
:param text: A string with 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. :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 These forks are needed to correctly annotate interconnect delays
(see :py:func:`kyupy.sdf.DelayFile.annotation`). (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: 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): def load(file, *args, **kwargs):

6
src/kyupy/wave_sim.py

@ -192,7 +192,7 @@ class WaveSim:
prev_line = prev_line.driver.ins[0] prev_line = prev_line.driver.ins[0]
stem_idx = prev_line.index stem_idx = prev_line.index
for ol in f.outs: 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 # calculate level (distance from PI/PPI) and reference count for each line
levels = np.zeros(self.sat_length, dtype='int32') 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 self.sat[self.ppi_offset + i] = h.alloc(intf_wavecap), intf_wavecap, 0
ref_count[self.ppi_offset + i] += 1 ref_count[self.ppi_offset + i] += 1
if len(n.ins) > 0: 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 ref_count[i0_idx] += 1
# allocate memory for the rest of the circuit # allocate memory for the rest of the circuit
@ -259,7 +259,7 @@ class WaveSim:
# copy memory location to PO/PPO area # copy memory location to PO/PPO area
for i, n in enumerate(self.interface): for i, n in enumerate(self.interface):
if len(n.ins) > 0: 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 # pad timing
self.timing = np.zeros((self.sat_length, 2, 2)) self.timing = np.zeros((self.sat_length, 2, 2))

19
tests/test_sdf.py

@ -1,5 +1,4 @@
from kyupy import sdf, verilog from kyupy import sdf, verilog
from kyupy.saed import pin_index
def test_parse(): def test_parse():
@ -81,20 +80,20 @@ def test_b14(mydir):
def test_gates(mydir): def test_gates(mydir):
c = verilog.load(mydir / 'gates.v') c = verilog.load(mydir / 'gates.v')
df = sdf.load(mydir / 'gates.sdf') 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_a = c.cells['nandgate'].ins[0]
nand_b = c.cells['nandgate'].ins[1] nand_b = c.cells['nandgate'].ins[1]
and_a = c.cells['andgate'].ins[0] and_a = c.cells['andgate'].ins[0]
and_b = c.cells['andgate'].ins[1] and_b = c.cells['andgate'].ins[1]
assert lt[nand_a.index, 0, 0] == 0.103 assert lt[nand_a, 0, 0] == 0.103
assert lt[nand_a.index, 0, 1] == 0.127 assert lt[nand_a, 0, 1] == 0.127
assert lt[nand_b.index, 0, 0] == 0.086 assert lt[nand_b, 0, 0] == 0.086
assert lt[nand_b.index, 0, 1] == 0.104 assert lt[nand_b, 0, 1] == 0.104
assert lt[and_a.index, 0, 0] == 0.378 assert lt[and_a, 0, 0] == 0.378
assert lt[and_a.index, 0, 1] == 0.377 assert lt[and_a, 0, 1] == 0.377
assert lt[and_b.index, 0, 0] == 0.375 assert lt[and_b, 0, 0] == 0.375
assert lt[and_b.index, 0, 1] == 0.370 assert lt[and_b, 0, 1] == 0.370

7
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.wave_sim import WaveSim, WaveSimCuda, wave_eval, TMIN, TMAX
from kyupy.logic_sim import LogicSim from kyupy.logic_sim import LogicSim
from kyupy import verilog, sdf, logic from kyupy import verilog, sdf, logic
from kyupy.saed import pin_index
from kyupy.logic import MVArray, BPArray from kyupy.logic import MVArray, BPArray
@ -128,7 +127,7 @@ def compare_to_logic_sim(wsim):
def test_b14(mydir): def test_b14(mydir):
c = verilog.load(mydir / 'b14.v.gz', branchforks=True) c = verilog.load(mydir / 'b14.v.gz', branchforks=True)
df = sdf.load(mydir / 'b14.sdf.gz') df = sdf.load(mydir / 'b14.sdf.gz')
lt = df.annotation(c, pin_index) lt = df.annotation(c)
wsim = WaveSim(c, lt, 8) wsim = WaveSim(c, lt, 8)
compare_to_logic_sim(wsim) compare_to_logic_sim(wsim)
@ -136,7 +135,7 @@ def test_b14(mydir):
def test_b14_strip_forks(mydir): def test_b14_strip_forks(mydir):
c = verilog.load(mydir / 'b14.v.gz', branchforks=True) c = verilog.load(mydir / 'b14.v.gz', branchforks=True)
df = sdf.load(mydir / 'b14.sdf.gz') 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) wsim = WaveSim(c, lt, 8, strip_forks=True)
compare_to_logic_sim(wsim) compare_to_logic_sim(wsim)
@ -144,6 +143,6 @@ def test_b14_strip_forks(mydir):
def test_b14_cuda(mydir): def test_b14_cuda(mydir):
c = verilog.load(mydir / 'b14.v.gz', branchforks=True) c = verilog.load(mydir / 'b14.v.gz', branchforks=True)
df = sdf.load(mydir / 'b14.sdf.gz') df = sdf.load(mydir / 'b14.sdf.gz')
lt = df.annotation(c, pin_index) lt = df.annotation(c)
wsim = WaveSimCuda(c, lt, 8) wsim = WaveSimCuda(c, lt, 8)
compare_to_logic_sim(wsim) compare_to_logic_sim(wsim)

Loading…
Cancel
Save