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
))])
21 class Counter(Module
):
22 def __init__(self
, *args
, increment
=1, **kwargs
):
23 self
.value
= Signal(*args
, **kwargs
)
24 self
.width
= len(self
.value
)
25 self
.sync
+= self
.value
.eq(self
.value
+increment
)
28 def __init__(self
, endpoint
):
29 self
.sop
= sop
= Signal()
30 self
.eop
= eop
=Signal()
31 self
.ongoing
= Signal()
37 eop
.eq(endpoint
.eop
& endpoint
.ack
)
39 self
.sync
+= ongoing
.eq((sop | ongoing
) & ~eop
)
40 self
.comb
+= self
.ongoing
.eq((sop | ongoing
) & ~eop
)
43 class Arbiter(Module
):
44 def __init__(self
, masters
, slave
):
47 elif len(masters
) == 1:
49 self
.comb
+= Record
.connect(masters
.pop(), slave
)
51 self
.submodules
.rr
= RoundRobin(len(masters
))
52 self
.grant
= self
.rr
.grant
54 for i
, master
in enumerate(masters
):
55 status
= Status(master
)
56 self
.submodules
+= status
57 self
.comb
+= self
.rr
.request
[i
].eq(status
.ongoing
)
58 cases
[i
] = [Record
.connect(master
, slave
)]
59 self
.comb
+= Case(self
.grant
, cases
)
62 class Dispatcher(Module
):
63 def __init__(self
, master
, slaves
, one_hot
=False):
66 elif len(slaves
) == 1:
67 self
.comb
+= Record
.connect(master
, slaves
.pop())
71 self
.sel
= Signal(len(slaves
))
73 self
.sel
= Signal(max=len(slaves
))
77 status
= Status(master
)
78 self
.submodules
+= status
80 sel
= Signal
.like(self
.sel
)
81 sel_ongoing
= Signal
.like(self
.sel
)
84 sel_ongoing
.eq(self
.sel
)
93 for i
, slave
in enumerate(slaves
):
98 cases
[idx
] = [Record
.connect(master
, slave
)]
99 cases
["default"] = [master
.ack
.eq(1)]
100 self
.comb
+= Case(sel
, cases
)
104 def __init__(self
, byte
, offset
, width
):
111 def __init__(self
, fields
, length
, swap_field_bytes
=True):
114 self
.swap_field_bytes
= swap_field_bytes
116 def get_layout(self
):
118 for k
, v
in sorted(self
.fields
.items()):
119 layout
.append((k
, v
.width
))
122 def get_field(self
, obj
, name
, width
):
124 field
= getattr(obj
, name
.replace("_lsb", ""))[:width
]
126 field
= getattr(obj
, name
.replace("_msb", ""))[width
:2*width
]
128 field
= getattr(obj
, name
)
131 def encode(self
, obj
, signal
):
133 for k
, v
in sorted(self
.fields
.items()):
134 start
= v
.byte
*8+v
.offset
136 field
= self
.get_field(obj
, k
, v
.width
)
137 if self
.swap_field_bytes
:
138 field
= reverse_bytes(field
)
139 r
.append(signal
[start
:end
].eq(field
))
142 def decode(self
, signal
, obj
):
144 for k
, v
in sorted(self
.fields
.items()):
145 start
= v
.byte
*8+v
.offset
147 field
= self
.get_field(obj
, k
, v
.width
)
148 if self
.swap_field_bytes
:
149 r
.append(field
.eq(reverse_bytes(signal
[start
:end
])))
151 r
.append(field
.eq(signal
[start
:end
]))
155 class Packetizer(Module
):
156 def __init__(self
, sink_description
, source_description
, header
):
157 self
.sink
= sink
= Sink(sink_description
)
158 self
.source
= source
= Source(source_description
)
159 self
.header
= Signal(header
.length
*8)
163 dw
= len(self
.sink
.data
)
165 header_reg
= Signal(header
.length
*8)
166 header_words
= (header
.length
*8)//dw
169 counter
= Counter(max=max(header_words
, 2))
170 self
.submodules
+= counter
172 self
.comb
+= header
.encode(sink
, self
.header
)
173 if header_words
== 1:
176 header_reg
.eq(self
.header
)
182 header_reg
.eq(self
.header
)
184 header_reg
.eq(Cat(header_reg
[dw
:], Signal(dw
)))
188 fsm
= FSM(reset_state
="IDLE")
189 self
.submodules
+= fsm
191 if header_words
== 1:
192 idle_next_state
= "COPY"
194 idle_next_state
= "SEND_HEADER"
199 If(sink
.stb
& sink
.sop
,
204 source
.data
.eq(self
.header
[:dw
]),
205 If(source
.stb
& source
.ack
,
207 NextState(idle_next_state
)
211 if header_words
!= 1:
212 fsm
.act("SEND_HEADER",
216 source
.data
.eq(header_reg
[dw
:2*dw
]),
217 If(source
.stb
& source
.ack
,
220 If(counter
.value
== header_words
-2,
226 source
.stb
.eq(sink
.stb
),
228 source
.eop
.eq(sink
.eop
),
229 source
.data
.eq(sink
.data
),
230 source
.error
.eq(sink
.error
),
231 If(source
.stb
& source
.ack
,
240 class Depacketizer(Module
):
241 def __init__(self
, sink_description
, source_description
, header
):
242 self
.sink
= sink
= Sink(sink_description
)
243 self
.source
= source
= Source(source_description
)
244 self
.header
= Signal(header
.length
*8)
250 header_words
= (header
.length
*8)//dw
253 counter
= Counter(max=max(header_words
, 2))
254 self
.submodules
+= counter
256 if header_words
== 1:
259 self
.header
.eq(sink
.data
)
264 self
.header
.eq(Cat(self
.header
[dw
:], sink
.data
))
267 fsm
= FSM(reset_state
="IDLE")
268 self
.submodules
+= fsm
270 if header_words
== 1:
271 idle_next_state
= "COPY"
273 idle_next_state
= "RECEIVE_HEADER"
280 NextState(idle_next_state
)
283 if header_words
!= 1:
284 fsm
.act("RECEIVE_HEADER",
289 If(counter
.value
== header_words
-2,
294 no_payload
= Signal()
296 If(fsm
.before_entering("COPY"),
298 no_payload
.eq(sink
.eop
)
299 ).Elif(source
.stb
& source
.ack
,
303 if hasattr(sink
, "error"):
304 self
.comb
+= source
.error
.eq(sink
.error
)
306 source
.eop
.eq(sink
.eop | no_payload
),
307 source
.data
.eq(sink
.data
),
308 header
.decode(self
.header
, source
)
311 sink
.ack
.eq(source
.ack
),
312 source
.stb
.eq(sink
.stb | no_payload
),
313 If(source
.stb
& source
.ack
& source
.eop
,
319 class Buffer(Module
):
320 def __init__(self
, description
, data_depth
, cmd_depth
=4, almost_full
=None):
321 self
.sink
= sink
= Sink(description
)
322 self
.source
= source
= Source(description
)
326 sink_status
= Status(self
.sink
)
327 source_status
= Status(self
.source
)
328 self
.submodules
+= sink_status
, source_status
330 # store incoming packets
332 def cmd_description():
333 layout
= [("error", 1)]
334 return EndpointDescription(layout
)
335 cmd_fifo
= SyncFIFO(cmd_description(), cmd_depth
)
336 self
.submodules
+= cmd_fifo
337 self
.comb
+= cmd_fifo
.sink
.stb
.eq(sink_status
.eop
)
338 if hasattr(sink
, "error"):
339 self
.comb
+= cmd_fifo
.sink
.error
.eq(sink
.error
)
342 data_fifo
= SyncFIFO(description
, data_depth
, buffered
=True)
343 self
.submodules
+= data_fifo
345 Record
.connect(self
.sink
, data_fifo
.sink
),
346 data_fifo
.sink
.stb
.eq(self
.sink
.stb
& cmd_fifo
.sink
.ack
),
347 self
.sink
.ack
.eq(data_fifo
.sink
.ack
& cmd_fifo
.sink
.ack
),
351 self
.fsm
= fsm
= FSM(reset_state
="IDLE")
352 self
.submodules
+= fsm
354 If(cmd_fifo
.source
.stb
,
355 NextState("SEEK_SOP")
359 If(~data_fifo
.source
.sop
,
360 data_fifo
.source
.ack
.eq(1)
365 if hasattr(source
, "error"):
366 source_error
= self
.source
.error
368 source_error
= Signal()
371 Record
.connect(data_fifo
.source
, self
.source
),
372 source_error
.eq(cmd_fifo
.source
.error
),
373 If(source_status
.eop
,
374 cmd_fifo
.source
.ack
.eq(1),
379 # compute almost full
380 if almost_full
is not None:
381 self
.almost_full
= Signal()
382 self
.comb
+= self
.almost_full
.eq(data_fifo
.fifo
.level
> almost_full
)