• ZYNQ_project:test_fifo_255X8


    首先,这个vivado的fifo和quartus有很大不同。

    用BRAM来实现异步fifo。

    vivado的fifo有复位,在时钟信号稳定后,复位至少三个时钟周期(读写端口的慢时钟),复位完成后30个时钟周期后再进行写操作(慢时钟)。

    有两个模式:标准模式和预读模式。

    标准模式,读出的数据会比读使能延后一个时钟周期,fifo的深度也会比配置的少一个。

    预读模式,读出的数据会与读使能同步,深度会比配置的多一个。

    犯下的错误:顶层模块,fifo的复位接到了系统复位上。

    没有认真阅读正点原子开发指南,忽略了深度的问题。

    模块框图:

    时序图:

     

    代码:

    1. module fifo_wr_ctrl(
    2. input wire sys_clk , // clk_wr // 50Mhz
    3. input wire sys_rst_n ,
    4. output wire rst_fifo ,
    5. output wire wr_clk ,
    6. output wire [7:0] wr_din ,
    7. output reg wr_en
    8. );
    9. // parameter
    10. parameter RST_FIFO_CNT = 3 ,
    11. RST_WAIT_CNT = 30 ,
    12. DATA_IN_CNT = 200 ; // 设置深度256,但实际深度只有255.写进数据0~254
    13. // localparam
    14. localparam RST = 4'b0001 ,
    15. RST_WAIT = 4'b0010 ,
    16. DATA_IN_S = 4'b0100 ,
    17. FINISH_S = 4'b1000 ;
    18. // reg signal define
    19. reg [7:0] cnt_core ;
    20. reg finish ;
    21. reg [3:0] state ;
    22. // wire signal define
    23. wire rst_flag ;
    24. wire wait_flag ;
    25. wire data_over_flag ;
    26. // reg [7:0] cnt_core ;
    27. always @(posedge sys_clk or negedge sys_rst_n) begin
    28. if(~sys_rst_n)
    29. cnt_core <= 8'd0 ;
    30. else if(rst_flag || wait_flag || data_over_flag || finish)
    31. cnt_core <= 8'd0 ;
    32. else
    33. cnt_core <= cnt_core + 1'b1 ;
    34. end
    35. // reg finish ;
    36. always @(posedge sys_clk or negedge sys_rst_n) begin
    37. if(~sys_rst_n)
    38. finish <= 1'b0 ;
    39. else if(data_over_flag)
    40. finish <= 1'b1 ;
    41. else
    42. finish <= finish ;
    43. end
    44. // reg [3:0] state ;
    45. always @(posedge sys_clk or negedge sys_rst_n) begin
    46. if(~sys_rst_n)
    47. state <= 4'b0001 ;
    48. else
    49. case (state)
    50. RST : if(rst_flag)
    51. state <= RST_WAIT ;
    52. else
    53. state <= RST ;
    54. RST_WAIT : if(wait_flag)
    55. state <= DATA_IN_S ;
    56. else
    57. state <= RST_WAIT ;
    58. DATA_IN_S : if(data_over_flag)
    59. state <= FINISH_S ;
    60. else
    61. state <= DATA_IN_S ;
    62. FINISH_S : state <= FINISH_S ;
    63. default : state <= RST ;
    64. endcase
    65. end
    66. // wire rst_flag ;
    67. assign rst_flag = ((cnt_core == (RST_FIFO_CNT - 1)) && (state == RST)) ;
    68. // wire wait_flag ;
    69. assign wait_flag = ((cnt_core == (RST_WAIT_CNT - 1)) && (state == RST_WAIT)) ;
    70. // wire data_over_flag ;
    71. assign data_over_flag = ((cnt_core == (DATA_IN_CNT - 1)) && (state == DATA_IN_S)) ;
    72. // output reg rst_fifo ,
    73. // always @(posedge sys_clk or negedge sys_rst_n) begin
    74. // if(~sys_rst_n)
    75. // rst_fifo <= 1'b1 ;
    76. // else if(state == RST && rst_flag)
    77. // rst_fifo <= 1'b1 ;
    78. // else if(state == RST)
    79. // rst_fifo <= 1'b0 ;
    80. // else
    81. // rst_fifo <= 1'b1 ;
    82. // end
    83. assign rst_fifo = (state == RST) ? 1'b1 : 1'b0 ;
    84. // output wire wr_clk ,
    85. assign wr_clk = (sys_rst_n) ? sys_clk : 1'b0 ;
    86. // output wire [7:0] wr_din ,
    87. assign wr_din = (state == DATA_IN_S) ? cnt_core : 8'd0 ;
    88. // output reg wr_en ,
    89. always @(posedge sys_clk or negedge sys_rst_n) begin
    90. if(~sys_rst_n)
    91. wr_en <= 1'b0 ;
    92. else if(wait_flag || data_over_flag)
    93. wr_en <= ~wr_en ;
    94. else
    95. wr_en <= wr_en ;
    96. end
    97. endmodule
    1. module fifo_rd_ctrl(
    2. input wire sys_clk ,// clk_rd
    3. input wire sys_rst_n ,
    4. input wire wr_full ,
    5. input wire almost_empty,// 将要读空
    6. output reg rd_en ,
    7. output wire rd_clk
    8. );
    9. assign rd_clk = (sys_rst_n) ? sys_clk : 1'b0 ;
    10. always @(posedge sys_clk or negedge sys_rst_n) begin
    11. if(~sys_rst_n)
    12. rd_en <= 1'b0 ;
    13. else if(almost_empty) // 将要读空后拉低读使能。因为是时序逻辑,应该正好读空fifo
    14. rd_en <= 1'b0 ;
    15. else if(wr_full) // 写满后拉高写使能
    16. rd_en <= 1'b1 ;
    17. else
    18. rd_en <= rd_en ;
    19. end
    20. endmodule
    1. module top(
    2. input wire sys_clk ,
    3. input wire sys_rst_n ,
    4. output wire [7:0] data_out
    5. );
    6. // 例化间连线
    7. wire clk_100Mhz ;
    8. wire clk_50Mhz ;
    9. wire locked ;
    10. wire rst_n ;
    11. wire rst_fifo ; // fifo的复位信号
    12. wire wr_clk ; // 写端口相关信号
    13. wire [7:0] wr_din ; // 写端口相关信号
    14. wire wr_en ; // 写端口相关信号
    15. wire [7:0] dout ;
    16. wire full ;
    17. wire almost_full ;
    18. wire empty ;
    19. wire almost_empty;
    20. wire [7:0] rd_data_count;
    21. wire [7:0] wr_data_count;
    22. wire wr_rst_busy ;
    23. wire rd_rst_busy ;
    24. wire rd_en ;
    25. wire rd_clk ;
    26. mmcm_100M_50M mmcm_100M_50M_inst (
    27. .resetn ( sys_rst_n ) ,
    28. .clk_in1 ( sys_clk ) ,
    29. .clk_out1 ( clk_100Mhz ) ,
    30. .clk_out2 ( clk_50Mhz ) ,
    31. .locked ( locked )
    32. );
    33. assign rst_n = sys_rst_n && locked ;
    34. fifo_wr_ctrl fifo_wr_ctrl_inst(
    35. .sys_clk ( clk_50Mhz ) , // clk_wr // 50Mhz
    36. .sys_rst_n ( rst_n ) ,
    37. .rst_fifo ( rst_fifo ) ,
    38. .wr_clk ( wr_clk ) ,
    39. .wr_din ( wr_din ) ,
    40. .wr_en ( wr_en )
    41. );
    42. fifo_rd_ctrl fifo_rd_ctrl_inst(
    43. .sys_clk ( clk_100Mhz ) ,// clk_rd
    44. .sys_rst_n ( rst_n ) ,
    45. .wr_full ( full ) ,
    46. .almost_empty ( almost_empty ) ,// 将要读空
    47. .rd_en ( rd_en ) ,
    48. .rd_clk ( rd_clk )
    49. );
    50. fifo_256X8 fifo_256X8_inst(
    51. .rst ( rst_fifo ) , // 在fpga配置完成后,fifo必须要进行复位操作�?�复位信号至少保�?3个时钟周期以慢时钟为准�?�复位完成后至少经过30个时钟周期后,才能进行数据写操作�?
    52. .wr_clk ( wr_clk ) , // 写数据时�?50Mhz // 复位高有效�??
    53. .rd_clk ( rd_clk ) , // 读数据时�?100Mhz
    54. .din ( wr_din ) , // 写入数据
    55. .wr_en ( wr_en ) , // 写使�?
    56. .rd_en ( rd_en ) , // 读使�?
    57. .dout ( data_out ) , // 输出数据
    58. .full ( full ) , // 写满
    59. .almost_full ( almost_full ) , // 将写�?
    60. .empty ( empty ) , // 读空
    61. .almost_empty ( almost_empty ) , // 将读�?
    62. .rd_data_count ( rd_data_count ) , // 可读数据
    63. .wr_data_count ( wr_data_count ) , // 已写数据
    64. .wr_rst_busy ( wr_rst_busy ) , // 写复位忙�?
    65. .rd_rst_busy ( rd_rst_busy ) // 读复位忙�?
    66. );
    67. endmodule

     

    1. `timescale 1ns/1ns
    2. module test_top();
    3. reg sys_clk ;
    4. reg sys_rst_n ;
    5. wire [7:0] data_out ;
    6. top top_inst(
    7. .sys_clk ( sys_clk ) ,
    8. .sys_rst_n ( sys_rst_n ) ,
    9. .data_out ( data_out )
    10. );
    11. parameter CYCLE = 20 ;
    12. initial begin
    13. sys_clk = 1'b1 ;
    14. sys_rst_n <= 1'b0 ;
    15. #( CYCLE * 5) ;
    16. sys_rst_n <= 1'b1 ;
    17. #(3000*CYCLE) ;
    18. $stop;
    19. end
    20. always #(CYCLE/2) sys_clk = ~sys_clk ;
    21. endmodule

     

    仿真图:

  • 相关阅读:
    String的增删查【C++】
    R语言将数据转化为DALEX包期望的格式、使用DALEX包的explain函数对多个h2o算法模型构建解释器进行解释分析、使用验证集数据构建模型解释器
    计算机毕业设计springboot+vue基本微信小程序的校园跑腿平台 uniapp
    【mysql学习笔记23】索引优化
    JAVA常见基础面试问题汇集
    Java 入门练习(6 - 10)
    【算法实战】每日一题:17.1 订单处理问题(差分思想,二分搜索)
    StarRocks 的学习笔记
    链表的回文判断
    神经网络在控制系统中的应用有哪些
  • 原文地址:https://blog.csdn.net/Meng_long2022/article/details/134448776