2 from migen
.genlib
.record
import *
3 from migen
.genlib
import fifo
9 if isinstance(f
[1], (int, tuple)):
10 r
.append((f
[0], f
[1], DIR_M_TO_S
))
12 r
.append((f
[0], _make_m2s(f
[1])))
16 class EndpointDescription
:
17 def __init__(self
, payload_layout
, packetized
=False):
18 self
.payload_layout
= payload_layout
19 self
.packetized
= packetized
21 def get_full_layout(self
):
22 reserved
= {"stb", "ack", "payload", "sop", "eop", "description"}
24 for f
in self
.payload_layout
:
25 if f
[0] in attributed
:
26 raise ValueError(f
[0] + " already attributed in payload layout")
28 raise ValueError(f
[0] + " cannot be used in endpoint layout")
32 ("payload", _make_m2s(self
.payload_layout
)),
33 ("stb", 1, DIR_M_TO_S
),
34 ("ack", 1, DIR_S_TO_M
)
38 ("sop", 1, DIR_M_TO_S
),
39 ("eop", 1, DIR_M_TO_S
)
44 class _Endpoint(Record
):
45 def __init__(self
, description_or_layout
):
46 if isinstance(description_or_layout
, EndpointDescription
):
47 self
.description
= description_or_layout
49 self
.description
= EndpointDescription(description_or_layout
)
50 Record
.__init
__(self
, self
.description
.get_full_layout())
52 def __getattr__(self
, name
):
53 return getattr(object.__getattribute
__(self
, "payload"), name
)
56 class Source(_Endpoint
):
57 def connect(self
, sink
):
58 return Record
.connect(self
, sink
)
61 class Sink(_Endpoint
):
62 def connect(self
, source
):
63 return source
.connect(self
)
66 class _FIFOWrapper(Module
):
67 def __init__(self
, fifo_class
, layout
, depth
):
68 self
.sink
= Sink(layout
)
69 self
.source
= Source(layout
)
74 description
= self
.sink
.description
75 fifo_layout
= [("payload", description
.payload_layout
)]
76 if description
.packetized
:
77 fifo_layout
+= [("sop", 1), ("eop", 1)]
79 self
.submodules
.fifo
= fifo_class(layout_len(fifo_layout
), depth
)
80 fifo_in
= Record(fifo_layout
)
81 fifo_out
= Record(fifo_layout
)
83 self
.fifo
.din
.eq(fifo_in
.raw_bits()),
84 fifo_out
.raw_bits().eq(self
.fifo
.dout
)
88 self
.sink
.ack
.eq(self
.fifo
.writable
),
89 self
.fifo
.we
.eq(self
.sink
.stb
),
90 fifo_in
.payload
.eq(self
.sink
.payload
),
92 self
.source
.stb
.eq(self
.fifo
.readable
),
93 self
.source
.payload
.eq(fifo_out
.payload
),
94 self
.fifo
.re
.eq(self
.source
.ack
)
96 if description
.packetized
:
98 fifo_in
.sop
.eq(self
.sink
.sop
),
99 fifo_in
.eop
.eq(self
.sink
.eop
),
100 self
.source
.sop
.eq(fifo_out
.sop
),
101 self
.source
.eop
.eq(fifo_out
.eop
)
105 class SyncFIFO(_FIFOWrapper
):
106 def __init__(self
, layout
, depth
, buffered
=False):
107 _FIFOWrapper
.__init
__(
109 fifo
.SyncFIFOBuffered
if buffered
else fifo
.SyncFIFO
,
113 class AsyncFIFO(_FIFOWrapper
):
114 def __init__(self
, layout
, depth
):
115 _FIFOWrapper
.__init
__(self
, fifo
.AsyncFIFO
, layout
, depth
)
118 class Multiplexer(Module
):
119 def __init__(self
, layout
, n
):
120 self
.source
= Source(layout
)
124 setattr(self
, "sink"+str(i
), sink
)
126 self
.sel
= Signal(max=n
)
131 for i
, sink
in enumerate(sinks
):
132 cases
[i
] = Record
.connect(sink
, self
.source
)
133 self
.comb
+= Case(self
.sel
, cases
)
136 class Demultiplexer(Module
):
137 def __init__(self
, layout
, n
):
138 self
.sink
= Sink(layout
)
141 source
= Source(layout
)
142 setattr(self
, "source"+str(i
), source
)
143 sources
.append(source
)
144 self
.sel
= Signal(max=n
)
149 for i
, source
in enumerate(sources
):
150 cases
[i
] = Record
.connect(self
.sink
, source
)
151 self
.comb
+= Case(self
.sel
, cases
)
153 # TODO: clean up code below
156 from copy
import copy
157 from migen
.util
.misc
import xdir
159 def pack_layout(l
, n
):
160 return [("chunk"+str(i
), l
) for i
in range(n
)]
162 def get_endpoints(obj
, filt
=_Endpoint
):
163 if hasattr(obj
, "get_endpoints") and callable(obj
.get_endpoints
):
164 return obj
.get_endpoints(filt
)
166 for k
, v
in xdir(obj
, True):
167 if isinstance(v
, filt
):
171 def get_single_ep(obj
, filt
):
172 eps
= get_endpoints(obj
, filt
)
174 raise ValueError("More than one endpoint")
175 return list(eps
.items())[0]
178 class BinaryActor(Module
):
179 def __init__(self
, *args
, **kwargs
):
181 sink
= get_single_ep(self
, Sink
)[1]
182 source
= get_single_ep(self
, Source
)[1]
183 self
.build_binary_control(sink
, source
, *args
, **kwargs
)
185 def build_binary_control(self
, sink
, source
):
186 raise NotImplementedError("Binary actor classes must overload build_binary_control_fragment")
189 class CombinatorialActor(BinaryActor
):
190 def build_binary_control(self
, sink
, source
):
192 source
.stb
.eq(sink
.stb
),
193 sink
.ack
.eq(source
.ack
),
196 if sink
.description
.packetized
:
198 source
.sop
.eq(sink
.sop
),
199 source
.eop
.eq(sink
.eop
)
203 class Unpack(Module
):
204 def __init__(self
, n
, layout_to
, reverse
=False):
205 self
.source
= source
= Source(layout_to
)
206 description_from
= copy(source
.description
)
207 description_from
.payload_layout
= pack_layout(description_from
.payload_layout
, n
)
208 self
.sink
= sink
= Sink(description_from
)
219 last
.eq(mux
== (n
-1)),
220 source
.stb
.eq(sink
.stb
),
221 sink
.ack
.eq(last
& source
.ack
)
224 If(source
.stb
& source
.ack
,
234 chunk
= n
-i
-1 if reverse
else i
235 cases
[i
] = [source
.payload
.raw_bits().eq(getattr(sink
.payload
, "chunk"+str(chunk
)).raw_bits())]
236 self
.comb
+= Case(mux
, cases
).makedefault()
238 if description_from
.packetized
:
240 source
.sop
.eq(sink
.sop
& first
),
241 source
.eop
.eq(sink
.eop
& last
)
246 def __init__(self
, layout_from
, n
, reverse
=False):
247 self
.sink
= sink
= Sink(layout_from
)
248 description_to
= copy(sink
.description
)
249 description_to
.payload_layout
= pack_layout(description_to
.payload_layout
, n
)
250 self
.source
= source
= Source(description_to
)
255 demux
= Signal(max=n
)
258 strobe_all
= Signal()
261 chunk
= n
-i
-1 if reverse
else i
262 cases
[i
] = [getattr(source
.payload
, "chunk"+str(chunk
)).raw_bits().eq(sink
.payload
.raw_bits())]
264 self
.busy
.eq(strobe_all
),
265 sink
.ack
.eq(~strobe_all | source
.ack
),
266 source
.stb
.eq(strobe_all
),
267 load_part
.eq(sink
.stb
& sink
.ack
)
270 if description_to
.packetized
:
271 demux_last
= ((demux
== (n
- 1)) | sink
.eop
)
273 demux_last
= (demux
== (n
- 1))
276 If(source
.ack
, strobe_all
.eq(0)),
288 if description_to
.packetized
:
290 If(source
.stb
& source
.ack
,
291 source
.sop
.eq(sink
.sop
),
292 source
.eop
.eq(sink
.eop
),
293 ).Elif(sink
.stb
& sink
.ack
,
294 source
.sop
.eq(sink
.sop | source
.sop
),
295 source
.eop
.eq(sink
.eop | source
.eop
)
300 class Chunkerize(CombinatorialActor
):
301 def __init__(self
, layout_from
, layout_to
, n
, reverse
=False):
302 self
.sink
= Sink(layout_from
)
303 if isinstance(layout_to
, EndpointDescription
):
304 layout_to
= copy(layout_to
)
305 layout_to
.payload_layout
= pack_layout(layout_to
.payload_layout
, n
)
307 layout_to
= pack_layout(layout_to
, n
)
308 self
.source
= Source(layout_to
)
309 CombinatorialActor
.__init
__(self
)
314 chunk
= n
-i
-1 if reverse
else i
315 for f
in self
.sink
.description
.payload_layout
:
316 src
= getattr(self
.sink
, f
[0])
317 dst
= getattr(getattr(self
.source
, "chunk"+str(chunk
)), f
[0])
318 self
.comb
+= dst
.eq(src
[i
*len(src
)//n
:(i
+1)*len(src
)//n
])
321 class Unchunkerize(CombinatorialActor
):
322 def __init__(self
, layout_from
, n
, layout_to
, reverse
=False):
323 if isinstance(layout_from
, EndpointDescription
):
324 fields
= layout_from
.payload_layout
325 layout_from
= copy(layout_from
)
326 layout_from
.payload_layout
= pack_layout(layout_from
.payload_layout
, n
)
329 layout_from
= pack_layout(layout_from
, n
)
330 self
.sink
= Sink(layout_from
)
331 self
.source
= Source(layout_to
)
332 CombinatorialActor
.__init
__(self
)
337 chunk
= n
-i
-1 if reverse
else i
339 src
= getattr(getattr(self
.sink
, "chunk"+str(chunk
)), f
[0])
340 dst
= getattr(self
.source
, f
[0])
341 self
.comb
+= dst
[i
*len(dst
)//n
:(i
+1)*len(dst
)//n
].eq(src
)
344 class Converter(Module
):
345 def __init__(self
, layout_from
, layout_to
, reverse
=False):
346 self
.sink
= Sink(layout_from
)
347 self
.source
= Source(layout_to
)
352 width_from
= len(self
.sink
.payload
.raw_bits())
353 width_to
= len(self
.source
.payload
.raw_bits())
356 if width_from
> width_to
:
357 if width_from
% width_to
:
359 ratio
= width_from
//width_to
360 self
.submodules
.chunkerize
= Chunkerize(layout_from
, layout_to
, ratio
, reverse
)
361 self
.submodules
.unpack
= Unpack(ratio
, layout_to
)
364 Record
.connect(self
.sink
, self
.chunkerize
.sink
),
365 Record
.connect(self
.chunkerize
.source
, self
.unpack
.sink
),
366 Record
.connect(self
.unpack
.source
, self
.source
),
367 self
.busy
.eq(self
.unpack
.busy
)
370 elif width_to
> width_from
:
371 if width_to
% width_from
:
373 ratio
= width_to
//width_from
374 self
.submodules
.pack
= Pack(layout_from
, ratio
)
375 self
.submodules
.unchunkerize
= Unchunkerize(layout_from
, ratio
, layout_to
, reverse
)
378 Record
.connect(self
.sink
, self
.pack
.sink
),
379 Record
.connect(self
.pack
.source
, self
.unchunkerize
.sink
),
380 Record
.connect(self
.unchunkerize
.source
, self
.source
),
381 self
.busy
.eq(self
.pack
.busy
)
385 self
.comb
+= Record
.connect(self
.sink
, self
.source
)