soc/interconnect: rename packet to stream_packet
[litex.git] / litex / soc / interconnect / stream_packet.py
1 from litex.gen import *
2 from litex.gen.genlib.roundrobin import *
3 from litex.gen.genlib.record import *
4 from litex.gen.genlib.fsm import FSM, NextState
5
6 from litex.soc.interconnect.stream import *
7
8 # TODO: move reverse_bytes / Counter
9
10 def reverse_bytes(signal):
11 n = (len(signal)+7)//8
12 r = []
13 for i in reversed(range(n)):
14 r.append(signal[i*8:min((i+1)*8, len(signal))])
15 return Cat(iter(r))
16
17
18 @ResetInserter()
19 @CEInserter()
20 class Counter(Module):
21 def __init__(self, *args, increment=1, **kwargs):
22 self.value = Signal(*args, **kwargs)
23 self.width = len(self.value)
24 self.sync += self.value.eq(self.value+increment)
25
26 class Status(Module):
27 def __init__(self, endpoint):
28 self.sop = sop = Signal()
29 self.eop = eop =Signal()
30 self.ongoing = Signal()
31
32 ongoing = Signal()
33 self.comb += \
34 If(endpoint.stb,
35 sop.eq(endpoint.sop),
36 eop.eq(endpoint.eop & endpoint.ack)
37 )
38 self.sync += ongoing.eq((sop | ongoing) & ~eop)
39 self.comb += self.ongoing.eq((sop | ongoing) & ~eop)
40
41
42 class Arbiter(Module):
43 def __init__(self, masters, slave):
44 if len(masters) == 0:
45 pass
46 elif len(masters) == 1:
47 self.grant = Signal()
48 self.comb += Record.connect(masters.pop(), slave)
49 else:
50 self.submodules.rr = RoundRobin(len(masters))
51 self.grant = self.rr.grant
52 cases = {}
53 for i, master in enumerate(masters):
54 status = Status(master)
55 self.submodules += status
56 self.comb += self.rr.request[i].eq(status.ongoing)
57 cases[i] = [Record.connect(master, slave)]
58 self.comb += Case(self.grant, cases)
59
60
61 class Dispatcher(Module):
62 def __init__(self, master, slaves, one_hot=False):
63 if len(slaves) == 0:
64 self.sel = Signal()
65 elif len(slaves) == 1:
66 self.comb += Record.connect(master, slaves.pop())
67 self.sel = Signal()
68 else:
69 if one_hot:
70 self.sel = Signal(len(slaves))
71 else:
72 self.sel = Signal(max=len(slaves))
73
74 # # #
75
76 status = Status(master)
77 self.submodules += status
78
79 sel = Signal.like(self.sel)
80 sel_ongoing = Signal.like(self.sel)
81 self.sync += \
82 If(status.sop,
83 sel_ongoing.eq(self.sel)
84 )
85 self.comb += \
86 If(status.sop,
87 sel.eq(self.sel)
88 ).Else(
89 sel.eq(sel_ongoing)
90 )
91 cases = {}
92 for i, slave in enumerate(slaves):
93 if one_hot:
94 idx = 2**i
95 else:
96 idx = i
97 cases[idx] = [Record.connect(master, slave)]
98 cases["default"] = [master.ack.eq(1)]
99 self.comb += Case(sel, cases)
100
101
102 class HeaderField:
103 def __init__(self, byte, offset, width):
104 self.byte = byte
105 self.offset = offset
106 self.width = width
107
108
109 class Header:
110 def __init__(self, fields, length, swap_field_bytes=True):
111 self.fields = fields
112 self.length = length
113 self.swap_field_bytes = swap_field_bytes
114
115 def get_layout(self):
116 layout = []
117 for k, v in sorted(self.fields.items()):
118 layout.append((k, v.width))
119 return layout
120
121 def get_field(self, obj, name, width):
122 if "_lsb" in name:
123 field = getattr(obj, name.replace("_lsb", ""))[:width]
124 elif "_msb" in name:
125 field = getattr(obj, name.replace("_msb", ""))[width:2*width]
126 else:
127 field = getattr(obj, name)
128 return field
129
130 def encode(self, obj, signal):
131 r = []
132 for k, v in sorted(self.fields.items()):
133 start = v.byte*8+v.offset
134 end = start+v.width
135 field = self.get_field(obj, k, v.width)
136 if self.swap_field_bytes:
137 field = reverse_bytes(field)
138 r.append(signal[start:end].eq(field))
139 return r
140
141 def decode(self, signal, obj):
142 r = []
143 for k, v in sorted(self.fields.items()):
144 start = v.byte*8+v.offset
145 end = start+v.width
146 field = self.get_field(obj, k, v.width)
147 if self.swap_field_bytes:
148 r.append(field.eq(reverse_bytes(signal[start:end])))
149 else:
150 r.append(field.eq(signal[start:end]))
151 return r
152
153
154 class Packetizer(Module):
155 def __init__(self, sink_description, source_description, header):
156 self.sink = sink = Sink(sink_description)
157 self.source = source = Source(source_description)
158 self.header = Signal(header.length*8)
159
160 # # #
161
162 dw = len(self.sink.data)
163
164 header_reg = Signal(header.length*8)
165 header_words = (header.length*8)//dw
166 load = Signal()
167 shift = Signal()
168 counter = Counter(max=max(header_words, 2))
169 self.submodules += counter
170
171 self.comb += header.encode(sink, self.header)
172 if header_words == 1:
173 self.sync += [
174 If(load,
175 header_reg.eq(self.header)
176 )
177 ]
178 else:
179 self.sync += [
180 If(load,
181 header_reg.eq(self.header)
182 ).Elif(shift,
183 header_reg.eq(Cat(header_reg[dw:], Signal(dw)))
184 )
185 ]
186
187 fsm = FSM(reset_state="IDLE")
188 self.submodules += fsm
189
190 if header_words == 1:
191 idle_next_state = "COPY"
192 else:
193 idle_next_state = "SEND_HEADER"
194
195 fsm.act("IDLE",
196 sink.ack.eq(1),
197 counter.reset.eq(1),
198 If(sink.stb & sink.sop,
199 sink.ack.eq(0),
200 source.stb.eq(1),
201 source.sop.eq(1),
202 source.eop.eq(0),
203 source.data.eq(self.header[:dw]),
204 If(source.stb & source.ack,
205 load.eq(1),
206 NextState(idle_next_state)
207 )
208 )
209 )
210 if header_words != 1:
211 fsm.act("SEND_HEADER",
212 source.stb.eq(1),
213 source.sop.eq(0),
214 source.eop.eq(0),
215 source.data.eq(header_reg[dw:2*dw]),
216 If(source.stb & source.ack,
217 shift.eq(1),
218 counter.ce.eq(1),
219 If(counter.value == header_words-2,
220 NextState("COPY")
221 )
222 )
223 )
224 fsm.act("COPY",
225 source.stb.eq(sink.stb),
226 source.sop.eq(0),
227 source.eop.eq(sink.eop),
228 source.data.eq(sink.data),
229 source.error.eq(sink.error),
230 If(source.stb & source.ack,
231 sink.ack.eq(1),
232 If(source.eop,
233 NextState("IDLE")
234 )
235 )
236 )
237
238
239 class Depacketizer(Module):
240 def __init__(self, sink_description, source_description, header):
241 self.sink = sink = Sink(sink_description)
242 self.source = source = Source(source_description)
243 self.header = Signal(header.length*8)
244
245 # # #
246
247 dw = len(sink.data)
248
249 header_words = (header.length*8)//dw
250
251 shift = Signal()
252 counter = Counter(max=max(header_words, 2))
253 self.submodules += counter
254
255 if header_words == 1:
256 self.sync += \
257 If(shift,
258 self.header.eq(sink.data)
259 )
260 else:
261 self.sync += \
262 If(shift,
263 self.header.eq(Cat(self.header[dw:], sink.data))
264 )
265
266 fsm = FSM(reset_state="IDLE")
267 self.submodules += fsm
268
269 if header_words == 1:
270 idle_next_state = "COPY"
271 else:
272 idle_next_state = "RECEIVE_HEADER"
273
274 fsm.act("IDLE",
275 sink.ack.eq(1),
276 counter.reset.eq(1),
277 If(sink.stb,
278 shift.eq(1),
279 NextState(idle_next_state)
280 )
281 )
282 if header_words != 1:
283 fsm.act("RECEIVE_HEADER",
284 sink.ack.eq(1),
285 If(sink.stb,
286 counter.ce.eq(1),
287 shift.eq(1),
288 If(counter.value == header_words-2,
289 NextState("COPY")
290 )
291 )
292 )
293 no_payload = Signal()
294 self.sync += \
295 If(fsm.before_entering("COPY"),
296 source.sop.eq(1),
297 no_payload.eq(sink.eop)
298 ).Elif(source.stb & source.ack,
299 source.sop.eq(0)
300 )
301
302 if hasattr(sink, "error"):
303 self.comb += source.error.eq(sink.error)
304 self.comb += [
305 source.eop.eq(sink.eop | no_payload),
306 source.data.eq(sink.data),
307 header.decode(self.header, source)
308 ]
309 fsm.act("COPY",
310 sink.ack.eq(source.ack),
311 source.stb.eq(sink.stb | no_payload),
312 If(source.stb & source.ack & source.eop,
313 NextState("IDLE")
314 )
315 )
316
317
318 class Buffer(Module):
319 def __init__(self, description, data_depth, cmd_depth=4, almost_full=None):
320 self.sink = sink = Sink(description)
321 self.source = source = Source(description)
322
323 # # #
324
325 sink_status = Status(self.sink)
326 source_status = Status(self.source)
327 self.submodules += sink_status, source_status
328
329 # store incoming packets
330 # cmds
331 def cmd_description():
332 layout = [("error", 1)]
333 return EndpointDescription(layout)
334 cmd_fifo = SyncFIFO(cmd_description(), cmd_depth)
335 self.submodules += cmd_fifo
336 self.comb += cmd_fifo.sink.stb.eq(sink_status.eop)
337 if hasattr(sink, "error"):
338 self.comb += cmd_fifo.sink.error.eq(sink.error)
339
340 # data
341 data_fifo = SyncFIFO(description, data_depth, buffered=True)
342 self.submodules += data_fifo
343 self.comb += [
344 Record.connect(self.sink, data_fifo.sink),
345 data_fifo.sink.stb.eq(self.sink.stb & cmd_fifo.sink.ack),
346 self.sink.ack.eq(data_fifo.sink.ack & cmd_fifo.sink.ack),
347 ]
348
349 # output packets
350 self.fsm = fsm = FSM(reset_state="IDLE")
351 self.submodules += fsm
352 fsm.act("IDLE",
353 If(cmd_fifo.source.stb,
354 NextState("SEEK_SOP")
355 )
356 )
357 fsm.act("SEEK_SOP",
358 If(~data_fifo.source.sop,
359 data_fifo.source.ack.eq(1)
360 ).Else(
361 NextState("OUTPUT")
362 )
363 )
364 if hasattr(source, "error"):
365 source_error = self.source.error
366 else:
367 source_error = Signal()
368
369 fsm.act("OUTPUT",
370 Record.connect(data_fifo.source, self.source),
371 source_error.eq(cmd_fifo.source.error),
372 If(source_status.eop,
373 cmd_fifo.source.ack.eq(1),
374 NextState("IDLE")
375 )
376 )
377
378 # compute almost full
379 if almost_full is not None:
380 self.almost_full = Signal()
381 self.comb += self.almost_full.eq(data_fifo.fifo.level > almost_full)