Skip to content
Permalink

Comparing changes

Choose two branches to see what’s changed or to start a new pull request. If you need to, you can also or learn more about diff comparisons.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also . Learn more about diff comparisons here.
base repository: m-labs/nmigen
Failed to load repositories. Confirm that selected base ref is valid, then try again.
Loading
base: 7ff4c6ce4314
Choose a base ref
...
head repository: m-labs/nmigen
Failed to load repositories. Confirm that selected head ref is valid, then try again.
Loading
compare: fa1e466a6545
Choose a head ref
  • 1 commit
  • 4 files changed
  • 1 contributor

Commits on Oct 11, 2019

  1. hdl.ast: Operator.{op→operator}

    Both "operator" and "operand" were shortened to "op" in different
    places in code, which caused confusion.
    whitequark committed Oct 11, 2019
    Copy the full SHA
    fa1e466 View commit details
Showing with 72 additions and 66 deletions.
  1. +23 −23 nmigen/back/pysim.py
  2. +5 −5 nmigen/back/rtlil.py
  3. +43 −37 nmigen/hdl/ast.py
  4. +1 −1 nmigen/hdl/xfrm.py
46 changes: 23 additions & 23 deletions nmigen/back/pysim.py
Original file line number Diff line number Diff line change
@@ -123,64 +123,64 @@ def on_Operator(self, value):
shape = value.shape()
if len(value.operands) == 1:
arg, = map(self, value.operands)
if value.op == "~":
if value.operator == "~":
return lambda state: normalize(~arg(state), shape)
if value.op == "-":
if value.operator == "-":
return lambda state: normalize(-arg(state), shape)
if value.op == "b":
if value.operator == "b":
return lambda state: normalize(bool(arg(state)), shape)
if value.op == "r|":
if value.operator == "r|":
return lambda state: normalize(arg(state) != 0, shape)
if value.op == "r&":
if value.operator == "r&":
val, = value.operands
mask = (1 << len(val)) - 1
return lambda state: normalize(arg(state) == mask, shape)
if value.op == "r^":
if value.operator == "r^":
# Believe it or not, this is the fastest way to compute a sideways XOR in Python.
return lambda state: normalize(format(arg(state), "b").count("1") % 2, shape)
elif len(value.operands) == 2:
lhs, rhs = map(self, value.operands)
if value.op == "+":
if value.operator == "+":
return lambda state: normalize(lhs(state) + rhs(state), shape)
if value.op == "-":
if value.operator == "-":
return lambda state: normalize(lhs(state) - rhs(state), shape)
if value.op == "*":
if value.operator == "*":
return lambda state: normalize(lhs(state) * rhs(state), shape)
if value.op == "//":
if value.operator == "//":
def floordiv(lhs, rhs):
return 0 if rhs == 0 else lhs // rhs
return lambda state: normalize(floordiv(lhs(state), rhs(state)), shape)
if value.op == "&":
if value.operator == "&":
return lambda state: normalize(lhs(state) & rhs(state), shape)
if value.op == "|":
if value.operator == "|":
return lambda state: normalize(lhs(state) | rhs(state), shape)
if value.op == "^":
if value.operator == "^":
return lambda state: normalize(lhs(state) ^ rhs(state), shape)
if value.op == "<<":
if value.operator == "<<":
def sshl(lhs, rhs):
return lhs << rhs if rhs >= 0 else lhs >> -rhs
return lambda state: normalize(sshl(lhs(state), rhs(state)), shape)
if value.op == ">>":
if value.operator == ">>":
def sshr(lhs, rhs):
return lhs >> rhs if rhs >= 0 else lhs << -rhs
return lambda state: normalize(sshr(lhs(state), rhs(state)), shape)
if value.op == "==":
if value.operator == "==":
return lambda state: normalize(lhs(state) == rhs(state), shape)
if value.op == "!=":
if value.operator == "!=":
return lambda state: normalize(lhs(state) != rhs(state), shape)
if value.op == "<":
if value.operator == "<":
return lambda state: normalize(lhs(state) < rhs(state), shape)
if value.op == "<=":
if value.operator == "<=":
return lambda state: normalize(lhs(state) <= rhs(state), shape)
if value.op == ">":
if value.operator == ">":
return lambda state: normalize(lhs(state) > rhs(state), shape)
if value.op == ">=":
if value.operator == ">=":
return lambda state: normalize(lhs(state) >= rhs(state), shape)
elif len(value.operands) == 3:
if value.op == "m":
if value.operator == "m":
sel, val1, val0 = map(self, value.operands)
return lambda state: val1(state) if sel(state) else val0(state)
raise NotImplementedError("Operator '{}' not implemented".format(value.op)) # :nocov:
raise NotImplementedError("Operator '{}' not implemented".format(value.operator)) # :nocov:

def on_Slice(self, value):
shape = value.shape()
10 changes: 5 additions & 5 deletions nmigen/back/rtlil.py
Original file line number Diff line number Diff line change
@@ -452,7 +452,7 @@ def on_Operator_unary(self, value):
arg_bits, arg_sign = arg.shape()
res_bits, res_sign = value.shape()
res = self.s.rtlil.wire(width=res_bits, src=src(value.src_loc))
self.s.rtlil.cell(self.operator_map[(1, value.op)], ports={
self.s.rtlil.cell(self.operator_map[(1, value.operator)], ports={
"\\A": self(arg),
"\\Y": res,
}, params={
@@ -485,7 +485,7 @@ def on_Operator_binary(self, value):
lhs, rhs = value.operands
lhs_bits, lhs_sign = lhs.shape()
rhs_bits, rhs_sign = rhs.shape()
if lhs_sign == rhs_sign or value.op in ("<<", ">>", "**"):
if lhs_sign == rhs_sign or value.operator in ("<<", ">>", "**"):
lhs_wire = self(lhs)
rhs_wire = self(rhs)
else:
@@ -494,7 +494,7 @@ def on_Operator_binary(self, value):
rhs_wire = self.match_shape(rhs, rhs_bits, rhs_sign)
res_bits, res_sign = value.shape()
res = self.s.rtlil.wire(width=res_bits, src=src(value.src_loc))
self.s.rtlil.cell(self.operator_map[(2, value.op)], ports={
self.s.rtlil.cell(self.operator_map[(2, value.operator)], ports={
"\\A": lhs_wire,
"\\B": rhs_wire,
"\\Y": res,
@@ -505,7 +505,7 @@ def on_Operator_binary(self, value):
"B_WIDTH": rhs_bits,
"Y_WIDTH": res_bits,
}, src=src(value.src_loc))
if value.op in ("//", "%"):
if value.operator in ("//", "%"):
# RTLIL leaves division by zero undefined, but we require it to return zero.
divmod_res = res
res = self.s.rtlil.wire(width=res_bits, src=src(value.src_loc))
@@ -544,7 +544,7 @@ def on_Operator(self, value):
elif len(value.operands) == 2:
return self.on_Operator_binary(value)
elif len(value.operands) == 3:
assert value.op == "m"
assert value.operator == "m"
return self.on_Operator_mux(value)
else:
raise TypeError # :nocov:
80 changes: 43 additions & 37 deletions nmigen/hdl/ast.py
Original file line number Diff line number Diff line change
@@ -453,79 +453,84 @@ def __repr__(self):

@final
class Operator(Value):
def __init__(self, op, operands, *, src_loc_at=0):
def __init__(self, operator, operands, *, src_loc_at=0):
super().__init__(src_loc_at=1 + src_loc_at)
self.op = op
self.operands = [Value.cast(o) for o in operands]
self.operator = operator
self.operands = [Value.cast(op) for op in operands]

@staticmethod
def _bitwise_binary_shape(a_shape, b_shape):
a_bits, a_sign = a_shape
b_bits, b_sign = b_shape
if not a_sign and not b_sign:
# both operands unsigned
return max(a_bits, b_bits), False
elif a_sign and b_sign:
# both operands signed
return max(a_bits, b_bits), True
elif not a_sign and b_sign:
# first operand unsigned (add sign bit), second operand signed
return max(a_bits + 1, b_bits), True
else:
# first signed, second operand unsigned (add sign bit)
return max(a_bits, b_bits + 1), True
# TODO(nmigen-0.2): move this to nmigen.compat and make it a deprecated extension
@property
@deprecated("instead of `.op`, use `.operator`")
def op(self):
return self.operator

def shape(self):
def _bitwise_binary_shape(a_shape, b_shape):
a_bits, a_sign = a_shape
b_bits, b_sign = b_shape
if not a_sign and not b_sign:
# both operands unsigned
return max(a_bits, b_bits), False
elif a_sign and b_sign:
# both operands signed
return max(a_bits, b_bits), True
elif not a_sign and b_sign:
# first operand unsigned (add sign bit), second operand signed
return max(a_bits + 1, b_bits), True
else:
# first signed, second operand unsigned (add sign bit)
return max(a_bits, b_bits + 1), True

op_shapes = list(map(lambda x: x.shape(), self.operands))
if len(op_shapes) == 1:
(a_width, a_signed), = op_shapes
if self.op in ("+", "~"):
if self.operator in ("+", "~"):
return a_width, a_signed
if self.op == "-":
if self.operator == "-":
if not a_signed:
return a_width + 1, True
else:
return a_width, a_signed
if self.op in ("b", "r|", "r&", "r^"):
if self.operator in ("b", "r|", "r&", "r^"):
return 1, False
elif len(op_shapes) == 2:
(a_width, a_signed), (b_width, b_signed) = op_shapes
if self.op == "+" or self.op == "-":
width, signed = self._bitwise_binary_shape(*op_shapes)
if self.operator == "+" or self.operator == "-":
width, signed = _bitwise_binary_shape(*op_shapes)
return width + 1, signed
if self.op == "*":
if self.operator == "*":
return a_width + b_width, a_signed or b_signed
if self.op in ("//", "%"):
if self.operator in ("//", "%"):
assert not b_signed
return a_width, a_signed
if self.op in ("<", "<=", "==", "!=", ">", ">="):
if self.operator in ("<", "<=", "==", "!=", ">", ">="):
return 1, False
if self.op in ("&", "^", "|"):
return self._bitwise_binary_shape(*op_shapes)
if self.op == "<<":
if self.operator in ("&", "^", "|"):
return _bitwise_binary_shape(*op_shapes)
if self.operator == "<<":
if b_signed:
extra = 2 ** (b_width - 1) - 1
else:
extra = 2 ** (b_width) - 1
return a_width + extra, a_signed
if self.op == ">>":
if self.operator == ">>":
if b_signed:
extra = 2 ** (b_width - 1)
else:
extra = 0
return a_width + extra, a_signed
elif len(op_shapes) == 3:
if self.op == "m":
if self.operator == "m":
s_shape, a_shape, b_shape = op_shapes
return self._bitwise_binary_shape(a_shape, b_shape)
return _bitwise_binary_shape(a_shape, b_shape)
raise NotImplementedError("Operator {}/{} not implemented"
.format(self.op, len(op_shapes))) # :nocov:
.format(self.operator, len(op_shapes))) # :nocov:

def _rhs_signals(self):
return union(op._rhs_signals() for op in self.operands)

def __repr__(self):
return "({} {})".format(self.op, " ".join(map(repr, self.operands)))
return "({} {})".format(self.operator, " ".join(map(repr, self.operands)))


def Mux(sel, val1, val0):
@@ -1478,7 +1483,8 @@ def __init__(self, value):
elif isinstance(self.value, (ClockSignal, ResetSignal)):
self._hash = hash(self.value.domain)
elif isinstance(self.value, Operator):
self._hash = hash((self.value.op, tuple(ValueKey(o) for o in self.value.operands)))
self._hash = hash((self.value.operator,
tuple(ValueKey(o) for o in self.value.operands)))
elif isinstance(self.value, Slice):
self._hash = hash((ValueKey(self.value.value), self.value.start, self.value.end))
elif isinstance(self.value, Part):
@@ -1513,7 +1519,7 @@ def __eq__(self, other):
elif isinstance(self.value, (ClockSignal, ResetSignal)):
return self.value.domain == other.value.domain
elif isinstance(self.value, Operator):
return (self.value.op == other.value.op and
return (self.value.operator == other.value.operator and
len(self.value.operands) == len(other.value.operands) and
all(ValueKey(a) == ValueKey(b)
for a, b in zip(self.value.operands, other.value.operands)))
2 changes: 1 addition & 1 deletion nmigen/hdl/xfrm.py
Original file line number Diff line number Diff line change
@@ -157,7 +157,7 @@ def on_ResetSignal(self, value):
return value

def on_Operator(self, value):
return Operator(value.op, [self.on_value(o) for o in value.operands])
return Operator(value.operator, [self.on_value(o) for o in value.operands])

def on_Slice(self, value):
return Slice(self.on_value(value.value), value.start, value.end)