Skip to content

Commit 75b5079

Browse files
committed
interface/stream_utils: add a stream arbiter
1 parent 4af5729 commit 75b5079

File tree

1 file changed

+74
-0
lines changed

1 file changed

+74
-0
lines changed

lambdalib/interface/stream_utils.py

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
"Splitter",
1111
"Merger",
1212
"LastInserter",
13+
"Arbiter",
1314
]
1415

1516

@@ -248,3 +249,76 @@ def elaborate(self, platform):
248249
m.d.sync += counter.eq(0)
249250

250251
return m
252+
253+
254+
class RoundRobin(Elaboratable):
255+
""" Fair round robin.
256+
"""
257+
def __init__(self, n):
258+
self.n = n
259+
self.request = Signal(n)
260+
self.grant = Signal(range(n))
261+
262+
def elaborate(self, platform):
263+
m = Module()
264+
265+
with m.Switch(self.grant):
266+
for i in range(self.n):
267+
with m.Case(i):
268+
269+
cond = m.If
270+
# Loop over all other candidates and grant the
271+
# priority to the next one that requests it.
272+
for j in range(i+1, i+self.n):
273+
nxt = j % self.n
274+
with cond(self.request[nxt]):
275+
m.d.sync += self.grant.eq(nxt)
276+
cond = m.Elif
277+
278+
return m
279+
280+
281+
class Arbiter(Elaboratable):
282+
""" Select one stream among all valid sinks and connect it to the source.
283+
284+
The sinks streams must be delimited with `last`.
285+
286+
Wait for one transaction to complete (valid & ready & last) before
287+
selecting another valid sink.
288+
289+
sinks: a list of streams to arbiter.
290+
"""
291+
def __init__(self, sinks, source):
292+
self.sinks = sinks
293+
self.source = source
294+
295+
def elaborate(self, platform):
296+
source = self.source
297+
298+
m = Module()
299+
300+
run = Signal()
301+
302+
valids = Cat(*[s.valid for s in self.sinks])
303+
m.submodules.rr = rr = EnableInserter(run)(
304+
RoundRobin(len(self.sinks))
305+
)
306+
m.d.comb += rr.request.eq(valids)
307+
308+
pending = source.valid
309+
complete = source.valid & source.ready & source.last
310+
ongoing = Signal()
311+
with m.If(source.valid & source.ready):
312+
m.d.sync += ongoing.eq(~source.last)
313+
314+
# Run the round robin when:
315+
# the current transaction has completed,
316+
# or nothing is currently ongoing or pending.
317+
m.d.comb += run.eq(~(ongoing | pending) | complete)
318+
319+
with m.Switch(rr.grant):
320+
for i, sink in enumerate(self.sinks):
321+
with m.Case(i):
322+
m.d.comb += sink.connect(source)
323+
324+
return m

0 commit comments

Comments
 (0)