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
):
56 # Auto Refresh after tRP
64 # Done after tRP + tRFC
75 m
.d
.comb
+= tl
.trigger
.eq(self
.start
)
79 # RefreshSequencer ---------------------------------------------------------------------------------
82 class RefreshSequencer(Elaboratable
):
85 Sequence N refreshs to the DRAM.
88 def __init__(self
, abits
, babits
, trp
, trfc
, postponing
=1):
94 self
._postponing
= postponing
98 self
.a
= Signal(abits
)
99 self
.ba
= Signal(babits
)
104 def elaborate(self
, platform
):
107 executer
= RefreshExecuter(self
._abits
, self
._babits
, self
._trp
, self
._trfc
)
108 m
.submodules
+= executer
110 self
.a
.eq(executer
.a
),
111 self
.ba
.eq(executer
.ba
),
112 self
.cas
.eq(executer
.cas
),
113 self
.ras
.eq(executer
.ras
),
114 self
.we
.eq(executer
.we
),
117 countEqZero
= Signal(reset
=(self
._postponing
<= 1))
118 countDiffZero
= Signal(reset
=(self
._postponing
> 1))
120 count
= Signal(range(self
._postponing
), reset
=self
._postponing
-1)
121 with m
.If(self
.start
):
123 count
.eq(count
.reset
),
124 countEqZero
.eq(self
._postponing
<= 1),
125 countDiffZero
.eq(self
._postponing
> 1),
127 with m
.Elif(executer
.done
):
128 with m
.If(count
!= 0):
129 m
.d
.sync
+= count
.eq(count
-1)
131 with m
.If(count
== 1):
143 executer
.start
.eq(self
.start | countDiffZero
),
144 self
.done
.eq(executer
.done
& countEqZero
),
147 if platform
== "formal":
149 Assert(countEqZero
== (count
== 0)),
150 Assert(countDiffZero
== (count
!= 0)),
155 # RefreshTimer -------------------------------------------------------------------------------------
158 class RefreshTimer(Elaboratable
):
161 Generate periodic pulses (tREFI period) to trigger DRAM refresh.
164 def __init__(self
, trefi
):
165 # TODO: we don't pass formal verification for trefi = 1
170 self
.count
= Signal(range(trefi
), reset
=trefi
-1)
173 def elaborate(self
, platform
):
178 with m
.If(self
.wait
& (self
.count
!= 0)):
179 m
.d
.sync
+= self
.count
.eq(self
.count
-1)
181 with m
.If(self
.count
== 1):
182 m
.d
.sync
+= self
.done
.eq(1)
185 self
.count
.eq(self
.count
.reset
),
189 if platform
== "formal":
190 m
.d
.comb
+= Assert(self
.done
== (self
.count
== 0))
194 # RefreshPostponer -------------------------------------------------------------------------------
197 class RefreshPostponer(Elaboratable
):
200 Postpone N Refresh requests and generate a request when N is reached.
203 def __init__(self
, postponing
=1):
204 self
.req_i
= Signal()
205 self
.req_o
= Signal()
206 self
._postponing
= postponing
208 def elaborate(self
, platform
):
211 count
= Signal(range(self
._postponing
), reset
=self
._postponing
-1)
213 with m
.If(self
.req_i
):
214 with m
.If(count
== 0):
216 count
.eq(count
.reset
),
225 m
.d
.sync
+= self
.req_o
.eq(0)
229 # ZQCSExecuter ----------------------------------------------------------------------------------
232 class ZQCSExecuter(Elaboratable
):
233 """ZQ Short Calibration Executer
235 Execute the ZQCS sequence to the DRAM:
236 - Send a "Precharge All" command
238 - Send an "ZQ Short Calibration" command
242 def __init__(self
, abits
, babits
, trp
, tzqcs
):
243 self
.start
= Signal()
248 self
.a
= Signal(abits
)
249 self
.ba
= Signal(babits
)
254 def elaborate(self
, platform
):
270 # ZQ Short Calibration after tRP
279 # Done after tRP + tZQCS
290 m
.d
.comb
+= tl
.trigger
.eq(self
.start
)
294 # Refresher ----------------------------------------------------------------------------------------
297 class Refresher(Elaboratable
):
302 The DRAM needs to be periodically refreshed with a tREFI period to avoid data corruption. During
303 a refresh, the controller send a "Precharge All" command to close and precharge all rows and then
304 send a "Auto Refresh" command.
306 Before executing the refresh, the Refresher advertises the Controller that a refresh should occur,
307 this allows the Controller to finish the current transaction and block next transactions. Once all
308 transactions are done, the Refresher can execute the refresh Sequence and release the Controller.
312 def __init__(self
, settings
, clk_freq
, zqcs_freq
=1e0
, postponing
=1):
313 assert postponing
<= 8
314 self
._abits
= settings
.geom
.addressbits
315 self
._babits
= settings
.geom
.bankbits
+ log2_int(settings
.phy
.nranks
)
316 self
.cmd
= cmd
= stream
.Endpoint(
317 cmd_request_rw_layout(a
=self
._abits
, ba
=self
._babits
))
318 self
._postponing
= postponing
319 self
._settings
= settings
320 self
._clk
_freq
= clk_freq
321 self
._zqcs
_freq
= zqcs_freq
323 def elaborate(self
, platform
):
326 wants_refresh
= Signal()
328 settings
= self
._settings
330 # Refresh Timer ----------------------------------------------------------------------------
331 timer
= RefreshTimer(settings
.timing
.tREFI
)
332 m
.submodules
.timer
= timer
333 m
.d
.comb
+= timer
.wait
.eq(~timer
.done
)
335 # Refresh Postponer ------------------------------------------------------------------------
336 postponer
= RefreshPostponer(self
._postponing
)
337 m
.submodules
.postponer
= postponer
339 postponer
.req_i
.eq(timer
.done
),
340 wants_refresh
.eq(postponer
.req_o
),
343 # Refresh Sequencer ------------------------------------------------------------------------
344 sequencer
= RefreshSequencer(self
._abits
, self
._babits
, settings
.timing
.tRP
, settings
.timing
.tRFC
, self
._postponing
)
345 m
.submodules
.sequencer
= sequencer
347 if settings
.timing
.tZQCS
is not None:
348 wants_zqcs
= Signal()
350 # ZQCS Timer ---------------------------------------------------------------------------
351 zqcs_timer
= RefreshTimer(int(self
._clk
_freq
/self
._zqcs
_freq
))
352 m
.submodules
.zqcs_timer
= zqcs_timer
353 m
.d
.comb
+= wants_zqcs
.eq(zqcs_timer
.done
)
355 # ZQCS Executer ------------------------------------------------------------------------
356 zqcs_executer
= ZQCSExecuter(self
._abits
, self
._babits
, settings
.timing
.tRP
, settings
.timing
.tZQCS
)
357 m
.submodules
.zqs_executer
= zqcs_executer
358 m
.d
.comb
+= zqcs_timer
.wait
.eq(~zqcs_executer
.done
)
360 # Refresh FSM ------------------------------------------------------------------------------
362 with m
.State("Idle"):
363 with m
.If(settings
.with_refresh
& wants_refresh
):
364 m
.next
= "Wait-Bank-Machines"
366 with m
.State("Wait-Bank-Machines"):
367 m
.d
.comb
+= self
.cmd
.valid
.eq(1)
368 with m
.If(self
.cmd
.ready
):
369 m
.d
.comb
+= sequencer
.start
.eq(1)
370 m
.next
= "Do-Refresh"
372 if settings
.timing
.tZQCS
is None:
373 with m
.State("Do-Refresh"):
374 m
.d
.comb
+= self
.cmd
.valid
.eq(1)
375 with m
.If(sequencer
.done
):
377 self
.cmd
.valid
.eq(0),
382 with m
.State("Do-Refresh"):
383 m
.d
.comb
+= self
.cmd
.valid
.eq(1)
384 with m
.If(sequencer
.done
):
385 with m
.If(wants_zqcs
):
386 m
.d
.comb
+= zqcs_executer
.start
.eq(1)
390 self
.cmd
.valid
.eq(0),
395 with m
.State("Do-Zqcs"):
396 m
.d
.comb
+= self
.cmd
.valid
.eq(1)
397 with m
.If(zqcs_executer
.done
):
399 self
.cmd
.valid
.eq(0),
404 # Connect sequencer/executer outputs to cmd
405 if settings
.timing
.tZQCS
is None:
407 self
.cmd
.a
.eq(sequencer
.a
),
408 self
.cmd
.ba
.eq(sequencer
.ba
),
409 self
.cmd
.cas
.eq(sequencer
.cas
),
410 self
.cmd
.ras
.eq(sequencer
.ras
),
411 self
.cmd
.we
.eq(sequencer
.we
),
415 self
.cmd
.a
.eq(zqcs_executer
.a
),
416 self
.cmd
.ba
.eq(zqcs_executer
.ba
),
417 self
.cmd
.cas
.eq(zqcs_executer
.cas
),
418 self
.cmd
.ras
.eq(zqcs_executer
.ras
),
419 self
.cmd
.we
.eq(zqcs_executer
.we
),