--- /dev/null
+"""Encoders and decoders between binary and one-hot representation."""
+
+from .. import *
+
+
+class Encoder:
+ """Encode one-hot to binary.
+
+ If one bit in ``i`` is asserted, ``n`` is low and ``o`` indicates the asserted bit.
+ Otherwise, ``n`` is high and ``o`` is ``0``.
+
+ Parameters
+ ----------
+ width : int
+ Bit width of the input
+
+ Attributes
+ ----------
+ i : Signal(width), in
+ One-hot input.
+ o : Signal(max=width), out
+ Encoded binary.
+ n : Signal, out
+ Invalid: either none or multiple input bits are asserted.
+ """
+ def __init__(self, width):
+ self.i = Signal(width)
+ self.o = Signal(max=max(2, width))
+ self.n = Signal()
+
+ def get_fragment(self, platform):
+ m = Module()
+ with m.Switch(self.i):
+ for j in range(len(self.i)):
+ with m.Case(1 << j):
+ m.d.comb += self.o.eq(j)
+ with m.Case():
+ m.d.comb += self.n.eq(1)
+ return m.lower(platform)
+
+
+class PriorityEncoder:
+ """Priority encode requests to binary.
+
+ If any bit in ``i`` is asserted, ``n`` is low and ``o`` indicates the least significant
+ asserted bit.
+ Otherwise, ``n`` is high and ``o`` is ``0``.
+
+ Parameters
+ ----------
+ width : int
+ Bit width of the input.
+
+ Attributes
+ ----------
+ i : Signal(width), in
+ Input requests.
+ o : Signal(max=width), out
+ Encoded binary.
+ n : Signal, out
+ Invalid: no input bits are asserted.
+ """
+ def __init__(self, width):
+ self.i = Signal(width)
+ self.o = Signal(max=max(2, width))
+ self.n = Signal()
+
+ def get_fragment(self, platform):
+ m = Module()
+ for j, b in enumerate(reversed(self.i)):
+ with m.If(b):
+ m.d.comb += self.o.eq(j)
+ m.d.comb += self.n.eq(self.i == 0)
+ return m.lower(platform)
+
+
+class Decoder:
+ """Decode binary to one-hot.
+
+ If ``n`` is low, only the ``i``th bit in ``o`` is asserted.
+ If ``n`` is high, ``o`` is ``0``.
+
+ Parameters
+ ----------
+ width : int
+ Bit width of the output.
+
+ Attributes
+ ----------
+ i : Signal(max=width), in
+ Input binary.
+ o : Signal(width), out
+ Decoded one-hot.
+ n : Signal, in
+ Invalid, no output bits are to be asserted.
+ """
+ def __init__(self, width):
+ self.i = Signal(max=max(2, width))
+ self.n = Signal()
+ self.o = Signal(width)
+
+ def get_fragment(self, platform):
+ m = Module()
+ with m.Switch(self.i):
+ for j in range(len(self.o)):
+ with m.Case(j):
+ m.d.comb += self.o.eq(1 << j)
+ with m.Case():
+ with m.If(self.n):
+ m.d.comb += self.o.eq(0)
+ return m.lower(platform)
+
+
+class PriorityDecoder(Decoder):
+ """Decode binary to priority request.
+
+ Identical to :class:`Decoder`.
+ """
--- /dev/null
+from .tools import *
+from ..hdl.ast import *
+from ..back.pysim import *
+from ..lib.coding import *
+
+
+class EncoderTestCase(FHDLTestCase):
+ def test_basic(self):
+ enc = Encoder(4)
+ with Simulator(enc) as sim:
+ def process():
+ self.assertEqual((yield enc.n), 1)
+ self.assertEqual((yield enc.o), 0)
+
+ yield enc.i.eq(0b0001)
+ yield Delay()
+ self.assertEqual((yield enc.n), 0)
+ self.assertEqual((yield enc.o), 0)
+
+ yield enc.i.eq(0b0100)
+ yield Delay()
+ self.assertEqual((yield enc.n), 0)
+ self.assertEqual((yield enc.o), 2)
+
+ yield enc.i.eq(0b0110)
+ yield Delay()
+ self.assertEqual((yield enc.n), 1)
+ self.assertEqual((yield enc.o), 0)
+
+ sim.add_process(process)
+
+
+class PriorityEncoderTestCase(FHDLTestCase):
+ def test_basic(self):
+ enc = PriorityEncoder(4)
+ with Simulator(enc) as sim:
+ def process():
+ self.assertEqual((yield enc.n), 1)
+ self.assertEqual((yield enc.o), 0)
+
+ yield enc.i.eq(0b0001)
+ yield Delay()
+ self.assertEqual((yield enc.n), 0)
+ self.assertEqual((yield enc.o), 0)
+
+ yield enc.i.eq(0b0100)
+ yield Delay()
+ self.assertEqual((yield enc.n), 0)
+ self.assertEqual((yield enc.o), 2)
+
+ yield enc.i.eq(0b0110)
+ yield Delay()
+ self.assertEqual((yield enc.n), 0)
+ self.assertEqual((yield enc.o), 1)
+
+ sim.add_process(process)
+
+
+class DecoderTestCase(FHDLTestCase):
+ def test_basic(self):
+ dec = Decoder(4)
+ with Simulator(dec) as sim:
+ def process():
+ self.assertEqual((yield enc.o), 0b0001)
+
+ yield enc.i.eq(1)
+ yield Delay()
+ self.assertEqual((yield enc.o), 0b0010)
+
+ yield enc.i.eq(3)
+ yield Delay()
+ self.assertEqual((yield enc.o), 0b1000)
+
+ yield enc.n.eq(1)
+ yield Delay()
+ self.assertEqual((yield enc.o), 0b0000)
+
+ sim.add_process(process)