diff --git a/src/kyupy/techlib.py b/src/kyupy/techlib.py index 4c35819..5e8e843 100644 --- a/src/kyupy/techlib.py +++ b/src/kyupy/techlib.py @@ -47,7 +47,9 @@ class TechLib: ('SDFF', ('QN',), 1), ('SDFF', ('CLK',), 3), ('SDFF', ('RSTB', 'RN'), 4), - ('SDFF', ('SETB',), 5)]: + ('SDFF', ('SETB',), 5), + ('ISOL', ('ISO',), 0), + ('ISOL', ('D',), 1)]: if kind.startswith(prefix) and pin in pins: return index for index, pins in enumerate([('A1', 'IN1', 'A', 'S', 'INP', 'I', 'Q', 'QN', 'Y', 'Z', 'ZN'), ('A2', 'IN2', 'B', 'CK', 'CLK', 'CO', 'SE'), diff --git a/src/kyupy/verilog.py b/src/kyupy/verilog.py index 10cf9dd..fef8b13 100644 --- a/src/kyupy/verilog.py +++ b/src/kyupy/verilog.py @@ -44,9 +44,7 @@ class VerilogTransformer(Transformer): @staticmethod def name(args): s = args[0].value - if s[0] == '\\': - s = s[1:].replace(' ','') - return s + return s[1:-1] if s[0] == '\\' else s @staticmethod def instantiation(args): @@ -56,9 +54,25 @@ class VerilogTransformer(Transformer): def range(self, args): left = int(args[0].value) - right = int(args[1].value) + right = int(args[1].value) if len(args) > 1 else left return range(left, right+1) if left <= right else range(left, right-1, -1) + def sigsel(self, args): + if len(args) > 1 and isinstance(args[1], range): + l = [f'{args[0]}[{i}]' for i in args[1]] + return l if len(l) > 1 else l[0] + else: + return args[0] + + def concat(self, args): + sigs = [] + for a in args: + if isinstance(a, list): + sigs += a + else: + sigs.append(a) + return sigs + def declaration(self, kind, args): rnge = None if isinstance(args[0], range): @@ -110,12 +124,23 @@ class VerilogTransformer(Transformer): cnode = Node(c, f'__const{s2[3]}_{const_count}__', f'__const{s2[3]}__') const_count += 1 Line(c, cnode, Node(c, s1)) - for s1, s2 in assignments: # pass 1.5: process signal assignments - if isinstance(s2, Tree) and s2.data == 'concatenation': - for target, source in zip(self._signal_declarations[s1].names, s2.children): - assign_wire(target, source) - else: - assign_wire(s1, s2) + for target, source in assignments: # pass 1.5: process signal assignments + target_sigs = [] + if not isinstance(target, list): target = [target] + for s in target: + if s in self._signal_declarations: + target_sigs += self._signal_declarations[s].names + else: + target_sigs.append(s) + source_sigs = [] + if not isinstance(source, list): source = [source] + for s in source: + if s in self._signal_declarations: + source_sigs += self._signal_declarations[s].names + else: + source_sigs.append(s) + for t, s in zip(target_sigs, source_sigs): + assign_wire(t, s) for stmt in args[2:]: # pass 2: connect signals to readers if isinstance(stmt, Instantiation): for p, s in stmt.pins.items(): @@ -159,15 +184,14 @@ GRAMMAR = r""" inout: "inout" range? _namelist ";" tri: "tri" range? _namelist ";" wire: "wire" range? _namelist ";" - assign: "assign" lvalue "=" _expression ";" + assign: "assign" sigsel "=" sigsel ";" instantiation: name name "(" [ pin ( "," pin )* ] ")" ";" - pin: "." name "(" name? ")" + pin: "." name "(" sigsel? ")" range: "[" /[0-9]+/ (":" /[0-9]+/)? "]" - ?lvalue: name range? - _expression: name | concatenation - concatenation: "{" _namelist "}" + sigsel: name range? | concat + concat: "{" sigsel ( "," sigsel )* "}" _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]/i | /1'b0/i | /1'b1/i ) %import common.NEWLINE COMMENT: /\/\*(\*(?!\/)|[^*])*\*\// | /\(\*(\*(?!\))|[^*])*\*\)/ | "//" /(.)*/ NEWLINE %ignore ( /\r?\n/ | COMMENT )+ diff --git a/tests/test_verilog.py b/tests/test_verilog.py index 366032a..67ec9a6 100644 --- a/tests/test_verilog.py +++ b/tests/test_verilog.py @@ -3,6 +3,43 @@ from kyupy import verilog def test_b01(mydir): with open(mydir / 'b01.v', 'r') as f: - modules = verilog.parse(f.read()) - assert modules is not None + c = verilog.parse(f.read()) + assert c is not None assert verilog.load(mydir / 'b01.v') is not None + + assert len(c.nodes) == 139 + assert len(c.lines) == 203 + stats = c.stats + assert stats['input'] == 6 + assert stats['output'] == 3 + assert stats['__seq__'] == 5 + + +def test_b15(mydir): + c = verilog.load(mydir / 'b15_4ig.v.gz') + assert len(c.nodes) == 12067 + assert len(c.lines) == 20731 + stats = c.stats + assert stats['input'] == 40 + assert stats['output'] == 71 + assert stats['__seq__'] == 417 + + +def test_gates(mydir): + c = verilog.load(mydir / 'gates.v') + assert len(c.nodes) == 10 + assert len(c.lines) == 10 + stats = c.stats + assert stats['input'] == 2 + assert stats['output'] == 2 + assert stats['__seq__'] == 0 + + +def test_halton2(mydir): + c = verilog.load(mydir / 'rng_haltonBase2.synth_yosys.v') + assert len(c.nodes) == 146 + assert len(c.lines) == 210 + stats = c.stats + assert stats['input'] == 2 + assert stats['output'] == 12 + assert stats['__seq__'] == 12 \ No newline at end of file