1 from functools
import reduce
2 from operator
import or_
5 from nmigen
.hdl
.rec
import *
11 def _make_m2s(layout
):
14 if isinstance(f
[1], (int, tuple)):
15 r
.append((f
[0], f
[1], DIR_FANOUT
))
17 r
.append((f
[0], _make_m2s(f
[1])))
21 class _EndpointDescription
:
22 def __init__(self
, payload_layout
):
23 self
.payload_layout
= payload_layout
25 def get_full_layout(self
):
26 reserved
= {"valid", "stall", "kill"}
28 for f
in self
.payload_layout
:
29 if f
[0] in attributed
:
30 raise ValueError(f
[0] + " already attributed in payload layout")
32 raise ValueError(f
[0] + " cannot be used in endpoint layout")
36 ("valid", 1, DIR_FANOUT
),
37 ("stall", 1, DIR_FANIN
),
38 ("kill", 1, DIR_FANOUT
),
39 ("payload", _make_m2s(self
.payload_layout
))
44 class _Endpoint(Record
):
45 def __init__(self
, layout
):
46 self
.description
= _EndpointDescription(layout
)
47 super().__init
__(self
.description
.get_full_layout())
49 def __getattr__(self
, name
):
51 return super().__getattr
__(name
)
52 except AttributeError:
53 return self
.fields
["payload"][name
]
56 class Stage(Elaboratable
):
57 def __init__(self
, sink_layout
, source_layout
):
62 if sink_layout
is None and source_layout
is None:
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
)
69 self
._kill
_sources
= []
70 self
._stall
_sources
= []
72 def kill_on(self
, cond
):
73 self
._kill
_sources
.append(cond
)
75 def stall_on(self
, cond
):
76 self
._stall
_sources
.append(cond
)
78 def elaborate(self
, platform
):
81 if hasattr(self
, "sink"):
83 self
.valid
.eq(self
.sink
.valid
& ~self
.sink
.kill
),
84 self
.sink
.stall
.eq(self
.stall
)
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
)
94 self
.source
.kill
.eq(self
.kill
),
95 self
.kill
.eq(reduce(or_
, self
._kill
_sources
, 0))
98 m
.d
.comb
+= self
.stall
.eq(reduce(or_
, self
._stall
_sources
, 0))