赞
踩
在LVDS学习笔记之 IDELAYE2应用及仿真中作者已说明高速接口为什么需要延时。根据tap的值可以进行数据位的微调,如果当clk和data信号延时较大时,仅仅使用IDELAYE2无法达到预期,此时ISERDESE2就派上用途。
ISERDESE2是专用的串并转换器,无需过多复杂的时序操作,并且其有sdr和ddr两种模式,很适合应用到高速源同步应用中。
下们对几个比较重要的端口进行阐述:
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属性
用来选择输出源,真值表如下图所示:
`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
`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
不知道是前面理解问题还是什么,仿真的结果跟我想象的不一样,可能是文档的某个细节没看到,如果读者有懂的,欢迎私信、留言,在此先谢过大家了。
仿真结果如下:
这里,我们只需要关心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文件里发送的数据改成其他的数据仿真以下。
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的第三个时钟数据才会改变,根据仿真图可以发现跟手册上有冲突。
懂的不是很多,本文可能有很多错误理解的地方,向各位大佬请教以下。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。