_lock = Signal()
delay = Signal()
m.submodules += Instance("DDRDLLA",
- i_CLK=ClockSignal("sync2x"),
- i_RST=ResetSignal("init"),
- i_UDDCNTLN=~update,
- i_FREEZE=freeze,
- o_DDRDEL=delay,
- o_LOCK=_lock
- )
+ i_CLK=ClockSignal("sync2x"),
+ i_RST=ResetSignal("init"),
+ i_UDDCNTLN=~update,
+ i_FREEZE=freeze,
+ o_DDRDEL=delay,
+ o_LOCK=_lock)
lock = Signal()
lock_d = Signal()
m.submodules += FFSynchronizer(_lock, lock, o_domain="init")
# CSR
bank = self.csr_bank()
- self._dly_sel = bank.csr(databits//8, "rw")
+ self.burstdet = bank.csr(databits//8, "rw")
- self._rdly_dq_rst = bank.csr(1, "rw")
- self._rdly_dq_inc = bank.csr(1, "rw")
- self._rdly_dq_bitslip_rst = bank.csr(1, "rw")
- self._rdly_dq_bitslip = bank.csr(1, "rw")
-
- self._burstdet_clr = bank.csr(1, "rw")
- self._burstdet_seen = bank.csr(databits//8, "r")
+ self.rdly = []
+ self.rdly += [bank.csr(3, "rw", name="rdly_p0")]
+ self.rdly += [bank.csr(3, "rw", name="rdly_p1")]
self._bridge = self.bridge(data_width=32, granularity=8, alignment=2)
self.bus = self._bridge.bus
self.dfi = Interface(addressbits, bankbits, nranks, 4*databits, 4)
# PHY settings -----------------------------------------------------------------------------
- tck = 2/(2*2*self._sys_clk_freq)
+ tck = 1/(2*self._sys_clk_freq)
nphases = 2
databits = len(self.pads.dq.io)
nranks = 1 if not hasattr(self.pads, "cs") else len(self.pads.cs.o0)
m.submodules.bridge = self._bridge
- tck = 2/(2*2*self._sys_clk_freq)
+ tck = 1/(2*self._sys_clk_freq)
nphases = 2
databits = len(self.pads.dq.io)
+ burstdet_reg = Signal(databits//8)
+ m.d.comb += self.burstdet.r_data.eq(burstdet_reg)
+
+ # Burstdet clear
+ with m.If(self.burstdet.w_stb):
+ m.d.sync += burstdet_reg.eq(0)
+
# Init -------------------------------------------------------------------------------------
m.submodules.init = init = ECP5DDRPHYInit()
self.pads.ba.o3[i].eq(dfi.phases[1].bank[i]),
]
+ # Control pins
controls = ["ras", "cas", "we", "clk_en", "odt"]
if hasattr(self.pads, "reset"):
controls.append("reset")
# DQ ---------------------------------------------------------------------------------------
dq_oe = Signal()
+ dqs_re = Signal()
dqs_oe = Signal()
dqs_postamble = Signal()
dqs_preamble = Signal()
dqsw = Signal()
rdpntr = Signal(3)
wrpntr = Signal(3)
- rdly = Signal(7)
burstdet = Signal()
m.submodules += Instance("DQSBUFM",
- p_DQS_LI_DEL_ADJ="MINUS",
- p_DQS_LI_DEL_VAL=1,
- p_DQS_LO_DEL_ADJ="MINUS",
- p_DQS_LO_DEL_VAL=4,
-
- # Delay
- i_DYNDELAY0=0,
- i_DYNDELAY1=0,
- i_DYNDELAY2=0,
- i_DYNDELAY3=0,
- i_DYNDELAY4=0,
- i_DYNDELAY5=0,
- i_DYNDELAY6=0,
- i_DYNDELAY7=0,
-
- # Clocks / Reset
- i_SCLK=ClockSignal("sync"),
- i_ECLK=ClockSignal("sync2x"),
- i_RST=ResetSignal("dramsync"),
- i_DDRDEL=init.delay,
- i_PAUSE=init.pause | self._dly_sel.w_data[i],
-
- # Control
- # Assert LOADNs to use DDRDEL control
- i_RDLOADN=0,
- i_RDMOVE=0,
- i_RDDIRECTION=1,
- i_WRLOADN=0,
- i_WRMOVE=0,
- i_WRDIRECTION=1,
-
- # Reads (generate shifted DQS clock for reads)
- i_READ0=1,
- i_READ1=1,
- i_READCLKSEL0=rdly[0],
- i_READCLKSEL1=rdly[1],
- i_READCLKSEL2=rdly[2],
- i_DQSI=dqs_i,
- o_DQSR90=dqsr90,
- o_RDPNTR0=rdpntr[0],
- o_RDPNTR1=rdpntr[1],
- o_RDPNTR2=rdpntr[2],
- o_WRPNTR0=wrpntr[0],
- o_WRPNTR1=wrpntr[1],
- o_WRPNTR2=wrpntr[2],
- o_DATAVALID=self.datavalid[i],
- o_BURSTDET=burstdet,
-
- # Writes (generate shifted ECLK clock for writes)
- o_DQSW270=dqsw270,
- o_DQSW=dqsw)
- burstdet_d = Signal()
- m.d.sync += burstdet_d.eq(burstdet)
- with m.If(self._burstdet_clr.w_stb):
- m.d.sync += self._burstdet_seen.r_data[i].eq(0)
- with m.If(burstdet & ~burstdet_d):
- m.d.sync += self._burstdet_seen.r_data[i].eq(1)
+ p_DQS_LI_DEL_ADJ="MINUS",
+ p_DQS_LI_DEL_VAL=1,
+ p_DQS_LO_DEL_ADJ="MINUS",
+ p_DQS_LO_DEL_VAL=4,
+
+ # Delay
+ i_DYNDELAY0=0,
+ i_DYNDELAY1=0,
+ i_DYNDELAY2=0,
+ i_DYNDELAY3=0,
+ i_DYNDELAY4=0,
+ i_DYNDELAY5=0,
+ i_DYNDELAY6=0,
+ i_DYNDELAY7=0,
+
+ # Clocks / Reset
+ i_SCLK=ClockSignal("sync"),
+ i_ECLK=ClockSignal("sync2x"),
+ i_RST=ResetSignal("dramsync"),
+ i_DDRDEL=init.delay,
+ i_PAUSE=init.pause | self.rdly[i].w_stb,
+
+ # Control
+ # Assert LOADNs to use DDRDEL control
+ i_RDLOADN=0,
+ i_RDMOVE=0,
+ i_RDDIRECTION=1,
+ i_WRLOADN=0,
+ i_WRMOVE=0,
+ i_WRDIRECTION=1,
+
+ # Reads (generate shifted DQS clock for reads)
+ i_READ0=dqs_re,
+ i_READ1=dqs_re,
+ i_READCLKSEL0=self.rdly[i].w_data[0],
+ i_READCLKSEL1=self.rdly[i].w_data[1],
+ i_READCLKSEL2=self.rdly[i].w_data[2],
+ i_DQSI=dqs_i,
+ o_DQSR90=dqsr90,
+ o_RDPNTR0=rdpntr[0],
+ o_RDPNTR1=rdpntr[1],
+ o_RDPNTR2=rdpntr[2],
+ o_WRPNTR0=wrpntr[0],
+ o_WRPNTR1=wrpntr[1],
+ o_WRPNTR2=wrpntr[2],
+ o_DATAVALID=self.datavalid[i],
+ o_BURSTDET=burstdet,
+
+ # Writes (generate shifted ECLK clock for writes)
+ o_DQSW270=dqsw270,
+ o_DQSW=dqsw)
+
+ with m.If(burstdet):
+ m.d.sync += burstdet_reg[i].eq(1)
# DQS and DM ---------------------------------------------------------------------------
dm_o_data = Signal(8)
with m.Else():
m.d.sync += dm_o_data_muxed.eq(dm_o_data[:4])
- dm_o_data_muxed_d = Signal(4)
- m.d.sync += dm_o_data_muxed_d.eq(dm_o_data_muxed)
-
m.submodules += Instance("ODDRX2DQA",
i_RST=ResetSignal("dramsync"),
i_ECLK=ClockSignal("sync2x"),
i_SCLK=ClockSignal("dramsync"),
i_DQSW270=dqsw270,
- i_D2=dm_o_data_muxed[0],
- i_D3=dm_o_data_muxed[1],
- i_D0=dm_o_data_muxed_d[2],
- i_D1=dm_o_data_muxed_d[3],
+ i_D0=dm_o_data_muxed[0],
+ i_D1=dm_o_data_muxed[1],
+ i_D2=dm_o_data_muxed[2],
+ i_D3=dm_o_data_muxed[3],
o_Q=self.pads.dm.o[i])
dqs = Signal()
dqs_oe_n = Signal()
m.submodules += [
Instance("ODDRX2DQSB",
- i_RST=ResetSignal("dramsync"),
- i_ECLK=ClockSignal("sync2x"),
- i_SCLK=ClockSignal(),
- i_DQSW=dqsw,
- i_D0=0,
- i_D1=1,
- i_D2=0,
- i_D3=1,
- o_Q=dqs
- ),
+ i_RST=ResetSignal("dramsync"),
+ i_ECLK=ClockSignal("sync2x"),
+ i_SCLK=ClockSignal(),
+ i_DQSW=dqsw,
+ i_D0=0,
+ i_D1=1,
+ i_D2=0,
+ i_D3=1,
+ o_Q=dqs),
Instance("TSHX2DQSA",
- i_RST=ResetSignal("dramsync"),
- i_ECLK=ClockSignal("sync2x"),
- i_SCLK=ClockSignal(),
- i_DQSW=dqsw,
- i_T0=~(dqs_oe | dqs_postamble),
- i_T1=~(dqs_oe | dqs_postamble),
- o_Q=dqs_oe_n
- ),
+ i_RST=ResetSignal("dramsync"),
+ i_ECLK=ClockSignal("sync2x"),
+ i_SCLK=ClockSignal(),
+ i_DQSW=dqsw,
+ i_T0=~(dqs_oe | dqs_postamble),
+ i_T1=~(dqs_oe | dqs_preamble),
+ o_Q=dqs_oe_n),
Instance("BB",
i_I=dqs,
i_T=dqs_oe_n,
o_O=dqs_i,
- io_B=self.pads.dqs.io[i]
- )
+ io_B=self.pads.dqs.io[i]),
]
for j in range(8*i, 8*(i+1)):
)
m.d.sync += dq_o_data_d.eq(dq_o_data)
- with m.Switch(bl8_chunk):
- with m.Case(0):
- m.d.sync += dq_o_data_muxed.eq(dq_o_data[:4])
- with m.Case(1):
- m.d.sync += dq_o_data_muxed.eq(dq_o_data_d[4:])
-
- dq_o_data_muxed_d = Signal.like(dq_o_data_muxed)
- m.d.sync += dq_o_data_muxed_d.eq(dq_o_data_muxed)
+ with m.If(bl8_chunk):
+ m.d.sync += dq_o_data_muxed.eq(dq_o_data_d[4:])
+ with m.Else():
+ m.d.sync += dq_o_data_muxed.eq(dq_o_data[:4])
m.submodules += [
Instance("ODDRX2DQA",
- i_RST=ResetSignal("dramsync"),
- i_ECLK=ClockSignal("sync2x"),
- i_SCLK=ClockSignal(),
- i_DQSW270=dqsw270,
- i_D0=dq_o_data_muxed_d[2],
- i_D1=dq_o_data_muxed_d[3],
- i_D2=dq_o_data_muxed[0],
- i_D3=dq_o_data_muxed[1],
- o_Q=dq_o
- ),
+ i_RST=ResetSignal("dramsync"),
+ i_ECLK=ClockSignal("sync2x"),
+ i_SCLK=ClockSignal(),
+ i_DQSW270=dqsw270,
+ i_D0=dq_o_data_muxed[0],
+ i_D1=dq_o_data_muxed[1],
+ i_D2=dq_o_data_muxed[2],
+ i_D3=dq_o_data_muxed[3],
+ o_Q=dq_o),
Instance("DELAYF",
- p_DEL_MODE="DQS_ALIGNED_X2",
- i_LOADN=1,
- i_MOVE=0,
- i_DIRECTION=0,
- i_A=dq_i,
- o_Z=dq_i_delayed
- ),
+ p_DEL_MODE="DQS_ALIGNED_X2",
+ i_LOADN=1,
+ i_MOVE=0,
+ i_DIRECTION=0,
+ i_A=dq_i,
+ o_Z=dq_i_delayed),
Instance("IDDRX2DQA",
- i_RST=ResetSignal("dramsync"),
- i_ECLK=ClockSignal("sync2x"),
- i_SCLK=ClockSignal(),
- i_DQSR90=dqsr90,
- i_RDPNTR0=rdpntr[0],
- i_RDPNTR1=rdpntr[1],
- i_RDPNTR2=rdpntr[2],
- i_WRPNTR0=wrpntr[0],
- i_WRPNTR1=wrpntr[1],
- i_WRPNTR2=wrpntr[2],
- i_D=dq_i_delayed,
- o_Q0=dq_i_data[0],
- o_Q1=dq_i_data[1],
- o_Q2=dq_i_data[2],
- o_Q3=dq_i_data[3],
- ),
+ i_RST=ResetSignal("dramsync"),
+ i_ECLK=ClockSignal("sync2x"),
+ i_SCLK=ClockSignal(),
+ i_DQSR90=dqsr90,
+ i_RDPNTR0=rdpntr[0],
+ i_RDPNTR1=rdpntr[1],
+ i_RDPNTR2=rdpntr[2],
+ i_WRPNTR0=wrpntr[0],
+ i_WRPNTR1=wrpntr[1],
+ i_WRPNTR2=wrpntr[2],
+ i_D=dq_i_delayed,
+ o_Q0=dq_i_data[0],
+ o_Q1=dq_i_data[1],
+ o_Q2=dq_i_data[2],
+ o_Q3=dq_i_data[3]),
]
m.submodules += [
Instance("TSHX2DQA",
- i_RST=ResetSignal("dramsync"),
- i_ECLK=ClockSignal("sync2x"),
- i_SCLK=ClockSignal(),
- i_DQSW270=dqsw270,
- i_T0=~dq_oe,
- i_T1=~dq_oe,
- o_Q=dq_oe_n,
- ),
+ i_RST=ResetSignal("dramsync"),
+ i_ECLK=ClockSignal("sync2x"),
+ i_SCLK=ClockSignal(),
+ i_DQSW270=dqsw270,
+ i_T0=~dq_oe,
+ i_T1=~dq_oe,
+ o_Q=dq_oe_n),
Instance("BB",
i_I=dq_o,
i_T=dq_oe_n,
o_O=dq_i,
- io_B=self.pads.dq.io[j]
- )
+ io_B=self.pads.dq.io[j])
]
m.d.sync += [
dfi.phases[1].rddata[j].eq(dq_i_data[0]),
m.d.comb += rddata_en.eq(Cat(dfi.phases[self.settings.rdphase].rddata_en, rddata_en_last))
m.d.sync += rddata_en_last.eq(rddata_en)
m.d.sync += [phase.rddata_valid.eq(rddata_en[-1]) for phase in dfi.phases]
+ m.d.comb += dqs_re.eq(rddata_en[cl_sys_latency + 0] | rddata_en[cl_sys_latency + 1] | rddata_en[cl_sys_latency + 2])
# Write Control Path -----------------------------------------------------------------------
# Creates a shift register of write commands coming from the DFI interface. This shift register
# 2x for DDR, 2x for halfrate) but DDR3 requires a burst of 8 datas (BL8) for best efficiency.
# Writes are then performed in 2 sys_clk cycles and data needs to be selected for each cycle.
# FIXME: understand +2
- wrdata_en = Signal(cwl_sys_latency + 5)
+ wrdata_en = Signal(cwl_sys_latency + 4)
wrdata_en_last = Signal.like(wrdata_en)
m.d.comb += wrdata_en.eq(Cat(dfi.phases[self.settings.wrphase].wrdata_en, wrdata_en_last))
m.d.sync += wrdata_en_last.eq(wrdata_en)
m.d.comb += dq_oe.eq(wrdata_en[cwl_sys_latency + 1] | wrdata_en[cwl_sys_latency + 2])
m.d.comb += bl8_chunk.eq(wrdata_en[cwl_sys_latency + 1])
- m.d.comb += dqs_oe.eq(dq_oe | wrdata_en[cwl_sys_latency + 3])
+ m.d.comb += dqs_oe.eq(dq_oe)
# Write DQS Postamble/Preamble Control Path ------------------------------------------------
# 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:
# 1 for Preamble, 2 for the Write and 1 for the Postamble.
m.d.comb += dqs_preamble.eq(wrdata_en[cwl_sys_latency + 0] & ~wrdata_en[cwl_sys_latency + 1])
- m.d.comb += dqs_postamble.eq(wrdata_en[cwl_sys_latency + 4] & ~wrdata_en[cwl_sys_latency + 3])
+ m.d.comb += dqs_postamble.eq(wrdata_en[cwl_sys_latency + 3] & ~wrdata_en[cwl_sys_latency + 2])
return m