Merge branch 'master' of https://github.com/enjoy-digital/litedram into AutoPrecharge
This commit is contained in:
commit
771ccfdc41
|
@ -31,8 +31,8 @@ class BankMachine(Module):
|
|||
self.req = req = Record(cmd_layout(aw))
|
||||
self.refresh_req = Signal()
|
||||
self.refresh_gnt = Signal()
|
||||
self.ras_allowed = ras_allowed = Signal()
|
||||
self.cas_allowed = cas_allowed = 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))
|
||||
|
@ -99,6 +99,7 @@ class BankMachine(Module):
|
|||
]
|
||||
|
||||
# Control and command generation FSM
|
||||
# Note: tRRD, tFAW, tCCD, tWTR timings are enforced by the multiplexer
|
||||
self.submodules.fsm = fsm = FSM()
|
||||
fsm.act("REGULAR",
|
||||
If(self.refresh_req,
|
||||
|
@ -107,8 +108,6 @@ class BankMachine(Module):
|
|||
If(has_openrow,
|
||||
If(hit,
|
||||
If(cas_allowed,
|
||||
# Note: write-to-read specification is enforced by
|
||||
# multiplexer
|
||||
cmd.valid.eq(1),
|
||||
If(cmd_buffer.source.we,
|
||||
req.wdata_ready.eq(cmd.ready),
|
||||
|
@ -153,9 +152,9 @@ class BankMachine(Module):
|
|||
fsm.act("ACTIVATE",
|
||||
sel_row_adr.eq(1),
|
||||
track_open.eq(1),
|
||||
cmd.valid.eq(activate_allowed),
|
||||
cmd.valid.eq(ras_allowed),
|
||||
cmd.is_cmd.eq(1),
|
||||
If(cmd.ready & activate_allowed,
|
||||
If(cmd.ready & ras_allowed,
|
||||
NextState("TRCD")
|
||||
),
|
||||
cmd.ras.eq(1)
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
from functools import reduce
|
||||
from operator import or_, and_
|
||||
from operator import add, or_, and_
|
||||
|
||||
from migen import *
|
||||
from migen.genlib.roundrobin import *
|
||||
|
@ -20,6 +20,7 @@ class _CommandChooser(Module):
|
|||
|
||||
a = len(requests[0].a)
|
||||
ba = len(requests[0].ba)
|
||||
|
||||
# cas/ras/we are 0 when valid is inactive
|
||||
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)
|
||||
|
||||
# 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):
|
||||
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):
|
||||
def __init__(self,
|
||||
settings,
|
||||
|
@ -112,8 +173,8 @@ class Multiplexer(Module, AutoCSR):
|
|||
with_bandwidth=False):
|
||||
assert(settings.phy.nphases == len(dfi.phases))
|
||||
|
||||
# Forward Declares
|
||||
activate_allowed = Signal(reset=1)
|
||||
ras_allowed = Signal(reset=1)
|
||||
cas_allowed = Signal(reset=1)
|
||||
|
||||
# Command choosing
|
||||
requests = [bm.cmd for bm in bank_machines]
|
||||
|
@ -122,7 +183,7 @@ class Multiplexer(Module, AutoCSR):
|
|||
if settings.phy.nphases == 1:
|
||||
self.comb += [
|
||||
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)
|
||||
]
|
||||
|
||||
|
@ -135,66 +196,32 @@ class Multiplexer(Module, AutoCSR):
|
|||
steerer = _Steerer(commands, dfi)
|
||||
self.submodules += steerer
|
||||
|
||||
# tRRD Command Timing
|
||||
trrd = settings.timing.tRRD
|
||||
trrd_allowed = Signal(reset=1)
|
||||
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)
|
||||
# tRRD timing (Row to Row delay)
|
||||
self.trrdcon = trrdcon = tXXDController(settings.timing.tRRD)
|
||||
self.comb += trrdcon.valid.eq(choose_cmd.accept() & choose_cmd.activate())
|
||||
|
||||
# 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))
|
||||
# tFAW timing (Four Activate Window)
|
||||
self.tfawcon = tfawcon = tFAWController(settings.timing.tFAW)
|
||||
self.comb += tfawcon.valid.eq(choose_cmd.accept() & choose_cmd.activate())
|
||||
|
||||
self.comb += activate_allowed.eq(trrd_allowed & tfaw_allowed)
|
||||
self.comb += [bm.activate_allowed.eq(activate_allowed) for bm in bank_machines]
|
||||
# RAS control
|
||||
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
|
||||
cas = choose_req.cmd.valid & choose_req.cmd.ready & (choose_req.cmd.is_read | choose_req.cmd.is_write)
|
||||
cas_allowed = Signal(reset=1)
|
||||
tccd = settings.timing.tCCD
|
||||
if tccd is not None:
|
||||
cas_count = Signal(max=tccd+1)
|
||||
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)
|
||||
# tCCD timing (Column to Column delay)
|
||||
self.tccdcon = tccdcon = tXXDController(settings.timing.tCCD)
|
||||
self.comb += tccdcon.valid.eq(choose_cmd.accept() & (choose_cmd.write() | choose_cmd.read()))
|
||||
|
||||
# CAS control
|
||||
self.comb += cas_allowed.eq(tccdcon.ready)
|
||||
self.comb += [bm.cas_allowed.eq(cas_allowed) for bm in bank_machines]
|
||||
|
||||
# Write to Read
|
||||
wtr_allowed = Signal(reset=1)
|
||||
twtr = settings.timing.tWTR
|
||||
if tccd is not None:
|
||||
twtr += settings.timing.tCCD # tWTR begins after the transfer is complete, tCCD accounts for this
|
||||
wtr_count = Signal(max=twtr+1)
|
||||
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)
|
||||
# tWTR timing (Write to Read delay)
|
||||
self.twtrcon = twtrcon = tXXDController(
|
||||
settings.timing.tWTR +
|
||||
# tCCD must be added since tWTR begins after the transfer is complete
|
||||
settings.timing.tCCD if settings.timing.tCCD is not None else 0)
|
||||
self.comb += twtrcon.valid.eq(choose_req.accept() & choose_req.write())
|
||||
|
||||
# Read/write turnaround
|
||||
read_available = Signal()
|
||||
|
@ -265,8 +292,8 @@ class Multiplexer(Module, AutoCSR):
|
|||
fsm.act("READ",
|
||||
read_time_en.eq(1),
|
||||
choose_req.want_reads.eq(1),
|
||||
choose_cmd.want_activates.eq(activate_allowed),
|
||||
choose_cmd.cmd.ready.eq(~is_act_cmd | activate_allowed),
|
||||
choose_cmd.want_activates.eq(ras_allowed),
|
||||
choose_cmd.cmd.ready.eq(~choose_cmd.activate() | ras_allowed),
|
||||
choose_req.cmd.ready.eq(1),
|
||||
steerer_sel(steerer, "read"),
|
||||
If(write_available,
|
||||
|
@ -282,8 +309,8 @@ class Multiplexer(Module, AutoCSR):
|
|||
fsm.act("WRITE",
|
||||
write_time_en.eq(1),
|
||||
choose_req.want_writes.eq(1),
|
||||
choose_cmd.want_activates.eq(activate_allowed),
|
||||
choose_cmd.cmd.ready.eq(~is_act_cmd | activate_allowed),
|
||||
choose_cmd.want_activates.eq(ras_allowed),
|
||||
choose_cmd.cmd.ready.eq(~choose_cmd.activate() | ras_allowed),
|
||||
choose_req.cmd.ready.eq(1),
|
||||
steerer_sel(steerer, "write"),
|
||||
If(read_available,
|
||||
|
@ -298,12 +325,12 @@ class Multiplexer(Module, AutoCSR):
|
|||
fsm.act("REFRESH",
|
||||
steerer.sel[0].eq(STEER_REFRESH),
|
||||
refresher.cmd.ready.eq(1),
|
||||
If(refresher.cmd.last,
|
||||
If(~refresher.cmd.valid,
|
||||
NextState("READ")
|
||||
)
|
||||
)
|
||||
fsm.act("WTR",
|
||||
If(wtr_allowed,
|
||||
If(twtrcon.ready,
|
||||
NextState("READ")
|
||||
)
|
||||
)
|
||||
|
|
|
@ -45,14 +45,16 @@ class Refresher(Module):
|
|||
self.comb += self.timer.wait.eq(settings.with_refresh & ~self.timer.done)
|
||||
|
||||
# Control FSM
|
||||
cmd_valid = Signal()
|
||||
self.submodules.fsm = fsm = FSM()
|
||||
fsm.act("IDLE",
|
||||
If(self.timer.done,
|
||||
cmd_valid.eq(1),
|
||||
NextState("WAIT_GRANT")
|
||||
)
|
||||
)
|
||||
fsm.act("WAIT_GRANT",
|
||||
cmd.valid.eq(1),
|
||||
cmd_valid.eq(1),
|
||||
If(cmd.ready,
|
||||
seq_start.eq(1),
|
||||
NextState("WAIT_SEQ")
|
||||
|
@ -60,9 +62,8 @@ class Refresher(Module):
|
|||
)
|
||||
fsm.act("WAIT_SEQ",
|
||||
If(seq_done,
|
||||
cmd.last.eq(1),
|
||||
cmd_valid.eq(0),
|
||||
NextState("IDLE")
|
||||
).Else(
|
||||
cmd.valid.eq(1)
|
||||
)
|
||||
)
|
||||
self.sync += cmd.valid.eq(cmd_valid)
|
||||
|
|
Loading…
Reference in New Issue