我们在综合时,为了面积和时序目标,常常开了很多优化选项,比如compile_ultra。这个命令会根据面积和时序的要求,自动ungroup部分子模块,并进行跨模块边界优化。为了优化动态功耗,我们还会自动插入门控时钟。还有DCT、DCG模式,会打开物理优化,为了修复Cap和Transition的违例,进行寄存器复制、子模块端口复制等。下面就这些选项做一些说明。
状态机编码转换
我们都知道状态机最好用格雷码,原因是相临两个状态只有一位变化。但实际项目中,要实现格雷码并不容易。如下的例子中,四个状态A、B、C、D可以相互跳转。A、B、C、D四个状态的格雷码分别是00、01、11、10。我们发现A与D跳转、B与C跳转,并不只是变一位,而是变化了两位。所谓的格雷码的优势也就不存在了。位数变化少,还有一个好处就是功耗低。
比格雷码更极端的编码方式——独热码。如下图,任意两个状态都只变化两位,且每个状态都有且只有一位是1。这样状态机的状态就可以用1位来表示:A = current_state[0],B = current_state[1],C = current_state[2],D = current_state[3]。所以可以看出独热码的译码逻辑更简单,即Timing最好。
缺点是状态的编码用到的DFF数量呈指数增加。比如32个状态,用格雷码只需要5个DFF,用独热码却需要32个DFF,面积大。
我们写代码时,怎么折中呢?用格雷码比较麻烦,需要根据状态之间的跳转概率和顺序来调整哪个状态用哪个编码。而且有时候总是会出现多bit变化的情况。如果修改代码时增加了状态或者减少了状态,格雷码需要重新调整。
那么有没有更好的方式呢?有。利用综合工具的状态机优化选项——“重编码”。代码里写哪种编码已经不重要了,都可以在综合时提取再重编码。
dc_shell> set_fsm_encoding_style -help
Usage: set_fsm_encoding_style
[< one_hot | zero_one_hot | binary | gray | auto | neutral >]
状态机相关的option:
set_fsm_encoding
set_fsm_minimize
set_fsm_preserve_state
set_fsm_encoding_style
set_fsm_order
set_fsm_state_vector
那工具都这么智能了,我们还需要学习和保持优秀状态的写法吗?要的。因为工具是为人服务的,只是人的帮手。
系列文章:
一、flatten hierarchy