在RTL中,可以使用signed关键字来声明一个有符号信号,以此来向仿真器和综合器说明该信号是有符号的。相比于不声明signed的表达方式,声明signed的好处主要体现为两点:
1)自动补足符号位。
2)可忽略补码规则,直接进行正负数的比较。
这两个优点能够明显简化数字工程师的设计表达,使得他们可以将精力更多地投入到主要算法的实现上。
如果仿真器和综合器不能自动补充符号,则会给加减运算和右移带来不便。
体现在加减运算上,就像2.3.4节和2.4.2节所举例子一样,在进行加减法前,设计者必须将参与运算的信号位宽补充到与结果位宽一致。
体现在信号数据右移上,设计者必须在右移信号时,对高位空出来的位宽补充其符号。
在两个数值的比较方面,如果直接比较两者的补码,在两数同号时可以比较,但在两数异号时无法直接比较。比如,两个3位的有符号信号3'b100和3'b011,虽然前者表示-4,后者表示+3,但直接比较会认为前者大。为了避免此类错误,也需要设计者增加一些额外的语法表达。
通过signed声明可以解决上述两个问题,被声明的信号基本可以像MATLAB算法程序那样操作,这为设计带来了许多方便。例如,同样是2.4.2节中四舍五入的RTL示例,使用signed声明后代码如下。在本例中,加法之前对a2的补位没有了,溢出保护中信号的比较以直观的方式呈现。signed声明的位置在wire或reg之后。
使用signed声明时,需要注意以下4点:
1)如果一句RTL表达,既包含加、减、乘、移位等运算,又包含逻辑选择、逻辑判断、位操作等,需要将运算和逻辑分成两句表达。既包含运算又包含逻辑的语句,如下例所示,在运算中,综合器会将参与运算的信号a和b作为无符号信号来处理。
将逻辑判断语句与运算语句分开后,表达式如下:
2)在进行加、减、乘及移位运算或者对两个信号进行比较时,要保持参与运算或比较的信号是相同类型的,即要求它们统一为未声明signed的形式或signed的形式,不能将未声明的信号与已声明的信号混合运算,否则已声明为signed的信号会被当作未声明为signed的信号来处理。下例中,信号a声明了signed,信号b未声明,两者进行比较可能会发生意外。仿真器和综合器会将a转化为未声明的状态。因此,如果a是一个负数,那么它的补码将比正数大,从而发生判断错误。
在实际电路设计中,确实存在一个有signed声明的信号和一个无signed声明的信号之间进行比较的需求,同样的情况也发生在数值运算中,此时,需要将无signed声明的信号强制转换为有signed声明的信号。这里将上例中的b强制转换,就会得到如下的符合设计意图的RTL表达。无signed声明的信号在被强制转换时,需要在高位补0,像本例中的signed'({1'b0,b})。补零的作用是使综合器认为该信号的符号为正,假设b的值为4'b1001,若高位不补零,会被识别为负数。
当然,有时也会遇到已知一个有符号信号a和一个无符号信号b,但a比较的对象是-b的情况,如下例所示,也需要强制转换,但转换前要带负号。转换式不可写为 − signed'({1'b0,b})。
综合器对数值是否包含符号有自己的判断,凡是包含位宽的数值,如6'd18,均被视为无符号数,即无论设计者是否认为该数带符号,综合器均将其当作无符号数进行运算和比较。但是,如果数值不包含位宽,比如直接写18,综合器会认为它是一个32位的有符号数。因此,下面两句RTL表达式的效果是相同的。当然,推荐使用前一种表达式,因为语法检查工具对比较器两边或运算式两边数值位宽不相同的情况会进行警告。
3)对于有signed声明的信号,拥有专门的移位运算符>>>和<<<。>>>不同于常用的移位符>>,>>是无符号信号移位时使用的。若一个由signed声明的信号使用了>>移位,则综合器也同样会将其作为无signed声明的信号。如下例中,a向右移动1位,虽然它已声明了signed,但移位得到的b却总是正值。比如,a为4'b1001(即-7),向右移动后,预期b的值为4'b1100(即-4),但实际上却得到了4'b0100(即4)。
移位也是一种计算,也有位宽的要求。上例中,b的位宽为4,若位宽为3,则即便用>>,得到的结果也是正确的。上例仅是为了说明使用>>后,高位多余的比特会被填充为0,而使用>>>,高位多余的比特会被填充为数值的符号。
对于<<和<<<,目前主流的综合器如DC和Genus均做等效处理。但对于有signed声明的信号,还是推荐使用<<<进行左移操作。
移位除使用移位符号外,右移可以用类似a[3:1]的数位索引表达,而左移也可以使用类似{a,1'b0}的数位组合表达。此操作属于无符号逻辑操作,对于有signed声明的信号,移位时不使用这种方法。
4)signed声明未包含在典型的Verilog语法中,它属于System Verilog的语法。因此,无论是仿真还是综合,要使用它都必须开启支持System Verilog的选项。
在使用VCS编译时,需要加入-sverilog选项,如下:
在使用DC综合时,需要加入-format sverilog选项,如下:
正是由于signed声明可提高电路设计时数值表达的直观性,使得算法移植到电路中更加容易,本书在下面的设计中将主要采用这种声明方式来编写RTL。