文章目录
- 前言
- 一、SDR模式
- 1.1、设计代码
- 1.2、testbench代码
- 1.3、仿真分析
- 二、DDR模式下
- 2.1、设计代码
- 2.2、testbench代码
- 2.3、仿真分析
- 三、OSERDES2级联
- 3.1、设计代码
- 3.2、testbench代码
- 3.3、代码分析
前言
上文通过xilinx ug471手册对OSERDESE有了简单的了解,接下来通过仿真进一步深化印象。
一、SDR模式
1.1、设计代码
以下代码表示在SDR模式下对输入的4位宽并行数据进行并串转换。
module serdes_top(
input i_clk ,
input i_div_clk ,
input i_rst ,
input [3 :0] i_par_data ,
output o_ser_data
);
wire OFB;
OSERDESE2 #(
.DATA_RATE_OQ ("SDR" ), // 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 (1 ) // 3-state converter width (1,4)
)
OSERDESE2_inst (
.OFB (OFB ), // 1-bit output: Feedback path for data
.OQ (o_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 (i_clk ), // 1-bit input: High speed clock
.CLKDIV (i_div_clk ), // 1-bit input: Divided clock
// D1 - D8: 1-bit (each) input: Parallel data inputs (1-bit each)
.D1 (i_par_data[0] ),
.D2 (i_par_data[1] ),
.D3 (i_par_data[2] ),
.D4 (i_par_data[3] ),
.D5 (),
.D6 (),
.D7 (),
.D8 (),
// .D5 (i_par_data[4] ),
// .D6 (i_par_data[5] ),
// .D7 (i_par_data[6] ),
// .D8 (i_par_data[7] ),
.OCE (1'b1 ), // 1-bit input: Output data clock enable
.RST (i_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
);
1.2、testbench代码
以下为TB文件:
module serdes_sim();
localparam P_CLK_PERIOD = 40;
reg clk, div_clk , rst;
reg [3 :0] r_din;
wire w_ser_dout;
always begin
div_clk = 0;
#(P_CLK_PERIOD);
div_clk = 1;
#(P_CLK_PERIOD);
end
always begin
clk = 1;
#(P_CLK_PERIOD/4);
clk = 0;
#(P_CLK_PERIOD/4);
end
initial begin
rst = 1;
#100;
@(posedge clk);
rst = 0;
repeat(200) @(posedge clk);
$stop;
end
initial begin
r_din = 'd0;
data_gen();
end
serdes_top serdes_top_u0(
.i_clk (clk ),
.i_div_clk (div_clk ),
.i_rst (rst ),
.i_par_data (r_din ),
.o_ser_data (w_ser_dout )
);
task data_gen();
begin
r_din <= 'd0;
wait(!rst);
repeat(10) @(posedge div_clk);
r_din <= ({$random} % 16);
forever begin
@(posedge div_clk);
r_din <= ({$random} % 16);
end
end
endtask
endmodule
1.3、仿真分析
第一个并行数据为4’b0100,在蓝色刻度线处被采样,黄色刻度线开始输出,但是按照表中输出时延应该是3个CLK后开始输出,这是因为CLK和CLKDIV相位对齐,输出时延可以变化一个CLK,仿真结果显示是4个CLK,相比于表中描述多了一个CLK.
二、DDR模式下
2.1、设计代码
只需要修改位宽,输入D5-D8、以及并串转换模式即可。
module serdes_top(
input i_clk ,
input i_div_clk ,
input i_rst ,
input [7 :0] i_par_data ,
output o_ser_data
);
wire OFB;
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)
)
OSERDESE2_inst (
.OFB (OFB ), // 1-bit output: Feedback path for data
.OQ (o_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 (i_clk ), // 1-bit input: High speed clock
.CLKDIV (i_div_clk ), // 1-bit input: Divided clock
// D1 - D8: 1-bit (each) input: Parallel data inputs (1-bit each)
.D1 (i_par_data[0] ),
.D2 (i_par_data[1] ),
.D3 (i_par_data[2] ),
.D4 (i_par_data[3] ),
// .D5 (),
// .D6 (),
// .D7 (),
// .D8 (),
.D5 (i_par_data[4] ),
.D6 (i_par_data[5] ),
.D7 (i_par_data[6] ),
.D8 (i_par_data[7] ),
.OCE (1'b1 ), // 1-bit input: Output data clock enable
.RST (i_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
2.2、testbench代码
修改位宽以及产生随机数的大小即可。
module serdes_sim();
localparam P_CLK_PERIOD = 40;
reg clk, div_clk , rst;
reg [7 :0] r_din;
wire w_ser_dout;
always begin
div_clk = 0;
#(P_CLK_PERIOD);
div_clk = 1;
#(P_CLK_PERIOD);
end
always begin
clk = 1;
#(P_CLK_PERIOD/4);
clk = 0;
#(P_CLK_PERIOD/4);
end
initial begin
rst = 1;
#100;
@(posedge clk);
rst = 0;
repeat(200) @(posedge clk);
$stop;
end
initial begin
r_din = 'd0;
data_gen();
end
serdes_top serdes_top_u0(
.i_clk (clk ),
.i_div_clk (div_clk ),
.i_rst (rst ),
.i_par_data (r_din ),
.o_ser_data (w_ser_dout )
);
task data_gen();
begin
r_din <= 'd0;
wait(!rst);
repeat(10) @(posedge div_clk);
r_din <= ({$random} % 256);
forever begin
@(posedge div_clk);
r_din <= ({$random} % 256);
end
end
endtask
endmodule
2.3、仿真分析
蓝色刻度线处采样到并行输入数据,黄色刻度线开始输出,延时为4个CLK,与表中描述是一致的。
三、OSERDES2级联
当我们需要对10位或14位并行数据进行并串转换时,需要对OSERDSES2进行级联。本实验以10位输入数据并串转换为例进行说明。
3.1、设计代码
俩个OSERDESE2级联,修改位宽,添加从OSERDESE2,连接SHIFT引脚,修改位宽即可。
module serdes_top(
input i_clk ,
input i_div_clk ,
input i_rst ,
input [9 :0] i_par_data ,
output o_ser_data
);
wire OFB ;
wire w_shiftout1 ;
wire w_shiftout2 ;
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 (
.OFB (OFB ), // 1-bit output: Feedback path for data
.OQ (o_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 (i_clk ), // 1-bit input: High speed clock
.CLKDIV (i_div_clk ), // 1-bit input: Divided clock
// D1 - D8: 1-bit (each) input: Parallel data inputs (1-bit each)
.D1 (i_par_data[0] ),
.D2 (i_par_data[1] ),
.D3 (i_par_data[2] ),
.D4 (i_par_data[3] ),
.D5 (i_par_data[4] ),
.D6 (i_par_data[5] ),
.D7 (i_par_data[6] ),
.D8 (i_par_data[7] ),
.OCE (1'b1 ), // 1-bit input: Output data clock enable
.RST (i_rst ), // 1-bit input: Reset
// SHIFTIN1 / SHIFTIN2: 1-bit (each) input: Data input expansion (1-bit each)
.SHIFTIN1 (w_shiftout1 ),
.SHIFTIN2 (w_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
);
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_inst1 (
.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 (w_shiftout1 ),
.SHIFTOUT2 (w_shiftout2 ),
.TBYTEOUT ( ), // 1-bit output: Byte group tristate
.TFB ( ), // 1-bit output: 3-state control
.TQ ( ), // 1-bit output: 3-state control
.CLK (i_clk ), // 1-bit input: High speed clock
.CLKDIV (i_div_clk ), // 1-bit input: Divided clock
// D1 - D8: 1-bit (each) input: Parallel data inputs (1-bit each)
.D1 (),
.D2 (),
.D3 (i_par_data[8] ),
.D4 (i_par_data[9] ),
// .D5 (),
// .D6 (),
// .D7 (),
// .D8 (),
.D5 (),
.D6 (),
.D7 (),
.D8 (),
.OCE (1'b1 ), // 1-bit input: Output data clock enable
.RST (i_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
3.2、testbench代码
首先需要修改时钟信号,因为输入输出位宽10:1,在DDR模式下,时钟比为5:1,其次修改位宽以及随机数产生即可。
3.3、代码分析
蓝色刻度线处采样到并行输入数据,黄色刻度线开始输出,延时为4个CLK,表中描述延时应当为5个CLK,但此处CLK和DIVCLK是对齐的,所有导致了一个CLK的变化。