Skip to content
Permalink

Comparing changes

Choose two branches to see what’s changed or to start a new pull request. If you need to, you can also or learn more about diff comparisons.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also . Learn more about diff comparisons here.
base repository: m-labs/nmigen
Failed to load repositories. Confirm that selected base ref is valid, then try again.
Loading
base: 9de927270986
Choose a base ref
...
head repository: m-labs/nmigen
Failed to load repositories. Confirm that selected head ref is valid, then try again.
Loading
compare: c110fe6a9ddc
Choose a head ref
  • 3 commits
  • 4 files changed
  • 1 contributor

Commits on Jan 20, 2019

  1. lib.coding: add width as attribute to all coders.

    whitequark committed Jan 20, 2019
    Copy the full SHA
    9757157 View commit details
  2. lib.coding: add GrayEncoder and GrayDecoder.

    Unlike the Migen ones, these are purely combinatorial.
    whitequark committed Jan 20, 2019
    Copy the full SHA
    b6cff2c View commit details
  3. Copy the full SHA
    c110fe6 View commit details
Showing with 165 additions and 7 deletions.
  1. +3 −2 doc/COMPAT_SUMMARY.md
  2. +44 −1 nmigen/compat/genlib/cdc.py
  3. +73 −4 nmigen/lib/coding.py
  4. +45 −0 nmigen/test/test_lib_coding.py
5 changes: 3 additions & 2 deletions doc/COMPAT_SUMMARY.md
Original file line number Diff line number Diff line change
@@ -126,8 +126,9 @@ Compatibility summary
- (⊕) `MultiReg` id
- (−) `PulseSynchronizer` ?
- (−) `BusSynchronizer` ?
- (−) `GrayCounter` ?
- (−) `GrayDecoder` ?
- (⊕) `GrayCounter` **obs**`.lib.coding.GrayEncoder`
- (⊕) `GrayDecoder` **obs**`.lib.coding.GrayDecoder`
<br>Note: `.lib.coding.GrayEncoder` and `.lib.coding.GrayDecoder` are purely combinatorial.
- (−) `ElasticBuffer` ?
- (−) `lcm` ?
- (−) `Gearbox` ?
45 changes: 44 additions & 1 deletion nmigen/compat/genlib/cdc.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,47 @@
from ...tools import deprecated
from ...lib.cdc import MultiReg
from ...hdl.ast import *
from ..fhdl.module import CompatModule


__all__ = ["MultiReg"]
__all__ = ["MultiReg", "GrayCounter", "GrayDecoder"]


@deprecated("instead of `migen.genlib.cdc.GrayCounter`, use `nmigen.lib.coding.GrayEncoder`")
class GrayCounter(CompatModule):
def __init__(self, width):
self.ce = Signal()
self.q = Signal(width)
self.q_next = Signal(width)
self.q_binary = Signal(width)
self.q_next_binary = Signal(width)

###

self.comb += [
If(self.ce,
self.q_next_binary.eq(self.q_binary + 1)
).Else(
self.q_next_binary.eq(self.q_binary)
),
self.q_next.eq(self.q_next_binary ^ self.q_next_binary[1:])
]
self.sync += [
self.q_binary.eq(self.q_next_binary),
self.q.eq(self.q_next)
]


@deprecated("instead of `migen.genlib.cdc.GrayDecoder`, use `nmigen.lib.coding.GrayDecoder`")
class GrayDecoder(CompatModule):
def __init__(self, width):
self.i = Signal(width)
self.o = Signal(width, reset_less=True)

# # #

o_comb = Signal(width)
self.comb += o_comb[-1].eq(self.i[-1])
for i in reversed(range(width-1)):
self.comb += o_comb[i].eq(o_comb[i+1] ^ self.i[i])
self.sync += self.o.eq(o_comb)
77 changes: 73 additions & 4 deletions nmigen/lib/coding.py
Original file line number Diff line number Diff line change
@@ -3,6 +3,13 @@
from .. import *


__all__ = [
"Encoder", "Decoder",
"PriorityEncoder", "PriorityDecoder",
"GrayEncoder", "GrayDecoder",
]


class Encoder:
"""Encode one-hot to binary.
@@ -24,14 +31,16 @@ class Encoder:
Invalid: either none or multiple input bits are asserted.
"""
def __init__(self, width):
self.width = 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)):
for j in range(self.width):
with m.Case(1 << j):
m.d.comb += self.o.eq(j)
with m.Case():
@@ -61,15 +70,17 @@ class PriorityEncoder:
Invalid: no input bits are asserted.
"""
def __init__(self, width):
self.width = 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(len(self.i) - j - 1)
for j in reversed(range(self.width)):
with m.If(self.i[j]):
m.d.comb += self.o.eq(j)
m.d.comb += self.n.eq(self.i == 0)
return m.lower(platform)

@@ -95,6 +106,8 @@ class Decoder:
Invalid, no output bits are to be asserted.
"""
def __init__(self, width):
self.width = width

self.i = Signal(max=max(2, width))
self.n = Signal()
self.o = Signal(width)
@@ -115,3 +128,59 @@ class PriorityDecoder(Decoder):
Identical to :class:`Decoder`.
"""


class GrayEncoder:
"""Encode binary to Gray code.
Parameters
----------
width : int
Bit width.
Attributes
----------
i : Signal(width), in
Input natural binary.
o : Signal(width), out
Encoded Gray code.
"""
def __init__(self, width):
self.width = width

self.i = Signal(width)
self.o = Signal(width)

def get_fragment(self, platform):
m = Module()
m.d.comb += self.o.eq(self.i ^ self.i[1:])
return m.lower(platform)


class GrayDecoder:
"""Decode Gray code to binary.
Parameters
----------
width : int
Bit width.
Attributes
----------
i : Signal(width), in
Input Gray code.
o : Signal(width), out
Decoded natural binary.
"""
def __init__(self, width):
self.width = width

self.i = Signal(width)
self.o = Signal(width)

def get_fragment(self, platform):
m = Module()
m.d.comb += self.o[-1].eq(self.i[-1])
for i in reversed(range(self.width - 1)):
m.d.comb += self.o[i].eq(self.o[i + 1] ^ self.i[i])
return m.lower(platform)
45 changes: 45 additions & 0 deletions nmigen/test/test_lib_coding.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
from .tools import *
from ..hdl.ast import *
from ..hdl.dsl import *
from ..back.pysim import *
from ..lib.coding import *

@@ -79,3 +80,47 @@ def process():

sim.add_process(process)
sim.run()


class ReversibleSpec:
def __init__(self, encoder_cls, decoder_cls, args):
self.encoder_cls = encoder_cls
self.decoder_cls = decoder_cls
self.coder_args = args

def get_fragment(self, platform):
m = Module()
enc, dec = self.encoder_cls(*self.coder_args), self.decoder_cls(*self.coder_args)
m.submodules += enc, dec
m.d.comb += [
dec.i.eq(enc.o),
Assert(enc.i == dec.o)
]
return m.lower(platform)


class HammingDistanceSpec:
def __init__(self, distance, encoder_cls, args):
self.distance = distance
self.encoder_cls = encoder_cls
self.coder_args = args

def get_fragment(self, platform):
m = Module()
enc1, enc2 = self.encoder_cls(*self.coder_args), self.encoder_cls(*self.coder_args)
m.submodules += enc1, enc2
m.d.comb += [
Assume(enc1.i + 1 == enc2.i),
Assert(sum(enc1.o ^ enc2.o) == self.distance)
]
return m.lower(platform)


class GrayCoderTestCase(FHDLTestCase):
def test_reversible(self):
spec = ReversibleSpec(encoder_cls=GrayEncoder, decoder_cls=GrayDecoder, args=(16,))
self.assertFormal(spec, mode="prove")

def test_distance(self):
spec = HammingDistanceSpec(distance=1, encoder_cls=GrayEncoder, args=(16,))
self.assertFormal(spec, mode="prove")