from operator import or_, and_
from nmigen import *
+from nmigen.asserts import Assert, Assume
from gram.common import *
import gram.stream as stream
write = request.is_write == self.want_writes
m.d.comb += valids[i].eq(request.valid & (command | (read & write)))
- arbiter = RoundRobin(n)
- m.submodules += arbiter
+ m.submodules.arbiter = arbiter = RoundRobin(n)
choices = Array(valids[i] for i in range(n))
m.d.comb += [
arbiter.request.eq(valids),
"""
def __init__(self, commands, dfi):
+ assert len(commands) == 4
self._commands = commands
self._dfi = dfi
- ncmd = len(commands)
- nph = len(dfi.phases)
- self.sel = [Signal(range(ncmd)) for i in range(nph)]
+ self.sel = [Signal(range(len(commands))) for i in range(len(dfi.phases))]
def elaborate(self, platform):
m = Module()
return cmd.valid & cmd.ready & getattr(cmd, attr)
for i, (phase, sel) in enumerate(zip(dfi.phases, self.sel)):
- nranks = len(phase.cs_n)
+ nranks = len(phase.cs)
rankbits = log2_int(nranks)
- if hasattr(phase, "reset_n"):
- m.d.comb += phase.reset_n.eq(1)
+ if hasattr(phase, "reset"):
+ m.d.comb += phase.reset.eq(0)
m.d.comb += phase.clk_en.eq(Repl(Signal(reset=1), nranks))
if hasattr(phase, "odt"):
# FIXME: add dynamic drive for multi-rank (will be needed for high frequencies)
(Array(cmd.ba[-rankbits:] for cmd in commands)[sel]))
if i == 0: # Select all ranks on refresh.
with m.If(sel == STEER_REFRESH):
- m.d.sync += phase.cs_n.eq(0)
+ m.d.sync += phase.cs.eq(1)
with m.Else():
- m.d.sync += phase.cs_n.eq(~rank_decoder.o)
+ m.d.sync += phase.cs.eq(rank_decoder.o)
else:
- m.d.sync += phase.cs_n.eq(~rank_decoder.o)
+ m.d.sync += phase.cs.eq(rank_decoder.o)
m.d.sync += phase.bank.eq(Array(cmd.ba[:-rankbits]
for cmd in commands)[sel])
else:
m.d.sync += [
- phase.cs_n.eq(0),
+ phase.cs.eq(1),
phase.bank.eq(Array(cmd.ba[:] for cmd in commands)[sel]),
]
m.d.sync += [
phase.address.eq(Array(cmd.a for cmd in commands)[sel]),
- phase.cas_n.eq(~Array(valid_and(cmd, "cas")
- for cmd in commands)[sel]),
- phase.ras_n.eq(~Array(valid_and(cmd, "ras")
- for cmd in commands)[sel]),
- phase.we_n.eq(~Array(valid_and(cmd, "we")
- for cmd in commands)[sel])
+ phase.cas.eq(Array(valid_and(cmd, "cas") for cmd in commands)[sel]),
+ phase.ras.eq(Array(valid_and(cmd, "ras") for cmd in commands)[sel]),
+ phase.we.eq(Array(valid_and(cmd, "we") for cmd in commands)[sel])
]
rddata_ens = Array(valid_and(cmd, "is_read") for cmd in commands)
return m
-# Multiplexer --------------------------------------------------------------------------------------
+class _AntiStarvation(Elaboratable):
+ def __init__(self, timeout):
+ self.en = Signal()
+ self.max_time = Signal(reset=1)
+ self._timeout = timeout
+ def elaborate(self, platform):
+ m = Module()
+
+ # TODO: timeout=1 fails formal checks
+ assert self._timeout != 1
+
+ if self._timeout > 0:
+ time = Signal(range(self._timeout))
+ with m.If(~self.en):
+ m.d.sync += [
+ time.eq(self._timeout-1),
+ self.max_time.eq(0),
+ ]
+ with m.Elif(time != 0):
+ m.d.sync += time.eq(time-1)
+ with m.If(time == 1):
+ m.d.sync += self.max_time.eq(1)
+ with m.Else():
+ m.d.sync += self.max_time.eq(0)
+ else:
+ m.d.comb += self.max_time.eq(0)
+
+ if platform == "formal" and self._timeout > 0:
+ m.d.comb += Assert(self.max_time == (time == 0))
+
+ return m
class Multiplexer(Elaboratable):
"""Multplexes requets from BankMachines to DFI
log2_int(len(bank_machines))))
# nop must be 1st
commands = [nop, choose_cmd.cmd, choose_req.cmd, refresher.cmd]
- steerer = _Steerer(commands, dfi)
- m.submodules += steerer
+ m.submodules.steerer = steerer = _Steerer(commands, dfi)
# tRRD timing (Row to Row delay) -----------------------------------------------------------
m.submodules.trrdcon = trrdcon = tXXDController(settings.timing.tRRD)
]
# Anti Starvation --------------------------------------------------------------------------
-
- def anti_starvation(timeout):
- en = Signal()
- max_time = Signal()
- if timeout:
- t = timeout - 1
- time = Signal(range(t+1))
- m.d.comb += max_time.eq(time == 0)
- 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
-
- read_time_en, max_read_time = anti_starvation(settings.read_time)
- write_time_en, max_write_time = anti_starvation(settings.write_time)
+ m.submodules.read_antistarvation = read_antistarvation = _AntiStarvation(settings.read_time)
+ m.submodules.write_antistarvation = write_antistarvation = _AntiStarvation(settings.write_time)
# Refresh ----------------------------------------------------------------------------------
- m.d.comb += [bm.refresh_req.eq(refresher.cmd.valid)
- for bm in bank_machines]
+ m.d.comb += [bm.refresh_req.eq(refresher.cmd.valid) for bm in bank_machines]
go_to_refresh = Signal()
bm_refresh_gnts = [bm.refresh_gnt for bm in bank_machines]
m.d.comb += go_to_refresh.eq(reduce(and_, bm_refresh_gnts))
with m.FSM():
with m.State("Read"):
m.d.comb += [
- read_time_en.eq(1),
+ read_antistarvation.en.eq(1),
choose_req.want_reads.eq(1),
steerer_sel(steerer, "read"),
]
with m.If(write_available):
# TODO: switch only after several cycles of ~read_available?
- with m.If(~read_available | max_read_time):
+ with m.If(~read_available | read_antistarvation.max_time):
m.next = "RTW"
with m.If(go_to_refresh):
with m.State("Write"):
m.d.comb += [
- write_time_en.eq(1),
+ write_antistarvation.en.eq(1),
choose_req.want_writes.eq(1),
steerer_sel(steerer, "write"),
]
]
with m.If(read_available):
- with m.If(~write_available | max_write_time):
+ with m.If(~write_available | write_antistarvation.max_time):
m.next = "WTR"
with m.If(go_to_refresh):