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