soc/interconnect/stream_packet: fix Counter removing
[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: clean up code below
9 # XXX
10
11 def reverse_bytes(signal):
12 n = (len(signal)+7)//8
13 r = []
14 for i in reversed(range(n)):
15 r.append(signal[i*8:min((i+1)*8, len(signal))])
16 return Cat(iter(r))
17
18
19 class Status(Module):
20 def __init__(self, endpoint):
21 self.sop = sop = Signal()
22 self.eop = eop =Signal()
23 self.ongoing = Signal()
24
25 ongoing = Signal()
26 self.comb += \
27 If(endpoint.stb,
28 sop.eq(endpoint.sop),
29 eop.eq(endpoint.eop & endpoint.ack)
30 )
31 self.sync += ongoing.eq((sop | ongoing) & ~eop)
32 self.comb += self.ongoing.eq((sop | ongoing) & ~eop)
33
34
35 class Arbiter(Module):
36 def __init__(self, masters, slave):
37 if len(masters) == 0:
38 pass
39 elif len(masters) == 1:
40 self.grant = Signal()
41 self.comb += Record.connect(masters.pop(), slave)
42 else:
43 self.submodules.rr = RoundRobin(len(masters))
44 self.grant = self.rr.grant
45 cases = {}
46 for i, master in enumerate(masters):
47 status = Status(master)
48 self.submodules += status
49 self.comb += self.rr.request[i].eq(status.ongoing)
50 cases[i] = [Record.connect(master, slave)]
51 self.comb += Case(self.grant, cases)
52
53
54 class Dispatcher(Module):
55 def __init__(self, master, slaves, one_hot=False):
56 if len(slaves) == 0:
57 self.sel = Signal()
58 elif len(slaves) == 1:
59 self.comb += Record.connect(master, slaves.pop())
60 self.sel = Signal()
61 else:
62 if one_hot:
63 self.sel = Signal(len(slaves))
64 else:
65 self.sel = Signal(max=len(slaves))
66
67 # # #
68
69 status = Status(master)
70 self.submodules += status
71
72 sel = Signal.like(self.sel)
73 sel_ongoing = Signal.like(self.sel)
74 self.sync += \
75 If(status.sop,
76 sel_ongoing.eq(self.sel)
77 )
78 self.comb += \
79 If(status.sop,
80 sel.eq(self.sel)
81 ).Else(
82 sel.eq(sel_ongoing)
83 )
84 cases = {}
85 for i, slave in enumerate(slaves):
86 if one_hot:
87 idx = 2**i
88 else:
89 idx = i
90 cases[idx] = [Record.connect(master, slave)]
91 cases["default"] = [master.ack.eq(1)]
92 self.comb += Case(sel, cases)
93
94
95 class HeaderField:
96 def __init__(self, byte, offset, width):
97 self.byte = byte
98 self.offset = offset
99 self.width = width
100
101
102 class Header:
103 def __init__(self, fields, length, swap_field_bytes=True):
104 self.fields = fields
105 self.length = length
106 self.swap_field_bytes = swap_field_bytes
107
108 def get_layout(self):
109 layout = []
110 for k, v in sorted(self.fields.items()):
111 layout.append((k, v.width))
112 return layout
113
114 def get_field(self, obj, name, width):
115 if "_lsb" in name:
116 field = getattr(obj, name.replace("_lsb", ""))[:width]
117 elif "_msb" in name:
118 field = getattr(obj, name.replace("_msb", ""))[width:2*width]
119 else:
120 field = getattr(obj, name)
121 return field
122
123 def encode(self, obj, signal):
124 r = []
125 for k, v in sorted(self.fields.items()):
126 start = v.byte*8+v.offset
127 end = start+v.width
128 field = self.get_field(obj, k, v.width)
129 if self.swap_field_bytes:
130 field = reverse_bytes(field)
131 r.append(signal[start:end].eq(field))
132 return r
133
134 def decode(self, signal, obj):
135 r = []
136 for k, v in sorted(self.fields.items()):
137 start = v.byte*8+v.offset
138 end = start+v.width
139 field = self.get_field(obj, k, v.width)
140 if self.swap_field_bytes:
141 r.append(field.eq(reverse_bytes(signal[start:end])))
142 else:
143 r.append(field.eq(signal[start:end]))
144 return r
145
146
147 class Packetizer(Module):
148 def __init__(self, sink_description, source_description, header):
149 self.sink = sink = Sink(sink_description)
150 self.source = source = Source(source_description)
151 self.header = Signal(header.length*8)
152
153 # # #
154
155 dw = len(self.sink.data)
156
157 header_reg = Signal(header.length*8)
158 header_words = (header.length*8)//dw
159 load = Signal()
160 shift = Signal()
161 counter = Signal(max=max(header_words, 2))
162 counter_reset = Signal()
163 counter_ce = Signal()
164 self.sync += \
165 If(counter_reset,
166 counter.eq(0)
167 ).Elif(counter_ce,
168 counter.eq(counter + 1)
169 )
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 == 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 = Signal(max=max(header_words, 2))
253 counter_reset = Signal()
254 counter_ce = Signal()
255 self.sync += \
256 If(counter_reset,
257 counter.eq(0)
258 ).Elif(counter_ce,
259 counter.eq(counter + 1)
260 )
261
262 if header_words == 1:
263 self.sync += \
264 If(shift,
265 self.header.eq(sink.data)
266 )
267 else:
268 self.sync += \
269 If(shift,
270 self.header.eq(Cat(self.header[dw:], sink.data))
271 )
272
273 fsm = FSM(reset_state="IDLE")
274 self.submodules += fsm
275
276 if header_words == 1:
277 idle_next_state = "COPY"
278 else:
279 idle_next_state = "RECEIVE_HEADER"
280
281 fsm.act("IDLE",
282 sink.ack.eq(1),
283 counter_reset.eq(1),
284 If(sink.stb,
285 shift.eq(1),
286 NextState(idle_next_state)
287 )
288 )
289 if header_words != 1:
290 fsm.act("RECEIVE_HEADER",
291 sink.ack.eq(1),
292 If(sink.stb,
293 counter_ce.eq(1),
294 shift.eq(1),
295 If(counter == header_words-2,
296 NextState("COPY")
297 )
298 )
299 )
300 no_payload = Signal()
301 self.sync += \
302 If(fsm.before_entering("COPY"),
303 source.sop.eq(1),
304 no_payload.eq(sink.eop)
305 ).Elif(source.stb & source.ack,
306 source.sop.eq(0)
307 )
308
309 if hasattr(sink, "error"):
310 self.comb += source.error.eq(sink.error)
311 self.comb += [
312 source.eop.eq(sink.eop | no_payload),
313 source.data.eq(sink.data),
314 header.decode(self.header, source)
315 ]
316 fsm.act("COPY",
317 sink.ack.eq(source.ack),
318 source.stb.eq(sink.stb | no_payload),
319 If(source.stb & source.ack & source.eop,
320 NextState("IDLE")
321 )
322 )
323
324
325 class Buffer(Module):
326 def __init__(self, description, data_depth, cmd_depth=4, almost_full=None):
327 self.sink = sink = Sink(description)
328 self.source = source = Source(description)
329
330 # # #
331
332 sink_status = Status(self.sink)
333 source_status = Status(self.source)
334 self.submodules += sink_status, source_status
335
336 # store incoming packets
337 # cmds
338 def cmd_description():
339 layout = [("error", 1)]
340 return EndpointDescription(layout)
341 cmd_fifo = SyncFIFO(cmd_description(), cmd_depth)
342 self.submodules += cmd_fifo
343 self.comb += cmd_fifo.sink.stb.eq(sink_status.eop)
344 if hasattr(sink, "error"):
345 self.comb += cmd_fifo.sink.error.eq(sink.error)
346
347 # data
348 data_fifo = SyncFIFO(description, data_depth, buffered=True)
349 self.submodules += data_fifo
350 self.comb += [
351 Record.connect(self.sink, data_fifo.sink),
352 data_fifo.sink.stb.eq(self.sink.stb & cmd_fifo.sink.ack),
353 self.sink.ack.eq(data_fifo.sink.ack & cmd_fifo.sink.ack),
354 ]
355
356 # output packets
357 self.fsm = fsm = FSM(reset_state="IDLE")
358 self.submodules += fsm
359 fsm.act("IDLE",
360 If(cmd_fifo.source.stb,
361 NextState("SEEK_SOP")
362 )
363 )
364 fsm.act("SEEK_SOP",
365 If(~data_fifo.source.sop,
366 data_fifo.source.ack.eq(1)
367 ).Else(
368 NextState("OUTPUT")
369 )
370 )
371 if hasattr(source, "error"):
372 source_error = self.source.error
373 else:
374 source_error = Signal()
375
376 fsm.act("OUTPUT",
377 Record.connect(data_fifo.source, self.source),
378 source_error.eq(cmd_fifo.source.error),
379 If(source_status.eop,
380 cmd_fifo.source.ack.eq(1),
381 NextState("IDLE")
382 )
383 )
384
385 # compute almost full
386 if almost_full is not None:
387 self.almost_full = Signal()
388 self.comb += self.almost_full.eq(data_fifo.level > almost_full)
389
390 # XXX