hdl.ast: Operator.{op→operator}

Both "operator" and "operand" were shortened to "op" in different
places in code, which caused confusion.
This commit is contained in:
whitequark 2019-10-11 11:37:26 +00:00
parent 7ff4c6ce43
commit fa1e466a65
4 changed files with 72 additions and 66 deletions

View file

@ -123,64 +123,64 @@ class _RHSValueCompiler(_ValueCompiler):
shape = value.shape() shape = value.shape()
if len(value.operands) == 1: if len(value.operands) == 1:
arg, = map(self, value.operands) arg, = map(self, value.operands)
if value.op == "~": if value.operator == "~":
return lambda state: normalize(~arg(state), shape) return lambda state: normalize(~arg(state), shape)
if value.op == "-": if value.operator == "-":
return lambda state: normalize(-arg(state), shape) return lambda state: normalize(-arg(state), shape)
if value.op == "b": if value.operator == "b":
return lambda state: normalize(bool(arg(state)), shape) return lambda state: normalize(bool(arg(state)), shape)
if value.op == "r|": if value.operator == "r|":
return lambda state: normalize(arg(state) != 0, shape) return lambda state: normalize(arg(state) != 0, shape)
if value.op == "r&": if value.operator == "r&":
val, = value.operands val, = value.operands
mask = (1 << len(val)) - 1 mask = (1 << len(val)) - 1
return lambda state: normalize(arg(state) == mask, shape) 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. # 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) return lambda state: normalize(format(arg(state), "b").count("1") % 2, shape)
elif len(value.operands) == 2: elif len(value.operands) == 2:
lhs, rhs = map(self, value.operands) lhs, rhs = map(self, value.operands)
if value.op == "+": if value.operator == "+":
return lambda state: normalize(lhs(state) + rhs(state), shape) return lambda state: normalize(lhs(state) + rhs(state), shape)
if value.op == "-": if value.operator == "-":
return lambda state: normalize(lhs(state) - rhs(state), shape) return lambda state: normalize(lhs(state) - rhs(state), shape)
if value.op == "*": if value.operator == "*":
return lambda state: normalize(lhs(state) * rhs(state), shape) return lambda state: normalize(lhs(state) * rhs(state), shape)
if value.op == "//": if value.operator == "//":
def floordiv(lhs, rhs): def floordiv(lhs, rhs):
return 0 if rhs == 0 else lhs // rhs return 0 if rhs == 0 else lhs // rhs
return lambda state: normalize(floordiv(lhs(state), rhs(state)), shape) 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) return lambda state: normalize(lhs(state) & rhs(state), shape)
if value.op == "|": if value.operator == "|":
return lambda state: normalize(lhs(state) | rhs(state), shape) return lambda state: normalize(lhs(state) | rhs(state), shape)
if value.op == "^": if value.operator == "^":
return lambda state: normalize(lhs(state) ^ rhs(state), shape) return lambda state: normalize(lhs(state) ^ rhs(state), shape)
if value.op == "<<": if value.operator == "<<":
def sshl(lhs, rhs): def sshl(lhs, rhs):
return lhs << rhs if rhs >= 0 else lhs >> -rhs return lhs << rhs if rhs >= 0 else lhs >> -rhs
return lambda state: normalize(sshl(lhs(state), rhs(state)), shape) return lambda state: normalize(sshl(lhs(state), rhs(state)), shape)
if value.op == ">>": if value.operator == ">>":
def sshr(lhs, rhs): def sshr(lhs, rhs):
return lhs >> rhs if rhs >= 0 else lhs << -rhs return lhs >> rhs if rhs >= 0 else lhs << -rhs
return lambda state: normalize(sshr(lhs(state), rhs(state)), shape) 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) return lambda state: normalize(lhs(state) == rhs(state), shape)
if value.op == "!=": if value.operator == "!=":
return lambda state: normalize(lhs(state) != rhs(state), shape) return lambda state: normalize(lhs(state) != rhs(state), shape)
if value.op == "<": if value.operator == "<":
return lambda state: normalize(lhs(state) < rhs(state), shape) return lambda state: normalize(lhs(state) < rhs(state), shape)
if value.op == "<=": if value.operator == "<=":
return lambda state: normalize(lhs(state) <= rhs(state), shape) return lambda state: normalize(lhs(state) <= rhs(state), shape)
if value.op == ">": if value.operator == ">":
return lambda state: normalize(lhs(state) > rhs(state), shape) return lambda state: normalize(lhs(state) > rhs(state), shape)
if value.op == ">=": if value.operator == ">=":
return lambda state: normalize(lhs(state) >= rhs(state), shape) return lambda state: normalize(lhs(state) >= rhs(state), shape)
elif len(value.operands) == 3: elif len(value.operands) == 3:
if value.op == "m": if value.operator == "m":
sel, val1, val0 = map(self, value.operands) sel, val1, val0 = map(self, value.operands)
return lambda state: val1(state) if sel(state) else val0(state) 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): def on_Slice(self, value):
shape = value.shape() shape = value.shape()

View file

@ -452,7 +452,7 @@ class _RHSValueCompiler(_ValueCompiler):
arg_bits, arg_sign = arg.shape() arg_bits, arg_sign = arg.shape()
res_bits, res_sign = value.shape() res_bits, res_sign = value.shape()
res = self.s.rtlil.wire(width=res_bits, src=src(value.src_loc)) 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), "\\A": self(arg),
"\\Y": res, "\\Y": res,
}, params={ }, params={
@ -485,7 +485,7 @@ class _RHSValueCompiler(_ValueCompiler):
lhs, rhs = value.operands lhs, rhs = value.operands
lhs_bits, lhs_sign = lhs.shape() lhs_bits, lhs_sign = lhs.shape()
rhs_bits, rhs_sign = rhs.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) lhs_wire = self(lhs)
rhs_wire = self(rhs) rhs_wire = self(rhs)
else: else:
@ -494,7 +494,7 @@ class _RHSValueCompiler(_ValueCompiler):
rhs_wire = self.match_shape(rhs, rhs_bits, rhs_sign) rhs_wire = self.match_shape(rhs, rhs_bits, rhs_sign)
res_bits, res_sign = value.shape() res_bits, res_sign = value.shape()
res = self.s.rtlil.wire(width=res_bits, src=src(value.src_loc)) 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, "\\A": lhs_wire,
"\\B": rhs_wire, "\\B": rhs_wire,
"\\Y": res, "\\Y": res,
@ -505,7 +505,7 @@ class _RHSValueCompiler(_ValueCompiler):
"B_WIDTH": rhs_bits, "B_WIDTH": rhs_bits,
"Y_WIDTH": res_bits, "Y_WIDTH": res_bits,
}, src=src(value.src_loc)) }, 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. # RTLIL leaves division by zero undefined, but we require it to return zero.
divmod_res = res divmod_res = res
res = self.s.rtlil.wire(width=res_bits, src=src(value.src_loc)) res = self.s.rtlil.wire(width=res_bits, src=src(value.src_loc))
@ -544,7 +544,7 @@ class _RHSValueCompiler(_ValueCompiler):
elif len(value.operands) == 2: elif len(value.operands) == 2:
return self.on_Operator_binary(value) return self.on_Operator_binary(value)
elif len(value.operands) == 3: elif len(value.operands) == 3:
assert value.op == "m" assert value.operator == "m"
return self.on_Operator_mux(value) return self.on_Operator_mux(value)
else: else:
raise TypeError # :nocov: raise TypeError # :nocov:

View file

@ -453,79 +453,84 @@ class AnySeq(AnyValue):
@final @final
class Operator(Value): 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) super().__init__(src_loc_at=1 + src_loc_at)
self.op = op self.operator = operator
self.operands = [Value.cast(o) for o in operands] self.operands = [Value.cast(op) for op in operands]
@staticmethod # TODO(nmigen-0.2): move this to nmigen.compat and make it a deprecated extension
def _bitwise_binary_shape(a_shape, b_shape): @property
a_bits, a_sign = a_shape @deprecated("instead of `.op`, use `.operator`")
b_bits, b_sign = b_shape def op(self):
if not a_sign and not b_sign: return self.operator
# 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
def shape(self): 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)) op_shapes = list(map(lambda x: x.shape(), self.operands))
if len(op_shapes) == 1: if len(op_shapes) == 1:
(a_width, a_signed), = op_shapes (a_width, a_signed), = op_shapes
if self.op in ("+", "~"): if self.operator in ("+", "~"):
return a_width, a_signed return a_width, a_signed
if self.op == "-": if self.operator == "-":
if not a_signed: if not a_signed:
return a_width + 1, True return a_width + 1, True
else: else:
return a_width, a_signed return a_width, a_signed
if self.op in ("b", "r|", "r&", "r^"): if self.operator in ("b", "r|", "r&", "r^"):
return 1, False return 1, False
elif len(op_shapes) == 2: elif len(op_shapes) == 2:
(a_width, a_signed), (b_width, b_signed) = op_shapes (a_width, a_signed), (b_width, b_signed) = op_shapes
if self.op == "+" or self.op == "-": if self.operator == "+" or self.operator == "-":
width, signed = self._bitwise_binary_shape(*op_shapes) width, signed = _bitwise_binary_shape(*op_shapes)
return width + 1, signed return width + 1, signed
if self.op == "*": if self.operator == "*":
return a_width + b_width, a_signed or b_signed return a_width + b_width, a_signed or b_signed
if self.op in ("//", "%"): if self.operator in ("//", "%"):
assert not b_signed assert not b_signed
return a_width, a_signed return a_width, a_signed
if self.op in ("<", "<=", "==", "!=", ">", ">="): if self.operator in ("<", "<=", "==", "!=", ">", ">="):
return 1, False return 1, False
if self.op in ("&", "^", "|"): if self.operator in ("&", "^", "|"):
return self._bitwise_binary_shape(*op_shapes) return _bitwise_binary_shape(*op_shapes)
if self.op == "<<": if self.operator == "<<":
if b_signed: if b_signed:
extra = 2 ** (b_width - 1) - 1 extra = 2 ** (b_width - 1) - 1
else: else:
extra = 2 ** (b_width) - 1 extra = 2 ** (b_width) - 1
return a_width + extra, a_signed return a_width + extra, a_signed
if self.op == ">>": if self.operator == ">>":
if b_signed: if b_signed:
extra = 2 ** (b_width - 1) extra = 2 ** (b_width - 1)
else: else:
extra = 0 extra = 0
return a_width + extra, a_signed return a_width + extra, a_signed
elif len(op_shapes) == 3: elif len(op_shapes) == 3:
if self.op == "m": if self.operator == "m":
s_shape, a_shape, b_shape = op_shapes 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" raise NotImplementedError("Operator {}/{} not implemented"
.format(self.op, len(op_shapes))) # :nocov: .format(self.operator, len(op_shapes))) # :nocov:
def _rhs_signals(self): def _rhs_signals(self):
return union(op._rhs_signals() for op in self.operands) return union(op._rhs_signals() for op in self.operands)
def __repr__(self): 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): def Mux(sel, val1, val0):
@ -1478,7 +1483,8 @@ class ValueKey:
elif isinstance(self.value, (ClockSignal, ResetSignal)): elif isinstance(self.value, (ClockSignal, ResetSignal)):
self._hash = hash(self.value.domain) self._hash = hash(self.value.domain)
elif isinstance(self.value, Operator): 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): elif isinstance(self.value, Slice):
self._hash = hash((ValueKey(self.value.value), self.value.start, self.value.end)) self._hash = hash((ValueKey(self.value.value), self.value.start, self.value.end))
elif isinstance(self.value, Part): elif isinstance(self.value, Part):
@ -1513,7 +1519,7 @@ class ValueKey:
elif isinstance(self.value, (ClockSignal, ResetSignal)): elif isinstance(self.value, (ClockSignal, ResetSignal)):
return self.value.domain == other.value.domain return self.value.domain == other.value.domain
elif isinstance(self.value, Operator): 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 len(self.value.operands) == len(other.value.operands) and
all(ValueKey(a) == ValueKey(b) all(ValueKey(a) == ValueKey(b)
for a, b in zip(self.value.operands, other.value.operands))) for a, b in zip(self.value.operands, other.value.operands)))

View file

@ -157,7 +157,7 @@ class ValueTransformer(ValueVisitor):
return value return value
def on_Operator(self, 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): def on_Slice(self, value):
return Slice(self.on_value(value.value), value.start, value.end) return Slice(self.on_value(value.value), value.start, value.end)