migen.fhdl.size: add fiter(), fslice(), and freversed()
do not overload __len__, __iter__, __reversed__ as not all valid expressions (ints and bools) have them. furthermore len([]) is and should be different from flen([]) (the later raises an error). keep __getitem__ as an exception that proves the rule ;)
This commit is contained in:
parent
ae6b78faeb
commit
fe67210d77
|
@ -8,6 +8,13 @@ migen API Documentation
|
|||
:members:
|
||||
:show-inheritance:
|
||||
|
||||
:mod:`fhdl.size` Module
|
||||
------------------------------
|
||||
|
||||
.. automodule:: migen.fhdl.size
|
||||
:members:
|
||||
:show-inheritance:
|
||||
|
||||
:mod:`genlib.fifo` Module
|
||||
------------------------------
|
||||
|
||||
|
|
|
@ -96,7 +96,103 @@ def value_bits_sign(v):
|
|||
bsc = map(value_bits_sign, v.choices)
|
||||
return max(bs[0] for bs in bsc), any(bs[1] for bs in bsc)
|
||||
else:
|
||||
raise TypeError
|
||||
raise TypeError("Can not calculate bit length of {} {}".format(
|
||||
type(v), v))
|
||||
|
||||
def flen(v):
|
||||
"""Bit length of an expression
|
||||
|
||||
Parameters
|
||||
----------
|
||||
v : int, bool or Value
|
||||
|
||||
Returns
|
||||
-------
|
||||
int
|
||||
Number of bits required to store `v` or available in `v`
|
||||
|
||||
Examples
|
||||
--------
|
||||
>>> flen(f.Signal(8))
|
||||
8
|
||||
>>> flen(0xaa)
|
||||
8
|
||||
"""
|
||||
return value_bits_sign(v)[0]
|
||||
|
||||
def fiter(v):
|
||||
"""Bit iterator
|
||||
|
||||
Parameters
|
||||
----------
|
||||
v : int, bool or Value
|
||||
|
||||
Returns
|
||||
-------
|
||||
iter
|
||||
Iterator over the bits in `v`
|
||||
|
||||
Examples
|
||||
--------
|
||||
>>> list(fiter(f.Signal(2))) #doctest: +ELLIPSIS
|
||||
[<migen.fhdl.structure._Slice object at 0x...>, <migen.fhdl.structure._Slice object at 0x...>]
|
||||
>>> list(fiter(4))
|
||||
[0, 0, 1]
|
||||
"""
|
||||
if isinstance(v, (bool, int)):
|
||||
return ((v >> i) & 1 for i in range(bits_for(v)))
|
||||
elif isinstance(v, f.Value):
|
||||
return (v[i] for i in range(flen(v)))
|
||||
else:
|
||||
raise TypeError("Can not bit-iterate {} {}".format(type(v), v))
|
||||
|
||||
def fslice(v, s):
|
||||
"""Bit slice
|
||||
|
||||
Parameters
|
||||
----------
|
||||
v : int, bool or Value
|
||||
s : slice or int
|
||||
|
||||
Returns
|
||||
-------
|
||||
int or Value
|
||||
Expression for the slice `s` of `v`.
|
||||
|
||||
Examples
|
||||
--------
|
||||
>>> fslice(Signal(2), 1) #doctest: +ELLIPSIS
|
||||
<migen.fhdl.structure._Slice object at 0x...>
|
||||
>>> bin(fslice(0b1101, slice(1, None, 2)))
|
||||
'0b10'
|
||||
"""
|
||||
if isinstance(v, (bool, int)):
|
||||
if isinstance(s, int):
|
||||
s = slice(s)
|
||||
idx = range(*s.indices(flen(v)))
|
||||
return sum(((v>>i) & 1) << j for j, i in enumerate(idx))
|
||||
elif isinstance(v, f.Value):
|
||||
return v[s]
|
||||
else:
|
||||
raise TypeError("Can not bit-slice {} {}".format(type(v), v))
|
||||
|
||||
def freversed(v):
|
||||
"""Bit reverse
|
||||
|
||||
Parameters
|
||||
----------
|
||||
v : int, bool or Value
|
||||
|
||||
Returns
|
||||
-------
|
||||
int or Value
|
||||
Expression containing the bit reversed input.
|
||||
|
||||
Examples
|
||||
--------
|
||||
>>> freversed(Signal(2)) #doctest: +ELLIPSIS
|
||||
<migen.fhdl.structure._Slice object at 0x...>
|
||||
>>> bin(freversed(0b1011))
|
||||
'0b1101'
|
||||
"""
|
||||
return fslice(v, slice(None, None, -1))
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
from migen.fhdl.structure import *
|
||||
from migen.fhdl.module import Module
|
||||
from migen.fhdl.specials import TSTriple, Instance, Memory
|
||||
from migen.fhdl.size import log2_int, bits_for, flen
|
||||
from migen.fhdl.size import log2_int, bits_for, flen, fiter, fslice, freversed
|
||||
from migen.fhdl.decorators import DecorateModule, InsertCE, InsertReset, RenameClockDomains
|
||||
|
|
|
@ -0,0 +1,45 @@
|
|||
import unittest
|
||||
|
||||
from migen.fhdl.std import *
|
||||
|
||||
class SignalSizeCase(unittest.TestCase):
|
||||
def setUp(self):
|
||||
self.i = 0xaa
|
||||
self.j = -127
|
||||
self.s = Signal((13, True))
|
||||
|
||||
def test_flen(self):
|
||||
self.assertEqual(flen(self.s), 13)
|
||||
self.assertEqual(flen(self.i), 8)
|
||||
self.assertEqual(flen(self.j), 8)
|
||||
|
||||
def test_flen_type(self):
|
||||
self.assertRaises(TypeError, flen, [])
|
||||
|
||||
def test_fiter(self):
|
||||
for i, si in enumerate(fiter(self.s)):
|
||||
self.assertEqual(si, self.s[i])
|
||||
self.assertEqual(list(fiter(self.i)),
|
||||
[(self.i >> i) & 1 for i in range(8)])
|
||||
self.assertEqual(list(fiter(self.j)),
|
||||
[(self.j >> i) & 1 for i in range(8)])
|
||||
|
||||
def test_fiter_type(self):
|
||||
self.assertRaises(TypeError, fiter, [])
|
||||
|
||||
def test_fslice(self):
|
||||
sl = slice(1, None, 2)
|
||||
fslice(self.s, sl)
|
||||
self.assertEqual(fslice(self.i, sl), 15)
|
||||
self.assertEqual(fslice(self.j, sl), 8)
|
||||
|
||||
def test_fslice_type(self):
|
||||
self.assertRaises(TypeError, fslice, [], 3)
|
||||
|
||||
def test_freversed(self):
|
||||
freversed(self.s)
|
||||
freversed(self.i)
|
||||
freversed(self.j)
|
||||
|
||||
def test_freveseed_type(self):
|
||||
self.assertRaises(TypeError, freversed, [])
|
Loading…
Reference in New Issue