This commit is contained in:
2026-03-13 19:58:28 +03:00
commit c938609393
87 changed files with 230200 additions and 0 deletions

View File

@@ -0,0 +1,95 @@
import operator
from functools import reduce
from amaranth import *
from amaranth.build import Platform
from amlib.stream import StreamInterface
from amlib.test import GatewareTestCase, sync_test_case
class BundleDemultiplexer(Elaboratable):
NO_CHANNELS_ADAT = 8
SAMPLE_WIDTH = 24
def __init__(self, no_bundles=4):
# parameters
self._no_bundles = no_bundles
self._channel_bits = Shape.cast(range(no_bundles * self.NO_CHANNELS_ADAT)).width
self._bundle_channel_bits = Shape.cast(range(self.NO_CHANNELS_ADAT)).width
# ports
self.no_channels_in = Signal(range(32 + 1))
self.channel_stream_in = StreamInterface(name="channel_stream",
payload_width=self.SAMPLE_WIDTH,
extra_fields=[("channel_nr", self._channel_bits)])
self.bundles_out = Array(StreamInterface(name=f"output_bundle_{i}",
payload_width=self.SAMPLE_WIDTH,
extra_fields=[("channel_nr", self._bundle_channel_bits)])
for i in range(no_bundles))
# debug signals
self.bundle_nr = Signal(range(self._no_bundles))
def elaborate(self, platform: Platform) -> Module:
m = Module()
# this is necessary to keep the simulator happy
keep_sync = Signal()
m.d.sync += keep_sync.eq(1)
channel_stream = self.channel_stream_in
bundle_ready = Signal()
bundle_nr = Signal(range(self._no_bundles))
channel_nr = Signal(range(self.NO_CHANNELS_ADAT))
last_channel = Signal(3)
channel_mask = last_channel
m.d.comb += [
bundle_nr .eq(channel_stream.channel_nr >> channel_nr.width),
self.bundle_nr .eq(bundle_nr),
channel_nr .eq(channel_stream.channel_nr & channel_mask),
last_channel .eq(Mux(self.no_channels_in == 2, 1, 7)),
bundle_ready .eq(self.bundles_out[bundle_nr].ready),
channel_stream.ready .eq(bundle_ready),
]
with m.If(bundle_ready & channel_stream.valid):
m.d.comb += [
self.bundles_out[bundle_nr].valid.eq(1),
self.bundles_out[bundle_nr].payload.eq(channel_stream.payload),
self.bundles_out[bundle_nr].channel_nr.eq(channel_nr),
self.bundles_out[bundle_nr].first.eq(channel_nr == 0),
self.bundles_out[bundle_nr].last.eq(channel_nr == last_channel),
]
return m
class BundleDemultiplexerTest(GatewareTestCase):
FRAGMENT_UNDER_TEST = BundleDemultiplexer
FRAGMENT_ARGUMENTS = dict()
def send_one_frame(self, sample: int, channel: int, wait=True):
yield self.dut.channel_stream_in.channel_nr.eq(channel)
yield self.dut.channel_stream_in.payload.eq(sample)
yield self.dut.channel_stream_in.valid.eq(1)
yield
yield self.dut.channel_stream_in.valid.eq(0)
if wait:
yield
@sync_test_case
def test_smoke(self):
dut = self.dut
for bundle in range(4):
yield dut.bundles_out[bundle].ready.eq(1)
yield
yield
for sample in range(3):
for ch in range(4*BundleDemultiplexer.NO_CHANNELS_ADAT):
yield from self.send_one_frame((sample << 8) | ch, ch, wait=False)
yield
yield