add ZQ periodic short calibration support (default to 1s)

This commit is contained in:
Florent Kermarrec 2019-09-09 15:07:38 +02:00
parent 6e176d40ac
commit 188b6a8feb
5 changed files with 161 additions and 49 deletions

View file

@ -53,7 +53,7 @@ class GeomSettings(Settings):
class TimingSettings(Settings):
def __init__(self, tRP, tRCD, tWR, tWTR, tREFI, tRFC, tFAW, tCCD, tRRD, tRC, tRAS):
def __init__(self, tRP, tRCD, tWR, tWTR, tREFI, tRFC, tFAW, tCCD, tRRD, tRC, tRAS, tZQCS):
self.set_attributes(locals())
# Layouts/Interface ------------------------------------------------------------

View file

@ -18,7 +18,7 @@ class ControllerSettings(Settings):
cmd_buffer_depth=8, cmd_buffer_buffered=False,
read_time=32, write_time=16,
with_bandwidth=False,
with_refresh=True, refresher_cls=Refresher,
with_refresh=True, refresher_cls=Refresher, refresher_zqcs_freq=1e0,
with_auto_precharge=True,
address_mapping="ROW_BANK_COL"):
self.set_attributes(locals())
@ -26,7 +26,7 @@ class ControllerSettings(Settings):
# Controller ---------------------------------------------------------------------------------------
class LiteDRAMController(Module):
def __init__(self, phy_settings, geom_settings, timing_settings,
def __init__(self, phy_settings, geom_settings, timing_settings, clk_freq,
controller_settings=ControllerSettings()):
address_align = log2_int(burst_lengths[phy_settings.memtype])
@ -53,7 +53,7 @@ class LiteDRAMController(Module):
# # #
# Refresher --------------------------------------------------------------------------------
self.submodules.refresher = self.settings.refresher_cls(self.settings)
self.submodules.refresher = self.settings.refresher_cls(self.settings, clk_freq)
# Bank Machines ----------------------------------------------------------------------------
bank_machines = []

View file

@ -20,7 +20,7 @@ class RefreshExecuter(Module):
- Send a "Precharge All" command
- Wait tRP
- Send an "Auto Refresh" command
- Wait rRFC
- Wait tRFC
"""
def __init__(self, cmd, trp, trfc):
self.start = Signal()
@ -29,22 +29,39 @@ class RefreshExecuter(Module):
# # #
self.sync += [
cmd.a.eq(2**10),
cmd.ba.eq(0),
cmd.a.eq( 0),
cmd.ba.eq( 0),
cmd.cas.eq(0),
cmd.ras.eq(0),
cmd.we.eq(0),
]
self.sync += [
cmd.we.eq( 0),
self.done.eq(0),
# Wait start
timeline(self.start, [
# Precharge All
(0, [cmd.ras.eq(1), cmd.we.eq(1)]),
(0, [
cmd.a.eq( 2**10),
cmd.ba.eq( 0),
cmd.cas.eq(0),
cmd.ras.eq(1),
cmd.we.eq( 1)
]),
# Auto Refresh after tRP
(trp, [cmd.cas.eq(1), cmd.ras.eq(1)]),
(trp, [
cmd.a.eq( 0),
cmd.ba.eq( 0),
cmd.cas.eq(1),
cmd.ras.eq(1),
cmd.we.eq( 0),
]),
# Done after tRP + tRFC
(trp + trfc, [self.done.eq(1)])
(trp + trfc, [
cmd.a.eq( 0),
cmd.ba.eq( 0),
cmd.cas.eq(0),
cmd.ras.eq(0),
cmd.we.eq( 0),
self.done.eq(1),
]),
])
]
@ -132,6 +149,56 @@ class RefreshAccumulator(Module):
)
]
# ZQCSExecuter ----------------------------------------------------------------------------------
class ZQCSExecuter(Module):
"""ZQ Short Calibration Executer
Execute the ZQCS sequence to the DRAM:
- Send a "Precharge All" command
- Wait tRP
- Send an "ZQ Short Calibration" command
- Wait tZQCS
"""
def __init__(self, cmd, trp, tzqcs):
self.start = Signal()
self.done = Signal()
# # #
self.sync += [
# Note: Don't set cmd to 0 since already done in RefreshExecuter
self.done.eq(0),
# Wait start
timeline(self.start, [
# Precharge All
(0, [
cmd.a.eq( 2**10),
cmd.ba.eq( 0),
cmd.cas.eq(0),
cmd.ras.eq(1),
cmd.we.eq( 1)
]),
# ZQ Short Calibration after tRP
(trp, [
cmd.a.eq( 0),
cmd.ba.eq( 0),
cmd.cas.eq(0),
cmd.ras.eq(0),
cmd.we.eq( 1),
]),
# Done after tRP + tZQCS
(trp + tzqcs, [
cmd.a.eq( 0),
cmd.ba.eq( 0),
cmd.cas.eq(0),
cmd.ras.eq(0),
cmd.we.eq( 0),
self.done.eq(1)
]),
])
]
# Refresher ----------------------------------------------------------------------------------------
class Refresher(Module):
@ -148,51 +215,86 @@ class Refresher(Module):
transactions are done, the Refresher can execute the refresh Sequence and release the Controller.
"""
def __init__(self, settings, n=1):
def __init__(self, settings, clk_freq, n=1):
abits = settings.geom.addressbits
babits = settings.geom.bankbits + log2_int(settings.phy.nranks)
self.cmd = cmd = stream.Endpoint(cmd_request_rw_layout(a=abits, ba=babits))
# # #
wants_refresh = Signal()
wants_zqcs = Signal()
# Refresh Timer ----------------------------------------------------------------------------
timer = RefreshTimer(settings.timing.tREFI)
self.submodules.timer = timer
self.comb += self.timer.wait.eq(~self.timer.done)
self.comb += timer.wait.eq(~timer.done)
# Refresh Accumulator ----------------------------------------------------------------------
accum = RefreshAccumulator(n=n)
self.submodules.accum = accum
self.comb += accum.req_i.eq(self.timer.done)
self.comb += wants_refresh.eq(accum.req_o)
# Refresh Sequencer ------------------------------------------------------------------------
sequencer = RefreshSequencer(cmd, settings.timing.tRP, settings.timing.tRFC, n=n)
self.submodules.sequencer = sequencer
if settings.timing.tZQCS is not None:
# ZQCS Timer ---------------------------------------------------------------------------
zqcs_timer = RefreshTimer(int(clk_freq/settings.refresher_zqcs_freq))
self.submodules.zqcs_timer = zqcs_timer
self.comb += wants_zqcs.eq(zqcs_timer.done)
# ZQCS Executer ------------------------------------------------------------------------
zqcs_executer = ZQCSExecuter(cmd, settings.timing.tRP, settings.timing.tZQCS)
self.submodules.zqs_executer = zqcs_executer
self.comb += zqcs_timer.wait.eq(~zqcs_executer.done)
# Refresh FSM ------------------------------------------------------------------------------
self.submodules.fsm = fsm = FSM()
fsm.act("IDLE",
If(settings.with_refresh,
# Wait refresh accumulator
If(accum.req_o,
NextState("WAIT-GRANT")
If(wants_refresh,
NextState("WAIT-BANK-MACHINES")
)
)
)
fsm.act("WAIT-GRANT",
# Advertise Controller, wait grant and start Sequencer
fsm.act("WAIT-BANK-MACHINES",
cmd.valid.eq(1),
If(cmd.ready,
sequencer.start.eq(1),
NextState("WAIT-SEQUENCER")
NextState("DO-REFRESH")
)
)
fsm.act("WAIT-SEQUENCER",
# Wait Sequencer and advertise Controller when done
cmd.valid.eq(1),
If(sequencer.done,
cmd.valid.eq(0),
cmd.last.eq(1),
NextState("IDLE")
if settings.timing.tZQCS is None:
fsm.act("DO-REFRESH",
cmd.valid.eq(1),
If(sequencer.done,
cmd.valid.eq(0),
cmd.last.eq(1),
NextState("IDLE")
)
)
else:
fsm.act("DO-REFRESH",
cmd.valid.eq(1),
If(sequencer.done,
If(wants_zqcs,
zqcs_executer.start.eq(1),
NextState("DO-ZQCS")
).Else(
cmd.valid.eq(0),
cmd.last.eq(1),
NextState("IDLE")
)
)
)
fsm.act("DO-ZQCS",
cmd.valid.eq(1),
If(zqcs_executer.done,
cmd.valid.eq(0),
cmd.last.eq(1),
NextState("IDLE")
)
)
)

View file

@ -16,13 +16,20 @@ from collections import namedtuple
from migen import *
from litedram.common import GeomSettings, TimingSettings
from litedram.common import Settings, GeomSettings, TimingSettings
_technology_timings = ["tREFI", "tWTR", "tCCD", "tRRD", "tZQCS"]
class _TechnologyTimings(Settings):
def __init__(self, tREFI, tWTR, tCCD, tRRD, tZQCS=None):
self.set_attributes(locals())
_technology_timings = ["tREFI", "tWTR", "tCCD", "tRRD"]
_TechnologyTimings = namedtuple("TechnologyTimings", _technology_timings)
_speedgrade_timings = ["tRP", "tRCD", "tWR", "tRFC", "tFAW", "tRAS"]
_SpeedgradeTimings = namedtuple("SpeedgradeTimings", _speedgrade_timings)
class _SpeedgradeTimings(Settings):
def __init__(self, tRP, tRCD, tWR, tRFC, tFAW, tRAS):
self.set_attributes(locals())
class SDRAMModule:
@ -56,7 +63,8 @@ class SDRAMModule:
tCCD=None if self.get("tCCD") is None else self.ck_ns_to_cycles(*self.get("tCCD")),
tRRD=None if self.get("tRRD") is None else self.ck_ns_to_cycles(*self.get("tRRD")),
tRC=None if self.get("tRAS") is None else self.ns_to_cycles(self.get("tRP") + self.get("tRAS")),
tRAS=None if self.get("tRAS") is None else self.ns_to_cycles(self.get("tRAS"))
tRAS=None if self.get("tRAS") is None else self.ns_to_cycles(self.get("tRAS")),
tZQCS=None if self.get("tZQCS") is None else self.ck_ns_to_cycles(*self.get("tZQCS"))
)
def get(self, name):
@ -259,7 +267,7 @@ class MT41K64M16(SDRAMModule):
nrows = 8192
ncols = 1024
# timings
technology_timings = _TechnologyTimings(tREFI=64e6/8192, tWTR=(4, 7.5), tCCD=(4, None), tRRD=(4, 10))
technology_timings = _TechnologyTimings(tREFI=64e6/8192, tWTR=(4, 7.5), tCCD=(4, None), tRRD=(4, 10), tZQCS=(64, 80))
speedgrade_timings = {
"800": _SpeedgradeTimings(tRP=13.1, tRCD=13.1, tWR=13.1, tRFC=(64, None), tFAW=(None, 50), tRAS=37.5),
"1066": _SpeedgradeTimings(tRP=13.1, tRCD=13.1, tWR=13.1, tRFC=(86, None), tFAW=(None, 50), tRAS=37.5),
@ -276,7 +284,7 @@ class MT41J128M16(SDRAMModule):
nrows = 16384
ncols = 1024
# timings
technology_timings = _TechnologyTimings(tREFI=64e6/8192, tWTR=(4, 7.5), tCCD=(4, None), tRRD=(4, 10))
technology_timings = _TechnologyTimings(tREFI=64e6/8192, tWTR=(4, 7.5), tCCD=(4, None), tRRD=(4, 10), tZQCS=(64, 80))
speedgrade_timings = {
"800": _SpeedgradeTimings(tRP=13.1, tRCD=13.1, tWR=13.1, tRFC=(64, None), tFAW=(None, 50), tRAS=37.5),
"1066": _SpeedgradeTimings(tRP=13.1, tRCD=13.1, tWR=13.1, tRFC=(86, None), tFAW=(None, 50), tRAS=37.5),
@ -297,7 +305,7 @@ class MT41J256M16(SDRAMModule):
nrows = 32768
ncols = 1024
# timings
technology_timings = _TechnologyTimings(tREFI=64e6/8192, tWTR=(4, 7.5), tCCD=(4, None), tRRD=(4, 10))
technology_timings = _TechnologyTimings(tREFI=64e6/8192, tWTR=(4, 7.5), tCCD=(4, None), tRRD=(4, 10), tZQCS=(64, 80))
speedgrade_timings = {
"800": _SpeedgradeTimings(tRP=13.1, tRCD=13.1, tWR=13.1, tRFC=(139, None), tFAW=(None, 50), tRAS=37.5),
"1066": _SpeedgradeTimings(tRP=13.1, tRCD=13.1, tWR=13.1, tRFC=(138, None), tFAW=(None, 50), tRAS=37.5),
@ -318,7 +326,7 @@ class K4B1G0446F(SDRAMModule):
nrows = 16384
ncols = 1024
# timings
technology_timings = _TechnologyTimings(tREFI=64e6/8192, tWTR=(4, 7.5), tCCD=(4, None), tRRD=(4, 10))
technology_timings = _TechnologyTimings(tREFI=64e6/8192, tWTR=(4, 7.5), tCCD=(4, None), tRRD=(4, 10), tZQCS=(64, 80))
speedgrade_timings = {
"800": _SpeedgradeTimings(tRP=15, tRCD=15, tWR=15, tRFC=(120, None), tFAW=(None, 50), tRAS=37.5),
"1066": _SpeedgradeTimings(tRP=13.125, tRCD=13.125, tWR=15, tRFC=(160, None), tFAW=(None, 50), tRAS=37.5),
@ -335,7 +343,7 @@ class K4B2G1646F(SDRAMModule):
nrows = 16384
ncols = 1024
# timings
technology_timings = _TechnologyTimings(tREFI=64e6/8192, tWTR=(4, 7.5), tCCD=(4, None), tRRD=(4, 10))
technology_timings = _TechnologyTimings(tREFI=64e6/8192, tWTR=(4, 7.5), tCCD=(4, None), tRRD=(4, 10), tZQCS=(64, 80))
speedgrade_timings = {
"800": _SpeedgradeTimings(tRP=15, tRCD=15, tWR=15, tRFC=(104, None), tFAW=(None, 50), tRAS=37.5),
"1066": _SpeedgradeTimings(tRP=13.125, tRCD=13.125, tWR=15, tRFC=(139, None), tFAW=(None, 50), tRAS=37.5),
@ -352,7 +360,7 @@ class IS43TR16128B(SDRAMModule):
nrows = 16384
ncols = 1024
# timings
technology_timings = _TechnologyTimings(tREFI=64e6/8192, tWTR=(4, 7.5), tCCD=(4, None), tRRD=(4, 6))
technology_timings = _TechnologyTimings(tREFI=64e6/8192, tWTR=(4, 7.5), tCCD=(4, None), tRRD=(4, 6), tZQCS=(64, 80))
speedgrade_timings = {
"1600": _SpeedgradeTimings(tRP=13.75, tRCD=13.75, tWR=15, tRFC=(None, 160), tFAW=(None, 40), tRAS=35),
}
@ -367,7 +375,7 @@ class MT8JTF12864(SDRAMModule):
nrows = 16384
ncols = 1024
# timings
technology_timings = _TechnologyTimings(tREFI=64e6/8192, tWTR=(4, 7.5), tCCD=(4, None), tRRD=(4, 10))
technology_timings = _TechnologyTimings(tREFI=64e6/8192, tWTR=(4, 7.5), tCCD=(4, None), tRRD=(4, 10), tZQCS=(64, 80))
speedgrade_timings = {
"1066": _SpeedgradeTimings(tRP=15, tRCD=15, tWR=15, tRFC=(86, None), tFAW=(None, 50), tRAS=None),
"1333": _SpeedgradeTimings(tRP=15, tRCD=15, tWR=15, tRFC=(107, None), tFAW=(None, 45), tRAS=None),
@ -382,7 +390,7 @@ class MT8KTF51264(SDRAMModule):
nrows = 16384
ncols = 1024
# timings
technology_timings = _TechnologyTimings(tREFI=64e6/8192, tWTR=(4, 7.5), tCCD=(4, None), tRRD=(4, 10))
technology_timings = _TechnologyTimings(tREFI=64e6/8192, tWTR=(4, 7.5), tCCD=(4, None), tRRD=(4, 10), tZQCS=(64, 80))
speedgrade_timings = {
"800": _SpeedgradeTimings(tRP=13.91, tRCD=13.91, tWR=13.91, tRFC=260, tFAW=(None, 50), tRAS=None),
"1066": _SpeedgradeTimings(tRP=15, tRCD=15, tWR=15, tRFC=86, tFAW=(None, 50), tRAS=None),
@ -398,7 +406,7 @@ class MT18KSF1G72HZ(SDRAMModule):
nrows = 65536
ncols = 1024
# timings
technology_timings = _TechnologyTimings(tREFI=64e6/8192, tWTR=(4, 7.5), tCCD=(4, None), tRRD=(4, 10))
technology_timings = _TechnologyTimings(tREFI=64e6/8192, tWTR=(4, 7.5), tCCD=(4, None), tRRD=(4, 10), tZQCS=(64, 80))
speedgrade_timings = {
"1066": _SpeedgradeTimings(tRP=15, tRCD=15, tWR=15, tRFC=(86, None), tFAW=(None, 50), tRAS=None),
"1333": _SpeedgradeTimings(tRP=15, tRCD=15, tWR=15, tRFC=(107, None), tFAW=(None, 45), tRAS=None),
@ -414,7 +422,7 @@ class AS4C256M16D3A(SDRAMModule):
nrows = 32768
ncols = 1024
# timings
technology_timings = _TechnologyTimings(tREFI=64e6/8192, tWTR=(4, 7.5), tCCD=(4, None), tRRD=(4, 7.5))
technology_timings = _TechnologyTimings(tREFI=64e6/8192, tWTR=(4, 7.5), tCCD=(4, None), tRRD=(4, 7.5), tZQCS=(64, 80))
speedgrade_timings = {
"1600": _SpeedgradeTimings(tRP=13.75, tRCD=13.75, tWR=15, tRFC=(None, 260), tFAW=(None, 40), tRAS=35),
}
@ -428,7 +436,7 @@ class MT16KTF1G64HZ(SDRAMModule):
nrows = 65536
ncols = 1024
# timings
technology_timings = _TechnologyTimings(tREFI=64e6/8192, tWTR=(4, 7.5), tCCD=(4, None), tRRD=(4, 10))
technology_timings = _TechnologyTimings(tREFI=64e6/8192, tWTR=(4, 7.5), tCCD=(4, None), tRRD=(4, 10), tZQCS=(64, 80))
speedgrade_timings = {
"800" : _SpeedgradeTimings(tRP=15, tRCD=15, tWR=15, tRFC=(140, None), tFAW=(None, 40), tRAS=None),
"1066": _SpeedgradeTimings(tRP=15, tRCD=15, tWR=15, tRFC=(187, None), tFAW=(None, 40), tRAS=None),
@ -448,7 +456,7 @@ class EDY4016A(SDRAMModule):
nrows = 32768
ncols = 1024
# timings
technology_timings = _TechnologyTimings(tREFI=64e6/8192, tWTR=(4, 7.5), tCCD=(4, None), tRRD=(4, 4.9))
technology_timings = _TechnologyTimings(tREFI=64e6/8192, tWTR=(4, 7.5), tCCD=(4, None), tRRD=(4, 4.9), tZQCS=(128, 80))
speedgrade_timings = {
"2400": _SpeedgradeTimings(tRP=13.32, tRCD=13.32, tWR=15, tRFC=(None, 260), tFAW=(28, 30), tRAS=32),
}
@ -464,7 +472,7 @@ class MT40A1G8(SDRAMModule):
nrows = 65536
ncols = 1024
# timings
technology_timings = _TechnologyTimings(tREFI=64e6/8192, tWTR=(4, 7.5), tCCD=(4, None), tRRD=(4, 6.4))
technology_timings = _TechnologyTimings(tREFI=64e6/8192, tWTR=(4, 7.5), tCCD=(4, None), tRRD=(4, 6.4), tZQCS=(128, 80))
speedgrade_timings = {
"2400": _SpeedgradeTimings(tRP=13.32, tRCD=13.32, tWR=15, tRFC=(None, 350), tFAW=(20, 25), tRAS=32),
"2666": _SpeedgradeTimings(tRP=13.50, tRCD=13.50, tWR=15, tRFC=(None, 350), tFAW=(20, 21), tRAS=32),
@ -481,7 +489,7 @@ class MT40A512M16(SDRAMModule):
nrows = 65536
ncols = 1024
# timings
technology_timings = _TechnologyTimings(tREFI=64e6/8192, tWTR=(4, 7.5), tCCD=(4, None), tRRD=(4, 4.9))
technology_timings = _TechnologyTimings(tREFI=64e6/8192, tWTR=(4, 7.5), tCCD=(4, None), tRRD=(4, 4.9), tZQCS=(128, 80))
speedgrade_timings = {
"2400": _SpeedgradeTimings(tRP=13.32, tRCD=13.32, tWR=15, tRFC=(None, 350), tFAW=(20, 25), tRAS=32),
}

View file

@ -70,10 +70,12 @@ class TestRefresh(unittest.TestCase):
class Obj: pass
settings = Obj()
settings.with_refresh = True
settings.refresher_zqcs_freq = 1e0
settings.timing = Obj()
settings.timing.tREFI = 64
settings.timing.tRP = 1
settings.timing.tRFC = 2
settings.timing.tZQCS = 64
settings.geom = Obj()
settings.geom.addressbits = 16
settings.geom.bankbits = 3
@ -97,7 +99,7 @@ class TestRefresh(unittest.TestCase):
print(cmd_valid_gap)
dut.errors += 1
dut = Refresher(settings, n=n)
dut = Refresher(settings, n=n, clk_freq=100e6)
run_simulation(dut, [generator(dut)])
self.assertEqual(dut.errors, 0)