only use positive logic in the controller(cas/ras/we) and use Record/stream.Endpoint for command requests

This commit is contained in:
Florent Kermarrec 2016-05-02 12:18:56 +02:00
parent cbe9748fa1
commit fb98d12241
8 changed files with 69 additions and 68 deletions

View File

@ -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()

View File

@ -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")
) )

View File

@ -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)

View File

@ -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)

View File

@ -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)

View File

@ -50,7 +50,7 @@ class GENSDRPHY(Module):
self.dfi = Interface(addressbits, bankbits, databits) self.dfi = Interface(addressbits, bankbits, databits)
### # # #
# #
# Command/address # Command/address

View File

@ -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()

View File

@ -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