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:
|
||||
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):
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in New Issue