基于FPGA的卷积神经网络实现-Step2 卷积模块设计

文档说明 :本文档是 Step 2------CNN 流式卷积加速器的子模块级详细设计报告。Step 1 建立了"分块 + 迭代"的数学框架并论证了算子层可行性;Step 2 在此基础上将理论落地为硬件微架构,聚焦于单个子模块 Conv_Kernel.V 的完整 RTL 设计。全文覆盖 Step1 核心回顾、模块接口与数据格式、五级流水线详细设计、BRAM 与 FIFO 资源计算以及多层次验证策略。所有设计同时覆盖 C S I Z E = 3 C_{SIZE}=3 CSIZE=3(9 子模块)和 C S I Z E = 5 C_{SIZE}=5 CSIZE=5(25 子模块)两种配置,推荐优先实现 C S I Z E = 3 C_{SIZE}=3 CSIZE=3。


目录

  1. [设计背景与 Step1 核心回顾](#设计背景与 Step1 核心回顾)
  2. 模块接口与数据格式
  3. 五级流水线详细设计
  4. [BRAM 与 FIFO 资源计算](#BRAM 与 FIFO 资源计算)

1. 设计背景与 Step1 核心回顾

1.1 从算法到硬件:为什么需要"分块"

二维卷积是 CNN 推理的算力瓶颈。一个 C S I Z E × C S I Z E C_{SIZE} \times C_{SIZE} CSIZE×CSIZE 的卷积核对一帧 F R A M E _ S I Z E × F R A M E _ S I Z E FRAME\_SIZE \times FRAME\_SIZE FRAME_SIZE×FRAME_SIZE 的图像执行 same 卷积,需要完成 F R A M E _ S I Z E 2 × C S I Z E 2 FRAME\SIZE^2 \times C{SIZE}^2 FRAME_SIZE2×CSIZE2 次乘法累加。在 FPGA 上实现高性能流式卷积,面临三项挑战:

  1. 吞吐量:目标达到每时钟周期处理一个(一批)输入像素,即流水线不阻塞、不丢拍
  2. 存储带宽:每个输出位置的部分和需要反复读写,BRAM 端口数受限,直接映射会导致频繁的读写冲突
  3. 并行度 : C S I Z E 2 C_{SIZE}^2 CSIZE2 次乘累加无法在单周期内串行完成,必须并行展开

Step1 报告建立的分块+迭代同时解决了这三项挑战:

  • 分块 :将输出空间按行列坐标对 C S I Z E C_{SIZE} CSIZE 取模的余数划分为 C S I Z E 2 C_{SIZE}^2 CSIZE2 个互不重叠的"责任田",每块交由一个专属子模块 K ( i , j ) K(i, j) K(i,j) 独立管辖。 3 × 3 3\times 3 3×3 卷积分 9 块, 5 × 5 5\times 5 5×5 卷积分 25 块,块间零依赖、零通信。
  • 迭代:每个子模块面对逐个到达的像素,在每个时钟周期内就地完成多项判定------激活条件、权重选择、输出归属、更新判定。部分和随像素流动逐次累积,最后一个依赖像素到达的同一周期即产出结果,零缓冲、零等待。

Step2 聚焦 C S I Z E 2 C_{SIZE}^2 CSIZE2 个子模块中任意一个 的微观硬件实现------即单个 Conv_Kernel.V 的内部结构。下文所有流水级、BRAM 规格、验证方案均以"一个子模块"为讨论单位。

1.2 配置参数

参数 符号 可选值 默认值 说明
卷积核尺寸 C S I Z E C_{SIZE} CSIZE 3 或 5 3 卷积核行列数,决定分块数与感受野大小
行偏移 i i i [ 0 , C S I Z E − 1 ] [0, C_{SIZE}-1] [0,CSIZE−1] 例化决定 子模块在分块网格中的行索引
列偏移 j j j [ 0 , C S I Z E − 1 ] [0, C_{SIZE}-1] [0,CSIZE−1] 例化决定 子模块在分块网格中的列索引
帧尺寸 F R A M E _ S I Z E FRAME\_SIZE FRAME_SIZE 任意正整数 128 输入/输出图像的行列像素数
Padding 宽度 P P P 1 或 2 ( C S I Z E − 1 ) / 2 (C_{SIZE}-1)/2 (CSIZE−1)/2 same 模式零填充半宽

1.3 七项核心公式

以下七项公式是 Step1 推导的闭式判定公式,构成流水线各级组合逻辑的数学基础。为便于交叉引用,每条公式标注了其在流水线中的对应级。

公式一:激活条件与输出坐标

给定输入像素坐标 ( x i n , y i n ) (x_{in}, y_{in}) (xin,yin) 和子模块索引 ( i , j ) (i, j) (i,j),该像素在该子模块中所贡献的输出坐标 ( x o u t , y o u t ) (x_{out}, y_{out}) (xout,yout) 为:

x o u t = x i n − P + ( ( i − x i n + P )   m o d   C S I Z E ) y o u t = y i n − P + ( ( j − y i n + P )   m o d   C S I Z E ) \boxed{ \begin{aligned} x_{out} &= x_{in} - P + \big((i - x_{in} + P) \bmod C_{SIZE}\big) \\[4pt] y_{out} &= y_{in} - P + \big((j - y_{in} + P) \bmod C_{SIZE}\big) \end{aligned} } xoutyout=xin−P+((i−xin+P)modCSIZE)=yin−P+((j−yin+P)modCSIZE)

当且仅当该坐标落在图像有效范围内时,当前像素对子模块 K ( i , j ) K(i,j) K(i,j) 有效:

activated    =    ( 0 ≤ x o u t < F R A M E _ S I Z E )    ∧    ( 0 ≤ y o u t < F R A M E _ S I Z E ) \boxed{ \text{activated} \;=\; \big(0 \leq x_{out} < FRAME\SIZE\big) \;\land\; \big(0 \leq y{out} < FRAME\_SIZE\big) } activated=(0≤xout<FRAME_SIZE)∧(0≤yout<FRAME_SIZE)

直觉 :以 ( x i n , y i n ) (x_{in}, y_{in}) (xin,yin) 为中心的 C S I Z E × C S I Z E C_{SIZE} \times C_{SIZE} CSIZE×CSIZE 感受野中,恰有一个坐标满足"行模 C S I Z E C_{SIZE} CSIZE 余 i i i、列模 C S I Z E C_{SIZE} CSIZE 余 j j j"------这就是 ( x o u t , y o u t ) (x_{out}, y_{out}) (xout,yout)。→ Stage 1

公式二:起始像素判定(is_first)

输出位置 O ( x o u t , y o u t ) O(x_{out}, y_{out}) O(xout,yout) 在光栅扫描顺序下遇到的第一个依赖像素位于其感受野的左上角

first_x = max ⁡ ( 0 ,    x o u t − P ) first_y = max ⁡ ( 0 ,    y o u t − P ) is_first = ( x i n = first_x )    ∧    ( y i n = first_y ) \boxed{ \begin{aligned} \text{first\x} &= \max(0,\; x{out} - P) \\ \text{first\y} &= \max(0,\; y{out} - P) \\[4pt] \text{is\first} &= (x{in} = \text{first\x}) \;\land\; (y{in} = \text{first\_y}) \end{aligned} } first_xfirst_yis_first=max(0,xout−P)=max(0,yout−P)=(xin=first_x)∧(yin=first_y)

is_first = 1 时,该像素是此输出位置的首个贡献者 ,BRAM 中的历史值(无论来自上一帧残留还是上电随机值)应当被忽略,部分和从零开始。→ Stage 2

公式三:权重索引

感受野中 ( x i n , y i n ) (x_{in}, y_{in}) (xin,yin) 相对于 ( x o u t , y o u t ) (x_{out}, y_{out}) (xout,yout) 的偏移,直接映射为参数矩阵的行列索引:

k = x i n − x o u t + P , m = y i n − y o u t + P \boxed{ k = x_{in} - x_{out} + P,\qquad m = y_{in} - y_{out} + P } k=xin−xout+P,m=yin−yout+P

等价形式(直接由取模推导,节省减法器):

k = C S I Z E − 1 − ( ( i − x i n + P )   m o d   C S I Z E ) , m = C S I Z E − 1 − ( ( j − y i n + P )   m o d   C S I Z E ) k = C_{SIZE} - 1 - \big((i - x_{in} + P) \bmod C_{SIZE}\big),\qquad m = C_{SIZE} - 1 - \big((j - y_{in} + P) \bmod C_{SIZE}\big) k=CSIZE−1−((i−xin+P)modCSIZE),m=CSIZE−1−((j−yin+P)modCSIZE)

其中 k , m ∈ [ 0 , C S I Z E − 1 ] k, m \in [0, C_{SIZE}-1] k,m∈[0,CSIZE−1] 始终唯一合法。→ Stage 2

公式四:输出归属

( x o u t , y o u t ) (x_{out}, y_{out}) (xout,yout) 天然满足同余约束,全局有且仅有一个专属子模块:

x o u t ≡ i ( m o d C S I Z E ) , y o u t ≡ j ( m o d C S I Z E ) \boxed{ x_{out} \equiv i \pmod{C_{SIZE}},\qquad y_{out} \equiv j \pmod{C_{SIZE}} } xout≡i(modCSIZE),yout≡j(modCSIZE)

Stage 1 / Stage 5

公式五:BRAM 地址映射

子模块 K ( i , j ) K(i,j) K(i,j) 管辖的输出坐标为 { x ∣ x ≡ i ( m o d C S I Z E ) ,    x < F R A M E _ S I Z E } \{x \mid x \equiv i \pmod{C_{SIZE}},\; x < FRAME\SIZE\} {x∣x≡i(modCSIZE),x<FRAME_SIZE} 与 { y ∣ y ≡ j ( m o d C S I Z E ) ,    y < F R A M E _ S I Z E } \{y \mid y \equiv j \pmod{C{SIZE}},\; y < FRAME\_SIZE\} {y∣y≡j(modCSIZE),y<FRAME_SIZE} 的笛卡尔积,共 N x × N y N_x \times N_y Nx×Ny 个,其中:

N x = ⌈ F R A M E _ S I Z E − i C S I Z E ⌉ , N y = ⌈ F R A M E _ S I Z E − j C S I Z E ⌉ N_x = \left\lceil \frac{FRAME\SIZE - i}{C{SIZE}} \right\rceil,\qquad N_y = \left\lceil \frac{FRAME\SIZE - j}{C{SIZE}} \right\rceil Nx=⌈CSIZEFRAME_SIZE−i⌉,Ny=⌈CSIZEFRAME_SIZE−j⌉

一维 BRAM 线性地址由二维输出坐标按行优先映射:

bram_addr = x o u t − i C S I Z E × N y + y o u t − j C S I Z E \boxed{ \text{bram\addr} = \frac{x{out} - i}{C_{SIZE}} \times N_y + \frac{y_{out} - j}{C_{SIZE}} } bram_addr=CSIZExout−i×Ny+CSIZEyout−j

由公式四可证 x o u t − i x_{out} - i xout−i 和 y o u t − j y_{out} - j yout−j 均为 C S I Z E C_{SIZE} CSIZE 的整数倍,因此除法为精确整数除法,可以考虑用LUT来代替除法。→ Stage 2

公式六:末位像素判定(is_last)

x l a s t = min ⁡ ( x o u t + P ,    F R A M E _ S I Z E − 1 ) , y l a s t = min ⁡ ( y o u t + P ,    F R A M E _ S I Z E − 1 ) \boxed{ x_{last} = \min(x_{out} + P,\; FRAME\SIZE - 1),\qquad y{last} = \min(y_{out} + P,\; FRAME\_SIZE - 1) } xlast=min(xout+P,FRAME_SIZE−1),ylast=min(yout+P,FRAME_SIZE−1)

is_last    =    ( x i n = x l a s t )    ∧    ( y i n = y l a s t ) \boxed{ \text{is\last} \;=\; (x{in} = x_{last}) \;\land\; (y_{in} = y_{last}) } is_last=(xin=xlast)∧(yin=ylast)

is_last = 1 时,输出位置的全部 C S I Z E 2 C_{SIZE}^2 CSIZE2 次乘累加完成,应产出结果并清零 BRAM 对应地址。→ Stage 5

公式七:卷积乘累加

P s u m ( i , j ) [ x o u t , y o u t ]    + =    P a r a ( k , m ) ⋅ I ( x i n , y i n ) \boxed{ P_{sum}^{(i,j)}[x_{out}, y_{out}] \;\mathrel{+}=\; Para(k, m) \cdot I(x_{in}, y_{in}) } Psum(i,j)[xout,yout]+=Para(k,m)⋅I(xin,yin)

is_first = 1 时,右侧初始部分和取 0。→ Stage 4

位宽注意:Step1 的 Python 仿真使用 64 位浮点无精度问题。FPGA 定点实现中乘法会扩展位宽、累加会逐次增长,必须在设计初期精确计算------详见第 2 章的数据格式分析和第 3 章的 DSP48E2 位宽规划。


2. 模块接口与数据格式

2.1 接口分类总览

Conv_Kernel.V 的对外接口分为五大类:

类别 说明
全局信号 时钟与复位,所有时序逻辑的节拍来源
AXIS Slave 输入接口 标准 AXI4-Stream 从接口,接收像素数据、坐标与有效标志,并反压上游
AXIS Master 输出接口 标准 AXI4-Stream 主接口,发送卷积结果、输出坐标与有效标志,响应下游反压
控制与标志接口 模块使能、同步复位,FIFO 状态衍生反压
卷积参数输入 静态参数矩阵 P a r a Para Para,外部并行接入,内部按索引 MUX 选取

2.2 数据格式

2.2.1 定点化 Q 格式

Q 格式将 N N N 位有符号二进制数解释为 [ − 1 , + 1 ) [-1, +1) [−1,+1) 之间的小数------1 位符号位、 N − 1 N-1 N−1 位小数位。在硬件中它就是普通的 signed wire/reg,区别仅在于数值解释方式。

格式 总位宽 符号位 小数位 数值范围 LSB
Q8 8 1 7 [ − 1.0 ,    0.9921875 ] [-1.0,\; 0.9921875] [−1.0,0.9921875] 2 − 7 2^{-7} 2−7
Q10 10 1 9 [ − 1.0 ,    0.998046875 ] [-1.0,\; 0.998046875] [−1.0,0.998046875] 2 − 9 2^{-9} 2−9
Q12 12 1 11 [ − 1.0 ,    0.99951171875 ] [-1.0,\; 0.99951171875] [−1.0,0.99951171875] 2 − 11 2^{-11} 2−11
Q16 16 1 15 [ − 1.0 ,    0.999969482421875 ] [-1.0,\; 0.999969482421875] [−1.0,0.999969482421875] 2 − 15 2^{-15} 2−15

Q 格式是非对称的:能表示 − 1.0 -1.0 −1.0,但最大正值为 1 − 2 − ( N − 1 ) 1 - 2^{-(N-1)} 1−2−(N−1)。

2.2.2 整型格式 UINT / INT

格式 总位宽 符号 数值范围 LSB
UINT8 8 无符号 [ 0 , 255 ] [0, 255] [0,255] 1
UINT12 12 无符号 [ 0 , 4095 ] [0, 4095] [0,4095] 1
INT8 8 有符号 [ − 128 , 127 ] [-128, 127] [−128,127] 1
INT12 12 有符号 [ − 2048 , 2047 ] [-2048, 2047] [−2048,2047] 1
INT16 16 有符号 [ − 32768 , 32767 ] [-32768, 32767] [−32768,32767] 1

整型的 LSB 为 1 1 1。

2.2.3 混合运算的 LSB 传递与位宽推导

当输入格式与参数格式不同时,乘法积的 LSB 为两者 LSB 之积,位宽为两者位宽之和:

LSB product = LSB in × LSB para W product = W in + W para \boxed{\text{LSB}{\text{product}} = \text{LSB}{\text{in}} \times \text{LSB}{\text{para}}} \qquad \boxed{W{\text{product}} = W_{\text{in}} + W_{\text{para}}} LSBproduct=LSBin×LSBparaWproduct=Win+Wpara

全精度部分和经 C S I Z E 2 C_{SIZE}^2 CSIZE2 次累加后位宽再增长 ⌈ log ⁡ 2 ( C S I Z E 2 ) ⌉ \lceil \log_2(C_{SIZE}^2) \rceil ⌈log2(CSIZE2)⌉ 位:

F U L L _ W I D T H = W in + W para + ⌈ log ⁡ 2 ( C S I Z E 2 ) ⌉ \boxed{FULL\WIDTH = W{\text{in}} + W_{\text{para}} + \lceil\log_2(C_{SIZE}^2)\rceil} FULL_WIDTH=Win+Wpara+⌈log2(CSIZE2)⌉

典型组合的 LSB 传递:

输入格式 参数格式 LSB in \text{LSB}_{\text{in}} LSBin LSB para \text{LSB}_{\text{para}} LSBpara LSB product \text{LSB}_{\text{product}} LSBproduct W product W_{\text{product}} Wproduct
UINT8 Q8 1 1 1 2 − 7 2^{-7} 2−7 2 − 7 2^{-7} 2−7 16
UINT8 INT8 1 1 1 1 1 1 1 1 1 16
Q8 Q8 2 − 7 2^{-7} 2−7 2 − 7 2^{-7} 2−7 2 − 14 2^{-14} 2−14 16
UINT12 Q12 1 1 1 2 − 11 2^{-11} 2−11 2 − 11 2^{-11} 2−11 24
INT12 INT16 1 1 1 1 1 1 1 1 1 28
UINT12 Q16 1 1 1 2 − 15 2^{-15} 2−15 2 − 15 2^{-15} 2−15 28

2.2.4 溢出容限

以最坏情况 C S I Z E = 5 C_{SIZE}=5 CSIZE=5(25 次累加)、UINT12 输入(最大值 4095)、Q16 参数(绝对值最大 ~1.0)为例,全精度累加峰值约为 25 × 4095 × 32768 ≈ 2 31.6 25 \times 4095 \times 32768 \approx 2^{31.6} 25×4095×32768≈231.6。DSP48E2 累加器宽 48 位(上限 2 47 − 1 2^{47}-1 247−1),裕量超过 15 位,在 F U L L _ W I D T H ≤ 48 FULL\_WIDTH \leq 48 FULL_WIDTH≤48 的条件下无需任何中间饱和处理

2.3 接口信号总表

2.3.1 全局信号

信号名 方向 位宽 说明
clk input 1 系统时钟
rst_n input 1 异步硬复位,低有效

2.3.2 AXIS Slave 输入接口

信号名 方向 位宽 说明
s_axis_tdata input IN_DATA_WIDTH 输入像素数据
s_axis_tuser_x input ⌈ log ⁡ 2 ( F R A M E _ S I Z E ) ⌉ \lceil\log_2(FRAME\_SIZE)\rceil ⌈log2(FRAME_SIZE)⌉ 输入行坐标 x i n x_{in} xin
s_axis_tuser_y input ⌈ log ⁡ 2 ( F R A M E _ S I Z E ) ⌉ \lceil\log_2(FRAME\_SIZE)\rceil ⌈log2(FRAME_SIZE)⌉ 输入列坐标 y i n y_{in} yin
s_axis_tvalid input 1 输入有效标志
s_axis_tready output 1 模块就绪,由 !fifo_almost_full && enable 组合驱动。拉低时阻断上游新数据,零数据丢失
s_axis_tlast input 1 帧结束标志(可选)

2.3.3 AXIS Master 输出接口

信号名 方向 位宽 说明
m_axis_tdata output OUT_DATA_WIDTH 输出卷积结果
m_axis_tuser_x output ⌈ log ⁡ 2 ( F R A M E _ S I Z E ) ⌉ \lceil\log_2(FRAME\_SIZE)\rceil ⌈log2(FRAME_SIZE)⌉ 输出行坐标 x o u t x_{out} xout
m_axis_tuser_y output ⌈ log ⁡ 2 ( F R A M E _ S I Z E ) ⌉ \lceil\log_2(FRAME\_SIZE)\rceil ⌈log2(FRAME_SIZE)⌉ 输出列坐标 y o u t y_{out} yout
m_axis_tvalid output 1 输出有效标志
m_axis_tready input 1 后级就绪,直接驱动输出 FIFO 读使能
m_axis_tlast output 1 帧末标志

2.3.4 控制与标志接口

信号名 方向 位宽 说明
reset input 1 同步模块复位,高有效。清空流水线寄存器和输出 FIFO
enable input 1 模块使能,拉低时暂停流水线推进

反压设计 :模块不对外暴露粘滞错误标志。溢出保护完全由 AXI-Stream 反压协议保证------s_axis_tready 由 FIFO 剩余深度组合逻辑驱动(剩余深度 ≤ 10 时拉低),上级停止发送。五级流水线在途最多 5 个结果,10 个安全阈值是 2× 裕量,确保 FIFO 永不溢出。

2.3.5 卷积参数输入

信号名 方向 位宽 说明
para[k][m] input PARA_WIDTH 参数矩阵 P a r a [ C S I Z E ] [ C S I Z E ] Para[C_{SIZE}][C_{SIZE}] Para[CSIZE][CSIZE]。帧内稳定不变,帧间可动态切换

2.4 模块例化配置参数

参数名 范围 默认值 说明
C_SIZE 3 或 5 3 卷积核尺寸
X_INDEX_OFFSET [ 0 , C S I Z E − 1 ] [0, C_{SIZE}-1] [0,CSIZE−1] 例化决定 子模块行索引 i i i
Y_INDEX_OFFSET [ 0 , C S I Z E − 1 ] [0, C_{SIZE}-1] [0,CSIZE−1] 例化决定 子模块列索引 j j j
FRAME_SIZE 正整数 128 帧尺寸
IN_DATA_WIDTH 8/10/12 8 输入数据位宽
IN_FORMAT "Q"/"UINT"/"INT" "UINT" 输入格式
PARA_WIDTH 8/12/16 8 参数位宽
PARA_FORMAT "Q"/"INT" "INT" 参数格式
OUT_DATA_WIDTH 8/10/12 8 输出位宽
OUT_FORMAT "Q"/"UINT"/"INT" "UINT" 输出格式
FIFO_DEPTH 正整数 32 输出 FIFO 深度
P 由 C S I Z E C_{SIZE} CSIZE 推导 ( C S I Z E − 1 ) / 2 (C_{SIZE}-1)/2 (CSIZE−1)/2 Padding 半宽

这些参数共同决定流水线寄存器位宽、BRAM 地址线宽度、DSP48E2 输入映射及格式转换逻辑。


3. 五级流水线详细设计

3.1 流水线结构总览

需求仅要求"至少三级",实际设计采用五级,每级承载明确且时序可收敛的逻辑任务。流水级之间由显式寄存器隔开,级内运算为纯组合逻辑,单周期完成。

复制代码
┌──────────┐    ┌──────────┐    ┌──────────┐    ┌──────────┐    ┌──────────┐
│ Stage 1  │    │ Stage 2  │    │ Stage 3  │    │ Stage 4  │    │ Stage 5  │
│ 判定阶段  │───▶│索引生成阶段│───▶│数据获取阶段│───▶│ 乘累加阶段 │───▶│回写与输出 │
│          │    │          │    │          │    │          │    │          │
│•公式一   │    │•公式二/三 │    │•BRAM A口 │    │•公式七   │    │•公式六   │
│ x_out,   │    │ is_first │    │  组合读  │    │ DSP乘累加│    │ is_last  │
│ y_out    │    │•公式三   │    │•参数MUX  │    │•计算缓存 │    │•BRAM B口 │
│•activated│    │ k,m索引  │    │ 取Para   │    │  旁路    │    │  回写    │
│          │    │•公式五   │    │          │    │          │    │•格式转换 │
│          │    │ BRAM地址 │    │          │    │          │    │•FIFO写入 │
└──────────┘    └──────────┘    └──────────┘    └──────────┘    └──────────┘
    1 clk           1 clk           1 clk           1 clk           1 clk

BRAM 端口分配 :A 口专用于 Stage 3 组合读(DOA_REG=0,地址组合驱动,读数据同周期组合返回并打拍至 S3→S4 寄存器);B 口专用于 Stage 5 时序写(地址/数据/使能在时钟上升沿锁存并落盘)。读写在流水线上天然错开 Stage 3 与 Stage 5,消除了同周期 A/B 口地址冲突。

拆分动机:将索引生成(地址 + 参数索引 + is_first)与数据获取(BRAM 读 + MUX)分离为独立的 Stage 2 和 Stage 3,使各级时序路径更均衡。BRAM 读数据在 Stage 3 组合读出并打拍,Stage 4 仅接收干净寄存器数据,关键路径不含 BRAM 延迟。

3.2 Stage 1:判定阶段

功能描述

Stage 1 是流水线入口级,消费 AXIS Slave 总线上的像素数据,完成两项核心任务:

  1. 输出坐标计算 :按公式一,为每个输入像素 ( x i n , y i n ) (x_{in}, y_{in}) (xin,yin) 计算其在子模块 K ( i , j ) K(i,j) K(i,j) 中所贡献的输出坐标 ( x o u t , y o u t ) (x_{out}, y_{out}) (xout,yout)
  2. 激活判定 :判断 ( x o u t , y o u t ) (x_{out}, y_{out}) (xout,yout) 是否在有效图像范围内

非激活像素(如 Padding 区域产生越界坐标)在 Stage 1 即被丢弃,不消耗后续流水级资源。

公式一实现

取模辅助量(供公式三等价形式复用):

R x = ( i − x i n + P )   m o d   C S I Z E R y = ( j − y i n + P )   m o d   C S I Z E \begin{aligned} R_x &= (i - x_{in} + P) \bmod C_{SIZE} \\ R_y &= (j - y_{in} + P) \bmod C_{SIZE} \end{aligned} RxRy=(i−xin+P)modCSIZE=(j−yin+P)modCSIZE

实现过程中,取模操作可以简化为LUT, R x = L U T ( x i n ) R_x = LUT(x_{in}) Rx=LUT(xin), R y = L U T ( y i n ) R_y = LUT(y_{in}) Ry=LUT(yin)。也就是说每一个例化的卷积模块因为 i , j i,j i,j不相同所以LUT里的数据也会不相同。

输出坐标:

x o u t = x i n − P + R x y o u t = y i n − P + R y \begin{aligned} x_{out} &= x_{in} - P + R_x \\ y_{out} &= y_{in} - P + R_y \end{aligned} xoutyout=xin−P+Rx=yin−P+Ry

实现过程中,这处的加法操作没有必要用DSP,综合器会将其转化为异步逻辑。

激活判定:

a c t i v a t e d = ( 0 ≤ x o u t < F R A M E _ S I Z E )    ∧    ( 0 ≤ y o u t < F R A M E _ S I Z E ) activated = (0 \leq x_{out} < FRAME\SIZE) \;\land\; (0 \leq y{out} < FRAME\_SIZE) activated=(0≤xout<FRAME_SIZE)∧(0≤yout<FRAME_SIZE)

s_axis_tready 工作方式

复制代码
assign s_axis_tready = !fifo_almost_full && enable;

纯组合逻辑,两个拉低条件:

  • enable = 0:顶层使能关闭
  • fifo_almost_full = 1:输出 FIFO 剩余深度 ≤ 10

反压传导链为全组合逻辑(0 拍延迟),确保 FIFO 在真正溢出前上级已停止发送。

有效标志 s1_valid

s1_valid 合并四重语义------只有四者同时满足,像素才进入流水线:

复制代码
s1_valid = tvalid && tready && enable && activated

Stage 1 输出接口

输出 位宽 说明
s1_valid 1 有效标志(合并四重语义)
s1_x_out ⌈ log ⁡ 2 ( F R A M E _ S I Z E ) ⌉ \lceil\log_2(FRAME\_SIZE)\rceil ⌈log2(FRAME_SIZE)⌉ 输出行坐标
s1_y_out ⌈ log ⁡ 2 ( F R A M E _ S I Z E ) ⌉ \lceil\log_2(FRAME\_SIZE)\rceil ⌈log2(FRAME_SIZE)⌉ 输出列坐标
s1_x_in ⌈ log ⁡ 2 ( F R A M E _ S I Z E ) ⌉ \lceil\log_2(FRAME\_SIZE)\rceil ⌈log2(FRAME_SIZE)⌉ 输入行坐标(透传)
s1_y_in ⌈ log ⁡ 2 ( F R A M E _ S I Z E ) ⌉ \lceil\log_2(FRAME\_SIZE)\rceil ⌈log2(FRAME_SIZE)⌉ 输入列坐标(透传)
s1_pixel_data IN_DATA_WIDTH 输入像素值
s1_Rx ⌈ log ⁡ 2 ( C S I Z E ) ⌉ \lceil\log_2(C_{SIZE})\rceil ⌈log2(CSIZE)⌉ 取模值 R x R_x Rx(供 Stage 2 复用)
s1_Ry ⌈ log ⁡ 2 ( C S I Z E ) ⌉ \lceil\log_2(C_{SIZE})\rceil ⌈log2(CSIZE)⌉ 取模值 R y R_y Ry(供 Stage 2 复用)

R x R_x Rx 与 R y R_y Ry 在 Stage 1 计算一次,Stage 2 直接用于推导参数索引 ( k , m ) (k, m) (k,m) 的等价形式(公式三第二条),避免了重复取模运算。

处理流程(伪代码)

复制代码
// ========== Stage 1: 输出坐标 + 激活判定 ==========
Rx  = (i - x_in + P) mod C_SIZE
Ry  = (j - y_in + P) mod C_SIZE
x_out = x_in - P + Rx
y_out = y_in - P + Ry
activated = (0 <= x_out && x_out < FRAME_SIZE) &&
            (0 <= y_out && y_out < FRAME_SIZE)

s1_valid_comb = tvalid && tready && enable && activated

if (s1_valid_comb) begin
    s1_valid      <= 1
    s1_x_out      <= x_out
    s1_y_out      <= y_out
    s1_x_in       <= x_in
    s1_y_in       <= y_in
    s1_pixel_data <= pixel_data
    s1_Rx         <= Rx
    s1_Ry         <= Ry
end else begin
    s1_valid      <= 0
    // 其余寄存器全部显式初始化为 0,避免 latch
end

3.3 Stage 2:索引生成阶段

功能描述

Stage 2 是纯组合逻辑索引计算级,不访问 BRAM。它消费 Stage 1 传来的坐标和取模值,并行计算三项索引:

  1. BRAM 线性地址(公式五)
  2. 参数索引 ( k , m ) (k, m) (k,m) (公式三等价形式,复用 Stage 1 的 R x R_x Rx、 R y R_y Ry)
  3. is_first 起始标志(公式二)

公式五实现------BRAM 地址

x _ i d x = x o u t − i C S I Z E , y _ i d x = y o u t − j C S I Z E , b r a m _ a d d r = x _ i d x × N y + y _ i d x x\idx = \frac{x{out} - i}{C_{SIZE}}, \quad y\idx = \frac{y{out} - j}{C_{SIZE}}, \quad bram\_addr = x\_idx \times N_y + y\_idx x_idx=CSIZExout−i,y_idx=CSIZEyout−j,bram_addr=x_idx×Ny+y_idx

由公式四可证 x o u t − i x_{out} - i xout−i 为 C S I Z E C_{SIZE} CSIZE 的整数倍,因此这里也可以用查找表来完成,查找表的形式如下: b r a m a d d r = L U T ( x o u t , y o u t ) bram_{addr} = LUT(x_{out},y_{out}) bramaddr=LUT(xout,yout)。值得注意的是,由于每一个例化的卷积模块中 i , j i,j i,j不相同,所以LUT里的数据也会不相同;下面类似的实现方案不在赘述。

公式三实现------参数索引

复用 Stage 1 的取模结果:

k = C S I Z E − 1 − R x , m = C S I Z E − 1 − R y k = C_{SIZE} - 1 - R_x,\qquad m = C_{SIZE} - 1 - R_y k=CSIZE−1−Rx,m=CSIZE−1−Ry

公式二实现------is_first

i s _ f i r s t = ( x i n = max ⁡ ( 0 , x o u t − P ) )    ∧    ( y i n = max ⁡ ( 0 , y o u t − P ) ) is\first = (x{in} = \max(0, x_{out} - P)) \;\land\; (y_{in} = \max(0, y_{out} - P)) is_first=(xin=max(0,xout−P))∧(yin=max(0,yout−P))

Stage 2 输出接口

输出 位宽 说明
s2_valid 1 有效标志
s2_bram_addr ⌈ log ⁡ 2 ( N x × N y ) ⌉ \lceil\log_2(N_x \times N_y)\rceil ⌈log2(Nx×Ny)⌉ BRAM 线性地址
s2_para_k ⌈ log ⁡ 2 ( C S I Z E ) ⌉ \lceil\log_2(C_{SIZE})\rceil ⌈log2(CSIZE)⌉ 参数行索引 k k k
s2_para_m ⌈ log ⁡ 2 ( C S I Z E ) ⌉ \lceil\log_2(C_{SIZE})\rceil ⌈log2(CSIZE)⌉ 参数列索引 m m m
s2_is_first 1 起始像素标志
s2_x_outs2_y_out --- 输出坐标(透传)
s2_x_ins2_y_in --- 输入坐标(透传至 Stage 5)
s2_pixel_data IN_DATA_WIDTH 输入像素值(透传)

处理流程(伪代码)

复制代码
// ========== Stage 2: BRAM地址 + Para索引 + is_first ==========
if (s1_valid) begin
    // 公式五:BRAM 地址
    x_idx = (s1_x_out - i) / C_SIZE       // 整数除法
    y_idx = (s1_y_out - j) / C_SIZE
    bram_addr = x_idx * N_y + y_idx
    
    // 公式三等价形式:参数索引(复用 Stage 1 取模结果)
    k = C_SIZE - 1 - s1_Rx
    m = C_SIZE - 1 - s1_Ry
    
    // 公式二:is_first
    first_x = max(0, s1_x_out - P)
    first_y = max(0, s1_y_out - P)
    is_first = (s1_x_in == first_x) && (s1_y_in == first_y)
    
    s2_valid      <= 1
    s2_bram_addr  <= bram_addr
    s2_para_k     <= k
    s2_para_m     <= m
    s2_is_first   <= is_first
    s2_x_out      <= s1_x_out
    s2_y_out      <= s1_y_out
    s2_x_in       <= s1_x_in
    s2_y_in       <= s1_y_in
    s2_pixel_data <= s1_pixel_data
end else begin
    s2_valid <= 0
    // 其余寄存器显式初始化为 0
end

3.4 Stage 3:数据获取阶段(BRAM 读 + 参数 MUX)

功能描述

Stage 3 消费 Stage 2 传来的索引,完成两项数据获取操作:

  1. BRAM A 口组合读 :用 s2_bram_addr 组合驱动 BRAM A 地址线(DOA_REG=0),读数据在同周期组合返回并打入 S3→S4 流水寄存器
  2. 参数 MUX 选取 :用 s2_para_ks2_para_m 从 C S I Z E 2 C_{SIZE}^2 CSIZE2 个并行参数端口中通过组合 MUX 选出 P a r a ( k , m ) Para(k,m) Para(k,m),结果打入 S3→S4 寄存器

其余信号(像素数据、坐标、is_first)从 Stage 2 透传,不做处理。

BRAM A 口接口

BRAM 配置 DOA_REG=0(旁路输出寄存器),地址由 Stage 3 组合逻辑驱动,读数据同周期组合返回:

BRAM A 口信号 方向 驱动来源 说明
bram_a_addr output s2_bram_addr(组合直连) A 口读地址
bram_a_en output s2_valid(组合使能) A 口使能
bram_a_rdata input BRAM A 原始读端口 组合读数据(含 BRAM 门延迟 + 布线延迟)

架构收益bram_a_rdata 在 Stage 3 被显式寄存器 s3_bram_rdata 锁存(Tco ≈ 0.5 ns),Stage 4 关键路径不含 BRAM 延迟。

参数 MUX

C S I Z E 2 C_{SIZE}^2 CSIZE2-to-1 组合 MUX 。参数值 para_val 打入 s3_para_val 寄存器,Stage 4 由寄存器直驱 DSP A 口(零 LUT 延迟)。

Stage 3 输出接口

输出 位宽 说明
s3_valid 1 有效标志
s3_bram_rdata FULL_WIDTH BRAM 读出的历史部分和(寄存器输出,Tco ≈ 0.5 ns)
s3_para_val PARA_WIDTH 参数 MUX 输出 P a r a ( k , m ) Para(k,m) Para(k,m)(寄存器直驱 DSP A 口)
s3_bram_addr ⌈ log ⁡ 2 ( N x × N y ) ⌉ \lceil\log_2(N_x \times N_y)\rceil ⌈log2(Nx×Ny)⌉ BRAM 地址(透传,用于缓存标签)
s3_is_first 1 is_first 标志(透传至 Stage 4 门控)
s3_x_outs3_y_out --- 输出坐标(透传)
s3_x_ins3_y_in --- 输入坐标(透传至 Stage 5)
s3_pixel_data IN_DATA_WIDTH 像素值(透传至 Stage 4)

处理流程(伪代码)

复制代码
// ========== Stage 3: BRAM A口读 + 参数MUX ==========
// 组合逻辑
bram_a_addr = s2_bram_addr
bram_a_en   = s2_valid
para_val    = Para[s2_para_k][s2_para_m]

// 时序逻辑
if (s2_valid) begin
    s3_valid       <= 1
    s3_bram_rdata  <= bram_a_rdata    // BRAM 组合读数据打拍
    s3_para_val    <= para_val        // 参数值寄存器输出
    s3_bram_addr   <= s2_bram_addr
    s3_is_first    <= s2_is_first
    s3_x_out       <= s2_x_out
    s3_y_out       <= s2_y_out
    s3_x_in        <= s2_x_in
    s3_y_in        <= s2_y_in
    s3_pixel_data  <= s2_pixel_data
end else begin
    s3_valid <= 0
    // 其余寄存器显式初始化为 0
end

3.5 Stage 4:乘累加阶段(计算缓存核心)

功能描述

Stage 4 是算术核心,消费 Stage 3 传来的全部数据,单周期完成:

  1. 历史数据三路选择 (按优先级):
    • is_first = 1 → 历史数据 = 0(无条件门控)
    • 缓存命中 → 历史数据 = 上一拍新部分和(旁路 BRAM 过时数据)
    • 否则 → 历史数据 = s3_bram_rdata(BRAM 读出的值)
  2. DSP48E2 乘累加s3_para_val × s3_pixel_data + historical_data
  3. 更新计算缓存 :新部分和打入 s4_partial_sum,下一拍自动成为缓存命中数据源

计算缓存旁路机制

这是流水线设计中最关键的微架构决策,源于 BRAM 真双口的 RAW(Read-After-Write)数据冒险。

RAW 冒险 :Stage 3 的 BRAM A 口组合读与 Stage 5 的 BRAM B 口时序写之间仅隔 1 个流水级。同一输出位置连续两次访问时,后一次读发生在前一次写落盘之前,BRAM A 口必然返回旧值。

缓存旁路方案 :直接复用 Stage 4 流水寄存器中上一拍的 s4_partial_sums4_bram_addr 作为"计算缓存"。当下一次 Stage 4 需要历史数据时,先比对该地址是否命中:

  • 命中 :直接用 s4_partial_sum(上一拍的新部分和),无视 BRAM 旧值
  • 未命中 :用 s3_bram_rdata

效果等同于 CPU 的 Store-to-Load Forwarding------尚未落盘的数据从流水寄存器直接旁路给下一次运算。

不做旁路的后果 : C S I Z E = 3 C_{SIZE}=3 CSIZE=3 时,同一输出位置连续被访问 9 次。除第一次外,第 2~9 次全部使用 BRAM 过时旧值,最终结果仅剩最后一次乘累加的贡献------在任何场景下均不可接受。

is_first 门控

is_first 以最高优先级生效:输出位置首次被访问时,无论 BRAM 中残留什么值(上电随机值或上一帧数据),历史值强制为 0。这带来了三项关键硬件收益:

  • 上电后无需等待 BRAM 初始化
  • 帧间无需 BRAM 清零操作
  • 支持背靠背连续帧处理,零帧间等待

历史数据三路选择的完整优先级:

复制代码
if (is_first)       → historical_data = 0
else if (cache_hit) → historical_data = s4_partial_sum
else                → historical_data = s3_bram_rdata

Stage 4 输出接口

输出 位宽 说明
s4_valid 1 有效标志
s4_partial_sum FULL_WIDTH 更新后的全精度部分和(同时作为下一拍缓存数据源)
s4_bram_addr ⌈ log ⁡ 2 ( N x × N y ) ⌉ \lceil\log_2(N_x \times N_y)\rceil ⌈log2(Nx×Ny)⌉ BRAM 地址(同时作为下一拍缓存标签和 Stage 5 回写地址)
s4_x_outs4_y_out --- 输出坐标(透传)
s4_x_ins4_y_in --- 输入坐标(透传至 Stage 5)

处理流程(伪代码)

复制代码
// ========== Stage 4: 三路选择 + 乘累加 + 缓存更新 ==========
// 历史数据三路选择
if (s3_is_first) begin
    historical_data = 0
end else if (s4_valid && (s4_bram_addr == s3_bram_addr)) begin
    historical_data = s4_partial_sum      // 缓存命中------旁路
end else begin
    historical_data = s3_bram_rdata       // BRAM 读取
end

// DSP48E2 乘累加
partial_sum = s3_para_val * s3_pixel_data + historical_data

// 时序逻辑
if (s3_valid) begin
    s4_valid       <= 1
    s4_partial_sum <= partial_sum         // 输出 + 缓存数据
    s4_bram_addr   <= s3_bram_addr        // 输出 + 缓存标签
    s4_x_out       <= s3_x_out
    s4_y_out       <= s3_y_out
    s4_x_in        <= s3_x_in
    s4_y_in        <= s3_y_in
end else begin
    s4_valid <= 0
    // 其余寄存器显式初始化为 0
end

DSP48E2 端口映射与位宽规划

复制代码
   ┌──────────────────────────────────────┐
   │              DSP48E2                  │
   │  A (30-bit) ← s3_para_val(寄存器直驱) │
   │  B (18-bit) ← s3_pixel_data           │
   │  C (48-bit) ← historical_data         │
   │  OPMODE     ← A×B + C                │
   │  P (48-bit) → partial_sum             │
   └──────────────────────────────────────┘

DSP 配置为组合乘累加模式。参数值由 s3_para_val 寄存器直驱 A 口,参数 MUX 的 LUT 延迟已在 Stage 3 消化。

全精度位宽(最坏情况):

C S I Z E C_{SIZE} CSIZE I N _ W IN\_W IN_W (max) P A R A _ W PARA\_W PARA_W (max) 累加扩展 F U L L _ W I D T H FULL\_WIDTH FULL_WIDTH 累加器宽度 裕量
3 12 16 4 位 32 48 16 位
5 12 16 5 位 33 48 15 位

时序估算(7 系列 FPGA,speed grade -1):

  • S3→S4 寄存器 Tco:~0.5 ns
  • 历史数据 MUX(3 选 1):~0.5 ns
  • DSP48E2 组合乘加:~3.5 ns
  • 建立时间:~0.5 ns
  • 总路径 :~5.0 ns → f m a x ≈ 200 f_{max} \approx 200 fmax≈200 MHz

3.6 Stage 5:回写与输出阶段

功能描述

Stage 5 是流水线收尾级,消费 Stage 4 的全精度部分和,完成最终判定与分发:

  1. is_last 判定(公式六):判断当前像素是否为输出位置的最后一个依赖像素
  2. BRAM B 口回写
    • is_last=1:写入 0(清零),将最终结果推入 FIFO
    • is_last=0:写入更新后的全精度部分和,继续等待后续像素
  3. 格式转换 (仅 is_last=1):全精度部分和缩放/钳位至输出格式
  4. 输出 FIFO 写入:格式转换后的结果连同输出坐标写入 FIFO

BRAM B 口接口

BRAM B 口信号 方向 驱动来源 说明
s5_bram_b_wr_en output Stage 5 组合逻辑 每个有效拍均拉高
s5_bram_b_addr output s4_bram_addr B 口写地址
s5_bram_b_wr_data output s4_partial_sum 或 0 B 口写数据

处理流程(伪代码)

复制代码
// ========== Stage 5: is_last + BRAM回写 + 格式转换 + FIFO写入 ==========
x_last = min(s4_x_out + P, FRAME_SIZE - 1)
y_last = min(s4_y_out + P, FRAME_SIZE - 1)
is_last = (s4_x_in == x_last) && (s4_y_in == y_last)

s5_bram_b_addr  = s4_bram_addr
s5_bram_b_wr_en = s4_valid

if (is_last) begin
    s5_bram_b_wr_data = 0                          // 清零 BRAM
    out_data = format_convert(s4_partial_sum, ...)  // 格式转换
    s5_fifo_wr_en   = 1
    s5_fifo_wr_data = {out_data, s4_x_out, s4_y_out}
end else begin
    s5_bram_b_wr_data = s4_partial_sum              // 写回部分和
    s5_fifo_wr_en     = 0
end

格式转换

全精度部分和 P f u l l P_{full} Pfull 的隐含 LSB 为 LSB product = LSB in × LSB para \text{LSB}{\text{product}} = \text{LSB}{\text{in}} \times \text{LSB}_{\text{para}} LSBproduct=LSBin×LSBpara。转换为输出格式分两步:

  1. 缩放 :乘以 LSB product / LSB out \text{LSB}{\text{product}} / \text{LSB}{\text{out}} LSBproduct/LSBout(退化为算术移位)
  2. 钳位 :钳位到 [ O U T _ M I N , O U T _ M A X ] [OUT\_MIN, OUT\_MAX] [OUT_MIN,OUT_MAX]

示例 :UINT8 输入(LSB=1)、Q8 参数(LSB= 2 − 7 2^{-7} 2−7)、UINT8 输出(LSB=1)→ 右移 7 位,钳位 [ 0 , 255 ] [0, 255] [0,255]。

FIFO 写入接口

Stage 5 消费流水线最终结果,通过专用写入端口推入输出缓冲 FIFO。写入端口信号定义如下:

信号名 方向 位宽 说明
s5_fifo_wr_en → FIFO 1 FIFO 写使能。仅当 s4_valid && is_last 时为高,将格式转换后的结果 + 坐标压入 FIFO
s5_fifo_wr_data → FIFO OUT_PACK_WIDTH FIFO 写数据。拼接格式:{out_data, s4_x_out, s4_y_out},其中 out_data 为格式转换后的输出像素值

写入时机s5_fifo_wr_en 仅在 is_last=1 时拉高------即输出位置的最后一个依赖像素到达、部分和已完整累计、格式转换已完成的同一周期。一个输出位置在其全生命周期中恰好写入 FIFO 一次。

fifo_almost_full 信号定义

fifo_almost_full 是输出缓冲 FIFO 内部衍生的组合信号,用于驱动 AXIS Slave 反压链:

信号名 方向 宽度 定义
fifo_almost_full FIFO → 顶层 1 (fifo_depth - fifo_data_count) ≤ 10 时拉高
  • 阈值选取 ( C S I Z E = 3 C_{SIZE}=3 CSIZE=3,FIFO 深 32):剩余 ≤ 10 个空位。五级流水线在途最多 5 个待写结果,10 是 2× 裕量,确保组合逻辑反压有足够响应时间。
  • 传导路径fifo_almost_full 0 拍组合逻辑 → 与 enable 相与 → 驱动 s_axis_tready → 上游立即停止发送新像素。
  • 效果:全程零溢出、零数据丢失,无需粘滞错误标志。

FIFO 读出侧:AXIS Master 接口映射

输出 FIFO 同时是 Stage 5 处理结果与模块顶层 AXIS Master 之间的隔离缓冲层。FIFO 读出侧直接映射为 AXIS Master 的 TData / TUser / TValid / TReady:

FIFO 内部读出信号 方向 AXIS Master 端口 说明
fifo_rdata.out_data m_axis_tdata 输出像素数据
fifo_rdata.x_out m_axis_tuser_x 输出行坐标
fifo_rdata.y_out m_axis_tuser_y 输出列坐标
!fifo_empty m_axis_tvalid 非空即有效
m_axis_tready fifo_rd_en 后级就绪直接驱动 FIFO 读使能
复制代码
// FIFO 读出侧 → AXIS Master 组合逻辑直连
assign m_axis_tvalid  = !fifo_empty;
assign fifo_rd_en     = m_axis_tready && m_axis_tvalid;
assign m_axis_tdata   = fifo_rdata.out_data;
assign m_axis_tuser_x = fifo_rdata.x_out;
assign m_axis_tuser_y = fifo_rdata.y_out;

读写隔离 :FIFO 写入侧由 Stage 5 is_last 门控触发,读出侧由下游 AXIS Master tready 节拍驱动,两端完全解耦。FIFO 吸收流水线产出速率与下游消费速率之间的瞬时差异。


4. BRAM 与 FIFO 资源计算

4.1 BRAM 深度与宽度

4.1.1 存储需求

每个子模块 K ( i , j ) K(i,j) K(i,j) 独立维护其辖内全部输出位置的全精度部分和。子模块管辖的输出位置总数为 N x × N y N_x \times N_y Nx×Ny(见公式五)。BRAM 深度由所有子模块中 N x × N y N_x \times N_y Nx×Ny 的最大值向上取整到 2 的整数次幂,统一所有模块深度以简化时序约束。

depth = 2 ⌈ log ⁡ 2 ( max ⁡ i , j N x × N y ) ⌉ \boxed{\text{depth} = 2^{\lceil\log_2(\max_{i,j} N_x \times N_y)\rceil}} depth=2⌈log2(maxi,jNx×Ny)⌉

4.1.2 C S I Z E = 3 C_{SIZE}=3 CSIZE=3, F R A M E _ S I Z E = 128 FRAME\_SIZE=128 FRAME_SIZE=128

子模块 ( i , j ) (i,j) (i,j) N x N_x Nx N y N_y Ny N x × N y N_x \times N_y Nx×Ny
( 0 , 0 ) (0,0) (0,0) ⌈ 128 / 3 ⌉ = 43 \lceil 128/3\rceil = 43 ⌈128/3⌉=43 43 1849
( 0 , 1 ) (0,1) (0,1) 43 ⌈ 127 / 3 ⌉ = 43 \lceil 127/3\rceil = 43 ⌈127/3⌉=43 1849
( 0 , 2 ) (0,2) (0,2) 43 ⌈ 126 / 3 ⌉ = 42 \lceil 126/3\rceil = 42 ⌈126/3⌉=42 1806
( 1 , 0 ) (1,0) (1,0) ⌈ 127 / 3 ⌉ = 43 \lceil 127/3\rceil = 43 ⌈127/3⌉=43 43 1849
( 1 , 1 ) (1,1) (1,1) 43 43 1849
( 1 , 2 ) (1,2) (1,2) 43 42 1806
( 2 , 0 ) (2,0) (2,0) ⌈ 126 / 3 ⌉ = 42 \lceil 126/3\rceil = 42 ⌈126/3⌉=42 43 1806
( 2 , 1 ) (2,1) (2,1) 42 43 1806
( 2 , 2 ) (2,2) (2,2) 42 42 1764

max ⁡ ( N x × N y ) = 1849 , depth = 2 11 = 2048 \max(N_x \times N_y) = 1849, \quad \text{depth} = 2^{11} = \boxed{2048} max(Nx×Ny)=1849,depth=211=2048

4.1.3 C S I Z E = 5 C_{SIZE}=5 CSIZE=5, F R A M E _ S I Z E = 128 FRAME\_SIZE=128 FRAME_SIZE=128

子模块 ( i , j ) (i,j) (i,j) N x N_x Nx N y N_y Ny N x × N y N_x \times N_y Nx×Ny
( 0 , 0 ) (0,0) (0,0) ⌈ 128 / 5 ⌉ = 26 \lceil 128/5\rceil = 26 ⌈128/5⌉=26 26 676
( 0 , 1 ) ∼ ( 2 , 2 ) (0,1) \sim (2,2) (0,1)∼(2,2) 26 26 676
边界子模块 ( i ≥ 3 (i\geq 3 (i≥3 或 j ≥ 3 ) j\geq 3) j≥3) 26 25 650

max ⁡ ( N x × N y ) = 676 , depth = 2 10 = 1024 \max(N_x \times N_y) = 676, \quad \text{depth} = 2^{10} = \boxed{1024} max(Nx×Ny)=676,depth=210=1024

4.1.4 位宽与 BRAM 原语折算

C S I Z E C_{SIZE} CSIZE 全精度位宽 BRAM 位宽(取整) 深度
3 32 位 36 位 2048
5 33 位 36 位 1024

Xilinx 7 系列 BRAM36 原生配置表:

配置 深度 宽度 总量
BRAM36 TDP 1024 36 36 Kb
BRAM36 TDP 2048 18 36 Kb

C S I Z E = 3 C_{SIZE}=3 CSIZE=3(9 模块,深 2048,宽 36) :BRAM36 在 2048 深度下原生仅 18 位宽,需 2 个 BRAM36 拼接为 2048 × 36 2048 \times 36 2048×36 → 每模块 2 BRAM36,9 模块共 18 BRAM36

C S I Z E = 5 C_{SIZE}=5 CSIZE=5(25 模块,深 1024,宽 36) :BRAM36 在 1024 深度下原生 36 位宽,全精度 33 位恰好装入 → 每模块 1 BRAM36,25 模块共 25 BRAM36

4.2 FIFO 资源

4.2.1 输出缓冲 FIFO 规格

输出 FIFO 在 is_last=1 时写入一次,数据包位宽为:

OUT_PACK_WIDTH = OUT_DATA_WIDTH + 2 × ⌈ log ⁡ 2 ( F R A M E _ S I Z E ) ⌉ \text{OUT\_PACK\_WIDTH} = \text{OUT\_DATA\_WIDTH} + 2 \times \lceil\log_2(FRAME\_SIZE)\rceil OUT_PACK_WIDTH=OUT_DATA_WIDTH+2×⌈log2(FRAME_SIZE)⌉

以 F R A M E _ S I Z E = 128 FRAME\_SIZE=128 FRAME_SIZE=128、OUT_DATA_WIDTH=8 为例: 8 + 2 × 7 = 22 8 + 2\times7 = 22 8+2×7=22 位。

C S I Z E C_{SIZE} CSIZE 推荐深度 依据
3(9 模块) 32 5 级流水在途 + 9 项同时完成 + 反压裕量
5(25 模块) 64 5 级流水在途 + 25 项可同时完成 + 反压裕量

4.2.2 FIFO 实现方式

方式 资源 适用深度 说明
LUT-RAM ~60 LUT ≤ 32 面积效率高,时序好
BRAM18 FIFO 1 BRAM18 ≥ 64 控制逻辑约 50 LUT

相关推荐
资源分享助手1 小时前
超级改图P图改字无限制版教程(安卓)AI改图软件、图片改字软件、安卓修图APP、智能消除工具、图片拼接APP、超级改图下载
android·人工智能
二哈赛车手1 小时前
新人笔记---简易版AI实现以图搜图功能
java·人工智能·笔记·spring·ai
sno_guo1 小时前
直播抠图技术100谈之25---调色中曲线是最优解
人工智能·算法·机器学习·直播·内容运营·obs抠图·直播技术
zhangxingchao1 小时前
AI应用开发二:Embedding与向量数据库
前端·人工智能·后端
日取其半万世不竭1 小时前
Ollama + Open WebUI 部署教程:本地运行大语言模型,自建私有 AI 助手
人工智能·语言模型·自然语言处理
weixin_446260851 小时前
本地部署与实践指南:构建免费的AI开发助手系统(Claude Code + Ollama)
人工智能
南宫萧幕1 小时前
Simulink 从零搭建 HEV ECMS 环境:模块解析、排坑指南与智能算法接口预留
人工智能·算法·matlab·汽车·控制
YuanDaima20481 小时前
Docker 工程化安装与核心命令实战
运维·人工智能·docker·微服务·容器·bash
杰之行1 小时前
Fast-DDS 接收数据完整时序分析
c++·人工智能