DMA数据发送缓存模块实现

发布时间 2023-07-05 10:52:36作者: 李白的白

DMA数据发送缓存模块实现

graph TD A[DMA数据发送缓存模块实现] --> B[目的] A --> C[原理] A --> D[实现] B --> E[把池化后的数据返回给PS端的ADI3] C --> F[使用FIFO作为存储载体] C --> G[设置FIFO的位宽和深度] D --> H[复制输入数据缓存模块] D --> I[修改端口名和信号名] D --> J[连接FIFO的写使能和写数据] D --> K[留出FIFO的读使能和读数据]
  • 背景

    • 在卷积计算、量化和激活之后,需要把池化后的数据返回给PS端ADI3

      DMA:Direct Memory Access,直接内存访问,是一种可以让外设直接访问内存而不经过CPU的技术,可以提高数据传输的效率

      ADI3:Application Debug Interface 3,应用调试接口3,是一种可以让PS端和PL端进行双向通信的接口,可以用于传输数据或指令

    • 需要通过DMA把数据发送出去,所以在发送之前需要一个缓存模块

    • 缓存模块的设计以layer 0为例,后面会逐步完善其他层的兼容

  • 缓存模块的设计(原理)

    • 选择用FIFO作为缓存载体
      • 因为FIFO有先进先出的特点,可以实现数据的缓存和同步,方便数据的读写
      • FIFO可以根据需要设置位宽和深度,以适应不同的数据格式和量
      • FIFO可以简化数据的读写操作,只需要控制读写使能信号
    • FIFO的位宽为64bit,因为每个通道的数据为18bit,共8个通道
    • FIFO的深度为4096,和输入数据缓存的深度一致,以适应不同层的数据量
    • 缓存模块只需要把池化后的数据写入FIFO,然后由DMA发送模块去读取FIFO中的数据
    • 缓存模块可以复用输入数据缓存模块的代码,只需要修改一些信号名称和接口
    • 封装写入端口(buffer_write_en, buffer_write_data)
    • 封装读出端口(buffer_read_en, buffer_read_data)
  • 在顶层模块中调用缓存模块

    • 连接池化模块的输出到缓存模块的输入
    • 连接缓存模块的输出到DMA发送模块的输入
    • 根据池化后的数据有效标志控制写入使能信号
    • 根据DMA发送模块的需求控制读出使能信号
  • 注意:

    • 对于其他层的数据缓存,需要对缓存模块做一些完善和兼容
    • 对于没有池化操作的层,需要对写使能信号做一个选择
  • 缓存模块的仿真

    • 查看池化后的数据情况,确认数据位宽和有效标志
    • 把缓存模块替换到顶层设计中,连接好信号线
    • 运行仿真,观察缓存模块的读写情况

代码清单:

module  tx_buffer(
        // system signals
        input                   sclk                    ,       
        input                   s_rst_n                 ,       
        // in 
        input           [63:0]  buffer_wr_data          ,       
        input                   buffer_wr_en            ,       
        // Read
        input                   buffer_rd_en            ,       
        output  wire    [63:0]  buffer_rd_data          ,
        // 
        input                   read_start              ,       
        output  reg     [12:0]  buffer_data_count              
);

//========================================================================\
// =========== Define Parameter and Internal signals =========== 
//========================================================================/

wire    [12:0]                  data_count                      ;       


//=============================================================================
//**************    Main Code   **************
//=============================================================================
always  @(posedge sclk or negedge s_rst_n) begin
        if(s_rst_n == 1'b0)
                buffer_data_count       <=      'd0;
        else if(read_start == 1'b1)
                buffer_data_count       <=      data_count;
end

feature_fifo_ip feature_fifo_ip_inst (
        .clk                    (sclk                   ),      // input wire clk
        .srst                   (~s_rst_n               ),      // input wire srst
        .din                    (buffer_wr_data         ),      // input wire [63 : 0] din
        .wr_en                  (buffer_wr_en           ),      // input wire wr_en
        .rd_en                  (buffer_rd_en           ),      // input wire rd_en
        .dout                   (buffer_rd_data         ),      // output wire [63 : 0] dout
        .full                   (                       ),      // output wire full
        .empty                  (                       ),      // output wire empty
        .data_count             (data_count             )// output wire [12 : 0] data_count
);

endmodule