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
, abits
, babits
, trp
, trfc
):
34 self
.a
= Signal(abits
)
35 self
.ba
= Signal(babits
)
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
, abits
, babits
, trp
, trfc
, postponing
=1):
93 self
._postponing
= postponing
97 self
.a
= Signal(abits
)
98 self
.ba
= Signal(babits
)
103 def elaborate(self
, platform
):
106 executer
= RefreshExecuter(self
._abits
, self
._babits
, self
._trp
, self
._trfc
)
107 m
.submodules
+= executer
109 self
.a
.eq(executer
.a
),
110 self
.ba
.eq(executer
.ba
),
111 self
.cas
.eq(executer
.cas
),
112 self
.ras
.eq(executer
.ras
),
113 self
.we
.eq(executer
.we
),
116 count
= Signal(range(self
._postponing
), reset
=self
._postponing
-1)
117 with m
.If(self
.start
):
118 m
.d
.sync
+= count
.eq(count
.reset
)
119 with m
.Elif(executer
.done
):
120 with m
.If(count
!= 0):
121 m
.d
.sync
+= count
.eq(count
-1)
124 executer
.start
.eq(self
.start |
(count
!= 0)),
125 self
.done
.eq(executer
.done
& (count
== 0)),
130 # RefreshTimer -------------------------------------------------------------------------------------
133 class RefreshTimer(Elaboratable
):
136 Generate periodic pulses (tREFI period) to trigger DRAM refresh.
139 def __init__(self
, trefi
):
142 self
.count
= Signal(range(trefi
))
145 def elaborate(self
, platform
):
151 count
= Signal(range(trefi
), reset
=trefi
-1)
153 with m
.If(self
.wait
& ~self
.done
):
154 m
.d
.sync
+= count
.eq(count
-1)
156 m
.d
.sync
+= count
.eq(count
.reset
)
166 # RefreshPostponer -------------------------------------------------------------------------------
169 class RefreshPostponer(Elaboratable
):
172 Postpone N Refresh requests and generate a request when N is reached.
175 def __init__(self
, postponing
=1):
176 self
.req_i
= Signal()
177 self
.req_o
= Signal()
178 self
._postponing
= postponing
180 def elaborate(self
, platform
):
183 count
= Signal(range(self
._postponing
), reset
=self
._postponing
-1)
185 with m
.If(self
.req_i
):
186 with m
.If(count
== 0):
188 count
.eq(count
.reset
),
197 m
.d
.sync
+= self
.req_o
.eq(0)
201 # ZQCSExecuter ----------------------------------------------------------------------------------
204 class ZQCSExecuter(Elaboratable
):
205 """ZQ Short Calibration Executer
207 Execute the ZQCS sequence to the DRAM:
208 - Send a "Precharge All" command
210 - Send an "ZQ Short Calibration" command
214 def __init__(self
, abits
, babits
, trp
, tzqcs
):
215 self
.start
= Signal()
220 self
.a
= Signal(abits
)
221 self
.ba
= Signal(babits
)
226 def elaborate(self
, platform
):
242 # ZQ Short Calibration after tRP
251 # Done after tRP + tZQCS
262 m
.d
.comb
+= tl
.trigger
.eq(self
.start
)
266 # Refresher ----------------------------------------------------------------------------------------
269 class Refresher(Elaboratable
):
274 The DRAM needs to be periodically refreshed with a tREFI period to avoid data corruption. During
275 a refresh, the controller send a "Precharge All" command to close and precharge all rows and then
276 send a "Auto Refresh" command.
278 Before executing the refresh, the Refresher advertises the Controller that a refresh should occur,
279 this allows the Controller to finish the current transaction and block next transactions. Once all
280 transactions are done, the Refresher can execute the refresh Sequence and release the Controller.
284 def __init__(self
, settings
, clk_freq
, zqcs_freq
=1e0
, postponing
=1):
285 assert postponing
<= 8
286 self
._abits
= settings
.geom
.addressbits
287 self
._babits
= settings
.geom
.bankbits
+ log2_int(settings
.phy
.nranks
)
288 self
.cmd
= cmd
= stream
.Endpoint(
289 cmd_request_rw_layout(a
=self
._abits
, ba
=self
._babits
))
290 self
._postponing
= postponing
291 self
._settings
= settings
292 self
._clk
_freq
= clk_freq
293 self
._zqcs
_freq
= zqcs_freq
295 def elaborate(self
, platform
):
298 wants_refresh
= Signal()
300 settings
= self
._settings
302 # Refresh Timer ----------------------------------------------------------------------------
303 timer
= RefreshTimer(settings
.timing
.tREFI
)
304 m
.submodules
.timer
= timer
305 m
.d
.comb
+= timer
.wait
.eq(~timer
.done
)
307 # Refresh Postponer ------------------------------------------------------------------------
308 postponer
= RefreshPostponer(self
._postponing
)
309 m
.submodules
.postponer
= postponer
311 postponer
.req_i
.eq(timer
.done
),
312 wants_refresh
.eq(postponer
.req_o
),
315 # Refresh Sequencer ------------------------------------------------------------------------
316 sequencer
= RefreshSequencer(
317 self
._abits
, self
._babits
, settings
.timing
.tRP
, settings
.timing
.tRFC
, self
._postponing
)
318 m
.submodules
.sequencer
= sequencer
320 if settings
.timing
.tZQCS
is not None:
321 wants_zqcs
= Signal()
323 # ZQCS Timer ---------------------------------------------------------------------------
324 zqcs_timer
= RefreshTimer(int(self
._clk
_freq
/self
._zqcs
_freq
))
325 m
.submodules
.zqcs_timer
= zqcs_timer
326 m
.d
.comb
+= wants_zqcs
.eq(zqcs_timer
.done
)
328 # ZQCS Executer ------------------------------------------------------------------------
329 zqcs_executer
= ZQCSExecuter(
330 self
._abits
, self
._babits
, settings
.timing
.tRP
, settings
.timing
.tZQCS
)
331 m
.submodules
.zqs_executer
= zqcs_executer
332 m
.d
.comb
+= zqcs_timer
.wait
.eq(~zqcs_executer
.done
)
334 # Refresh FSM ------------------------------------------------------------------------------
336 with m
.State("Idle"):
337 with m
.If(settings
.with_refresh
& wants_refresh
):
338 m
.next
= "Wait-Bank-Machines"
340 with m
.State("Wait-Bank-Machines"):
341 m
.d
.comb
+= self
.cmd
.valid
.eq(1)
342 with m
.If(self
.cmd
.ready
):
343 m
.d
.comb
+= sequencer
.start
.eq(1)
344 m
.next
= "Do-Refresh"
346 if settings
.timing
.tZQCS
is None:
347 with m
.State("Do-Refresh"):
348 m
.d
.comb
+= self
.cmd
.valid
.eq(1)
349 with m
.If(sequencer
.done
):
351 self
.cmd
.valid
.eq(0),
356 with m
.State("Do-Refresh"):
357 m
.d
.comb
+= self
.cmd
.valid
.eq(1)
358 with m
.If(sequencer
.done
):
359 with m
.If(wants_zqcs
):
360 m
.d
.comb
+= zqcs_executer
.start
.eq(1)
364 self
.cmd
.valid
.eq(0),
369 with m
.State("Do-Zqcs"):
370 m
.d
.comb
+= self
.cmd
.valid
.eq(1)
371 with m
.If(zqcs_executer
.done
):
373 self
.cmd
.valid
.eq(0),
378 # Connect sequencer/executer outputs to cmd
379 if settings
.timing
.tZQCS
is None:
381 self
.cmd
.a
.eq(sequencer
.a
),
382 self
.cmd
.ba
.eq(sequencer
.ba
),
383 self
.cmd
.cas
.eq(sequencer
.cas
),
384 self
.cmd
.ras
.eq(sequencer
.ras
),
385 self
.cmd
.we
.eq(sequencer
.we
),
389 self
.cmd
.a
.eq(zqcs_executer
.a
),
390 self
.cmd
.ba
.eq(zqcs_executer
.ba
),
391 self
.cmd
.cas
.eq(zqcs_executer
.cas
),
392 self
.cmd
.ras
.eq(zqcs_executer
.ras
),
393 self
.cmd
.we
.eq(zqcs_executer
.we
),