• 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_W{1'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驱动成功。

  • 相关阅读:
    一个小白的进击之路——Hadoop开篇
    日元对人民币汇率的大数据分析与预测
    团队第九次作业-用户使用手册与反馈
    第九次团队作业-测试报告与用户使用手册
    系统设计和任务分配(个人)
    结对项目之需求分析与原型设计
    第五次作业——四则运算
    django-团队简介的网页
    该怎么学好软件工程这门课?
    第九次团队作业-测试报告与用户手册
  • 原文地址:https://www.cnblogs.com/Librarian/p/11001270.html
Copyright © 2020-2023  润新知