diff --git a/src/kyupy/logic_sim.py b/src/kyupy/logic_sim.py index 993938a..92641f2 100644 --- a/src/kyupy/logic_sim.py +++ b/src/kyupy/logic_sim.py @@ -107,10 +107,10 @@ class LogicSim: sim.capture(state_bp) :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 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(): if self.state_epoch[node] != self.epoch: continue diff --git a/src/kyupy/sdf.py b/src/kyupy/sdf.py index f89d7b3..78715f7 100644 --- a/src/kyupy/sdf.py +++ b/src/kyupy/sdf.py @@ -9,6 +9,7 @@ Call :py:func:`DelayFile.annotation` to match the intermediate representation to """ from collections import namedtuple +import re import numpy as np from lark import Lark, Transformer @@ -93,13 +94,11 @@ class DelayFile: if cell is None: log.warn(f'Cell from SDF not found in circuit: {cn}') continue + ipn = re.sub(r'\((neg|pos)edge ([^)]+)\)', r'\2', ipn) 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')\ - .replace('(posedge A2)', 'A2').replace('(negedge A2)', 'A2') - def add_delays(_line): if _line is not None: timing[_line, :, 0] += select_del(delvals, 0) @@ -107,13 +106,12 @@ class DelayFile: take_avg = False if kind.startswith('sdff'): - if not ipn.startswith('(posedge CLK'): + if not ipn.startswith('CLK'): continue if ffdelays and (len(cell.outs) > opin): add_delays(cell.outs[opin]) else: if kind.startswith(('xor', 'xnor')): - 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]) diff --git a/src/kyupy/stil.py b/src/kyupy/stil.py index 75bffc2..c0c789d 100644 --- a/src/kyupy/stil.py +++ b/src/kyupy/stil.py @@ -49,11 +49,10 @@ class StilFile: for si_port in self.si_ports: if si_port in call.parameters: sload[si_port] = call.parameters[si_port].replace('\n', '') - if call.name.endswith('_launch') or call.name.endswith('_capture'): - if len(launch) == 0: - launch = dict((k, v.replace('\n', '')) for k, v in call.parameters.items()) - else: - capture = dict((k, v.replace('\n', '')) for k, v in call.parameters.items()) + if call.name.endswith('_launch'): + launch = dict((k, v.replace('\n', '')) for k, v in call.parameters.items()) + if call.name.endswith('_capture'): + capture = dict((k, v.replace('\n', '')) for k, v in call.parameters.items()) def _maps(self, c): interface = list(c.interface) + [n for n in c.nodes if 'DFF' in n.kind] @@ -197,7 +196,7 @@ class StilTransformer(Transformer): GRAMMAR = r""" - start: "STIL" FLOAT _ignore _block* + start: "STIL" FLOAT ( _ignore | ";" ) _block* _block: signal_groups | scan_structures | pattern | "Header" _ignore | "Signals" _ignore @@ -206,6 +205,7 @@ GRAMMAR = r""" | "PatternExec" _ignore | "Procedures" _ignore | "MacroDefs" _ignore + | "UserKeywords" /[a-zA-Z]*;/ signal_groups: "SignalGroups" "{" signal_group* "}" signal_group: quoted "=" "'" quoted ( "+" quoted)* "'" _ignore? ";"? diff --git a/src/kyupy/techlib.py b/src/kyupy/techlib.py index 5a5a01b..e4c4955 100644 --- a/src/kyupy/techlib.py +++ b/src/kyupy/techlib.py @@ -29,20 +29,28 @@ class TechLib: @staticmethod def pin_index(kind, pin): """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), ('MUX21', ('S',), 2), + ('MX2', ('S0',), 2), + ('TBUF', ('OE',), 1), + ('TINV', ('OE',), 1), ('DFF', ('QN',), 1), + ('DFF', ('D',), 0), + ('SDFF', ('D',), 0), ('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')]): + for index, pins in enumerate([('A1', 'IN1', 'A', 'S', 'INP', 'Q', 'QN', 'Y', 'Z', 'ZN'), + ('A2', 'IN2', 'B', 'CK', 'CLK', 'CO', 'SE'), + ('A3', 'IN3', 'C', 'RN', 'RSTB', 'CI', 'SI'), + ('A4', 'IN4', 'D', 'SN', 'SETB'), + ('A5', 'IN5', 'E'), + ('A6', 'IN6', 'F')]): if pin in pins: return index raise ValueError(f'Unknown pin index for {kind}.{pin}') diff --git a/src/kyupy/verilog.py b/src/kyupy/verilog.py index c6b5ab0..e8a20bd 100644 --- a/src/kyupy/verilog.py +++ b/src/kyupy/verilog.py @@ -8,7 +8,7 @@ from collections import namedtuple from lark import Lark, Transformer -from . import readtext +from . import log, readtext from .circuit import Circuit, Node, Line from .techlib import TechLib @@ -17,27 +17,21 @@ Instantiation = namedtuple('Instantiation', ['type', 'name', 'pins']) class SignalDeclaration: - def __init__(self, kind, tokens): + def __init__(self, kind, name, rnge=None): self.left = None self.right = None self.kind = kind - if len(tokens.children) == 1: - self.basename = tokens.children[0] - else: - self.basename = tokens.children[2] - self.left = int(tokens.children[0].value) - self.right = int(tokens.children[1].value) + self.basename = name + self.rnge = rnge @property def names(self): - if self.left is None: + if self.rnge is None: return [self.basename] - if self.left <= self.right: - 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)] + return [f'{self.basename}[{i}]' for i in self.rnge] def __repr__(self): - return f"{self.kind}:{self.basename}[{self.left}:{self.right}]" + return f"{self.kind}:{self.basename}[{self.rnge}]" class VerilogTransformer(Transformer): @@ -57,28 +51,33 @@ class VerilogTransformer(Transformer): @staticmethod def instantiation(args): return Instantiation(args[0], args[1], - dict((pin.children[0], pin.children[1]) for pin in args[2:])) - - def input(self, args): - for sd in [SignalDeclaration('input', signal) for signal in args]: - self._signal_declarations[sd.basename] = sd - - def inout(self, args): - for sd in [SignalDeclaration('input', signal) for signal in args]: # just treat as input - self._signal_declarations[sd.basename] = sd - - def output(self, args): - for sd in [SignalDeclaration('output', signal) for signal in args]: - self._signal_declarations[sd.basename] = sd - - def wire(self, args): - for sd in [SignalDeclaration('wire', signal) for signal in args]: - self._signal_declarations[sd.basename] = sd + dict((pin.children[0], + pin.children[1]) for pin in args[2:] if len(pin.children) > 1)) + + def range(self, args): + left = int(args[0].value) + right = int(args[1].value) + return range(left, right+1) if left <= right else range(left, right-1, -1) + + def declaration(self, kind, args): + rnge = None + if isinstance(args[0], range): + rnge = args[0] + args = args[1:] + for sd in [SignalDeclaration(kind, signal, rnge) for signal in args]: + if kind != 'wire' or sd.basename not in self._signal_declarations: + 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): c = Circuit(args[0]) positions = {} pos = 0 + const_count = 0 for intf_sig in args[1].children: for name in self._signal_declarations[intf_sig].names: positions[name] = pos @@ -107,15 +106,24 @@ class VerilogTransformer(Transformer): elif s2 in c.forks: assert s1 not in c.forks, 'assignment between two driven signals' 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 if isinstance(stmt, Instantiation): for p, s in stmt.pins.items(): n = c.cells[stmt.name] 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: - Line(c, Node(c, const, const), Node(c, s)) + cname = f'__const{s[3]}_{const_count}__' + cnode = Node(c, cname, f'__const{s[3]}__') + 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] if self.branchforks: branchfork = Node(c, fork.name + "~" + n.name + "/" + p) @@ -125,7 +133,10 @@ class VerilogTransformer(Transformer): for sd in self._signal_declarations.values(): if sd.kind == 'output': 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 @staticmethod @@ -135,18 +146,19 @@ class VerilogTransformer(Transformer): GRAMMAR = """ start: (module)* module: "module" name parameters ";" (_statement)* "endmodule" - parameters: "(" [ name ( "," name )* ] ")" + parameters: "(" [ _namelist ] ")" _statement: input | output | inout | tri | wire | assign | instantiation - input: "input" signal ( "," signal )* ";" - output: "output" signal ( "," signal )* ";" - inout: "inout" signal ( "," signal )* ";" - tri: "tri" name ";" - wire: "wire" signal ( "," signal )* ";" + input: "input" range? _namelist ";" + output: "output" range? _namelist ";" + inout: "inout" range? _namelist ";" + tri: "tri" range? _namelist ";" + wire: "wire" range? _namelist ";" assign: "assign" name "=" name ";" instantiation: name name "(" [ pin ( "," pin )* ] ")" ";" - pin: "." name "(" name ")" - signal: ( name | "[" /[0-9]+/ ":" /[0-9]+/ "]" name ) + pin: "." name "(" 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 ) COMMENT: "//" /[^\\n]*/ %ignore ( /\\r?\\n/ | COMMENT )+