1 # This file is Copyright (c) 2020 LambdaConcept <contact@lambdaconcept.com>
4 from nmigen
import tracer
5 from nmigen
.compat
import Case
7 __ALL__
= ["delayed_enter", "RoundRobin", "Timeline", "CSRPrefixProxy"]
10 def delayed_enter(m
, src
, dst
, delay
):
13 for i
in range(delay
):
17 statename
= "{}-{}".format(src
, i
)
22 deststate
= "{}-{}".format(src
, i
+1)
24 with m
.State(statename
):
27 # Original nMigen implementation by HarryHo90sHK
30 class RoundRobin(Elaboratable
):
31 """A round-robin scheduler.
35 Maximum number of requests to handle.
39 Signal where a '1' on the i-th bit represents an incoming request from the i-th device.
40 grant : Signal(range(n))
41 Signal that equals to the index of the device which is currently granted access.
43 Strobe signal to enable granting access to the next device requesting. Externally driven.
46 def __init__(self
, n
):
48 self
.request
= Signal(n
)
49 self
.grant
= Signal(range(n
))
52 def elaborate(self
, platform
):
56 with m
.Switch(self
.grant
):
57 for i
in range(self
.n
):
59 for j
in reversed(range(i
+1, i
+self
.n
)):
60 # If i+1 <= j < n, then t == j; (after i)
61 # If n <= j < i+n, then t == j - n (before i)
63 with m
.If(self
.request
[t
]):
64 m
.d
.sync
+= self
.grant
.eq(t
)
69 class Timeline(Elaboratable
):
70 def __init__(self
, events
):
71 self
.trigger
= Signal()
74 def elaborate(self
, platform
):
77 lastevent
= max([e
[0] for e
in self
._events
])
78 counter
= Signal(range(lastevent
+1))
80 # Counter incrementation
81 # (with overflow handling)
82 if (lastevent
& (lastevent
+ 1)) != 0:
83 with m
.If(counter
== lastevent
):
84 m
.d
.sync
+= counter
.eq(0)
86 with m
.If(counter
!= 0):
87 m
.d
.sync
+= counter
.eq(counter
+1)
88 with m
.Elif(self
.trigger
):
89 m
.d
.sync
+= counter
.eq(1)
91 with m
.If(counter
!= 0):
92 m
.d
.sync
+= counter
.eq(counter
+1)
93 with m
.Elif(self
.trigger
):
94 m
.d
.sync
+= counter
.eq(1)
96 for e
in self
._events
:
98 with m
.If(self
.trigger
& (counter
== 0)):
101 with m
.If(counter
== e
[0]):
107 class CSRPrefixProxy
:
108 def __init__(self
, bank
, prefix
):
110 self
._prefix
= prefix
112 def csr(self
, width
, access
, *, addr
=None, alignment
=None, name
=None,
114 if name
is not None and not isinstance(name
, str):
115 raise TypeError("Name must be a string, not {!r}".format(name
))
116 name
= name
or tracer
.get_var_name(depth
=2 + src_loc_at
).lstrip("_")
118 prefixed_name
= "{}_{}".format(self
._prefix
, name
)
119 return self
._bank
.csr(width
=width
, access
=access
, addr
=addr
,
120 alignment
=alignment
, name
=prefixed_name
)