From a2c7ff4c0c88d8c1c1167fed40d558f947fe5f0c Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Fri, 8 Aug 2014 21:28:26 +0800 Subject: [PATCH] sdramphy: initial K7 DDR3 support --- misoclib/sdramphy/k7ddrphy.py | 211 ++++++++++++++++++++++++++++++++++ 1 file changed, 211 insertions(+) create mode 100644 misoclib/sdramphy/k7ddrphy.py diff --git a/misoclib/sdramphy/k7ddrphy.py b/misoclib/sdramphy/k7ddrphy.py new file mode 100644 index 000000000..88063673e --- /dev/null +++ b/misoclib/sdramphy/k7ddrphy.py @@ -0,0 +1,211 @@ +# tCK=5ns CL=8 CWL=6 + +from migen.fhdl.std import * +from migen.bus.dfi import * + +from misoclib import lasmicon + +class K7DDRPHY(Module): + def __init__(self, pads, memtype): + a = flen(pads.a) + ba = flen(pads.ba) + d = flen(pads.dq) + nphases = 4 + + self.phy_settings = lasmicon.PhySettings( + memtype=memtype, + dfi_d=2*d, + nphases=nphases, + rdphase=0, + wrphase=2, + rdcmdphase=1, + wrcmdphase=0, + cl=8, + cwl=6, + read_latency=8, + write_latency=1 + ) + + self.dfi = Interface(a, ba, self.phy_settings.dfi_d, nphases) + + sd_clk_se = Signal() + self.specials += [ + Instance("OSERDESE2", + p_DATA_WIDTH=8, p_TRISTATE_WIDTH=1, + p_DATA_RATE_OQ="DDR", p_DATA_RATE_TQ="SDR", + p_SERDES_MODE="MASTER", + + o_OQ=sd_clk_se, + i_OCE=1, + i_CLK=ClockSignal("sys4x"), i_CLKDIV=ClockSignal(), + i_D1=0, i_D2=1, i_D3=0, i_D4=1, + i_D5=0, i_D6=1, i_D7=0, i_D8=1 + ), + Instance("OBUFDS", + i_I=sd_clk_se, + o_O=pads.clk_p, + o_OB=pads.clk_n + ) + ] + + for i in range(a): + self.specials += \ + Instance("OSERDESE2", + p_DATA_WIDTH=8, p_TRISTATE_WIDTH=1, + p_DATA_RATE_OQ="DDR", p_DATA_RATE_TQ="SDR", + p_SERDES_MODE="MASTER", + + o_OQ=pads.a[i], + i_OCE=1, + i_CLK=ClockSignal("sys4x"), i_CLKDIV=ClockSignal(), + i_D1=self.dfi.phases[0].address[i], i_D2=self.dfi.phases[0].address[i], + i_D3=self.dfi.phases[1].address[i], i_D4=self.dfi.phases[1].address[i], + i_D5=self.dfi.phases[2].address[i], i_D6=self.dfi.phases[2].address[i], + i_D7=self.dfi.phases[3].address[i], i_D8=self.dfi.phases[3].address[i] + ) + for i in range(ba): + self.specials += \ + Instance("OSERDESE2", + p_DATA_WIDTH=8, p_TRISTATE_WIDTH=1, + p_DATA_RATE_OQ="DDR", p_DATA_RATE_TQ="SDR", + p_SERDES_MODE="MASTER", + + o_OQ=pads.ba[i], + i_OCE=1, + i_CLK=ClockSignal("sys4x"), i_CLKDIV=ClockSignal(), + i_D1=self.dfi.phases[0].bank[i], i_D2=self.dfi.phases[0].bank[i], + i_D3=self.dfi.phases[1].bank[i], i_D4=self.dfi.phases[1].bank[i], + i_D5=self.dfi.phases[2].bank[i], i_D6=self.dfi.phases[2].bank[i], + i_D7=self.dfi.phases[3].bank[i], i_D8=self.dfi.phases[3].bank[i] + ) + for name in "ras_n", "cas_n", "we_n", "cs_n", "cke", "odt", "reset_n": + self.specials += \ + Instance("OSERDESE2", + p_DATA_WIDTH=8, p_TRISTATE_WIDTH=1, + p_DATA_RATE_OQ="DDR", p_DATA_RATE_TQ="SDR", + p_SERDES_MODE="MASTER", + + o_OQ=getattr(pads, name), + i_OCE=1, + i_CLK=ClockSignal("sys4x"), i_CLKDIV=ClockSignal(), + i_D1=getattr(self.dfi.phases[0], name), i_D2=getattr(self.dfi.phases[0], name), + i_D3=getattr(self.dfi.phases[1], name), i_D4=getattr(self.dfi.phases[1], name), + i_D5=getattr(self.dfi.phases[2], name), i_D6=getattr(self.dfi.phases[2], name), + i_D7=getattr(self.dfi.phases[3], name), i_D8=getattr(self.dfi.phases[3], name) + ) + + oe = Signal() + for i in range(d//8): + self.specials += \ + Instance("OSERDESE2", + p_DATA_WIDTH=8, p_TRISTATE_WIDTH=1, + p_DATA_RATE_OQ="DDR", p_DATA_RATE_TQ="SDR", + p_SERDES_MODE="MASTER", + + o_OQ=pads.dm[i], + i_OCE=1, + i_CLK=ClockSignal("sys4x"), i_CLKDIV=ClockSignal(), + i_D1=self.dfi.phases[0].wrdata_mask[i], i_D2=self.dfi.phases[0].wrdata_mask[d//8+i], + i_D3=self.dfi.phases[1].wrdata_mask[i], i_D4=self.dfi.phases[1].wrdata_mask[d//8+i], + i_D5=self.dfi.phases[2].wrdata_mask[i], i_D6=self.dfi.phases[2].wrdata_mask[d//8+i], + i_D7=self.dfi.phases[3].wrdata_mask[i], i_D8=self.dfi.phases[3].wrdata_mask[d//8+i] + ) + dqs_nodelay = Signal() + dqs_delayed = Signal() + dqs_t = Signal() + self.specials += [ + Instance("OSERDESE2", + p_DATA_WIDTH=8, p_TRISTATE_WIDTH=1, + p_DATA_RATE_OQ="DDR", p_DATA_RATE_TQ="SDR", + p_SERDES_MODE="MASTER", + + o_OFB=dqs_nodelay, o_TQ=dqs_t, + i_OCE=1, i_TCE=1, + i_CLK=ClockSignal("sys4x"), i_CLKDIV=ClockSignal(), + i_D1=1, i_D2=0, i_D3=1, i_D4=0, + i_D5=1, i_D6=0, i_D7=1, i_D8=0, + i_T1=~oe + ), + Instance("ODELAYE2", + p_DELAY_SRC="ODATAIN", p_SIGNAL_PATTERN="DATA", + p_CINVCTRL_SEL="FALSE", p_HIGH_PERFORMANCE_MODE="TRUE", p_REFCLK_FREQUENCY=200.0, + p_PIPE_SEL="FALSE", p_ODELAY_TYPE="FIXED", p_ODELAY_VALUE=6, + + o_ODATAIN=dqs_nodelay, o_DATAOUT=dqs_delayed + ), + Instance("OBUFTDS", + i_I=dqs_delayed, i_T=dqs_t, + o_O=pads.dqs_p[i], o_OB=pads.dqs_n[i] + ) + ] + + for i in range(d): + dq_o_nodelay = Signal() + dq_o_delayed = Signal() + dq_i_nodelay = Signal() + dq_i_delayed = Signal() + dq_t = Signal() + self.specials += [ + Instance("OSERDESE2", + p_DATA_WIDTH=8, p_TRISTATE_WIDTH=1, + p_DATA_RATE_OQ="DDR", p_DATA_RATE_TQ="SDR", + p_SERDES_MODE="MASTER", + + o_OQ=dq_o_nodelay, o_TQ=dq_t, + i_OCE=1, i_TCE=1, + i_CLK=ClockSignal("sys4x"), i_CLKDIV=ClockSignal(), + i_D1=self.dfi.phases[0].wrdata[i], i_D2=self.dfi.phases[0].wrdata[d+i], + i_D3=self.dfi.phases[1].wrdata[i], i_D4=self.dfi.phases[1].wrdata[d+i], + i_D5=self.dfi.phases[2].wrdata[i], i_D6=self.dfi.phases[2].wrdata[d+i], + i_D7=self.dfi.phases[3].wrdata[i], i_D8=self.dfi.phases[3].wrdata[d+i], + i_T1=~oe + ), + Instance("ISERDESE2", + p_DATA_WIDTH=8, p_DATA_RATE="DDR", + p_SERDES_MODE="MASTER", p_INTERFACE_TYPE="NETWORKING", + p_NUM_CE=1, p_IOBDELAY="BOTH", + + i_DDLY=dq_i_delayed, + i_CE1=1, + i_CLK=ClockSignal("sys4x"), i_CLKB=~ClockSignal("sys4x"), i_CLKDIV=ClockSignal(), + o_Q8=self.dfi.phases[0].rddata[i], o_Q7=self.dfi.phases[0].rddata[d+i], + o_Q6=self.dfi.phases[1].rddata[i], o_Q5=self.dfi.phases[1].rddata[d+i], + o_Q4=self.dfi.phases[2].rddata[i], o_Q3=self.dfi.phases[2].rddata[d+i], + o_Q2=self.dfi.phases[3].rddata[i], o_Q1=self.dfi.phases[3].rddata[d+i] + ), + Instance("ODELAYE2", + p_DELAY_SRC="ODATAIN", p_SIGNAL_PATTERN="DATA", + p_CINVCTRL_SEL="FALSE", p_HIGH_PERFORMANCE_MODE="TRUE", p_REFCLK_FREQUENCY=200.0, + p_PIPE_SEL="FALSE", p_ODELAY_TYPE="FIXED", p_ODELAY_VALUE=0, + + o_ODATAIN=dq_o_nodelay, o_DATAOUT=dq_o_delayed + ), + Instance("IDELAYE2", + p_DELAY_SRC="IDATAIN", p_SIGNAL_PATTERN="DATA", + p_CINVCTRL_SEL="FALSE", p_HIGH_PERFORMANCE_MODE="TRUE", p_REFCLK_FREQUENCY=200.0, + p_PIPE_SEL="FALSE", p_IDELAY_TYPE="FIXED", p_IDELAY_VALUE=6, + + i_IDATAIN=dq_i_nodelay, o_DATAOUT=dq_i_delayed + ), + Instance("IOBUF", + i_I=dq_o_delayed, o_O=dq_i_nodelay, i_T=dq_t, + io_IO=pads.dq[i] + ) + ] + + # total read latency = 8: + # 2 cycles through OSERDESE2 + # 4 cycles CAS + # 2 cycles through ISERDESE2 + for phase in self.dfi.phases: + rddata_valid = phase.rddata_valid + for i in range(7): + n_rddata_valid = Signal() + self.sync += rddata_valid.eq(n_rddata_valid) + rddata_valid = n_rddata_valid + self.sync += rddata_valid.eq(phase.rddata_en) + + last_wrdata_en = Signal(3) + wrphase = self.dfi.phases[self.phy_settings.wrphase] + self.sync += last_wrdata_en.eq(Cat(wrphase.wrdata_en, last_wrdata_en[:2])) + self.comb += oe.eq(last_wrdata_en[0] | last_wrdata_en[1] | last_wrdata_en[2])