芯片设计小经验——寄存器的不同verilog描述

数字IC自修室 2021-08-20 15:12
我们知道对于每个IC前端工程师来说,一个好的代码风格很重要,一方面便于保证自己书写时硬件逻辑脉络的清晰,另外一个更重要的原因是便于代码的阅读和维护。这篇文章想聊一下RTL里描述寄存器的两种不同代码风格。


RTL(Register Transfer Level),指的是寄存器传输级别的硬件描述,那么关于寄存器Register的硬件描述自然是我们写代码时候最日常的操作了。在verilog语言中,使用always语句块便能描述最基本的d寄存器。如果该寄存器的更新条件和更新值复杂一点,配合if-else也可以轻易完成。


对于寄存器来说,分为控制寄存器和数据寄存器。一般而言数据寄存器不需要复位,bit数也较大。在描述的时候略为不同。

1 控制寄存器

举一个简单的例子。一个用来表示数据有效的单bit valid信号,复位值为1’b0,在新数据到来的时刻条件A成立时需要被设置成1’b1,在数据清除B条件成立时要被清为1’b0,如果某时刻A和B同时成立,则数据依然有效。根据条件,很轻易地可以写出以下verilog寄存器描述:


这么写肯定是没问题的。通过if-else的描述来保证AB同时有效时刻的优先级,功能描述也符合需求。但有个点,这么写综合出来的电路是什么样的,很难通过代码直观感受。很明显这应该综合出一个1bit的d寄存器,但它的d端,en端具体和A,B这些条件是什么连接关系呢?只看代码不好推测。我们来看另外一种代码风格描述同一个功能:


很明显,这种方式描述的d寄存器,每个pin所连接的逻辑都一目了然。


2 数据寄存器

依旧举一个简单的例子。一个多bit的数据,A条件成立时被赋值成data_a,B条件成立时被赋值成data_b,C条件成立时被赋值成data_c,优先级A>B>C。依旧可以有两种不同的描述方式:

第一种:

第二种:

以上两个例子中,前一种写法本质上是行为级的描述,用偏软件风格的描述,if-else更加直观容易理解,但综合实现结果取决于工具。而后一种写法本质上是门级的描述,逻辑看着不那么直观明了,但是确实门级电路最终实现的样子。一方面可以最大程度人为控制综合结果(比起行为级描述),另一方面便于寄存器批量替换。在蜂鸟E203开源RISCV项目中便使用了这种寄存器描述来实例化标准寄存器:


如果使用行为级描述的if-else来描述寄存器,那么无法实现这样的寄存器模块化。

此外,对于数据寄存器的d端,如果使用if-else,没有特别对综合工具下约束,只能生成优先级选择逻辑,而使用门级描述,可以轻易选择使用优先级选择逻辑或者是并行选择逻辑,以此来优化时序(当然前提是A,B,C条件互斥)。