diff --git a/README b/README index 7ef7ed6..103d514 100644 --- a/README +++ b/README @@ -33,7 +33,7 @@ Core: - Fully pipelined, high performance. - Configurable commands depth on bankmachines. - Auto-Precharge. - - Periodic refresh/ZQ short calibration. + - Periodic refresh/ZQ short calibration (up to 8 postponed refreshes). Frontend: - Configurable crossbar (simply use crossbar.get_port() to add a new port!) - Ports arbitration transparent to the user. diff --git a/litedram/core/controller.py b/litedram/core/controller.py index f6211b4..503f605 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, refresher_zqcs_freq=1e0, + with_refresh=True, refresh_cls=Refresher, refresh_zqcs_freq=1e0, refresh_postponing=1, with_auto_precharge=True, address_mapping="ROW_BANK_COL"): self.set_attributes(locals()) @@ -53,7 +53,10 @@ class LiteDRAMController(Module): # # # # Refresher -------------------------------------------------------------------------------- - self.submodules.refresher = self.settings.refresher_cls(self.settings, clk_freq) + self.submodules.refresher = self.settings.refresh_cls(self.settings, + clk_freq = clk_freq, + zqcs_freq = self.settings.refresh_zqcs_freq, + postponing = self.settings.refresh_postponing) # Bank Machines ---------------------------------------------------------------------------- bank_machines = [] diff --git a/litedram/core/refresher.py b/litedram/core/refresher.py index f777422..c04b372 100644 --- a/litedram/core/refresher.py +++ b/litedram/core/refresher.py @@ -72,7 +72,7 @@ class RefreshSequencer(Module): Sequence N refreshs to the DRAM. """ - def __init__(self, cmd, trp, trfc, n=1): + def __init__(self, cmd, trp, trfc, postponing=1): self.start = Signal() self.done = Signal() @@ -81,7 +81,7 @@ class RefreshSequencer(Module): executer = RefreshExecuter(cmd, trp, trfc) self.submodules += executer - count = Signal(bits_for(n), reset=n-1) + count = Signal(bits_for(postponing), reset=postponing-1) self.sync += [ If(self.start, count.eq(count.reset) @@ -124,20 +124,20 @@ class RefreshTimer(Module): self.count.eq(count) ] -# RefreshAccumulator ------------------------------------------------------------------------------- +# RefreshPostponer ------------------------------------------------------------------------------- -class RefreshAccumulator(Module): - """Refresh Accumulator +class RefreshPostponer(Module): + """Refresh Postponer - Accumulate N Refresh requests and generate a request when N is reached. + Postpone N Refresh requests and generate a request when N is reached. """ - def __init__(self, n=1): + def __init__(self, postponing=1): self.req_i = Signal() self.req_o = Signal() # # # - count = Signal(bits_for(n), reset=n-1) + count = Signal(bits_for(postponing), reset=postponing-1) self.sync += [ self.req_o.eq(0), If(self.req_i, @@ -215,7 +215,8 @@ class Refresher(Module): transactions are done, the Refresher can execute the refresh Sequence and release the Controller. """ - def __init__(self, settings, clk_freq, n=1): + def __init__(self, settings, clk_freq, zqcs_freq=1e0, postponing=1): + assert postponing <= 8 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)) @@ -230,19 +231,19 @@ class Refresher(Module): self.submodules.timer = timer 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 Postponer ------------------------------------------------------------------------ + postponer = RefreshPostponer(postponing) + self.submodules.postponer = postponer + self.comb += postponer.req_i.eq(self.timer.done) + self.comb += wants_refresh.eq(postponer.req_o) # Refresh Sequencer ------------------------------------------------------------------------ - sequencer = RefreshSequencer(cmd, settings.timing.tRP, settings.timing.tRFC, n=n) + sequencer = RefreshSequencer(cmd, settings.timing.tRP, settings.timing.tRFC, postponing) self.submodules.sequencer = sequencer if settings.timing.tZQCS is not None: # ZQCS Timer --------------------------------------------------------------------------- - zqcs_timer = RefreshTimer(int(clk_freq/settings.refresher_zqcs_freq)) + zqcs_timer = RefreshTimer(int(clk_freq/zqcs_freq)) self.submodules.zqcs_timer = zqcs_timer self.comb += wants_zqcs.eq(zqcs_timer.done) diff --git a/test/test_refresh.py b/test/test_refresh.py index db7db35..a541790 100644 --- a/test/test_refresh.py +++ b/test/test_refresh.py @@ -66,11 +66,11 @@ class TestRefresh(unittest.TestCase): for i in range(1, 32): self.refresh_timer_test(i) - def refresher_test(self, n): + def refresher_test(self, postponing): class Obj: pass settings = Obj() settings.with_refresh = True - settings.refresher_zqcs_freq = 1e0 + settings.refresh_zqcs_freq = 1e0 settings.timing = Obj() settings.timing.tREFI = 64 settings.timing.tRP = 1 @@ -95,14 +95,14 @@ class TestRefresh(unittest.TestCase): while (yield dut.cmd.valid) == 0: cmd_valid_gap += 1 yield - if cmd_valid_gap != n*settings.timing.tREFI: + if cmd_valid_gap != postponing*settings.timing.tREFI: print(cmd_valid_gap) dut.errors += 1 - dut = Refresher(settings, n=n, clk_freq=100e6) + dut = Refresher(settings, clk_freq=100e6, postponing=postponing) run_simulation(dut, [generator(dut)]) self.assertEqual(dut.errors, 0) def test_refresher(self): for i in [1, 2, 4, 8]: - self.refresher_test(n=i) + self.refresher_test(postponing=i)