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 import OrderedDict
|
||||||
from collections.abc import Iterable, MutableMapping, MutableSet
|
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.
|
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.
|
The ``reset`` value is only used as a combinatorial default or as the initial value.
|
||||||
Defaults to ``False``.
|
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
|
Attributes
|
||||||
----------
|
----------
|
||||||
|
@ -505,7 +511,7 @@ class Signal(Value, DUID):
|
||||||
reset : int
|
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__()
|
super().__init__()
|
||||||
|
|
||||||
if name is None:
|
if name is None:
|
||||||
|
@ -515,11 +521,28 @@ class Signal(Value, DUID):
|
||||||
name = "$signal"
|
name = "$signal"
|
||||||
self.name = name
|
self.name = name
|
||||||
|
|
||||||
if isinstance(bits_sign, int):
|
if bits_sign is None:
|
||||||
bits_sign = bits_sign, False
|
if min is None:
|
||||||
self.nbits, self.signed = bits_sign
|
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:
|
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 = reset
|
||||||
self.reset_less = reset_less
|
self.reset_less = reset_less
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
from collections import Iterable
|
from collections import Iterable
|
||||||
|
|
||||||
|
|
||||||
__all__ = ["flatten", "union"]
|
__all__ = ["flatten", "union", "log2_int", "bits_for"]
|
||||||
|
|
||||||
|
|
||||||
def flatten(i):
|
def flatten(i):
|
||||||
|
@ -20,3 +20,23 @@ def union(i):
|
||||||
else:
|
else:
|
||||||
r |= e
|
r |= e
|
||||||
return r
|
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