Add tRRD timing checks, and fix tFAW so it considers all banks
This commit is contained in:
parent
f0f067fe7d
commit
f0f5e6036b
|
@ -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):
|
||||||
|
|
|
@ -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,9 +126,7 @@ class BankMachine(Module):
|
||||||
NextState("PRECHARGE")
|
NextState("PRECHARGE")
|
||||||
)
|
)
|
||||||
).Else(
|
).Else(
|
||||||
If(activate_allowed,
|
NextState("ACTIVATE")
|
||||||
NextState("ACTIVATE")
|
|
||||||
)
|
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
@ -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)
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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
|
||||||
|
|
Loading…
Reference in New Issue