Xilinx LVDS Output——原语调用
根据上一篇Xilinx LVDS Output——OSERDESE2说的内容,先例化出OSEREDSE2
模块;
Primitive 调用
调
Vivado
提供了相关的原语程序模板,可以直接调用,按照如下步骤:
先打开语言模板:
选择相应的原语文档:
完整文档如下(务必仔细阅读注释):
// OSERDESE2 : In order to incorporate this function into the design,
// Verilog : the following instance declaration needs to be placed
// instance : in the body of the design code. The instance name
// declaration : (OSERDESE2_inst) and/or the port declarations within the
// code : parenthesis may be changed to properly reference and
// : connect this function to the design. All inputs
// : and outputs must be connected.
// <-----Cut code below this line---->
// OSERDESE2: Output SERial/DESerializer with bitslip
// Kintex-7
// Xilinx HDL Language Template, version 2018.3
OSERDESE2 #(
.DATA_RATE_OQ("DDR"), // DDR, SDR
.DATA_RATE_TQ("DDR"), // DDR, BUF, SDR
.DATA_WIDTH(4), // Parallel data width (2-8,10,14)
.INIT_OQ(1'b0), // Initial value of OQ output (1'b0,1'b1)
.INIT_TQ(1'b0), // Initial value of TQ output (1'b0,1'b1)
.SERDES_MODE("MASTER"), // MASTER, SLAVE
.SRVAL_OQ(1'b0), // OQ output value when SR is used (1'b0,1'b1)
.SRVAL_TQ(1'b0), // TQ output value when SR is used (1'b0,1'b1)
.TBYTE_CTL("FALSE"), // Enable tristate byte operation (FALSE, TRUE)
.TBYTE_SRC("FALSE"), // Tristate byte source (FALSE, TRUE)
.TRISTATE_WIDTH(4) // 3-state converter width (1,4)
)
OSERDESE2_inst (
.OFB(OFB), // 1-bit output: Feedback path for data
.OQ(OQ), // 1-bit output: Data path output
// SHIFTOUT1 / SHIFTOUT2: 1-bit (each) output: Data output expansion (1-bit each)
.SHIFTOUT1(SHIFTOUT1),
.SHIFTOUT2(SHIFTOUT2),
.TBYTEOUT(TBYTEOUT), // 1-bit output: Byte group tristate
.TFB(TFB), // 1-bit output: 3-state control
.TQ(TQ), // 1-bit output: 3-state control
.CLK(CLK), // 1-bit input: High speed clock
.CLKDIV(CLKDIV), // 1-bit input: Divided clock
// D1 - D8: 1-bit (each) input: Parallel data inputs (1-bit each)
.D1(D1),
.D2(D2),
.D3(D3),
.D4(D4),
.D5(D5),
.D6(D6),
.D7(D7),
.D8(D8),
.OCE(OCE), // 1-bit input: Output data clock enable
.RST(RST), // 1-bit input: Reset
// SHIFTIN1 / SHIFTIN2: 1-bit (each) input: Data input expansion (1-bit each)
.SHIFTIN1(SHIFTIN1),
.SHIFTIN2(SHIFTIN2),
// T1 - T4: 1-bit (each) input: Parallel 3-state inputs
.T1(T1),
.T2(T2),
.T3(T3),
.T4(T4),
.TBYTEIN(TBYTEIN), // 1-bit input: Byte group tristate
.TCE(TCE) // 1-bit input: 3-state clock enable
);
// End of OSERDESE2_inst instantiation
用
属性
如果使用的是DDR
的方式,属性部分不用改动;如果使用SDR
的方式,就将对应属性修改,其余默认:
- 参数
DATA_WIDTH
修改为为需要使用的串解因子,这里修改为8
; - 参数
DATA_RATE_OQ
修改为SDR
; - 参数
DATA_RATE_TQ
修改为SDR
; - 参数
TRISTATE_WIDTH
修改为1
;
Port
端口部分需要根据使用进行修改:
OQ
连接到输出数据;CLK
连接高频率的时钟;CLKDIV
连接低频率的时钟;D1 ~ D7
连接需要进行并转串的数据(1bit);OCE
,1’b1
,输出数据时钟使能,这里为常高;RST
,~XRST
,Reset
信号,这里系统时钟sys_rst_n
为低有效,所以取反;- 其余
SHIFTOUT1
,2
,TBYTEOUT
,TFB
,TQ
不连接; SHIFTIN1
,2
,T1 ~ T4
,TBYTEIN
,TCE
均连接1’b0
;
OBUFDS
之前说的,都是将并行数据,串行输出的步骤;假设已经获串行的数据,还需要将其使用OBUFDS
输出;
参考手册ug471_7Series_SelectIO.pdf Page45 ~ Page46;
OBUFDS Primitive
观察为,输入Port I
,输出Port O
和OB
;
同样在Language Templates
中找到原语模版:
// OBUFDS : In order to incorporate this function into the design,
// Verilog : the following instance declaration needs to be placed
// instance : in the body of the design code. The instance name
// declaration : (OBUFDS_inst) and/or the port declarations within the
// code : parenthesis may be changed to properly reference and
// : connect this function to the design. All inputs
// : and outputs must be connected.
// <-----Cut code below this line---->
// OBUFDS: Differential Output Buffer
// Kintex UltraScale
// Xilinx HDL Language Template, version 2018.3
OBUFDS OBUFDS_inst (
.O(O), // 1-bit output: Diff_p output (connect directly to top-level port)
.OB(OB), // 1-bit output: Diff_n output (connect directly to top-level port)
.I(I) // 1-bit input: Buffer input
);
// End of OBUFDS_inst instantiation
注意,看到O
和OB Port
需要直接连接到顶层的输出引脚;
通用设计
将OSERDES2
和OBUFDS
联合起来,进行通用设计,这样移植和例化都比较方便;
需要定输出引脚个数,还需要加上CLK
输出信号;
比如说输出引脚个数为16
,串解因子为8
;
与低频时钟CLKDIV
同步的数据tx_data
位宽就是16 * 8 = 128bit
;
这时候需要将数据拆分,分别例化到16
个引脚上;
如果是两个引脚,那就可以直接例化,如果有很多,那么就可以使用generate大法;
CLK
直接上code
:
parameter clk_pattern = 8'b0101_0101;
wire s_OSERDES_CLK ; // tx io clk
//---------------------------------------------------------------------
// Clock Output control
//---------------------------------------------------------------------
OSERDESE2 #(
.DATA_RATE_OQ ( "DDR" ), // DDR, SDR
.DATA_RATE_TQ ( "DDR" ), // DDR, BUF, SDR
.DATA_WIDTH ( 8 ), // Parallel data width (2-8,10,14)
.INIT_OQ ( 1'b0 ), // Initial value of OQ output (1'b0,1'b1)
.INIT_TQ ( 1'b0 ), // Initial value of TQ output (1'b0,1'b1)
.SERDES_MODE ( "MASTER" ), // MASTER, SLAVE
.SRVAL_OQ ( 1'b0 ), // OQ output value when SR is used (1'b0,1'b1)
.SRVAL_TQ ( 1'b0 ), // TQ output value when SR is used (1'b0,1'b1)
.TBYTE_CTL ( "FALSE" ), // Enable tristate byte operation (FALSE, TRUE)
.TBYTE_SRC ( "FALSE" ), // Tristate byte source (FALSE, TRUE)
.TRISTATE_WIDTH ( 1 ) // 3-state converter width (1,4)
)
U_OSERDESE2_CLK0 (
.OFB ( ), // 1-bit output: Feedback path for data
.OQ ( s_OSERDES_CLK ), // 1-bit output: Data path output
// SHIFTOUT1 / SHIFTOUT2: 1-bit (each) output: Data output expansion (1-bit each)
.SHIFTOUT1 ( ),
.SHIFTOUT2 ( ),
.TBYTEOUT ( ), // 1-bit output: Byte group tristate
.TFB ( ), // 1-bit output: 3-state control
.TQ ( ), // 1-bit output: 3-state control
.CLK ( CLK ), // 1-bit input: High speed clock
.CLKDIV ( CLK_DIV ), // 1-bit input: Divided clock
// D1 - D8: 1-bit (each) input: Parallel data inputs (1-bit each)
.D1 ( clk_pattern[0] ),
.D2 ( clk_pattern[1] ),
.D3 ( clk_pattern[2] ),
.D4 ( clk_pattern[3] ),
.D5 ( clk_pattern[4] ),
.D6 ( clk_pattern[5] ),
.D7 ( clk_pattern[6] ),
.D8 ( clk_pattern[7] ),
.OCE ( 1'b1 ), // 1-bit input: Output data clock enable
.RST ( ~XRST ), // 1-bit input: Reset
// SHIFTIN1 / SHIFTIN2: 1-bit (each) input: Data input expansion (1-bit each)
.SHIFTIN1 ( 1'b0 ),
.SHIFTIN2 ( 1'b0 ),
// T1 - T4: 1-bit (each) input: Parallel 3-state inputs
.T1 ( 1'b0 ),
.T2 ( 1'b0 ),
.T3 ( 1'b0 ),
.T4 ( 1'b0 ),
.TBYTEIN ( 1'b0 ), // 1-bit input: Byte group tristate
.TCE ( 1'b0 ) // 1-bit input: 3-state clock enable
);
OBUFDS #(
.SLEW ( "FAST" ) // Specify the output slew rate
)
U_OBUFDS_CLK0 (
.O ( OSERDES_CLK_P ), // Diff_p output (connect directly to top-level port)
.OB ( OSERDES_CLK_N ), // Diff_n output (connect directly to top-level port)
.I ( s_OSERDES_CLK ) // Buffer input
);
先通过OSERDES2
将clk_pattern
输出,就有了clk
的波形,接着连接到OBUFDS
上,直接输出到差分引脚。
DATA
依然直接上code
:
parameter DB_W = 16 // data bus width
wire [DB_W-1 :0] s_OSERDES_DAT ; // tx io data
//---------------------------------------------------------------------
// Data Output control
//---------------------------------------------------------------------
genvar i;
generate
for (i=0; i<DB_W; i=i+1) begin: data_txout
OSERDESE2 #(
.DATA_RATE_OQ ( "SDR" ), // DDR, SDR
.DATA_RATE_TQ ( "SDR" ), // DDR, BUF, SDR
.DATA_WIDTH ( 8 ), // Parallel data width (2-8,10,14)
.INIT_OQ ( 1'b0 ), // Initial value of OQ output (1'b0,1'b1)
.INIT_TQ ( 1'b0 ), // Initial value of TQ output (1'b0,1'b1)
.SERDES_MODE ( "MASTER" ), // MASTER, SLAVE
.SRVAL_OQ ( 1'b0 ), // OQ output value when SR is used (1'b0,1'b1)
.SRVAL_TQ ( 1'b0 ), // TQ output value when SR is used (1'b0,1'b1)
.TBYTE_CTL ( "FALSE" ), // Enable tristate byte operation (FALSE, TRUE)
.TBYTE_SRC ( "FALSE" ), // Tristate byte source (FALSE, TRUE)
.TRISTATE_WIDTH ( 1 ) // 3-state converter width (1,4)
)
U_OSERDESE2_TLA0 (
.OFB ( ), // 1-bit output: Feedback path for data
.OQ ( s_OSERDES_DAT[i] ), // 1-bit output: Data path output
// SHIFTOUT1 / SHIFTOUT2: 1-bit (each) output: Data output expansion (1-bit each)
.SHIFTOUT1 ( ),
.SHIFTOUT2 ( ),
.TBYTEOUT ( ), // 1-bit output: Byte group tristate
.TFB ( ), // 1-bit output: 3-state control
.TQ ( ), // 1-bit output: 3-state control
.CLK ( CLK ), // 1-bit input: High speed clock
.CLKDIV ( CLK_DIV ), // 1-bit input: Divided clock
// D1 - D8: 1-bit (each) input: Parallel data inputs (1-bit each)
.D1 ( TX_DATA[i*8+7] ),
.D2 ( TX_DATA[i*8+6] ),
.D3 ( TX_DATA[i*8+5] ),
.D4 ( TX_DATA[i*8+4] ),
.D5 ( TX_DATA[i*8+3] ),
.D6 ( TX_DATA[i*8+2] ),
.D7 ( TX_DATA[i*8+1] ),
.D8 ( TX_DATA[i*8+0] ),
.OCE ( 1'b1 ), // 1-bit input: Output data clock enable
.RST ( ~XRST ), // 1-bit input: Reset
// SHIFTIN1 / SHIFTIN2: 1-bit (each) input: Data input expansion (1-bit each)
.SHIFTIN1 ( 1'b0 ),
.SHIFTIN2 ( 1'b0 ),
// T1 - T4: 1-bit (each) input: Parallel 3-state inputs
.T1 ( 1'b0 ),
.T2 ( 1'b0 ),
.T3 ( 1'b0 ),
.T4 ( 1'b0 ),
.TBYTEIN ( 1'b0 ), // 1-bit input: Byte group tristate
.TCE ( 1'b0 ) // 1-bit input: 3-state clock enable
);
OBUFDS #(
.SLEW ( "FAST" ) // Specify the output slew rate
)
U_OBUFDS_TLA0 (
.O ( OSERDES_DAT_P[i] ), // Diff_p output (connect directly to top-level port)
.OB ( OSERDES_DAT_N[i] ), // Diff_n output (connect directly to top-level port)
.I ( s_OSERDES_DAT[i] ) // Buffer input
);
end
endgenerate
使用generate语句,将16
个引脚,全部一次例化,非常方便;下次使用的时候,直接修改参数DB_W
即可;
至此,LVDS
的输出RTL
已经完成了。
One more thing
需要添加xdc
文件,加入端口的约束和电平规格约束,举例如下:
# DATA
set_property PACKAGE_PIN L16 [get_ports {LVDS_OUTP[0]}]
set_property PACKAGE_PIN K16 [get_ports {LVDS_OUTN[0]}]
set_property IOSTANDARD LVDS_25 [get_ports {LVDS_OUTP[0]}]
set_property IOSTANDARD LVDS_25 [get_ports {LVDS_OUTN[0]}]
所有LVDS
输出的引脚进行引脚约束和电平规格约束之后,才算是大功告成。