migen.fhdl.size: add fiter(), fslice(), and freversed()
authorRobert Jordens <jordens@gmail.com>
Tue, 3 Dec 2013 00:19:32 +0000 (17:19 -0700)
committerSebastien Bourdeauducq <sebastien@milkymist.org>
Tue, 3 Dec 2013 20:36:33 +0000 (21:36 +0100)
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 ;)

doc/api.rst
migen/fhdl/size.py
migen/fhdl/std.py
migen/test/test_size.py [new file with mode: 0644]

index 06c8a55334554b31afca983e07db7b0a1ccfda13..d49b9b70e94c8fae84eeee861c9c3a9c3785fa3b 100644 (file)
@@ -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
 ------------------------------
 
index a11690133381e4400705901e707706e20150bba6..e771cccad99722bb57936065795946fe823afc57 100644 (file)
@@ -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))
index 3a4a3de51f3ec498e9774ade90b4f2560de0861f..b9ec729f30b58184d92a42c4d3967a22dd8930ef 100644 (file)
@@ -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
diff --git a/migen/test/test_size.py b/migen/test/test_size.py
new file mode 100644 (file)
index 0000000..07b3052
--- /dev/null
@@ -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, [])