Skip to content

Commit

Permalink
litex/gen/fhdl: Move expression generation function to expression.py.
Browse files Browse the repository at this point in the history
  • Loading branch information
enjoy-digital committed Jan 14, 2025
1 parent 4933bcb commit 0bfaf39
Show file tree
Hide file tree
Showing 2 changed files with 151 additions and 139 deletions.
148 changes: 148 additions & 0 deletions litex/gen/fhdl/expression.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,148 @@
#
# This file is part of LiteX (Adapted from Migen for LiteX usage).
#
# This file is Copyright (c) 2013-2014 Sebastien Bourdeauducq <[email protected]>
# This file is Copyright (c) 2013-2023 Florent Kermarrec <[email protected]>
# SPDX-License-Identifier: BSD-2-Clause

from enum import IntEnum

from migen.fhdl.structure import *
from migen.fhdl.structure import _Operator, _Slice, _Assign, _Fragment

# ------------------------------------------------------------------------------------------------ #
# EXPRESSIONS #
# ------------------------------------------------------------------------------------------------ #

# Print Constant -----------------------------------------------------------------------------------

def _generate_constant(node):
return "{sign}{bits}'d{value}".format(
sign = "" if node.value >= 0 else "-",
bits = str(node.nbits),
value = abs(node.value),
), node.signed

# Print Signal -------------------------------------------------------------------------------------

def _generate_signal(ns, s):
length = 8
vector = f"[{str(len(s)-1)}:0] "
vector = " "*(length-len(vector)) + vector
return "{signed}{vector}{name}".format(
signed = " " if (not s.signed) else "signed ",
vector = " "*length if (len(s) <= 1) else vector,
name = ns.get_name(s)
)

# Print Operator -----------------------------------------------------------------------------------

class OperatorType(IntEnum):
UNARY = 1
BINARY = 2
TERNARY = 3

def _generate_operator(ns, node):
operator = node.op
operands = node.operands
arity = len(operands)
assert arity in [item.value for item in OperatorType]

def to_signed(r):
return f"$signed({{1'd0, {r}}})"

# Unary Operator.
if arity == OperatorType.UNARY:
r1, s1 = _generate_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 == OperatorType.BINARY:
r1, s1 = _generate_expression(ns, operands[0])
r2, s2 = _generate_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 == OperatorType.TERNARY:
assert operator == "m"
r1, s1 = _generate_expression(ns, operands[0])
r2, s2 = _generate_expression(ns, operands[1])
r3, s3 = _generate_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 _generate_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 = _generate_expression(ns, node.value)
return r + sr, s

# Print Cat ----------------------------------------------------------------------------------------

def _generate_cat(ns, node):
l = [_generate_expression(ns, v)[0] for v in reversed(node.l)]
return "{" + ", ".join(l) + "}", False

# Print Replicate ----------------------------------------------------------------------------------

def _generate_replicate(ns, node):
return "{" + str(node.n) + "{" + _generate_expression(ns, node.v)[0] + "}}", False

# Print Expression ---------------------------------------------------------------------------------

def _generate_expression(ns, node):
# Constant.
if isinstance(node, Constant):
return _generate_constant(node)

# Signal.
elif isinstance(node, Signal):
return ns.get_name(node), node.signed

# Operator.
elif isinstance(node, _Operator):
return _generate_operator(ns, node)

# Slice.
elif isinstance(node, _Slice):
return _generate_slice(ns, node)

# Cat.
elif isinstance(node, Cat):
return _generate_cat(ns, node)

# Replicate.
elif isinstance(node, Replicate):
return _generate_replicate(ns, node)

# Unknown.
else:
raise TypeError(f"Expression of unrecognized type: '{type(node).__name__}'")
142 changes: 3 additions & 139 deletions litex/gen/fhdl/verilog.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,9 @@
from migen.fhdl.specials import Instance, Memory

from litex.gen import LiteXContext
from litex.gen.fhdl.namer import build_signal_namespace
from litex.gen.fhdl.hierarchy import LiteXHierarchyExplorer
from litex.gen.fhdl.expression import _generate_expression, _generate_signal
from litex.gen.fhdl.namer import build_signal_namespace
from litex.gen.fhdl.hierarchy import LiteXHierarchyExplorer

from litex.build.tools import get_litex_git_revision

Expand Down Expand Up @@ -158,143 +159,6 @@ def _generate_hierarchy(top):
"wor", "xnor", "xor",
}

# ------------------------------------------------------------------------------------------------ #
# EXPRESSIONS #
# ------------------------------------------------------------------------------------------------ #

# Print Constant -----------------------------------------------------------------------------------

def _generate_constant(node):
return "{sign}{bits}'d{value}".format(
sign = "" if node.value >= 0 else "-",
bits = str(node.nbits),
value = abs(node.value),
), node.signed

# Print Signal -------------------------------------------------------------------------------------

def _generate_signal(ns, s):
length = 8
vector = f"[{str(len(s)-1)}:0] "
vector = " "*(length-len(vector)) + vector
return "{signed}{vector}{name}".format(
signed = " " if (not s.signed) else "signed ",
vector = " "*length if (len(s) <= 1) else vector,
name = ns.get_name(s)
)

# Print Operator -----------------------------------------------------------------------------------

class OperatorType(IntEnum):
UNARY = 1
BINARY = 2
TERNARY = 3

def _generate_operator(ns, node):
operator = node.op
operands = node.operands
arity = len(operands)
assert arity in [item.value for item in OperatorType]

def to_signed(r):
return f"$signed({{1'd0, {r}}})"

# Unary Operator.
if arity == OperatorType.UNARY:
r1, s1 = _generate_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 == OperatorType.BINARY:
r1, s1 = _generate_expression(ns, operands[0])
r2, s2 = _generate_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 == OperatorType.TERNARY:
assert operator == "m"
r1, s1 = _generate_expression(ns, operands[0])
r2, s2 = _generate_expression(ns, operands[1])
r3, s3 = _generate_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 _generate_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 = _generate_expression(ns, node.value)
return r + sr, s

# Print Cat ----------------------------------------------------------------------------------------

def _generate_cat(ns, node):
l = [_generate_expression(ns, v)[0] for v in reversed(node.l)]
return "{" + ", ".join(l) + "}", False

# Print Replicate ----------------------------------------------------------------------------------

def _generate_replicate(ns, node):
return "{" + str(node.n) + "{" + _generate_expression(ns, node.v)[0] + "}}", False

# Print Expression ---------------------------------------------------------------------------------

def _generate_expression(ns, node):
# Constant.
if isinstance(node, Constant):
return _generate_constant(node)

# Signal.
elif isinstance(node, Signal):
return ns.get_name(node), node.signed

# Operator.
elif isinstance(node, _Operator):
return _generate_operator(ns, node)

# Slice.
elif isinstance(node, _Slice):
return _generate_slice(ns, node)

# Cat.
elif isinstance(node, Cat):
return _generate_cat(ns, node)

# Replicate.
elif isinstance(node, Replicate):
return _generate_replicate(ns, node)

# Unknown.
else:
raise TypeError(f"Expression of unrecognized type: '{type(node).__name__}'")

# ------------------------------------------------------------------------------------------------ #
# NODES #
# ------------------------------------------------------------------------------------------------ #
Expand Down

0 comments on commit 0bfaf39

Please sign in to comment.