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
10 from nmigen
.asserts
import Assert
, Assume
12 from gram
.core
.multiplexer
import *
13 from gram
.compat
import Timeline
14 import gram
.stream
as stream
16 # RefreshExecuter ----------------------------------------------------------------------------------
19 class RefreshExecuter(Elaboratable
):
22 Execute the refresh sequence to the DRAM:
23 - Send a "Precharge All" command
25 - Send an "Auto Refresh" command
29 def __init__(self
, abits
, babits
, trp
, trfc
):
35 self
.a
= Signal(abits
)
36 self
.ba
= Signal(babits
)
41 def elaborate(self
, platform
):
47 m
.submodules
.timeline
= tl
= Timeline([
56 # Auto Refresh after tRP
64 # 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 m
.submodules
.executer
= executer
= RefreshExecuter(self
._abits
, self
._babits
, self
._trp
, self
._trfc
)
108 self
.a
.eq(executer
.a
),
109 self
.ba
.eq(executer
.ba
),
110 self
.cas
.eq(executer
.cas
),
111 self
.ras
.eq(executer
.ras
),
112 self
.we
.eq(executer
.we
),
115 countEqZero
= Signal(reset
=(self
._postponing
<= 1))
116 countDiffZero
= Signal(reset
=(self
._postponing
> 1))
118 count
= Signal(range(self
._postponing
), reset
=self
._postponing
-1)
119 with m
.If(self
.start
):
121 count
.eq(count
.reset
),
122 countEqZero
.eq(self
._postponing
<= 1),
123 countDiffZero
.eq(self
._postponing
> 1),
125 with m
.Elif(executer
.done
):
126 with m
.If(count
!= 0):
127 m
.d
.sync
+= count
.eq(count
-1)
129 with m
.If(count
== 1):
141 executer
.start
.eq(self
.start | countDiffZero
),
142 self
.done
.eq(executer
.done
& countEqZero
),
145 if platform
== "formal":
147 Assert(countEqZero
== (count
== 0)),
148 Assert(countDiffZero
== (count
!= 0)),
153 # RefreshTimer -------------------------------------------------------------------------------------
156 class RefreshTimer(Elaboratable
):
159 Generate periodic pulses (tREFI period) to trigger DRAM refresh.
162 def __init__(self
, trefi
):
163 # TODO: we don't pass formal verification for trefi = 1
168 self
.count
= Signal(range(trefi
), reset
=trefi
-1)
171 def elaborate(self
, platform
):
176 with m
.If(self
.wait
& (self
.count
!= 0)):
177 m
.d
.sync
+= self
.count
.eq(self
.count
-1)
179 with m
.If(self
.count
== 1):
180 m
.d
.sync
+= self
.done
.eq(1)
183 self
.count
.eq(self
.count
.reset
),
187 if platform
== "formal":
188 m
.d
.comb
+= Assert(self
.done
== (self
.count
== 0))
192 # RefreshPostponer -------------------------------------------------------------------------------
195 class RefreshPostponer(Elaboratable
):
198 Postpone N Refresh requests and generate a request when N is reached.
201 def __init__(self
, postponing
=1):
202 self
.req_i
= Signal()
203 self
.req_o
= Signal()
204 self
._postponing
= postponing
206 def elaborate(self
, platform
):
209 count
= Signal(range(self
._postponing
), reset
=self
._postponing
-1)
211 with m
.If(self
.req_i
):
212 with m
.If(count
== 0):
214 count
.eq(count
.reset
),
223 m
.d
.sync
+= self
.req_o
.eq(0)
227 # ZQCSExecuter ----------------------------------------------------------------------------------
230 class ZQCSExecuter(Elaboratable
):
231 """ZQ Short Calibration Executer
233 Execute the ZQCS sequence to the DRAM:
234 - Send a "Precharge All" command
236 - Send an "ZQ Short Calibration" command
240 def __init__(self
, abits
, babits
, trp
, tzqcs
):
241 self
.start
= Signal()
246 self
.a
= Signal(abits
)
247 self
.ba
= Signal(babits
)
252 def elaborate(self
, platform
):
258 m
.submodules
.timeline
= tl
= Timeline([
268 # ZQ Short Calibration after tRP
277 # Done after tRP + tZQCS
287 m
.d
.comb
+= tl
.trigger
.eq(self
.start
)
291 # Refresher ----------------------------------------------------------------------------------------
294 class Refresher(Elaboratable
):
299 The DRAM needs to be periodically refreshed with a tREFI period to avoid data corruption. During
300 a refresh, the controller send a "Precharge All" command to close and precharge all rows and then
301 send a "Auto Refresh" command.
303 Before executing the refresh, the Refresher advertises the Controller that a refresh should occur,
304 this allows the Controller to finish the current transaction and block next transactions. Once all
305 transactions are done, the Refresher can execute the refresh Sequence and release the Controller.
309 def __init__(self
, settings
, clk_freq
, zqcs_freq
=1e0
, postponing
=1):
310 assert postponing
<= 8
311 self
._abits
= settings
.geom
.addressbits
312 self
._babits
= settings
.geom
.bankbits
+ log2_int(settings
.phy
.nranks
)
313 self
.cmd
= cmd
= stream
.Endpoint(
314 cmd_request_rw_layout(a
=self
._abits
, ba
=self
._babits
))
315 self
._postponing
= postponing
316 self
._settings
= settings
317 self
._clk
_freq
= clk_freq
318 self
._zqcs
_freq
= zqcs_freq
320 def elaborate(self
, platform
):
323 wants_refresh
= Signal()
325 settings
= self
._settings
327 # Refresh Timer ----------------------------------------------------------------------------
328 timer
= RefreshTimer(settings
.timing
.tREFI
)
329 m
.submodules
.timer
= timer
330 m
.d
.comb
+= timer
.wait
.eq(~timer
.done
)
332 # Refresh Postponer ------------------------------------------------------------------------
333 postponer
= RefreshPostponer(self
._postponing
)
334 m
.submodules
.postponer
= postponer
336 postponer
.req_i
.eq(timer
.done
),
337 wants_refresh
.eq(postponer
.req_o
),
340 # Refresh Sequencer ------------------------------------------------------------------------
341 sequencer
= RefreshSequencer(self
._abits
, self
._babits
, settings
.timing
.tRP
, settings
.timing
.tRFC
, self
._postponing
)
342 m
.submodules
.sequencer
= sequencer
344 if settings
.timing
.tZQCS
is not None:
345 wants_zqcs
= Signal()
347 # ZQCS Timer ---------------------------------------------------------------------------
348 zqcs_timer
= RefreshTimer(int(self
._clk
_freq
/self
._zqcs
_freq
))
349 m
.submodules
.zqcs_timer
= zqcs_timer
350 m
.d
.comb
+= wants_zqcs
.eq(zqcs_timer
.done
)
352 # ZQCS Executer ------------------------------------------------------------------------
353 zqcs_executer
= ZQCSExecuter(self
._abits
, self
._babits
, settings
.timing
.tRP
, settings
.timing
.tZQCS
)
354 m
.submodules
.zqs_executer
= zqcs_executer
355 m
.d
.comb
+= zqcs_timer
.wait
.eq(~zqcs_executer
.done
)
357 # Refresh FSM ------------------------------------------------------------------------------
359 with m
.State("Idle"):
360 with m
.If(settings
.with_refresh
& wants_refresh
):
361 m
.next
= "Wait-Bank-Machines"
363 with m
.State("Wait-Bank-Machines"):
364 m
.d
.comb
+= self
.cmd
.valid
.eq(1)
365 with m
.If(self
.cmd
.ready
):
366 m
.d
.comb
+= sequencer
.start
.eq(1)
367 m
.next
= "Do-Refresh"
369 if settings
.timing
.tZQCS
is None:
370 with m
.State("Do-Refresh"):
371 m
.d
.comb
+= self
.cmd
.valid
.eq(~sequencer
.done
)
372 with m
.If(sequencer
.done
):
373 m
.d
.comb
+= self
.cmd
.last
.eq(1)
376 with m
.State("Do-Refresh"):
377 m
.d
.comb
+= self
.cmd
.valid
.eq(wants_zqcs
& ~sequencer
.done
)
378 with m
.If(sequencer
.done
):
379 with m
.If(wants_zqcs
):
380 m
.d
.comb
+= zqcs_executer
.start
.eq(1)
383 m
.d
.comb
+= self
.cmd
.last
.eq(1)
386 with m
.State("Do-Zqcs"):
387 m
.d
.comb
+= self
.cmd
.valid
.eq(~zqcs_executer
.done
)
388 with m
.If(zqcs_executer
.done
):
389 m
.d
.comb
+= self
.cmd
.last
.eq(1)
392 # Connect sequencer/executer outputs to cmd
393 if settings
.timing
.tZQCS
is None:
395 self
.cmd
.a
.eq(sequencer
.a
),
396 self
.cmd
.ba
.eq(sequencer
.ba
),
397 self
.cmd
.cas
.eq(sequencer
.cas
),
398 self
.cmd
.ras
.eq(sequencer
.ras
),
399 self
.cmd
.we
.eq(sequencer
.we
),
403 self
.cmd
.a
.eq(zqcs_executer
.a
),
404 self
.cmd
.ba
.eq(zqcs_executer
.ba
),
405 self
.cmd
.cas
.eq(zqcs_executer
.cas
),
406 self
.cmd
.ras
.eq(zqcs_executer
.ras
),
407 self
.cmd
.we
.eq(zqcs_executer
.we
),