3. 可配置尺寸的滑动窗口生成器

3. 可配置尺寸的滑动窗口生成器 学习卡片

任务目标

设计一个参数化窗口大小的滑动窗口生成器,通过参数WIN_SIZE配置窗口尺寸(支持3x3、5x5等),从串行像素输入流中生成对应的二维窗口数据,供后续卷积运算直接使用。

设计要点

  • 输入为单像素流(每时钟1个有效像素),输出为WIN_SIZE*WIN_SIZE个并行像素,构成当前窗口快照。
  • 内部使用行缓冲(Line Buffer)暂存WIN_SIZE-1行数据,每行深度为IMG_WIDTH。
  • 窗口数据在像素有效时逐周期更新,输出与输入像素对齐(当前像素位于窗口右下角)。
  • 通过parameter实现窗口尺寸可配置,无需修改RTL逻辑结构。

Verilog实现

module sliding_window #(
    parameter WIN_SIZE  = 3,          // 窗口尺寸:3或5
    parameter IMG_WIDTH = 8,          // 图像行宽(像素数)
    parameter DATA_W    = 8           // 像素位宽
)(
    input  wire                     clk,
    input  wire                     rst_n,
    input  wire                     px_valid,   // 输入像素有效
    input  wire [DATA_W-1:0]        px_in,      // 输入像素
    output reg  [WIN_SIZE*WIN_SIZE*DATA_W-1:0] win_data, // 窗口并行输出
    output reg                      win_valid   // 窗口有效(已填满)
);

    // 行缓冲:WIN_SIZE-1行,每行IMG_WIDTH个像素
    reg [DATA_W-1:0] line_buf [WIN_SIZE-1][IMG_WIDTH-1:0];
    // 当前窗口寄存器
    reg [DATA_W-1:0] win_reg [WIN_SIZE-1:0][WIN_SIZE-1:0];
    
    integer i, j;
    reg [7:0] col_cnt;   // 当前列计数
    reg [7:0] row_cnt;   // 当前行计数
    
    // 列计数与行计数
    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 == IMG_WIDTH-1) begin
                col_cnt <= 0;
                if (row_cnt == IMG_WIDTH-1)
                    row_cnt <= 0;
                else
                    row_cnt <= row_cnt + 1;
            end else begin
                col_cnt <= col_cnt + 1;
            end
        end
    end
    
    // 写入行缓冲(延迟1拍,使当前像素与窗口输出对齐)
    reg [DATA_W-1:0] px_d1;
    reg px_valid_d1;
    always @(posedge clk or negedge rst_n) begin
        if (!rst_n) begin
            px_d1 <= 0;
            px_valid_d1 <= 0;
        end else begin
            px_d1 <= px_in;
            px_valid_d1 <= px_valid;
        end
    end
    
    // 行缓冲写入与移位
    integer k;
    always @(posedge clk or negedge rst_n) begin
        if (!rst_n) begin
            for (i = 0; i < WIN_SIZE-1; i = i + 1)
                for (j = 0; j < IMG_WIDTH; j = j + 1)
                    line_buf[i][j] <= 0;
        end else if (px_valid_d1) begin
            // 第0行缓冲接收新像素
            for (j = IMG_WIDTH-1; j > 0; j = j - 1)
                line_buf[0][j] <= line_buf[0][j-1];
            line_buf[0][0] <= px_d1;
            // 其余行缓冲从上一行移位
            for (i = 1; i < WIN_SIZE-1; i = i + 1) begin
                for (j = IMG_WIDTH-1; j > 0; j = j - 1)
                    line_buf[i][j] <= line_buf[i][j-1];
                line_buf[i][0] <= line_buf[i-1][IMG_WIDTH-1];
            end
        end
    end
    
    // 窗口寄存器更新
    always @(posedge clk or negedge rst_n) begin
        if (!rst_n) begin
            for (i = 0; i < WIN_SIZE; i = i + 1)
                for (j = 0; j < WIN_SIZE; j = j + 1)
                    win_reg[i][j] <= 0;
            win_valid <= 0;
        end else if (px_valid_d1) begin
            // 新像素进入窗口右下角
            win_reg[WIN_SIZE-1][WIN_SIZE-1] <= px_d1;
            // 窗口内右移
            for (i = 0; i < WIN_SIZE; i = i + 1)
                for (j = WIN_SIZE-1; j > 0; j = j - 1)
                    win_reg[i][j] <= win_reg[i][j-1];
            // 窗口行间下移(从行缓冲取上一行最右像素)
            for (i = WIN_SIZE-1; i > 0; i = i - 1)
                win_reg[i][0] <= win_reg[i-1][WIN_SIZE-1];
            win_reg[0][0] <= line_buf[WIN_SIZE-2][IMG_WIDTH-1];
            
            // 窗口有效条件:行列计数均达到窗口边界
            if (row_cnt >= WIN_SIZE-1 && col_cnt >= WIN_SIZE-1)
                win_valid <= 1;
            else
                win_valid <= 0;
        end else begin
            win_valid <= 0;
        end
    end
    
    // 并行输出
    always @(*) begin
        for (i = 0; i < WIN_SIZE; i = i + 1)
            for (j = 0; j < WIN_SIZE; j = j + 1)
                win_data[(i*WIN_SIZE + j)*DATA_W +: DATA_W] = win_reg[i][j];
    end

endmodule

仿真测试要点

  • 实例化时设置WIN_SIZE=3、IMG_WIDTH=8,输入连续递增像素值0~63。
  • 观察win_valid信号:当输入第(WIN_SIZE-1)*IMG_WIDTH + WIN_SIZE-1个像素(即第3行第3列)时,win_valid首次拉高。
  • 检查win_data输出:窗口内容应为当前像素及其上方、左方相邻像素,例如第3行第3列像素值为18时,窗口应为[8,9,10; 16,17,18](按行展开)。
  • 修改WIN_SIZE=5重新仿真,验证窗口尺寸参数化生效。

验证通过标准

  • win_valid拉高时机与理论计算一致(第(WIN_SIZE-1)*IMG_WIDTH + WIN_SIZE-1个有效像素)。
  • win_data中每个像素位置与输入流顺序严格对应,无错位、无重复。
  • 参数WIN_SIZE改为5后,窗口输出尺寸变为25个像素,且时序逻辑无需修改。