• AXI-Stream协议详解(3)—— AXI4-Stream IP核原理分析


    一、前言

            在之前的文章中,我们介绍了AXI-S协议的一些基础知识,这是我们进行本文学习的前置基础,因此建议在开始本文章的学习前,完整阅读以下两篇文章:

    AXI-Stream协议详解(1)—— Introductionicon-default.png?t=N7T8https://blog.csdn.net/apple_53311083/article/details/134058532?spm=1001.2014.3001.5501AXI-Stream协议详解(2)—— Interface Signalsicon-default.png?t=N7T8https://blog.csdn.net/apple_53311083/article/details/134065597?spm=1001.2014.3001.5501

    二、带AXI-Stream接口的IP核

    1、IP核创建

            在这里我们选择最底下的一项,创建一个带有AXI接口的IP核

            接下来我们设置IP核的一些细节信息,这里把名称改成了axis_m,代表这是AXI-Stream协议的主机。

            选择stream协议,选择主机类型,相应地完成名称更改,这里的数据位宽我们暂时不做更改,保持默认的32bit就行。

            最后这里直接添加到IP库里就完成了。

            然后我们通过同样的方式可以完成axi_s(带有AXI-S接口的从机)的创建,这里就省略创建过程了。

    2、IP核学习

            在IP Catlog下搜索找到我们之前创建的2个带有AXI-Stream协议的IP核

            右击选择Edit in packager

            我们先以从机为例,显示如何找到AXI-S的设计部分,直接点击OK直到打开一个新的vivado界面

            可以看到里面有两个模块 

     

            我们依次打开两个文件,同时可以把axis_m IP核中的文件同时打开,方便我们进行学习,打开过程同上,这里不做重复。

            对于axis_s_v1_0和axis_m_v1_0这两个模块来说,只是完成了对底层模块的一个例化,所以没有什么可以过多赘述的。

            下面我们着重介绍axis_s_v1_0_S00_AXIS和axis_m_v1_0_M00_AXIS两个模块

    三、AXI-Stream源代码学习

            其实Xilinx官方已经给出了非常详细的英文注释,可以帮助我们快速了解整个AXI-S协议的实现方式,写的真的非常好。这里也只是在其基础上做一个简单的翻译和补充,首先给出笔者中文注释版本,再给出官方的注释版本,推荐阅读后者。

    1、AXIS主机部分

    1.1 中文注释

    1. `timescale 1 ns / 1 ps
    2. module axis_m_v1_0_M00_AXIS #
    3. (
    4. /*
    5. 用户可以在此自定义参数
    6. */
    7. parameter integer C_M_AXIS_TDATA_WIDTH = 32, // 发送数据的位宽
    8. // 初始化的最大计数时钟(等待系统稳定的时间)
    9. parameter integer C_M_START_COUNT = 32
    10. )
    11. (
    12. /*
    13. 用户可以在此自定义端口
    14. */
    15. //全局信号
    16. input wire M_AXIS_ACLK, // 时钟信号
    17. input wire M_AXIS_ARESETN, // 复位信号(低电平有效)
    18. output wire M_AXIS_TVALID, //有效信号,代表主机已经准备好了
    19. output wire [C_M_AXIS_TDATA_WIDTH-1 : 0] M_AXIS_TDATA, //数据信号
    20. output wire [(C_M_AXIS_TDATA_WIDTH/8)-1 : 0] M_AXIS_TSTRB, //数据修饰符,辨别字节类型
    21. output wire M_AXIS_TLAST, //last信号,拉高代表是传输中的最后一个字节
    22. input wire M_AXIS_TREADY //ready信号,代表从机准备好了
    23. );
    24. localparam NUMBER_OF_OUTPUT_WORDS = 8; //发送数据的个数
    25. //函数:以2为低求对数,用于计算位宽
    26. function integer clogb2 (input integer bit_depth);
    27. begin
    28. for(clogb2=0; bit_depth>0; clogb2=clogb2+1)
    29. bit_depth = bit_depth >> 1;
    30. end
    31. endfunction
    32. localparam integer WAIT_COUNT_BITS = clogb2(C_M_START_COUNT-1); //等待计时寄存器的位宽
    33. localparam bit_num = clogb2(NUMBER_OF_OUTPUT_WORDS); //发送数据寄存器位宽
    34. //状态机参数
    35. parameter [1:0] IDLE = 2'b00, //初始状态
    36. INIT_COUNTER = 2'b01, //初始化计数器,等待计数值达到最大计数时钟,进入下一个状态
    37. SEND_STREAM = 2'b10; //数据发送状态
    38. reg [1:0] mst_exec_state; //状态寄存器
    39. reg [bit_num-1:0] read_pointer; //FIFO读指针
    40. // AXIS内部信号
    41. reg [WAIT_COUNT_BITS-1 : 0] count; //等待计数器(实现我们之前说的计时功能)
    42. wire axis_tvalid; //valid
    43. reg axis_tvalid_delay; //延时一个时钟周期的valid
    44. wire axis_tlast; //last
    45. reg axis_tlast_delay; //延迟一个时钟周期的last
    46. reg [C_M_AXIS_TDATA_WIDTH-1 : 0] stream_data_out; //data
    47. wire tx_en; //发送使能
    48. reg tx_done; //发送完成
    49. //赋值操作
    50. assign M_AXIS_TVALID = axis_tvalid_delay;
    51. assign M_AXIS_TDATA = stream_data_out;
    52. assign M_AXIS_TLAST = axis_tlast_delay;
    53. assign M_AXIS_TSTRB = {(C_M_AXIS_TDATA_WIDTH/8){1'b1}}; //1
    54. //控制状态机
    55. always @(posedge M_AXIS_ACLK)
    56. begin
    57. if (!M_AXIS_ARESETN)
    58. begin
    59. mst_exec_state <= IDLE;
    60. count <= 0;
    61. end
    62. else
    63. case (mst_exec_state)
    64. IDLE: //一个周期后直接进入下一个状态
    65. mst_exec_state <= INIT_COUNTER;
    66. INIT_COUNTER: //计数器达到最大计数值,进入次态
    67. if ( count == C_M_START_COUNT - 1 )
    68. begin
    69. mst_exec_state <= SEND_STREAM;
    70. end
    71. else
    72. begin
    73. count <= count + 1;
    74. mst_exec_state <= INIT_COUNTER;
    75. end
    76. SEND_STREAM: //发送状态,完成发送后回到初始态
    77. if (tx_done)
    78. begin
    79. mst_exec_state <= IDLE;
    80. end
    81. else
    82. begin
    83. mst_exec_state <= SEND_STREAM;
    84. end
    85. endcase
    86. end
    87. //valid信号(表示主机有没有准备好),当处于发送状态,读指针小于发送数据个数时(也就是处于发送状态且还有数据要发)生效
    88. assign axis_tvalid = ((mst_exec_state == SEND_STREAM) && (read_pointer < NUMBER_OF_OUTPUT_WORDS));
    89. //last信号(表示发送的最后一个字节),当读指针等于发送数据个数-1时生效
    90. assign axis_tlast = (read_pointer == NUMBER_OF_OUTPUT_WORDS-1);
    91. //完成axis_tvalid_delay,axis_tlast_delay(延迟一个时钟的validlast)的赋值
    92. always @(posedge M_AXIS_ACLK)
    93. begin
    94. if (!M_AXIS_ARESETN)
    95. begin
    96. axis_tvalid_delay <= 1'b0;
    97. axis_tlast_delay <= 1'b0;
    98. end
    99. else
    100. begin
    101. axis_tvalid_delay <= axis_tvalid;
    102. axis_tlast_delay <= axis_tlast;
    103. end
    104. end
    105. //读指针
    106. always@(posedge M_AXIS_ACLK)
    107. begin
    108. if(!M_AXIS_ARESETN) //复位
    109. begin
    110. read_pointer <= 0;
    111. tx_done <= 1'b0;
    112. end
    113. else
    114. if (read_pointer <= NUMBER_OF_OUTPUT_WORDS-1) //读指针小于等于发送数据个数-1,如果tx_en(发送使能),读指针递增,发送完成信号为0
    115. begin
    116. if (tx_en)
    117. begin
    118. read_pointer <= read_pointer + 1;
    119. tx_done <= 1'b0;
    120. end
    121. end
    122. else if (read_pointer == NUMBER_OF_OUTPUT_WORDS)
    123. begin
    124. tx_done <= 1'b1; //如果读指针等于发送数据个数,完成信号为1
    125. end
    126. end
    127. assign tx_en = M_AXIS_TREADY && axis_tvalid; //读使能信号(从机+主机准备好)
    128. //生成数据输出
    129. always @( posedge M_AXIS_ACLK )
    130. begin
    131. if(!M_AXIS_ARESETN)
    132. begin
    133. stream_data_out <= 1;
    134. end
    135. else if (tx_en)
    136. begin
    137. stream_data_out <= read_pointer + 32'b1; //定义数据为指针+1
    138. end
    139. end
    140. /*
    141. 实现用户逻辑
    142. */
    143. endmodule

    1.2 源码展示

    1. `timescale 1 ns / 1 ps
    2. module axis_m_v1_0_M00_AXIS #
    3. (
    4. // Users to add parameters here
    5. // User parameters ends
    6. // Do not modify the parameters beyond this line
    7. // Width of S_AXIS address bus. The slave accepts the read and write addresses of width C_M_AXIS_TDATA_WIDTH.
    8. parameter integer C_M_AXIS_TDATA_WIDTH = 32,
    9. // Start count is the number of clock cycles the master will wait before initiating/issuing any transaction.
    10. parameter integer C_M_START_COUNT = 32
    11. )
    12. (
    13. // Users to add ports here
    14. // User ports ends
    15. // Do not modify the ports beyond this line
    16. // Global ports
    17. input wire M_AXIS_ACLK,
    18. //
    19. input wire M_AXIS_ARESETN,
    20. // Master Stream Ports. TVALID indicates that the master is driving a valid transfer, A transfer takes place when both TVALID and TREADY are asserted.
    21. output wire M_AXIS_TVALID,
    22. // TDATA is the primary payload that is used to provide the data that is passing across the interface from the master.
    23. output wire [C_M_AXIS_TDATA_WIDTH-1 : 0] M_AXIS_TDATA,
    24. // TSTRB is the byte qualifier that indicates whether the content of the associated byte of TDATA is processed as a data byte or a position byte.
    25. output wire [(C_M_AXIS_TDATA_WIDTH/8)-1 : 0] M_AXIS_TSTRB,
    26. // TLAST indicates the boundary of a packet.
    27. output wire M_AXIS_TLAST,
    28. // TREADY indicates that the slave can accept a transfer in the current cycle.
    29. input wire M_AXIS_TREADY
    30. );
    31. // Total number of output data
    32. localparam NUMBER_OF_OUTPUT_WORDS = 8;
    33. // function called clogb2 that returns an integer which has the
    34. // value of the ceiling of the log base 2.
    35. function integer clogb2 (input integer bit_depth);
    36. begin
    37. for(clogb2=0; bit_depth>0; clogb2=clogb2+1)
    38. bit_depth = bit_depth >> 1;
    39. end
    40. endfunction
    41. // WAIT_COUNT_BITS is the width of the wait counter.
    42. localparam integer WAIT_COUNT_BITS = clogb2(C_M_START_COUNT-1);
    43. // bit_num gives the minimum number of bits needed to address 'depth' size of FIFO.
    44. localparam bit_num = clogb2(NUMBER_OF_OUTPUT_WORDS);
    45. // Define the states of state machine
    46. // The control state machine oversees the writing of input streaming data to the FIFO,
    47. // and outputs the streaming data from the FIFO
    48. parameter [1:0] IDLE = 2'b00, // This is the initial/idle state
    49. INIT_COUNTER = 2'b01, // This state initializes the counter, once
    50. // the counter reaches C_M_START_COUNT count,
    51. // the state machine changes state to SEND_STREAM
    52. SEND_STREAM = 2'b10; // In this state the
    53. // stream data is output through M_AXIS_TDATA
    54. // State variable
    55. reg [1:0] mst_exec_state;
    56. // Example design FIFO read pointer
    57. reg [bit_num-1:0] read_pointer;
    58. // AXI Stream internal signals
    59. //wait counter. The master waits for the user defined number of clock cycles before initiating a transfer.
    60. reg [WAIT_COUNT_BITS-1 : 0] count;
    61. //streaming data valid
    62. wire axis_tvalid;
    63. //streaming data valid delayed by one clock cycle
    64. reg axis_tvalid_delay;
    65. //Last of the streaming data
    66. wire axis_tlast;
    67. //Last of the streaming data delayed by one clock cycle
    68. reg axis_tlast_delay;
    69. //FIFO implementation signals
    70. reg [C_M_AXIS_TDATA_WIDTH-1 : 0] stream_data_out;
    71. wire tx_en;
    72. //The master has issued all the streaming data stored in FIFO
    73. reg tx_done;
    74. // I/O Connections assignments
    75. assign M_AXIS_TVALID = axis_tvalid_delay;
    76. assign M_AXIS_TDATA = stream_data_out;
    77. assign M_AXIS_TLAST = axis_tlast_delay;
    78. assign M_AXIS_TSTRB = {(C_M_AXIS_TDATA_WIDTH/8){1'b1}};
    79. // Control state machine implementation
    80. always @(posedge M_AXIS_ACLK)
    81. begin
    82. if (!M_AXIS_ARESETN)
    83. // Synchronous reset (active low)
    84. begin
    85. mst_exec_state <= IDLE;
    86. count <= 0;
    87. end
    88. else
    89. case (mst_exec_state)
    90. IDLE:
    91. // The slave starts accepting tdata when
    92. // there tvalid is asserted to mark the
    93. // presence of valid streaming data
    94. //if ( count == 0 )
    95. // begin
    96. mst_exec_state <= INIT_COUNTER;
    97. // end
    98. //else
    99. // begin
    100. // mst_exec_state <= IDLE;
    101. // end
    102. INIT_COUNTER:
    103. // The slave starts accepting tdata when
    104. // there tvalid is asserted to mark the
    105. // presence of valid streaming data
    106. if ( count == C_M_START_COUNT - 1 )
    107. begin
    108. mst_exec_state <= SEND_STREAM;
    109. end
    110. else
    111. begin
    112. count <= count + 1;
    113. mst_exec_state <= INIT_COUNTER;
    114. end
    115. SEND_STREAM:
    116. // The example design streaming master functionality starts
    117. // when the master drives output tdata from the FIFO and the slave
    118. // has finished storing the S_AXIS_TDATA
    119. if (tx_done)
    120. begin
    121. mst_exec_state <= IDLE;
    122. end
    123. else
    124. begin
    125. mst_exec_state <= SEND_STREAM;
    126. end
    127. endcase
    128. end
    129. //tvalid generation
    130. //axis_tvalid is asserted when the control state machine's state is SEND_STREAM and
    131. //number of output streaming data is less than the NUMBER_OF_OUTPUT_WORDS.
    132. assign axis_tvalid = ((mst_exec_state == SEND_STREAM) && (read_pointer < NUMBER_OF_OUTPUT_WORDS));
    133. // AXI tlast generation
    134. // axis_tlast is asserted number of output streaming data is NUMBER_OF_OUTPUT_WORDS-1
    135. // (0 to NUMBER_OF_OUTPUT_WORDS-1)
    136. assign axis_tlast = (read_pointer == NUMBER_OF_OUTPUT_WORDS-1);
    137. // Delay the axis_tvalid and axis_tlast signal by one clock cycle
    138. // to match the latency of M_AXIS_TDATA
    139. always @(posedge M_AXIS_ACLK)
    140. begin
    141. if (!M_AXIS_ARESETN)
    142. begin
    143. axis_tvalid_delay <= 1'b0;
    144. axis_tlast_delay <= 1'b0;
    145. end
    146. else
    147. begin
    148. axis_tvalid_delay <= axis_tvalid;
    149. axis_tlast_delay <= axis_tlast;
    150. end
    151. end
    152. //read_pointer pointer
    153. always@(posedge M_AXIS_ACLK)
    154. begin
    155. if(!M_AXIS_ARESETN)
    156. begin
    157. read_pointer <= 0;
    158. tx_done <= 1'b0;
    159. end
    160. else
    161. if (read_pointer <= NUMBER_OF_OUTPUT_WORDS-1)
    162. begin
    163. if (tx_en)
    164. // read pointer is incremented after every read from the FIFO
    165. // when FIFO read signal is enabled.
    166. begin
    167. read_pointer <= read_pointer + 1;
    168. tx_done <= 1'b0;
    169. end
    170. end
    171. else if (read_pointer == NUMBER_OF_OUTPUT_WORDS)
    172. begin
    173. // tx_done is asserted when NUMBER_OF_OUTPUT_WORDS numbers of streaming data
    174. // has been out.
    175. tx_done <= 1'b1;
    176. end
    177. end
    178. //FIFO read enable generation
    179. assign tx_en = M_AXIS_TREADY && axis_tvalid;
    180. // Streaming output data is read from FIFO
    181. always @( posedge M_AXIS_ACLK )
    182. begin
    183. if(!M_AXIS_ARESETN)
    184. begin
    185. stream_data_out <= 1;
    186. end
    187. else if (tx_en)// && M_AXIS_TSTRB[byte_index]
    188. begin
    189. stream_data_out <= read_pointer + 32'b1;
    190. end
    191. end
    192. // Add user logic here
    193. // User logic ends
    194. endmodule

    2、AXIS从机部分

    1.1 中文注释

    1. `timescale 1 ns / 1 ps
    2. module axis_s_v1_0_S00_AXIS #
    3. (
    4. /*
    5. 用户可以自定义参数
    6. */
    7. //AXIS数据位宽
    8. parameter integer C_S_AXIS_TDATA_WIDTH = 32
    9. )
    10. (
    11. /*
    12. 用户可以在此自定义端口
    13. */
    14. input wire S_AXIS_ACLK, //时钟信号
    15. input wire S_AXIS_ARESETN, //复位信号
    16. output wire S_AXIS_TREADY, //ready信号,代表从机准备好了
    17. input wire [C_S_AXIS_TDATA_WIDTH-1 : 0] S_AXIS_TDATA, //数据信号
    18. input wire [(C_S_AXIS_TDATA_WIDTH/8)-1 : 0] S_AXIS_TSTRB, //数据修饰符,辨别字节类型
    19. input wire S_AXIS_TLAST, //last信号,拉高代表是传输中的最后一个字节
    20. input wire S_AXIS_TVALID //ready信号,代表从机准备好了
    21. );
    22. //函数:以2为低求对数,用于计算位宽
    23. function integer clogb2 (input integer bit_depth);
    24. begin
    25. for(clogb2=0; bit_depth>0; clogb2=clogb2+1)
    26. bit_depth = bit_depth >> 1;
    27. end
    28. endfunction
    29. localparam NUMBER_OF_INPUT_WORDS = 8; //输入数据个数
    30. localparam bit_num = clogb2(NUMBER_OF_INPUT_WORDS-1); //输入数据的位宽
    31. //状态机定义
    32. parameter [1:0] IDLE = 1'b0, //初始状态
    33. WRITE_FIFO = 1'b1; //读状态
    34. wire axis_tready; //ready信号
    35. reg mst_exec_state; //状态寄存器
    36. genvar byte_index; //字节索引
    37. wire fifo_wren; //FIFO写使能
    38. reg fifo_full_flag; //FIFO满标志
    39. reg [bit_num-1:0] write_pointer; //FIFO写指针
    40. reg writes_done; //写满标志
    41. assign S_AXIS_TREADY = axis_tready;
    42. //状态机
    43. always @(posedge S_AXIS_ACLK)
    44. begin
    45. if (!S_AXIS_ARESETN)
    46. begin
    47. mst_exec_state <= IDLE;
    48. end
    49. else
    50. case (mst_exec_state)
    51. IDLE:
    52. if (S_AXIS_TVALID)
    53. begin
    54. mst_exec_state <= WRITE_FIFO;
    55. end
    56. else
    57. begin
    58. mst_exec_state <= IDLE;
    59. end
    60. WRITE_FIFO:
    61. if (writes_done)
    62. begin
    63. mst_exec_state <= IDLE;
    64. end
    65. else
    66. begin
    67. mst_exec_state <= WRITE_FIFO;
    68. end
    69. endcase
    70. end
    71. //ready信号赋值,写状态+读指针写于等于接收数据总个数
    72. assign axis_tready = ((mst_exec_state == WRITE_FIFO) && (write_pointer <= NUMBER_OF_INPUT_WORDS-1));
    73. //写指针,写完成信号
    74. always@(posedge S_AXIS_ACLK)
    75. begin
    76. if(!S_AXIS_ARESETN)
    77. begin
    78. write_pointer <= 0;
    79. writes_done <= 1'b0;
    80. end
    81. else
    82. if (write_pointer <= NUMBER_OF_INPUT_WORDS-1)
    83. begin
    84. if (fifo_wren)
    85. begin
    86. write_pointer <= write_pointer + 1;
    87. writes_done <= 1'b0;
    88. end
    89. if ((write_pointer == NUMBER_OF_INPUT_WORDS-1)|| S_AXIS_TLAST)
    90. begin
    91. writes_done <= 1'b1;
    92. end
    93. end
    94. end
    95. //FIFO写使能信号
    96. assign fifo_wren = S_AXIS_TVALID && axis_tready;
    97. //例化4个宽为8,深度为8的二维数组stream_data_fifo,用来充当FIFO,每个FIFO依次写入数据的0-7;8-15;16-23;24-31位
    98. generate
    99. for(byte_index=0; byte_index<= (C_S_AXIS_TDATA_WIDTH/8-1); byte_index=byte_index+1)
    100. begin:FIFO_GEN
    101. reg [(C_S_AXIS_TDATA_WIDTH/4)-1:0] stream_data_fifo [0 : NUMBER_OF_INPUT_WORDS-1];
    102. //写入FIFO数据
    103. always @( posedge S_AXIS_ACLK )
    104. begin
    105. if (fifo_wren)// && S_AXIS_TSTRB[byte_index])
    106. begin
    107. stream_data_fifo[write_pointer] <= S_AXIS_TDATA[(byte_index*8+7) -: 8];
    108. end
    109. end
    110. end
    111. endgenerate
    112. /*
    113. 实现用户逻辑
    114. */
    115. endmodule

    1.2 源码展示

    1. `timescale 1 ns / 1 ps
    2. module axis_s_v1_0_S00_AXIS #
    3. (
    4. // Users to add parameters here
    5. // User parameters ends
    6. // Do not modify the parameters beyond this line
    7. // AXI4Stream sink: Data Width
    8. parameter integer C_S_AXIS_TDATA_WIDTH = 32
    9. )
    10. (
    11. // Users to add ports here
    12. // User ports ends
    13. // Do not modify the ports beyond this line
    14. // AXI4Stream sink: Clock
    15. input wire S_AXIS_ACLK,
    16. // AXI4Stream sink: Reset
    17. input wire S_AXIS_ARESETN,
    18. // Ready to accept data in
    19. output wire S_AXIS_TREADY,
    20. // Data in
    21. input wire [C_S_AXIS_TDATA_WIDTH-1 : 0] S_AXIS_TDATA,
    22. // Byte qualifier
    23. input wire [(C_S_AXIS_TDATA_WIDTH/8)-1 : 0] S_AXIS_TSTRB,
    24. // Indicates boundary of last packet
    25. input wire S_AXIS_TLAST,
    26. // Data is in valid
    27. input wire S_AXIS_TVALID
    28. );
    29. // function called clogb2 that returns an integer which has the
    30. // value of the ceiling of the log base 2.
    31. function integer clogb2 (input integer bit_depth);
    32. begin
    33. for(clogb2=0; bit_depth>0; clogb2=clogb2+1)
    34. bit_depth = bit_depth >> 1;
    35. end
    36. endfunction
    37. // Total number of input data.
    38. localparam NUMBER_OF_INPUT_WORDS = 8;
    39. // bit_num gives the minimum number of bits needed to address 'NUMBER_OF_INPUT_WORDS' size of FIFO.
    40. localparam bit_num = clogb2(NUMBER_OF_INPUT_WORDS-1);
    41. // Define the states of state machine
    42. // The control state machine oversees the writing of input streaming data to the FIFO,
    43. // and outputs the streaming data from the FIFO
    44. parameter [1:0] IDLE = 1'b0, // This is the initial/idle state
    45. WRITE_FIFO = 1'b1; // In this state FIFO is written with the
    46. // input stream data S_AXIS_TDATA
    47. wire axis_tready;
    48. // State variable
    49. reg mst_exec_state;
    50. // FIFO implementation signals
    51. genvar byte_index;
    52. // FIFO write enable
    53. wire fifo_wren;
    54. // FIFO full flag
    55. reg fifo_full_flag;
    56. // FIFO write pointer
    57. reg [bit_num-1:0] write_pointer;
    58. // sink has accepted all the streaming data and stored in FIFO
    59. reg writes_done;
    60. // I/O Connections assignments
    61. assign S_AXIS_TREADY = axis_tready;
    62. // Control state machine implementation
    63. always @(posedge S_AXIS_ACLK)
    64. begin
    65. if (!S_AXIS_ARESETN)
    66. // Synchronous reset (active low)
    67. begin
    68. mst_exec_state <= IDLE;
    69. end
    70. else
    71. case (mst_exec_state)
    72. IDLE:
    73. // The sink starts accepting tdata when
    74. // there tvalid is asserted to mark the
    75. // presence of valid streaming data
    76. if (S_AXIS_TVALID)
    77. begin
    78. mst_exec_state <= WRITE_FIFO;
    79. end
    80. else
    81. begin
    82. mst_exec_state <= IDLE;
    83. end
    84. WRITE_FIFO:
    85. // When the sink has accepted all the streaming input data,
    86. // the interface swiches functionality to a streaming master
    87. if (writes_done)
    88. begin
    89. mst_exec_state <= IDLE;
    90. end
    91. else
    92. begin
    93. // The sink accepts and stores tdata
    94. // into FIFO
    95. mst_exec_state <= WRITE_FIFO;
    96. end
    97. endcase
    98. end
    99. // AXI Streaming Sink
    100. //
    101. // The example design sink is always ready to accept the S_AXIS_TDATA until
    102. // the FIFO is not filled with NUMBER_OF_INPUT_WORDS number of input words.
    103. assign axis_tready = ((mst_exec_state == WRITE_FIFO) && (write_pointer <= NUMBER_OF_INPUT_WORDS-1));
    104. always@(posedge S_AXIS_ACLK)
    105. begin
    106. if(!S_AXIS_ARESETN)
    107. begin
    108. write_pointer <= 0;
    109. writes_done <= 1'b0;
    110. end
    111. else
    112. if (write_pointer <= NUMBER_OF_INPUT_WORDS-1)
    113. begin
    114. if (fifo_wren)
    115. begin
    116. // write pointer is incremented after every write to the FIFO
    117. // when FIFO write signal is enabled.
    118. write_pointer <= write_pointer + 1;
    119. writes_done <= 1'b0;
    120. end
    121. if ((write_pointer == NUMBER_OF_INPUT_WORDS-1)|| S_AXIS_TLAST)
    122. begin
    123. // reads_done is asserted when NUMBER_OF_INPUT_WORDS numbers of streaming data
    124. // has been written to the FIFO which is also marked by S_AXIS_TLAST(kept for optional usage).
    125. writes_done <= 1'b1;
    126. end
    127. end
    128. end
    129. // FIFO write enable generation
    130. assign fifo_wren = S_AXIS_TVALID && axis_tready;
    131. // FIFO Implementation
    132. generate
    133. for(byte_index=0; byte_index<= (C_S_AXIS_TDATA_WIDTH/8-1); byte_index=byte_index+1)
    134. begin:FIFO_GEN
    135. reg [(C_S_AXIS_TDATA_WIDTH/4)-1:0] stream_data_fifo [0 : NUMBER_OF_INPUT_WORDS-1];
    136. // Streaming input data is stored in FIFO
    137. always @( posedge S_AXIS_ACLK )
    138. begin
    139. if (fifo_wren)// && S_AXIS_TSTRB[byte_index])
    140. begin
    141. stream_data_fifo[write_pointer] <= S_AXIS_TDATA[(byte_index*8+7) -: 8];
    142. end
    143. end
    144. end
    145. endgenerate
    146. // Add user logic here
    147. // User logic ends
    148. endmodule

    四、仿真测试

    1、top

    1. module top(
    2. input clk,
    3. input rst_n
    4. );
    5. wire [31:0] axis_tdata;
    6. wire [3:0] axis_tstrb;
    7. wire axis_tlast;
    8. wire axis_tready;
    9. wire axis_tvalid;
    10. axis_m_0 axis_m_u0
    11. (
    12. .m00_axis_tdata (axis_tdata),
    13. .m00_axis_tstrb (axis_tstrb),
    14. .m00_axis_tlast (axis_tlast),
    15. .m00_axis_tvalid (axis_tvalid),
    16. .m00_axis_tready (axis_tready),
    17. .m00_axis_aclk (clk),
    18. .m00_axis_aresetn (rst_n)
    19. );
    20. axis_s_0 axis_s_u0
    21. (
    22. .s00_axis_tdata (axis_tdata),
    23. .s00_axis_tstrb (axis_tstrb),
    24. .s00_axis_tlast (axis_tlast),
    25. .s00_axis_tvalid (axis_tvalid),
    26. .s00_axis_tready (axis_tready),
    27. .s00_axis_aclk (clk),
    28. .s00_axis_aresetn (rst_n)
    29. );
    30. endmodule

    2、tb

    1. `timescale 1ns / 1ps
    2. module tb_top();
    3. reg clk,rst_n;
    4. initial begin
    5. clk = 0;
    6. rst_n = 1;
    7. #10
    8. rst_n = 0;
    9. #10
    10. rst_n = 1;
    11. end
    12. always #5 clk <= ~clk;
    13. top top_u1(.clk(clk),
    14. .rst_n(rst_n));
    15. endmodule

    3、结果

  • 相关阅读:
    Docker—概述与安装
    牛客刷题系列之进阶版(组队竞赛,排序子序列,倒置字符串, 删除公共字符,修理牧场)
    Ps:选框工具
    GitHub2022年度前100的Java面试真题&高频知识点汇总
    谷歌验证码无法显示问题
    哈希加盐算法
    java计算机毕业设计小区物业管理系统演示录像2020源码+数据库+系统+lw文档+mybatis+运行部署
    基于工业互联网平台智能制造方案【工业互联网甄选联盟】
    垃圾回收 - 复制算法
    RandomForestClassifier 与 GradientBoostingClassifier 的区别
  • 原文地址:https://blog.csdn.net/apple_53311083/article/details/134071768