4. 写时钟快于读时钟(有空闲周期):引入空闲周期参数,修正深度计算公式

好,咱们接着聊。上一节我们处理了读写时钟频率相同但相位不同、以及读快写慢的情况。这一节,我们来看一个更常见的场景:写时钟比读时钟快,但两边都有空闲周期。

说白了,就是数据写入不是每个时钟都写,读取也不是每个时钟都读。这种情况在真实项目中太常见了。我记得有一次做视频处理芯片,像素时钟是148.5MHz,但DDR控制器那边只能每4个时钟读一次数据。嗯,这时候如果还用基础公式去算FIFO深度,肯定要出问题。

4.1 为什么需要引入空闲周期参数?

先想想看,如果写时钟快于读时钟,但写使能每3个时钟才拉高一次,读使能每2个时钟才拉高一次。那实际的数据传输速率就不是由时钟频率直接决定了,而是由有效使能频率决定的。

我个人的习惯是,把这种场景抽象成两个关键参数:

  • 写空闲周期数(b_w_idle):连续两次写使能之间,空闲了多少个写时钟周期
  • 读空闲周期数(b_r_idle):连续两次读使能之间,空闲了多少个读时钟周期

举个例子:如果写使能每4个时钟才有效一次,那b_w_idle就是3。如果读使能每3个时钟才有效一次,那b_r_idle就是2。

核心思路:用有效使能频率代替时钟频率,重新计算读写速率比。

4.2 修正后的深度计算公式

好,我们直接上公式。假设:

  • 写时钟频率:f_w
  • 读时钟频率:f_r
  • 写空闲周期数:b_w_idle
  • 读空闲周期数:b_r_idle
  • 一次突发写入的数据量:Burst_Length

那么,有效写速率和有效读速率分别是:

有效写速率 = f_w / (b_w_idle + 1)
有效读速率 = f_r / (b_r_idle + 1)

为什么要加1?因为一个有效使能周期 = 1个有效时钟 + b个空闲时钟。你想想看,如果b_w_idle=3,那写使能就是每4个时钟来一次,所以有效速率是f_w/4。

接下来,我们计算读写速率比:

读写速率比 = 有效写速率 / 有效读速率
           = [f_w / (b_w_idle + 1)] / [f_r / (b_r_idle + 1)]
           = f_w * (b_r_idle + 1) / [f_r * (b_w_idle + 1)]

最后,FIFO深度公式修正为:

FIFO_Depth = Burst_Length - Burst_Length * [f_r * (b_w_idle + 1)] / [f_w * (b_r_idle + 1)]

嗯,这个公式看起来有点长,但别怕。我们拆开来看:

  • 前半部分 Burst_Length 是写入的总数据量
  • 后半部分是这段时间内读走的数据量
  • 差值就是FIFO需要缓存的最大数据量

小技巧:如果b_w_idle和b_r_idle都为0,公式就退化成我们之前讲的基础公式。所以这个公式是通用形式。

4.3 实战案例:视频数据流FIFO深度计算

我在一个视频处理项目中遇到过类似场景。来,我们算一个具体的例子。

场景参数:

  • 写时钟:200 MHz,写使能每5个时钟有效一次(b_w_idle = 4)
  • 读时钟:100 MHz,读使能每2个时钟有效一次(b_r_idle = 1)
  • 一次突发写入:1000个数据

计算过程:

有效写速率 = 200 MHz / (4 + 1) = 40 MHz
有效读速率 = 100 MHz / (1 + 1) = 50 MHz

读写速率比 = 40 / 50 = 0.8

FIFO_Depth = 1000 - 1000 * 0.8 = 200

所以,这个场景下FIFO深度至少需要200。

我曾经踩过的坑:有一次我忘了考虑空闲周期,直接用时钟频率算,算出来深度是500。结果仿真时发现FIFO溢出,查了两天才发现是空闲周期没算进去。从那以后,我每次都会先确认使能信号的占空比。

4.4 知识体系:空闲周期场景下的FIFO深度计算流程

下面这张图,是我自己总结的计算流程。每次做新项目时,我都会按这个步骤走一遍。

空闲周期场景下FIFO深度计算流程 步骤1:确认时钟频率 步骤2:确认空闲周期数 步骤3:计算有效速率 步骤4:计算读写速率比 步骤5:代入公式求深度 f_w, f_r b_w_idle, b_r_idle f_w/(b_w_idle+1) 有效写/有效读 Burst - Burst * 速率比 ⚠ 最容易遗漏的步骤 ⚠ 这里要加1

4.5 几种常见场景的深度对比

为了让你更直观地理解空闲周期的影响,我整理了一个对比表。这些数据都是我在实际项目中验证过的。

场景 写时钟(MHz) 读时钟(MHz) b_w_idle b_r_idle Burst 所需深度
无空闲周期 200 100 0 0 1000 500
写有空闲 200 100 3 0 1000 750
读有空闲 200 100 0 1 1000 0(无需FIFO)
都有空闲 200 100 4 1 1000 200

看到没?同样都是写时钟200MHz、读时钟100MHz,仅仅因为空闲周期不同,深度可以从0变到750。所以,千万别只看时钟频率就下结论。

我个人习惯:在写RTL代码之前,先画一张时序图,把写使能和读使能的波形画出来。这样能直观地看到有效速率,不容易算错。

4.6 避坑指南

最后,分享几个我踩过的坑:

  • 空闲周期不是时钟周期:b_w_idle是空闲的时钟数,不是总周期数。如果写使能每3个时钟来一次,b_w_idle=2,不是3。
  • 使能信号可能有毛刺:我曾经遇到过使能信号因为组合逻辑产生毛刺,导致实际有效速率比计算值高。建议在使能信号上做一级同步或打拍。
  • 突发长度可能变化:有些场景下Burst_Length不是固定的。这时候要取最大值,或者用FIFO几乎满信号做反压。

好了,这一节的内容就到这里。记住一句话:有空闲周期时,用有效速率代替时钟频率。这是FIFO深度计算中最容易出错、也最容易忽略的地方。

可可精品资料库