diff --git a/litedram/common.py b/litedram/common.py index 44248f1..b9a5f59 100644 --- a/litedram/common.py +++ b/litedram/common.py @@ -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 ------------------------------------------------------------ diff --git a/litedram/core/controller.py b/litedram/core/controller.py index 8380dd8..f6211b4 100644 --- a/litedram/core/controller.py +++ b/litedram/core/controller.py @@ -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 = [] diff --git a/litedram/core/refresher.py b/litedram/core/refresher.py index c360ec8..f777422 100644 --- a/litedram/core/refresher.py +++ b/litedram/core/refresher.py @@ -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") + ) ) - ) diff --git a/litedram/modules.py b/litedram/modules.py index 585ff1a..83b05a0 100644 --- a/litedram/modules.py +++ b/litedram/modules.py @@ -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), } diff --git a/test/test_refresh.py b/test/test_refresh.py index 79213ea..db7db35 100644 --- a/test/test_refresh.py +++ b/test/test_refresh.py @@ -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)