1 # This file is Copyright (c) 2020 LambdaConcept <contact@lambdaconcept.com>
6 from nmigen
import tracer
7 from nmigen
.compat
import Case
8 from nmigen
.back
.pysim
import *
10 __ALL__
= ["delayed_enter", "RoundRobin", "Timeline", "CSRPrefixProxy"]
13 def delayed_enter(m
, src
, dst
, delay
):
16 for i
in range(delay
):
20 statename
= "{}-{}".format(src
, i
)
25 deststate
= "{}-{}".format(src
, i
+1)
27 with m
.State(statename
):
30 class RoundRobin(Elaboratable
):
31 """A round-robin scheduler. (HarryHo90sHK)
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 m
.d
.comb
+= self
.grant
.eq(0)
59 with m
.Switch(self
.grant
):
60 for i
in range(self
.n
):
62 for j
in reversed(range(i
+1, i
+self
.n
)):
63 # If i+1 <= j < n, then t == j; (after i)
64 # If n <= j < i+n, then t == j - n (before i)
66 with m
.If(self
.request
[t
]):
67 m
.d
.sync
+= self
.grant
.eq(t
)
72 class Timeline(Elaboratable
):
73 def __init__(self
, events
):
74 self
.trigger
= Signal()
77 def elaborate(self
, platform
):
80 lastevent
= max([e
[0] for e
in self
._events
])
81 counter
= Signal(range(lastevent
+1))
83 # Counter incrementation
84 # (with overflow handling)
85 if (lastevent
& (lastevent
+ 1)) != 0:
86 with m
.If(counter
== lastevent
):
87 m
.d
.sync
+= counter
.eq(0)
89 with m
.If(counter
!= 0):
90 m
.d
.sync
+= counter
.eq(counter
+1)
91 with m
.Elif(self
.trigger
):
92 m
.d
.sync
+= counter
.eq(1)
94 with m
.If(counter
!= 0):
95 m
.d
.sync
+= counter
.eq(counter
+1)
96 with m
.Elif(self
.trigger
):
97 m
.d
.sync
+= counter
.eq(1)
99 for e
in self
._events
:
101 with m
.If(self
.trigger
& (counter
== 0)):
104 with m
.If(counter
== e
[0]):
110 class CSRPrefixProxy
:
111 def __init__(self
, bank
, prefix
):
113 self
._prefix
= prefix
115 def csr(self
, width
, access
, *, addr
=None, alignment
=None, name
=None,
117 if name
is not None and not isinstance(name
, str):
118 raise TypeError("Name must be a string, not {!r}".format(name
))
119 name
= name
or tracer
.get_var_name(depth
=2 + src_loc_at
).lstrip("_")
121 prefixed_name
= "{}_{}".format(self
._prefix
, name
)
122 return self
._bank
.csr(width
=width
, access
=access
, addr
=addr
,
123 alignment
=alignment
, name
=prefixed_name
)