Skip to content

Commit af85f83

Browse files
committedOct 10, 2017
sdram/a7ddrphy: add from litex
1 parent 5764e23 commit af85f83

File tree

1 file changed

+237
-0
lines changed

1 file changed

+237
-0
lines changed
 

‎misoc/cores/sdram_phy/a7ddrphy.py

+237
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,237 @@
1+
# 1:4 frequency-ratio DDR3 PHYs for Artix7
2+
# tCK=2.5ns CL=7 CWL=6
3+
4+
from migen import *
5+
6+
from misoc.interconnect.dfi import *
7+
from misoc.interconnect.csr import *
8+
from misoc.cores import sdram_settings
9+
10+
11+
class A7DDRPHY(Module, AutoCSR):
12+
def __init__(self, pads):
13+
addressbits = len(pads.a)
14+
bankbits = len(pads.ba)
15+
databits = len(pads.dq)
16+
nphases = 4
17+
18+
self._dly_sel = CSRStorage(databits//8)
19+
self._rdly_dq_rst = CSR()
20+
self._rdly_dq_inc = CSR()
21+
self._rdly_dq_bitslip = CSR()
22+
23+
self.settings = sdram_settings.PhySettings(
24+
memtype="DDR3",
25+
dfi_databits=2*databits,
26+
nphases=nphases,
27+
rdphase=0,
28+
wrphase=2,
29+
rdcmdphase=1,
30+
wrcmdphase=0,
31+
cl=7,
32+
cwl=6,
33+
read_latency=6,
34+
write_latency=2
35+
)
36+
37+
self.dfi = Interface(addressbits, bankbits, 2*databits, nphases)
38+
39+
# # #
40+
41+
# Clock
42+
sd_clk_se = Signal()
43+
self.specials += [
44+
Instance("OSERDESE2",
45+
p_DATA_WIDTH=8, p_TRISTATE_WIDTH=1,
46+
p_DATA_RATE_OQ="DDR", p_DATA_RATE_TQ="BUF",
47+
p_SERDES_MODE="MASTER",
48+
49+
o_OQ=sd_clk_se,
50+
i_OCE=1,
51+
i_RST=ResetSignal(),
52+
i_CLK=ClockSignal("sys4x"), i_CLKDIV=ClockSignal(),
53+
i_D1=0, i_D2=1, i_D3=0, i_D4=1,
54+
i_D5=0, i_D6=1, i_D7=0, i_D8=1
55+
),
56+
Instance("OBUFDS",
57+
i_I=sd_clk_se,
58+
o_O=pads.clk_p,
59+
o_OB=pads.clk_n
60+
)
61+
]
62+
63+
# Addresses and commands
64+
for i in range(addressbits):
65+
self.specials += \
66+
Instance("OSERDESE2",
67+
p_DATA_WIDTH=8, p_TRISTATE_WIDTH=1,
68+
p_DATA_RATE_OQ="DDR", p_DATA_RATE_TQ="BUF",
69+
p_SERDES_MODE="MASTER",
70+
71+
o_OQ=pads.a[i],
72+
i_OCE=1,
73+
i_RST=ResetSignal(),
74+
i_CLK=ClockSignal("sys4x"), i_CLKDIV=ClockSignal(),
75+
i_D1=self.dfi.phases[0].address[i], i_D2=self.dfi.phases[0].address[i],
76+
i_D3=self.dfi.phases[1].address[i], i_D4=self.dfi.phases[1].address[i],
77+
i_D5=self.dfi.phases[2].address[i], i_D6=self.dfi.phases[2].address[i],
78+
i_D7=self.dfi.phases[3].address[i], i_D8=self.dfi.phases[3].address[i]
79+
)
80+
for i in range(bankbits):
81+
self.specials += \
82+
Instance("OSERDESE2",
83+
p_DATA_WIDTH=8, p_TRISTATE_WIDTH=1,
84+
p_DATA_RATE_OQ="DDR", p_DATA_RATE_TQ="BUF",
85+
p_SERDES_MODE="MASTER",
86+
87+
o_OQ=pads.ba[i],
88+
i_OCE=1,
89+
i_RST=ResetSignal(),
90+
i_CLK=ClockSignal("sys4x"), i_CLKDIV=ClockSignal(),
91+
i_D1=self.dfi.phases[0].bank[i], i_D2=self.dfi.phases[0].bank[i],
92+
i_D3=self.dfi.phases[1].bank[i], i_D4=self.dfi.phases[1].bank[i],
93+
i_D5=self.dfi.phases[2].bank[i], i_D6=self.dfi.phases[2].bank[i],
94+
i_D7=self.dfi.phases[3].bank[i], i_D8=self.dfi.phases[3].bank[i]
95+
)
96+
controls = ["ras_n", "cas_n", "we_n", "cke", "odt", "reset_n"]
97+
if hasattr(pads, "cs_n"):
98+
controls.append("cs_n")
99+
for name in controls:
100+
self.specials += \
101+
Instance("OSERDESE2",
102+
p_DATA_WIDTH=8, p_TRISTATE_WIDTH=1,
103+
p_DATA_RATE_OQ="DDR", p_DATA_RATE_TQ="BUF",
104+
p_SERDES_MODE="MASTER",
105+
106+
o_OQ=getattr(pads, name),
107+
i_OCE=1,
108+
i_RST=ResetSignal(),
109+
i_CLK=ClockSignal("sys4x"), i_CLKDIV=ClockSignal(),
110+
i_D1=getattr(self.dfi.phases[0], name), i_D2=getattr(self.dfi.phases[0], name),
111+
i_D3=getattr(self.dfi.phases[1], name), i_D4=getattr(self.dfi.phases[1], name),
112+
i_D5=getattr(self.dfi.phases[2], name), i_D6=getattr(self.dfi.phases[2], name),
113+
i_D7=getattr(self.dfi.phases[3], name), i_D8=getattr(self.dfi.phases[3], name)
114+
)
115+
# DQS and DM
116+
oe_dqs = Signal()
117+
dqs_serdes_pattern = Signal(8, reset=0b01010101)
118+
for i in range(databits//8):
119+
self.specials += \
120+
Instance("OSERDESE2",
121+
p_DATA_WIDTH=8, p_TRISTATE_WIDTH=1,
122+
p_DATA_RATE_OQ="DDR", p_DATA_RATE_TQ="BUF",
123+
p_SERDES_MODE="MASTER",
124+
125+
o_OQ=pads.dm[i],
126+
i_OCE=1,
127+
i_RST=ResetSignal(),
128+
i_CLK=ClockSignal("sys4x"), i_CLKDIV=ClockSignal(),
129+
i_D1=self.dfi.phases[0].wrdata_mask[i], i_D2=self.dfi.phases[0].wrdata_mask[databits//8+i],
130+
i_D3=self.dfi.phases[1].wrdata_mask[i], i_D4=self.dfi.phases[1].wrdata_mask[databits//8+i],
131+
i_D5=self.dfi.phases[2].wrdata_mask[i], i_D6=self.dfi.phases[2].wrdata_mask[databits//8+i],
132+
i_D7=self.dfi.phases[3].wrdata_mask[i], i_D8=self.dfi.phases[3].wrdata_mask[databits//8+i]
133+
)
134+
135+
dqs = Signal()
136+
dqs_t = Signal()
137+
self.specials += [
138+
Instance("OSERDESE2",
139+
p_DATA_WIDTH=8, p_TRISTATE_WIDTH=1,
140+
p_DATA_RATE_OQ="DDR", p_DATA_RATE_TQ="BUF",
141+
p_SERDES_MODE="MASTER",
142+
143+
o_OQ=dqs, o_TQ=dqs_t,
144+
i_OCE=1, i_TCE=1,
145+
i_RST=ResetSignal(),
146+
i_CLK=ClockSignal("sys4x_dqs"), i_CLKDIV=ClockSignal(),
147+
i_D1=dqs_serdes_pattern[0], i_D2=dqs_serdes_pattern[1],
148+
i_D3=dqs_serdes_pattern[2], i_D4=dqs_serdes_pattern[3],
149+
i_D5=dqs_serdes_pattern[4], i_D6=dqs_serdes_pattern[5],
150+
i_D7=dqs_serdes_pattern[6], i_D8=dqs_serdes_pattern[7],
151+
i_T1=~oe_dqs
152+
),
153+
Instance("OBUFTDS",
154+
i_I=dqs, i_T=dqs_t,
155+
o_O=pads.dqs_p[i], o_OB=pads.dqs_n[i]
156+
)
157+
]
158+
159+
# DQ
160+
oe_dq = Signal()
161+
for i in range(databits):
162+
dq_o = Signal()
163+
dq_i_nodelay = Signal()
164+
dq_i_delayed = Signal()
165+
dq_t = Signal()
166+
self.specials += [
167+
Instance("OSERDESE2",
168+
p_DATA_WIDTH=8, p_TRISTATE_WIDTH=1,
169+
p_DATA_RATE_OQ="DDR", p_DATA_RATE_TQ="BUF",
170+
p_SERDES_MODE="MASTER",
171+
172+
o_OQ=dq_o, o_TQ=dq_t,
173+
i_OCE=1, i_TCE=1,
174+
i_RST=ResetSignal(),
175+
i_CLK=ClockSignal("sys4x"), i_CLKDIV=ClockSignal(),
176+
i_D1=self.dfi.phases[0].wrdata[i], i_D2=self.dfi.phases[0].wrdata[databits+i],
177+
i_D3=self.dfi.phases[1].wrdata[i], i_D4=self.dfi.phases[1].wrdata[databits+i],
178+
i_D5=self.dfi.phases[2].wrdata[i], i_D6=self.dfi.phases[2].wrdata[databits+i],
179+
i_D7=self.dfi.phases[3].wrdata[i], i_D8=self.dfi.phases[3].wrdata[databits+i],
180+
i_T1=~oe_dq
181+
),
182+
Instance("ISERDESE2",
183+
p_DATA_WIDTH=8, p_DATA_RATE="DDR",
184+
p_SERDES_MODE="MASTER", p_INTERFACE_TYPE="NETWORKING",
185+
p_NUM_CE=1, p_IOBDELAY="IFD",
186+
187+
i_DDLY=dq_i_delayed,
188+
i_CE1=1,
189+
i_RST=ResetSignal() | (self._dly_sel.storage[i//8] & self._rdly_dq_rst.re),
190+
i_CLK=ClockSignal("sys4x"), i_CLKB=~ClockSignal("sys4x"), i_CLKDIV=ClockSignal(),
191+
i_BITSLIP=self._dly_sel.storage[i//8] & self._rdly_dq_bitslip.re,
192+
o_Q8=self.dfi.phases[0].rddata[i], o_Q7=self.dfi.phases[0].rddata[databits+i],
193+
o_Q6=self.dfi.phases[1].rddata[i], o_Q5=self.dfi.phases[1].rddata[databits+i],
194+
o_Q4=self.dfi.phases[2].rddata[i], o_Q3=self.dfi.phases[2].rddata[databits+i],
195+
o_Q2=self.dfi.phases[3].rddata[i], o_Q1=self.dfi.phases[3].rddata[databits+i]
196+
),
197+
Instance("IDELAYE2",
198+
p_DELAY_SRC="IDATAIN", p_SIGNAL_PATTERN="DATA",
199+
p_CINVCTRL_SEL="FALSE", p_HIGH_PERFORMANCE_MODE="TRUE", p_REFCLK_FREQUENCY=200.0,
200+
p_PIPE_SEL="FALSE", p_IDELAY_TYPE="VARIABLE", p_IDELAY_VALUE=6,
201+
202+
i_C=ClockSignal(),
203+
i_LD=self._dly_sel.storage[i//8] & self._rdly_dq_rst.re,
204+
i_CE=self._dly_sel.storage[i//8] & self._rdly_dq_inc.re,
205+
i_LDPIPEEN=0, i_INC=1,
206+
207+
i_IDATAIN=dq_i_nodelay, o_DATAOUT=dq_i_delayed
208+
),
209+
Instance("IOBUF",
210+
i_I=dq_o, o_O=dq_i_nodelay, i_T=dq_t,
211+
io_IO=pads.dq[i]
212+
)
213+
]
214+
215+
# Flow control
216+
#
217+
# total read latency = 6:
218+
# 2 cycles through OSERDESE2
219+
# 2 cycles CAS
220+
# 2 cycles through ISERDESE2
221+
rddata_en = self.dfi.phases[self.settings.rdphase].rddata_en
222+
for i in range(6-1):
223+
n_rddata_en = Signal()
224+
self.sync += n_rddata_en.eq(rddata_en)
225+
rddata_en = n_rddata_en
226+
self.sync += [phase.rddata_valid.eq(rddata_en)
227+
for phase in self.dfi.phases]
228+
229+
oe = Signal()
230+
last_wrdata_en = Signal(4)
231+
wrphase = self.dfi.phases[self.settings.wrphase]
232+
self.sync += last_wrdata_en.eq(Cat(wrphase.wrdata_en, last_wrdata_en[:3]))
233+
self.comb += oe.eq(last_wrdata_en[1] | last_wrdata_en[2] | last_wrdata_en[3])
234+
self.sync += [
235+
oe_dqs.eq(oe),
236+
oe_dq.eq(oe)
237+
]

0 commit comments

Comments
 (0)
Please sign in to comment.