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