1. 3x3卷积核的滑动窗口生成器
任务目标
实现一个3x3卷积核的滑动窗口生成器,从串行输入的像素流中提取3x3窗口数据,为后续卷积计算提供并行窗口输出。输入为单像素时钟流,输出为9个对齐的像素值。
接口定义
module window_3x3 #(
parameter DW = 8, // 像素位宽
parameter IW = 8, // 图像宽度(像素数)
parameter IH = 8 // 图像高度(像素数)
)(
input wire clk,
input wire rst_n,
input wire px_valid, // 输入像素有效
input wire [DW-1:0] px_in, // 串行输入像素
output reg [DW-1:0] w11, w12, w13, // 窗口第1行
output reg [DW-1:0] w21, w22, w23, // 窗口第2行
output reg [DW-1:0] w31, w32, w33, // 窗口第3行
output reg win_valid // 窗口有效(已填满3行)
);
实现方案
采用行缓冲(Line Buffer)结构:使用2个移位寄存器分别缓存第1行和第2行数据,当前输入像素作为第3行。每个时钟周期,当像素有效时,三行数据同步右移,形成3x3窗口。窗口有效信号在输入像素位于第3行第3列及之后的位置拉高。
关键完整代码
module window_3x3 #(
parameter DW = 8,
parameter IW = 8,
parameter IH = 8
)(
input wire clk,
input wire rst_n,
input wire px_valid,
input wire [DW-1:0] px_in,
output reg [DW-1:0] w11, w12, w13,
output reg [DW-1:0] w21, w22, w23,
output reg [DW-1:0] w31, w32, w33,
output reg win_valid
);
// 行缓冲:每行缓存 IW 个像素
reg [DW-1:0] line_buf [0:1][0:IW-1]; // [行][列]
// 列计数器与行计数器
reg [$clog2(IW)-1:0] col_cnt;
reg [$clog2(IH)-1:0] row_cnt;
// 内部窗口寄存器
reg [DW-1:0] w11_r, w12_r, w13_r;
reg [DW-1:0] w21_r, w22_r, w23_r;
reg [DW-1:0] w31_r, w32_r, w33_r;
integer i;
// 行列计数
always @(posedge clk or negedge rst_n) begin
if (!rst_n) begin
col_cnt <= 0;
row_cnt <= 0;
end else if (px_valid) begin
if (col_cnt == IW-1) begin
col_cnt <= 0;
row_cnt <= (row_cnt == IH-1) ? 0 : row_cnt + 1;
end else begin
col_cnt <= col_cnt + 1;
end
end
end
// 行缓冲写入与移位
always @(posedge clk or negedge rst_n) begin
if (!rst_n) begin
for (i = 0; i < IW; i = i + 1) begin
line_buf[0][i] <= {DW{1'b0}};
line_buf[1][i] <= {DW{1'b0}};
end
end else if (px_valid) begin
// 第0行缓冲:写入当前像素,同时整体左移
for (i = IW-1; i > 0; i = i - 1)
line_buf[0][i] <= line_buf[0][i-1];
line_buf[0][0] <= px_in;
// 第1行缓冲:从第0行缓冲的移出端取数
for (i = IW-1; i > 0; i = i - 1)
line_buf[1][i] <= line_buf[1][i-1];
line_buf[1][0] <= line_buf[0][IW-1];
end
end
// 窗口输出组合逻辑
always @(*) begin
// 第1行窗口 = 第0行缓冲末尾3个
w11_r = line_buf[0][IW-3];
w12_r = line_buf[0][IW-2];
w13_r = line_buf[0][IW-1];
// 第2行窗口 = 第1行缓冲末尾3个
w21_r = line_buf[1][IW-3];
w22_r = line_buf[1][IW-2];
w23_r = line_buf[1][IW-1];
// 第3行窗口 = 当前输入像素及其前2个(需额外寄存器)
w31_r = px_dly2;
w32_r = px_dly1;
w33_r = px_in;
end
// 当前行像素延迟
reg [DW-1:0] px_dly1, px_dly2;
always @(posedge clk or negedge rst_n) begin
if (!rst_n) begin
px_dly1 <= {DW{1'b0}};
px_dly2 <= {DW{1'b0}};
end else if (px_valid) begin
px_dly1 <= px_in;
px_dly2 <= px_dly1;
end
end
// 输出赋值
always @(posedge clk or negedge rst_n) begin
if (!rst_n) begin
w11 <= 0; w12 <= 0; w13 <= 0;
w21 <= 0; w22 <= 0; w23 <= 0;
w31 <= 0; w32 <= 0; w33 <= 0;
win_valid <= 0;
end else begin
w11 <= w11_r; w12 <= w12_r; w13 <= w13_r;
w21 <= w21_r; w22 <= w22_r; w23 <= w23_r;
w31 <= w31_r; w32 <= w32_r; w33 <= w33_r;
// 窗口有效条件:已处理至少3行且当前列>=2
win_valid <= (row_cnt >= 2) && (col_cnt >= 2) && px_valid;
end
end
endmodule
运行与验证
Testbench要点:
- 按行输入8x8灰度图像,每个时钟一个像素,px_valid拉高
- 观察win_valid拉高时的w11~w33输出
- 验证第3行第3列像素输入后,窗口内容应为图像左上角3x3区域
// 测试激励核心片段
initial begin
rst_n = 0; px_valid = 0; px_in = 0;
#20 rst_n = 1;
// 输入8x8图像,像素值 = row*8 + col
for (r = 0; r < 8; r = r + 1) begin
for (c = 0; c < 8; c = c + 1) begin
@(posedge clk);
px_valid = 1;
px_in = r*8 + c;
end
end
@(posedge clk); px_valid = 0;
end
通过条件:当第3行第3列像素(值=18)输入后的下一个时钟沿,win_valid拉高,且w11=0, w12=1, w13=2, w21=8, w22=9, w23=10, w31=16, w32=17, w33=18。仿真波形中窗口数据与预期一致即验证通过。
边界说明
本设计针对图像尺寸≥3x3的情况。当图像边缘像素输入时,窗口包含边界外数据(填充为0),实际卷积时需根据边界处理策略(如复制、补零)调整。行缓冲深度由IW参数决定,综合时按实际图像宽度配置。