马克思教我们优化时序之补全if else

2023-11-22 00:40

本文主要是介绍马克思教我们优化时序之补全if else,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

刚入驻博客园,先搬几篇近期原创的文章。

时序优化中重要的一项就是提高模块的最高工作频率,工作频率由关键路径决定,通常的提高工作频率的步骤是:利用时序分析工具找到关键路径,分析关键路径主要延迟是布线延迟还是逻辑延迟,然后轮番十八般武器,如果是逻辑延迟过大就用逻辑切割,插入D触发器,如果布线延迟太长,则复制触发器,减小负载等等,按部就班后,有时可以明显改善,但很多时候由于设计需求所限不能插入触发器,或是面积受限无法复制触发器,这些程式化的优化方法收效就甚微了,此时,该怎么办呢? 马克思爷爷曾经说过:“世上任何事物都不是孤立的,而是相互联系的,相互制约,相互作用”。受此启发,我们所看到的关键路径,并不是单单由关键路径上的逻辑决定的,而是由工程里所有的逻辑决定的,其中也包括很多和关键路径无关的逻辑。一块FPGA的资源是固定的,如果工程里的一些模块优先占用了风水宝地,剩下的模块只能将就着使用其次的资源,最终很委屈的成为了关键路径。所以,关键路径的形成可能并不是由于自身逻辑的复杂,而是好的资源被其他模块抢走了,我们可以换一换思路,不要局限于关键路径,从系统角度出发,通过简化关键路径之外模块的逻辑,提高工作频率

 

最有效的简化方法一般都要基于具体的工程而言,从需求,功能,实现等大方向做减法,这些方法需要很强的专业背景,不具备通用性,而我想从更具普遍性的编码风格细节入手,谈一谈好的编码风格是如何简化逻辑,提高工作频率的。本篇先来讲讲大家再熟悉不过,但又很容易被忽视的if  else。

 

if else在FPGA工程里可以说是无处不在,在时序逻辑里其主要可以归为两类,一类是补全if else的,主要用于选择器,如下所示,当sel_1有效输出0,sel_2有效时输出1,其他情况都输出0。

always @(posedge clk or negedge rset_n) 
begin if(!rset_n) d <= 0; else if(sel_1) d <= 0; else if(sel_2) d <= 1; else d <= 0; 
end

 

其RTL图如图一所示,很简单,就是一个选择器加一个D触发器。

ScreenClip(7)

图一

 

另一类是没有补全的if else,主要用于锁存数据,如下所示,和上例不同的是,当sel_1和sel_2无效时,输出会保持上一个状态。

always @(posedge clk or negedge rset_n) 
begin if(!rset_n) d <= 0; else if(sel_1) d <= 0; else if(sel_2) d <= 1; 
end

其RTL图如图二所示,和图一相比,多了一个选择器,并将D触发器的输出反馈到了选择器的输入端,实现锁存的功能。

ScreenClip(8)

图二

 

从上述可知,补全if else实现的逻辑会比if else不全的逻辑少一条反馈路径和一个选择器,如果是更复杂的应用,后者消耗的资源可能还会更多。

 

至此,如能根据具体的应用,需要选择器时使用补全的if else,需要锁存功能时,使用不全的if else,那就没有任何问题了,但是,我想重点提醒下,很多人在使用时,对这两种编码风格混淆不清,特别是在一段式状态机里,造成了不必要的浪费,拉低了最高工作频率,下面举一个工作中实际的例子。

 

工程需要跑到200MHz,但在优化前只有174MHz,查看关键路径如图三所示。

ScreenClip(10)

图三

 

oe_width到fast_rd_wait_fifo是当前的速度瓶颈,由于设计所限,无法在这条路径内插入D触发器,开启quartus的寄存器复制优化项,效果也不明显...常用的优化方法都试过一遍了,但都没太多疗效。按照开篇提到的马克思爷爷的"万事万物都有联系"的思路,撇开关键路径,查看工程里其他的模块是否有可以简化之处,寻找了良久,终于找到了一个貌似可以优化的状态机,截取了其中的关键代码如下。

.... 
case(fast_rd_state)fast_rd_st0: 
begin if(executive_cmd) begin fast_rd_busy  <= 1; if(!count_en) begin fast_rd_ok    <= 0; rdaddr_add <= 1; fast_rd_state <= fast_rd_st1; end else begin fast_rd_ok    <= 0; rdaddr_add <= 1; fast_rd_state <= fast_rd_st2; end end else begin fast_rd_busy  <= 0; fast_rd_ok    <= 0; rdaddr_add <= 0; fast_rd_state <= fast_rd_st0; end 
endfast_rd_st1: 
begin rdaddr_add <= 0; if(rd_count_almost_full) begin if(fifo_wrusedw < fifo_rd_deep) begin fast_rd_busy  <= 0; fast_rd_ok    <= 1; fast_rd_state <= fast_rd_st0; end else begin //fast_rd_busy  <= 1;       /*注意这句话*/ fast_rd_ok    <= 0; fast_rd_state <= fast_rd_st3; end end else begin //fast_rd_busy  <= 1;         /*注意这句话*/ fast_rd_state <= fast_rd_st1; end 
end 
.....

注意红色加粗部分,优化前是没有这两句话的,所以优化前,这是一个没有补全的if else,会综合出锁存器,当初没加这两句话的原因是:从逻辑上感觉没有必要,因为从fast_rd_st0状态跳到fast_rd_st1状态后,fast_rd_busy肯定是1了,没有必要再在fast_rd_st1状态机里加上fast_rd_busy  <= 1,让其保持上一个状态的输出就可以了,而且这样还可以省两行代码,关键是实际的执行的结果完全正常。

 

但是,实际上根本不需要在fast_rd_st1状态锁存fast_rd_st0状态时fast_rd_busy的输出,在红色加粗处补上 fast_rd_busy  <= 1后,将状态机变成补全的if else类型后,奇迹发生了,综合频率提高到了190MHz,虽然还没达到200MHz,但相比没有补全if else的写法,提高了16MHz,再看关键路径报告如图四,oe_width到fast_rd_wait_fifo的关键路径悄无声息的消失了。

ScreenClip(11)

图四

 

这再一次的证明了马爷爷的思想是多么的神奇和伟大,没有使用任何传统的优化方式,仅仅是改变了其他逻辑的编码风格,就显著的提升了工作频率,虽然从程序上看,fast_rd_busy并不直接属于关键路径的逻辑范畴,但fast_rd_busy牵扯到的逻辑资源和关键路径的逻辑有着紧密的间接相互作用关系,继续查找频率提升的原因,用Technology map viewer查看没有补全if else的fast_rd_busy的源端逻辑资源如图五所示。

Image(10)

图五

 

再看看补全if else情况下fast_rd_busy的Technology map viewer如图六所示。

Image(11)

图六

 

比较图五和图六,前者具备锁存功能,将fast_rd_busy的输出经过复杂的判断比较逻辑又反馈到了寄存器的输入端,牵扯到的逻辑要明显多于后者,补全if else后,只有选择功能,省去了输出反馈的逻辑,整体的工作频率自然就得到了改善。

 

使用if else时,我们常常会因为其简单,而混淆了带锁存器和无锁存器这两种编码风格,更甚,在误用了没有补全的if else的写法后,会因其表面的逻辑功能正常和减少的代码量而觉得不以为然,其实,它都在潜移默化的影响着你工程的关键路径,赶紧看看你的工程里是否存在这些没有必要的锁存器吧,统统去掉,定有惊喜等着你奥。

 



转载于:https://www.cnblogs.com/littlexiaocai/archive/2012/06/03/2533076.html

这篇关于马克思教我们优化时序之补全if else的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/406240

相关文章

Python中 try / except / else / finally 异常处理方法详解

《Python中try/except/else/finally异常处理方法详解》:本文主要介绍Python中try/except/else/finally异常处理方法的相关资料,涵... 目录1. 基本结构2. 各部分的作用tryexceptelsefinally3. 执行流程总结4. 常见用法(1)多个e

从原理到实战解析Java Stream 的并行流性能优化

《从原理到实战解析JavaStream的并行流性能优化》本文给大家介绍JavaStream的并行流性能优化:从原理到实战的全攻略,本文通过实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的... 目录一、并行流的核心原理与适用场景二、性能优化的核心策略1. 合理设置并行度:打破默认阈值2. 避免装箱

Python实战之SEO优化自动化工具开发指南

《Python实战之SEO优化自动化工具开发指南》在数字化营销时代,搜索引擎优化(SEO)已成为网站获取流量的重要手段,本文将带您使用Python开发一套完整的SEO自动化工具,需要的可以了解下... 目录前言项目概述技术栈选择核心模块实现1. 关键词研究模块2. 网站技术seo检测模块3. 内容优化分析模

Java实现复杂查询优化的7个技巧小结

《Java实现复杂查询优化的7个技巧小结》在Java项目中,复杂查询是开发者面临的“硬骨头”,本文将通过7个实战技巧,结合代码示例和性能对比,手把手教你如何让复杂查询变得优雅,大家可以根据需求进行选择... 目录一、复杂查询的痛点:为何你的代码“又臭又长”1.1冗余变量与中间状态1.2重复查询与性能陷阱1.

Python内存优化的实战技巧分享

《Python内存优化的实战技巧分享》Python作为一门解释型语言,虽然在开发效率上有着显著优势,但在执行效率方面往往被诟病,然而,通过合理的内存优化策略,我们可以让Python程序的运行速度提升3... 目录前言python内存管理机制引用计数机制垃圾回收机制内存泄漏的常见原因1. 循环引用2. 全局变

Python多线程应用中的卡死问题优化方案指南

《Python多线程应用中的卡死问题优化方案指南》在利用Python语言开发某查询软件时,遇到了点击搜索按钮后软件卡死的问题,本文将简单分析一下出现的原因以及对应的优化方案,希望对大家有所帮助... 目录问题描述优化方案1. 网络请求优化2. 多线程架构优化3. 全局异常处理4. 配置管理优化优化效果1.

详解Java中三种状态机实现方式来优雅消灭 if-else 嵌套

《详解Java中三种状态机实现方式来优雅消灭if-else嵌套》这篇文章主要为大家详细介绍了Java中三种状态机实现方式从而优雅消灭if-else嵌套,文中的示例代码讲解详细,感兴趣的小伙伴可以跟... 目录1. 前言2. 复现传统if-else实现的业务场景问题3. 用状态机模式改造3.1 定义状态接口3

MySQL中优化CPU使用的详细指南

《MySQL中优化CPU使用的详细指南》优化MySQL的CPU使用可以显著提高数据库的性能和响应时间,本文为大家整理了一些优化CPU使用的方法,大家可以根据需要进行选择... 目录一、优化查询和索引1.1 优化查询语句1.2 创建和优化索引1.3 避免全表扫描二、调整mysql配置参数2.1 调整线程数2.

深入解析Java NIO在高并发场景下的性能优化实践指南

《深入解析JavaNIO在高并发场景下的性能优化实践指南》随着互联网业务不断演进,对高并发、低延时网络服务的需求日益增长,本文将深入解析JavaNIO在高并发场景下的性能优化方法,希望对大家有所帮助... 目录简介一、技术背景与应用场景二、核心原理深入分析2.1 Selector多路复用2.2 Buffer

SpringBoot利用树形结构优化查询速度

《SpringBoot利用树形结构优化查询速度》这篇文章主要为大家详细介绍了SpringBoot利用树形结构优化查询速度,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... 目录一个真实的性能灾难传统方案为什么这么慢N+1查询灾难性能测试数据对比核心解决方案:一次查询 + O(n)算法解决