Merge branch 'master' of https://github.com/enjoy-digital/litedram into AutoPrecharge

This commit is contained in:
2018-08-14 15:25:21 -04:00
commit 771ccfdc41
3 changed files with 101 additions and 74 deletions

View File

@ -31,8 +31,8 @@ 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.ras_allowed = ras_allowed = Signal()
self.cas_allowed = cas_allowed = Signal() self.cas_allowed = cas_allowed = 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))
@ -99,6 +99,7 @@ class BankMachine(Module):
] ]
# Control and command generation FSM # Control and command generation FSM
# Note: tRRD, tFAW, tCCD, tWTR timings are enforced by the multiplexer
self.submodules.fsm = fsm = FSM() self.submodules.fsm = fsm = FSM()
fsm.act("REGULAR", fsm.act("REGULAR",
If(self.refresh_req, If(self.refresh_req,
@ -107,8 +108,6 @@ class BankMachine(Module):
If(has_openrow, If(has_openrow,
If(hit, If(hit,
If(cas_allowed, If(cas_allowed,
# Note: write-to-read specification is enforced by
# multiplexer
cmd.valid.eq(1), cmd.valid.eq(1),
If(cmd_buffer.source.we, If(cmd_buffer.source.we,
req.wdata_ready.eq(cmd.ready), req.wdata_ready.eq(cmd.ready),
@ -153,9 +152,9 @@ class BankMachine(Module):
fsm.act("ACTIVATE", fsm.act("ACTIVATE",
sel_row_adr.eq(1), sel_row_adr.eq(1),
track_open.eq(1), track_open.eq(1),
cmd.valid.eq(activate_allowed), cmd.valid.eq(ras_allowed),
cmd.is_cmd.eq(1), cmd.is_cmd.eq(1),
If(cmd.ready & activate_allowed, If(cmd.ready & ras_allowed,
NextState("TRCD") NextState("TRCD")
), ),
cmd.ras.eq(1) cmd.ras.eq(1)

View File

@ -1,5 +1,5 @@
from functools import reduce from functools import reduce
from operator import or_, and_ from operator import add, or_, and_
from migen import * from migen import *
from migen.genlib.roundrobin import * from migen.genlib.roundrobin import *
@ -20,6 +20,7 @@ class _CommandChooser(Module):
a = len(requests[0].a) a = len(requests[0].a)
ba = len(requests[0].ba) ba = len(requests[0].ba)
# cas/ras/we are 0 when valid is inactive # cas/ras/we are 0 when valid is inactive
self.cmd = cmd = stream.Endpoint(cmd_request_rw_layout(a, ba)) self.cmd = cmd = stream.Endpoint(cmd_request_rw_layout(a, ba))
@ -63,6 +64,19 @@ class _CommandChooser(Module):
) )
self.comb += arbiter.ce.eq(cmd.ready) self.comb += arbiter.ce.eq(cmd.ready)
# helpers
def accept(self):
return self.cmd.valid & self.cmd.ready
def activate(self):
return self.cmd.ras & ~self.cmd.cas & ~self.cmd.we
def write(self):
return self.cmd.is_write
def read(self):
return self.cmd.is_read
class _Steerer(Module): class _Steerer(Module):
def __init__(self, commands, dfi): def __init__(self, commands, dfi):
@ -102,6 +116,53 @@ class _Steerer(Module):
] ]
class tXXDController(Module):
def __init__(self, txxd):
self.valid = valid = Signal()
self.ready = ready = Signal(reset=1)
ready.attr.add("no_retiming")
# # #
if txxd is not None:
count = Signal(max=txxd + 1)
self.sync += \
If(valid,
count.eq(txxd - 1),
If((txxd - 1) == 0,
ready.eq(1)
).Else(
ready.eq(0)
)
).Elif(~ready,
count.eq(count - 1),
If(count == 1, ready.eq(1))
)
class tFAWController(Module):
def __init__(self, tfaw):
self.valid = valid = Signal()
self.ready = ready = Signal(reset=1)
ready.attr.add("no_retiming")
# # #
if tfaw is not None:
count = Signal(max=tfaw)
window = Signal(tfaw)
self.sync += window.eq(Cat(valid, window))
self.comb += reduce(add, [window[i] for i in range(tfaw)])
self.sync += \
If(count < 4,
If(count == 3,
ready.eq(~valid)
).Else(
ready.eq(1)
)
)
class Multiplexer(Module, AutoCSR): class Multiplexer(Module, AutoCSR):
def __init__(self, def __init__(self,
settings, settings,
@ -112,8 +173,8 @@ 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 ras_allowed = Signal(reset=1)
activate_allowed = Signal(reset=1) cas_allowed = Signal(reset=1)
# Command choosing # Command choosing
requests = [bm.cmd for bm in bank_machines] requests = [bm.cmd for bm in bank_machines]
@ -122,7 +183,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.eq(activate_allowed), choose_cmd.want_activates.eq(ras_allowed),
choose_req.want_cmds.eq(1) choose_req.want_cmds.eq(1)
] ]
@ -135,66 +196,32 @@ class Multiplexer(Module, AutoCSR):
steerer = _Steerer(commands, dfi) steerer = _Steerer(commands, dfi)
self.submodules += steerer self.submodules += steerer
# tRRD Command Timing # tRRD timing (Row to Row delay)
trrd = settings.timing.tRRD self.trrdcon = trrdcon = tXXDController(settings.timing.tRRD)
trrd_allowed = Signal(reset=1) self.comb += trrdcon.valid.eq(choose_cmd.accept() & choose_cmd.activate())
is_act_cmd = Signal()
self.comb += is_act_cmd.eq(choose_cmd.cmd.ras & ~choose_cmd.cmd.cas & ~choose_cmd.cmd.we)
if trrd is not None:
trrd_count = Signal(max=trrd+1)
self.sync += \
If(choose_cmd.cmd.ready & choose_cmd.cmd.valid & is_act_cmd,
trrd_count.eq(trrd-1)
).Elif(~activate_allowed,
trrd_count.eq(trrd_count-1)
)
self.comb += trrd_allowed.eq(trrd_count == 0)
# tFAW Command Timing # tFAW timing (Four Activate Window)
tfaw = settings.timing.tFAW self.tfawcon = tfawcon = tFAWController(settings.timing.tFAW)
tfaw_allowed = Signal(reset=1) self.comb += tfawcon.valid.eq(choose_cmd.accept() & choose_cmd.activate())
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) # RAS control
self.comb += [bm.activate_allowed.eq(activate_allowed) for bm in bank_machines] self.comb += ras_allowed.eq(trrdcon.ready & tfawcon.ready)
self.comb += [bm.ras_allowed.eq(ras_allowed) for bm in bank_machines]
# CAS to CAS # tCCD timing (Column to Column delay)
cas = choose_req.cmd.valid & choose_req.cmd.ready & (choose_req.cmd.is_read | choose_req.cmd.is_write) self.tccdcon = tccdcon = tXXDController(settings.timing.tCCD)
cas_allowed = Signal(reset=1) self.comb += tccdcon.valid.eq(choose_cmd.accept() & (choose_cmd.write() | choose_cmd.read()))
tccd = settings.timing.tCCD
if tccd is not None: # CAS control
cas_count = Signal(max=tccd+1) self.comb += cas_allowed.eq(tccdcon.ready)
self.sync += \
If(cas,
cas_count.eq(tccd-1)
).Elif(~cas_allowed,
cas_count.eq(cas_count-1)
)
self.comb += cas_allowed.eq(cas_count == 0)
self.comb += [bm.cas_allowed.eq(cas_allowed) for bm in bank_machines] self.comb += [bm.cas_allowed.eq(cas_allowed) for bm in bank_machines]
# Write to Read # tWTR timing (Write to Read delay)
wtr_allowed = Signal(reset=1) self.twtrcon = twtrcon = tXXDController(
twtr = settings.timing.tWTR settings.timing.tWTR +
if tccd is not None: # tCCD must be added since tWTR begins after the transfer is complete
twtr += settings.timing.tCCD # tWTR begins after the transfer is complete, tCCD accounts for this settings.timing.tCCD if settings.timing.tCCD is not None else 0)
wtr_count = Signal(max=twtr+1) self.comb += twtrcon.valid.eq(choose_req.accept() & choose_req.write())
self.sync += [
If(choose_req.cmd.ready & choose_req.cmd.valid & choose_req.cmd.is_write,
wtr_count.eq(twtr-1)
).Elif(wtr_count != 0,
wtr_count.eq(wtr_count-1)
)
]
self.comb += wtr_allowed.eq(wtr_count == 0)
# Read/write turnaround # Read/write turnaround
read_available = Signal() read_available = Signal()
@ -265,8 +292,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.want_activates.eq(activate_allowed), choose_cmd.want_activates.eq(ras_allowed),
choose_cmd.cmd.ready.eq(~is_act_cmd | activate_allowed), choose_cmd.cmd.ready.eq(~choose_cmd.activate() | ras_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,
@ -282,8 +309,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.want_activates.eq(activate_allowed), choose_cmd.want_activates.eq(ras_allowed),
choose_cmd.cmd.ready.eq(~is_act_cmd | activate_allowed), choose_cmd.cmd.ready.eq(~choose_cmd.activate() | ras_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,
@ -298,12 +325,12 @@ class Multiplexer(Module, AutoCSR):
fsm.act("REFRESH", fsm.act("REFRESH",
steerer.sel[0].eq(STEER_REFRESH), steerer.sel[0].eq(STEER_REFRESH),
refresher.cmd.ready.eq(1), refresher.cmd.ready.eq(1),
If(refresher.cmd.last, If(~refresher.cmd.valid,
NextState("READ") NextState("READ")
) )
) )
fsm.act("WTR", fsm.act("WTR",
If(wtr_allowed, If(twtrcon.ready,
NextState("READ") NextState("READ")
) )
) )

View File

@ -45,14 +45,16 @@ class Refresher(Module):
self.comb += self.timer.wait.eq(settings.with_refresh & ~self.timer.done) self.comb += self.timer.wait.eq(settings.with_refresh & ~self.timer.done)
# Control FSM # Control FSM
cmd_valid = Signal()
self.submodules.fsm = fsm = FSM() self.submodules.fsm = fsm = FSM()
fsm.act("IDLE", fsm.act("IDLE",
If(self.timer.done, If(self.timer.done,
cmd_valid.eq(1),
NextState("WAIT_GRANT") NextState("WAIT_GRANT")
) )
) )
fsm.act("WAIT_GRANT", fsm.act("WAIT_GRANT",
cmd.valid.eq(1), cmd_valid.eq(1),
If(cmd.ready, If(cmd.ready,
seq_start.eq(1), seq_start.eq(1),
NextState("WAIT_SEQ") NextState("WAIT_SEQ")
@ -60,9 +62,8 @@ class Refresher(Module):
) )
fsm.act("WAIT_SEQ", fsm.act("WAIT_SEQ",
If(seq_done, If(seq_done,
cmd.last.eq(1), cmd_valid.eq(0),
NextState("IDLE") NextState("IDLE")
).Else(
cmd.valid.eq(1)
) )
) )
self.sync += cmd.valid.eq(cmd_valid)