Connect dramcore to SoC bus in ECPIX-5 example
[gram.git] / gram / compat.py
1 # This file is Copyright (c) 2020 LambdaConcept <contact@lambdaconcept.com>
2
3 from nmigen import *
4 from nmigen import tracer
5 from nmigen.compat import Case
6
7 __ALL__ = ["delayed_enter", "RoundRobin", "Timeline", "CSRPrefixProxy"]
8
9 def delayed_enter(m, src, dst, delay):
10 assert delay > 0
11
12 for i in range(delay):
13 if i == 0:
14 statename = src
15 else:
16 statename = "{}-{}".format(src, i)
17
18 if i == delay-1:
19 deststate = dst
20 else:
21 deststate = "{}-{}".format(src, i+1)
22
23 with m.State(statename):
24 m.next = deststate
25
26 # Original nMigen implementation by HarryHo90sHK
27 class RoundRobin(Elaboratable):
28 """A round-robin scheduler.
29 Parameters
30 ----------
31 n : int
32 Maximum number of requests to handle.
33 Attributes
34 ----------
35 request : Signal(n)
36 Signal where a '1' on the i-th bit represents an incoming request from the i-th device.
37 grant : Signal(range(n))
38 Signal that equals to the index of the device which is currently granted access.
39 stb : Signal()
40 Strobe signal to enable granting access to the next device requesting. Externally driven.
41 """
42 def __init__(self, n):
43 self.n = n
44 self.request = Signal(n)
45 self.grant = Signal(range(n))
46 self.stb = Signal()
47
48 def elaborate(self, platform):
49 m = Module()
50
51 with m.If(self.stb):
52 with m.Switch(self.grant):
53 for i in range(self.n):
54 with m.Case(i):
55 for j in reversed(range(i+1, i+self.n)):
56 # If i+1 <= j < n, then t == j; (after i)
57 # If n <= j < i+n, then t == j - n (before i)
58 t = j % self.n
59 with m.If(self.request[t]):
60 m.d.sync += self.grant.eq(t)
61
62 return m
63
64 class Timeline(Elaboratable):
65 def __init__(self, events):
66 self.trigger = Signal()
67 self._events = events
68
69 def elaborate(self, platform):
70 m = Module()
71
72 lastevent = max([e[0] for e in self._events])
73 counter = Signal(range(lastevent+1))
74
75 # Counter incrementation
76 # (with overflow handling)
77 if (lastevent & (lastevent + 1)) != 0:
78 with m.If(counter == lastevent):
79 m.d.sync += counter.eq(0)
80 with m.Else():
81 with m.If(counter != 0):
82 m.d.sync += counter.eq(counter+1)
83 with m.Elif(self.trigger):
84 m.d.sync += counter.eq(1)
85 else:
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)
90
91 for e in self._events:
92 if e[0] == 0:
93 with m.If(self.trigger & (counter == 0)):
94 m.d.sync += e[1]
95 else:
96 with m.If(counter == e[0]):
97 m.d.sync += e[1]
98
99 return m
100
101 class CSRPrefixProxy:
102 def __init__(self, bank, prefix):
103 self._bank = bank
104 self._prefix = prefix
105
106 def csr(self, width, access, *, addr=None, alignment=None, name=None,
107 src_loc_at=0):
108 if name is not None and not isinstance(name, str):
109 raise TypeError("Name must be a string, not {!r}".format(name))
110 name = name or tracer.get_var_name(depth=2 + src_loc_at).lstrip("_")
111
112 prefixed_name = "{}_{}".format(self._prefix, name)
113 return self._bank.csr(width=width, access=access, addr=addr,
114 alignment=alignment, name=prefixed_name)