/
csi_rx_hs_lane_phy.vhd
executable file
·287 lines (261 loc) · 7.73 KB
/
csi_rx_hs_lane_phy.vhd
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.NUMERIC_STD.ALL;
library UNISIM;
use UNISIM.VComponents.all;
--High-Speed D-PHY lane RX PHY for MIPI CSI-2 Rx core
--Copyright (C) 2016 David Shah
--Licensed under the MIT License
--This entity handles input skew compensation and deserialisation for the
--CSI data input lanes. Output is has arbitrary alignment which must be fixed later on
--in the processing chain
entity csi_rx_hs_lane_phy is
generic(
series : string := "7SERIES"; --FPGA series, 7SERIES or VIRTEX6
invert : boolean := false; --Whether or not to invert output (i.e. if pairs are swapped)
term_en : boolean := true; --Whether or not to enable internal input termination
delay : natural --IDELAY delay value for skew compensation
);
port (
ddr_bit_clock : in STD_LOGIC; --true and complement DDR bit clocks, buffered from D-PHY clock
ddr_bit_clock_b : in STD_LOGIC;
byte_clock : in STD_LOGIC; --byte clock; i.e. input clock /4
enable : in STD_LOGIC; --active high enable for SERDES
reset : in STD_LOGIC; --reset, latched internally to byte clock
dphy_hs : in STD_LOGIC_VECTOR (1 downto 0); --lane input, 1 is P, 0 is N
deser_out : out STD_LOGIC_VECTOR (7 downto 0) --deserialised byte output
);
end csi_rx_hs_lane_phy;
architecture Behavioral of csi_rx_hs_lane_phy is
signal reset_lat : std_logic; --reset synchronised to byte clock
signal in_se : std_logic; --input after differential buffer
signal in_delayed : std_logic; --input after deskew
--for Virtex-6 devices where we cascade two ISERDESs
signal shift_1 : std_logic;
signal shift_2 : std_logic;
signal serdes_out_int : std_logic_vector(7 downto 0);
begin
process(byte_clock)
begin
if rising_edge(byte_clock) then
reset_lat <= reset;
end if;
end process;
inbuf : IBUFDS
generic map(
DIFF_TERM => term_en,
IBUF_LOW_PWR => FALSE,
IOSTANDARD => "DEFAULT")
port map(
O => in_se,
I => dphy_hs(1),
IB => dphy_hs(0));
--7 series specific blocks
gen_7s : if series = "7SERIES" generate
indelay : IDELAYE2
generic map (
CINVCTRL_SEL => "FALSE",
DELAY_SRC => "IDATAIN",
HIGH_PERFORMANCE_MODE => "TRUE",
IDELAY_TYPE => "FIXED",
IDELAY_VALUE => delay,
REFCLK_FREQUENCY => 200.0,
SIGNAL_PATTERN => "DATA",
PIPE_SEL => "FALSE"
)
port map (
DATAOUT => in_delayed,
DATAIN => '0',
C => byte_clock,
CE => '0',
INC => '0',
IDATAIN => in_se,
CNTVALUEIN => "00000",
CNTVALUEOUT => open,
CINVCTRL => '0',
LD => '0',
LDPIPEEN => '0',
REGRST => '0'
);
ideser : ISERDESE2
generic map (
DATA_RATE => "DDR",
DATA_WIDTH => 8,
DYN_CLKDIV_INV_EN => "FALSE",
DYN_CLK_INV_EN => "FALSE",
INIT_Q1 => '0',
INIT_Q2 => '0',
INIT_Q3 => '0',
INIT_Q4 => '0',
INTERFACE_TYPE => "NETWORKING",
IOBDELAY => "IFD",
NUM_CE => 1,
OFB_USED => "FALSE",
SERDES_MODE => "MASTER",
SRVAL_Q1 => '0',
SRVAL_Q2 => '0',
SRVAL_Q3 => '0',
SRVAL_Q4 => '0')
port map (
O => open,
--In the ISERDESE2, Q8 is the oldest bit but in the CSI spec
--the MSB is the most recent bit. So we mirror the output
Q1 => serdes_out_int(7),
Q2 => serdes_out_int(6),
Q3 => serdes_out_int(5),
Q4 => serdes_out_int(4),
Q5 => serdes_out_int(3),
Q6 => serdes_out_int(2),
Q7 => serdes_out_int(1),
Q8 => serdes_out_int(0),
SHIFTOUT1 => open,
SHIFTOUT2 => open,
BITSLIP => '0',
CE1 => enable,
CE2 => '1',
CLKDIVP => '0',
CLK => ddr_bit_clock,
CLKB => ddr_bit_clock_b,
CLKDIV => byte_clock,
OCLK => '0',
DYNCLKDIVSEL => '0',
DYNCLKSEL => '0',
D => '0',
DDLY => in_delayed,
OFB => '0',
OCLKB => '0',
RST => reset_lat,
SHIFTIN1 => '0',
SHIFTIN2 => '0'
);
end generate;
--Legacy Virtex-6 specific blocks
gen_v6 : if series = "VIRTEX6" generate
--Input delay for skew compensation
indelay : IODELAYE1
generic map (
CINVCTRL_SEL => FALSE,
DELAY_SRC => "I",
HIGH_PERFORMANCE_MODE => TRUE,
IDELAY_TYPE => "FIXED",
IDELAY_VALUE => delay,
ODELAY_TYPE => "FIXED",
ODELAY_VALUE => 0,
REFCLK_FREQUENCY => 200.0,
SIGNAL_PATTERN => "DATA"
)
port map (
DATAOUT => in_delayed,
DATAIN => '0',
C => byte_clock,
CE => '0',
INC => '0',
IDATAIN => in_se,
ODATAIN => '0',
RST => '0',
T => '1',
CNTVALUEIN => "00000",
CNTVALUEOUT => open,
CLKIN => '0',
CINVCTRL => '0'
);
--Input deserialisation
ideser1 : ISERDESE1
generic map (
DATA_RATE => "DDR",
DATA_WIDTH => 8,
DYN_CLKDIV_INV_EN => FALSE,
DYN_CLK_INV_EN => FALSE,
INIT_Q1 => '0',
INIT_Q2 => '0',
INIT_Q3 => '0',
INIT_Q4 => '0',
INTERFACE_TYPE => "NETWORKING",
IOBDELAY => "IFD",
NUM_CE => 2,
OFB_USED => FALSE,
SERDES_MODE => "MASTER",
SRVAL_Q1 => '0',
SRVAL_Q2 => '0',
SRVAL_Q3 => '0',
SRVAL_Q4 => '0'
)
port map(
O => open,
Q1 => serdes_out_int(7),
Q2 => serdes_out_int(6),
Q3 => serdes_out_int(5),
Q4 => serdes_out_int(4),
Q5 => serdes_out_int(3),
Q6 => serdes_out_int(2),
SHIFTOUT1 => shift_1,
SHIFTOUT2 => shift_2,
BITSLIP => '0',
CE1 => enable,
CE2 => enable,
CLK => ddr_bit_clock,
CLKB => ddr_bit_clock_b,
CLKDIV => byte_clock,
D => '0',
DDLY => in_delayed,
DYNCLKDIVSEL => '0',
DYNCLKSEL => '0',
OCLK => '0',
OFB => '0',
RST => reset_lat,
SHIFTIN1 => '0',
SHIFTIN2 => '0');
ideser2 : ISERDESE1
generic map (
DATA_RATE => "DDR",
DATA_WIDTH => 8,
DYN_CLKDIV_INV_EN => FALSE,
DYN_CLK_INV_EN => FALSE,
INIT_Q1 => '0',
INIT_Q2 => '0',
INIT_Q3 => '0',
INIT_Q4 => '0',
INTERFACE_TYPE => "NETWORKING",
IOBDELAY => "IFD",
NUM_CE => 2,
OFB_USED => FALSE,
SERDES_MODE => "SLAVE",
SRVAL_Q1 => '0',
SRVAL_Q2 => '0',
SRVAL_Q3 => '0',
SRVAL_Q4 => '0'
)
port map(
O => open,
Q1 => open,
Q2 => open,
Q3 => serdes_out_int(1),
Q4 => serdes_out_int(0),
Q5 => open,
Q6 => open,
SHIFTOUT1 => open,
SHIFTOUT2 => open,
BITSLIP => '0',
CE1 => enable,
CE2 => enable,
CLK => ddr_bit_clock,
CLKB => ddr_bit_clock_b,
CLKDIV => byte_clock,
D => '0',
DDLY => '0',
DYNCLKDIVSEL => '0',
DYNCLKSEL => '0',
OCLK => '0',
OFB => '0',
RST => reset_lat,
SHIFTIN1 => shift_1,
SHIFTIN2 => shift_2);
end generate;
--Inversion of output based on generic
gen_true : if not invert generate
deser_out <= serdes_out_int;
end generate;
gen_inv : if invert generate
deser_out <= not serdes_out_int;
end generate;
end architecture;