Xilinx中oserdes的原语及IP的使用
vivado中oserdes的原语及IP的使用
应用场景
在高速应用中,我们经常性的听说serdes的应用,确实serdes是一项重要的应用。serdes又可以分为iserdes与oserdes两个操作分别是串行转并行以及并行转串行,因为FPGA内部跑的频率较低,不能处理那么高的串行频率需要转成并行处理。举两个serdes的例子以供大家明白它的作用:
1、HDMI中的发射端用到了Oserdes接收端用到了Iserdes,因为HDMI是数字串行通信
2、在GTP的应用中,如PCIE、SFP都用到了serdes操作
我们下篇文章会讲解HDMI应用。知道了serdes的作用,那么学习起来这个操作才有意义。
serdes原语的应用
首先从vivado中调出oserdes原语如下
接下来对其接口信号进行描述:
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
1、DATA_RATE_OQ:数据模式,DDR代表上升沿和下降沿都发送数据,SDR代表只在上升沿发送数据
2、DATA_RATE_TQ:三态门模式,同上,这里我们不关注三态状态,所有与三态设置相关的信号输入设置成0,输出不关心。
3、INIT_OQ:初始化数据输出端初始值
4、SERDES_MODE:串行的模式,在10,14串行通信的时候用到,如下图:
用到两个serdes,上面的选择Master下面的选择Slave
5、SRVAL_OQ:复位时输出电平的状态
6、OFB:反馈输出,这里不关心即可
7、OQ:输出信号
8、SHIFTOUT1:serdes串联时送给上一个serdes用到的信号
9、SHIFTOUT2:serdes串联时送给上一个serdes用到的信号
10、CLK:串行块时钟,在HDMI中是CLKDIV的5倍
11、CLKDIV:并行数据的随路时钟
12、DX:并行输入数据
13、OCE:模块使能信号,默认为1使能
14、RST:模块复位信号,默认为1复位
15、SHIFTIN1:serdes串联时送接收下一个serdes用到的信号
16、SHIFTIN2:serdes串联时送接收下一个serdes用到的信号
我们这里使用典型的10bit数据转串行数据发送。
serdes原语的使用示例
这里将以10bit转成串行输出为例给出相应的代码,注意原语中TRISTATE_WIDTH设置为1,因为手册中的说明如下:
所以代码如下:
`timescale 1ns / 1ps
// *********************************************************************************
// Project Name : OSXXXX
// Author : zhangningning
// Email : aaa@qq.com
// Website :
// Module Name : par2ser.v
// Create Time : 2020-02-23 14:20:43
// Editor : sublime text3, tab size (4)
// CopyRight(c) : All Rights Reserved
//
// *********************************************************************************
// Modification History:
// Date By Version Change Description
// -----------------------------------------------------------------------
// XXXX zhangningning 1.0 Original
//
// *********************************************************************************
module par2ser(
input clk_1x ,
input clk_5x ,
input rst_n ,
input [ 9:0] par_data ,
output wire ser_data_p ,
output wire ser_data_n
);
//========================================================================================\
//**************Define Parameter and Internal Signals**********************************
//========================================================================================/
wire shiftout1 ;
wire shiftout2 ;
wire ser_data ;
//========================================================================================\
//************** Main Code **********************************
//========================================================================================/
OBUFDS #(
.IOSTANDARD ("DEFAULT" ), // Specify the output I/O standard
.SLEW ("SLOW" ) // Specify the output slew rate
) OBUFDS_inst (
.O (ser_data_p ), // Diff_p output (connect directly to top-level port)
.OB (ser_data_n ), // Diff_n output (connect directly to top-level port)
.I (ser_data ) // Buffer input
);
OSERDESE2 #(
.DATA_RATE_OQ ("DDR" ), // DDR, SDR
.DATA_RATE_TQ ("DDR" ), // DDR, BUF, SDR
.DATA_WIDTH (10 ), // 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)
) OSERDESE2_inst_master (
.OFB ( ), // 1-bit output: Feedback path for data
.OQ (ser_data ), // 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_5x ), // 1-bit input: High speed clock
.CLKDIV (clk_1x ), // 1-bit input: Divided clock
// D1 - D8: 1-bit (each) input: Parallel data inputs (1-bit each)
.D1 (par_data[0] ),
.D2 (par_data[1] ),
.D3 (par_data[2] ),
.D4 (par_data[3] ),
.D5 (par_data[4] ),
.D6 (par_data[5] ),
.D7 (par_data[6] ),
.D8 (par_data[7] ),
.OCE (1'b1 ), // 1-bit input: Output data clock enable
.RST (~rst_n ), // 1-bit input: Reset
// SHIFTIN1 / SHIFTIN2: 1-bit (each) input: Data input expansion (1-bit each)
.SHIFTIN1 (shiftout1 ),
.SHIFTIN2 (shiftout2 ),
// 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
);
// End of OSERDESE2_inst instantiation
OSERDESE2 #(
.DATA_RATE_OQ ("DDR" ), // DDR, SDR
.DATA_RATE_TQ ("DDR" ), // DDR, BUF, SDR
.DATA_WIDTH (10 ), // 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 ("SLAVE" ), // 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)
) OSERDESE2_inst_slave (
.OFB ( ), // 1-bit output: Feedback path for data
.OQ ( ), // 1-bit output: Data path output
// SHIFTOUT1 / SHIFTOUT2: 1-bit (each) output: Data output expansion (1-bit each)
.SHIFTOUT1 (shiftout1 ),
.SHIFTOUT2 (shiftout2 ),
.TBYTEOUT ( ), // 1-bit output: Byte group tristate
.TFB ( ), // 1-bit output: 3-state control
.TQ ( ), // 1-bit output: 3-state control
.CLK (clk_5x ), // 1-bit input: High speed clock
.CLKDIV (clk_1x ), // 1-bit input: Divided clock
// D1 - D8: 1-bit (each) input: Parallel data inputs (1-bit each)
.D1 ( ),
.D2 ( ),
.D3 (par_data[8] ),
.D4 (par_data[9] ),
.D5 ( ),
.D6 ( ),
.D7 ( ),
.D8 ( ),
.OCE (1'b1 ), // 1-bit input: Output data clock enable
.RST (~rst_n ), // 1-bit input: Reset
// SHIFTIN1 / SHIFTIN2: 1-bit (each) input: Data input expansion (1-bit each)
.SHIFTIN1 ( ),
.SHIFTIN2 ( ),
// 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
);
endmodule
serdes原语的测试代码
`timescale 1ns / 1ps
`define CLOCK 20
//////////////////////////////////////////////////////////////////////////////////
// Company:
// Engineer:
//
// Create Date: 2020/02/23 14:23:39
// Design Name:
// Module Name: tb_par2ser
// Project Name:
// Target Devices:
// Tool Versions:
// Description:
//
// Dependencies:
//
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
//
//////////////////////////////////////////////////////////////////////////////////
module tb_par2ser;
reg clk_1x ;
reg clk_5x ;
reg rst_n ;
reg [ 9:0] par_data ;
wire ser_data_p ;
wire ser_data_n ;
initial begin
clk_1x = 1'b0;
clk_5x = 1'b0;
rst_n <= 1'b0;
#(100*`CLOCK)
rst_n <= 1'b1;
end
always #(`CLOCK/2) clk_1x = ~clk_1x;
always #(`CLOCK/8) clk_5x = ~clk_5x;
always @(posedge clk_1x or negedge rst_n)
if(rst_n == 1'b0)
par_data <= 10'b11_1111_1111;
else
par_data <= par_data - 1'b1;
par2ser par2ser_inst(
.clk_1x (clk_1x ),
.clk_5x (clk_5x ),
.rst_n (rst_n ),
.par_data (par_data ),
.ser_data_p (ser_data_p ),
.ser_data_n (ser_data_n )
);
endmodule
仿真代码没有任何难度,看一下便明白原理。
serdes原语的仿真结果
从上面图形中我们可以验证我们oserdes程序的正确性。
select_io的使用
上面的原语或许不是那么容易理解,那么我们同样完成上面的功能,通过使用IP来完成,该IP的名字叫做select_io,在vivado中调用对应的IP,如下
首先的界面设置如下:
第二个界面设置如下:
第三个默认即可
从上面的设置中我们可以发现是与原语的参数设置一致的。
select_io的测试代码
测试代码如下:
`timescale 1ns / 1ps
`define CLOCK 20
//////////////////////////////////////////////////////////////////////////////////
// Company:
// Engineer:
//
// Create Date: 2020/02/23 15:39:03
// Design Name:
// Module Name: tb_select_io
// Project Name:
// Target Devices:
// Tool Versions:
// Description:
//
// Dependencies:
//
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
//
//////////////////////////////////////////////////////////////////////////////////
module tb_select_io;
reg clk_1x ;
reg clk_5x ;
reg rst_n ;
reg [ 9:0] par_data ;
wire ser_data_p ;
wire ser_data_n ;
initial begin
clk_1x = 1'b0;
clk_5x = 1'b0;
rst_n <= 1'b0;
#(100*`CLOCK)
rst_n <= 1'b1;
end
always #(`CLOCK/2) clk_1x = ~clk_1x;
always #(`CLOCK/8) clk_5x = ~clk_5x;
always @(posedge clk_1x or negedge rst_n)
if(rst_n == 1'b0)
par_data <= 10'b11_1111_1111;
else
par_data <= par_data - 1'b1;
selectio_wiz_0 selectio_wiz_0_inst
(
.data_out_from_device (par_data ), // input [9:0] data_out_from_device
.data_out_to_pins_p (ser_data_p ), // output [0:0] data_out_to_pins_p
.data_out_to_pins_n (ser_data_n ), // output [0:0] data_out_to_pins_n
.clk_in (clk_5x ), // input clk_in
.clk_div_in (clk_1x ), // input clk_div_in
.io_reset (~rst_n ) // input io_reset
);
endmodule
测试结果
从测试结果上看,IP与原语的作用相同。
总结
创作不易,认为文章有帮助的同学们可以关注点赞支持。(工程也都在群中)对文章有什么看法或者需要更近一步交流的同学,可以加入下面的群:
上一篇: 【十九】Spark安装(standalone模式)
下一篇: vivado中coe文件的生成