bb4ab736de46d13a43414b7fc15e48f0cbbe159c
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
6 from litex
.soc
.interconnect
.stream
import *
8 # TODO: clean up code below
11 def reverse_bytes(signal
):
12 n
= (len(signal
)+7)//8
14 for i
in reversed(range(n
)):
15 r
.append(signal
[i
*8:min((i
+1)*8, len(signal
))])
20 def __init__(self
, endpoint
):
21 self
.sop
= sop
= Signal()
22 self
.eop
= eop
=Signal()
23 self
.ongoing
= Signal()
29 eop
.eq(endpoint
.eop
& endpoint
.ack
)
31 self
.sync
+= ongoing
.eq((sop | ongoing
) & ~eop
)
32 self
.comb
+= self
.ongoing
.eq((sop | ongoing
) & ~eop
)
35 class Arbiter(Module
):
36 def __init__(self
, masters
, slave
):
39 elif len(masters
) == 1:
41 self
.comb
+= Record
.connect(masters
.pop(), slave
)
43 self
.submodules
.rr
= RoundRobin(len(masters
))
44 self
.grant
= self
.rr
.grant
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
)
54 class Dispatcher(Module
):
55 def __init__(self
, master
, slaves
, one_hot
=False):
58 elif len(slaves
) == 1:
59 self
.comb
+= Record
.connect(master
, slaves
.pop())
63 self
.sel
= Signal(len(slaves
))
65 self
.sel
= Signal(max=len(slaves
))
69 status
= Status(master
)
70 self
.submodules
+= status
72 sel
= Signal
.like(self
.sel
)
73 sel_ongoing
= Signal
.like(self
.sel
)
76 sel_ongoing
.eq(self
.sel
)
85 for i
, slave
in enumerate(slaves
):
90 cases
[idx
] = [Record
.connect(master
, slave
)]
91 cases
["default"] = [master
.ack
.eq(1)]
92 self
.comb
+= Case(sel
, cases
)
96 def __init__(self
, byte
, offset
, width
):
103 def __init__(self
, fields
, length
, swap_field_bytes
=True):
106 self
.swap_field_bytes
= swap_field_bytes
108 def get_layout(self
):
110 for k
, v
in sorted(self
.fields
.items()):
111 layout
.append((k
, v
.width
))
114 def get_field(self
, obj
, name
, width
):
116 field
= getattr(obj
, name
.replace("_lsb", ""))[:width
]
118 field
= getattr(obj
, name
.replace("_msb", ""))[width
:2*width
]
120 field
= getattr(obj
, name
)
123 def encode(self
, obj
, signal
):
125 for k
, v
in sorted(self
.fields
.items()):
126 start
= v
.byte
*8+v
.offset
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
))
134 def decode(self
, signal
, obj
):
136 for k
, v
in sorted(self
.fields
.items()):
137 start
= v
.byte
*8+v
.offset
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
])))
143 r
.append(field
.eq(signal
[start
:end
]))
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)
155 dw
= len(self
.sink
.data
)
157 header_reg
= Signal(header
.length
*8)
158 header_words
= (header
.length
*8)//dw
161 counter
= Signal(max=max(header_words
, 2))
162 counter_reset
= Signal()
163 counter_ce
= Signal()
168 counter
.eq(counter
+ 1)
171 self
.comb
+= header
.encode(sink
, self
.header
)
172 if header_words
== 1:
175 header_reg
.eq(self
.header
)
181 header_reg
.eq(self
.header
)
183 header_reg
.eq(Cat(header_reg
[dw
:], Signal(dw
)))
187 fsm
= FSM(reset_state
="IDLE")
188 self
.submodules
+= fsm
190 if header_words
== 1:
191 idle_next_state
= "COPY"
193 idle_next_state
= "SEND_HEADER"
198 If(sink
.stb
& sink
.sop
,
203 source
.data
.eq(self
.header
[:dw
]),
204 If(source
.stb
& source
.ack
,
206 NextState(idle_next_state
)
210 if header_words
!= 1:
211 fsm
.act("SEND_HEADER",
215 source
.data
.eq(header_reg
[dw
:2*dw
]),
216 If(source
.stb
& source
.ack
,
219 If(counter
== header_words
-2,
225 source
.stb
.eq(sink
.stb
),
227 source
.eop
.eq(sink
.eop
),
228 source
.data
.eq(sink
.data
),
229 source
.error
.eq(sink
.error
),
230 If(source
.stb
& source
.ack
,
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)
249 header_words
= (header
.length
*8)//dw
252 counter
= Signal(max=max(header_words
, 2))
253 counter_reset
= Signal()
254 counter_ce
= Signal()
259 counter
.eq(counter
+ 1)
262 if header_words
== 1:
265 self
.header
.eq(sink
.data
)
270 self
.header
.eq(Cat(self
.header
[dw
:], sink
.data
))
273 fsm
= FSM(reset_state
="IDLE")
274 self
.submodules
+= fsm
276 if header_words
== 1:
277 idle_next_state
= "COPY"
279 idle_next_state
= "RECEIVE_HEADER"
286 NextState(idle_next_state
)
289 if header_words
!= 1:
290 fsm
.act("RECEIVE_HEADER",
295 If(counter
== header_words
-2,
300 no_payload
= Signal()
302 If(fsm
.before_entering("COPY"),
304 no_payload
.eq(sink
.eop
)
305 ).Elif(source
.stb
& source
.ack
,
309 if hasattr(sink
, "error"):
310 self
.comb
+= source
.error
.eq(sink
.error
)
312 source
.eop
.eq(sink
.eop | no_payload
),
313 source
.data
.eq(sink
.data
),
314 header
.decode(self
.header
, source
)
317 sink
.ack
.eq(source
.ack
),
318 source
.stb
.eq(sink
.stb | no_payload
),
319 If(source
.stb
& source
.ack
& source
.eop
,
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
)
332 sink_status
= Status(self
.sink
)
333 source_status
= Status(self
.source
)
334 self
.submodules
+= sink_status
, source_status
336 # store incoming packets
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
)
348 data_fifo
= SyncFIFO(description
, data_depth
, buffered
=True)
349 self
.submodules
+= data_fifo
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
),
357 self
.fsm
= fsm
= FSM(reset_state
="IDLE")
358 self
.submodules
+= fsm
360 If(cmd_fifo
.source
.stb
,
361 NextState("SEEK_SOP")
365 If(~data_fifo
.source
.sop
,
366 data_fifo
.source
.ack
.eq(1)
371 if hasattr(source
, "error"):
372 source_error
= self
.source
.error
374 source_error
= Signal()
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),
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
)