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
.implies(count
== 0)),
150 Assert(countDiffZero
.implies(count
!= 0))
155 # RefreshTimer -------------------------------------------------------------------------------------
158 class RefreshTimer(Elaboratable
):
161 Generate periodic pulses (tREFI period) to trigger DRAM refresh.
164 def __init__(self
, trefi
):
167 self
.count
= Signal(range(trefi
), reset
=trefi
-1)
170 def elaborate(self
, platform
):
177 with m
.If(self
.wait
& (self
.count
!= 0)):
178 m
.d
.sync
+= self
.count
.eq(self
.count
-1)
180 with m
.If(self
.count
== 1):
181 m
.d
.sync
+= self
.done
.eq(1)
184 self
.count
.eq(self
.count
.reset
),
188 if platform
== "formal":
189 m
.d
.comb
+= Assert(self
.done
.implies(self
.count
== 0))
193 # RefreshPostponer -------------------------------------------------------------------------------
196 class RefreshPostponer(Elaboratable
):
199 Postpone N Refresh requests and generate a request when N is reached.
202 def __init__(self
, postponing
=1):
203 self
.req_i
= Signal()
204 self
.req_o
= Signal()
205 self
._postponing
= postponing
207 def elaborate(self
, platform
):
210 count
= Signal(range(self
._postponing
), reset
=self
._postponing
-1)
212 with m
.If(self
.req_i
):
213 with m
.If(count
== 0):
215 count
.eq(count
.reset
),
224 m
.d
.sync
+= self
.req_o
.eq(0)
228 # ZQCSExecuter ----------------------------------------------------------------------------------
231 class ZQCSExecuter(Elaboratable
):
232 """ZQ Short Calibration Executer
234 Execute the ZQCS sequence to the DRAM:
235 - Send a "Precharge All" command
237 - Send an "ZQ Short Calibration" command
241 def __init__(self
, abits
, babits
, trp
, tzqcs
):
242 self
.start
= Signal()
247 self
.a
= Signal(abits
)
248 self
.ba
= Signal(babits
)
253 def elaborate(self
, platform
):
269 # ZQ Short Calibration after tRP
278 # Done after tRP + tZQCS
289 m
.d
.comb
+= tl
.trigger
.eq(self
.start
)
293 # Refresher ----------------------------------------------------------------------------------------
296 class Refresher(Elaboratable
):
301 The DRAM needs to be periodically refreshed with a tREFI period to avoid data corruption. During
302 a refresh, the controller send a "Precharge All" command to close and precharge all rows and then
303 send a "Auto Refresh" command.
305 Before executing the refresh, the Refresher advertises the Controller that a refresh should occur,
306 this allows the Controller to finish the current transaction and block next transactions. Once all
307 transactions are done, the Refresher can execute the refresh Sequence and release the Controller.
311 def __init__(self
, settings
, clk_freq
, zqcs_freq
=1e0
, postponing
=1):
312 assert postponing
<= 8
313 self
._abits
= settings
.geom
.addressbits
314 self
._babits
= settings
.geom
.bankbits
+ log2_int(settings
.phy
.nranks
)
315 self
.cmd
= cmd
= stream
.Endpoint(
316 cmd_request_rw_layout(a
=self
._abits
, ba
=self
._babits
))
317 self
._postponing
= postponing
318 self
._settings
= settings
319 self
._clk
_freq
= clk_freq
320 self
._zqcs
_freq
= zqcs_freq
322 def elaborate(self
, platform
):
325 wants_refresh
= Signal()
327 settings
= self
._settings
329 # Refresh Timer ----------------------------------------------------------------------------
330 timer
= RefreshTimer(settings
.timing
.tREFI
)
331 m
.submodules
.timer
= timer
332 m
.d
.comb
+= timer
.wait
.eq(~timer
.done
)
334 # Refresh Postponer ------------------------------------------------------------------------
335 postponer
= RefreshPostponer(self
._postponing
)
336 m
.submodules
.postponer
= postponer
338 postponer
.req_i
.eq(timer
.done
),
339 wants_refresh
.eq(postponer
.req_o
),
342 # Refresh Sequencer ------------------------------------------------------------------------
343 sequencer
= RefreshSequencer(
344 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(
357 self
._abits
, self
._babits
, settings
.timing
.tRP
, settings
.timing
.tZQCS
)
358 m
.submodules
.zqs_executer
= zqcs_executer
359 m
.d
.comb
+= zqcs_timer
.wait
.eq(~zqcs_executer
.done
)
361 # Refresh FSM ------------------------------------------------------------------------------
363 with m
.State("Idle"):
364 with m
.If(settings
.with_refresh
& wants_refresh
):
365 m
.next
= "Wait-Bank-Machines"
367 with m
.State("Wait-Bank-Machines"):
368 m
.d
.comb
+= self
.cmd
.valid
.eq(1)
369 with m
.If(self
.cmd
.ready
):
370 m
.d
.comb
+= sequencer
.start
.eq(1)
371 m
.next
= "Do-Refresh"
373 if settings
.timing
.tZQCS
is None:
374 with m
.State("Do-Refresh"):
375 m
.d
.comb
+= self
.cmd
.valid
.eq(1)
376 with m
.If(sequencer
.done
):
378 self
.cmd
.valid
.eq(0),
383 with m
.State("Do-Refresh"):
384 m
.d
.comb
+= self
.cmd
.valid
.eq(1)
385 with m
.If(sequencer
.done
):
386 with m
.If(wants_zqcs
):
387 m
.d
.comb
+= zqcs_executer
.start
.eq(1)
391 self
.cmd
.valid
.eq(0),
396 with m
.State("Do-Zqcs"):
397 m
.d
.comb
+= self
.cmd
.valid
.eq(1)
398 with m
.If(zqcs_executer
.done
):
400 self
.cmd
.valid
.eq(0),
405 # Connect sequencer/executer outputs to cmd
406 if settings
.timing
.tZQCS
is None:
408 self
.cmd
.a
.eq(sequencer
.a
),
409 self
.cmd
.ba
.eq(sequencer
.ba
),
410 self
.cmd
.cas
.eq(sequencer
.cas
),
411 self
.cmd
.ras
.eq(sequencer
.ras
),
412 self
.cmd
.we
.eq(sequencer
.we
),
416 self
.cmd
.a
.eq(zqcs_executer
.a
),
417 self
.cmd
.ba
.eq(zqcs_executer
.ba
),
418 self
.cmd
.cas
.eq(zqcs_executer
.cas
),
419 self
.cmd
.ras
.eq(zqcs_executer
.ras
),
420 self
.cmd
.we
.eq(zqcs_executer
.we
),