Altera DDR2 IP核学习总结3-----------DDR2 IP核的使用

Posted librarian

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Altera DDR2 IP核学习总结3-----------DDR2 IP核的使用相关的知识,希望对你有一定的参考价值。

技术图片

根据上一篇生成的IP核,例化之后如上图,Local开头的数据是用户侧数据,其他数据暂时不用纠结,不用管。

技术图片

这些是需要关注的信号,但是初学阶段很难对这些信号形成具体的概念,这里参考明德扬的代码进行二次封装。

  1. module ddr2_intf(  
  2.     clk_in           ,  
  3.     clk_out          ,  
  4.     rst_n            ,  
  5.     local_address    ,  
  6.     local_write_req  ,  
  7.     local_read_req   ,  
  8.     local_wdata      ,  
  9.     local_ready      ,  
  10.     local_rdata      ,  
  11.     local_rdata_valid,  
  12.     local_init_done  ,  
  13.     local_burstbegin ,  
  14.     user_wdata       ,  
  15.     user_wdata_en    ,  
  16.     user_waddr       ,  
  17.     user_raddr       ,  
  18.     user_rdata_en    ,  
  19.     user_rdata       ,  
  20.     user_rdata_vld   ,  
  21.     user_wdata_rdy   ,  
  22.     user_rdata_rdy     
  23. );  
  24.   
  25. parameter           ADDR_W     = 23       ;  
  26. parameter           DDR_DATA_W = 32       ;  
  27. parameter           BURST      = 2        ;  
  28. parameter           USE_DATA_W = DDR_DATA_W * BURST;  
  29. parameter           FIFO_W     = USE_DATA_W + ADDR_W;  
  30.   
  31. input                   clk_in           ;  
  32. input                   rst_n            ;  
  33. input                   clk_out          ;          
  34. input                   local_ready      ;    
  35. input  [DDR_DATA_W-1:0] local_rdata      ;    
  36. input                   local_rdata_valid;  
  37. input                   local_init_done  ;   
  38. input  [USE_DATA_W-1:0] user_wdata       ;  
  39. input                   user_wdata_en    ;  
  40. input  [ADDR_W-1:0]     user_waddr       ;         
  41. input  [ADDR_W-1:0]     user_raddr       ;  
  42. input                   user_rdata_en    ;  
  43. output [ADDR_W-1:0]     local_address    ;    
  44. output                  local_write_req  ;    
  45. output                  local_read_req   ;    
  46. output [DDR_DATA_W-1:0] local_wdata      ;  
  47. output                  local_burstbegin ;  
  48. output [USE_DATA_W-1:0] user_rdata       ;  
  49. output                  user_rdata_vld   ;  
  50. output                  user_wdata_rdy   ;  
  51. output                  user_rdata_rdy   ;  
  52. reg    [USE_DATA_W-1:0] user_rdata       ;  
  53. reg                     user_rdata_vld   ;  
  54. reg                     user_wdata_rdy   ;  
  55. reg                     user_rdata_rdy   ;  
  56.   
  57. wire   [ADDR_W-1:0]     local_address    ;    
  58. wire                    local_write_req  ;    
  59. wire                    local_read_req   ;    
  60. wire   [DDR_DATA_W-1:0] local_wdata      ;  
  61. wire                    local_burstbegin ;  
  62.   
  63. wire   [FIFO_W-1:0]     wfifo_wdata      ;  
  64. wire                    wfifo_wrreq      ;  
  65. wire                    wfifo_empty      ;  
  66. wire                    wfifo_rdreq      ;  
  67. wire   [FIFO_W-1:0]     wfifo_q          ;  
  68. wire   [       5:0]     wfifo_usedw      ;  
  69.   
  70.   
  71. wire   [ADDR_W-1:0]     rfifo_wdata      ;  
  72. wire                    rfifo_wrreq      ;  
  73. wire                    rfifo_empty      ;  
  74. wire                    rfifo_rdreq      ;  
  75. wire   [ADDR_W-1:0]     rfifo_q          ;  
  76. wire   [       5:0]     rfifo_usedw      ;  
  77.   
  78.   
  79. reg    [FIFO_W  :0]     ififo_wdata      ;  
  80. reg                     ififo_wrreq      ;  
  81. wire                    ififo_empty      ;  
  82. wire                    ififo_rdreq      ;  
  83. wire   [FIFO_W  :0]     ififo_q          ;  
  84. wire   [       5:0]     ififo_usedw      ;  
  85. wire                    ififo_rdy        ;  
  86.   
  87. reg    [USE_DATA_W-1:0] gfifo_wdata      ;  
  88. reg                     gfifo_wrreq      ;  
  89. wire                    gfifo_empty      ;  
  90. wire                    gfifo_rdreq      ;  
  91. wire   [USE_DATA_W-1:0] gfifo_q          ;  
  92. wire   [       5:0]     gfifo_usedw      ;  
  93.   
  94. reg [ 1:0]              cnt0             ;  
  95. wire                    add_cnt0         ;  
  96. wire                    end_cnt0         ;  
  97. reg [ 2:0]              x                ;  
  98.   
  99. reg [ 3:0]              cnt1             ;  
  100. wire                    add_cnt1         ;  
  101. wire                    end_cnt1         ;  
  102.   
  103. fifo_ahead_sys #(.DATA_W(FIFO_W),.DEPT_W(64)) u_wfifo(  
  104.     .aclr           (~rst_n             ),  
  105.     .clock          (clk_in             ),  
  106.     .data           (wfifo_wdata        ),  
  107.     .rdreq          (wfifo_rdreq        ),  
  108.     .wrreq          (wfifo_wrreq        ),  
  109.     .empty          (wfifo_empty        ),  
  110.     .q              (wfifo_q            ),  
  111.     .usedw          (wfifo_usedw        )  
  112. );  
  113.   
  114. fifo_ahead_sys #(.DATA_W(ADDR_W),.DEPT_W(64)) u_rfifo(  
  115.     .aclr           (~rst_n             ),  
  116.     .clock          (clk_in             ),  
  117.     .data           (rfifo_wdata        ),  
  118.     .rdreq          (rfifo_rdreq        ),  
  119.     .wrreq          (rfifo_wrreq        ),  
  120.     .empty          (rfifo_empty        ),  
  121.     .q              (rfifo_q            ),  
  122.     .usedw          (rfifo_usedw        )  
  123. );  
  124.   
  125.   
  126. fifo_ahead_asy #(.DATA_W(FIFO_W+1),.DEPT_W(64))  u_ififo(  
  127.             .aclr    (~rst_n        ),  
  128.             .data    (ififo_wdata   ),  
  129.             .rdclk   (clk_out       ),  
  130.             .rdreq   (ififo_rdreq   ),  
  131.             .wrclk   (clk_in        ),  
  132.             .wrreq   (ififo_wrreq   ),  
  133.             .q       (ififo_q       ),  
  134.             .rdempty (ififo_empty ),  
  135.             .wrusedw (ififo_usedw )   
  136.     );  
  137.   
  138.   
  139. assign wfifo_wdata = user_waddr,user_wdata;  
  140. assign wfifo_wrreq = user_wdata_en          ;  
  141. assign wfifo_rdreq = ififo_rdy && wfifo_empty==0 && rfifo_empty==1;  
  142.   
  143. assign rfifo_wdata = user_raddr             ;  
  144. assign rfifo_wrreq = user_rdata_en          ;  
  145. assign rfifo_rdreq = ififo_rdy && rfifo_empty==0;  
  146.   
  147. always  @(posedge clk_in or negedge rst_n)begin  
  148.     if(rst_n==1‘b0)begin  
  149.         ififo_wdata <= 0;   
  150.     end  
  151.     else if(wfifo_rdreq) begin  
  152.         ififo_wdata <= 1‘b1,wfifo_q;  
  153.     end  
  154.     else if(rfifo_rdreq)begin  
  155.         ififo_wdata <= 1‘b0,rfifo_q,USE_DATA_W1‘b0;  
  156.     end  
  157. end  
  158.   
  159. always  @(posedge clk_in or negedge rst_n)begin  
  160.     if(rst_n==1‘b0)begin  
  161.         ififo_wrreq <= 0;  
  162.     end  
  163.     else begin  
  164.         ififo_wrreq <= wfifo_rdreq || rfifo_rdreq;  
  165.     end  
  166. end  
  167.   
  168. assign ififo_rdy = ififo_usedw<40;  
  169.   
  170. always  @(posedge clk_in or negedge rst_n)begin  
  171.     if(rst_n==1‘b0)begin  
  172.         user_wdata_rdy <= 0;  
  173.     end  
  174.     else begin  
  175.         user_wdata_rdy <= wfifo_usedw<40;  
  176.     end  
  177. end  
  178.   
  179. always  @(posedge clk_in or negedge rst_n)begin  
  180.     if(rst_n==1‘b0)begin  
  181.         user_rdata_rdy <= 0;  
  182.     end  
  183.     else begin  
  184.         user_rdata_rdy <= rfifo_usedw<40;  
  185.     end  
  186. end  
  187.   
  188. wire      local_read_req_tmp;  
  189.   
  190. assign local_wdata     = ififo_q[USE_DATA_W-DDR_DATA_W*cnt0-1 -:DDR_DATA_W];  
  191. assign local_address   = ififo_q[FIFO_W-1 -:ADDR_W];  
  192. assign local_write_req = ififo_q[FIFO_W]    && ififo_empty==0 && local_init_done;  
  193. assign local_read_req_tmp  = ififo_q[FIFO_W]==0 && ififo_empty==0 && local_init_done;  
  194. assign local_read_req      = local_read_req_tmp && cnt0==1-1;  
  195. assign local_burstbegin= add_cnt0 && cnt0==1-1;  
  196.   
  197. assign ififo_rdreq     =  end_cnt0;  
  198.   
  199. reg     ififo_q_ff0;  
  200. always  @(posedge clk_out or negedge rst_n)begin  
  201.     if(rst_n==1‘b0)begin  
  202.         ififo_q_ff0<=0;  
  203.     end  
  204.     else begin  
  205.         ififo_q_ff0<=ififo_q[FIFO_W];  
  206.     end  
  207. end  
  208.   
  209. always @(posedge clk_out or negedge rst_n)begin  
  210.     if(!rst_n)begin  
  211.         cnt0 <= 0;  
  212.     end  
  213.     else if(add_cnt0)begin  
  214.         if(end_cnt0)  
  215.             cnt0 <= 0;  
  216.         else  
  217.             cnt0 <= cnt0 + 1;  
  218.     end  
  219. end  
  220.   
  221. assign add_cnt0 = (local_write_req||local_read_req_tmp)&&local_ready;         
  222. assign end_cnt0 = add_cnt0 && cnt0==2-1;  
  223.   
  224.   
  225.   
  226.   
  227.   
  228.   
  229.   
  230. always @(posedge clk_out or negedge rst_n)begin  
  231.     if(!rst_n)begin  
  232.         cnt1 <= 0;  
  233.     end  
  234.     else if(add_cnt1)begin  
  235.         if(end_cnt1)  
  236.             cnt1 <= 0;  
  237.         else  
  238.             cnt1 <= cnt1 + 1;  
  239.     end  
  240. end  
  241.   
  242. assign add_cnt1 = local_rdata_valid;         
  243. assign end_cnt1 = add_cnt1 && cnt1==BURST-1 ;  
  244.   
  245. always  @(posedge clk_out or negedge rst_n)begin  
  246.     if(rst_n==1‘b0)begin  
  247.         gfifo_wrreq <= 0;  
  248.     end  
  249.     else begin  
  250.         gfifo_wrreq <= end_cnt1;  
  251.     end  
  252. end  
  253.   
  254. always  @(posedge clk_out or negedge rst_n)begin  
  255.     if(rst_n==1‘b0)begin  
  256.         gfifo_wdata <= 0;  
  257.     end  
  258.     else if(add_cnt1)begin  
  259.         gfifo_wdata[USE_DATA_W - DDR_DATA_W*cnt1 -1  -:DDR_DATA_W] <= local_rdata;  
  260.     end  
  261. end  
  262.   
  263.   
  264. fifo_ahead_asy #(.DATA_W(USE_DATA_W),.DEPT_W(64))  u_gfifo(  
  265.             .aclr    (~rst_n        ),  
  266.             .data    (gfifo_wdata   ),  
  267.             .rdclk   (clk_in        ),  
  268.             .rdreq   (gfifo_rdreq   ),  
  269.             .wrclk   (clk_out       ),  
  270.             .wrreq   (gfifo_wrreq   ),  
  271.             .q       (gfifo_q       ),  
  272.             .rdempty (gfifo_empty ),  
  273.             .wrusedw (gfifo_usedw )   
  274.     );  
  275.   
  276. assign gfifo_rdreq = gfifo_empty==0;  
  277.   
  278. always  @(posedge clk_in or negedge rst_n)begin  
  279.     if(rst_n==1‘b0)begin  
  280.         user_rdata <= 0;  
  281.     end  
  282.     else begin  
  283.         user_rdata <= gfifo_q;  
  284.     end  
  285. end  
  286.   
  287. always  @(posedge clk_in or negedge rst_n)begin  
  288.     if(rst_n==1‘b0)begin  
  289.         user_rdata_vld <= 0;  
  290.     end  
  291.     else begin  
  292.         user_rdata_vld <= gfifo_rdreq;  
  293.     end  
  294. end  
  295.   
  296.   
  297.   
  298.   
  299. endmodule 

 

 

  1.   
  2.     ddr2_intf   u8(  
  3.         .clk_in           (  clk               ),    
  4.         .clk_out          (  phy_clk           ),   
  5.         .rst_n            (  rst_n_ff1             ),  
  6.         .local_address    (  local_address     ),     
  7.         .local_write_req  (  local_write_req   ),   
  8.         .local_read_req   (  local_read_req    ),  
  9.         .local_wdata      (  local_wdata       ),  
  10.         .local_ready      (  local_ready       ),   
  11.         .local_rdata      (  local_rdata       ),                     
  12.         .local_rdata_valid(  local_rdata_valid ),    
  13.         .local_init_done  (  local_init_done   ),   
  14.         .local_burstbegin (  local_burstbegin  ),  
  15.         .user_wdata       (  user_wdata        ),  
  16.         .user_wdata_en    (  user_wdata_en     ),   
  17.         .user_waddr       (  user_waddr        ),   
  18.         .user_raddr       (  user_raddr        ),   
  19.         .user_rdata_en    (  user_rdata_en     ),   
  20.         .user_rdata       (  user_rdata        ),   
  21.         .user_rdata_vld   (  user_rdata_vld    ),  
  22.         .user_wdata_rdy   (  user_wdata_rdy    ),  
  23.         .user_rdata_rdy   (  user_rdata_rdy    )  
  24.    
  25.     );  
  26.     

封装之后只需要关注

  1.         .user_wdata       (  user_wdata        ),  
  2.         .user_wdata_en    (  user_wdata_en     ),   
  3.         .user_waddr       (  user_waddr        ),   
  4.         .user_raddr       (  user_raddr        ),   
  5.         .user_rdata_en    (  user_rdata_en     ),   
  6.         .user_rdata       (  user_rdata        ),   
  7.         .user_rdata_vld   (  user_rdata_vld    ),  
  8.         .user_wdata_rdy   (  user_wdata_rdy    ),  
  9.         .user_rdata_rdy   (  user_rdata_rdy    ) 

上面这9个信号,当user_wdata_rdy为高电平的时候可以写入数据,user_rdata_rdy   (  user_rdata_rdy    ) 可以读出数据,

写了一个简单的测试程序

  1. always @(posedge clk or negedge rst_n)begin  
  2.     if(!rst_n)begin  
  3.         cnt0 <= 0;  
  4.     end  
  5.     else if(add_cnt0)begin  
  6.         if(end_cnt0)  
  7.             cnt0 <= 0;  
  8.         else  
  9.             cnt0 <= cnt0 + 1;  
  10.     end  
  11. end  
  12.   
  13. assign add_cnt0 = user_wdata_en ;         
  14. assign end_cnt0 = add_cnt0 && cnt0==100          ;       
  15.       
  16. assign user_wdata_en = user_wdata_rdy && flag_add==0;      
  17.       
  18. always @(posedge clk or negedge rst_n)begin  
  19.     if(!rst_n)begin  
  20.         cnt1 <= 0;  
  21.     end  
  22.     else if(add_cnt1)begin  
  23.         if(end_cnt1)  
  24.             cnt1 <= 0;  
  25.         else  
  26.             cnt1 <= cnt1 + 1;  
  27.     end  
  28. end  
  29.   
  30. assign add_cnt1 = user_rdata_en ;         
  31. assign end_cnt1 = add_cnt1 && cnt1==100            ;       
  32.       
  33. assign user_rdata_en = user_rdata_rdy && flag_add==1;  
  34.       
  35. always  @(posedge clk)begin  
  36.     if(!rst_n)  
  37.         flag_add <= 0;  
  38.           else if(end_cnt0)  
  39.         flag_add <= 1;  
  40.           else if(end_cnt1)  
  41.           flag_add <= 0;  
  42. end      
  43.       
  44. always  @(posedge clk or negedge rst_n)begin  
  45.     if(rst_n==1‘b0)begin  
  46.         user_wdata    <= 0;  
  47.         user_waddr    <= 0;  
  48.         user_raddr    <= 0;            
  49.     end  
  50.     else begin  
  51.         user_wdata    <= cnt0    ;  
  52.         user_waddr    <= cnt0*2    ;  
  53.         user_raddr    <= cnt1*2    ;        
  54.     end  
  55. end

当flag_add为低电平的时候往DDR2中写入数据,flag_add为高电平的时候读出数据。一共写入一百个数据。

使用signaltapII抓到的波形为

技术图片

local_init_done为高电平说明DDR2芯片初始化完成,user_wdata_en为高电平时写入数据,放大了看则是

 技术图片

写入的数据为地址的二分之一

然后看一下读出来的数据

技术图片

这里很清楚的可以看出来user_rdata_en跟user_rdata_vld并不能对齐

放大了看

技术图片

当user_rdata_vld为高电平的时候输出的数据有效,

技术图片

测量一下得知user_rdata_en跟user_rdata_vld的偏差是21个数据,从Altera DDR2 IP核学习总结1中得知DRAM数据输出有延迟,结构相同的DDR2自然有相同的特性,大神称为首字惩罚特性(当时纠结这个问题半天,怎么也解决不了,多谢群里的大神)。

观察写入数据和读取数据一致,DDR2驱动成功。

 

以上是关于Altera DDR2 IP核学习总结3-----------DDR2 IP核的使用的主要内容,如果未能解决你的问题,请参考以下文章

altera DDR2 ip使用笔记之IP核生成

小梅哥FPGA进阶学习之旅基于Altera FPGA 的DDR2+千兆以太网电路设计

怎样调用altera中的ip核

quartus中dll为什么写入不了

采用激励driver模块IP核模拟DDR2控制器的用户侧,来调度DDR2控制器。 请问你的激励driver模块IP核是哪里来

Quartus II 与ModelSim-Altera联合仿真FFT IP核之FFT IP核分析