186 lines
5.9 KiB
Python
186 lines
5.9 KiB
Python
import builtins
|
|
import warnings
|
|
from collections import OrderedDict
|
|
|
|
from ...utils import bits_for
|
|
from ..._utils import deprecated, extend
|
|
from ...hdl import ast
|
|
from ...hdl.ast import (DUID,
|
|
Shape, signed, unsigned,
|
|
Value, Const, C, Mux, Slice as _Slice, Part, Cat, Repl,
|
|
Signal as NativeSignal,
|
|
ClockSignal, ResetSignal,
|
|
Array, ArrayProxy as _ArrayProxy)
|
|
from ...hdl.cd import ClockDomain
|
|
|
|
|
|
__all__ = ["DUID", "wrap", "Mux", "Cat", "Replicate", "Constant", "C", "Signal", "ClockSignal",
|
|
"ResetSignal", "If", "Case", "Array", "ClockDomain"]
|
|
|
|
|
|
@deprecated("instead of `wrap`, use `Value.cast`")
|
|
def wrap(v):
|
|
return Value.cast(v)
|
|
|
|
|
|
class CompatSignal(NativeSignal):
|
|
def __init__(self, bits_sign=None, name=None, variable=False, reset=0,
|
|
reset_less=False, name_override=None, min=None, max=None,
|
|
related=None, attr=None, src_loc_at=0, **kwargs):
|
|
if min is not None or max is not None:
|
|
warnings.warn("instead of `Signal(min={min}, max={max})`, "
|
|
"use `Signal(range({min}, {max}))`"
|
|
.format(min=min or 0, max=max or 2),
|
|
DeprecationWarning, stacklevel=2 + src_loc_at)
|
|
|
|
if bits_sign is None:
|
|
if min is None:
|
|
min = 0
|
|
if max is None:
|
|
max = 2
|
|
max -= 1 # make both bounds inclusive
|
|
if min > max:
|
|
raise ValueError("Lower bound {} should be less or equal to higher bound {}"
|
|
.format(min, max + 1))
|
|
sign = min < 0 or max < 0
|
|
if min == max:
|
|
bits = 0
|
|
else:
|
|
bits = builtins.max(bits_for(min, sign), bits_for(max, sign))
|
|
shape = signed(bits) if sign else unsigned(bits)
|
|
else:
|
|
if not (min is None and max is None):
|
|
raise ValueError("Only one of bits/signedness or bounds may be specified")
|
|
shape = bits_sign
|
|
|
|
super().__init__(shape=shape, name=name_override or name,
|
|
reset=reset, reset_less=reset_less,
|
|
attrs=attr, src_loc_at=1 + src_loc_at, **kwargs)
|
|
|
|
|
|
Signal = CompatSignal
|
|
|
|
|
|
@deprecated("instead of `Constant`, use `Const`")
|
|
def Constant(value, bits_sign=None):
|
|
return Const(value, bits_sign)
|
|
|
|
|
|
@deprecated("instead of `Replicate`, use `Repl`")
|
|
def Replicate(v, n):
|
|
return Repl(v, n)
|
|
|
|
|
|
@extend(Const)
|
|
@property
|
|
@deprecated("instead of `.nbits`, use `.width`")
|
|
def nbits(self):
|
|
return self.width
|
|
|
|
|
|
@extend(NativeSignal)
|
|
@property
|
|
@deprecated("instead of `.nbits`, use `.width`")
|
|
def nbits(self):
|
|
return self.width
|
|
|
|
|
|
@extend(NativeSignal)
|
|
@NativeSignal.nbits.setter
|
|
@deprecated("instead of `.nbits = x`, use `.width = x`")
|
|
def nbits(self, value):
|
|
self.width = value
|
|
|
|
|
|
@extend(NativeSignal)
|
|
@deprecated("instead of `.part`, use `.bit_select`")
|
|
def part(self, offset, width):
|
|
return Part(self, offset, width, src_loc_at=2)
|
|
|
|
|
|
@extend(Cat)
|
|
@property
|
|
@deprecated("instead of `.l`, use `.parts`")
|
|
def l(self):
|
|
return self.parts
|
|
|
|
|
|
@extend(ast.Operator)
|
|
@property
|
|
@deprecated("instead of `.op`, use `.operator`")
|
|
def op(self):
|
|
return self.operator
|
|
|
|
|
|
@extend(_ArrayProxy)
|
|
@property
|
|
@deprecated("instead `_ArrayProxy.choices`, use `ArrayProxy.elems`")
|
|
def choices(self):
|
|
return self.elems
|
|
|
|
|
|
class If(ast.Switch):
|
|
@deprecated("instead of `If(cond, ...)`, use `with m.If(cond): ...`")
|
|
def __init__(self, cond, *stmts):
|
|
cond = Value.cast(cond)
|
|
if len(cond) != 1:
|
|
cond = cond.bool()
|
|
super().__init__(cond, {("1",): ast.Statement.cast(stmts)})
|
|
|
|
@deprecated("instead of `.Elif(cond, ...)`, use `with m.Elif(cond): ...`")
|
|
def Elif(self, cond, *stmts):
|
|
cond = Value.cast(cond)
|
|
if len(cond) != 1:
|
|
cond = cond.bool()
|
|
self.cases = OrderedDict((("-" + k,), v) for (k,), v in self.cases.items())
|
|
self.cases[("1" + "-" * len(self.test),)] = ast.Statement.cast(stmts)
|
|
self.test = Cat(self.test, cond)
|
|
return self
|
|
|
|
@deprecated("instead of `.Else(...)`, use `with m.Else(): ...`")
|
|
def Else(self, *stmts):
|
|
self.cases[()] = ast.Statement.cast(stmts)
|
|
return self
|
|
|
|
|
|
class Case(ast.Switch):
|
|
@deprecated("instead of `Case(test, { value: stmts })`, use `with m.Switch(test):` and "
|
|
"`with m.Case(value): stmts`; instead of `\"default\": stmts`, use "
|
|
"`with m.Case(): stmts`")
|
|
def __init__(self, test, cases):
|
|
new_cases = []
|
|
default = None
|
|
for k, v in cases.items():
|
|
if isinstance(k, (bool, int)):
|
|
k = Const(k)
|
|
if (not isinstance(k, Const)
|
|
and not (isinstance(k, str) and k == "default")):
|
|
raise TypeError("Case object is not a Migen constant")
|
|
if isinstance(k, str) and k == "default":
|
|
default = v
|
|
continue
|
|
else:
|
|
k = k.value
|
|
new_cases.append((k, v))
|
|
if default is not None:
|
|
new_cases.append((None, default))
|
|
super().__init__(test, OrderedDict(new_cases))
|
|
|
|
@deprecated("instead of `Case(...).makedefault()`, use an explicit default case: "
|
|
"`with m.Case(): ...`")
|
|
def makedefault(self, key=None):
|
|
if key is None:
|
|
for choice in self.cases.keys():
|
|
if (key is None
|
|
or (isinstance(choice, str) and choice == "default")
|
|
or choice > key):
|
|
key = choice
|
|
elif isinstance(key, str) and key == "default":
|
|
key = ()
|
|
else:
|
|
key = ("{:0{}b}".format(ast.Value.cast(key).value, len(self.test)),)
|
|
stmts = self.cases[key]
|
|
del self.cases[key]
|
|
self.cases[()] = stmts
|
|
return self
|