only use positive logic in the controller(cas/ras/we) and use Record/stream.Endpoint for command requests
This commit is contained in:
parent
cbe9748fa1
commit
fb98d12241
|
@ -84,20 +84,18 @@ class UserInterface(Record):
|
|||
Record.__init__(self, layout)
|
||||
|
||||
|
||||
class CommandRequest:
|
||||
def __init__(self, a, ba):
|
||||
self.a = Signal(a)
|
||||
self.ba = Signal(ba)
|
||||
self.cas_n = Signal(reset=1)
|
||||
self.ras_n = Signal(reset=1)
|
||||
self.we_n = Signal(reset=1)
|
||||
def cmd_request_layout(a, ba):
|
||||
return [
|
||||
("a", a),
|
||||
("ba", ba),
|
||||
("cas", 1),
|
||||
("ras", 1),
|
||||
("we", 1)
|
||||
]
|
||||
|
||||
|
||||
class CommandRequestRW(CommandRequest):
|
||||
def __init__(self, a, ba):
|
||||
CommandRequest.__init__(self, a, ba)
|
||||
self.valid = Signal()
|
||||
self.ready = Signal()
|
||||
self.is_cmd = Signal()
|
||||
self.is_read = Signal()
|
||||
self.is_write = Signal()
|
||||
def cmd_request_rw_layout(a, ba):
|
||||
return cmd_request_layout(a, ba) + [
|
||||
("is_cmd", 1),
|
||||
("is_read", 1),
|
||||
("is_write", 1)
|
||||
]
|
||||
|
|
|
@ -32,7 +32,8 @@ class BankMachine(Module):
|
|||
self.req = req = Record(cmd_layout(aw))
|
||||
self.refresh_req = Signal()
|
||||
self.refresh_gnt = Signal()
|
||||
self.cmd = CommandRequestRW(geom_settings.addressbits, geom_settings.bankbits)
|
||||
self.cmd = cmd = stream.Endpoint(cmd_request_rw_layout(geom_settings.addressbits,
|
||||
geom_settings.bankbits))
|
||||
|
||||
# # #
|
||||
|
||||
|
@ -68,19 +69,19 @@ class BankMachine(Module):
|
|||
# Address generation
|
||||
s_row_adr = Signal()
|
||||
self.comb += [
|
||||
self.cmd.ba.eq(n),
|
||||
cmd.ba.eq(n),
|
||||
If(s_row_adr,
|
||||
self.cmd.a.eq(slicer.row(fifo.source.adr))
|
||||
cmd.a.eq(slicer.row(fifo.source.adr))
|
||||
).Else(
|
||||
self.cmd.a.eq(slicer.col(fifo.source.adr))
|
||||
cmd.a.eq(slicer.col(fifo.source.adr))
|
||||
)
|
||||
]
|
||||
|
||||
# Respect write-to-precharge specification
|
||||
self.submodules.precharge_timer = WaitTimer(2 + timing_settings.tWR - 1 + 1)
|
||||
self.comb += self.precharge_timer.wait.eq(~(self.cmd.valid &
|
||||
self.cmd.ready &
|
||||
self.cmd.is_write))
|
||||
self.comb += self.precharge_timer.wait.eq(~(cmd.valid &
|
||||
cmd.ready &
|
||||
cmd.is_write))
|
||||
|
||||
# Control and command generation FSM
|
||||
self.submodules.fsm = fsm = FSM()
|
||||
|
@ -91,16 +92,16 @@ class BankMachine(Module):
|
|||
If(has_openrow,
|
||||
If(hit,
|
||||
# NB: write-to-read specification is enforced by multiplexer
|
||||
self.cmd.valid.eq(1),
|
||||
cmd.valid.eq(1),
|
||||
If(fifo.source.we,
|
||||
req.dat_w_ack.eq(self.cmd.ready),
|
||||
self.cmd.is_write.eq(1)
|
||||
req.dat_w_ack.eq(cmd.ready),
|
||||
cmd.is_write.eq(1),
|
||||
cmd.we.eq(1),
|
||||
).Else(
|
||||
req.dat_r_ack.eq(self.cmd.ready),
|
||||
self.cmd.is_read.eq(1)
|
||||
req.dat_r_ack.eq(cmd.ready),
|
||||
cmd.is_read.eq(1)
|
||||
),
|
||||
self.cmd.cas_n.eq(0),
|
||||
self.cmd.we_n.eq(~fifo.source.we)
|
||||
cmd.cas.eq(1)
|
||||
).Else(
|
||||
NextState("PRECHARGE")
|
||||
)
|
||||
|
@ -115,31 +116,31 @@ class BankMachine(Module):
|
|||
# 2. since we always go to the ACTIVATE state, we do not need
|
||||
# to assert track_close.
|
||||
If(self.precharge_timer.done,
|
||||
self.cmd.valid.eq(1),
|
||||
If(self.cmd.ready,
|
||||
cmd.valid.eq(1),
|
||||
If(cmd.ready,
|
||||
NextState("TRP")
|
||||
),
|
||||
self.cmd.ras_n.eq(0),
|
||||
self.cmd.we_n.eq(0),
|
||||
self.cmd.is_cmd.eq(1)
|
||||
cmd.ras.eq(1),
|
||||
cmd.we.eq(1),
|
||||
cmd.is_cmd.eq(1)
|
||||
)
|
||||
)
|
||||
fsm.act("ACTIVATE",
|
||||
s_row_adr.eq(1),
|
||||
track_open.eq(1),
|
||||
self.cmd.valid.eq(1),
|
||||
self.cmd.is_cmd.eq(1),
|
||||
If(self.cmd.ready,
|
||||
cmd.valid.eq(1),
|
||||
cmd.is_cmd.eq(1),
|
||||
If(cmd.ready,
|
||||
NextState("TRCD")
|
||||
),
|
||||
self.cmd.ras_n.eq(0)
|
||||
cmd.ras.eq(1)
|
||||
)
|
||||
fsm.act("REFRESH",
|
||||
If(self.precharge_timer.done,
|
||||
self.refresh_gnt.eq(1),
|
||||
),
|
||||
track_close.eq(1),
|
||||
self.cmd.is_cmd.eq(1),
|
||||
cmd.is_cmd.eq(1),
|
||||
If(~self.refresh_req,
|
||||
NextState("REGULAR")
|
||||
)
|
||||
|
|
|
@ -4,6 +4,7 @@ from operator import or_, and_
|
|||
from litex.gen import *
|
||||
from litex.gen.genlib.roundrobin import *
|
||||
|
||||
from litex.soc.interconnect import stream
|
||||
from litex.soc.interconnect.csr import AutoCSR
|
||||
|
||||
from litedram.common import *
|
||||
|
@ -15,8 +16,9 @@ class _CommandChooser(Module):
|
|||
self.want_reads = Signal()
|
||||
self.want_writes = Signal()
|
||||
self.want_cmds = Signal()
|
||||
# NB: cas_n/ras_n/we_n are 1 when valid is inactive
|
||||
self.cmd = CommandRequestRW(len(requests[0].a), len(requests[0].ba))
|
||||
# NB: cas/ras/we are 0 when valid is inactive
|
||||
self.cmd = cmd = stream.Endpoint(cmd_request_rw_layout(len(requests[0].a),
|
||||
len(requests[0].ba)))
|
||||
|
||||
# # #
|
||||
|
||||
|
@ -32,18 +34,18 @@ class _CommandChooser(Module):
|
|||
self.comb += valid.eq(Array(req.valid for req in requests)[rr.grant])
|
||||
for name in ["a", "ba", "is_read", "is_write", "is_cmd"]:
|
||||
choices = Array(getattr(req, name) for req in requests)
|
||||
self.comb += getattr(self.cmd, name).eq(choices[rr.grant])
|
||||
for name in ["cas_n", "ras_n", "we_n"]:
|
||||
self.comb += getattr(cmd, name).eq(choices[rr.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 requests)
|
||||
self.comb += If(self.cmd.valid, getattr(self.cmd, name).eq(choices[rr.grant]))
|
||||
self.comb += self.cmd.valid.eq(valid \
|
||||
& ((self.cmd.is_cmd & self.want_cmds) | ((self.cmd.is_read == self.want_reads) \
|
||||
& (self.cmd.is_write == self.want_writes))))
|
||||
self.comb += If(cmd.valid, getattr(cmd, name).eq(choices[rr.grant]))
|
||||
self.comb += cmd.valid.eq(valid \
|
||||
& ((cmd.is_cmd & self.want_cmds) | ((cmd.is_read == self.want_reads) \
|
||||
& (cmd.is_write == self.want_writes))))
|
||||
|
||||
self.comb += [If(self.cmd.valid & self.cmd.ready & (rr.grant == i), req.ready.eq(1))
|
||||
self.comb += [If(cmd.valid & cmd.ready & (rr.grant == i), req.ready.eq(1))
|
||||
for i, req in enumerate(requests)]
|
||||
self.comb += rr.ce.eq(self.cmd.ready)
|
||||
self.comb += rr.ce.eq(cmd.ready)
|
||||
|
||||
|
||||
class _Steerer(Module):
|
||||
|
@ -52,7 +54,7 @@ class _Steerer(Module):
|
|||
nph = len(dfi.phases)
|
||||
self.sel = [Signal(max=ncmd) for i in range(nph)]
|
||||
|
||||
###
|
||||
# # #
|
||||
|
||||
def valid_and(cmd, attr):
|
||||
if not hasattr(cmd, "valid"):
|
||||
|
@ -71,9 +73,9 @@ class _Steerer(Module):
|
|||
self.sync += [
|
||||
phase.address.eq(Array(cmd.a for cmd in commands)[sel]),
|
||||
phase.bank.eq(Array(cmd.ba for cmd in commands)[sel]),
|
||||
phase.cas_n.eq(Array(cmd.cas_n for cmd in commands)[sel]),
|
||||
phase.ras_n.eq(Array(cmd.ras_n for cmd in commands)[sel]),
|
||||
phase.we_n.eq(Array(cmd.we_n for cmd in commands)[sel]),
|
||||
phase.cas_n.eq(~Array(cmd.cas for cmd in commands)[sel]),
|
||||
phase.ras_n.eq(~Array(cmd.ras for cmd in commands)[sel]),
|
||||
phase.we_n.eq(~Array(cmd.we for cmd in commands)[sel]),
|
||||
phase.rddata_en.eq(Array(valid_and(cmd, "is_read") for cmd in commands)[sel]),
|
||||
phase.wrdata_en.eq(Array(valid_and(cmd, "is_write") for cmd in commands)[sel])
|
||||
]
|
||||
|
@ -100,7 +102,7 @@ class Multiplexer(Module, AutoCSR):
|
|||
]
|
||||
|
||||
# Command steering
|
||||
nop = CommandRequest(geom_settings.addressbits, geom_settings.bankbits)
|
||||
nop = Record(cmd_request_layout(geom_settings.addressbits, geom_settings.bankbits))
|
||||
commands = [nop, choose_cmd.cmd, choose_req.cmd, refresher.cmd] # nop must be 1st
|
||||
(STEER_NOP, STEER_CMD, STEER_REQ, STEER_REFRESH) = range(4)
|
||||
steerer = _Steerer(commands, dfi)
|
||||
|
|
|
@ -8,7 +8,7 @@ class Refresher(Module):
|
|||
def __init__(self, a, ba, tRP, tREFI, tRFC, enable):
|
||||
self.req = Signal()
|
||||
self.ack = Signal() # 1st command 1 cycle after assertion of ack
|
||||
self.cmd = cmd = CommandRequest(a, ba)
|
||||
self.cmd = cmd = Record(cmd_request_layout(a, ba))
|
||||
|
||||
# # #
|
||||
|
||||
|
@ -19,19 +19,19 @@ class Refresher(Module):
|
|||
self.sync += [
|
||||
cmd.a.eq(2**10),
|
||||
cmd.ba.eq(0),
|
||||
cmd.cas_n.eq(1),
|
||||
cmd.ras_n.eq(1),
|
||||
cmd.we_n.eq(1),
|
||||
cmd.cas.eq(0),
|
||||
cmd.ras.eq(0),
|
||||
cmd.we.eq(0),
|
||||
seq_done.eq(0)
|
||||
]
|
||||
self.sync += timeline(seq_start, [
|
||||
(1, [
|
||||
cmd.ras_n.eq(0),
|
||||
cmd.we_n.eq(0)
|
||||
cmd.ras.eq(1),
|
||||
cmd.we.eq(1)
|
||||
]),
|
||||
(1+tRP, [
|
||||
cmd.cas_n.eq(0),
|
||||
cmd.ras_n.eq(0)
|
||||
cmd.cas.eq(1),
|
||||
cmd.ras.eq(1)
|
||||
]),
|
||||
(1+tRP+tRFC, [
|
||||
seq_done.eq(1)
|
||||
|
|
|
@ -13,7 +13,7 @@ class PhaseInjector(Module, AutoCSR):
|
|||
self._wrdata = CSRStorage(len(phase.wrdata))
|
||||
self._rddata = CSRStatus(len(phase.rddata))
|
||||
|
||||
###
|
||||
# # #
|
||||
|
||||
self.comb += [
|
||||
If(self._command_issue.re,
|
||||
|
@ -48,7 +48,7 @@ class DFIInjector(Module, AutoCSR):
|
|||
for n, phase in enumerate(inti.phases):
|
||||
setattr(self.submodules, "pi" + str(n), PhaseInjector(phase))
|
||||
|
||||
###
|
||||
# # #
|
||||
|
||||
self.comb += If(self._control.storage[0],
|
||||
self.slave.connect(self.master)
|
||||
|
|
|
@ -50,7 +50,7 @@ class GENSDRPHY(Module):
|
|||
|
||||
self.dfi = Interface(addressbits, bankbits, databits)
|
||||
|
||||
###
|
||||
# # #
|
||||
|
||||
#
|
||||
# Command/address
|
||||
|
|
|
@ -43,7 +43,7 @@ class K7DDRPHY(Module, AutoCSR):
|
|||
|
||||
self.dfi = Interface(addressbits, bankbits, 2*databits, nphases)
|
||||
|
||||
###
|
||||
# # #
|
||||
|
||||
# Clock
|
||||
sd_clk_se = Signal()
|
||||
|
|
|
@ -68,7 +68,7 @@ class S6HalfRateDDRPHY(Module):
|
|||
self.clk4x_wr_strb = Signal()
|
||||
self.clk4x_rd_strb = Signal()
|
||||
|
||||
###
|
||||
# # #
|
||||
|
||||
# sys_clk : system clk, used for dfi interface
|
||||
# sdram_half_clk : half rate sdram clk
|
||||
|
|
Loading…
Reference in New Issue