Browse Source

support more SAED cells, improve verilog parsing, fix inspection warnings

main
Stefan Holst 4 years ago
parent
commit
3ad95153ab
  1. 2
      kyupy/__init__.py
  2. 118
      kyupy/saed.py
  3. 2
      kyupy/sdf.py
  4. 26
      kyupy/verilog.py

2
kyupy/__init__.py

@ -45,6 +45,7 @@ class MockCuda:
self.y = 0 self.y = 0
def jit(self, device=False): def jit(self, device=False):
_ = device # silence "not used" warning
outer = self outer = self
def make_launcher(func): def make_launcher(func):
@ -84,6 +85,7 @@ class MockCuda:
pass pass
def grid(self, dims): def grid(self, dims):
_ = dims # silence "not used" warning
return self.x, self.y return self.x, self.y

118
kyupy/saed.py

@ -2,10 +2,14 @@ from kyupy.circuit import Node, Line
def pin_index(cell_type, pin): 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('MUX21') and pin == 'S': return 2
if cell_type.startswith('SDFF') and pin == 'QN': return 1 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 == 'QN': return 1
if cell_type.startswith('DFF') and pin == 'CLK': 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 ['A2', 'IN2', 'SE', 'B', 'CO']: return 1
if pin in ['A3', 'IN3', 'SI', 'CI']: return 2 if pin in ['A3', 'IN3', 'SI', 'CI']: return 2
if pin == 'A4' or pin == 'IN4' or pin == 'CLK': return 3 # CLK for scan cells SDFF if pin == 'A4' or pin == 'IN4' or pin == 'CLK': return 3 # CLK for scan cells SDFF
@ -17,7 +21,7 @@ def pin_index(cell_type, pin):
def pin_is_output(kind, pin): def pin_is_output(kind, pin):
if 'MUX' in kind and pin == 'S': if 'MUX' in kind and pin == 'S':
return False return False
return pin in ['Q', 'QN', 'Z', 'ZN', 'Y', 'CO', 'S'] 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): def add_and_connect(circuit, name, kind, in1=None, in2=None, out=None):
@ -58,7 +62,7 @@ def split_complex_gates(circuit):
n_or = add_and_connect(circuit, name+'~or', 'OR2', ins[0], ins[1], None) 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]) n_and = add_and_connect(circuit, name+'~and', 'AND2', None, ins[2], outs[0])
Line(circuit, n_or, n_and) Line(circuit, n_or, n_and)
elif n.kind.startswith('OAI21'): elif n.kind.startswith('OAI21X'):
n.remove() n.remove()
n_or = add_and_connect(circuit, name+'~or', 'OR2', ins[0], ins[1], None) 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]) n_nand = add_and_connect(circuit, name+'~nand', 'NAND2', None, ins[2], outs[0])
@ -70,6 +74,13 @@ def split_complex_gates(circuit):
n_and = add_and_connect(circuit, name+'~and', 'AND2', None, None, outs[0]) n_and = add_and_connect(circuit, name+'~and', 'AND2', None, None, outs[0])
Line(circuit, n_or0, n_and) Line(circuit, n_or0, n_and)
Line(circuit, n_or1, 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'): elif n.kind.startswith('AO22X'):
n.remove() n.remove()
n_and0 = add_and_connect(circuit, name+'~and0', 'AND2', ins[0], ins[1], None) n_and0 = add_and_connect(circuit, name+'~and0', 'AND2', ins[0], ins[1], None)
@ -77,6 +88,13 @@ def split_complex_gates(circuit):
n_or = add_and_connect(circuit, name+'~or', 'OR2', None, None, outs[0]) n_or = add_and_connect(circuit, name+'~or', 'OR2', None, None, outs[0])
Line(circuit, n_and0, n_or) Line(circuit, n_and0, n_or)
Line(circuit, n_and1, 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'): elif n.kind.startswith('AO221X'):
n.remove() n.remove()
n_and0 = add_and_connect(circuit, name+'~and0', 'AND2', ins[0], ins[1], None) n_and0 = add_and_connect(circuit, name+'~and0', 'AND2', ins[0], ins[1], None)
@ -104,6 +122,15 @@ def split_complex_gates(circuit):
Line(circuit, n_or0, n_and0) Line(circuit, n_or0, n_and0)
Line(circuit, n_or1, n_and0) Line(circuit, n_or1, n_and0)
Line(circuit, n_and0, n_and1) 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'): elif n.kind.startswith('AO222X'):
n.remove() n.remove()
n_and0 = add_and_connect(circuit, name+'~and0', 'AND2', ins[0], ins[1], None) n_and0 = add_and_connect(circuit, name+'~and0', 'AND2', ins[0], ins[1], None)
@ -137,11 +164,75 @@ def split_complex_gates(circuit):
Line(circuit, n_or1, n_and0) Line(circuit, n_or1, n_and0)
Line(circuit, n_or2, n_and1) Line(circuit, n_or2, n_and1)
Line(circuit, n_and0, 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'): elif n.kind.startswith('NOR3X'):
n.remove() n.remove()
n_or = add_and_connect(circuit, name+'~or', 'OR2', ins[0], ins[1], None) n0 = add_and_connect(circuit, name+'~or', 'OR2', ins[0], ins[1], None)
n_nor = add_and_connect(circuit, name+'~nor', 'NOR2', None, ins[2], outs[0]) n1 = add_and_connect(circuit, name+'~nor', 'NOR2', None, ins[2], outs[0])
Line(circuit, n_or, n_nor) 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'): elif n.kind.startswith('FADDX'):
n.remove() n.remove()
# forks for fan-outs # forks for fan-outs
@ -169,6 +260,17 @@ def split_complex_gates(circuit):
n_or = add_and_connect(circuit, name + '~or0', 'OR2', None, None, outs[1]) n_or = add_and_connect(circuit, name + '~or0', 'OR2', None, None, outs[1])
Line(circuit, n_and0, n_or) Line(circuit, n_and0, n_or)
Line(circuit, n_and1, 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'): elif n.kind.startswith('MUX21X'):
n.remove() n.remove()
f_s = add_and_connect(circuit, name + '~fork0', '__fork__', ins[2]) f_s = add_and_connect(circuit, name + '~fork0', '__fork__', ins[2])
@ -181,5 +283,7 @@ def split_complex_gates(circuit):
Line(circuit, f_s, n_and1) Line(circuit, f_s, n_and1)
Line(circuit, n_and0, n_or0) Line(circuit, n_and0, n_or0)
Line(circuit, n_and1, 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))

2
kyupy/sdf.py

@ -170,7 +170,7 @@ class SdfTransformer(Transformer):
return DelayFile(name, cells) return DelayFile(name, cells)
def parse(sdf) -> DelayFile: def parse(sdf):
grammar = r""" grammar = r"""
start: "(DELAYFILE" ( "(SDFVERSION" _NOB ")" start: "(DELAYFILE" ( "(SDFVERSION" _NOB ")"
| "(DESIGN" "\"" NAME "\"" ")" | "(DESIGN" "\"" NAME "\"" ")"

26
kyupy/verilog.py

@ -1,6 +1,8 @@
from lark import Lark, Transformer
from collections import namedtuple from collections import namedtuple
import gzip import gzip
from lark import Lark, Transformer
from .circuit import Circuit, Node, Line from .circuit import Circuit, Node, Line
from .saed import pin_index, pin_is_output from .saed import pin_index, pin_is_output
@ -110,7 +112,7 @@ class VerilogTransformer(Transformer):
Line(c, Node(c, const, const), Node(c, s)) Line(c, Node(c, const, const), Node(c, s))
fork = c.forks[s] fork = c.forks[s]
if self.branchforks: if self.branchforks:
branchfork = Node(c, fork.name + "~" + n.name) 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, pin_index(stmt.type, p)))
@ -126,10 +128,9 @@ class VerilogTransformer(Transformer):
return args[0] return args[0]
else: else:
return args return args
def parse(verilog, branchforks=False) -> Circuit:
grammar = """ grammar = """
start: (module)* start: (module)*
module: "module" name parameters ";" (_statement)* "endmodule" module: "module" name parameters ";" (_statement)* "endmodule"
parameters: "(" [ name ( "," name )* ] ")" parameters: "(" [ name ( "," name )* ] ")"
@ -143,12 +144,23 @@ def parse(verilog, branchforks=False) -> Circuit:
instantiation: name name "(" [ pin ( "," pin )* ] ")" ";" instantiation: name name "(" [ pin ( "," pin )* ] ")" ";"
pin: "." name "(" name ")" pin: "." name "(" name ")"
signal: ( name | "[" /[0-9]+/ ":" /[0-9]+/ "]" name ) signal: ( name | "[" /[0-9]+/ ":" /[0-9]+/ "]" name )
name: ( /[a-z_][a-z0-9_\\[\\]]*/i | /\\\\[^\\t \\r\\n]+[\\t \\r\\n](\\[[0-9]+\\])?/i | /1'b0/i | /1'b1/i ) name: ( /[a-z_][a-z0-9_\\[\\]]*/i | /\\\\[^\\t \\r\\n]+[\\t \\r\\n](\\[[0-9]+\\])?/i | /1'b0/i | /1'b1/i )
COMMENT: "//" /[^\\n]*/ COMMENT: "//" /[^\\n]*/
%ignore ( /\\r?\\n/ | COMMENT )+ %ignore ( /\\r?\\n/ | COMMENT )+
%ignore /[\\t \\f]+/ %ignore /[\\t \\f]+/
""" """
def loads(s, *, branchforks=False):
return Lark(grammar, parser="lalr", transformer=VerilogTransformer(branchforks)).parse(s)
def load(fp, *, branchforks=False):
return loads(fp.read(), branchforks=branchforks)
def parse(verilog, branchforks=False):
if '\n' not in str(verilog): # One line?: Assuming it is a file name. if '\n' not in str(verilog): # One line?: Assuming it is a file name.
if str(verilog).endswith('.gz'): if str(verilog).endswith('.gz'):
with gzip.open(verilog, 'rt') as f: with gzip.open(verilog, 'rt') as f:
@ -158,4 +170,4 @@ def parse(verilog, branchforks=False) -> Circuit:
text = f.read() text = f.read()
else: else:
text = str(verilog) text = str(verilog)
return Lark(grammar, parser="lalr", transformer=VerilogTransformer(branchforks)).parse(text) return loads(text, branchforks=branchforks)

Loading…
Cancel
Save