mirror of
https://github.com/enjoy-digital/litex.git
synced 2025-01-04 09:52:26 -05:00
lasmicon: remove limitations on the number of phases
This commit is contained in:
parent
7acd834964
commit
d1dddad811
5 changed files with 45 additions and 13 deletions
|
@ -7,7 +7,7 @@ from milkymist.lasmicon.refresher import *
|
||||||
from milkymist.lasmicon.bankmachine import *
|
from milkymist.lasmicon.bankmachine import *
|
||||||
from milkymist.lasmicon.multiplexer import *
|
from milkymist.lasmicon.multiplexer import *
|
||||||
|
|
||||||
PhySettings = namedtuple("PhySettings", "memtype dfi_d nphases rdphase wrphase cl read_latency write_latency")
|
PhySettings = namedtuple("PhySettings", "memtype dfi_d nphases rdphase wrphase rdcmdphase wrcmdphase cl read_latency write_latency")
|
||||||
|
|
||||||
class GeomSettings(namedtuple("_GeomSettings", "bank_a row_a col_a")):
|
class GeomSettings(namedtuple("_GeomSettings", "bank_a row_a col_a")):
|
||||||
def __init__(self, *args, **kwargs):
|
def __init__(self, *args, **kwargs):
|
||||||
|
@ -18,7 +18,10 @@ TimingSettings = namedtuple("TimingSettings", "tRP tRCD tWR tWTR tREFI tRFC" \
|
||||||
|
|
||||||
class LASMIcon(Module):
|
class LASMIcon(Module):
|
||||||
def __init__(self, phy_settings, geom_settings, timing_settings):
|
def __init__(self, phy_settings, geom_settings, timing_settings):
|
||||||
burst_length = phy_settings.nphases*2 # command multiplication*DDR
|
if phy_settings.memtype in ["SDR"]:
|
||||||
|
burst_length = phy_settings.nphases*1 # command multiplication*SDR
|
||||||
|
elif phy_settings.memtype in ["DDR", "LPDDR", "DDR2", "DDR3"]:
|
||||||
|
burst_length = phy_settings.nphases*2 # command multiplication*DDR
|
||||||
address_align = log2_int(burst_length)
|
address_align = log2_int(burst_length)
|
||||||
|
|
||||||
self.dfi = dfi.Interface(geom_settings.mux_a,
|
self.dfi = dfi.Interface(geom_settings.mux_a,
|
||||||
|
|
|
@ -122,19 +122,22 @@ class BankMachine(Module):
|
||||||
self.cmd.stb.eq(1),
|
self.cmd.stb.eq(1),
|
||||||
If(self.cmd.ack, NextState("TRP")),
|
If(self.cmd.ack, NextState("TRP")),
|
||||||
self.cmd.ras_n.eq(0),
|
self.cmd.ras_n.eq(0),
|
||||||
self.cmd.we_n.eq(0)
|
self.cmd.we_n.eq(0),
|
||||||
|
self.cmd.is_cmd.eq(1)
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
fsm.act("ACTIVATE",
|
fsm.act("ACTIVATE",
|
||||||
s_row_adr.eq(1),
|
s_row_adr.eq(1),
|
||||||
track_open.eq(1),
|
track_open.eq(1),
|
||||||
self.cmd.stb.eq(1),
|
self.cmd.stb.eq(1),
|
||||||
|
self.cmd.is_cmd.eq(1),
|
||||||
If(self.cmd.ack, NextState("TRCD")),
|
If(self.cmd.ack, NextState("TRCD")),
|
||||||
self.cmd.ras_n.eq(0)
|
self.cmd.ras_n.eq(0)
|
||||||
)
|
)
|
||||||
fsm.act("REFRESH",
|
fsm.act("REFRESH",
|
||||||
self.refresh_gnt.eq(precharge_ok),
|
self.refresh_gnt.eq(precharge_ok),
|
||||||
track_close.eq(1),
|
track_close.eq(1),
|
||||||
|
self.cmd.is_cmd.eq(1),
|
||||||
If(~self.refresh_req, NextState("REGULAR"))
|
If(~self.refresh_req, NextState("REGULAR"))
|
||||||
)
|
)
|
||||||
fsm.delayed_enter("TRP", "ACTIVATE", timing_settings.tRP-1)
|
fsm.delayed_enter("TRP", "ACTIVATE", timing_settings.tRP-1)
|
||||||
|
|
|
@ -19,6 +19,7 @@ class CommandRequestRW(CommandRequest):
|
||||||
CommandRequest.__init__(self, a, ba)
|
CommandRequest.__init__(self, a, ba)
|
||||||
self.stb = Signal()
|
self.stb = Signal()
|
||||||
self.ack = Signal()
|
self.ack = Signal()
|
||||||
|
self.is_cmd = Signal()
|
||||||
self.is_read = Signal()
|
self.is_read = Signal()
|
||||||
self.is_write = Signal()
|
self.is_write = Signal()
|
||||||
|
|
||||||
|
@ -26,6 +27,7 @@ class _CommandChooser(Module):
|
||||||
def __init__(self, requests):
|
def __init__(self, requests):
|
||||||
self.want_reads = Signal()
|
self.want_reads = Signal()
|
||||||
self.want_writes = Signal()
|
self.want_writes = Signal()
|
||||||
|
self.want_cmds = Signal()
|
||||||
# NB: cas_n/ras_n/we_n are 1 when stb is inactive
|
# NB: cas_n/ras_n/we_n are 1 when stb is inactive
|
||||||
self.cmd = CommandRequestRW(flen(requests[0].a), flen(requests[0].ba))
|
self.cmd = CommandRequestRW(flen(requests[0].a), flen(requests[0].ba))
|
||||||
|
|
||||||
|
@ -34,12 +36,12 @@ class _CommandChooser(Module):
|
||||||
rr = RoundRobin(len(requests), SP_CE)
|
rr = RoundRobin(len(requests), SP_CE)
|
||||||
self.submodules += rr
|
self.submodules += rr
|
||||||
|
|
||||||
self.comb += [rr.request[i].eq(req.stb & ((req.is_read == self.want_reads) | (req.is_write == self.want_writes)))
|
self.comb += [rr.request[i].eq(req.stb & ((req.is_cmd & self.want_cmds) | ((req.is_read == self.want_reads) | (req.is_write == self.want_writes))))
|
||||||
for i, req in enumerate(requests)]
|
for i, req in enumerate(requests)]
|
||||||
|
|
||||||
stb = Signal()
|
stb = Signal()
|
||||||
self.comb += stb.eq(Array(req.stb for req in requests)[rr.grant])
|
self.comb += stb.eq(Array(req.stb for req in requests)[rr.grant])
|
||||||
for name in ["a", "ba", "is_read", "is_write"]:
|
for name in ["a", "ba", "is_read", "is_write", "is_cmd"]:
|
||||||
choices = Array(getattr(req, name) for req in requests)
|
choices = Array(getattr(req, name) for req in requests)
|
||||||
self.comb += getattr(self.cmd, name).eq(choices[rr.grant])
|
self.comb += getattr(self.cmd, name).eq(choices[rr.grant])
|
||||||
for name in ["cas_n", "ras_n", "we_n"]:
|
for name in ["cas_n", "ras_n", "we_n"]:
|
||||||
|
@ -47,8 +49,8 @@ class _CommandChooser(Module):
|
||||||
choices = Array(getattr(req, name) for req in requests)
|
choices = Array(getattr(req, name) for req in requests)
|
||||||
self.comb += If(self.cmd.stb, getattr(self.cmd, name).eq(choices[rr.grant]))
|
self.comb += If(self.cmd.stb, getattr(self.cmd, name).eq(choices[rr.grant]))
|
||||||
self.comb += self.cmd.stb.eq(stb \
|
self.comb += self.cmd.stb.eq(stb \
|
||||||
& (self.cmd.is_read == self.want_reads) \
|
& ((self.cmd.is_cmd & self.want_cmds) | ((self.cmd.is_read == self.want_reads) \
|
||||||
& (self.cmd.is_write == self.want_writes))
|
& (self.cmd.is_write == self.want_writes))))
|
||||||
|
|
||||||
self.comb += [If(self.cmd.stb & self.cmd.ack & (rr.grant == i), req.ack.eq(1))
|
self.comb += [If(self.cmd.stb & self.cmd.ack & (rr.grant == i), req.ack.eq(1))
|
||||||
for i, req in enumerate(requests)]
|
for i, req in enumerate(requests)]
|
||||||
|
@ -85,8 +87,6 @@ class _Steerer(Module):
|
||||||
class Multiplexer(Module, AutoCSR):
|
class Multiplexer(Module, AutoCSR):
|
||||||
def __init__(self, phy_settings, geom_settings, timing_settings, bank_machines, refresher, dfi, lasmic):
|
def __init__(self, phy_settings, geom_settings, timing_settings, bank_machines, refresher, dfi, lasmic):
|
||||||
assert(phy_settings.nphases == len(dfi.phases))
|
assert(phy_settings.nphases == len(dfi.phases))
|
||||||
if phy_settings.nphases != 2:
|
|
||||||
raise NotImplementedError("TODO: multiplexer only supports 2 phases")
|
|
||||||
|
|
||||||
# Command choosing
|
# Command choosing
|
||||||
requests = [bm.cmd for bm in bank_machines]
|
requests = [bm.cmd for bm in bank_machines]
|
||||||
|
@ -96,6 +96,11 @@ class Multiplexer(Module, AutoCSR):
|
||||||
choose_cmd.want_reads.eq(0),
|
choose_cmd.want_reads.eq(0),
|
||||||
choose_cmd.want_writes.eq(0)
|
choose_cmd.want_writes.eq(0)
|
||||||
]
|
]
|
||||||
|
if phy_settings.nphases == 1:
|
||||||
|
self.comb += [
|
||||||
|
choose_cmd.want_cmds.eq(1),
|
||||||
|
choose_req.want_cmds.eq(1)
|
||||||
|
]
|
||||||
self.submodules += choose_cmd, choose_req
|
self.submodules += choose_cmd, choose_req
|
||||||
|
|
||||||
# Command steering
|
# Command steering
|
||||||
|
@ -148,14 +153,32 @@ class Multiplexer(Module, AutoCSR):
|
||||||
|
|
||||||
# Control FSM
|
# Control FSM
|
||||||
fsm = FSM()
|
fsm = FSM()
|
||||||
|
(STEER_WRITE, STEER_READ) = range(2)
|
||||||
|
|
||||||
|
def steerer_sel(steerer, phy_settings, r_w_n):
|
||||||
|
r = []
|
||||||
|
for i in range(phy_settings.nphases):
|
||||||
|
s = steerer.sel[i].eq(STEER_NOP)
|
||||||
|
if r_w_n:
|
||||||
|
if i == phy_settings.rdphase:
|
||||||
|
s = steerer.sel[i].eq(STEER_REQ)
|
||||||
|
elif i == phy_settings.wrcmdphase:
|
||||||
|
s = steerer.sel[i].eq(STEER_CMD)
|
||||||
|
else:
|
||||||
|
if i == phy_settings.wrphase:
|
||||||
|
s = steerer.sel[i].eq(STEER_REQ)
|
||||||
|
elif i == phy_settings.rdcmdphase:
|
||||||
|
s = steerer.sel[i].eq(STEER_CMD)
|
||||||
|
r.append(s)
|
||||||
|
return r
|
||||||
|
|
||||||
self.submodules += fsm
|
self.submodules += fsm
|
||||||
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.ack.eq(1),
|
choose_cmd.cmd.ack.eq(1),
|
||||||
choose_req.cmd.ack.eq(1),
|
choose_req.cmd.ack.eq(1),
|
||||||
steerer.sel[1-phy_settings.rdphase].eq(STEER_CMD),
|
steerer_sel(steerer, phy_settings, STEER_READ),
|
||||||
steerer.sel[phy_settings.rdphase].eq(STEER_REQ),
|
|
||||||
If(write_available,
|
If(write_available,
|
||||||
# TODO: switch only after several cycles of ~read_available?
|
# TODO: switch only after several cycles of ~read_available?
|
||||||
If(~read_available | max_read_time, NextState("RTW"))
|
If(~read_available | max_read_time, NextState("RTW"))
|
||||||
|
@ -167,8 +190,7 @@ class Multiplexer(Module, AutoCSR):
|
||||||
choose_req.want_writes.eq(1),
|
choose_req.want_writes.eq(1),
|
||||||
choose_cmd.cmd.ack.eq(1),
|
choose_cmd.cmd.ack.eq(1),
|
||||||
choose_req.cmd.ack.eq(1),
|
choose_req.cmd.ack.eq(1),
|
||||||
steerer.sel[1-phy_settings.wrphase].eq(STEER_CMD),
|
steerer_sel(steerer, phy_settings, STEER_WRITE),
|
||||||
steerer.sel[phy_settings.wrphase].eq(STEER_REQ),
|
|
||||||
If(read_available,
|
If(read_available,
|
||||||
If(~write_available | max_write_time, NextState("WTR"))
|
If(~write_available | max_write_time, NextState("WTR"))
|
||||||
),
|
),
|
||||||
|
|
|
@ -43,6 +43,8 @@ class S6DDRPHY(Module):
|
||||||
nphases=nphases,
|
nphases=nphases,
|
||||||
rdphase=0,
|
rdphase=0,
|
||||||
wrphase=1,
|
wrphase=1,
|
||||||
|
rdcmdphase=1,
|
||||||
|
wrcmdphase=0,
|
||||||
cl=cl,
|
cl=cl,
|
||||||
read_latency=5,
|
read_latency=5,
|
||||||
write_latency=0
|
write_latency=0
|
||||||
|
|
|
@ -21,6 +21,8 @@ sdram_phy = lasmicon.PhySettings(
|
||||||
nphases=2,
|
nphases=2,
|
||||||
rdphase=0,
|
rdphase=0,
|
||||||
wrphase=1,
|
wrphase=1,
|
||||||
|
rdcmdphase=1,
|
||||||
|
wrcmdphase=0,
|
||||||
cl=3,
|
cl=3,
|
||||||
read_latency=5,
|
read_latency=5,
|
||||||
write_latency=0
|
write_latency=0
|
||||||
|
|
Loading…
Reference in a new issue