lib.coding: port from Migen.

This commit is contained in:
whitequark 2018-12-26 13:19:34 +00:00
parent fe8cb55204
commit 528747703d
4 changed files with 205 additions and 5 deletions

View file

@ -130,11 +130,11 @@ Compatibility summary
- () `ElasticBuffer` ?
- () `lcm` ?
- () `Gearbox` ?
- () `coding` ?
- () `Encoder` ?
- () `PriorityEncoder` ?
- () `Decoder` ?
- () `PriorityDecoder` ?
- (⊕) `coding` id
- (⊕) `Encoder` id
- (⊕) `PriorityEncoder` id
- (⊕) `Decoder` id
- (⊕) `PriorityDecoder` id
- () `divider` ?
- () `Divider` ?
- () `fifo` ?

View file

@ -0,0 +1,4 @@
from ...lib.cdc import *
__all__ = ["Encoder", "PriorityEncoder", "Decoder", "PriorityDecoder"]

118
nmigen/lib/coding.py Normal file
View file

@ -0,0 +1,118 @@
"""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`.
"""

View file

@ -0,0 +1,78 @@
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)