fhdl.ast.Signal: implement width derivation from min/max.
This commit is contained in:
parent
bc60631d68
commit
4eadc1629a
|
@ -1,3 +1,4 @@
|
|||
import builtins
|
||||
from collections import OrderedDict
|
||||
from collections.abc import Iterable, MutableMapping, MutableSet
|
||||
|
||||
|
@ -496,6 +497,11 @@ class Signal(Value, DUID):
|
|||
If ``True``, do not generate reset logic for this ``Signal`` in synchronous statements.
|
||||
The ``reset`` value is only used as a combinatorial default or as the initial value.
|
||||
Defaults to ``False``.
|
||||
min : int or None
|
||||
max : int or None
|
||||
If `bits_sign` is `None`, the signal bit width and signedness are
|
||||
determined by the integer range given by `min` (inclusive,
|
||||
defaults to 0) and `max` (exclusive, defaults to 2).
|
||||
|
||||
Attributes
|
||||
----------
|
||||
|
@ -505,7 +511,7 @@ class Signal(Value, DUID):
|
|||
reset : int
|
||||
"""
|
||||
|
||||
def __init__(self, bits_sign=1, name=None, reset=0, reset_less=False):
|
||||
def __init__(self, bits_sign=None, name=None, reset=0, reset_less=False, min=None, max=None):
|
||||
super().__init__()
|
||||
|
||||
if name is None:
|
||||
|
@ -515,11 +521,28 @@ class Signal(Value, DUID):
|
|||
name = "$signal"
|
||||
self.name = name
|
||||
|
||||
if isinstance(bits_sign, int):
|
||||
bits_sign = bits_sign, False
|
||||
if bits_sign is None:
|
||||
if min is None:
|
||||
min = 0
|
||||
if max is None:
|
||||
max = 2
|
||||
max -= 1 # make both bounds inclusive
|
||||
if not min < max:
|
||||
raise ValueError("Lower bound {!r} should be less than higher bound {!r}"
|
||||
.format(min, max))
|
||||
self.signed = min < 0 or max < 0
|
||||
self.nbits = builtins.max(bits_for(min, self.signed), bits_for(max, self.signed))
|
||||
|
||||
elif isinstance(bits_sign, int):
|
||||
if not (min is None or max is None):
|
||||
raise ValueError("Only one of bits/signedness or bounds may be specified")
|
||||
self.nbits, self.signed = 1, False
|
||||
|
||||
else:
|
||||
self.nbits, self.signed = bits_sign
|
||||
|
||||
if not isinstance(self.nbits, int) or self.nbits < 0:
|
||||
raise TypeError("Width must be a positive integer")
|
||||
raise TypeError("Width must be a positive integer, not {!r}".format(self.nbits))
|
||||
self.reset = reset
|
||||
self.reset_less = reset_less
|
||||
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
from collections import Iterable
|
||||
|
||||
|
||||
__all__ = ["flatten", "union"]
|
||||
__all__ = ["flatten", "union", "log2_int", "bits_for"]
|
||||
|
||||
|
||||
def flatten(i):
|
||||
|
@ -20,3 +20,23 @@ def union(i):
|
|||
else:
|
||||
r |= e
|
||||
return r
|
||||
|
||||
|
||||
def log2_int(n, need_pow2=True):
|
||||
if n == 0:
|
||||
return 0
|
||||
r = (n - 1).bit_length()
|
||||
if need_pow2 and (1 << r) != n:
|
||||
raise ValueError("{} is not a power of 2".format(n))
|
||||
return r
|
||||
|
||||
|
||||
def bits_for(n, require_sign_bit=False):
|
||||
if n > 0:
|
||||
r = log2_int(n + 1, False)
|
||||
else:
|
||||
require_sign_bit = True
|
||||
r = log2_int(-n, False)
|
||||
if require_sign_bit:
|
||||
r += 1
|
||||
return r
|
||||
|
|
Loading…
Reference in a new issue