From 0b65b2d84a1b2b53329ca8f29639e0f0a1b2dce3 Mon Sep 17 00:00:00 2001 From: Wanda Date: Fri, 14 Jun 2024 23:47:23 +0200 Subject: [PATCH] Implement RFC 63: Remove `amaranth.lib.coding`. --- amaranth/lib/coding.py | 192 --------------------------------------- docs/changes.rst | 13 +++ docs/stdlib.rst | 3 +- docs/stdlib/coding.rst | 27 ------ tests/test_lib_coding.py | 128 -------------------------- 5 files changed, 14 insertions(+), 349 deletions(-) delete mode 100644 amaranth/lib/coding.py delete mode 100644 docs/stdlib/coding.rst delete mode 100644 tests/test_lib_coding.py diff --git a/amaranth/lib/coding.py b/amaranth/lib/coding.py deleted file mode 100644 index f7a4b75ee..000000000 --- a/amaranth/lib/coding.py +++ /dev/null @@ -1,192 +0,0 @@ -import warnings - -warnings.warn("the `amaranth.lib.coding` module will be removed without a replacement; " - "copy the module into your project to continue using it", - DeprecationWarning, stacklevel=2) - - -from .. import * - - -__all__ = [ - "Encoder", "Decoder", - "PriorityEncoder", "PriorityDecoder", - "GrayEncoder", "GrayDecoder", -] - - -class Encoder(Elaboratable): - """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(range(width)), out - Encoded natural binary. - n : Signal, out - Invalid: either none or multiple input bits are asserted. - """ - def __init__(self, width): - self.width = width - - self.i = Signal(width) - self.o = Signal(range(width)) - self.n = Signal() - - def elaborate(self, platform): - m = Module() - with m.Switch(self.i): - for j in range(self.width): - with m.Case(1 << j): - m.d.comb += self.o.eq(j) - with m.Default(): - m.d.comb += self.n.eq(1) - return m - - -class PriorityEncoder(Elaboratable): - """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(range(width)), out - Encoded natural binary. - n : Signal, out - Invalid: no input bits are asserted. - """ - def __init__(self, width): - self.width = width - - self.i = Signal(width) - self.o = Signal(range(width)) - self.n = Signal() - - def elaborate(self, platform): - m = Module() - 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 - - -class Decoder(Elaboratable): - """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(range(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.width = width - - self.i = Signal(range(width)) - self.n = Signal() - self.o = Signal(width) - - def elaborate(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.If(self.n): - m.d.comb += self.o.eq(0) - return m - - -class PriorityDecoder(Decoder): - """Decode binary to priority request. - - Identical to :class:`Decoder`. - """ - - -class GrayEncoder(Elaboratable): - """Encode binary to Gray code. - - Parameters - ---------- - width : int - Bit width. - - Attributes - ---------- - i : Signal(width), in - Natural binary input. - o : Signal(width), out - Encoded Gray code. - """ - def __init__(self, width): - self.width = width - - self.i = Signal(width) - self.o = Signal(width) - - def elaborate(self, platform): - m = Module() - m.d.comb += self.o.eq(self.i ^ self.i[1:]) - return m - - -class GrayDecoder(Elaboratable): - """Decode Gray code to binary. - - Parameters - ---------- - width : int - Bit width. - - Attributes - ---------- - i : Signal(width), in - Gray code input. - o : Signal(width), out - Decoded natural binary. - """ - def __init__(self, width): - self.width = width - - self.i = Signal(width) - self.o = Signal(width) - - def elaborate(self, platform): - m = Module() - rhs = Const(0) - for i in reversed(range(self.width)): - rhs = rhs ^ self.i[i] - m.d.comb += self.o[i].eq(rhs) - return m diff --git a/docs/changes.rst b/docs/changes.rst index 028091636..8f2d47859 100644 --- a/docs/changes.rst +++ b/docs/changes.rst @@ -9,6 +9,7 @@ Documentation for past releases Documentation for past releases of the Amaranth language and toolchain is available online: +* `Amaranth 0.5.0 `_ * `Amaranth 0.4.5 `_ * `Amaranth 0.4.4 `_ * `Amaranth 0.4.3 `_ @@ -18,6 +19,18 @@ Documentation for past releases of the Amaranth language and toolchain is availa * `Amaranth 0.3 `_ +Version 0.6 (unreleased) +======================== + + +Standard library changes +------------------------ + +.. currentmodule:: amaranth.lib + +* Removed: (deprecated in 0.5) :mod:`amaranth.lib.coding`. (`RFC 63`_) + + Version 0.5 =========== diff --git a/docs/stdlib.rst b/docs/stdlib.rst index 01e203459..78e97b0ff 100644 --- a/docs/stdlib.rst +++ b/docs/stdlib.rst @@ -5,7 +5,7 @@ The :mod:`amaranth.lib` module, also known as the standard library, provides mod 1. Modules that will used by essentially all idiomatic Amaranth code, or which are necessary for interoperability. This includes :mod:`amaranth.lib.enum` (enumerations), :mod:`amaranth.lib.data` (data structures), :mod:`amaranth.lib.wiring` (interfaces and components), :mod:`amaranth.lib.meta` (interface metadata), and :mod:`amaranth.lib.stream` (data streams). 2. Modules that abstract common functionality whose implementation differs between hardware platforms. This includes :mod:`amaranth.lib.memory` and :mod:`amaranth.lib.cdc`. -3. Modules that have essentially one correct implementation and are of broad utility in digital designs. This includes :mod:`amaranth.lib.coding`, :mod:`amaranth.lib.fifo`, and :mod:`amaranth.lib.crc`. +3. Modules that have essentially one correct implementation and are of broad utility in digital designs. This includes :mod:`amaranth.lib.fifo`, and :mod:`amaranth.lib.crc`. As part of the Amaranth backwards compatibility guarantee, any behaviors described in these documents will not change from a version to another without at least one version including a warning about the impending change. Any nontrivial change to these behaviors must also go through the public review as a part of the `Amaranth Request for Comments process `_. @@ -22,6 +22,5 @@ The Amaranth standard library is separate from the Amaranth language: everything stdlib/memory stdlib/io stdlib/cdc - stdlib/coding stdlib/fifo stdlib/crc diff --git a/docs/stdlib/coding.rst b/docs/stdlib/coding.rst deleted file mode 100644 index c112c0672..000000000 --- a/docs/stdlib/coding.rst +++ /dev/null @@ -1,27 +0,0 @@ -Code conversion -############### - -.. py:module:: amaranth.lib.coding - -The :mod:`amaranth.lib.coding` module provides building blocks for conversion between different encodings of binary numbers. - - -One-hot coding -============== - -.. autoclass:: Encoder() -.. autoclass:: Decoder() - - -Priority coding -=============== - -.. autoclass:: PriorityEncoder() -.. autoclass:: PriorityDecoder() - - -Gray coding -=========== - -.. autoclass:: GrayEncoder() -.. autoclass:: GrayDecoder() diff --git a/tests/test_lib_coding.py b/tests/test_lib_coding.py deleted file mode 100644 index fcdcd7ae0..000000000 --- a/tests/test_lib_coding.py +++ /dev/null @@ -1,128 +0,0 @@ -import warnings - -from amaranth.hdl import * -from amaranth.sim import * -with warnings.catch_warnings(): - warnings.filterwarnings(action="ignore", category=DeprecationWarning) - from amaranth.lib.coding import * - -from .utils import * - - -class EncoderTestCase(FHDLTestCase): - def test_basic(self): - enc = Encoder(4) - async def testbench(ctx): - self.assertEqual(ctx.get(enc.n), 1) - self.assertEqual(ctx.get(enc.o), 0) - - ctx.set(enc.i, 0b0001) - self.assertEqual(ctx.get(enc.n), 0) - self.assertEqual(ctx.get(enc.o), 0) - - ctx.set(enc.i, 0b0100) - self.assertEqual(ctx.get(enc.n), 0) - self.assertEqual(ctx.get(enc.o), 2) - - ctx.set(enc.i, 0b0110) - self.assertEqual(ctx.get(enc.n), 1) - self.assertEqual(ctx.get(enc.o), 0) - - sim = Simulator(enc) - sim.add_testbench(testbench) - sim.run() - - -class PriorityEncoderTestCase(FHDLTestCase): - def test_basic(self): - enc = PriorityEncoder(4) - async def testbench(ctx): - self.assertEqual(ctx.get(enc.n), 1) - self.assertEqual(ctx.get(enc.o), 0) - - ctx.set(enc.i, 0b0001) - self.assertEqual(ctx.get(enc.n), 0) - self.assertEqual(ctx.get(enc.o), 0) - - ctx.set(enc.i, 0b0100) - self.assertEqual(ctx.get(enc.n), 0) - self.assertEqual(ctx.get(enc.o), 2) - - ctx.set(enc.i, 0b0110) - self.assertEqual(ctx.get(enc.n), 0) - self.assertEqual(ctx.get(enc.o), 1) - - sim = Simulator(enc) - sim.add_testbench(testbench) - sim.run() - - -class DecoderTestCase(FHDLTestCase): - def test_basic(self): - dec = Decoder(4) - async def testbench(ctx): - self.assertEqual(ctx.get(dec.o), 0b0001) - - ctx.set(dec.i, 1) - self.assertEqual(ctx.get(dec.o), 0b0010) - - ctx.set(dec.i, 3) - self.assertEqual(ctx.get(dec.o), 0b1000) - - ctx.set(dec.n, 1) - self.assertEqual(ctx.get(dec.o), 0b0000) - - sim = Simulator(dec) - sim.add_testbench(testbench) - sim.run() - - -class ReversibleSpec(Elaboratable): - def __init__(self, encoder_cls, decoder_cls, i_width, args): - self.encoder_cls = encoder_cls - self.decoder_cls = decoder_cls - self.coder_args = args - self.i = Signal(i_width) - - def elaborate(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 += [ - enc.i.eq(self.i), - dec.i.eq(enc.o), - Assert(enc.i == dec.o) - ] - return m - - -class HammingDistanceSpec(Elaboratable): - def __init__(self, distance, encoder_cls, i_width, args): - self.distance = distance - self.encoder_cls = encoder_cls - self.coder_args = args - self.i1 = Signal(i_width) - self.i2 = Signal(i_width) - - def elaborate(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 += [ - enc1.i.eq(self.i1), - enc2.i.eq(self.i2), - Assume(enc1.i + 1 == enc2.i), - Assert(sum(enc1.o ^ enc2.o) == self.distance) - ] - return m - - -class GrayCoderTestCase(FHDLTestCase): - def test_reversible(self): - spec = ReversibleSpec(encoder_cls=GrayEncoder, decoder_cls=GrayDecoder, i_width=16, - args=(16,)) - self.assertFormal(spec, [spec.i], mode="prove") - - def test_distance(self): - spec = HammingDistanceSpec(distance=1, encoder_cls=GrayEncoder, i_width=16, args=(16,)) - self.assertFormal(spec, [spec.i1, spec.i2], mode="prove")