diff --git a/litedram/phy/ecp5ddrphy.py b/litedram/phy/ecp5ddrphy.py index 57e63d0..7e78daf 100644 --- a/litedram/phy/ecp5ddrphy.py +++ b/litedram/phy/ecp5ddrphy.py @@ -1,5 +1,5 @@ # This file is Copyright (c) 2019 David Shah -# This file is Copyright (c) 2019 Florent Kermarrec +# This file is Copyright (c) 2019-2020 Florent Kermarrec # License: BSD # 1:2 frequency-ratio DDR3 PHY for Lattice's ECP5 @@ -23,7 +23,7 @@ from litedram.phy.dfi import * class ECP5DDRPHYInit(Module): def __init__(self, eclk_cd): self.pause = Signal() - self.stop = Signal() + self.stop = Signal() self.delay = Signal() # # # @@ -39,14 +39,14 @@ class ECP5DDRPHYInit(Module): _lock = Signal() delay = Signal() self.specials += Instance("DDRDLLA", - i_CLK=ClockSignal("sys2x"), - i_RST=ResetSignal(), - i_UDDCNTLN=~update, - i_FREEZE=freeze, - o_DDRDEL=delay, - o_LOCK=_lock + i_CLK = ClockSignal("sys2x"), + i_RST = ResetSignal(), + i_UDDCNTLN = ~update, + i_FREEZE = freeze, + o_DDRDEL = delay, + o_LOCK = _lock ) - lock = Signal() + lock = Signal() lock_d = Signal() self.specials += MultiReg(_lock, lock) self.sync += lock_d.eq(lock) @@ -82,13 +82,13 @@ class ECP5DDRPHYInit(Module): class ECP5DDRPHY(Module, AutoCSR): def __init__(self, pads, sys_clk_freq=100e6): - memtype = "DDR3" - tck = 2/(2*2*sys_clk_freq) + memtype = "DDR3" + tck = 2/(2*2*sys_clk_freq) addressbits = len(pads.a) - bankbits = len(pads.ba) - nranks = 1 if not hasattr(pads, "cs_n") else len(pads.cs_n) - databits = len(pads.dq) - nphases = 2 + bankbits = len(pads.ba) + nranks = 1 if not hasattr(pads, "cs_n") else len(pads.cs_n) + databits = len(pads.dq) + nphases = 2 assert databits%8 == 0 # Init ------------------------------------------------------------------------------------- @@ -97,20 +97,20 @@ class ECP5DDRPHY(Module, AutoCSR): # Registers -------------------------------------------------------------------------------- self._dly_sel = CSRStorage(databits//8) - self._rdly_dq_rst = CSR() - self._rdly_dq_inc = CSR() + self._rdly_dq_rst = CSR() + self._rdly_dq_inc = CSR() self._rdly_dq_bitslip_rst = CSR() - self._rdly_dq_bitslip = CSR() + self._rdly_dq_bitslip = CSR() - self._burstdet_clr = CSR() + self._burstdet_clr = CSR() self._burstdet_seen = CSRStatus(databits//8) # Observation self.datavalid = Signal(databits//8) # PHY settings ----------------------------------------------------------------------------- - cl, cwl = get_cl_cw(memtype, tck) - cl_sys_latency = get_sys_latency(nphases, cl) + cl, cwl = get_cl_cw(memtype, tck) + cl_sys_latency = get_sys_latency(nphases, cl) cwl_sys_latency = get_sys_latency(nphases, cwl) rdcmdphase, rdphase = get_sys_phases(nphases, cl_sys_latency, cl) @@ -141,44 +141,40 @@ class ECP5DDRPHY(Module, AutoCSR): # Clock ------------------------------------------------------------------------------------ for i in range(len(pads.clk_p)): sd_clk_se = Signal() - self.specials += [ - Instance("ODDRX2F", - i_D0=0, - i_D1=1, - i_D2=0, - i_D3=1, - i_ECLK=ClockSignal("sys2x"), - i_SCLK=ClockSignal(), - i_RST=ResetSignal("sys2x"), - o_Q=pads.clk_p[i] - ), - ] + self.specials += Instance("ODDRX2F", + i_D0 = 0, + i_D1 = 1, + i_D2 = 0, + i_D3 = 1, + i_ECLK = ClockSignal("sys2x"), + i_SCLK = ClockSignal(), + i_RST = ResetSignal("sys2x"), + o_Q = pads.clk_p[i] + ) # Addresses and Commands ------------------------------------------------------------------- for i in range(addressbits): - self.specials += \ - Instance("ODDRX2F", - i_D0=dfi.phases[0].address[i], - i_D1=dfi.phases[0].address[i], - i_D2=dfi.phases[1].address[i], - i_D3=dfi.phases[1].address[i], - i_ECLK=ClockSignal("sys2x"), - i_SCLK=ClockSignal(), - i_RST=ResetSignal("sys2x"), - o_Q=pads.a[i] - ) + self.specials += Instance("ODDRX2F", + i_D0 = dfi.phases[0].address[i], + i_D1 = dfi.phases[0].address[i], + i_D2 = dfi.phases[1].address[i], + i_D3 = dfi.phases[1].address[i], + i_ECLK = ClockSignal("sys2x"), + i_SCLK = ClockSignal(), + i_RST = ResetSignal("sys2x"), + o_Q = pads.a[i] + ) for i in range(bankbits): - self.specials += \ - Instance("ODDRX2F", - i_D0=dfi.phases[0].bank[i], - i_D1=dfi.phases[0].bank[i], - i_D2=dfi.phases[1].bank[i], - i_D3=dfi.phases[1].bank[i], - i_ECLK=ClockSignal("sys2x"), - i_SCLK=ClockSignal(), - i_RST=ResetSignal("sys2x"), - o_Q=pads.ba[i] - ) + self.specials += Instance("ODDRX2F", + i_D0 = dfi.phases[0].bank[i], + i_D1 = dfi.phases[0].bank[i], + i_D2 = dfi.phases[1].bank[i], + i_D3 = dfi.phases[1].bank[i], + i_ECLK = ClockSignal("sys2x"), + i_SCLK = ClockSignal(), + i_RST = ResetSignal("sys2x"), + o_Q = pads.ba[i] + ) controls = ["ras_n", "cas_n", "we_n", "cke", "odt"] if hasattr(pads, "reset_n"): controls.append("reset_n") @@ -186,33 +182,32 @@ class ECP5DDRPHY(Module, AutoCSR): controls.append("cs_n") for name in controls: for i in range(len(getattr(pads, name))): - self.specials += \ - Instance("ODDRX2F", - i_D0=getattr(dfi.phases[0], name)[i], - i_D1=getattr(dfi.phases[0], name)[i], - i_D2=getattr(dfi.phases[1], name)[i], - i_D3=getattr(dfi.phases[1], name)[i], - i_ECLK=ClockSignal("sys2x"), - i_SCLK=ClockSignal(), - i_RST=ResetSignal("sys2x"), - o_Q=getattr(pads, name)[i] + self.specials += Instance("ODDRX2F", + i_D0 = getattr(dfi.phases[0], name)[i], + i_D1 = getattr(dfi.phases[0], name)[i], + i_D2 = getattr(dfi.phases[1], name)[i], + i_D3 = getattr(dfi.phases[1], name)[i], + i_ECLK = ClockSignal("sys2x"), + i_SCLK = ClockSignal(), + i_RST = ResetSignal("sys2x"), + o_Q = getattr(pads, name)[i] ) # DQ --------------------------------------------------------------------------------------- - oe_dq = Signal() - oe_dqs = Signal() + oe_dq = Signal() + oe_dqs = Signal() dqs_postamble = Signal() - dqs_preamble = Signal() - dqs_read = Signal() + dqs_preamble = Signal() + dqs_read = Signal() for i in range(databits//8): # DQSBUFM - dqs_i = Signal() - dqsr90 = Signal() + dqs_i = Signal() + dqsr90 = Signal() dqsw270 = Signal() - dqsw = Signal() - rdpntr = Signal(3) - wrpntr = Signal(3) - rdly = Signal(7) + dqsw = Signal() + rdpntr = Signal(3) + wrpntr = Signal(3) + rdly = Signal(7) self.sync += \ If(self._dly_sel.storage[i], If(self._rdly_dq_rst.re, @@ -222,48 +217,48 @@ class ECP5DDRPHY(Module, AutoCSR): ) ) datavalid = Signal() - burstdet = Signal() + burstdet = Signal() self.specials += 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, + p_DQS_LI_DEL_ADJ = "MINUS", + p_DQS_LI_DEL_VAL = 1, + p_DQS_LO_DEL_ADJ = "MINUS", + p_DQS_LO_DEL_VAL = 4, # Clocks / Reset - i_SCLK=ClockSignal("sys"), - i_ECLK=ClockSignal("sys2x"), - i_RST=ResetSignal("sys2x"), - i_DDRDEL=self.init.delay, - i_PAUSE=self.init.pause | self._dly_sel.storage[i], + i_SCLK = ClockSignal("sys"), + i_ECLK = ClockSignal("sys2x"), + i_RST = ResetSignal("sys2x"), + i_DDRDEL = self.init.delay, + i_PAUSE = self.init.pause | self._dly_sel.storage[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, + 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_read, - i_READ1=dqs_read, - 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, + i_READ0 = dqs_read, + i_READ1 = dqs_read, + 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 + o_DQSW270 = dqsw270, + o_DQSW = dqsw ) burstdet_d = Signal() self.sync += [ @@ -277,9 +272,9 @@ class ECP5DDRPHY(Module, AutoCSR): # DQS and DM --------------------------------------------------------------------------- dqs_serdes_pattern = Signal(8, reset=0b1010) - dm_o_data = Signal(8) - dm_o_data_d = Signal(8) - dm_o_data_muxed = Signal(4) + dm_o_data = Signal(8) + dm_o_data_d = Signal(8) + dm_o_data_muxed = Signal(4) self.comb += dm_o_data.eq(Cat( dfi.phases[0].wrdata_mask[0*databits//8+i], dfi.phases[0].wrdata_mask[1*databits//8+i], dfi.phases[0].wrdata_mask[2*databits//8+i], dfi.phases[0].wrdata_mask[3*databits//8+i], @@ -293,53 +288,52 @@ class ECP5DDRPHY(Module, AutoCSR): ).Else( dm_o_data_muxed.eq(dm_o_data[:4]) ) - self.specials += \ - Instance("ODDRX2DQA", - 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], - i_RST=ResetSignal("sys2x"), - i_DQSW270=dqsw270, - i_ECLK=ClockSignal("sys2x"), - i_SCLK=ClockSignal(), - o_Q=pads.dm[i] - ) + self.specials += Instance("ODDRX2DQA", + 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], + i_RST = ResetSignal("sys2x"), + i_DQSW270 = dqsw270, + i_ECLK = ClockSignal("sys2x"), + i_SCLK = ClockSignal(), + o_Q = pads.dm[i] + ) - dqs = Signal() + dqs = Signal() dqs_oe_n = Signal() - self.specials += \ + self.specials += [ Instance("ODDRX2DQSB", - i_D0=dqs_serdes_pattern[0], - i_D1=dqs_serdes_pattern[1], - i_D2=dqs_serdes_pattern[2], - i_D3=dqs_serdes_pattern[3], - i_RST=ResetSignal("sys2x"), - i_DQSW=dqsw, - i_ECLK=ClockSignal("sys2x"), - i_SCLK=ClockSignal(), - o_Q=dqs - ) - self.specials += \ + i_D0 = dqs_serdes_pattern[0], + i_D1 = dqs_serdes_pattern[1], + i_D2 = dqs_serdes_pattern[2], + i_D3 = dqs_serdes_pattern[3], + i_RST = ResetSignal("sys2x"), + i_DQSW = dqsw, + i_ECLK = ClockSignal("sys2x"), + i_SCLK = ClockSignal(), + o_Q = dqs + ), Instance("TSHX2DQSA", - i_T0=~(oe_dqs|dqs_postamble), - i_T1=~(oe_dqs|dqs_preamble), - i_SCLK=ClockSignal(), - i_ECLK=ClockSignal("sys2x"), - i_DQSW=dqsw, - i_RST=ResetSignal("sys2x"), - o_Q=dqs_oe_n, - ) - self.specials += Tristate(pads.dqs_p[i], dqs, ~dqs_oe_n, dqs_i) + i_T0 = ~(oe_dqs|dqs_postamble), + i_T1 = ~(oe_dqs|dqs_preamble), + i_SCLK = ClockSignal(), + i_ECLK = ClockSignal("sys2x"), + i_DQSW = dqsw, + i_RST = ResetSignal("sys2x"), + o_Q = dqs_oe_n, + ), + Tristate(pads.dqs_p[i], dqs, ~dqs_oe_n, dqs_i) + ] for j in range(8*i, 8*(i+1)): - dq_o = Signal() - dq_i = Signal() - dq_oe_n = Signal() - dq_i_delayed = Signal() - dq_i_data = Signal(4) - dq_o_data = Signal(8) - dq_o_data_d = Signal(8) + dq_o = Signal() + dq_i = Signal() + dq_oe_n = Signal() + dq_i_delayed = Signal() + dq_i_data = Signal(4) + dq_o_data = Signal(8) + dq_o_data_d = Signal(8) dq_o_data_muxed = Signal(4) self.comb += dq_o_data.eq(Cat( dfi.phases[0].wrdata[0*databits+j], dfi.phases[0].wrdata[1*databits+j], @@ -354,45 +348,44 @@ class ECP5DDRPHY(Module, AutoCSR): ).Else( dq_o_data_muxed.eq(dq_o_data[:4]) ) - self.specials += \ + self.specials += [ Instance("ODDRX2DQA", - 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], - i_RST=ResetSignal("sys2x"), - i_DQSW270=dqsw270, - i_ECLK=ClockSignal("sys2x"), - i_SCLK=ClockSignal(), - o_Q=dq_o - ) - self.specials += \ + 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], + i_RST = ResetSignal("sys2x"), + i_DQSW270 = dqsw270, + i_ECLK = ClockSignal("sys2x"), + i_SCLK = ClockSignal(), + o_Q = dq_o + ), Instance("DELAYF", - i_A=dq_i, - i_LOADN=1, - i_MOVE=0, - i_DIRECTION=0, - o_Z=dq_i_delayed, - p_DEL_MODE="DQS_ALIGNED_X2" - ) - self.specials += \ + i_A = dq_i, + i_LOADN = 1, + i_MOVE = 0, + i_DIRECTION = 0, + o_Z = dq_i_delayed, + p_DEL_MODE = "DQS_ALIGNED_X2" + ), Instance("IDDRX2DQA", - i_D=dq_i_delayed, - i_RST=ResetSignal("sys2x"), - i_DQSR90=dqsr90, - i_SCLK=ClockSignal(), - i_ECLK=ClockSignal("sys2x"), - i_RDPNTR0=rdpntr[0], - i_RDPNTR1=rdpntr[1], - i_RDPNTR2=rdpntr[2], - i_WRPNTR0=wrpntr[0], - i_WRPNTR1=wrpntr[1], - i_WRPNTR2=wrpntr[2], - 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_D = dq_i_delayed, + i_RST = ResetSignal("sys2x"), + i_DQSR90 = dqsr90, + i_SCLK = ClockSignal(), + i_ECLK = ClockSignal("sys2x"), + i_RDPNTR0 = rdpntr[0], + i_RDPNTR1 = rdpntr[1], + i_RDPNTR2 = rdpntr[2], + i_WRPNTR0 = wrpntr[0], + i_WRPNTR1 = wrpntr[1], + i_WRPNTR2 = wrpntr[2], + o_Q0 = dq_i_data[0], + o_Q1 = dq_i_data[1], + o_Q2 = dq_i_data[2], + o_Q3 = dq_i_data[3], ) + ] dq_bitslip = BitSlip(4) self.comb += dq_bitslip.i.eq(dq_i_data) self.sync += \ @@ -412,17 +405,18 @@ class ECP5DDRPHY(Module, AutoCSR): dfi.phases[1].rddata[0*databits+j].eq(dq_bitslip.o[0]), dfi.phases[1].rddata[1*databits+j].eq(dq_bitslip.o[1]), dfi.phases[1].rddata[2*databits+j].eq(dq_bitslip.o[2]), dfi.phases[1].rddata[3*databits+j].eq(dq_bitslip.o[3]), ] - self.specials += \ + self.specials += [ Instance("TSHX2DQA", - i_T0=~oe_dq, - i_T1=~oe_dq, - i_SCLK=ClockSignal(), - i_ECLK=ClockSignal("sys2x"), - i_DQSW270=dqsw270, - i_RST=ResetSignal("sys2x"), - o_Q=dq_oe_n, - ) - self.specials += Tristate(pads.dq[j], dq_o, ~dq_oe_n, dq_i) + i_T0 = ~oe_dq, + i_T1 = ~oe_dq, + i_SCLK = ClockSignal(), + i_ECLK = ClockSignal("sys2x"), + i_DQSW270 = dqsw270, + i_RST = ResetSignal("sys2x"), + o_Q = dq_oe_n, + ), + Tristate(pads.dq[j], dq_o, ~dq_oe_n, dq_i) + ] # Flow control ----------------------------------------------------------------------------- # @@ -430,7 +424,7 @@ class ECP5DDRPHY(Module, AutoCSR): # ODDRX2DQA latency # cl_sys_latency # IDDRX2DQA latency - rddata_en = dfi.phases[self.settings.rdphase].rddata_en + rddata_en = dfi.phases[self.settings.rdphase].rddata_en rddata_ens = Array([Signal() for i in range(self.settings.read_latency-1)]) for i in range(self.settings.read_latency-1): n_rddata_en = Signal()