// IODDR 回环 ,使用 SAME_EDGE 模式,注意的是 从 ODDR输出 时钟需要偏移90度,不然数据 上下沿采样错误
// 数据从 IDDR 输出时,最好将 数据和 frame 有效信号 同步在偏移90度的时钟下
// 本测试内容 是 50MHZ 的 8bit (1~126) 数据进入 IDDR -- ODDR 输出。 IDDR 和 ODDR 时钟 200MHZ
后续研究 OPPOSITE_EDGE 模式。
代码没有进行优化
大家自行参考
c
`timescale 1ns / 1ps
// IODDR 回环 ,使用 SAME_EDGE 模式,注意的是 从 ODDR输出 时钟需要偏移90度,不然数据 上下沿采样错误
// 数据从 IDDR 输出时,最好将 数据和 frame 有效信号 同步在偏移90度的时钟下
// 本测试内容 是 50MHZ 的 8bit (1~126) 数据进入 IDDR -- ODDR 输出。 IDDR 和 ODDR 时钟 200MHZ
module 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 )
begin
if (i_rst || ~locked)
r_valid <= 0;
else if (r_cnt == 128 - 1)
r_valid <= 0;
else if (r_cnt == 1)
r_valid <= 1;
else
r_valid <= r_valid;
end
always @ (posedge clk_out1 )
begin
r_data_valid <= frame_h;
r_data_valid_1d <= r_data_valid;
end
always @ (posedge i_clk_50m )
begin
if (i_rst || ~locked)
r_cnt <= 0;
else if (r_cnt == 256 -1)
r_cnt <= 0;
else
r_cnt <= r_cnt + 1;
end
always @ (posedge i_clk_50m)
begin
r_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; */
end
always @ (posedge i_clk_200m )
begin
if (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;
else
r_frame_cnt <= r_frame_cnt;
end
always @ (posedge i_clk_200m )
begin
if (i_rst || ~locked) begin
datain_p <= 0;
datain_n <= 0;
end else begin
case (r_frame_cnt)
0: begin
datain_p <= r_data_i[7];
datain_n <= r_data_i[6];
end
1: begin
datain_p <= r_data_i[5];
datain_n <= r_data_i[4];
end
2: begin
datain_p <= r_data_i[3];
datain_n <= r_data_i[2];
end
3: begin
datain_p <= r_data_i[1];
datain_n <= r_data_i[0];
end
default :begin
datain_p <= 0;
datain_n <= 0;
end
endcase
end
end
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_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)
begin
r_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;
end
always @ (posedge clk_out1 )
begin
if (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;
else
r_read_cnt <= r_read_cnt;
end
always @ (posedge clk_out1 )
begin
if (i_rst || ~locked) begin
r_shift_data <= 0;
end else if (r_data_valid_1d) begin
r_shift_data <= {r_data_pin,r_data_nin};
end
end
always @ (posedge clk_out1 )
begin
if (i_rst || ~locked) begin
r_dataout <= 0;
end else if (r_data_valid_2d) begin
r_dataout <= {r_dataout[5:0],r_shift_data};
end
end
always @ (posedge clk_out1 )
begin
if (i_rst || ~locked) begin
r_final_data <= 0;
end else if (r_read_cnt_2d == 3) begin
r_final_data <= r_dataout;
end else begin
r_final_data <= 0;
end
end
always @ (posedge clk_out1 )
begin
if (i_rst || ~locked) begin
r_final_valid <= 0;
end else if (r_read_cnt_2d == 3) begin
r_final_valid <= 1;
end else begin
r_final_valid <= 0;
end
end
endmodule
c
`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;
#100
i_rst = 1'b0;
end
always #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 输出延时一拍