add comment about SPRs CSV
[soc.git] / src / soc / minerva / stage.py
1 from functools import reduce
2 from operator import or_
3
4 from nmigen import Elaboratable, Module, Mux, Record, Signal
5 from nmigen.hdl.rec import DIR_FANIN, DIR_FANOUT, DIR_NONE
6
7
8 __all__ = ["Stage"]
9
10
11 def _make_m2s(layout):
12 r = []
13 for f in layout:
14 if isinstance(f[1], (int, tuple)):
15 r.append((f[0], f[1], DIR_FANOUT))
16 else:
17 r.append((f[0], _make_m2s(f[1])))
18 return r
19
20
21 class _EndpointDescription:
22 def __init__(self, payload_layout):
23 self.payload_layout = payload_layout
24
25 def get_full_layout(self):
26 reserved = {"valid", "stall", "kill"}
27 attributed = set()
28 for f in self.payload_layout:
29 if f[0] in attributed:
30 raise ValueError(f[0] + " already attributed in payload layout")
31 if f[0] in reserved:
32 raise ValueError(f[0] + " cannot be used in endpoint layout")
33 attributed.add(f[0])
34
35 full_layout = [
36 ("valid", 1, DIR_FANOUT),
37 ("stall", 1, DIR_FANIN),
38 ("kill", 1, DIR_FANOUT),
39 ("payload", _make_m2s(self.payload_layout))
40 ]
41 return full_layout
42
43
44 class _Endpoint(Record):
45 def __init__(self, layout):
46 self.description = _EndpointDescription(layout)
47 super().__init__(self.description.get_full_layout())
48
49 def __getattr__(self, name):
50 try:
51 return super().__getattr__(name)
52 except AttributeError:
53 return self.fields["payload"][name]
54
55
56 class Stage(Elaboratable):
57 def __init__(self, sink_layout, source_layout):
58 self.kill = Signal()
59 self.stall = Signal()
60 self.valid = Signal()
61
62 if sink_layout is None and source_layout is None:
63 raise ValueError
64 if sink_layout is not None:
65 self.sink = _Endpoint(sink_layout)
66 if source_layout is not None:
67 self.source = _Endpoint(source_layout)
68
69 self._kill_sources = []
70 self._stall_sources = []
71
72 def kill_on(self, cond):
73 self._kill_sources.append(cond)
74
75 def stall_on(self, cond):
76 self._stall_sources.append(cond)
77
78 def elaborate(self, platform):
79 m = Module()
80
81 if hasattr(self, "sink"):
82 m.d.comb += [
83 self.valid.eq(self.sink.valid & ~self.sink.kill),
84 self.sink.stall.eq(self.stall)
85 ]
86
87 if hasattr(self, "source"):
88 with m.If(~self.stall):
89 m.d.sync += self.source.valid.eq(self.valid)
90 with m.Elif(~self.source.stall | self.kill):
91 m.d.sync += self.source.valid.eq(0)
92 self.stall_on(self.source.stall)
93 m.d.comb += [
94 self.source.kill.eq(self.kill),
95 self.kill.eq(reduce(or_, self._kill_sources, 0))
96 ]
97
98 m.d.comb += self.stall.eq(reduce(or_, self._stall_sources, 0))
99
100 return m