文章目录
- 系列文章目录
- 为什么要学ISERDESE2
- 一、ISERDESE2原语
- 1.ISERDESE2端口说明
- 2.ISERDESE2属性说明
- 二、ISERDESE2工程代码
- 1.工程代码
- 2.测试代码
- 三、ISERDESE2仿真
- 1.不带Bitslip的仿真
- 2.带Bitslip的仿真
为什么要学ISERDESE2
在LVDS学习笔记之 IDELAYE2应用及仿真中作者已说明高速接口为什么需要延时。根据tap的值可以进行数据位的微调,如果当clk和data信号延时较大时,仅仅使用IDELAYE2无法达到预期,此时ISERDESE2就派上用途。
ISERDESE2是专用的串并转换器,无需过多复杂的时序操作,并且其有sdr和ddr两种模式,很适合应用到高速源同步应用中。
一、ISERDESE2原语
上图为ISERDESE2例化框图。ISERDESE2是FPGA的一个专用的串并联转换器,具有特定的时钟和逻辑特性,旨在促进高速源同步应用的实现。iserdes2避免了在FPGA结构中设计反序列化器时遇到的额外时序复杂性。其具有以下应用:
- 专用解串器/串并转换器:
该转换器支持单数据速率(SDR)和双数据速率(DDR)模式。在SDR模式下,串并联转换器创建一个2-、3-、4-、5-、6-、7-或8位宽并行字。在DDR模式下,当使用一个ISERDESE2时,串并联转换器创建4、6、8位宽的并行字模式,当使用两个级联时创建10或14位宽的并行字模式 - Bitslip 子模块:
Bitslip子模块允许设计人员重新排列进入FPGA结构的并行数据流的序列。这可以用于训练包含训练模式的源同步接口。 - 专用内存接口
ISERDESE2包含专用电路(包括OCLK输入引脚),在ISERDESE2块中完全处理频闪到fpga的时钟域交叉,更利于提高性能和简化设计。 - 支持网络接口、DDR3接口、QDR接口、异步接口。
1.ISERDESE2端口说明
下们对几个比较重要的端口进行阐述:
- 寄存器输出端口 Q1到Q8
Q1到Q8是ISERDESE2模块的并行输出端口,一个ISERDESE2块可支持8bits输出,在DDR模式下宽度最多支持14bits。接收的第一位在Q的最高为出现,如下图所示:
OSERDESE2要输出的串行数据从高到低位为[H G F E D C B A],当这些串行数据传输到ISERDESE2的输入端D后,首先进入ISERDESE2的是A,此时在Q1输出,紧接着进入B,ISERDESE2内部的移为寄存器会将A推向Q2,B从Q1输出,以此类推,最终输出的数据为[A B C D E F G H]。原来最高位变成了现在的最低位,这也是为什么ISERDESE2作为反序器的原因。 - 组合输出端口 O
组合输出端口O在ISERDESE2模块中是一个没有寄存器的输出,这个数据会根据数据输入端口(D)或者延时数据输入端口(DDLY)的值输出。 - BITSLIP
若在CLKDIV上升沿检测到BITSLIP引脚为高时,会执行一次bit位流动操作,随后输出端口Q1-Q8会移位。
上图分别为在SDR模式和DDR模式下BITSLIP的操作。
SDR模式下:每次的BITSLIP操作,会使输出左移1位;当8次操作后,恢复到最初状态;
DDR模式下:每次的BITSLIP操作,会使输出交替进行右移1位和左移3位操作,当8次操作后,恢复到最初状态;
上图为DDR模式下BITSLIP的时序图:
在1时刻:Bitslip不为高,此时Q4到Q1输出为CDAB;
在2时刻:Bitslip在CLKDIV的上升沿保持了一个时钟周期的高电平,触发了右移一位的操作;
在3时刻:经历了3个时钟周期,完成右移一位的操作,此时Q4到Q1输出BCDA。 - 时钟使能输入 CE1和CE2
CE1和CE2引脚用来作为时钟使能的时钟源,通过属性 NUM_CE来选择。当 NUM_CE=1时使用CE1作为时钟使能信号;当 NUM_CE=2时,在CLKDIV=0时使用CE2R,在CLKDIV=1时使用CE1R作为时钟使能信号。 - 高速时钟输入 CLK
该时钟用于对输入的串行数据流进行处理。 - 高速时钟输入 CLKB
该时钟用于对输入的串行数据流进行处理。CLKB连接到CLK的反相端, MEMORY_QDR模式除外。 - 分频时钟输入 CLKDIV
分频时钟CLKDIV是由CLK分频得到的,它驱动串并联转换器、Bitslip子模块和CE模块的输出。 - 来自IOB的串行输入数据 D
串行输入数据端口(D)是一个高速的数据输入端口。 - 来自IDELAYE2的串行输入数据 DDLY
串行输入数据端口(DDLY)是一个高速的数据输入端口。 - 来自OSERDESE2的串行输入数据 OFB
串行输入数据端口(OFB)是一个高速的数据输入端口。 - 用于频闪灯内存接口和过采样模式的高速时钟 OCLK
- 复位输入 RST
2.ISERDESE2属性说明
- DATA_RATE属性
选择数据输入模式,单倍速率模式(SDR),双倍速率模式(DDR)。 - DATA_WIDTH属性
DATA_WIDTH属性定义串并行转换器的并行数据输出宽度。此属性的可能值取决于INTERFACE_TYPE和DATA_RATE属性。 - 当DATA_WIDTH设置为大于8的宽度时,一对ISERDESE2必须配置为主从配置。
- INTERFACE_TYPE属性
INTERFACE_TYPE属性决定了ISERDESE2是在内存模式还是网络模式下配置的。这个属性允许的值是MEMORY,MEMORY_DDR3、MEMORY_QDR、OVERSAMPLE或NETWORKING。 - NUM_CE 属性
用来选择时钟使能源。 - SERDES_MODE属性
当使用宽度扩展时,SERDES_MODE属性定义了ISERDESE2模块是主从模块还是从模块。 - IOBDELAY属性
用来选择输出源,真值表如下图所示:
二、ISERDESE2工程代码
1.工程代码
`timescale 1ns / 1ps
module ISERDESE2_TEST(
input clk_in_50 ,
input reset ,
input BITSLIP ,
input D ,
output [7:0] Q ,
output O
);
wire clk_200 ;
wire clk_100 ;
wire clk_50 ;
wire clk_25 ;
wire locked ;
wire CLK ;
wire sys_rest ; //高有效
wire RST ;
assign sys_rest = locked? reset:1'b1;
assign RST = sys_rest;
assign CLK = clk_200;
assign CLKB = ~CLK;
assign CLKDIV = clk_25;
clk_wiz_0
clk_wiz_0_inst
(
.clk_200m (clk_200 ),
.clk_100m (clk_100 ),
.clk_50m (clk_50 ),
.clk_25m (clk_25 ),
.reset (reset ),
.locked (locked),
.clk_in1 (clk_in_50)
);
ISERDESE2 #(
.DATA_RATE("SDR"), // 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 - INIT_Q4: Initial value on the Q outputs (0/1)
.INIT_Q1(1'b0),
.INIT_Q2(1'b0),
.INIT_Q3(1'b0),
.INIT_Q4(1'b0),
.INTERFACE_TYPE("NETWORKING"), // MEMORY, MEMORY_DDR3, MEMORY_QDR, NETWORKING, OVERSAMPLE
.IOBDELAY("NONE"), // NONE, BOTH, IBUF, IFD
.NUM_CE(1), // Number of clock enables (1,2)
.OFB_USED("FALSE"), // Select OFB path (FALSE, TRUE)
.SERDES_MODE("MASTER"), // MASTER, SLAVE
// SRVAL_Q1 - SRVAL_Q4: Q output values when SR is used (0/1)
.SRVAL_Q1(1'b0),
.SRVAL_Q2(1'b0),
.SRVAL_Q3(1'b0),
.SRVAL_Q4(1'b0)
)
ISERDESE2_inst (
.O(O), // 1-bit output: Combinatorial output
// Q1 - Q8: 1-bit (each) output: Registered data outputs
.Q1(Q[0]),
.Q2(Q[1]),
.Q3(Q[2]),
.Q4(Q[3]),
.Q5(Q[4]),
.Q6(Q[5]),
// .Q7(Q[6]),
.Q8(Q[7]),
// SHIFTOUT1, SHIFTOUT2: 1-bit (each) output: Data width expansion output ports
.SHIFTOUT1(),
.SHIFTOUT2(),
.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, CE2: 1-bit (each) input: Data register clock enable inputs
.CE1(1'b1),
.CE2(1'b0),
.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(CLKB), // 1-bit input: High-speed secondary clock
.CLKDIV(CLKDIV), // 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(D), // 1-bit input: Data input
.DDLY(1'b0), // 1-bit input: Serial data from IDELAYE2
.OFB(1'b0), // 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()
);
// End of ISERDESE2_inst instantiation
endmodule
2.测试代码
`timescale 1ns / 1ps
`define clk_period 20
`define clk_data_period 5
module ISERDESE2_TEST_tb( );
reg clk_in_50 ;
reg reset ;
reg BITSLIP ;
reg D ;
wire [7:0] Q ;
wire O ;
ISERDESE2_TEST
ISERDESE2_TEST_inst
(
.clk_in_50 (clk_in_50 ),
.reset (reset ),
.BITSLIP (BITSLIP ),
.D (D ),
.Q (Q ),
.O (O )
);
initial begin clk_in_50 =0; end
always #(`clk_period/2) clk_in_50=~clk_in_50;
initial begin
// no_bitslip_task;
bitslip_task;
$stop;
end
task init;
begin
reset =1;
BITSLIP =0;
D =0;
#(`clk_period*2);
reset =0;
@(posedge ISERDESE2_TEST_inst.locked);
#(`clk_period*2+3);
end
endtask
task no_bitslip_task;
begin
init;
@(posedge ISERDESE2_TEST_inst.CLKDIV);
#37.5;
repeat(10)begin
gen_ser_data(8'h5a);
end
#(`clk_period*10);
end
endtask
task bitslip_task;
begin
init;
@(posedge ISERDESE2_TEST_inst.CLKDIV);
#37.5;
repeat(5)begin
repeat(10)begin
gen_ser_data(8'h5a);
end
BITSLIP = 1;
gen_ser_data(8'h5a);
BITSLIP = 0;
end
repeat(20)begin
gen_ser_data(8'h5a);
end
end
endtask
task gen_ser_data;
input [7:0] data;
reg [7:0] i;
begin
for(i=0;i<8;i=i+1)begin
D = data[0];
data = {1'b0,data[7:1]};
#(`clk_data_period);
end
D = 0;
end
endtask
endmodule
三、ISERDESE2仿真
1.不带Bitslip的仿真
不知道是前面理解问题还是什么,仿真的结果跟我想象的不一样,可能是文档的某个细节没看到,如果读者有懂的,欢迎私信、留言,在此先谢过大家了。
仿真结果如下:
这里,我们只需要关心CLK、CLKDIV、D、Q信号。一开始仿真的时候对于CLKDIV和CLK的关系,我一直没搞懂,后面才发现他们的关系。他们跟DDR或SDR的模式以及数据长度有关,为f_CLK/bit_NUM/模式,比如,我这里采用的SDR模式,8bit数据长度,CLK使用的是200M,CLKDIV的时钟为(200/8/1)=25M。若采用的是DDR模式,8bit数据长度,CLK是200M,则CLKDIV的时钟为(200/8/2)=12.5M。
最开始我认为在每个CLKDIV内,根据CLK的上升沿进行采样(DDR模式下为CLK的双沿采样),我发送的数据为(01011010),单实际Q段得到的却是最开始得到8’h02,后面稳定在8’hd2,将这两个拼在一块得到(0000_0010_1101_0010)。可以发现,黄色字体跟我们发送的一致。因此,我有个大胆的想法,是不是在第3个CLK时钟才开始采样,是不是应该这样看:
后来,我根据官方自带的仿真也是这样,从结果上看,第三个时钟才开始采样,可能是我有误解,有知道的大佬给小弟解惑。
还有一点要注意的是,我这里发送的数据比较特殊,我发送的是01011010,正序和倒序都是一样。ISERDESE2输出的的倒序,最先进入采样的点在Q的最高位。有感兴趣的小伙伴可以将TB文件里发送的数据改成其他的数据仿真以下。
2.带Bitslip的仿真
Bitslip是在CLKDIV控制下运行的,因此Bitslip的一个高脉冲要与CLKDIV的时钟周期相同,具体仿真结果如下:
由上图可发现,最开始Q端输出为(1101_0010),在一次Bitslip脉冲后,Q端输出变为(1010_0101),Q左移了一位。当Bitslip在次来时,Q端输出变为(0100_1011),Q又左移了一位,连续5次后得到了我想输入的值0x5A(0101_1010)。
前文也对DDR模式下Bitslip的操作做了说明,那个是官方手册上的,上面说在Bitslip到来后的CLKDIV的第三个时钟数据才会改变,根据仿真图可以发现跟手册上有冲突。