ac5c49fa7b651dcc2f64d2fd95eb36aaa4ad4d88
1 # This file is Copyright (c) 2016-2019 Florent Kermarrec <florent@enjoy-digital.fr>
5 from nmigen
.compat
import Case
7 from gram
.common
import *
8 import gram
.stream
as stream
10 # LiteDRAMNativePortCDC ----------------------------------------------------------------------------
12 class gramNativePortCDC(Elaboratable
):
13 def __init__(self
, port_from
, port_to
,
17 assert port_from
.address_width
== port_to
.address_width
18 assert port_from
.data_width
== port_to
.data_width
19 assert port_from
.mode
== port_to
.mode
21 self
._port
_from
= port_from
22 self
._port
_to
= port_to
23 self
._cmd
_depth
= cmd_depth
24 self
._wdata
_depth
= wdata_depth
25 self
._rdata
_depth
= rdata_depth
27 def elaborate(self
, platform
):
30 port_from
= self
._port
_from
31 port_to
= self
._port
_to
32 cmd_depth
= self
._cmd
_depth
33 wdata_depth
= self
._wdata
_depth
34 rdata_depth
= self
._rdata
_depth
36 address_width
= port_from
.address_width
37 data_width
= port_from
.data_width
39 clock_domain_from
= port_from
.clock_domain
40 clock_domain_to
= port_to
.clock_domain
42 cmd_fifo
= stream
.AsyncFIFO(
43 [("we", 1), ("addr", address_width
)], cmd_depth
)
44 cmd_fifo
= ClockDomainsRenamer(
45 {"write": clock_domain_from
,
46 "read": clock_domain_to
})(cmd_fifo
)
47 m
.submodules
+= cmd_fifo
48 m
.submodules
+= stream
.Pipeline(
49 port_from
.cmd
, cmd_fifo
, port_to
.cmd
)
51 if mode
== "write" or mode
== "both":
52 wdata_fifo
= stream
.AsyncFIFO(
53 [("data", data_width
), ("we", data_width
//8)], wdata_depth
)
54 wdata_fifo
= ClockDomainsRenamer(
55 {"write": clock_domain_from
,
56 "read": clock_domain_to
})(wdata_fifo
)
57 m
.submodules
+= wdata_fifo
58 m
.submodules
+= stream
.Pipeline(
59 port_from
.wdata
, wdata_fifo
, port_to
.wdata
)
61 if mode
== "read" or mode
== "both":
62 rdata_fifo
= stream
.AsyncFIFO([("data", data_width
)], rdata_depth
)
63 rdata_fifo
= ClockDomainsRenamer(
64 {"write": clock_domain_to
,
65 "read": clock_domain_from
})(rdata_fifo
)
66 m
.submodules
+= rdata_fifo
67 m
.submodules
+= stream
.Pipeline(
68 port_to
.rdata
, rdata_fifo
, port_from
.rdata
)
72 # LiteDRAMNativePortDownConverter ------------------------------------------------------------------
74 class gramNativePortDownConverter(Elaboratable
):
75 """LiteDRAM port DownConverter
77 This module reduces user port data width to fit controller data width.
78 With N = port_from.data_width/port_to.data_width:
79 - Address is adapted (multiplied by N + internal increments)
80 - A write from the user is splitted and generates N writes to the
82 - A read from the user generates N reads to the controller and returned
83 datas are regrouped in a single data presented to the user.
85 def __init__(self
, port_from
, port_to
, reverse
=False):
86 assert port_from
.clock_domain
== port_to
.clock_domain
87 assert port_from
.data_width
> port_to
.data_width
88 assert port_from
.mode
== port_to
.mode
89 if port_from
.data_width
% port_to
.data_width
:
90 raise ValueError("Ratio must be an int")
92 self
._port
_from
= port_from
93 self
._port
_to
= port_to
94 self
._reverse
= reverse
96 def elaborate(self
, platform
):
99 port_from
= self
._port
_from
100 port_to
= self
._port
_to
101 reverse
= self
._reverse
103 ratio
= port_from
.data_width
//port_to
.data_width
104 mode
= port_from
.mode
106 counter
= Signal(max=ratio
)
107 counter_reset
= Signal()
108 counter_ce
= Signal()
110 with m
.If(counter_reset
):
111 m
.d
.sync
+= counter
.eq(0)
112 with m
.Elif(counter_ce
):
113 m
.d
.sync
+= counter
.eq(counter
+1)
116 with m
.State("Idle"):
117 m
.d
.comb
+= counter_reset
.eq(1)
118 with m
.If(port_from
.cmd
.valid
):
121 with m
.State("Convert"):
123 port_to
.cmd
.valid
.eq(1),
124 port_to
.cmd
.we
.eq(port_from
.cmd
.we
),
125 port_to
.cmd
.addr
.eq(port_from
.cmd
.addr
*ratio
+ counter
),
127 with m
.If(port_to
.cmd
.ready
):
128 m
.d
.comb
+= counter_ce
.eq(1)
129 with m
.If(counter
== ratio
- 1):
130 m
.d
.comb
+= port_from
.cmd
.ready
.eq(1)
133 if mode
== "write" or mode
== "both":
134 wdata_converter
= stream
.StrideConverter(
135 port_from
.wdata
.description
,
136 port_to
.wdata
.description
,
138 m
.submodules
+= wdata_converter
139 m
.submodules
+= stream
.Pipeline(
140 port_from
.wdata
, wdata_converter
, port_to
.wdata
)
142 if mode
== "read" or mode
== "both":
143 rdata_converter
= stream
.StrideConverter(
144 port_to
.rdata
.description
,
145 port_from
.rdata
.description
,
147 m
.submodules
+= rdata_converter
148 m
.submodules
+= stream
.Pipeline(
149 port_to
.rdata
, rdata_converter
, port_from
.rdata
)
153 # LiteDRAMNativeWritePortUpConverter ---------------------------------------------------------------
155 class gramNativeWritePortUpConverter(Elaboratable
):
156 # TODO: finish and remove hack
157 """LiteDRAM write port UpConverter
159 This module increase user port data width to fit controller data width.
160 With N = port_to.data_width/port_from.data_width:
161 - Address is adapted (divided by N)
162 - N writes from user are regrouped in a single one to the controller
163 (when possible, ie when consecutive and bursting)
165 def __init__(self
, port_from
, port_to
, reverse
=False):
166 assert port_from
.clock_domain
== port_to
.clock_domain
167 assert port_from
.data_width
< port_to
.data_width
168 assert port_from
.mode
== port_to
.mode
169 assert port_from
.mode
== "write"
170 if port_to
.data_width
% port_from
.data_width
:
171 raise ValueError("Ratio must be an int")
173 self
._port
_from
= port_from
174 self
._port
_to
= port_to
175 self
._reverse
= reverse
177 def elaborate(self
, platform
):
180 port_from
= self
._port
_from
181 port_to
= self
._port
_to
182 reverse
= self
._reverse
184 ratio
= port_to
.data_width
//port_from
.data_width
187 address
= Signal(port_to
.address_width
)
189 counter
= Signal(max=ratio
)
190 counter_reset
= Signal()
191 counter_ce
= Signal()
196 counter
.eq(counter
+ 1)
200 with m
.State("Idle"):
201 m
.d
.comb
+= port_from
.cmd
.ready
.eq(1)
202 with m
.If(port_from
.cmd
.valid
):
204 we
.eq(port_from
.cmd
.we
),
205 address
.eq(port_from
.cmd
.addr
),
209 with m
.State("Receive"):
210 m
.d
.comb
+= port_from
.cmd
.ready
.eq(1)
211 with m
.If(port_from
.cmd
.valid
):
212 m
.d
.comb
+= counter_ce
.eq(1)
213 with m
.If(counter
== ratio
-1):
216 with m
.State("Generate"):
218 port_to
.cmd
.valid
.eq(1),
219 port_to
.cmd
.we
.eq(we
),
220 port_to
.cmd
.addr
.eq(address
[log2_int(ratio
):]),
222 with m
.If(port_to
.cmd
.ready
):
225 wdata_converter
= stream
.StrideConverter(
226 port_from
.wdata
.description
,
227 port_to
.wdata
.description
,
229 m
.submodules
+= wdata_converter
230 m
.submodules
+= stream
.Pipeline(
237 # LiteDRAMNativeReadPortUpConverter ----------------------------------------------------------------
239 class gramNativeReadPortUpConverter(Elaboratable
):
240 """LiteDRAM port UpConverter
242 This module increase user port data width to fit controller data width.
243 With N = port_to.data_width/port_from.data_width:
244 - Address is adapted (divided by N)
245 - N read from user are regrouped in a single one to the controller
246 (when possible, ie when consecutive and bursting)
248 def __init__(self
, port_from
, port_to
, reverse
=False):
249 assert port_from
.clock_domain
== port_to
.clock_domain
250 assert port_from
.data_width
< port_to
.data_width
251 assert port_from
.mode
== port_to
.mode
252 assert port_from
.mode
== "read"
253 if port_to
.data_width
% port_from
.data_width
:
254 raise ValueError("Ratio must be an int")
256 self
._port
_from
= port_from
257 self
._port
_to
= port_to
258 self
._reverse
= reverse
260 def elaborate(self
, platform
):
263 port_from
= self
._port
_from
264 port_to
= self
._port
_to
265 reverse
= self
._reverse
267 ratio
= port_to
.data_width
//port_from
.data_width
269 # Command ----------------------------------------------------------------------------------
271 cmd_buffer
= stream
.SyncFIFO([("sel", ratio
)], 4)
272 m
.submodules
+= cmd_buffer
274 counter
= Signal(range(ratio
))
275 counter_ce
= Signal()
276 with m
.If(counter_ce
):
277 m
.d
.sync
+= counter
.eq(counter
+1)
279 with m
.If(port_from
.cmd
.valid
):
280 with m
.If(counter
== 0):
282 port_to
.cmd
.valid
.eq(1),
283 port_to
.cmd
.addr
.eq(port_from
.cmd
.addr
[log2_int(ratio
):]),
284 port_from
.cmd
.ready
.eq(port_to
.cmd
.ready
),
285 counter_ce
.eq(port_to
.cmd
.ready
),
289 port_from
.cmd
.ready
.eq(1),
294 with m
.If(port_to
.cmd
.valid
& port_to
.cmd
.ready
):
296 cmd_buffer
.sink
.valid
.eq(1),
297 cmd_buffer
.sink
.sel
.eq(2**ratio
-1),
300 # Datapath ---------------------------------------------------------------------------------
302 rdata_buffer
= stream
.Buffer(port_to
.rdata
.description
)
303 rdata_converter
= stream
.StrideConverter(
304 port_to
.rdata
.description
,
305 port_from
.rdata
.description
,
307 m
.submodules
+= rdata_buffer
, rdata_converter
309 rdata_chunk
= Signal(ratio
, reset
=1)
310 rdata_chunk_valid
= Signal()
311 with m
.If(rdata_converter
.source
.valid
& rdata_converter
.source
.ready
):
312 m
.d
.sync
+= rdata_chunk
.eq(Cat(rdata_chunk
[ratio
-1], rdata_chunk
[:ratio
-1]))
315 port_to
.rdata
.connect(rdata_buffer
.sink
),
316 rdata_buffer
.source
.connect(rdata_converter
.sink
),
317 rdata_chunk_valid
.eq((cmd_buffer
.source
.sel
& rdata_chunk
) != 0),
318 cmd_buffer
.source
.ready
.eq(rdata_converter
.source
.ready
& rdata_chunk
[ratio
-1]),
321 with m
.If(port_from
.flush
):
322 m
.d
.comb
+= rdata_converter
.source
.ready
.eq(1)
323 with m
.Elif(cmd_buffer
.source
.valid
):
324 with m
.If(rdata_chunk_valid
):
326 port_from
.rdata
.valid
.eq(rdata_converter
.source
.valid
),
327 port_from
.rdata
.data
.eq(rdata_converter
.source
.data
),
328 rdata_converter
.source
.ready
.eq(port_from
.rdata
.ready
),
331 m
.d
.comb
+= rdata_converter
.source
.ready
.eq(1)
335 # LiteDRAMNativePortConverter ----------------------------------------------------------------------
337 class LiteDRAMNativePortConverter(Elaboratable
):
338 def __init__(self
, port_from
, port_to
, reverse
=False):
339 assert port_from
.clock_domain
== port_to
.clock_domain
340 assert port_from
.mode
== port_to
.mode
342 self
._port
_from
= port_from
343 self
._port
_to
= port_to
344 self
._reverse
= reverse
346 def elaborate(self
, platform
):
349 port_from
= self
._port
_from
350 port_to
= self
._port
_to
351 reverse
= self
._reverse
353 mode
= port_from
.mode
355 if port_from
.data_width
> port_to
.data_width
:
356 converter
= gramNativePortDownConverter(port_from
, port_to
, reverse
)
357 m
.submodules
+= converter
358 elif port_from
.data_width
< port_to
.data_width
:
360 converter
= gramNativeWritePortUpConverter(port_from
, port_to
, reverse
)
362 converter
= gramNativeReadPortUpConverter(port_from
, port_to
, reverse
)
364 raise NotImplementedError
365 m
.submodules
+= converter
368 port_from
.cmd
.connect(port_to
.cmd
),
369 port_from
.wdata
.connect(port_to
.wdata
),
370 port_to
.rdata
.connect(port_from
.rdata
)