Xilinx IDDR和 ODDR原语使用和仿真

// 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 输出延时一拍

相关推荐
仲南音1 天前
Xilinx FPGA——时钟IP核MMCM、PLL
fpga开发
I'm a winner2 天前
基于Xilinx FPGA的LVDS高速串行通信系统(三)--数据训练及握手机制【文末源码】
fpga开发
upper20202 天前
coremark移植坑之-nostartfiles -nostdlib参数
学习·fpga开发·coremark移植·riscv设计
Eloudy2 天前
Vivado 纯命令行构建 FPGA 项目教程
fpga开发
Rambo.xia2 天前
AXI跨时钟域与数据一致性——CDC FIFO深度不够、写后读冒险、多Master仲裁、乱序返回,出了Bug根本查不出来
fpga开发·bug
upper20202 天前
FPGA部署卷积神经网络识别MINST图片
fpga开发·卷积神经网络·minst·minst识别·部署神经网络·神经网络识别图片
你是我的解忧王子3 天前
嵌入式 ADC采样 原始数据分析上层(平均值 波动率 正态分布 线性补偿 系统误差)
fpga开发·数据挖掘·数据分析
9527华安3 天前
FPGA纯verilog代码ISP图像处理培训教程,基于IMX214,提供工程源码+视频教程+FPGA开发板
图像处理·fpga开发·isp·imx214·mipi
千寻xun4 天前
二、实战篇-NVME SSD控制之ZYNQ实现(六)-读写NVME SSD硬盘数据
fpga开发·nvme·nvme ssd
千寻xun4 天前
二、实战篇-NVME SSD控制之ZYNQ实现(三)
fpga开发·nvme ssd·nvme协议