from collections import OrderedDict
from nmigen import *
+from nmigen.hdl.rec import *
+from nmigen.utils import log2_int
+
import gram.stream as stream
# Helpers ------------------------------------------------------------------------------------------
def elaborate(self, platform):
m = Module()
- value = Signal(max=self._cycles*dw)
+ value = Signal(range(self._cycles*dw))
with m.If(self.slp):
m.d.sync += value.eq(value+1)
with m.Elif(self.rst):
]
-class LiteDRAMInterface(Record):
+class gramInterface(Record):
def __init__(self, address_align, settings):
rankbits = log2_int(settings.phy.nranks)
self.address_align = address_align
# Ports --------------------------------------------------------------------------------------------
-class LiteDRAMNativePort(Settings):
+class gramNativePort(Settings):
def __init__(self, mode, address_width, data_width, clock_domain="sys", id=0):
self.set_attributes(locals())
return self.cmd.addr[:cba_shift]
-class LiteDRAMNativeWritePort(LiteDRAMNativePort):
+class gramNativeWritePort(gramNativePort):
def __init__(self, *args, **kwargs):
LiteDRAMNativePort.__init__(self, "write", *args, **kwargs)
-class LiteDRAMNativeReadPort(LiteDRAMNativePort):
+class gramNativeReadPort(gramNativePort):
def __init__(self, *args, **kwargs):
LiteDRAMNativePort.__init__(self, "read", *args, **kwargs)
self.valid = Signal()
self.ready = ready = Signal(reset=txxd is None)
#ready.attr.add("no_retiming") TODO
+ self._txxd = txxd
def elaborate(self, platform):
m = Module()
- if txxd is not None:
- count = Signal(range(max(txxd, 2)))
+ if self._txxd is not None:
+ count = Signal(range(max(self._txxd, 2)))
with m.If(self.valid):
m.d.sync += [
- count.eq(txxd-1),
- self.ready.eq((txxd - 1) == 0),
+ count.eq(self._txxd-1),
+ self.ready.eq((self._txxd - 1) == 0),
]
with m.Else():
m.d.sync += count.eq(count-1)
self.valid = Signal()
self.ready = Signal(reset=1)
#ready.attr.add("no_retiming") TODO
+ self._tfaw = tfaw
def elaborate(self, platform):
m = Module()
- if tfaw is not None:
- count = Signal(range(max(tfaw, 2)))
- window = Signal(tfaw)
+ if self._tfaw is not None:
+ count = Signal(range(max(self._tfaw, 2)))
+ window = Signal(self._tfaw)
m.d.sync += window.eq(Cat(self.valid, window))
- m.d.comb += count.eq(reduce(add, [window[i] for i in range(tfaw)]))
+ m.d.comb += count.eq(reduce(add, [window[i] for i in range(self._tfaw)]))
with m.If(count < 4):
with m.If(count == 3):
m.d.sync += self.ready.eq(~self.valid)
from nmigen import *
+from nmigen.compat import Case
__ALL__ = ["delayed_enter", "RoundRobin", "Timeline"]
with m.State(statename):
m.next = deststate
-(SP_WITHDRAW, SP_CE) = range(2)
-
+# Original nMigen implementation by HarryHo90sHK
class RoundRobin(Elaboratable):
- def __init__(self, n, switch_policy=SP_WITHDRAW):
+ """A round-robin scheduler.
+ Parameters
+ ----------
+ n : int
+ Maximum number of requests to handle.
+ Attributes
+ ----------
+ request : Signal(n)
+ Signal where a '1' on the i-th bit represents an incoming request from the i-th device.
+ grant : Signal(range(n))
+ Signal that equals to the index of the device which is currently granted access.
+ stb : Signal()
+ Strobe signal to enable granting access to the next device requesting. Externally driven.
+ """
+ def __init__(self, n):
+ self.n = n
self.request = Signal(n)
- self.grant = Signal(max=max(2, n))
- self.switch_policy = switch_policy
- if self.switch_policy == SP_CE:
- self.ce = Signal()
+ self.grant = Signal(range(n))
+ self.stb = Signal()
def elaborate(self, platform):
m = Module()
- # TODO: fix
-
- if n > 1:
- cases = {}
- for i in range(n):
- switch = []
- for j in reversed(range(i+1, i+n)):
- t = j % n
- switch = [
- If(self.request[t],
- self.grant.eq(t)
- ).Else(
- *switch
- )
- ]
- if self.switch_policy == SP_WITHDRAW:
- case = [If(~self.request[i], *switch)]
- else:
- case = switch
- cases[i] = case
- statement = Case(self.grant, cases)
- if self.switch_policy == SP_CE:
- with m.If(self.ce):
- m.d.sync += statement
- else:
- m.d.sync += statement
- else:
- m.d.comb += self.grant.eq(0)
+ with m.If(self.stb):
+ with m.Switch(self.grant):
+ for i in range(self.n):
+ with m.Case(i):
+ for j in reversed(range(i+1, i+self.n)):
+ # If i+1 <= j < n, then t == j; (after i)
+ # If n <= j < i+n, then t == j - n (before i)
+ t = j % self.n
+ with m.If(self.request[t]):
+ m.d.sync += self.grant.eq(t)
return m
def elaborate(self, platform):
m = Module()
- m.submodules.dfii = DFIInjector(
+ m.submodules.dfii = dfii = DFIInjector(
addressbits = self._geom_settings.addressbits,
bankbits = self._geom_settings.bankbits,
nranks = self._phy.settings.nranks,
databits = self._phy.settings.dfi_databits,
nphases = self._phy.settings.nphases)
- m.d.comb += self.dfii.master.connect(self._phy.dfi)
+ m.d.comb += dfii.master.connect(self._phy.dfi)
m.submodules.controller = controller = gramController(
phy_settings = self._phy.settings,
timing_settings = self._timing_settings,
clk_freq = self._clk_freq,
**self._kwargs)
- m.d.comb += controller.dfi.connect(self.dfii.slave)
+ m.d.comb += controller.dfi.connect(dfii.slave)
- m.submodules.crossbar = LiteDRAMCrossbar(controller.interface)
+ m.submodules.crossbar = gramCrossbar(controller.interface)
return m
def col(self, address):
split = self.colbits - self.address_align
- return Cat(Replicate(0, self.address_align), address[:split])
+ return Cat(Repl(0, self.address_align), address[:split])
# BankMachine --------------------------------------------------------------------------------------
Stream of commands to the Multiplexer
"""
def __init__(self, n, address_width, address_align, nranks, settings):
+ self.settings = settings
self.req = req = Record(cmd_layout(address_width))
self.refresh_req = refresh_req = Signal()
self.refresh_gnt = refresh_gnt = Signal()
auto_precharge = Signal()
# Command buffer ---------------------------------------------------------------------------
- cmd_buffer_layout = [("we", 1), ("addr", len(req.addr))]
+ cmd_buffer_layout = [("we", 1), ("addr", len(self.req.addr))]
cmd_buffer_lookahead = stream.SyncFIFO(
- cmd_buffer_layout, settings.cmd_buffer_depth,
- buffered=settings.cmd_buffer_buffered)
+ cmd_buffer_layout, self.settings.cmd_buffer_depth,
+ buffered=self.settings.cmd_buffer_buffered)
cmd_buffer = stream.Buffer(cmd_buffer_layout) # 1 depth buffer to detect row change
m.submodules += cmd_buffer_lookahead, cmd_buffer
m.d.comb += [
- req.connect(cmd_buffer_lookahead.sink, keep={"valid", "ready", "we", "addr"}),
+ self.req.connect(cmd_buffer_lookahead.sink, include={"valid", "ready", "we", "addr"}),
cmd_buffer_lookahead.source.connect(cmd_buffer.sink),
- cmd_buffer.source.ready.eq(req.wdata_ready | req.rdata_valid),
- req.lock.eq(cmd_buffer_lookahead.source.valid | cmd_buffer.source.valid),
+ cmd_buffer.source.ready.eq(self.req.wdata_ready | self.req.rdata_valid),
+ self.req.lock.eq(cmd_buffer_lookahead.source.valid | cmd_buffer.source.valid),
]
- slicer = _AddressSlicer(settings.geom.colbits, address_align)
+ slicer = _AddressSlicer(self.settings.geom.colbits, address_align)
# Row tracking -----------------------------------------------------------------------------
- row = Signal(settings.geom.rowbits)
+ row = Signal(self.settings.geom.rowbits)
row_opened = Signal()
row_hit = Signal()
row_open = Signal()
m.d.comb += cmd.a.eq((auto_precharge << 10) | slicer.col(cmd_buffer.source.addr))
# tWTP (write-to-precharge) controller -----------------------------------------------------
- write_latency = math.ceil(settings.phy.cwl / settings.phy.nphases)
- precharge_time = write_latency + settings.timing.tWR + settings.timing.tCCD # AL=0
+ write_latency = math.ceil(self.settings.phy.cwl / self.settings.phy.nphases)
+ precharge_time = write_latency + self.settings.timing.tWR + self.settings.timing.tCCD # AL=0
m.submodules.twtpcon = twtpcon = tXXDController(precharge_time)
m.d.comb += twtpcon.valid.eq(cmd.valid & cmd.ready & cmd.is_write)
# tRC (activate-activate) controller -------------------------------------------------------
- m.submodules.trccon = trccon = tXXDController(settings.timing.tRC)
+ m.submodules.trccon = trccon = tXXDController(self.settings.timing.tRC)
m.d.comb += trccon.valid.eq(cmd.valid & cmd.ready & row_open)
# tRAS (activate-precharge) controller -----------------------------------------------------
- m.submodules.trascon = trascon = tXXDController(settings.timing.tRAS)
+ m.submodules.trascon = trascon = tXXDController(self.settings.timing.tRAS)
m.d.comb += trascon.valid.eq(cmd.valid & cmd.ready & row_open)
# Auto Precharge generation ----------------------------------------------------------------
]
with m.If(cmd_buffer.source.we):
m.d.comb += [
- req.wdata_ready.eq(cmd.ready),
+ self.req.wdata_ready.eq(cmd.ready),
cmd.is_write.eq(1),
cmd.we.eq(1),
]
with m.Else():
m.d.comb += [
- req.rdata_valid.eq(cmd.ready),
+ self.req.rdata_valid.eq(cmd.ready),
cmd.is_read.eq(1),
]
with m.If(cmd.ready & auto_precharge):
with m.If(~refresh_req):
m.next = "Regular"
- delayed_enter(m, "TRP", "ACTIVATE", settings.timing.tRP - 1)
- delayed_enter(m, "TRCD", "REGULAR", settings.timing.tRCD - 1)
+ delayed_enter(m, "tRP", "Activate", self.settings.timing.tRP - 1)
+ delayed_enter(m, "tRCD", "Regular", self.settings.timing.tRCD - 1)
return m
"""LiteDRAM Controller."""
from nmigen import *
+from nmigen.utils import log2_int
from gram.common import *
from gram.phy import dfi
class gramController(Elaboratable):
def __init__(self, phy_settings, geom_settings, timing_settings, clk_freq,
controller_settings=ControllerSettings()):
- address_align = log2_int(burst_lengths[phy_settings.memtype])
+ self._address_align = log2_int(burst_lengths[phy_settings.memtype])
# Settings ---------------------------------------------------------------------------------
self.settings = controller_settings
self.settings.geom = geom_settings
self.settings.timing = timing_settings
- nranks = phy_settings.nranks
- nbanks = 2**geom_settings.bankbits
-
# LiteDRAM Interface (User) ----------------------------------------------------------------
- self.interface = interface = LiteDRAMInterface(address_align, self.settings)
+ self.interface = interface = gramInterface(self._address_align, self.settings)
# DFI Interface (Memory) -------------------------------------------------------------------
self.dfi = dfi.Interface(
databits = phy_settings.dfi_databits,
nphases = phy_settings.nphases)
+ self._clk_freq = clk_freq
+
def elaborate(self, platform):
m = Module()
+ nranks = self.settings.phy.nranks
+ nbanks = 2**self.settings.geom.bankbits
+
# Refresher --------------------------------------------------------------------------------
m.submodules.refresher = self.settings.refresh_cls(self.settings,
- clk_freq = clk_freq,
+ clk_freq = self._clk_freq,
zqcs_freq = self.settings.refresh_zqcs_freq,
postponing = self.settings.refresh_postponing)
bank_machines = []
for n in range(nranks*nbanks):
bank_machine = BankMachine(n,
- address_width = interface.address_width,
- address_align = address_align,
+ address_width = self.interface.address_width,
+ address_align = self._address_align,
nranks = nranks,
settings = self.settings)
bank_machines.append(bank_machine)
m.submodules += bank_machine
- m.d.comb += getattr(interface, "bank"+str(n)).connect(bank_machine.req)
+ m.d.comb += getattr(self.interface, "bank"+str(n)).connect(bank_machine.req)
# Multiplexer ------------------------------------------------------------------------------
m.submodules.multiplexer = Multiplexer(
settings = self.settings,
bank_machines = bank_machines,
- refresher = self.refresher,
+ refresher = m.submodules.refresher,
dfi = self.dfi,
- interface = interface)
+ interface = self.interface)
return m
# LiteDRAMCrossbar ---------------------------------------------------------------------------------
-class gramCrossbar(Module):
+class gramCrossbar(Elaboratable):
"""Multiplexes LiteDRAMController (slave) between ports (masters)
To get a port to LiteDRAM, use the `get_port` method. It handles data width
return port
- def do_finalize(self):
+ def elaborate(self, platform):
+ m = Module()
+
controller = self.controller
nmasters = len(self.masters)
master_wdata_readys = [0]*nmasters
master_rdata_valids = [0]*nmasters
- arbiters = [roundrobin.RoundRobin(nmasters, roundrobin.SP_CE) for n in range(self.nbanks)]
- self.submodules += arbiters
+ arbiters = [RoundRobin(nmasters) for n in range(self.nbanks)]
+ m.submodules += arbiters
for nb, arbiter in enumerate(arbiters):
bank = getattr(controller, "bank"+str(nb))
# Arbitrate ----------------------------------------------------------------------------
bank_selected = [(ba == nb) & ~locked for ba, locked in zip(m_ba, master_locked)]
bank_requested = [bs & master.cmd.valid for bs, master in zip(bank_selected, self.masters)]
- self.comb += [
+ m.d.comb += [
arbiter.request.eq(Cat(*bank_requested)),
- arbiter.ce.eq(~bank.valid & ~bank.lock)
+ arbiter.stb.eq(~bank.valid & ~bank.lock)
]
# Route requests -----------------------------------------------------------------------
- self.comb += [
+ m.d.comb += [
bank.addr.eq(Array(m_rca)[arbiter.grant]),
bank.we.eq(Array(self.masters)[arbiter.grant].cmd.we),
bank.valid.eq(Array(bank_requested)[arbiter.grant])
for nm, master_wdata_ready in enumerate(master_wdata_readys):
for i in range(self.write_latency):
new_master_wdata_ready = Signal()
- self.sync += new_master_wdata_ready.eq(master_wdata_ready)
+ m.d.sync += new_master_wdata_ready.eq(master_wdata_ready)
master_wdata_ready = new_master_wdata_ready
master_wdata_readys[nm] = master_wdata_ready
for nm, master_rdata_valid in enumerate(master_rdata_valids):
for i in range(self.read_latency):
new_master_rdata_valid = Signal()
- self.sync += new_master_rdata_valid.eq(master_rdata_valid)
+ m.d.sync += new_master_rdata_valid.eq(master_rdata_valid)
master_rdata_valid = new_master_rdata_valid
master_rdata_valids[nm] = master_rdata_valid
for master, master_ready in zip(self.masters, master_readys):
- self.comb += master.cmd.ready.eq(master_ready)
+ m.d.comb += master.cmd.ready.eq(master_ready)
for master, master_wdata_ready in zip(self.masters, master_wdata_readys):
- self.comb += master.wdata.ready.eq(master_wdata_ready)
+ m.d.comb += master.wdata.ready.eq(master_wdata_ready)
for master, master_rdata_valid in zip(self.masters, master_rdata_valids):
- self.comb += master.rdata.valid.eq(master_rdata_valid)
+ m.d.comb += master.rdata.valid.eq(master_rdata_valid)
# Route data writes ------------------------------------------------------------------------
wdata_cases = {}
controller.wdata.eq(0),
controller.wdata_we.eq(0)
]
- self.comb += Case(Cat(*master_wdata_readys), wdata_cases)
+ m.d.comb += Case(Cat(*master_wdata_readys), wdata_cases)
# Route data reads -------------------------------------------------------------------------
for master in self.masters:
- self.comb += master.rdata.data.eq(controller.rdata)
+ m.d.comb += master.rdata.data.eq(controller.rdata)
+
+ return m
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)))
+ m.d.comb += valids[i].eq(request.valid & (command | (read & write)))
- arbiter = RoundRobin(n, SP_CE)
- self.submodules += arbiter
+ arbiter = RoundRobin(n)
+ m.submodules += arbiter
choices = Array(valids[i] for i in range(n))
m.d.comb += [
arbiter.request.eq(valids),
for name in ["a", "ba", "is_read", "is_write", "is_cmd"]:
choices = Array(getattr(req, name) for req in self._requests)
- self.comb += getattr(self.cmd, name).eq(choices[arbiter.grant])
+ m.d.comb += getattr(self.cmd, name).eq(choices[arbiter.grant])
for name in ["cas", "ras", "we"]:
# we should only assert those signals when valid is 1
choices = Array(getattr(req, name) for req in self._requests)
with m.If(self.cmd.valid):
- m.d.comb += getattr(cmd, name).eq(choices[arbiter.grant])
+ m.d.comb += getattr(self.cmd, name).eq(choices[arbiter.grant])
for i, request in enumerate(self._requests):
with m.If(self.cmd.valid & self.cmd.ready & (arbiter.grant == i)):
# Arbitrate if a command is being accepted or if the command is not valid to ensure a valid
# command is selected when cmd.ready goes high.
- m.d.comb += arbiter.ce.eq(self.cmd.ready | ~self.cmd.valid)
+ m.d.comb += arbiter.stb.eq(self.cmd.ready | ~self.cmd.valid)
return m
nranks = len(phase.cs_n)
rankbits = log2_int(nranks)
if hasattr(phase, "reset_n"):
- self.comb += phase.reset_n.eq(1)
- m.d.comb += phase.cke.eq(Replicate(Signal(reset=1), nranks))
+ m.d.comb += phase.reset_n.eq(1)
+ m.d.comb += phase.cke.eq(Repl(Signal(reset=1), nranks))
if hasattr(phase, "odt"):
# FIXME: add dynamic drive for multi-rank (will be needed for high frequencies)
- m.d.comb += phase.odt.eq(Replicate(Signal(reset=1), nranks))
+ m.d.comb += phase.odt.eq(Repl(Signal(reset=1), nranks))
if rankbits:
rank_decoder = Decoder(nranks)
- self.submodules += rank_decoder
+ m.submodules += rank_decoder
m.d.comb += rank_decoder.i.eq((Array(cmd.ba[-rankbits:] for cmd in commands)[sel]))
if i == 0: # Select all ranks on refresh.
with m.If(sel == STEER_REFRESH):
dfi,
interface):
assert(settings.phy.nphases == len(dfi.phases))
+ self._settings = settings
+ self._bank_machines = bank_machines
+ self._refresher = refresher
+ self._dfi = dfi
+ self._interface = interface
+
+ def elaborate(self, platform):
+ m = Module()
+
+ settings = self._settings
+ bank_machines = self._bank_machines
+ refresher = self._refresher
+ dfi = self._dfi
+ interface = self._interface
ras_allowed = Signal(reset=1)
cas_allowed = Signal(reset=1)
t = timeout - 1
time = Signal(range(t+1))
m.d.comb += max_time.eq(time == 0)
- m.d.sync += If(~en,
- time.eq(t)
- ).Elif(~max_time,
- time.eq(time - 1)
- )
+ with m.If(~en):
+ m.d.sync += time.eq(t)
+ with m.Elif(~max_time):
+ m.d.sync += time.eq(time - 1)
else:
m.d.comb += max_time.eq(0)
return en, max_time
m.next = "Read"
# TODO: reduce this, actual limit is around (cl+1)/nphases
- delayed_enter(m, "RTW", "WRITE", settings.phy.read_latency-1)
+ delayed_enter(m, "RTW", "Write", settings.phy.read_latency-1)
if settings.with_bandwidth:
data_width = settings.phy.dfi_databits*settings.phy.nphases
- self.submodules.bandwidth = Bandwidth(self.choose_req.cmd, data_width)
+ m.submodules.bandwidth = Bandwidth(self.choose_req.cmd, data_width)
+
+ return m
"""LiteDRAM Refresher."""
from nmigen import *
-
-from litex.soc.interconnect import stream
+from nmigen.utils import bits_for, log2_int
from gram.core.multiplexer import *
from gram.compat import Timeline
+import gram.stream as stream
# RefreshExecuter ----------------------------------------------------------------------------------
trp = self._trp
trfc = self._trfc
- self.sync += [
+ m.d.sync += [
self._cmd.a.eq( 0),
self._cmd.ba.eq( 0),
self._cmd.cas.eq(0),
def __init__(self, cmd, trp, trfc, postponing=1):
self.start = Signal()
self.done = Signal()
+
self._trp = trp
self._trfc = trfc
self._postponing = postponing
+ self._cmd = cmd
def elaborate(self, platform):
m = Module()
- trp = self._trp
- trfc = self._trfc
+ executer = RefreshExecuter(self._cmd, self._trp, self._trfc)
+ m.submodules += executer
- executer = RefreshExecuter(cmd, trp, trfc)
- self.submodules += executer
-
- count = Signal(bits_for(postponing), reset=postponing-1)
+ count = Signal(bits_for(self._postponing), reset=self._postponing-1)
with m.If(self.start):
m.d.sync += count.eq(count.reset)
with m.Elif(executer.done):
self._postponing = postponing
def elaborate(self, platform):
+ m = Module()
count = Signal(bits_for(self._postponing), reset=self._postponing-1)
babits = settings.geom.bankbits + log2_int(settings.phy.nranks)
self.cmd = cmd = stream.Endpoint(cmd_request_rw_layout(a=abits, ba=babits))
self._postponing = postponing
+ self._settings = settings
+ self._clk_freq = clk_freq
+ self._zqcs_freq = zqcs_freq
def elaborate(self, platform):
m = Module()
wants_refresh = Signal()
wants_zqcs = Signal()
+ settings = self._settings
+
# Refresh Timer ----------------------------------------------------------------------------
timer = RefreshTimer(settings.timing.tREFI)
- self.submodules.timer = timer
+ m.submodules.timer = timer
m.d.comb += timer.wait.eq(~timer.done)
# Refresh Postponer ------------------------------------------------------------------------
postponer = RefreshPostponer(self._postponing)
- self.submodules.postponer = postponer
+ m.submodules.postponer = postponer
m.d.comb += [
- postponer.req_i.eq(self.timer.done),
+ postponer.req_i.eq(timer.done),
wants_refresh.eq(postponer.req_o),
]
# Refresh Sequencer ------------------------------------------------------------------------
- sequencer = RefreshSequencer(cmd, settings.timing.tRP, settings.timing.tRFC, self._postponing)
- self.submodules.sequencer = sequencer
+ sequencer = RefreshSequencer(self.cmd, settings.timing.tRP, settings.timing.tRFC, self._postponing)
+ m.submodules.sequencer = sequencer
if settings.timing.tZQCS is not None:
# ZQCS Timer ---------------------------------------------------------------------------
- zqcs_timer = RefreshTimer(int(clk_freq/zqcs_freq))
- self.submodules.zqcs_timer = zqcs_timer
+ zqcs_timer = RefreshTimer(int(self._clk_freq/self._zqcs_freq))
+ m.submodules.zqcs_timer = zqcs_timer
m.d.comb += wants_zqcs.eq(zqcs_timer.done)
# ZQCS Executer ------------------------------------------------------------------------
- zqcs_executer = ZQCSExecuter(cmd, settings.timing.tRP, settings.timing.tZQCS)
- self.submodules.zqs_executer = zqcs_executer
+ zqcs_executer = ZQCSExecuter(self.cmd, settings.timing.tRP, settings.timing.tZQCS)
+ m.submodules.zqs_executer = zqcs_executer
m.d.comb += zqcs_timer.wait.eq(~zqcs_executer.done)
# Refresh FSM ------------------------------------------------------------------------------
m.next = "Wait-Bank-Machines"
with m.State("Wait-Bank-Machines"):
- m.d.comb += cmd.valid.eq(1)
- with m.If(cmd.ready):
+ m.d.comb += self.cmd.valid.eq(1)
+ with m.If(self.cmd.ready):
m.d.comb += sequencer.start.eq(1)
m.next = "Do-Refresh"
if settings.timing.tZQCS is None:
with m.State("Do-Refresh"):
- m.d.comb += cmd.valid.eq(1)
+ m.d.comb += self.cmd.valid.eq(1)
with m.If(sequencer.done):
m.d.comb += [
- cmd.valid.eq(0),
- cmd.last.eq(1),
+ self.cmd.valid.eq(0),
+ self.cmd.last.eq(1),
]
m.next = "Idle"
else:
with m.State("Do-Refresh"):
- m.d.comb += cmd.valid.eq(1)
+ m.d.comb += self.cmd.valid.eq(1)
with m.If(sequencer.done):
with m.If(wants_zqcs):
m.d.comb += zqcs_executer.start.eq(1)
m.next = "Do-Zqcs"
with m.Else():
m.d.comb += [
- cmd.valid.eq(0),
- cmd.last.eq(1),
+ self.cmd.valid.eq(0),
+ self.cmd.last.eq(1),
]
m.next = "Idle"
with m.State("Do-Zqcs"):
- m.d.comb += cmd.valid.eq(1)
+ m.d.comb += self.cmd.valid.eq(1)
with m.If(zqcs_executer.done):
m.d.comb += [
- cmd.valid.eq(0),
- cmd.last.eq(1),
+ self.cmd.valid.eq(0),
+ self.cmd.last.eq(1),
]
m.next = "Idle"
class PhaseInjector(Peripheral, Elaboratable):
def __init__(self, phase):
+ super().__init__(name = "phaseinjector")
+
bank = self.csr_bank()
self._command = bank.csr(6, "rw")
self._command_issue = bank.csr(1, "rw")
- self._address = bank.csr(len(phase.address), "rw", reset_less=True)
- self._baddress = bank.csr(len(phase.bank), "rw", reset_less=True)
- self._wrdata = bank.csr(len(phase.wrdata), "rw", reset_less=True)
- self._rddata = bank.csr(len(phase.rddata))
+ self._address = bank.csr(len(phase.address), "rw")
+ self._baddress = bank.csr(len(phase.bank), "rw")
+ self._wrdata = bank.csr(len(phase.wrdata), "rw")
+ self._rddata = bank.csr(len(phase.rddata), "rw")
+
+ self._phase = phase
def elaborate(self, platform):
m = Module()
m.d.comb += [
- phase.address.eq(self._address.storage),
- phase.bank.eq(self._baddress.storage),
- phase.wrdata_en.eq(self._command_issue.re & self._command.storage[4]),
- phase.rddata_en.eq(self._command_issue.re & self._command.storage[5]),
- phase.wrdata.eq(self._wrdata.storage),
- phase.wrdata_mask.eq(0)
+ self._phase.address.eq(self._address.r_data),
+ self._phase.bank.eq(self._baddress.r_data),
+ self._phase.wrdata_en.eq(self._command_issue.r_stb & self._command.r_data[4]),
+ self._phase.rddata_en.eq(self._command_issue.r_stb & self._command.r_data[5]),
+ self._phase.wrdata.eq(self._wrdata.r_data),
+ self._phase.wrdata_mask.eq(0)
]
- with m.If(self._command_issue.re):
+ with m.If(self._command_issue.r_stb):
m.d.comb += [
- phase.cs_n.eq(Replicate(~self._command.storage[0], len(phase.cs_n))),
- phase.we_n.eq(~self._command.storage[1]),
- phase.cas_n.eq(~self._command.storage[2]),
- phase.ras_n.eq(~self._command.storage[3]),
+ self._phase.cs_n.eq(Repl(value=~self._command.r_data[0], count=len(self._phase.cs_n))),
+ self._phase.we_n.eq(~self._command.r_data[1]),
+ self._phase.cas_n.eq(~self._command.r_data[2]),
+ self._phase.ras_n.eq(~self._command.r_data[3]),
]
with m.Else():
m.d.comb += [
- phase.cs_n.eq(Replicate(1, len(phase.cs_n))),
- phase.we_n.eq(1),
- phase.cas_n.eq(1),
- phase.ras_n.eq(1),
+ self._phase.cs_n.eq(Repl(value=1, count=len(self._phase.cs_n))),
+ self._phase.we_n.eq(1),
+ self._phase.cas_n.eq(1),
+ self._phase.ras_n.eq(1),
]
- with m.If(phase.rddata_valid):
- m.d.sync += self._rddata.status.eq(phase.rddata)
+ with m.If(self._phase.rddata_valid):
+ m.d.sync += self._rddata.w_data.eq(self._phase.rddata)
return m
class DFIInjector(Peripheral, Elaboratable):
def __init__(self, addressbits, bankbits, nranks, databits, nphases=1):
+ super().__init__(name = "dfii")
+
+ self._nranks = nranks
+
self._inti = dfi.Interface(addressbits, bankbits, nranks, databits, nphases)
self.slave = dfi.Interface(addressbits, bankbits, nranks, databits, nphases)
self.master = dfi.Interface(addressbits, bankbits, nranks, databits, nphases)
bank = self.csr_bank()
- self._control = bank.csr(4) # sel, cke, odt, reset_n
-
- #for n, phase in enumerate(inti.phases):
- # setattr(self.submodules, "pi" + str(n), PhaseInjector(phase)) TODO
-
- # # #
+ self._control = bank.csr(4, "rw") # sel, cke, odt, reset_n
def elaborate(self, platform):
m = Module()
- with m.If(self._control.storage[0]):
+ for n, phase in enumerate(self._inti.phases):
+ setattr(m.submodules, "pi" + str(n), PhaseInjector(phase))
+
+ with m.If(self._control.r_data[0]):
m.d.comb += self.slave.connect(self.master)
with m.Else():
m.d.comb += self._inti.connect(self.master)
- for i in range(nranks):
- m.d.comb += [phase.cke[i].eq(self._control.storage[1]) for phase in self._inti.phases]
- m.d.comb += [phase.odt[i].eq(self._control.storage[2]) for phase in self._inti.phases if hasattr(phase, "odt")]
- m.d.comb += [phase.reset_n.eq(self._control.storage[3]) for phase in self._inti.phases if hasattr(phase, "reset_n")]
+ for i in range(self._nranks):
+ m.d.comb += [phase.cke[i].eq(self._control.r_data[1]) for phase in self._inti.phases]
+ m.d.comb += [phase.odt[i].eq(self._control.r_data[2]) for phase in self._inti.phases if hasattr(phase, "odt")]
+ m.d.comb += [phase.reset_n.eq(self._control.r_data[3]) for phase in self._inti.phases if hasattr(phase, "reset_n")]
return m
self.submodules.read = LiteDRAMAXI2NativeR(axi, port, r_buffer_depth, base_address)
# Write / Read arbitration -----------------------------------------------------------------
- arbiter = RoundRobin(2, SP_CE)
+ arbiter = RoundRobin(2)
self.submodules += arbiter
- self.comb += arbiter.ce.eq(~port.cmd.valid | port.cmd.ready)
+ self.comb += arbiter.stb.eq(~port.cmd.valid | port.cmd.ready)
for i, master in enumerate([self.write, self.read]):
self.comb += arbiter.request[i].eq(master.cmd_request)
self.comb += master.cmd_grant.eq(arbiter.grant == i)
import gram.stream as stream
from gram.common import *
from gram.phy.dfi import *
-from gram.timeline import Timeline
+from gram.compat import Timeline
# Lattice ECP5 DDR PHY Initialization --------------------------------------------------------------
class ECP5DDRPHY(Peripheral, Elaboratable):
def __init__(self, pads, sys_clk_freq=100e6):
- super().__init__() # Peripheral init
+ super().__init__()
#self.pads = PHYPadsCombiner(pads)
self.pads = pads
write_port.adr.eq(wraddr),
write_port.dat_w.eq(self.write_data),
If(we_granularity,
- write_port.we.eq(Replicate(self.write, data_width//8) & ~self.write_mask),
+ write_port.we.eq(Repl(self.write, data_width//8) & ~self.write_mask),
).Else(
write_port.we.eq(self.write),
),
from nmigen.lib import fifo
-__all__ = ["Endpoint", "SyncFIFO", "AsyncFIFO"]
+__all__ = ["Endpoint", "SyncFIFO", "AsyncFIFO", "Buffer"]
def _make_fanout(layout):
class SyncFIFO(Elaboratable, _FIFOWrapper):
- def __init__(self, layout, depth, fwft=True):
+ def __init__(self, layout, depth, fwft=True, buffered=False):
super().__init__(layout)
- self.fifo = fifo.SyncFIFO(width=len(Record(self.layout)), depth=depth, fwft=fwft)
+ if buffered:
+ self.fifo = fifo.SyncFIFOBuffered(width=len(Record(self.layout)), depth=depth, fwft=fwft)
+ else:
+ self.fifo = fifo.SyncFIFO(width=len(Record(self.layout)), depth=depth, fwft=fwft)
self.depth = self.fifo.depth
self.level = self.fifo.level
self.fifo = fifo.AsyncFIFO(width=len(Record(self.layout)), depth=depth,
r_domain=r_domain, w_domain=w_domain)
self.depth = self.fifo.depth
+
+class PipeValid(Elaboratable):
+ """Pipe valid/payload to cut timing path"""
+ def __init__(self, layout):
+ self.sink = Endpoint(layout)
+ self.source = Endpoint(layout)
+
+ def elaborate(self, platform):
+ m = Module()
+
+ # Pipe when source is not valid or is ready.
+ with m.If(~self.source.valid | self.source.ready):
+ m.d.sync += [
+ self.source.valid.eq(self.sink.valid),
+ self.source.first.eq(self.sink.first),
+ self.source.last.eq(self.sink.last),
+ self.source.payload.eq(self.sink.payload),
+ self.source.param.eq(self.sink.param),
+ ]
+ m.d.comb += self.sink.ready.eq(~self.source.valid | self.source.ready)
+
+ return m
+
+class Buffer(PipeValid): pass # FIXME: Replace Buffer with PipeValid in codebase?