genlib/sort: add bitonic, combinatorial sorter
complete with with api documentation and unittests
This commit is contained in:
parent
ab48316fcd
commit
dd24fdd356
|
@ -28,3 +28,10 @@ migen API Documentation
|
||||||
.. automodule:: migen.genlib.cordic
|
.. automodule:: migen.genlib.cordic
|
||||||
:members:
|
:members:
|
||||||
:show-inheritance:
|
:show-inheritance:
|
||||||
|
|
||||||
|
:mod:`genlib.sort` Module
|
||||||
|
------------------------------
|
||||||
|
|
||||||
|
.. automodule:: migen.genlib.sort
|
||||||
|
:members:
|
||||||
|
:show-inheritance:
|
||||||
|
|
|
@ -0,0 +1,70 @@
|
||||||
|
from migen.fhdl.std import *
|
||||||
|
from migen.fhdl import verilog
|
||||||
|
|
||||||
|
class BitonicSort(Module):
|
||||||
|
"""Combinatorial sorting network
|
||||||
|
|
||||||
|
The Bitonic sort is implemented as a combinatorial sort using
|
||||||
|
comparators and multiplexers. Its asymptotic complexity (in terms of
|
||||||
|
number of comparators/muxes) is O(n log(n)**2), like mergesort or
|
||||||
|
shellsort.
|
||||||
|
|
||||||
|
http://www.dps.uibk.ac.at/~cosenza/teaching/gpu/sort-batcher.pdf
|
||||||
|
|
||||||
|
http://www.inf.fh-flensburg.de/lang/algorithmen/sortieren/bitonic/bitonicen.htm
|
||||||
|
|
||||||
|
http://www.myhdl.org/doku.php/cookbook:bitonic
|
||||||
|
|
||||||
|
Parameters
|
||||||
|
----------
|
||||||
|
n : int
|
||||||
|
Number of inputs and output signals.
|
||||||
|
m : int
|
||||||
|
Bit width of inputs and outputs. Or a tuple of `(m, signed)`.
|
||||||
|
ascending : bool
|
||||||
|
Sort direction. `True` if input is to be sorted ascending,
|
||||||
|
`False` for descending. Defaults to ascending.
|
||||||
|
|
||||||
|
Attributes
|
||||||
|
----------
|
||||||
|
i : list of Signals, in
|
||||||
|
Input values, each `m` wide.
|
||||||
|
o : list of Signals, out
|
||||||
|
Output values, sorted, each `m` bits wide.
|
||||||
|
"""
|
||||||
|
def __init__(self, n, m, ascending=True):
|
||||||
|
self.i = [Signal(m) for i in range(n)]
|
||||||
|
self.o = [Signal(m) for i in range(n)]
|
||||||
|
self._sort(self.i, self.o, int(ascending), m)
|
||||||
|
|
||||||
|
def _sort_two(self, i0, i1, o0, o1, dir):
|
||||||
|
self.comb += [
|
||||||
|
o0.eq(i0),
|
||||||
|
o1.eq(i1),
|
||||||
|
If(dir == (i0 > i1),
|
||||||
|
o0.eq(i1),
|
||||||
|
o1.eq(i0),
|
||||||
|
)]
|
||||||
|
|
||||||
|
def _merge(self, i, o, dir, m):
|
||||||
|
n = len(i)
|
||||||
|
k = n//2
|
||||||
|
if n > 1:
|
||||||
|
t = [Signal(m) for j in range(n)]
|
||||||
|
for j in range(k):
|
||||||
|
self._sort_two(i[j], i[j + k], t[j], t[j + k], dir)
|
||||||
|
self._merge(t[:k], o[:k], dir, m)
|
||||||
|
self._merge(t[k:], o[k:], dir, m)
|
||||||
|
else:
|
||||||
|
self.comb += o[0].eq(i[0])
|
||||||
|
|
||||||
|
def _sort(self, i, o, dir, m):
|
||||||
|
n = len(i)
|
||||||
|
k = n//2
|
||||||
|
if n > 1:
|
||||||
|
t = [Signal(m) for j in range(n)]
|
||||||
|
self._sort(i[:k], t[:k], 1, m) # ascending
|
||||||
|
self._sort(i[k:], t[k:], 0, m) # descending
|
||||||
|
self._merge(t, o, dir, m)
|
||||||
|
else:
|
||||||
|
self.comb += o[0].eq(i[0])
|
|
@ -0,0 +1,28 @@
|
||||||
|
import unittest
|
||||||
|
from random import randrange
|
||||||
|
|
||||||
|
from migen.fhdl.std import *
|
||||||
|
from migen.genlib.sort import *
|
||||||
|
|
||||||
|
from migen.test.support import SimCase, SimBench
|
||||||
|
|
||||||
|
class BitonicCase(SimCase, unittest.TestCase):
|
||||||
|
class TestBench(SimBench):
|
||||||
|
def __init__(self):
|
||||||
|
self.submodules.dut = BitonicSort(8, 4, ascending=True)
|
||||||
|
|
||||||
|
def test_sizes(self):
|
||||||
|
self.assertEqual(len(self.tb.dut.i), 8)
|
||||||
|
self.assertEqual(len(self.tb.dut.o), 8)
|
||||||
|
for i in range(8):
|
||||||
|
self.assertEqual(flen(self.tb.dut.i[i]), 4)
|
||||||
|
self.assertEqual(flen(self.tb.dut.o[i]), 4)
|
||||||
|
|
||||||
|
def test_sort(self):
|
||||||
|
def cb(tb, s):
|
||||||
|
for i in tb.dut.i:
|
||||||
|
s.wr(i, randrange(1<<flen(i)))
|
||||||
|
i = [s.rd(i) for i in tb.dut.i]
|
||||||
|
o = [s.rd(o) for o in tb.dut.o]
|
||||||
|
self.assertEqual(sorted(i), o)
|
||||||
|
self.run_with(cb, 20)
|
Loading…
Reference in New Issue