DMA数据发送缓存模块实现
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)
- 选择用FIFO作为缓存载体
-
在顶层模块中调用缓存模块
- 连接池化模块的输出到缓存模块的输入
- 连接缓存模块的输出到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