Browse Source

fixes for IWLS benchmark netlists and older STIL files

main
Stefan Holst 4 years ago
parent
commit
b17ab2d148
  1. 4
      src/kyupy/logic_sim.py
  2. 8
      src/kyupy/sdf.py
  3. 12
      src/kyupy/stil.py
  4. 20
      src/kyupy/techlib.py
  5. 96
      src/kyupy/verilog.py

4
src/kyupy/logic_sim.py

@ -107,10 +107,10 @@ class LogicSim:
sim.capture(state_bp) sim.capture(state_bp)
:param inject_cb: A callback function for manipulating intermediate signal values. :param inject_cb: A callback function for manipulating intermediate signal values.
This function is called with a line index and its new logic values (in bit-parallel format) after This function is called with a line and its new logic values (in bit-parallel format) after
evaluation of a node. The callback may manipulate the given values in-place, the simulation evaluation of a node. The callback may manipulate the given values in-place, the simulation
resumes with the manipulated values after the callback returns. resumes with the manipulated values after the callback returns.
:type inject_cb: ``f(int, ndarray)`` :type inject_cb: ``f(Line, ndarray)``
""" """
for node in self.circuit.topological_order(): for node in self.circuit.topological_order():
if self.state_epoch[node] != self.epoch: continue if self.state_epoch[node] != self.epoch: continue

8
src/kyupy/sdf.py

@ -9,6 +9,7 @@ Call :py:func:`DelayFile.annotation` to match the intermediate representation to
""" """
from collections import namedtuple from collections import namedtuple
import re
import numpy as np import numpy as np
from lark import Lark, Transformer from lark import Lark, Transformer
@ -93,13 +94,11 @@ 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
ipn = re.sub(r'\((neg|pos)edge ([^)]+)\)', r'\2', ipn)
ipin = tlib.pin_index(cell.kind, ipn) ipin = tlib.pin_index(cell.kind, ipn)
opin = tlib.pin_index(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')\
.replace('(posedge A2)', 'A2').replace('(negedge A2)', 'A2')
def add_delays(_line): def add_delays(_line):
if _line is not None: if _line is not None:
timing[_line, :, 0] += select_del(delvals, 0) timing[_line, :, 0] += select_del(delvals, 0)
@ -107,13 +106,12 @@ class DelayFile:
take_avg = False take_avg = False
if kind.startswith('sdff'): if kind.startswith('sdff'):
if not ipn.startswith('(posedge CLK'): if not ipn.startswith('CLK'):
continue continue
if ffdelays and (len(cell.outs) > opin): if ffdelays and (len(cell.outs) > opin):
add_delays(cell.outs[opin]) add_delays(cell.outs[opin])
else: else:
if kind.startswith(('xor', 'xnor')): if kind.startswith(('xor', 'xnor')):
ipin = tlib.pin_index(cell.kind, ipn2)
# print(ipn, ipin, times[cell.i_lines[ipin], 0, 0]) # print(ipn, ipin, times[cell.i_lines[ipin], 0, 0])
take_avg = timing[cell.ins[ipin]].sum() > 0 take_avg = timing[cell.ins[ipin]].sum() > 0
add_delays(cell.ins[ipin]) add_delays(cell.ins[ipin])

12
src/kyupy/stil.py

@ -49,11 +49,10 @@ class StilFile:
for si_port in self.si_ports: for si_port in self.si_ports:
if si_port in call.parameters: if si_port in call.parameters:
sload[si_port] = call.parameters[si_port].replace('\n', '') sload[si_port] = call.parameters[si_port].replace('\n', '')
if call.name.endswith('_launch') or call.name.endswith('_capture'): if call.name.endswith('_launch'):
if len(launch) == 0: launch = dict((k, v.replace('\n', '')) for k, v in call.parameters.items())
launch = dict((k, v.replace('\n', '')) for k, v in call.parameters.items()) if call.name.endswith('_capture'):
else: capture = dict((k, v.replace('\n', '')) for k, v in call.parameters.items())
capture = dict((k, v.replace('\n', '')) for k, v in call.parameters.items())
def _maps(self, c): def _maps(self, c):
interface = list(c.interface) + [n for n in c.nodes if 'DFF' in n.kind] interface = list(c.interface) + [n for n in c.nodes if 'DFF' in n.kind]
@ -197,7 +196,7 @@ class StilTransformer(Transformer):
GRAMMAR = r""" GRAMMAR = r"""
start: "STIL" FLOAT _ignore _block* start: "STIL" FLOAT ( _ignore | ";" ) _block*
_block: signal_groups | scan_structures | pattern _block: signal_groups | scan_structures | pattern
| "Header" _ignore | "Header" _ignore
| "Signals" _ignore | "Signals" _ignore
@ -206,6 +205,7 @@ GRAMMAR = r"""
| "PatternExec" _ignore | "PatternExec" _ignore
| "Procedures" _ignore | "Procedures" _ignore
| "MacroDefs" _ignore | "MacroDefs" _ignore
| "UserKeywords" /[a-zA-Z]*;/
signal_groups: "SignalGroups" "{" signal_group* "}" signal_groups: "SignalGroups" "{" signal_group* "}"
signal_group: quoted "=" "'" quoted ( "+" quoted)* "'" _ignore? ";"? signal_group: quoted "=" "'" quoted ( "+" quoted)* "'" _ignore? ";"?

20
src/kyupy/techlib.py

@ -29,20 +29,28 @@ class TechLib:
@staticmethod @staticmethod
def pin_index(kind, pin): def pin_index(kind, pin):
"""Returns a pin list position for a given node kind and pin name.""" """Returns a pin list position for a given node kind and pin name."""
if kind[:3] in ('OAI', 'AOI'):
if pin[0] == 'A': return int(pin[1])
if pin[0] == 'B': return int(pin[1]) + int(kind[4])
for prefix, pins, index in [('HADD', ('B0', 'SO'), 1), for prefix, pins, index in [('HADD', ('B0', 'SO'), 1),
('MUX21', ('S',), 2), ('MUX21', ('S',), 2),
('MX2', ('S0',), 2),
('TBUF', ('OE',), 1),
('TINV', ('OE',), 1),
('DFF', ('QN',), 1), ('DFF', ('QN',), 1),
('DFF', ('D',), 0),
('SDFF', ('D',), 0),
('SDFF', ('QN',), 1), ('SDFF', ('QN',), 1),
('SDFF', ('CLK',), 3), ('SDFF', ('CLK',), 3),
('SDFF', ('RSTB',), 4), ('SDFF', ('RSTB',), 4),
('SDFF', ('SETB',), 5)]: ('SDFF', ('SETB',), 5)]:
if kind.startswith(prefix) and pin in pins: return index 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'), for index, pins in enumerate([('A1', 'IN1', 'A', 'S', 'INP', 'Q', 'QN', 'Y', 'Z', 'ZN'),
('A2', 'IN2', 'CLK', 'CO', 'SE', 'B'), ('A2', 'IN2', 'B', 'CK', 'CLK', 'CO', 'SE'),
('A3', 'IN3', 'RSTB', 'CI', 'SI'), ('A3', 'IN3', 'C', 'RN', 'RSTB', 'CI', 'SI'),
('A4', 'IN4', 'SETB'), ('A4', 'IN4', 'D', 'SN', 'SETB'),
('A5', 'IN5'), ('A5', 'IN5', 'E'),
('A6', 'IN6')]): ('A6', 'IN6', 'F')]):
if pin in pins: return index if pin in pins: return index
raise ValueError(f'Unknown pin index for {kind}.{pin}') raise ValueError(f'Unknown pin index for {kind}.{pin}')

96
src/kyupy/verilog.py

@ -8,7 +8,7 @@ from collections import namedtuple
from lark import Lark, Transformer from lark import Lark, Transformer
from . import readtext from . import log, readtext
from .circuit import Circuit, Node, Line from .circuit import Circuit, Node, Line
from .techlib import TechLib from .techlib import TechLib
@ -17,27 +17,21 @@ Instantiation = namedtuple('Instantiation', ['type', 'name', 'pins'])
class SignalDeclaration: class SignalDeclaration:
def __init__(self, kind, tokens): def __init__(self, kind, name, rnge=None):
self.left = None self.left = None
self.right = None self.right = None
self.kind = kind self.kind = kind
if len(tokens.children) == 1: self.basename = name
self.basename = tokens.children[0] self.rnge = rnge
else:
self.basename = tokens.children[2]
self.left = int(tokens.children[0].value)
self.right = int(tokens.children[1].value)
@property @property
def names(self): def names(self):
if self.left is None: if self.rnge is None:
return [self.basename] return [self.basename]
if self.left <= self.right: return [f'{self.basename}[{i}]' for i in self.rnge]
return [f'{self.basename}[{i}]' for i in range(self.left, self.right + 1)]
return [f'{self.basename}[{i}]' for i in range(self.left, self.right - 1, -1)]
def __repr__(self): def __repr__(self):
return f"{self.kind}:{self.basename}[{self.left}:{self.right}]" return f"{self.kind}:{self.basename}[{self.rnge}]"
class VerilogTransformer(Transformer): class VerilogTransformer(Transformer):
@ -57,28 +51,33 @@ class VerilogTransformer(Transformer):
@staticmethod @staticmethod
def instantiation(args): def instantiation(args):
return Instantiation(args[0], args[1], return Instantiation(args[0], args[1],
dict((pin.children[0], pin.children[1]) for pin in args[2:])) dict((pin.children[0],
pin.children[1]) for pin in args[2:] if len(pin.children) > 1))
def input(self, args):
for sd in [SignalDeclaration('input', signal) for signal in args]: def range(self, args):
self._signal_declarations[sd.basename] = sd left = int(args[0].value)
right = int(args[1].value)
def inout(self, args): return range(left, right+1) if left <= right else range(left, right-1, -1)
for sd in [SignalDeclaration('input', signal) for signal in args]: # just treat as input
self._signal_declarations[sd.basename] = sd def declaration(self, kind, args):
rnge = None
def output(self, args): if isinstance(args[0], range):
for sd in [SignalDeclaration('output', signal) for signal in args]: rnge = args[0]
self._signal_declarations[sd.basename] = sd args = args[1:]
for sd in [SignalDeclaration(kind, signal, rnge) for signal in args]:
def wire(self, args): if kind != 'wire' or sd.basename not in self._signal_declarations:
for sd in [SignalDeclaration('wire', signal) for signal in args]: self._signal_declarations[sd.basename] = sd
self._signal_declarations[sd.basename] = sd
def input(self, args): self.declaration("input", args)
def output(self, args): self.declaration("output", args)
def inout(self, args): self.declaration("input", args) # just treat as input
def wire(self, args): self.declaration("wire", args)
def module(self, args): def module(self, args):
c = Circuit(args[0]) c = Circuit(args[0])
positions = {} positions = {}
pos = 0 pos = 0
const_count = 0
for intf_sig in args[1].children: for intf_sig in args[1].children:
for name in self._signal_declarations[intf_sig].names: for name in self._signal_declarations[intf_sig].names:
positions[name] = pos positions[name] = pos
@ -107,15 +106,24 @@ class VerilogTransformer(Transformer):
elif s2 in c.forks: elif s2 in c.forks:
assert s1 not in c.forks, 'assignment between two driven signals' assert s1 not in c.forks, 'assignment between two driven signals'
Line(c, c.forks[s2], Node(c, s1)) Line(c, c.forks[s2], Node(c, s1))
elif s2.startswith("1'b"):
cnode = Node(c, f'__const{s2[3]}_{const_count}__', f'__const{s2[3]}__')
const_count += 1
Line(c, cnode, Node(c, s1))
for stmt in args[2:]: # pass 2: connect signals to readers for stmt in args[2:]: # pass 2: connect signals to readers
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 self.tlib.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]}__' cname = f'__const{s[3]}_{const_count}__'
if const not in c.cells: cnode = Node(c, cname, f'__const{s[3]}__')
Line(c, Node(c, const, const), Node(c, s)) const_count += 1
s = cname
Line(c, cnode, Node(c, s))
if s not in c.forks:
log.warn(f'Signal not driven: {s}')
Node(c, s) # generate fork here
fork = c.forks[s] fork = c.forks[s]
if self.branchforks: if self.branchforks:
branchfork = Node(c, fork.name + "~" + n.name + "/" + p) branchfork = Node(c, fork.name + "~" + n.name + "/" + p)
@ -125,7 +133,10 @@ class VerilogTransformer(Transformer):
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:
Line(c, c.forks[name], c.cells[name]) if name not in c.forks:
log.warn(f'Output not driven: {name}')
else:
Line(c, c.forks[name], c.cells[name])
return c return c
@staticmethod @staticmethod
@ -135,18 +146,19 @@ class VerilogTransformer(Transformer):
GRAMMAR = """ GRAMMAR = """
start: (module)* start: (module)*
module: "module" name parameters ";" (_statement)* "endmodule" module: "module" name parameters ";" (_statement)* "endmodule"
parameters: "(" [ name ( "," name )* ] ")" parameters: "(" [ _namelist ] ")"
_statement: input | output | inout | tri | wire | assign | instantiation _statement: input | output | inout | tri | wire | assign | instantiation
input: "input" signal ( "," signal )* ";" input: "input" range? _namelist ";"
output: "output" signal ( "," signal )* ";" output: "output" range? _namelist ";"
inout: "inout" signal ( "," signal )* ";" inout: "inout" range? _namelist ";"
tri: "tri" name ";" tri: "tri" range? _namelist ";"
wire: "wire" signal ( "," signal )* ";" wire: "wire" range? _namelist ";"
assign: "assign" name "=" name ";" assign: "assign" name "=" name ";"
instantiation: name name "(" [ pin ( "," pin )* ] ")" ";" instantiation: name name "(" [ pin ( "," pin )* ] ")" ";"
pin: "." name "(" name ")" pin: "." name "(" name? ")"
signal: ( name | "[" /[0-9]+/ ":" /[0-9]+/ "]" name ) range: "[" /[0-9]+/ ":" /[0-9]+/ "]"
_namelist: name ( "," 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 )+

Loading…
Cancel
Save