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: move reverse_bytes / Counter
10 def reverse_bytes(signal
):
11 n
= (len(signal
)+7)//8
13 for i
in reversed(range(n
)):
14 r
.append(signal
[i
*8:min((i
+1)*8, len(signal
))])
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
)
27 def __init__(self
, endpoint
):
28 self
.sop
= sop
= Signal()
29 self
.eop
= eop
=Signal()
30 self
.ongoing
= Signal()
36 eop
.eq(endpoint
.eop
& endpoint
.ack
)
38 self
.sync
+= ongoing
.eq((sop | ongoing
) & ~eop
)
39 self
.comb
+= self
.ongoing
.eq((sop | ongoing
) & ~eop
)
42 class Arbiter(Module
):
43 def __init__(self
, masters
, slave
):
46 elif len(masters
) == 1:
48 self
.comb
+= Record
.connect(masters
.pop(), slave
)
50 self
.submodules
.rr
= RoundRobin(len(masters
))
51 self
.grant
= self
.rr
.grant
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
)
61 class Dispatcher(Module
):
62 def __init__(self
, master
, slaves
, one_hot
=False):
65 elif len(slaves
) == 1:
66 self
.comb
+= Record
.connect(master
, slaves
.pop())
70 self
.sel
= Signal(len(slaves
))
72 self
.sel
= Signal(max=len(slaves
))
76 status
= Status(master
)
77 self
.submodules
+= status
79 sel
= Signal
.like(self
.sel
)
80 sel_ongoing
= Signal
.like(self
.sel
)
83 sel_ongoing
.eq(self
.sel
)
92 for i
, slave
in enumerate(slaves
):
97 cases
[idx
] = [Record
.connect(master
, slave
)]
98 cases
["default"] = [master
.ack
.eq(1)]
99 self
.comb
+= Case(sel
, cases
)
103 def __init__(self
, byte
, offset
, width
):
110 def __init__(self
, fields
, length
, swap_field_bytes
=True):
113 self
.swap_field_bytes
= swap_field_bytes
115 def get_layout(self
):
117 for k
, v
in sorted(self
.fields
.items()):
118 layout
.append((k
, v
.width
))
121 def get_field(self
, obj
, name
, width
):
123 field
= getattr(obj
, name
.replace("_lsb", ""))[:width
]
125 field
= getattr(obj
, name
.replace("_msb", ""))[width
:2*width
]
127 field
= getattr(obj
, name
)
130 def encode(self
, obj
, signal
):
132 for k
, v
in sorted(self
.fields
.items()):
133 start
= v
.byte
*8+v
.offset
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
))
141 def decode(self
, signal
, obj
):
143 for k
, v
in sorted(self
.fields
.items()):
144 start
= v
.byte
*8+v
.offset
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
])))
150 r
.append(field
.eq(signal
[start
:end
]))
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)
162 dw
= len(self
.sink
.data
)
164 header_reg
= Signal(header
.length
*8)
165 header_words
= (header
.length
*8)//dw
168 counter
= Counter(max=max(header_words
, 2))
169 self
.submodules
+= counter
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
.value
== 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
= Counter(max=max(header_words
, 2))
253 self
.submodules
+= counter
255 if header_words
== 1:
258 self
.header
.eq(sink
.data
)
263 self
.header
.eq(Cat(self
.header
[dw
:], sink
.data
))
266 fsm
= FSM(reset_state
="IDLE")
267 self
.submodules
+= fsm
269 if header_words
== 1:
270 idle_next_state
= "COPY"
272 idle_next_state
= "RECEIVE_HEADER"
279 NextState(idle_next_state
)
282 if header_words
!= 1:
283 fsm
.act("RECEIVE_HEADER",
288 If(counter
.value
== header_words
-2,
293 no_payload
= Signal()
295 If(fsm
.before_entering("COPY"),
297 no_payload
.eq(sink
.eop
)
298 ).Elif(source
.stb
& source
.ack
,
302 if hasattr(sink
, "error"):
303 self
.comb
+= source
.error
.eq(sink
.error
)
305 source
.eop
.eq(sink
.eop | no_payload
),
306 source
.data
.eq(sink
.data
),
307 header
.decode(self
.header
, source
)
310 sink
.ack
.eq(source
.ack
),
311 source
.stb
.eq(sink
.stb | no_payload
),
312 If(source
.stb
& source
.ack
& source
.eop
,
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
)
325 sink_status
= Status(self
.sink
)
326 source_status
= Status(self
.source
)
327 self
.submodules
+= sink_status
, source_status
329 # store incoming packets
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
)
341 data_fifo
= SyncFIFO(description
, data_depth
, buffered
=True)
342 self
.submodules
+= data_fifo
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
),
350 self
.fsm
= fsm
= FSM(reset_state
="IDLE")
351 self
.submodules
+= fsm
353 If(cmd_fifo
.source
.stb
,
354 NextState("SEEK_SOP")
358 If(~data_fifo
.source
.sop
,
359 data_fifo
.source
.ack
.eq(1)
364 if hasattr(source
, "error"):
365 source_error
= self
.source
.error
367 source_error
= Signal()
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),
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
)