Bugfixing
[gram.git] / gram / compat.py
1 from nmigen import *
2 from nmigen.compat import Case
3
4 __ALL__ = ["delayed_enter", "RoundRobin", "Timeline"]
5
6 def delayed_enter(m, src, dst, delay):
7 assert delay > 0
8
9 for i in range(delay):
10 if i == 0:
11 statename = src
12 else:
13 statename = "{}-{}".format(src, i)
14
15 if i == delay-1:
16 deststate = dst
17 else:
18 deststate = "{}-{}".format(src, i+1)
19
20 with m.State(statename):
21 m.next = deststate
22
23 # Original nMigen implementation by HarryHo90sHK
24 class RoundRobin(Elaboratable):
25 """A round-robin scheduler.
26 Parameters
27 ----------
28 n : int
29 Maximum number of requests to handle.
30 Attributes
31 ----------
32 request : Signal(n)
33 Signal where a '1' on the i-th bit represents an incoming request from the i-th device.
34 grant : Signal(range(n))
35 Signal that equals to the index of the device which is currently granted access.
36 stb : Signal()
37 Strobe signal to enable granting access to the next device requesting. Externally driven.
38 """
39 def __init__(self, n):
40 self.n = n
41 self.request = Signal(n)
42 self.grant = Signal(range(n))
43 self.stb = Signal()
44
45 def elaborate(self, platform):
46 m = Module()
47
48 with m.If(self.stb):
49 with m.Switch(self.grant):
50 for i in range(self.n):
51 with m.Case(i):
52 for j in reversed(range(i+1, i+self.n)):
53 # If i+1 <= j < n, then t == j; (after i)
54 # If n <= j < i+n, then t == j - n (before i)
55 t = j % self.n
56 with m.If(self.request[t]):
57 m.d.sync += self.grant.eq(t)
58
59 return m
60
61 class Timeline(Elaboratable):
62 def __init__(self, events):
63 self.trigger = Signal()
64 self._events = events
65
66 def elaborate(self, platform):
67 m = Module()
68
69 lastevent = max([e[0] for e in self._events])
70 counter = Signal(range(lastevent+1))
71
72 # Counter incrementation
73 # (with overflow handling)
74 if (lastevent & (lastevent + 1)) != 0:
75 with m.If(counter == lastevent):
76 m.d.sync += counter.eq(0)
77 with m.Else():
78 with m.If(counter != 0):
79 m.d.sync += counter.eq(counter+1)
80 with m.Elif(self.trigger):
81 m.d.sync += counter.eq(1)
82 else:
83 with m.If(counter != 0):
84 m.d.sync += counter.eq(counter+1)
85 with m.Elif(self.trigger):
86 m.d.sync += counter.eq(1)
87
88 for e in self._events:
89 if e[0] == 0:
90 with m.If(self.trigger & (counter == 0)):
91 m.d.sync += e[1]
92 else:
93 with m.If(counter == e[0]):
94 m.d.sync += e[1]
95
96 return m