phy/ecp5/s7/usddrphy: simplify control path using TappedDelayLine.
This commit is contained in:
parent
d12caf1e0c
commit
e3461704b5
|
@ -362,40 +362,43 @@ class ECP5DDRPHY(Module, AutoCSR):
|
||||||
]
|
]
|
||||||
|
|
||||||
# Read Control Path ------------------------------------------------------------------------
|
# Read Control Path ------------------------------------------------------------------------
|
||||||
# Creates a shift register of read commands coming from the DFI interface. This shift register
|
# Creates a delay line of read commands coming from the DFI interface. The taps are used to
|
||||||
# is used to control DQS read (internal read pulse of the DQSBUF) and to indicate to the
|
# control DQS read (internal read pulse of the DQSBUF) and the output of the delay is used
|
||||||
# DFI interface that the read data is valid.
|
# signal a valid read data to the DFI interface.
|
||||||
#
|
#
|
||||||
# The DQS read must be asserted for 2 sys_clk cycles before the read data is coming back from
|
# The DQS read must be asserted for 2 sys_clk cycles before the read data is coming back from
|
||||||
# the DRAM (see 6.2.4 READ Pulse Positioning Optimization of FPGA-TN-02035-1.2)
|
# the DRAM (see 6.2.4 READ Pulse Positioning Optimization of FPGA-TN-02035-1.2)
|
||||||
#
|
#
|
||||||
# The read data valid is asserted for 1 sys_clk cycle when the data is available on the DFI
|
# The read data valid is asserted for 1 sys_clk cycle when the data is available on the DFI
|
||||||
# interface, the latency is the sum of the ODDRX2DQA, CAS, IDDRX2DQA latencies.
|
# interface, the latency is the sum of the ODDRX2DQA, CAS, IDDRX2DQA latencies.
|
||||||
rddata_en = Signal(self.settings.read_latency)
|
rddata_en = TappedDelayLine(
|
||||||
rddata_en_last = Signal.like(rddata_en)
|
signal = reduce(or_, [dfi.phases[i].rddata_en for i in range(nphases)]),
|
||||||
self.comb += rddata_en.eq(Cat(reduce(or_, [dfi.phases[i].rddata_en for i in range(nphases)]), rddata_en_last))
|
ntaps = self.settings.read_latency
|
||||||
self.sync += rddata_en_last.eq(rddata_en)
|
)
|
||||||
self.sync += [phase.rddata_valid.eq(rddata_en[-1]) for phase in dfi.phases]
|
self.submodules += rddata_en
|
||||||
self.comb += dqs_re.eq(rddata_en[cl_sys_latency + 1] | rddata_en[cl_sys_latency + 2])
|
|
||||||
|
|
||||||
|
self.sync += [phase.rddata_valid.eq(rddata_en.output) for phase in dfi.phases]
|
||||||
|
self.comb += dqs_re.eq(rddata_en.taps[cl_sys_latency + 1] | rddata_en.taps[cl_sys_latency + 2])
|
||||||
|
|
||||||
# Write Control Path -----------------------------------------------------------------------
|
# Write Control Path -----------------------------------------------------------------------
|
||||||
# Creates a shift register of write commands coming from the DFI interface. This shift register
|
# Create a delay line of write commands coming from the DFI interface. This taps are used to
|
||||||
# is used to control DQ/DQS tristates and to select write data of the DRAM burst from the DFI
|
# control DQ/DQS tristates and to select write data of the DRAM burst from the DFI interface.
|
||||||
# interface: The PHY is operating in halfrate mode (so provide 4 datas every sys_clk cycles:
|
# The PHY is operating in halfrate mode (so provide 4 datas every sys_clk cycles: 2x for DDR,
|
||||||
# 2x for DDR, 2x for halfrate) but DDR3 requires a burst of 8 datas (BL8) for best efficiency.
|
# 2x for halfrate) but DDR3 requires a burst of 8 datas (BL8) for best efficiency. Writes are
|
||||||
# Writes are then performed in 2 sys_clk cycles and data needs to be selected for each cycle.
|
# then performed in 2 sys_clk cycles and data needs to be selected for each cycle.
|
||||||
wrdata_en = Signal(cwl_sys_latency + 4)
|
wrdata_en = TappedDelayLine(
|
||||||
wrdata_en_last = Signal.like(wrdata_en)
|
signal = reduce(or_, [dfi.phases[i].wrdata_en for i in range(nphases)]),
|
||||||
self.comb += wrdata_en.eq(Cat(reduce(or_, [dfi.phases[i].wrdata_en for i in range(nphases)]), wrdata_en_last))
|
ntaps = cwl_sys_latency + 4
|
||||||
self.sync += wrdata_en_last.eq(wrdata_en)
|
)
|
||||||
self.comb += dq_oe.eq(wrdata_en[cwl_sys_latency + 1] | wrdata_en[cwl_sys_latency + 2])
|
self.submodules += wrdata_en
|
||||||
self.comb += bl8_chunk.eq(wrdata_en[cwl_sys_latency + 1])
|
|
||||||
|
self.comb += dq_oe.eq(wrdata_en.taps[cwl_sys_latency + 1] | wrdata_en.taps[cwl_sys_latency + 2])
|
||||||
|
self.comb += bl8_chunk.eq(wrdata_en.taps[cwl_sys_latency + 1])
|
||||||
self.comb += dqs_oe.eq(dq_oe)
|
self.comb += dqs_oe.eq(dq_oe)
|
||||||
|
|
||||||
# Write DQS Postamble/Preamble Control Path ------------------------------------------------
|
# Write DQS Postamble/Preamble Control Path ------------------------------------------------
|
||||||
# Generates DQS Preamble 1 cycle before the first write and Postamble 1 cycle after the last
|
# Generates DQS Preamble 1 cycle before the first write and Postamble 1 cycle after the last
|
||||||
# write. During writes, DQS tristate is configured as output for at least 4 sys_clk cycles:
|
# write. During writes, DQS tristate is configured as output for at least 4 sys_clk cycles:
|
||||||
# 1 for Preamble, 2 for the Write and 1 for the Postamble.
|
# 1 for Preamble, 2 for the Write and 1 for the Postamble.
|
||||||
self.comb += dqs_preamble.eq( wrdata_en[cwl_sys_latency + 0] & ~wrdata_en[cwl_sys_latency + 1])
|
self.comb += dqs_preamble.eq( wrdata_en.taps[cwl_sys_latency + 0] & ~wrdata_en.taps[cwl_sys_latency + 1])
|
||||||
self.comb += dqs_postamble.eq(wrdata_en[cwl_sys_latency + 3] & ~wrdata_en[cwl_sys_latency + 2])
|
self.comb += dqs_postamble.eq(wrdata_en.taps[cwl_sys_latency + 3] & ~wrdata_en.taps[cwl_sys_latency + 2])
|
||||||
|
|
|
@ -391,33 +391,39 @@ class S7DDRPHY(Module, AutoCSR):
|
||||||
]
|
]
|
||||||
|
|
||||||
# Read Control Path ------------------------------------------------------------------------
|
# Read Control Path ------------------------------------------------------------------------
|
||||||
# Creates a shift register of read commands coming from the DFI interface. This shift register
|
# Creates a delay line of read commands coming from the DFI interface. The output is used to
|
||||||
# is used to indicate to the DFI interface that the read data is valid.
|
# signal a valid read data to the DFI interface.
|
||||||
#
|
#
|
||||||
# The read data valid is asserted for 1 sys_clk cycle when the data is available on the DFI
|
# The read data valid is asserted for 1 sys_clk cycle when the data is available on the DFI
|
||||||
# interface, the latency is the sum of the OSERDESE2, CAS, ISERDESE2 and Bitslip latencies.
|
# interface, the latency is the sum of the OSERDESE2, CAS, ISERDESE2 and Bitslip latencies.
|
||||||
rddata_en = Signal(self.settings.read_latency)
|
rddata_en = TappedDelayLine(
|
||||||
rddata_en_last = Signal.like(rddata_en)
|
signal = reduce(or_, [dfi.phases[i].rddata_en for i in range(nphases)]),
|
||||||
self.comb += rddata_en.eq(Cat(reduce(or_, [dfi.phases[i].rddata_en for i in range(nphases)]), rddata_en_last))
|
ntaps = self.settings.read_latency
|
||||||
self.sync += rddata_en_last.eq(rddata_en)
|
)
|
||||||
self.sync += [phase.rddata_valid.eq(rddata_en[-1] | self._wlevel_en.storage) for phase in dfi.phases]
|
self.submodules += rddata_en
|
||||||
|
|
||||||
|
self.sync += [phase.rddata_valid.eq(rddata_en.output | self._wlevel_en.storage) for phase in dfi.phases]
|
||||||
|
|
||||||
# Write Control Path -----------------------------------------------------------------------
|
# Write Control Path -----------------------------------------------------------------------
|
||||||
# Creates a shift register of write commands coming from the DFI interface. This shift register
|
dq_latency = cwl_sys_latency
|
||||||
# is used to control DQ/DQS tristates.
|
|
||||||
wrdata_en = Signal(cwl_sys_latency + 2)
|
# Create a delay line of write commands coming from the DFI interface. This taps are used to
|
||||||
wrdata_en_last = Signal.like(wrdata_en)
|
# control DQ/DQS tristates.
|
||||||
self.comb += wrdata_en.eq(Cat(reduce(or_, [dfi.phases[i].wrdata_en for i in range(nphases)]), wrdata_en_last))
|
wrdata_en = TappedDelayLine(
|
||||||
self.sync += wrdata_en_last.eq(wrdata_en)
|
signal = reduce(or_, [dfi.phases[i].wrdata_en for i in range(nphases)]),
|
||||||
self.comb += dq_oe.eq(wrdata_en[cwl_sys_latency])
|
ntaps = dq_latency + 2
|
||||||
|
)
|
||||||
|
self.submodules += wrdata_en
|
||||||
|
|
||||||
|
self.comb += dq_oe.eq(wrdata_en.taps[cwl_sys_latency])
|
||||||
self.comb += If(self._wlevel_en.storage, dqs_oe.eq(1)).Else(dqs_oe.eq(dq_oe))
|
self.comb += If(self._wlevel_en.storage, dqs_oe.eq(1)).Else(dqs_oe.eq(dq_oe))
|
||||||
|
|
||||||
# Write DQS Postamble/Preamble Control Path ------------------------------------------------
|
# Write DQS Postamble/Preamble Control Path ------------------------------------------------
|
||||||
# Generates DQS Preamble 1 cycle before the first write and Postamble 1 cycle after the last
|
# Generates DQS Preamble 1 cycle before the first write and Postamble 1 cycle after the last
|
||||||
# write. During writes, DQS tristate is configured as output for at least 3 sys_clk cycles:
|
# write. During writes, DQS tristate is configured as output for at least 3 sys_clk cycles:
|
||||||
# 1 for Preamble, 1 for the Write and 1 for the Postamble.
|
# 1 for Preamble, 1 for the Write and 1 for the Postamble.
|
||||||
self.comb += dqs_pattern.preamble.eq( wrdata_en[cwl_sys_latency - 1] & ~wrdata_en[cwl_sys_latency])
|
self.comb += dqs_pattern.preamble.eq( wrdata_en.taps[dq_latency - 1] & ~wrdata_en.taps[dq_latency])
|
||||||
self.comb += dqs_pattern.postamble.eq(wrdata_en[cwl_sys_latency + 1] & ~wrdata_en[cwl_sys_latency])
|
self.comb += dqs_pattern.postamble.eq(wrdata_en.taps[dq_latency + 1] & ~wrdata_en.taps[dq_latency])
|
||||||
|
|
||||||
# Xilinx Virtex7 (S7DDRPHY with odelay) ------------------------------------------------------------
|
# Xilinx Virtex7 (S7DDRPHY with odelay) ------------------------------------------------------------
|
||||||
|
|
||||||
|
|
|
@ -425,33 +425,37 @@ class USDDRPHY(Module, AutoCSR):
|
||||||
self.comb += dfi.phases[n//2].rddata[n%2*databits+i].eq(dq_bitslip.o[n])
|
self.comb += dfi.phases[n//2].rddata[n%2*databits+i].eq(dq_bitslip.o[n])
|
||||||
|
|
||||||
# Read Control Path ------------------------------------------------------------------------
|
# Read Control Path ------------------------------------------------------------------------
|
||||||
# Creates a shift register of read commands coming from the DFI interface. This shift register
|
# Creates a delay line of read commands coming from the DFI interface. The output is used to
|
||||||
# is used to indicate to the DFI interface that the read data is valid.
|
# signal a valid read data to the DFI interface.
|
||||||
#
|
#
|
||||||
# The read data valid is asserted for 1 sys_clk cycle when the data is available on the DFI
|
# The read data valid is asserted for 1 sys_clk cycle when the data is available on the DFI
|
||||||
# interface, the latency is the sum of the OSERDESE3, CAS, ISERDESE3 and Bitslip latencies.
|
# interface, the latency is the sum of the OSERDESE3, CAS, ISERDESE3 and Bitslip latencies.
|
||||||
rddata_en = Signal(self.settings.read_latency)
|
rddata_en = TappedDelayLine(
|
||||||
rddata_en_last = Signal.like(rddata_en)
|
signal = reduce(or_, [dfi.phases[i].rddata_en for i in range(nphases)]),
|
||||||
self.comb += rddata_en.eq(Cat(reduce(or_, [dfi.phases[i].rddata_en for i in range(nphases)]), rddata_en_last))
|
ntaps = self.settings.read_latency
|
||||||
self.sync += rddata_en_last.eq(rddata_en)
|
)
|
||||||
self.sync += [phase.rddata_valid.eq(rddata_en[-1] | self._wlevel_en.storage) for phase in dfi.phases]
|
self.submodules += rddata_en
|
||||||
|
|
||||||
|
self.sync += [phase.rddata_valid.eq(rddata_en.output | self._wlevel_en.storage) for phase in dfi.phases]
|
||||||
|
|
||||||
# Write Control Path -----------------------------------------------------------------------
|
# Write Control Path -----------------------------------------------------------------------
|
||||||
# Creates a shift register of write commands coming from the DFI interface. This shift register
|
# Create a delay line of write commands coming from the DFI interface. This taps are used to
|
||||||
# is used to control DQ/DQS tristates.
|
# control DQ/DQS tristates.
|
||||||
wrdata_en = Signal(cwl_sys_latency + 2)
|
wrdata_en = TappedDelayLine(
|
||||||
wrdata_en_last = Signal.like(wrdata_en)
|
signal = reduce(or_, [dfi.phases[i].wrdata_en for i in range(nphases)]),
|
||||||
self.comb += wrdata_en.eq(Cat(reduce(or_, [dfi.phases[i].wrdata_en for i in range(nphases)]), wrdata_en_last))
|
ntaps = cwl_sys_latency + 2
|
||||||
self.sync += wrdata_en_last.eq(wrdata_en)
|
)
|
||||||
self.comb += dq_oe.eq(wrdata_en[cwl_sys_latency])
|
self.submodules += wrdata_en
|
||||||
|
|
||||||
|
self.comb += dq_oe.eq(wrdata_en.taps[cwl_sys_latency])
|
||||||
self.comb += If(self._wlevel_en.storage, dqs_oe.eq(1)).Else(dqs_oe.eq(dq_oe))
|
self.comb += If(self._wlevel_en.storage, dqs_oe.eq(1)).Else(dqs_oe.eq(dq_oe))
|
||||||
|
|
||||||
# Write DQS Postamble/Preamble Control Path ------------------------------------------------
|
# Write DQS Postamble/Preamble Control Path ------------------------------------------------
|
||||||
# Generates DQS Preamble 1 cycle before the first write and Postamble 1 cycle after the last
|
# Generates DQS Preamble 1 cycle before the first write and Postamble 1 cycle after the last
|
||||||
# write. During writes, DQS tristate is configured as output for at least 3 sys_clk cycles:
|
# write. During writes, DQS tristate is configured as output for at least 3 sys_clk cycles:
|
||||||
# 1 for Preamble, 1 for the Write and 1 for the Postamble.
|
# 1 for Preamble, 1 for the Write and 1 for the Postamble.
|
||||||
self.comb += dqs_pattern.preamble.eq( wrdata_en[cwl_sys_latency - 1] & ~wrdata_en[cwl_sys_latency])
|
self.comb += dqs_pattern.preamble.eq( wrdata_en.taps[cwl_sys_latency - 1] & ~wrdata_en.taps[cwl_sys_latency])
|
||||||
self.comb += dqs_pattern.postamble.eq(wrdata_en[cwl_sys_latency + 1] & ~wrdata_en[cwl_sys_latency])
|
self.comb += dqs_pattern.postamble.eq(wrdata_en.taps[cwl_sys_latency + 1] & ~wrdata_en.taps[cwl_sys_latency])
|
||||||
|
|
||||||
# Xilinx Ultrascale Plus DDR3/DDR4 PHY -------------------------------------------------------------
|
# Xilinx Ultrascale Plus DDR3/DDR4 PHY -------------------------------------------------------------
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue