ISERDESE2是一种专用的串行到并行转换器,具有特定的时钟和逻辑功能,旨在促进高速源同步应用的实现。ISERDESE2避免了在FPGA结构中设计反序列化器时遇到的额外时序复杂性。
1、iserdes2原语概述
1.1 串-并转换功能
iserdes2支持SDR与DDR两种模式,在SDR模式下可以完成1bit到2-8bit的数据转换,在DDR模式下可以完成1bit到4bit、6bit、8bit以及通过两个iserdes2原语可以完成1ibt到10bit、14bit的串并转换(如图二)。
图1:iserdes2位宽
图2:iserdes2的10位与14位级联
注意:Slave模块中的Q1与Q2不可以作为级联的输出,在1bit转10bit的过程中使用Q3与Q4进行扩展、在1bit转10bit的过程中使用Q3-Q8这6位进行扩展。
1.2 slipbit模块的概述
在串并转换过程中很难避免的会出现传输错位导致采集到的数据出现错误,这是就需要用到slipbit模块进行数据校准。
slipbit是iserdes2原语中的一个输入,通过判断输出Q中的数据与校验和是否相同来判断数据是否相同,如果不同通过拉高一个时钟的slipbit进行移位操作,直到检测到数据校验和正确表明采集到的正确。
图3:slip_bit信号的变化情况
备注:图3中的q[7:0]数值移位不正确,是随机添加上去的数据,具体可以看vivado仿真情况。
SRD模式下8:1 输出每次有一个时钟的slipbit会对校验不正确的数据Q[7:0]进行循环左移,例如:1001_0011——>0010_0111。DDR模式下8:1输出每次有一个时钟的slipbit会对校验不正确的数据Q[7:0]进行循环右移1bit,然后左移3bit依次循环,例如0010_0111把最高移的1移到最低位变成了0010_0111——>1001_0011(右移1bit)——>1001_1110(左移3bit)
图4:SDR与DDR 8:1模式移位方式
2、iserdes原语引脚介
iserdes2原语包含引脚
图5:iserdes2引脚框图
具体引脚说明 :
2.1 BITSLIP(input)
通过拉高BITSLIP重新排序输出信号,BITSLIP只需要拉高一个时钟(CLK_DIV),完成移位操作后,如果校验和与输入还是不通,再次拉高,直到校验和正确,来保证采集到的数据正确。
图6:DDR Bitslip 时序图
DDR 模式Bitslip信号变高后有三个CLK_DIV的延时,SDR 模式Bitslip号变高后有两个CLK_DIV的延时。
2.2 CE1、CE2(input)![](https://img-blog.csdnimg.cn/direct/546030b39f8e44959a5929c85408f189.png)
图7: 时钟使能引脚
CE1和CE2引脚用来作为时钟使能的时钟源,通过属性 NUM_CE来选择。当 NUM_CE=1时使用CE1作为时钟使能信号;当 NUM_CE=2时,在CLKDIV=0时使用CE2R,在CLKDIV=1时使用CE1R作为时钟使能信号。
2.3 时钟引脚
2.3.1、clk(input)与clkdiv(input)
clk串行数据输入时钟,clkdiv并行输出数据时钟,保证clk与clkdiv没有相位差,即可以通过PLL生成它们。
SDR模式8:1传输clk=400M,clkdiv=50M , DDR模式8:1传输clk=400M,clkdiv=100M
图8: 时钟使能引脚
2.3.2、CLKB(input)
在MEMORY_QDR以外的任何模式下,将CLKB连接到CLK的反转,在MEMORY_QDR模式下,CLKB应该连接到一个唯一的相移时钟。
2.3.3、OCLK(input)、OCLKB(input)
在iserdes模式MEMORY, MEMORY_DDR3, MEMORY_QDR, NETWORKING, OVERSAMPLE中只用MEMORY使用,其他模式接地就可以。
2.2.4、OCLKDIVP(input)
在MEMORY_DDR3模式使用,其他模式接地。
2.4 DYNCLKSEL (input)and DYNCLKDIVSEL(input)
在MEMORY、MEMORY_DDR3模式使用。
2.5 D(input)与DDLYA(input)
图9:输入模式设置
D与DDLYA都是iserdes2的输入引脚,通过配置IOBDELAY Value的模式来选择输入的引脚。
2.6 OFB(input)
在oserdes2的信号输入到iserdes2下使用,使用是需要将ISERDES2中的OFB_USED设置为TURE
图10:OFB使用连接方式
2.7 RST(input)
复位引脚,高电平复位,最好与CLKDIV同步,来保证ISERDES2同步复位成功。
2.8 Q1-Q8(output)
iserdes2的输出引脚。
2.9 SHIFTIN1、SHIFTIN2、SHIFTOUT1、SHIFTOUT2
传输位宽为10bit或者14bit时、将iserdes2(Slave)的SHIFTIN1、SHIFTIN2连接iserdes2(master)中的SHIFTOUT1、SHIFTOUT2(如图2)
3 、ISERDES2原语属性介绍
在使用ISERDES2是需要配置其中的一些属性,下边对其做一些简单的描述
3.1 DATA_RATE
配置数据流传输模式:SDR或者DDR,默认配置为DDR
3.2 DATA_WIDTH
配置数据位宽:1)、DATA_RATE为DDR可以配置为4、6、8、10、14。2)、DATA_RATE为SDR可以配置2、3、4、5、6、7、8。默认值为4
3.3 DYN_CLKDIV_INV_EN
配置CLKDIV时钟翻转使能,在MEMORY、MEMORY_DDR3模式使用,默认值为FALSE。
3.4 DYN_CLK_INV_EN
配置CLK与CLKB时钟翻转使能,在MEMORY、MEMORY_DDR3模式使用,默认值为FALSE。
3.5 INTERFACE_TYPE
模式配置,可配置模式为MEMORY, MEMORY_DDR3,MEMORY_QDR,NETWORKING,默认值为FALSE。一般使用NETWORKING。
3.6 NUM_CE
CE1、CE2使能配置,默认值为2。
3.7 OFB_USED
OSERDES2与ISERDES2级联配置,配置为TURE后可以将OSERDES2的输出引脚OFB与ISERDES2的输入引脚OFB进行数据传输。默认值为FALSE
3.8 SERDES_MODE
ISERDES2主从模式配置,默认为Master,只有DDR模式的10:1或者14:1是用到Slave,默认配置Master。
3.9 INIT_Q1-INIT_Q4
初始化第一个到第四个寄存器的值,默认为0,默认即可。
3.10 SRVAL_Q1-SRVAL_Q4
复位以后第一个到第四个寄存器的值,默认为0,默认即可。
3.11 IOBDELAY
配置D与DDLYA的模式、可配置为NONE、IBUF, IFD、BOTH,具体如图9,默认为NONE,默认即可,其他情况目前还没用到。
4、程序设计与仿真
在数据为方便测试文件编写,将OSERDES2与ISERDES2级联,如图10所示。本文采用数据8’h32与8'h8c作为一组校验和,一共使用了32组校验和与随机数组成一组包文,将该包文发送到OSERDES2原语进行并串转换,然后将数据发送到ISERDES2模块。
图11 :VIVADO Schematic
module top(
input sys_clk ,
input rst_n ,
output o_iserdese2_vld ,
output [7:0] o_iserdese2
);
wire rst_wire ;
wire clk_wiz_0 ;
wire clk ;
wire clk_div ;
wire oserdese_ofb;
wire locked ;
wire flag_wire ;
clk_wiz_0 u_clk_wiz_0(
.clk_out1 ( clk_div ),//output clk_out1
.clk_out2 ( clk ),//output clk_out2
.reset ( ~rst_n ),//input reset
.locked ( locked ),
.clk_in1 ( sys_clk ) //input clk_in1
);
assign rst_wire = rst_n==0;
//例化并串转换原语;
oserdese2_ctrl u_oserdese2_ctrl(
.clk ( clk ), //系统时钟信号;
.clk_div ( clk_div ),
.rst ( rst_wire ), //系统复位信号,高电平有效;
.ofb ( oserdese_ofb ),
.o_cheeksum_flag ( flag_wire ),
.cheek_sum_first ( 8'h32 ), //校验和
.cheek_sum_secord( 8'h8c )
);
iserdese2_ctrl u_iserdese2_ctrl(
.clk ( clk ),//系统时钟信号;
.clk_div ( clk_div ),
.rst ( rst_wire ),//系统复位信号,高电平有效;
.ofb ( oserdese_ofb ),
.dout ( o_iserdese2 ),//输出数据
.dout_vld ( o_iserdese2_vld ), //输出数据有效指示信号;
.i_cheeksum_flag (flag_wire ),
.cheek_sum_first ( 8'h32 ), //校验和
.cheek_sum_secord( 8'h8c )
);
endmodule
4.1 clk_wiz_0 模块
本文采用DDR模式8:1输出传输,系统时钟为50M,通过PLL模块生成CLK=200M,CLKDIV=50M。
图12:CLK(200M)与CLKDIV(50M)
4.2 oserdese2_ctrl
module oserdese2_ctrl(
input clk ,
input clk_div ,
input rst ,
input [7:0] cheek_sum_first , //校验和
input [7:0] cheek_sum_secord, //校验和
output ofb ,
output o_cheeksum_flag
);
parameter PACKAGE_NUM = 32 ; //校验和长度
reg o_cheeksum_flag ;
reg [7:0] cnt ;
reg [7:0] din ;
wire add_cnt ;
wire end_cnt ;
reg [5:0] cnt ;
reg [7:0] cnt_package ;
//校验和发送完成标志位;
always@(posedge clk_div)begin
if(rst)begin
o_cheeksum_flag <= 1'b0;
end
else if(cnt_package==PACKAGE_NUM-1)begin
o_cheeksum_flag <= 1'b1;
end
end
always@(posedge clk_div)begin
if(rst)begin
cnt <= 0;
end
else if(add_cnt)begin
if(end_cnt)begin
cnt <= 0;
end
else begin
cnt <= cnt + 1;
end
end
end
assign add_cnt = !o_cheeksum_flag ;
assign end_cnt = add_cnt && cnt == 2-1 ;
//校验头计数器计算头部长度
always @(posedge clk_div or posedge rst)begin
if(rst)begin
cnt_package <= 0;
end
else if(cnt_package==PACKAGE_NUM-1)begin
cnt_package <= cnt_package;
end
else if(end_cnt)begin
cnt_package <= cnt_package + 1;
end
end
//校验头部{7C,82}与数据拼接;
always@(posedge clk_div or posedge rst)begin
if(rst)begin
din <= cheek_sum_first;
end
else if(cnt_package==PACKAGE_NUM-1)begin//如果校准序列发送完毕,则发送随机信号用于测试。
din <= {(din[0] ^ din[4] ^ din[5] ^ din[6]),din[7:1]};//M序列公式为x^8+x^4+x^3+x^2+1。
end
else if(cnt==1-1)begin//发送校准序列8'h5c;
din <= cheek_sum_first;
end
else if(cnt==2-1)begin//发送校准序列8'h82.
din <= cheek_sum_secord;
end
end
//例化OSERDESE2原语
OSERDESE2 #(
.DATA_RATE_OQ ( "DDR" ),// 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)
)
OSERDESE2_inst (
.OFB ( 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 ( ),
.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 ( din[0] ),
.D2 ( din[1] ),
.D3 ( din[2] ),
.D4 ( din[3] ),
.D5 ( din[4] ),
.D6 ( din[5] ),
.D7 ( din[6] ),
.D8 ( din[7] ),
.OCE ( 1'b1 ),// 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 ( ),
.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
OSERDES2仿真
图13:OSERDES2仿真
如上图中din在clk_div上升沿采集到的数是8’h8c(8'b1000_1100),经过四个clk的延时(DDR模式8:1采样延时,如图14OSERDES2采集延时)后采集串行数据线ofb上的数为8‘b0011_0001,这个数是8’h8c的从高到低0011_0001,因此采用到的ofb数据正确。
4.3 iserdese2_ctrl
module iserdese2_ctrl(
clk ,
clk_div ,
rst ,
ofb ,
cheek_sum_first , //校验和
cheek_sum_secord , //校验和
i_cheeksum_flag ,
dout ,
dout_vld
);
parameter CNT_NUM = 5'd16 ;
input clk ;
input clk_div ;
input rst ;
input ofb ;
input i_cheeksum_flag ;
input [7:0] cheek_sum_first ;
input [7:0] cheek_sum_secord;
output [7:0] dout ;
output dout_vld ;
reg bitslip ;
reg slip_flag ;
wire add_cnt ;
reg [4:0] cnt ;
wire [7:0] dout ;
reg dout_vld ;
wire [7:0] q ;
reg flag_cheek ;
reg [2:0] slip_cnt ;
wire add_cnt_slip ;
wire end_cnt_slip ;
reg [2:0] cnt_shift ;
wire add_cnt_shift ;
wire end_cnt_shift ;
//例化ISERDESE2原语
ISERDESE2 #(
.DATA_RATE ( "DDR" ),// DDR, SDR
.DATA_WIDTH ( 8 ),// Parallel data width (2-8,10,14)
.DYN_CLKDIV_INV_EN ( "FALSE" ),// Enable DYNCLKDIVINVSEL inversion (FALSE, TRUE)
.DYN_CLK_INV_EN ( "FALSE" ),// Enable DYNCLKINVSEL inversion (FALSE, TRUE)
.INIT_Q1 ( 1'b0 ),// INIT_Q1 : Initial value on the Q outputs (0/1)
.INIT_Q2 ( 1'b0 ),// INIT_Q2 : Initial value on the Q outputs (0/1)
.INIT_Q3 ( 1'b0 ),// INIT_Q3 : Initial value on the Q outputs (0/1)
.INIT_Q4 ( 1'b0 ),// INIT_Q4 : Initial value on the Q outputs (0/1)
.INTERFACE_TYPE ( "NETWORKING" ),// MEMORY, MEMORY_DDR3, MEMORY_QDR, NETWORKING, OVERSAMPLE
.IOBDELAY ( "NONE" ),// NONE, BOTH, IBUF, IFD
.NUM_CE ( 2 ),// Number of clock enables (1,2)
.OFB_USED ( "TRUE" ),// Select OFB path (FALSE, TRUE)
.SERDES_MODE ( "MASTER" ),// MASTER, SLAVE
.SRVAL_Q1 ( 1'b0 ),// SRVAL_Q1 : Q output values when SR is used (0/1)
.SRVAL_Q2 ( 1'b0 ),// SRVAL_Q2 : Q output values when SR is used (0/1)
.SRVAL_Q3 ( 1'b0 ),// SRVAL_Q3 : Q output values when SR is used (0/1)
.SRVAL_Q4 ( 1'b0 ) // SRVAL_Q4 : Q output values when SR is used (0/1)
)
ISERDESE2_inst (
.O ( ),// 1-bit output: Combinatorial output
.Q1 ( q[7] ),// Q1 - Q8: 1-bit (each) output: Registered data outputs
.Q2 ( q[6] ),
.Q3 ( q[5] ),
.Q4 ( q[4] ),
.Q5 ( q[3] ),
.Q6 ( q[2] ),
.Q7 ( q[1] ),
.Q8 ( q[0] ),
.SHIFTOUT1 ( ),// SHIFTOUT1 : 1-bit (each) output: Data width expansion output ports
.SHIFTOUT2 ( ),// SHIFTOUT2 : 1-bit (each) output: Data width expansion output ports
.BITSLIP ( bitslip ),// 1-bit input: The BITSLIP pin performs a Bitslip operation synchronous to
// CLKDIV when asserted (active High). Subsequently, the data seen on the Q1
// to Q8 output ports will shift, as in a barrel-shifter operation, one
// position every time Bitslip is invoked (DDR operation is different from SDR).
.CE1 ( 1'b1 ),// CE1: 1-bit (each) input: Data register clock enable inputs
.CE2 ( 1'b1 ),// CE2: 1-bit (each) input: Data register clock enable inputs
.CLKDIVP ( 1'b0 ),// 1-bit input: TBD
// Clocks: 1-bit (each) input: ISERDESE2 clock input ports
.CLK ( clk ),// 1-bit input: High-speed clock
.CLKB ( ~clk ),// 1-bit input: High-speed secondary clock
.CLKDIV ( clk_div ),// 1-bit input: Divided clock
.OCLK ( 1'b0 ),// 1-bit input: High speed output clock used when INTERFACE_TYPE="MEMORY"
// Dynamic Clock Inversions: 1-bit (each) input: Dynamic clock inversion pins to switch clock polarity
.DYNCLKDIVSEL(1'b0 ),// 1-bit input: Dynamic CLKDIV inversion
.DYNCLKSEL ( 1'b0 ),// 1-bit input: Dynamic CLK/CLKB inversion
// Input Data: 1-bit (each) input: ISERDESE2 data input ports
.D ( 1'b0 ),// 1-bit input: Data input
.DDLY ( 1'b0 ),// 1-bit input: Serial data from IDELAYE2
.OFB ( ofb ),// 1-bit input: Data feedback from OSERDESE2
.OCLKB ( 1'b0 ),// 1-bit input: High speed negative edge output clock
.RST ( rst ),// 1-bit input: Active high asynchronous reset
// SHIFTIN1, SHIFTIN2: 1-bit (each) input: Data width expansion input ports
.SHIFTIN1 ( ),
.SHIFTIN2 ( )
);
//当没有完成校准时,如果检测到转换结果与要求不一致,则把该信号拉高。
always@(posedge clk_div or posedge rst)begin
if(rst)begin
bitslip <= 1'b0;
end//当没有校准,且没有处于校准阶段时检测到串并转换结果不为8'h32或者8'h8c时拉高;
else if(((q != cheek_sum_first) && (q != cheek_sum_secord)) && (~slip_flag) && (~bitslip) && (~dout_vld))begin
bitslip <= 1'b1;
end
else begin
bitslip <= 1'b0;
end
end
//滑块计数器,因为bitslip拉高后,输出需要经过一段时间才会有效,因此这段时间不能对输出数据进行读取判断。
always@(posedge clk_div or posedge rst)begin
if(rst)begin
slip_cnt <= 1'b0;
end
else if(add_cnt_slip)begin
if(end_cnt_slip)begin
slip_cnt <= 1'b0;
end
else begin
slip_cnt <= slip_cnt + 1'd1;
end
end
end
assign add_cnt_slip = slip_flag ;
assign end_cnt_slip = add_cnt_slip && slip_cnt == 4-1;
//bitslip拉高后的标志信号,初始值为0,当bitslip拉高时拉高,当slip_cnt计数器计数到最大值时清零。
always@(posedge clk_div or posedge rst)begin
if(rst)begin
slip_flag <= 1'b0;
end
else if(bitslip)begin
slip_flag <= 1'b1;
end
else if(end_cnt_slip)begin
slip_flag <= 1'b0;
end
end
//转换成功计数器,用于记录校准阶段,当校准阶段检测到固定个连续有效数据时,认为校准成功。
always@(posedge clk_div or posedge rst)begin
if(rst)begin//
cnt <= 0;
end//当在校准阶段时,当bitslip有效时拉高;
else if((slip_flag || bitslip) && (~dout_vld))begin
cnt <= 0;
end
else if(cnt == CNT_NUM - 1)begin//当检测到固定校准数据时,计数器保持该数值。
cnt <= CNT_NUM - 1;
end
else if(add_cnt)begin
cnt <= cnt + 1;
end
end
//当不处于移动滑块状态且检测到输出数据为规定数据时加1.
assign add_cnt = ((q == cheek_sum_first) || (q == cheek_sum_secord)) && (~slip_flag) && (~bitslip) && (cnt != (CNT_NUM - 1));
//将转换后的数据输出,只有当校准完成后,输出有效指示信号磁能拉高,表示输出的数据有效。
always@(posedge clk_div or posedge rst)begin
if(rst)begin
dout_vld <= 0;
end
else begin
dout_vld <= end_cnt_shift;
end
end
assign dout = q;
always@(posedge clk_div or posedge rst)begin //oserdese2采用的DDR(8:1)模式,它有4个CLK_DIV的延时
if(rst)begin
cnt_shift <= 0;
end
else if(add_cnt_shift)begin
if(end_cnt_shift)begin
cnt_shift <= cnt_shift ;
end
else begin
cnt_shift <= cnt_shift + 1;
end
end
end
assign add_cnt_shift = i_cheeksum_flag && flag_cheek ;
assign end_cnt_shift = add_cnt_shift && cnt_shift == 4-1 ;//CLK_DIV的延时计数
always@(posedge clk_div or posedge rst)begin
if(rst)begin
flag_cheek <= 1'd0;
end
else if(cnt == CNT_NUM - 1)begin//对bitslip拉高后的时钟计数。
flag_cheek <= 1'd1;
end
end
endmodule
ISERDES2仿真
图14 :ISERDES2仿真
在OSERDES2中输入32个{8'h32,8'h8c}后的数据是8'h46、8'ha3、8'ha3、8'h51、8'ha8、8'hd4,在ISERDES2中采集到的数据在dout_vld为高电平是也是8'h46、8'ha3、8'ha3、8'h51、8'ha8、8'hd4,因此,ISERDES2模块设计正确。
说明:本文是ISERDES2使用过程中的一些总结,可能不是完全正确,仅供参考。