copy
This commit is contained in:
95
gateware/bundle_demultiplexer.py
Normal file
95
gateware/bundle_demultiplexer.py
Normal 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
|
||||
Reference in New Issue
Block a user