Add tRRD timing checks, and fix tFAW so it considers all banks

This commit is contained in:
2018-07-30 23:45:52 -04:00
parent f0f067fe7d
commit f0f5e6036b
4 changed files with 62 additions and 25 deletions

View File

@ -31,7 +31,7 @@ class GeomSettings:
class TimingSettings: 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.tRP = tRP
self.tRCD = tRCD self.tRCD = tRCD
self.tWR = tWR self.tWR = tWR
@ -40,6 +40,7 @@ class TimingSettings:
self.tRFC = tRFC self.tRFC = tRFC
self.tFAW = tFAW self.tFAW = tFAW
self.tCCD = tCCD self.tCCD = tCCD
self.tRRD = tRRD
def cmd_layout(aw): def cmd_layout(aw):

View File

@ -31,6 +31,7 @@ class BankMachine(Module):
self.req = req = Record(cmd_layout(aw)) self.req = req = Record(cmd_layout(aw))
self.refresh_req = Signal() self.refresh_req = Signal()
self.refresh_gnt = Signal() self.refresh_gnt = Signal()
self.activate_allowed = activate_allowed = Signal()
a = settings.geom.addressbits a = settings.geom.addressbits
ba = settings.geom.bankbits ba = settings.geom.bankbits
self.cmd = cmd = stream.Endpoint(cmd_request_rw_layout(a, ba)) 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)) 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 to CAS
cas = Signal() cas = Signal()
cas_allowed = Signal(reset=1) cas_allowed = Signal(reset=1)
@ -140,12 +126,10 @@ class BankMachine(Module):
NextState("PRECHARGE") NextState("PRECHARGE")
) )
).Else( ).Else(
If(activate_allowed,
NextState("ACTIVATE") NextState("ACTIVATE")
) )
) )
) )
)
fsm.act("PRECHARGE", fsm.act("PRECHARGE",
# Note: we are presenting the column address, A10 is always low # Note: we are presenting the column address, A10 is always low
If(self.precharge_timer.done, If(self.precharge_timer.done,
@ -160,12 +144,11 @@ class BankMachine(Module):
track_close.eq(1) track_close.eq(1)
) )
fsm.act("ACTIVATE", fsm.act("ACTIVATE",
activate.eq(1),
sel_row_adr.eq(1), sel_row_adr.eq(1),
track_open.eq(1), track_open.eq(1),
cmd.valid.eq(1), cmd.valid.eq(activate_allowed),
cmd.is_cmd.eq(1), cmd.is_cmd.eq(1),
If(cmd.ready, If(cmd.ready & activate_allowed,
NextState("TRCD") NextState("TRCD")
), ),
cmd.ras.eq(1) cmd.ras.eq(1)

View File

@ -16,6 +16,7 @@ class _CommandChooser(Module):
self.want_reads = Signal() self.want_reads = Signal()
self.want_writes = Signal() self.want_writes = Signal()
self.want_cmds = Signal() self.want_cmds = Signal()
self.want_activates = Signal()
a = len(requests[0].a) a = len(requests[0].a)
ba = len(requests[0].ba) ba = len(requests[0].ba)
@ -28,7 +29,8 @@ class _CommandChooser(Module):
valids = Signal(n) valids = Signal(n)
for i, request in enumerate(requests): 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 read = request.is_read == self.want_reads
write = request.is_write == self.want_writes write = request.is_write == self.want_writes
self.comb += valids[i].eq(request.valid & (command | (read & write))) self.comb += valids[i].eq(request.valid & (command | (read & write)))
@ -110,6 +112,9 @@ class Multiplexer(Module, AutoCSR):
with_bandwidth=False): with_bandwidth=False):
assert(settings.phy.nphases == len(dfi.phases)) assert(settings.phy.nphases == len(dfi.phases))
# Forward Declares
activate_allowed = Signal(reset=1)
# Command choosing # Command choosing
requests = [bm.cmd for bm in bank_machines] requests = [bm.cmd for bm in bank_machines]
self.submodules.choose_cmd = choose_cmd = _CommandChooser(requests) self.submodules.choose_cmd = choose_cmd = _CommandChooser(requests)
@ -117,6 +122,7 @@ class Multiplexer(Module, AutoCSR):
if settings.phy.nphases == 1: if settings.phy.nphases == 1:
self.comb += [ self.comb += [
choose_cmd.want_cmds.eq(1), choose_cmd.want_cmds.eq(1),
choose_cmd.want_activates(activate_allowed),
choose_req.want_cmds.eq(1) choose_req.want_cmds.eq(1)
] ]
@ -129,6 +135,36 @@ class Multiplexer(Module, AutoCSR):
steerer = _Steerer(commands, dfi) steerer = _Steerer(commands, dfi)
self.submodules += steerer 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/write turnaround
read_available = Signal() read_available = Signal()
write_available = Signal() write_available = Signal()
@ -198,7 +234,8 @@ class Multiplexer(Module, AutoCSR):
fsm.act("READ", fsm.act("READ",
read_time_en.eq(1), read_time_en.eq(1),
choose_req.want_reads.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), choose_req.cmd.ready.eq(1),
steerer_sel(steerer, "read"), steerer_sel(steerer, "read"),
If(write_available, If(write_available,
@ -214,7 +251,8 @@ class Multiplexer(Module, AutoCSR):
fsm.act("WRITE", fsm.act("WRITE",
write_time_en.eq(1), write_time_en.eq(1),
choose_req.want_writes.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), choose_req.cmd.ready.eq(1),
steerer_sel(steerer, "write"), steerer_sel(steerer, "write"),
If(read_available, If(read_available,

View File

@ -34,6 +34,7 @@ class SDRAMModule:
tWTR=self.ck_ns_to_cycles(*self.get("tWTR")), 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")), 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")), 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): def get(self, name):
@ -44,6 +45,19 @@ class SDRAMModule:
except: except:
return None 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): def ns_to_cycles(self, t, margin=True):
clk_period_ns = 1e9/self.clk_freq clk_period_ns = 1e9/self.clk_freq
if margin: if margin:
@ -230,6 +244,7 @@ class MT41J128M16(SDRAMModule):
tREFI = 64e6/8192 tREFI = 64e6/8192
tWTR = (4, 7.5) tWTR = (4, 7.5)
tCCD = (4, None) tCCD = (4, None)
tRRD = 10
# speedgrade related timings # speedgrade related timings
# DDR3-1066 # DDR3-1066
tRP_1066 = 13.1 tRP_1066 = 13.1