【芯片前端】“异步FIFO全解析”的BUG——格雷码连续性

本文涉及的产品
公共DNS(含HTTPDNS解析),每月1000万次HTTP解析
云解析 DNS,旗舰版 1个月
全局流量管理 GTM,标准版 1个月
简介: 【芯片前端】“异步FIFO全解析”的BUG——格雷码连续性

前言

在前几天写完【芯片前端】保持代码手感——异步FIFO全解析之后自我感觉非常良好,觉得异步fifo的问题我已经全部拿捏了,没想到今天突然想到一个我自己代码里的bug。


代码中的BUG

事情的源头在同步fifo里,深度任意可配的同步fifo里使用了两个非饱和的cnt计数器记录读写地址指针,waddr和raddr均比实际地址多一位,最高位用来指示套圈情况。当waddr和raddr的最高位相同时,fifo_cnt = waddr-raddr;当waddr和raddr的最高位相反时,fifo_cnt = DEPTH + waddr[ADDR_WIDTH-1:0]   - raddr[ADDR_WIDTH-1:0]。最高位作为标志位,当低位计数到DEPTH-1时,高位翻转,代码大意如下:

assign waddr_d_h = (waddr[DP_WD-1:0] == DEPTH-1) ? ~waddr[DP_WD] : waddr[DP_WD];
assign waddr_d_l = (waddr[DP_WD-1:0] == DEPTH-1) ? 0 : waddr[DP_WD-1:0] + 1;
always @(posedge clk or negedge rst_n)begin
  if(~rst_n)    waddr <= 0;
  else if(wenc) waddr <= {waddr_d_h, waddr_d_l};
end


假设fifo深度设为10,那么waddr的跳转为:

高比特

低比特

指针数值

0

0000

0

0

0001

1

...

...

...

0

1001

9

1

0000

(套圈)0

1

0001

(套圈)1

...

...


1

1001

(套圈)9

0

0000

0


在同步fifo里这样做是没有问题的,但是问题出现在,把这个代码代入到异步fifo中的时候。



异步fifo中使用格雷码对addr进行跨异步,关键处理是二进制 - 格雷码 - 跨异步 - 二进制处理路径 。而之所以能够使用格雷码跨异步是因为格雷码相邻的两个数只相差1bit,而深度为10的异步fifo,存在'b01001('d9) -> 'b10000('d16)的跳转,这个就不是相邻跳转了,相应的格雷码变化也不是单比特的跳转:01101 -> 11000,显然的这会导致空满判断出现逻辑错误。

BUG修复

这个问题的关键就在于不饱和计数在边界的跳变导致的格雷码不连续,所以先观察格雷码。十进制0~15对应的二进制和格雷码如下表:

十进制

二进制

格雷码

0

0000

0000

1

0001

0001

2

0010

0011

3

0011

0010

4

0100

0110

5

0101

0111

6

0110

0101

7

0111

0100

8

1000

1100

9

1001

1101

10

1010

1111

11

1011

1110

12

1100

1010

13

1101

1011

14

1110

1001

15

1111

1000


显而易见的一条规律是,相邻两个数只有1bit不一样。进一步可以发现,3->0,7->0,15->0的编码也是“连续的”,即只有1bit不同。为了更好地观察规律,我们做出格雷码的码盘来观察,码盘如下图,红色为1白色为0,同心圆内为高比特,外部为低比特,如十进制2的格雷码为0011,对应的图就是“白白红红”。



盯一会码盘就会发现码盘的“对称性”和“连续性”,比如说1和14、2和13、6和9、7和8在码盘上处于轴对称的位置,而格雷码编码值恰好相差1bit。


那么也就是说,如果当前的值是5,那么下一个数想要保持格雷码连续性,就只能跳4、6或者10:

十进制5=格雷码:0111

十进制4=格雷码:0110


十进制6=格雷码:0101


十进制10=格雷码;1111


显然,此时只能跳10才能满足最高位作为标志位,当低位计数到DEPTH-1时,高位翻转的条件,也就是说我们实际要由5('b0101) -> 8('b1000)变成了由5('b0101) -> 10('b1010),所以说实际多条了两个数,因此实际cnt的值是10 - 偏移量,此时的偏移量是2,fifo的深度为6(所以低位计数计到5)。


那么继续推导,当深度配置为5,那么低位满4(格雷码:0110)跳转为11(格雷码:1110),实际的cnt值是11 - 3 = 8('d1000),偏移量为3。进一步的我就不推了,根据码盘也可以发现,偏移量 = 2^N - 配置深度,低位计满跳转值 = 2^N + 偏移量。用代码表示这几个参数:

parameter DEPTH = 11;
parameter WIDTH = $clog2(DEPTH);//4
parameter DEPTH_TO2 = 2 ^ WIDTH;//16
parameter SHIFT = DEPTH_TO2 - DEPTH;//16-11=5


还是以深度11为例,看一下这种策略下的指针跳转:

高比特

低比特

数值(二进制)

数值(格雷码)

实际指针数值

0

0000

0

0_0000

0

0

0001

1

0_0001

1

...

...

...

...

...

0

1010

10

0_1111

10

1

0101

21

1_1111

1_0101-101('d5)=1_0000,0

1

0110

22

1_1101

1_0110-101=1_0001,1

...

...

...

...

...

1

1111

31

1_0000

1_1111-101=1_1010,10

0

0000

0

0_0000

0


OK,策略上没有问题,进一步的异步FIFO代码组织放到下次,今天太晚了。  


相关文章
|
25天前
|
前端开发 JavaScript API
前端:事件循环/异步
前端开发中的事件循环和异步处理是核心机制,用于管理任务执行、性能优化及响应用户操作,确保网页流畅运行。事件循环负责调度任务,而异步则通过回调、Promise等实现非阻塞操作。
|
1月前
|
机器学习/深度学习 编解码 前端开发
探索无界:前端开发中的响应式设计深度解析####
【10月更文挑战第29天】 在当今数字化时代,用户体验的优化已成为网站与应用成功的关键。本文旨在深入探讨响应式设计的核心理念、技术实现及最佳实践,揭示其如何颠覆传统布局限制,实现跨设备无缝对接,从而提升用户满意度和访问量。通过剖析响应式设计的精髓,我们将一同见证其在现代Web开发中的重要地位与未来趋势。 ####
46 7
|
1月前
|
编解码 前端开发 UED
探索无界:前端开发中的响应式设计深度解析与实践####
【10月更文挑战第29天】 本文深入探讨了响应式设计的核心理念,即通过灵活的布局、媒体查询及弹性图片等技术手段,使网站能够在不同设备上提供一致且优质的用户体验。不同于传统摘要概述,本文将以一次具体项目实践为引,逐步剖析响应式设计的关键技术点,分享实战经验与避坑指南,旨在为前端开发者提供一套实用的响应式设计方法论。 ####
62 4
|
1月前
|
前端开发 JavaScript 开发者
前端开发的终极技巧:如何让你的代码既简洁又高效,还能减少bug?
【10月更文挑战第30天】前端开发充满挑战与创新,如何编写简洁高效且少bug的代码是开发者关注的重点。本文介绍五大技巧:1. 模块化,提高代码复用性;2. 组件化,降低代码耦合度;3. 使用现代框架,提高开发效率;4. 统一代码规范,降低沟通成本;5. 利用工具,优化代码质量。掌握这些技巧,让前端开发更高效。
80 1
|
1月前
|
缓存 前端开发 JavaScript
"面试通关秘籍:深度解析浏览器面试必考问题,从重绘回流到事件委托,让你一举拿下前端 Offer!"
【10月更文挑战第23天】在前端开发面试中,浏览器相关知识是必考内容。本文总结了四个常见问题:浏览器渲染机制、重绘与回流、性能优化及事件委托。通过具体示例和对比分析,帮助求职者更好地理解和准备面试。掌握这些知识点,有助于提升面试表现和实际工作能力。
66 1
|
1月前
|
前端开发 JavaScript 开发者
揭秘前端高手的秘密武器:深度解析递归组件与动态组件的奥妙,让你代码效率翻倍!
【10月更文挑战第23天】在Web开发中,组件化已成为主流。本文深入探讨了递归组件与动态组件的概念、应用及实现方式。递归组件通过在组件内部调用自身,适用于处理层级结构数据,如菜单和树形控件。动态组件则根据数据变化动态切换组件显示,适用于不同业务逻辑下的组件展示。通过示例,展示了这两种组件的实现方法及其在实际开发中的应用价值。
37 1
|
2月前
|
人工智能 资源调度 数据可视化
【AI应用落地实战】智能文档处理本地部署——可视化文档解析前端TextIn ParseX实践
2024长沙·中国1024程序员节以“智能应用新生态”为主题,吸引了众多技术大咖。合合信息展示了“智能文档处理百宝箱”的三大工具:可视化文档解析前端TextIn ParseX、向量化acge-embedding模型和文档解析测评工具markdown_tester,助力智能文档处理与知识管理。
|
2月前
|
缓存 前端开发 JavaScript
前端的全栈之路Meteor篇(二):容器化开发环境下的meteor工程架构解析
本文详细介绍了使用Docker创建Meteor项目的准备工作与步骤,解析了容器化Meteor项目的目录结构,包括工程准备、环境配置、容器启动及项目架构分析。提供了最佳实践建议,适合初学者参考学习。项目代码已托管至GitCode,方便读者实践与交流。
|
2月前
|
人工智能 前端开发 JavaScript
拿下奇怪的前端报错(一):报错信息是一个看不懂的数字数组Buffer(475) [Uint8Array],让AI大模型帮忙解析
本文介绍了前端开发中遇到的奇怪报错问题,特别是当错误信息不明确时的处理方法。作者分享了自己通过还原代码、试错等方式解决问题的经验,并以一个Vue3+TypeScript项目的构建失败为例,详细解析了如何从错误信息中定位问题,最终通过解读错误信息中的ASCII码找到了具体的错误文件。文章强调了基础知识的重要性,并鼓励读者遇到类似问题时不要慌张,耐心分析。
|
2月前
|
JSON 前端开发 JavaScript
前端模块打包器的深度解析
【10月更文挑战第13天】前端模块打包器的深度解析

推荐镜像

更多