前言:在图像处理和AI算法领域,由于经常需要与卷积核进行卷积运算,所以需要对串行数据进行出窗处理,比如对输入信号进行缓存,之后输出一个N*N大小的窗口,本文主要讲解缓存出窗的常用思路。
需求
对串行输入数据进行缓存,并输出一个9*9的窗口,其中与上下级交互以握手的形式。
输入
- 32bit串行打包数据data,相当于4个像素
- 数据有效使能信号valid_i
- 图像行像素数width
- 图像列像素数height
- 下级握手信号ready_i
- 时钟clk
- 复位rst_n
- 模块开启信号start
输出
- 上级握手信号ready_o
- 9*9窗口有效信号window_valid
- 9*9窗口数据[647:0] window_data
伪代码
module pixel2window(
);
parameter WINDOW_RADIUS = 4;
parameter FIFO_DEPTH = 247;
parameter WINDOW_WIDTH = WINDOW_RADIUS * 2;
localparam IDLE = 2'd0;
localparam WRITE_FST_8LINES = 2'd1;
localparam READ_9X9 = 2'd1;
input clk;
input rst_n;
input valid_i;
output ready_o;
input [31:0] data;
input ready_i;
output window_valid;
output [647:0] window_data;
input height;
input width;
input start;
output done;
//***************************************************
// MAIN CODE
//***************************************************
// STATE TRANS
//***************************************************
assign beats_num = width[9:2] + {7'd0, |width[1:0]} - 8'd1;
always@(posedge clk or negedge rst_n)begin
if(!rst_n)
curr_state <= 2'd0;
else
curr_state <= next_state;
end
assign wr_fst_8lines_done = (cnt_wr_line == 14'd6) && wr_turn;
assign rd_9x9_done = (cnt_rd_all_line == height - WINDOW_WIDTH) && rd_turn;
always@(*)begin
case(curr_state)
IDLE: begin
if(start)
next_state = WRITE_FST_8LINES;
else
next_state = IDLE;
end
WRITE_FST_8LINES: begin
if(wr_fst_8lines_done)
next_state = READ_9X9;
else
next_state = WRITE_FST_8LINES;
end
READ_9X9: begin
if(rd_9x9_done)
next_state = IDLE;
else
next_state = READ_9X9;
end
endcase
end
//****************************************************
// WRITE 8 RAMS
//****************************************************
assign wr_en_top = valid_i;
always@(posedge clk or negedge rst_n)begin
if(!rst_n)
cnt_wr_pix <= 9'd0;
else if(wr_en_top)begin
if(cnt_wr_pix == beats_num)
cnt_wr_pix <= 9'd0;
else
cnt_wr_pix <= cnt_wr_pix + 9'd1;
end
end
assign wr_turn = wr_en_top && (cnt_wr_pix == beats_num);
always@(posedge clk or negedge rst_n)begin
if(!rst_n)
cnt_wr_line <= 4'd0;
else if(done)
cnt_wr_line <= 4'd0;
else if(wr_turn)
cnt_wr_line <= cnt_wr_line + 4'd1;
end
genvar i;
generate
for(i = 1; i < 8; i = i + 1)begin: wr_en_i
assign wr_en[i] = (cnt_wr_line == i) ? wr_en_top : 1'b0;
end
endgenerate
genvar j;
generate
for(j = 0; j < 8; j = j + 1)begin: wr_addr_j
always@(posedge clk or negedge rst_n)begin
if(!rst_n)
wr_addr[j] <= 8'd0;
else if(done)
wr_addr[j] <= 8'd0;
else if(wr_en[j])begin
if(wr_addr[j] == FIFO_DEPTH)begin
wr_addr[j] <= 8'd0;
else
wr_addr[j] <= wr_addr[j] + 8'd1;
end
end
end
endgenerate
//*****************************************************************
// READ WINDOW'S DATA AND CONTROL
//*****************************************************************
always@(*)begin
if(curr_state = WRITE_FST_8LINES)
ready_o = 1'b1;
else if(curr_state == READ_9X9)begin
if(ready_en)
ready_o = 1'b1;
else
ready_o = 1'b0
end
else
ready_o = 1'b0;
end
assign ready_en = ~valid_i_ff1 && ~valid_i_ff2 && valid_i_ff3 && ready_i;
assign rd_en = curr_state == READ_9X9 ? wr_en_top_ff1 : 1'b0;
always@(posedge clk or negedge rst_n)begin
if(!rst_n)
rd_addr <= 9'd0;
else if(done)
rd_addr <= 9'd0;
else if(rd_en)begin
if(rd_addr ==