1 # This file is Copyright (c) 2015 Sebastien Bourdeauducq <sb@m-labs.hk>
2 # This file is Copyright (c) 2016-2019 Florent Kermarrec <florent@enjoy-digital.fr>
3 # This file is Copyright (c) 2020 LambdaConcept <contact@lambdaconcept.com>
6 """LiteDRAM Refresher."""
9 from nmigen
.utils
import log2_int
11 from gram
.core
.multiplexer
import *
12 from gram
.compat
import Timeline
13 import gram
.stream
as stream
15 # RefreshExecuter ----------------------------------------------------------------------------------
18 class RefreshExecuter(Elaboratable
):
21 Execute the refresh sequence to the DRAM:
22 - Send a "Precharge All" command
24 - Send an "Auto Refresh" command
28 def __init__(self
, trp
, trfc
):
40 def elaborate(self
, platform
):
55 # Auto Refresh after tRP
63 # Done after tRP + tRFC
74 m
.d
.comb
+= tl
.trigger
.eq(self
.start
)
78 # RefreshSequencer ---------------------------------------------------------------------------------
81 class RefreshSequencer(Elaboratable
):
84 Sequence N refreshs to the DRAM.
87 def __init__(self
, trp
, trfc
, postponing
=1):
93 self
._postponing
= postponing
101 def elaborate(self
, platform
):
104 executer
= RefreshExecuter(self
._trp
, self
._trfc
)
105 m
.submodules
+= executer
107 self
.a
.eq(executer
.a
),
108 self
.ba
.eq(executer
.ba
),
109 self
.cas
.eq(executer
.cas
),
110 self
.ras
.eq(executer
.ras
),
111 self
.we
.eq(executer
.we
),
114 count
= Signal(range(self
._postponing
), reset
=self
._postponing
-1)
115 with m
.If(self
.start
):
116 m
.d
.sync
+= count
.eq(count
.reset
)
117 with m
.Elif(executer
.done
):
118 with m
.If(count
!= 0):
119 m
.d
.sync
+= count
.eq(count
-1)
122 executer
.start
.eq(self
.start |
(count
!= 0)),
123 self
.done
.eq(executer
.done
& (count
== 0)),
128 # RefreshTimer -------------------------------------------------------------------------------------
131 class RefreshTimer(Elaboratable
):
134 Generate periodic pulses (tREFI period) to trigger DRAM refresh.
137 def __init__(self
, trefi
):
140 self
.count
= Signal(range(trefi
))
143 def elaborate(self
, platform
):
149 count
= Signal(range(trefi
), reset
=trefi
-1)
151 with m
.If(self
.wait
& ~self
.done
):
152 m
.d
.sync
+= count
.eq(count
-1)
154 m
.d
.sync
+= count
.eq(count
.reset
)
164 # RefreshPostponer -------------------------------------------------------------------------------
167 class RefreshPostponer(Elaboratable
):
170 Postpone N Refresh requests and generate a request when N is reached.
173 def __init__(self
, postponing
=1):
174 self
.req_i
= Signal()
175 self
.req_o
= Signal(reset
=0)
176 self
._postponing
= postponing
178 def elaborate(self
, platform
):
181 count
= Signal(range(self
._postponing
), reset
=self
._postponing
-1)
183 with m
.If(self
.req_i
):
184 with m
.If(count
== 0):
186 count
.eq(count
.reset
),
190 m
.d
.sync
+= count
.eq(count
-1)
194 # ZQCSExecuter ----------------------------------------------------------------------------------
197 class ZQCSExecuter(Elaboratable
):
198 """ZQ Short Calibration Executer
200 Execute the ZQCS sequence to the DRAM:
201 - Send a "Precharge All" command
203 - Send an "ZQ Short Calibration" command
207 def __init__(self
, trp
, tzqcs
):
208 self
.start
= Signal()
219 def elaborate(self
, platform
):
235 # ZQ Short Calibration after tRP
244 # Done after tRP + tZQCS
255 m
.d
.comb
+= tl
.trigger
.eq(self
.start
)
259 # Refresher ----------------------------------------------------------------------------------------
262 class Refresher(Elaboratable
):
267 The DRAM needs to be periodically refreshed with a tREFI period to avoid data corruption. During
268 a refresh, the controller send a "Precharge All" command to close and precharge all rows and then
269 send a "Auto Refresh" command.
271 Before executing the refresh, the Refresher advertises the Controller that a refresh should occur,
272 this allows the Controller to finish the current transaction and block next transactions. Once all
273 transactions are done, the Refresher can execute the refresh Sequence and release the Controller.
277 def __init__(self
, settings
, clk_freq
, zqcs_freq
=1e0
, postponing
=1):
278 assert postponing
<= 8
279 abits
= settings
.geom
.addressbits
280 babits
= settings
.geom
.bankbits
+ log2_int(settings
.phy
.nranks
)
281 self
.cmd
= cmd
= stream
.Endpoint(
282 cmd_request_rw_layout(a
=abits
, ba
=babits
))
283 self
._postponing
= postponing
284 self
._settings
= settings
285 self
._clk
_freq
= clk_freq
286 self
._zqcs
_freq
= zqcs_freq
288 def elaborate(self
, platform
):
291 wants_refresh
= Signal()
292 wants_zqcs
= Signal()
294 settings
= self
._settings
296 # Refresh Timer ----------------------------------------------------------------------------
297 timer
= RefreshTimer(settings
.timing
.tREFI
)
298 m
.submodules
.timer
= timer
299 m
.d
.comb
+= timer
.wait
.eq(~timer
.done
)
301 # Refresh Postponer ------------------------------------------------------------------------
302 postponer
= RefreshPostponer(self
._postponing
)
303 m
.submodules
.postponer
= postponer
305 postponer
.req_i
.eq(timer
.done
),
306 wants_refresh
.eq(postponer
.req_o
),
309 # Refresh Sequencer ------------------------------------------------------------------------
310 sequencer
= RefreshSequencer(
311 settings
.timing
.tRP
, settings
.timing
.tRFC
, self
._postponing
)
312 m
.submodules
.sequencer
= sequencer
314 if settings
.timing
.tZQCS
is not None:
315 # ZQCS Timer ---------------------------------------------------------------------------
316 zqcs_timer
= RefreshTimer(int(self
._clk
_freq
/self
._zqcs
_freq
))
317 m
.submodules
.zqcs_timer
= zqcs_timer
318 m
.d
.comb
+= wants_zqcs
.eq(zqcs_timer
.done
)
320 # ZQCS Executer ------------------------------------------------------------------------
321 zqcs_executer
= ZQCSExecuter(
322 settings
.timing
.tRP
, settings
.timing
.tZQCS
)
323 m
.submodules
.zqs_executer
= zqcs_executer
324 m
.d
.comb
+= zqcs_timer
.wait
.eq(~zqcs_executer
.done
)
326 # Refresh FSM ------------------------------------------------------------------------------
328 with m
.State("Idle"):
329 with m
.If(settings
.with_refresh
& wants_refresh
):
330 m
.next
= "Wait-Bank-Machines"
332 with m
.State("Wait-Bank-Machines"):
333 m
.d
.comb
+= self
.cmd
.valid
.eq(1)
334 with m
.If(self
.cmd
.ready
):
335 m
.d
.comb
+= sequencer
.start
.eq(1)
336 m
.next
= "Do-Refresh"
338 if settings
.timing
.tZQCS
is None:
339 with m
.State("Do-Refresh"):
341 self
.cmd
.valid
.eq(1),
342 self
.cmd
.a
.eq(sequencer
.a
),
343 self
.cmd
.ba
.eq(sequencer
.ba
),
344 self
.cmd
.cas
.eq(sequencer
.cas
),
345 self
.cmd
.ras
.eq(sequencer
.ras
),
346 self
.cmd
.we
.eq(sequencer
.we
),
348 with m
.If(sequencer
.done
):
350 self
.cmd
.valid
.eq(0),
355 with m
.State("Do-Refresh"):
356 m
.d
.comb
+= self
.cmd
.valid
.eq(1)
357 with m
.If(sequencer
.done
):
358 with m
.If(wants_zqcs
):
359 m
.d
.comb
+= zqcs_executer
.start
.eq(1)
363 self
.cmd
.valid
.eq(0),
368 with m
.State("Do-Zqcs"):
370 self
.cmd
.valid
.eq(1),
371 self
.cmd
.a
.eq(zqcs_executer
.a
),
372 self
.cmd
.ba
.eq(zqcs_executer
.ba
),
373 self
.cmd
.cas
.eq(zqcs_executer
.cas
),
374 self
.cmd
.ras
.eq(zqcs_executer
.ras
),
375 self
.cmd
.we
.eq(zqcs_executer
.we
),
377 with m
.If(zqcs_executer
.done
):
379 self
.cmd
.valid
.eq(0),