1 # This file is Copyright (c) 2016-2019 Florent Kermarrec <florent@enjoy-digital.fr>
6 from litex
.soc
.interconnect
import stream
8 from litedram
.common
import *
10 # LiteDRAMNativePortCDC ----------------------------------------------------------------------------
12 class LiteDRAMNativePortCDC(Module
):
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 address_width
= port_from
.address_width
22 data_width
= port_from
.data_width
24 clock_domain_from
= port_from
.clock_domain
25 clock_domain_to
= port_to
.clock_domain
29 cmd_fifo
= stream
.AsyncFIFO(
30 [("we", 1), ("addr", address_width
)], cmd_depth
)
31 cmd_fifo
= ClockDomainsRenamer(
32 {"write": clock_domain_from
,
33 "read": clock_domain_to
})(cmd_fifo
)
34 self
.submodules
+= cmd_fifo
35 self
.submodules
+= stream
.Pipeline(
36 port_from
.cmd
, cmd_fifo
, port_to
.cmd
)
38 if mode
== "write" or mode
== "both":
39 wdata_fifo
= stream
.AsyncFIFO(
40 [("data", data_width
), ("we", data_width
//8)], wdata_depth
)
41 wdata_fifo
= ClockDomainsRenamer(
42 {"write": clock_domain_from
,
43 "read": clock_domain_to
})(wdata_fifo
)
44 self
.submodules
+= wdata_fifo
45 self
.submodules
+= stream
.Pipeline(
46 port_from
.wdata
, wdata_fifo
, port_to
.wdata
)
48 if mode
== "read" or mode
== "both":
49 rdata_fifo
= stream
.AsyncFIFO([("data", data_width
)], rdata_depth
)
50 rdata_fifo
= ClockDomainsRenamer(
51 {"write": clock_domain_to
,
52 "read": clock_domain_from
})(rdata_fifo
)
53 self
.submodules
+= rdata_fifo
54 self
.submodules
+= stream
.Pipeline(
55 port_to
.rdata
, rdata_fifo
, port_from
.rdata
)
57 # LiteDRAMNativePortDownConverter ------------------------------------------------------------------
59 class LiteDRAMNativePortDownConverter(Module
):
60 """LiteDRAM port DownConverter
62 This module reduces user port data width to fit controller data width.
63 With N = port_from.data_width/port_to.data_width:
64 - Address is adapted (multiplied by N + internal increments)
65 - A write from the user is splitted and generates N writes to the
67 - A read from the user generates N reads to the controller and returned
68 datas are regrouped in a single data presented to the user.
70 def __init__(self
, port_from
, port_to
, reverse
=False):
71 assert port_from
.clock_domain
== port_to
.clock_domain
72 assert port_from
.data_width
> port_to
.data_width
73 assert port_from
.mode
== port_to
.mode
74 if port_from
.data_width
% port_to
.data_width
:
75 raise ValueError("Ratio must be an int")
79 ratio
= port_from
.data_width
//port_to
.data_width
82 counter
= Signal(max=ratio
)
83 counter_reset
= Signal()
89 counter
.eq(counter
+ 1)
92 self
.submodules
.fsm
= fsm
= FSM(reset_state
="IDLE")
95 If(port_from
.cmd
.valid
,
100 port_to
.cmd
.valid
.eq(1),
101 port_to
.cmd
.we
.eq(port_from
.cmd
.we
),
102 port_to
.cmd
.addr
.eq(port_from
.cmd
.addr
*ratio
+ counter
),
103 If(port_to
.cmd
.ready
,
105 If(counter
== ratio
- 1,
106 port_from
.cmd
.ready
.eq(1),
112 if mode
== "write" or mode
== "both":
113 wdata_converter
= stream
.StrideConverter(
114 port_from
.wdata
.description
,
115 port_to
.wdata
.description
,
117 self
.submodules
+= wdata_converter
118 self
.submodules
+= stream
.Pipeline(
119 port_from
.wdata
, wdata_converter
, port_to
.wdata
)
121 if mode
== "read" or mode
== "both":
122 rdata_converter
= stream
.StrideConverter(
123 port_to
.rdata
.description
,
124 port_from
.rdata
.description
,
126 self
.submodules
+= rdata_converter
127 self
.submodules
+= stream
.Pipeline(
128 port_to
.rdata
, rdata_converter
, port_from
.rdata
)
130 # LiteDRAMNativeWritePortUpConverter ---------------------------------------------------------------
132 class LiteDRAMNativeWritePortUpConverter(Module
):
133 # TODO: finish and remove hack
134 """LiteDRAM write port UpConverter
136 This module increase user port data width to fit controller data width.
137 With N = port_to.data_width/port_from.data_width:
138 - Address is adapted (divided by N)
139 - N writes from user are regrouped in a single one to the controller
140 (when possible, ie when consecutive and bursting)
142 def __init__(self
, port_from
, port_to
, reverse
=False):
143 assert port_from
.clock_domain
== port_to
.clock_domain
144 assert port_from
.data_width
< port_to
.data_width
145 assert port_from
.mode
== port_to
.mode
146 assert port_from
.mode
== "write"
147 if port_to
.data_width
% port_from
.data_width
:
148 raise ValueError("Ratio must be an int")
152 ratio
= port_to
.data_width
//port_from
.data_width
155 address
= Signal(port_to
.address_width
)
157 counter
= Signal(max=ratio
)
158 counter_reset
= Signal()
159 counter_ce
= Signal()
164 counter
.eq(counter
+ 1)
167 self
.submodules
.fsm
= fsm
= FSM(reset_state
="IDLE")
169 port_from
.cmd
.ready
.eq(1),
170 If(port_from
.cmd
.valid
,
172 NextValue(we
, port_from
.cmd
.we
),
173 NextValue(address
, port_from
.cmd
.addr
),
178 port_from
.cmd
.ready
.eq(1),
179 If(port_from
.cmd
.valid
,
181 If(counter
== ratio
-1,
182 NextState("GENERATE")
187 port_to
.cmd
.valid
.eq(1),
188 port_to
.cmd
.we
.eq(we
),
189 port_to
.cmd
.addr
.eq(address
[log2_int(ratio
):]),
190 If(port_to
.cmd
.ready
,
195 wdata_converter
= stream
.StrideConverter(
196 port_from
.wdata
.description
,
197 port_to
.wdata
.description
,
199 self
.submodules
+= wdata_converter
200 self
.submodules
+= stream
.Pipeline(
205 # LiteDRAMNativeReadPortUpConverter ----------------------------------------------------------------
207 class LiteDRAMNativeReadPortUpConverter(Module
):
208 """LiteDRAM port UpConverter
210 This module increase user port data width to fit controller data width.
211 With N = port_to.data_width/port_from.data_width:
212 - Address is adapted (divided by N)
213 - N read from user are regrouped in a single one to the controller
214 (when possible, ie when consecutive and bursting)
216 def __init__(self
, port_from
, port_to
, reverse
=False):
217 assert port_from
.clock_domain
== port_to
.clock_domain
218 assert port_from
.data_width
< port_to
.data_width
219 assert port_from
.mode
== port_to
.mode
220 assert port_from
.mode
== "read"
221 if port_to
.data_width
% port_from
.data_width
:
222 raise ValueError("Ratio must be an int")
226 ratio
= port_to
.data_width
//port_from
.data_width
229 # Command ----------------------------------------------------------------------------------
231 cmd_buffer
= stream
.SyncFIFO([("sel", ratio
)], 4)
232 self
.submodules
+= cmd_buffer
234 counter
= Signal(max=ratio
)
235 counter_ce
= Signal()
238 counter
.eq(counter
+ 1)
242 If(port_from
.cmd
.valid
,
244 port_to
.cmd
.valid
.eq(1),
245 port_to
.cmd
.addr
.eq(port_from
.cmd
.addr
[log2_int(ratio
):]),
246 port_from
.cmd
.ready
.eq(port_to
.cmd
.ready
),
247 counter_ce
.eq(port_to
.cmd
.ready
)
249 port_from
.cmd
.ready
.eq(1),
256 If(port_to
.cmd
.valid
& port_to
.cmd
.ready
,
257 cmd_buffer
.sink
.valid
.eq(1),
258 cmd_buffer
.sink
.sel
.eq(2**ratio
-1)
261 # Datapath ---------------------------------------------------------------------------------
263 rdata_buffer
= stream
.Buffer(port_to
.rdata
.description
)
264 rdata_converter
= stream
.StrideConverter(
265 port_to
.rdata
.description
,
266 port_from
.rdata
.description
,
268 self
.submodules
+= rdata_buffer
, rdata_converter
270 rdata_chunk
= Signal(ratio
, reset
=1)
271 rdata_chunk_valid
= Signal()
273 If(rdata_converter
.source
.valid
&
274 rdata_converter
.source
.ready
,
275 rdata_chunk
.eq(Cat(rdata_chunk
[ratio
-1], rdata_chunk
[:ratio
-1]))
279 port_to
.rdata
.connect(rdata_buffer
.sink
),
280 rdata_buffer
.source
.connect(rdata_converter
.sink
),
281 rdata_chunk_valid
.eq((cmd_buffer
.source
.sel
& rdata_chunk
) != 0),
283 rdata_converter
.source
.ready
.eq(1)
284 ).Elif(cmd_buffer
.source
.valid
,
285 If(rdata_chunk_valid
,
286 port_from
.rdata
.valid
.eq(rdata_converter
.source
.valid
),
287 port_from
.rdata
.data
.eq(rdata_converter
.source
.data
),
288 rdata_converter
.source
.ready
.eq(port_from
.rdata
.ready
)
290 rdata_converter
.source
.ready
.eq(1)
293 cmd_buffer
.source
.ready
.eq(
294 rdata_converter
.source
.ready
& rdata_chunk
[ratio
-1])
297 # LiteDRAMNativePortConverter ----------------------------------------------------------------------
299 class LiteDRAMNativePortConverter(Module
):
300 def __init__(self
, port_from
, port_to
, reverse
=False):
301 assert port_from
.clock_domain
== port_to
.clock_domain
302 assert port_from
.mode
== port_to
.mode
306 mode
= port_from
.mode
308 if port_from
.data_width
> port_to
.data_width
:
309 converter
= LiteDRAMNativePortDownConverter(port_from
, port_to
, reverse
)
310 self
.submodules
+= converter
311 elif port_from
.data_width
< port_to
.data_width
:
313 converter
= LiteDRAMNativeWritePortUpConverter(port_from
, port_to
, reverse
)
315 converter
= LiteDRAMNativeReadPortUpConverter(port_from
, port_to
, reverse
)
317 raise NotImplementedError
318 self
.submodules
+= converter
321 port_from
.cmd
.connect(port_to
.cmd
),
322 port_from
.wdata
.connect(port_to
.wdata
),
323 port_to
.rdata
.connect(port_from
.rdata
)