From f0f5e6036bbf33909db8e1ca661a5fe4f4a6113c Mon Sep 17 00:00:00 2001 From: Date: Mon, 30 Jul 2018 23:45:52 -0400 Subject: [PATCH] Add tRRD timing checks, and fix tFAW so it considers all banks --- litedram/common.py | 3 ++- litedram/core/bankmachine.py | 25 ++++---------------- litedram/core/multiplexer.py | 44 +++++++++++++++++++++++++++++++++--- litedram/modules.py | 15 ++++++++++++ 4 files changed, 62 insertions(+), 25 deletions(-) diff --git a/litedram/common.py b/litedram/common.py index 58773a9..d353954 100644 --- a/litedram/common.py +++ b/litedram/common.py @@ -31,7 +31,7 @@ class GeomSettings: class TimingSettings: - def __init__(self, tRP, tRCD, tWR, tWTR, tREFI, tRFC, tFAW, tCCD): + def __init__(self, tRP, tRCD, tWR, tWTR, tREFI, tRFC, tFAW, tCCD, tRRD): self.tRP = tRP self.tRCD = tRCD self.tWR = tWR @@ -40,6 +40,7 @@ class TimingSettings: self.tRFC = tRFC self.tFAW = tFAW self.tCCD = tCCD + self.tRRD = tRRD def cmd_layout(aw): diff --git a/litedram/core/bankmachine.py b/litedram/core/bankmachine.py index da026eb..ed60410 100644 --- a/litedram/core/bankmachine.py +++ b/litedram/core/bankmachine.py @@ -31,6 +31,7 @@ class BankMachine(Module): self.req = req = Record(cmd_layout(aw)) self.refresh_req = Signal() self.refresh_gnt = Signal() + self.activate_allowed = activate_allowed = Signal() a = settings.geom.addressbits ba = settings.geom.bankbits self.cmd = cmd = stream.Endpoint(cmd_request_rw_layout(a, ba)) @@ -66,21 +67,6 @@ class BankMachine(Module): openrow.eq(slicer.row(cmd_buffer.source.adr)) ) - - # Four Activate Window - activate = Signal() - activate_allowed = Signal(reset=1) - tfaw = settings.timing.tFAW - if tfaw is not None: - activate_count = Signal(max=tfaw) - activate_window = Signal(tfaw) - self.sync += activate_window.eq(Cat(activate, activate_window)) - for i in range(tfaw): - next_activate_count = Signal(max=tfaw) - self.comb += next_activate_count.eq(activate_count + activate_window[i]) - activate_count = next_activate_count - self.comb += If(activate_count >=4, activate_allowed.eq(0)) - # CAS to CAS cas = Signal() cas_allowed = Signal(reset=1) @@ -140,9 +126,7 @@ class BankMachine(Module): NextState("PRECHARGE") ) ).Else( - If(activate_allowed, - NextState("ACTIVATE") - ) + NextState("ACTIVATE") ) ) ) @@ -160,12 +144,11 @@ class BankMachine(Module): track_close.eq(1) ) fsm.act("ACTIVATE", - activate.eq(1), sel_row_adr.eq(1), track_open.eq(1), - cmd.valid.eq(1), + cmd.valid.eq(activate_allowed), cmd.is_cmd.eq(1), - If(cmd.ready, + If(cmd.ready & activate_allowed, NextState("TRCD") ), cmd.ras.eq(1) diff --git a/litedram/core/multiplexer.py b/litedram/core/multiplexer.py index 7eff13e..4e4d070 100644 --- a/litedram/core/multiplexer.py +++ b/litedram/core/multiplexer.py @@ -16,6 +16,7 @@ class _CommandChooser(Module): self.want_reads = Signal() self.want_writes = Signal() self.want_cmds = Signal() + self.want_activates = Signal() a = len(requests[0].a) ba = len(requests[0].ba) @@ -28,7 +29,8 @@ class _CommandChooser(Module): valids = Signal(n) for i, request in enumerate(requests): - command = request.is_cmd & self.want_cmds + is_act_cmd = request.ras & ~request.cas & ~request.we + command = request.is_cmd & self.want_cmds & (~is_act_cmd | self.want_activates) read = request.is_read == self.want_reads write = request.is_write == self.want_writes self.comb += valids[i].eq(request.valid & (command | (read & write))) @@ -110,6 +112,9 @@ class Multiplexer(Module, AutoCSR): with_bandwidth=False): assert(settings.phy.nphases == len(dfi.phases)) + # Forward Declares + activate_allowed = Signal(reset=1) + # Command choosing requests = [bm.cmd for bm in bank_machines] self.submodules.choose_cmd = choose_cmd = _CommandChooser(requests) @@ -117,6 +122,7 @@ class Multiplexer(Module, AutoCSR): if settings.phy.nphases == 1: self.comb += [ choose_cmd.want_cmds.eq(1), + choose_cmd.want_activates(activate_allowed), choose_req.want_cmds.eq(1) ] @@ -129,6 +135,36 @@ class Multiplexer(Module, AutoCSR): steerer = _Steerer(commands, dfi) self.submodules += steerer + # tRRD Command Timing + tRRD = settings.timing.tRRD + trrd_allowed = Signal(reset=1) + activate_count = Signal(max=tRRD) + is_act_cmd = Signal() + self.comb += is_act_cmd.eq(choose_cmd.cmd.ras & ~choose_cmd.cmd.cas & ~choose_cmd.cmd.we) + self.sync += \ + If(choose_cmd.cmd.ready & choose_cmd.cmd.valid & is_act_cmd, + activate_count.eq(tRRD-1) + ).Elif(~activate_allowed, + activate_count.eq(activate_count-1) + ) + self.comb += trrd_allowed.eq(activate_count == 0) + + # tFAW Command Timing + tfaw = settings.timing.tFAW + tfaw_allowed = Signal(reset=1) + if tfaw is not None: + tfaw_count = Signal(max=tfaw) + tfaw_window = Signal(tfaw) + self.sync += tfaw_window.eq(Cat((is_act_cmd & choose_cmd.cmd.ready & choose_cmd.cmd.valid), tfaw_window)) + for i in range(tfaw): + next_tfaw_count = Signal(max=tfaw) + self.comb += next_tfaw_count.eq(tfaw_count + tfaw_window[i]) + tfaw_count = next_tfaw_count + self.comb += If(tfaw_count >=4, tfaw_allowed.eq(0)) + + self.comb += activate_allowed.eq(trrd_allowed & tfaw_allowed) + self.comb += [bm.activate_allowed.eq(activate_allowed) for bm in bank_machines] + # Read/write turnaround read_available = Signal() write_available = Signal() @@ -198,7 +234,8 @@ class Multiplexer(Module, AutoCSR): fsm.act("READ", read_time_en.eq(1), choose_req.want_reads.eq(1), - choose_cmd.cmd.ready.eq(1), + choose_cmd.want_activates.eq(activate_allowed), + choose_cmd.cmd.ready.eq(~is_act_cmd | activate_allowed), choose_req.cmd.ready.eq(1), steerer_sel(steerer, "read"), If(write_available, @@ -214,7 +251,8 @@ class Multiplexer(Module, AutoCSR): fsm.act("WRITE", write_time_en.eq(1), choose_req.want_writes.eq(1), - choose_cmd.cmd.ready.eq(1), + choose_cmd.want_activates.eq(activate_allowed), + choose_cmd.cmd.ready.eq(~is_act_cmd | activate_allowed), choose_req.cmd.ready.eq(1), steerer_sel(steerer, "write"), If(read_available, diff --git a/litedram/modules.py b/litedram/modules.py index ccb86f3..6b4b397 100644 --- a/litedram/modules.py +++ b/litedram/modules.py @@ -34,6 +34,7 @@ class SDRAMModule: tWTR=self.ck_ns_to_cycles(*self.get("tWTR")), tFAW=None if self.get("tFAW") is None else self.ck_ns_to_cycles(*self.get("tFAW")), tCCD=None if self.get("tCCD") is None else self.ck_ns_to_cycles(*self.get("tCCD")), + tRRD=self.ns_to_cycles_trrd(self.get("tRRD")), ) def get(self, name): @@ -44,6 +45,19 @@ class SDRAMModule: except: return None + def ns_to_cycles_trrd(self, t): + lower_bound = { + "1:1" : 4, + "1:2" : 2, + "1:4" : 1 + } + if (t is None): + if self.memtype == "DDR3": + return lower_bound[self.rate] + else: + return 0 #Review: Is this needed for DDR2 and below? + return max(lower_bound[self.rate], self.ns_to_cycles(t, margin=False)) + def ns_to_cycles(self, t, margin=True): clk_period_ns = 1e9/self.clk_freq if margin: @@ -230,6 +244,7 @@ class MT41J128M16(SDRAMModule): tREFI = 64e6/8192 tWTR = (4, 7.5) tCCD = (4, None) + tRRD = 10 # speedgrade related timings # DDR3-1066 tRP_1066 = 13.1