Browse Source

full constants support, fix signal declarations

devel
Stefan Holst 1 year ago
parent
commit
39b8c1695b
  1. 54
      src/kyupy/verilog.py

54
src/kyupy/verilog.py

@ -65,6 +65,16 @@ class VerilogTransformer(Transformer):
if len(args) > 1 and isinstance(args[1], range): if len(args) > 1 and isinstance(args[1], range):
l = [f'{args[0]}[{i}]' for i in args[1]] l = [f'{args[0]}[{i}]' for i in args[1]]
return l if len(l) > 1 else l[0] return l if len(l) > 1 else l[0]
elif "'" in args[0]:
width, rest = args[0].split("'")
width = int(width)
base, const = rest[0], rest[1:]
const = int(const, {'b': 2, 'd':10, 'h':16}[base.lower()])
l = []
for _ in range(width):
l.insert(0, "1'b1" if (const & 1) else "1'b0")
const >>= 1
return l if len(l) > 1 else l[0]
else: else:
return args[0] return args[0]
@ -82,20 +92,24 @@ class VerilogTransformer(Transformer):
if isinstance(args[0], range): if isinstance(args[0], range):
rnge = args[0] rnge = args[0]
args = args[1:] args = args[1:]
for sd in [SignalDeclaration(kind, signal, rnge) for signal in args]: return [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 input(self, args): return self.declaration("input", args)
def output(self, args): self.declaration("output", args) def output(self, args): return self.declaration("output", args)
def inout(self, args): self.declaration("input", args) # just treat as input def inout(self, args): return self.declaration("input", args) # just treat as input
def wire(self, args): self.declaration("wire", args) def wire(self, args): return 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 const_count = 0
self._signal_declarations = {}
for decls in args[2:]: # pass 0: collect signal declarations
if isinstance(decls, list):
if len(decls) > 0 and isinstance(decls[0], SignalDeclaration):
for decl in decls:
self._signal_declarations[decl.basename] = decl
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,7 +121,7 @@ class VerilogTransformer(Transformer):
for p, s in stmt.pins.items(): for p, s in stmt.pins.items():
if self.tlib.pin_is_output(n.kind, p): if self.tlib.pin_is_output(n.kind, p):
Line(c, (n, self.tlib.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 hasattr(stmt, 'data') 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():
if sd.kind == 'output' or sd.kind == 'input': if sd.kind == 'output' or sd.kind == 'input':
@ -117,17 +131,6 @@ class VerilogTransformer(Transformer):
c.io_nodes[positions[name]] = n c.io_nodes[positions[name]] = n
if sd.kind == 'input': if sd.kind == 'input':
Line(c, n, Node(c, name)) Line(c, n, Node(c, name))
def assign_wire(s1, s2):
if s1 in c.forks:
assert s2 not in c.forks, 'assignment between two driven signals'
Line(c, c.forks[s1], Node(c, s2))
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 target, source in assignments: # pass 1.5: process signal assignments for target, source in assignments: # pass 1.5: process signal assignments
target_sigs = [] target_sigs = []
if not isinstance(target, list): target = [target] if not isinstance(target, list): target = [target]
@ -144,7 +147,16 @@ class VerilogTransformer(Transformer):
else: else:
source_sigs.append(s) source_sigs.append(s)
for t, s in zip(target_sigs, source_sigs): for t, s in zip(target_sigs, source_sigs):
assign_wire(t, s) if t in c.forks:
assert s not in c.forks, 'assignment between two driven signals'
Line(c, c.forks[t], Node(c, s))
elif s in c.forks:
assert t not in c.forks, 'assignment between two driven signals'
Line(c, c.forks[s], Node(c, t))
elif s.startswith("1'b"):
cnode = Node(c, f'__const{s[3]}_{const_count}__', f'__const{s[3]}__')
const_count += 1
Line(c, cnode, Node(c, t))
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():
@ -195,7 +207,7 @@ GRAMMAR = r"""
sigsel: name range? | concat sigsel: name range? | concat
concat: "{" sigsel ( "," sigsel )* "}" concat: "{" sigsel ( "," sigsel )* "}"
_namelist: name ( "," name )* _namelist: name ( "," name )*
name: ( /[a-z_][a-z0-9_]*/i | /\\[^\t \r\n]+[\t \r\n]/i | /1'b0/i | /1'b1/i ) name: ( /[a-z_][a-z0-9_]*/i | /\\[^\t \r\n]+[\t \r\n]/i | /[0-9]+'[bdh][0-9a-f]+/i )
%import common.NEWLINE %import common.NEWLINE
COMMENT: /\/\*(\*(?!\/)|[^*])*\*\// | /\(\*(\*(?!\))|[^*])*\*\)/ | "//" /(.)*/ NEWLINE COMMENT: /\/\*(\*(?!\/)|[^*])*\*\// | /\(\*(\*(?!\))|[^*])*\*\)/ | "//" /(.)*/ NEWLINE
%ignore ( /\r?\n/ | COMMENT )+ %ignore ( /\r?\n/ | COMMENT )+

Loading…
Cancel
Save