UpSample模块实现
UpSample模块的原理和功能:UpSample模块是用来将输入数据的尺寸放大的,它的原理是将每个数据复制四次,从而使得输出数据的尺寸变为输入数据的两倍。例如,如果输入数据是22的,那么输出数据就是44的。UpSample模块在神经网络中可以用来实现上采样的操作,提高图像的分辨率或者恢复图像的细节。
-
UpSample模块的作用是将输入数据的尺寸放大,例如将2x2的数据变成4x4的数据,本质上是对每个数据进行复制,一个变成四个
-
UpSample模块的实现原理是利用FPGA的PS端和PL端进行数据的传输和处理
-
UpSample模块的实现流程如下:
- 第一步:PS端向PL端发送输入数据
- 使用IP核中的FIFO缓存输入数据
- FIFO位宽为64比特,深度为4096
- 每次发送8个通道的数据,每个通道需要发送16次才能完成128个通道的传输
- FIFO深度2704即可存储所有输入数据
- 第二步:PL端执行UpSample操作
- PL端从缓存FIFO中读取输入数据,每隔一个双周期读取一个数据,并对其进行缓存
- 然后将一个数据复制成四个数据,并通过AXI接口发送到PS端,同时将第一行的数据写入另一个FIFO中进行缓存,该FIFO的位宽是64比特,深度是26
- 第三步:PL端通过DMA返回(PS端)输出数据
- PL端从另一个FIFO中读取第一行的数据,并通过AXI接口发送到PS端,完成第二行的输出,以此类推,直到所有输出数据都发送完毕,输出数据是26x26x128的矩阵
- 第一步:PS端向PL端发送输入数据
-
UpSample模块的实现优化如下:
-
将第二步和第三步合并,边执行UpSample操作,边通过AXI接口发送数据到PS端,减少缓存时间和空间(不需要缓存结果)
-
根据AXI接口的ready信号和value信号进行握手操作,控制数据的读取和发送时机,避免数据丢失或重复
-
UpSample的优化方法实现思路

- 为了提高效率,可以将第二步和第三步合并,即边执行UpSample操作,边发送输出数据,不需要额外缓存输出结果
- 为了实现这种优化方法,需要注意以下几点:
- 在奇数行时,每隔一个时钟周期读取输入buffer的数据,并对其进行寄存
- 在奇数行时,将UpSample后的结果写入另一个深度为26的FIFO进行缓存
- 在偶数行时,不读取输入buffer的数据,而是将另一个FIFO的数据读出并发送
- 利用两个计数器(col_cnt和row_cnt)控制读写时序和last信号
- 在发送数据时,需要根据AXI Stream接口的valid和ready信号进行握手handshake,以及根据last信号判断是否发送完毕
UpSample在Vivado HLS中的实现时序

- 在UpSample start信号来到后,状态机跳转到UpSample状态,并开始执行UpSample操作
- 在奇数行时,每隔一个时钟周期读取输入缓存的数据,并对其进行缓存(打拍),同时将UpSample的结果写入另一个深度为26的FIFO进行缓存
- 在偶数行时,不读取输入缓存的数据,而是将另一个FIFO的数据读出,并通过AXI Stream接口发送
- 在发送数据时,需要根据value信号和ready信号进行握手操作(handshake),并根据row_cnt和col_cnt判断是否发送last信号
- 状态机跳转到UpSample状态时开始工作
- buffer_read_en信号控制输入buffer的读取,每隔一个双周期拉高一次
- buffer_read_data信号输出读取的数据,并寄存到reg_ie中
- reg_ie和buffer_read_data共同构成AXI Stream的tdata信号
- tvalid信号在UpSample状态时一直为高,直到last信号为高时拉低
- tready信号由外部控制,影响handshake信号和计数器的加法操作
- handshake信号等于tvalid和tready的与操作,表示握手成功
- col_cnt在handshake为高时加1,到达25时清零,并使row_cnt加1
- row_cnt在UpSample状态时加1,到达415时清零,并跳出UpSample状态
- fifo_write_en信号在奇数行且handshake为高时拉高一次,将UpSample结果写入第一个FIFO中
- fifo_read_en信号在偶数行且handshake为高时拉高一次,将第一个FIFO中的数据读出发送
代码清单:
`include "debug_ctrl.h"
module upsample(
// system signals
input sclk ,
input s_rst_n ,
//
input [ 5:0] state ,
output wire buffer_rd_en ,
input [63:0] buffer_rd_data ,
//
output wire [63:0] axis_tdata ,
output wire axis_tvalid ,
input axis_tready ,
output reg axis_tlast ,
//
output wire upsample_finish
);
//========================================================================\
// =========== Define Parameter and Internal signals ===========
//========================================================================/
localparam COL_END = 'd26 ;
`ifndef SIM
localparam ROW_END = 'd416 ;
`else
localparam ROW_END = 'd26 ;
`endif
reg [ 4:0] col_cnt ;
reg [ 8:0] row_cnt ;
reg [63:0] buffer_rd_data_r1 ;
wire hand_shake ;
wire fifo_wr_en ;
wire fifo_rd_en ;
wire [63:0] fifo_rd_data ;
//=============================================================================
//************** Main Code **************
//=============================================================================
assign buffer_rd_en = (col_cnt[0] == 1'b0 && row_cnt[0] == 1'b0) ? hand_shake : 1'b0;
assign axis_tdata = (row_cnt[0] == 1'b0) ? ((buffer_rd_en == 1'b1) ? buffer_rd_data : buffer_rd_data_r1) : fifo_rd_data;
assign axis_tvalid = state[4];
assign hand_shake = axis_tvalid & axis_tready;
assign fifo_wr_en = (row_cnt[0] == 1'b0) ? hand_shake : 1'b0;
assign fifo_rd_en = (row_cnt[0] == 1'b1) ? hand_shake : 1'b0;
assign upsample_finish = axis_tlast;
always @(posedge sclk or negedge s_rst_n) begin
if(s_rst_n == 1'b0)
col_cnt <= 'd0;
else if(col_cnt == COL_END-1 && hand_shake == 1'b1)
col_cnt <= 'd0;
else if(hand_shake == 1'b1)
col_cnt <= col_cnt + 1'b1;
end
always @(posedge sclk or negedge s_rst_n) begin
if(s_rst_n == 1'b0)
row_cnt <= 'd0;
else if(state[4] == 1'b0)
row_cnt <= 'd0;
else if(col_cnt == COL_END-1 && hand_shake == 1'b1)
row_cnt <= row_cnt + 1'b1;
end
always @(posedge sclk or negedge s_rst_n) begin
if(s_rst_n == 1'b0)
buffer_rd_data_r1 <= 64'h0;
else if(buffer_rd_en == 1'b1)
buffer_rd_data_r1 <= buffer_rd_data;
end
always @(posedge sclk or negedge s_rst_n) begin
if(s_rst_n == 1'b0)
axis_tlast <= 1'b0;
else if(col_cnt == COL_END-2 && row_cnt == (ROW_END-1) && hand_shake == 1'b1)
axis_tlast <= 1'b1;
else
axis_tlast <= 1'b0;
end
up_fifo_ip up_fifo_ip_inst (
.clk (sclk ), // input wire clk
.srst (~s_rst_n ), // input wire srst
.din (axis_tdata ), // input wire [63 : 0] din
.wr_en (fifo_wr_en ), // input wire wr_en
.rd_en (fifo_rd_en ), // input wire rd_en
.dout (fifo_rd_data ), // output wire [63 : 0] dout
.full ( ), // output wire full
.empty ( ), // output wire empty
.data_count ( )// output wire [5 : 0] data_count
);
endmodule