// IODDR 回环 ,使用 SAME_EDGE 模式,注意的是 从 ODDR输出 时钟需要偏移90度,不然数据 上下沿采样错误
// 数据从 IDDR 输出时,最好将 数据和 frame 有效信号 同步在偏移90度的时钟下
// 本测试内容 是 50MHZ 的 8bit (1~126) 数据进入 IDDR – ODDR 输出。 IDDR 和 ODDR 时钟 200MHZ
后续研究 OPPOSITE_EDGE 模式。
代码没有进行优化
大家自行参考
`timescale 1ns / 1ps// IODDR 回环 ,使用 SAME_EDGE 模式,注意的是 从 ODDR输出 时钟需要偏移90度,不然数据 上下沿采样错误
// 数据从 IDDR 输出时,最好将 数据和 frame 有效信号 同步在偏移90度的时钟下
// 本测试内容 是 50MHZ 的 8bit (1~126) 数据进入 IDDR -- ODDR 输出。 IDDR 和 ODDR 时钟 200MHZmodule IODDR(input i_clk_50m ,input i_clk_200m,input i_rst
);wire w_data_o ;
wire w_data_valid_o ;
wire locked;
wire frame_h ;
wire frame_l ;
wire data_pin ;
wire data_nin ;reg [7:0] r_cnt ;
reg r_valid ;
reg [7:0] r_data_i ;
reg datain_n ;
reg datain_p ;
reg r_data_pin ;
reg r_data_nin ;
reg [3:0] r_read_cnt ;
reg [7:0] r_dataout ;
reg [1:0] r_shift_data ;
reg r_data_valid_1d;
reg r_data_valid_2d;
reg [3:0] r_read_cnt_1d ;
reg [3:0] r_read_cnt_2d ;
reg [7:0] r_final_data ;
reg r_final_valid ;
reg r_data_valid ;
reg [1:0] r_frame_cnt ;clk_wiz_0 clk_wiz_u0(// Clock out ports.clk_out1(clk_out1), // output clk_out1// Status and control signals.locked(locked), // output locked// Clock in ports.clk_in1(i_clk_200m)); always @ (posedge i_clk_50m )
beginif (i_rst || ~locked)r_valid <= 0;else if (r_cnt == 128 - 1)r_valid <= 0; else if (r_cnt == 1)r_valid <= 1; elser_valid <= r_valid;
endalways @ (posedge clk_out1 )
beginr_data_valid <= frame_h;r_data_valid_1d <= r_data_valid;
endalways @ (posedge i_clk_50m )
beginif (i_rst || ~locked)r_cnt <= 0;else if (r_cnt == 256 -1)r_cnt <= 0; elser_cnt <= r_cnt + 1;
endalways @ (posedge i_clk_50m)
beginr_data_i <= r_cnt ;
/* if (i_rst || ~locked)r_data_i <= 0;else if (r_cnt == 1)r_data_i <= 8'b10101010;else if (r_cnt == 2)r_data_i <= 8'b01010101;else if (r_cnt == 3)r_data_i <= 8'b00110011; */
endalways @ (posedge i_clk_200m )
beginif (i_rst || ~locked)r_frame_cnt <= 0;else if (r_frame_cnt == 3)r_frame_cnt <= 0; else if (r_valid)r_frame_cnt <= r_frame_cnt + 1;elser_frame_cnt <= r_frame_cnt;
endalways @ (posedge i_clk_200m )
beginif (i_rst || ~locked) begindatain_p <= 0;datain_n <= 0;end else begincase (r_frame_cnt) 0: begindatain_p <= r_data_i[7];datain_n <= r_data_i[6];end1: begindatain_p <= r_data_i[5];datain_n <= r_data_i[4]; end 2: begindatain_p <= r_data_i[3];datain_n <= r_data_i[2]; end 3: begindatain_p <= r_data_i[1];datain_n <= r_data_i[0]; end default :begin datain_p <= 0;datain_n <= 0; endendcaseend
endODDR #(.DDR_CLK_EDGE("SAME_EDGE"), // "OPPOSITE_EDGE" or "SAME_EDGE" .INIT(1'b0), // Initial value of Q: 1'b0 or 1'b1.SRTYPE("SYNC") // Set/Reset type: "SYNC" or "ASYNC" ) ODDR_dataout (.Q(w_data_o), // 1-bit DDR output.C(i_clk_200m), // 1-bit clock input.CE(1'b1), // 1-bit clock enable input.D1(datain_p), // 1-bit data input (positive edge).D2(datain_n), // 1-bit data input (negative edge).R(i_rst), // 1-bit reset.S(1'b0) // 1-bit set);ODDR #(.DDR_CLK_EDGE("SAME_EDGE"), // "OPPOSITE_EDGE" or "SAME_EDGE" .INIT(1'b0), // Initial value of Q: 1'b0 or 1'b1.SRTYPE("SYNC") // Set/Reset type: "SYNC" or "ASYNC" ) ODDR_valid (.Q(w_data_valid_o), // 1-bit DDR output.C(i_clk_200m), // 1-bit clock input.CE(1'b1), // 1-bit clock enable input.D1(r_valid), // 1-bit data input (positive edge).D2(r_valid), // 1-bit data input (negative edge).R(i_rst), // 1-bit reset.S(1'b0) // 1-bit set);IDDR #(.DDR_CLK_EDGE("SAME_EDGE_PIPELINED"), // "OPPOSITE_EDGE", "SAME_EDGE" // or "SAME_EDGE_PIPELINED" .INIT_Q1(1'b0), // Initial value of Q1: 1'b0 or 1'b1.INIT_Q2(1'b0), // Initial value of Q2: 1'b0 or 1'b1.SRTYPE("SYNC") // Set/Reset type: "SYNC" or "ASYNC" ) IDDR_datain (.Q1(data_pin), // 1-bit output for positive edge of clock.Q2(data_nin), // 1-bit output for negative edge of clock.C(clk_out1), // 1-bit clock input.CE(1), // 1-bit clock enable input.D(w_data_o), // 1-bit DDR data input.R(i_rst), // 1-bit reset.S(0) // 1-bit set);IDDR #(.DDR_CLK_EDGE("SAME_EDGE_PIPELINED"), // "OPPOSITE_EDGE", "SAME_EDGE" // or "SAME_EDGE_PIPELINED" .INIT_Q1(1'b0), // Initial value of Q1: 1'b0 or 1'b1.INIT_Q2(1'b0), // Initial value of Q2: 1'b0 or 1'b1.SRTYPE("SYNC") // Set/Reset type: "SYNC" or "ASYNC" ) IDDR_validin (.Q1(frame_h), // 1-bit output for positive edge of clock.Q2(frame_l), // 1-bit output for negative edge of clock.C(clk_out1), // 1-bit clock input.CE(1), // 1-bit clock enable input.D(w_data_valid_o), // 1-bit DDR data input.R(i_rst), // 1-bit reset.S(0) // 1-bit set);always @ (posedge clk_out1)
beginr_data_pin <= data_pin;r_data_nin <= data_nin;r_data_valid_2d <= r_data_valid_1d;r_read_cnt_1d <= r_read_cnt;r_read_cnt_2d <= r_read_cnt_1d;endalways @ (posedge clk_out1 )
beginif (i_rst || ~locked)r_read_cnt <= 0;else if (r_read_cnt == 3)r_read_cnt <= 0; else if (r_data_valid_1d)r_read_cnt <= r_read_cnt + 1;elser_read_cnt <= r_read_cnt;
endalways @ (posedge clk_out1 )
beginif (i_rst || ~locked) beginr_shift_data <= 0;end else if (r_data_valid_1d) beginr_shift_data <= {r_data_pin,r_data_nin};end
endalways @ (posedge clk_out1 )
beginif (i_rst || ~locked) beginr_dataout <= 0;end else if (r_data_valid_2d) beginr_dataout <= {r_dataout[5:0],r_shift_data};end
endalways @ (posedge clk_out1 )
beginif (i_rst || ~locked) beginr_final_data <= 0;end else if (r_read_cnt_2d == 3) beginr_final_data <= r_dataout; end else beginr_final_data <= 0; end
endalways @ (posedge clk_out1 )
beginif (i_rst || ~locked) beginr_final_valid <= 0;end else if (r_read_cnt_2d == 3) beginr_final_valid <= 1;end else beginr_final_valid <= 0; end
endendmodule
`timescale 1ns / 1ps
module tb_IODDR();reg i_clk_50m ;
reg i_clk_200m ;
reg i_rst ;initial begin i_clk_50m = 1'b1;i_clk_200m = 1'b1;i_rst = 1'b1;#100i_rst = 1'b0; endalways #10 i_clk_50m = ~ i_clk_50m;
always #2.5 i_clk_200m = ~ i_clk_200m;IODDR IODDR_u0(.i_clk_50m (i_clk_50m ),.i_clk_200m (i_clk_200m ),.i_rst (i_rst )
);endmodule
IDDR 数据输出延时一拍
数据输入 的时候,ODDR 输出延时一拍