diff --git a/transactron/testing/functions.py b/transactron/testing/functions.py index 347a41b..7cb69b1 100644 --- a/transactron/testing/functions.py +++ b/transactron/testing/functions.py @@ -1,6 +1,6 @@ from amaranth import * from amaranth.lib.data import Layout, StructLayout, View -from amaranth.sim.core import Command +from amaranth.sim._pycoro import Command from typing import TypeVar, Any, Generator, TypeAlias, TYPE_CHECKING, Union from transactron.utils._typing import RecordIntDict diff --git a/transactron/testing/gtkw_extension.py b/transactron/testing/gtkw_extension.py index db407ac..21eb90e 100644 --- a/transactron/testing/gtkw_extension.py +++ b/transactron/testing/gtkw_extension.py @@ -8,8 +8,10 @@ class _VCDWriterExt(_VCDWriter): - def __init__(self, design, *, vcd_file, gtkw_file, traces): - super().__init__(design=design, vcd_file=vcd_file, gtkw_file=gtkw_file, traces=list(flatten_signals(traces))) + def __init__(self, state, design, *, vcd_file, gtkw_file, traces): + super().__init__( + state=state, design=design, vcd_file=vcd_file, gtkw_file=gtkw_file, traces=list(flatten_signals(traces)) + ) self._tree_traces = traces def close(self, timestamp): @@ -60,7 +62,7 @@ def gtkw_traces(traces): @contextmanager def write_vcd_ext(engine, vcd_file, gtkw_file, traces): - vcd_writer = _VCDWriterExt(engine._design, vcd_file=vcd_file, gtkw_file=gtkw_file, traces=traces) + vcd_writer = _VCDWriterExt(engine._state, engine._design, vcd_file=vcd_file, gtkw_file=gtkw_file, traces=traces) try: engine._vcd_writers.append(vcd_writer) yield Tick() diff --git a/transactron/utils/amaranth_ext/__init__.py b/transactron/utils/amaranth_ext/__init__.py index 2b8533b..05df9e8 100644 --- a/transactron/utils/amaranth_ext/__init__.py +++ b/transactron/utils/amaranth_ext/__init__.py @@ -1,2 +1,3 @@ from .functions import * # noqa: F401 from .elaboratables import * # noqa: F401 +from .coding import * # noqa: F401 diff --git a/transactron/utils/amaranth_ext/coding.py b/transactron/utils/amaranth_ext/coding.py new file mode 100644 index 0000000..5360579 --- /dev/null +++ b/transactron/utils/amaranth_ext/coding.py @@ -0,0 +1,196 @@ +# This module was copied from Amaranth because it is deprecated there. +# Copyright (C) 2019-2024 Amaranth HDL contributors + +from amaranth 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: int): + 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: int): + 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: int): + 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: int): + 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: int): + 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