fhdl/verilog: Create _print_operator/_print_slice, move code outside _print_expression and cleanup/simplify.

This commit is contained in:
Florent Kermarrec 2021-10-15 13:33:09 +02:00
parent cdfb8d141a
commit 2c98ad94b5
1 changed files with 69 additions and 46 deletions

View File

@ -100,6 +100,73 @@ def _print_constant(node):
value = abs(node.value),
), node.signed
# Print Operator -----------------------------------------------------------------------------------
(UNARY, BINARY, TERNARY) = (1, 2, 3)
def _print_operator(ns, node):
operator = node.op
operands = node.operands
arity = len(operands)
assert arity in [UNARY, BINARY, TERNARY]
def to_signed(r):
return f"$signed({{1'd0 {r}}}))"
# Unary Operator.
if arity == UNARY:
r1, s1 = _print_expression(ns, operands[0])
# Negation Operator.
if operator == "-":
# Negate and convert to signed if not already.
r = "-" + (r1 if s1 else to_signed(r1))
s = True
# Other Operators.
else:
r = operator + r1
s = s1
# Binary Operator.
if arity == BINARY:
r1, s1 = _print_expression(ns, operands[0])
r2, s2 = _print_expression(ns, operands[1])
# Convert all expressions to signed when at least one is signed.
if operator not in ["<<<", ">>>"]:
if s2 and not s1:
r1 = to_signed(r1)
if s1 and not s2:
r2 = to_signed(r2)
r = f"{r1} {operator} {r2}"
s = s1 or s2
# Ternary Operator.
if arity == TERNARY:
assert operator == "m"
r1, s1 = _print_expression(ns, operands[0])
r2, s2 = _print_expression(ns, operands[1])
r3, s3 = _print_expression(ns, operands[2])
# Convert all expressions to signed when at least one is signed.
if s2 and not s3:
r3 = to_signed(r3)
if s3 and not s2:
r2 = to_signed(r2)
r = f"{r1} ? {r2} : {r3}"
s = s2 or s3
return f"({r})", s
# Print Slice --------------------------------------------------------------------------------------
def _print_slice(ns, node):
assert (node.stop - node.start) >= 1
if (isinstance(node.value, Signal) and len(node.value) == 1):
assert node.start == 0
sr = "" # Avoid slicing 1-bit Signals.
else:
sr = f"[{node.stop-1}:{node.start}]" if (node.stop - node.start) > 1 else f"[{node.start}]"
r, s = _print_expression(ns, node.value)
return r + sr, s
# Print Expression ---------------------------------------------------------------------------------
def _print_expression(ns, node):
@ -113,55 +180,11 @@ def _print_expression(ns, node):
# Operator.
elif isinstance(node, _Operator):
arity = len(node.operands)
r1, s1 = _print_expression(ns, node.operands[0])
if arity == 1:
if node.op == "-":
if s1:
r = node.op + r1
else:
r = "-$signed({1'd0, " + r1 + "})"
s = True
else:
r = node.op + r1
s = s1
elif arity == 2:
r2, s2 = _print_expression(ns, node.operands[1])
if node.op not in ["<<<", ">>>"]:
if s2 and not s1:
r1 = "$signed({1'd0, " + r1 + "})"
if s1 and not s2:
r2 = "$signed({1'd0, " + r2 + "})"
r = r1 + " " + node.op + " " + r2
s = s1 or s2
elif arity == 3:
assert node.op == "m"
r2, s2 = _print_expression(ns, node.operands[1])
r3, s3 = _print_expression(ns, node.operands[2])
if s2 and not s3:
r3 = "$signed({1'd0, " + r3 + "})"
if s3 and not s2:
r2 = "$signed({1'd0, " + r2 + "})"
r = r1 + " ? " + r2 + " : " + r3
s = s2 or s3
else:
raise TypeError
return "(" + r + ")", s
return _print_operator(ns, node)
# Slice.
elif isinstance(node, _Slice):
# Verilog does not like us slicing non-array signals...
if (isinstance(node.value, Signal) and
len(node.value) == 1 and
node.start == 0 and node.stop == 1):
return _print_expression(ns, node.value)
if node.start + 1 == node.stop:
sr = "[" + str(node.start) + "]"
else:
sr = "[" + str(node.stop-1) + ":" + str(node.start) + "]"
r, s = _print_expression(ns, node.value)
return r + sr, s
return _print_slice(ns, node)
# Cat.
elif isinstance(node, Cat):