最基础的,往往最容易出错。
最近,用到了SystemVerilog去写计算,然后,各种赋值规则,让人眼花缭乱,特此记录。
下面以int类型的赋值为例。
int的赋值方式有三种,分别是:
(1)unsized, unbased integer(e.g., 12)
(2)unsized, based integer (e.g., 'd12, 'sd12)
(3)sized, based integer(e.g., 16’d12, 16’sd12)
特别注意:方式(1)的值,没有进制,都是有符号的数;方式(2)和(3)中,有进制,但是没有标明是有符号的,比如’d12,16’d12,表示的值是无符号的。
int inta, intb, intc, intd;
assign inta = -12;// 2进制:1111_1111_1111_1111_1111_1111_1111_0100 10进制:-12 有符号数
assign intb = -'d12;// 2进制:1111_1111_1111_1111_1111_1111_1111_0100 10进制:-12 无符号数
assign intc = -'sd12;// 2进制:1111_1111_1111_1111_1111_1111_1111_0100 10进制:-12 有符号数
assign intd = -4'sd12;// 2进制:0000_0000_0000_0000_0000_0000_0000_0100 10进制:4 有符号数
int inta3, intb3, intc3, intd3;
assign inta3 = -12/3;// 2进制:1111_1111_1111_1111_1111_1111_1111_1100 10进制:-4
assign intb3 = -'d12/3;// 2进制:0101_0101_0101_0101_0101_0101_0101_0001 10进制:1431655761
assign intc3 = -'sd12/3;// 2进制:1111_1111_1111_1111_1111_1111_1111_1100 10进制:-4
assign intd3 = -4'sd12/3;// 2进制:0000_0000_0000_0000_0000_0000_0000_0001 10进制:1
int inta3n, intb3n, intc3n, intd3n;
assign inta3n = -12/-3;// 2进制:0000_0000_0000_0000_0000_0000_0000_0100 10进制:4
assign intb3n = -'d12/-3;// 2进制:0000_0000_0000_0000_0000_0000_0000_0000 10进制:0
assign intc3n = -'sd12/-3;// 2进制:0000_0000_0000_0000_0000_0000_0000_0100 10进制:4
assign intd3n = -4'sd12/-3;// 2进制:1111_1111_1111_1111_1111_1111_1111_1111 10进制:-1
下面看看这一组的赋值结果。
int intd_2, intd_3, intd_4, intd_5;
assign intd_2 = -2'sd12;// 2进制:0000_0000_0000_0000_0000_0000_0000_0000 10进制:0
assign intd_3 = -3'sd12;// 2进制:0000_0000_0000_0000_0000_0000_0000_0100 10进制:4
assign intd_4 = -4'sd12;// 2进制:0000_0000_0000_0000_0000_0000_0000_0100 10进制:4
assign intd_5 = -5'sd12;// 2进制:1111_1111_1111_1111_1111_1111_1111_0100 10进制:-12
int intb_2, intb_3, intb_4, intb_5;
assign intb_2 = -2'd12;// 2进制:0000_0000_0000_0000_0000_0000_0000_0000 10进制:0
assign intb_3 = -3'd12;// 2进制:1111_1111_1111_1111_1111_1111_1111_1100 10进制:-4
assign intb_4 = -4'd12;// 2进制:1111_1111_1111_1111_1111_1111_1111_0100 10进制:-12
assign intb_5 = -5'd12;// 2进制:1111_1111_1111_1111_1111_1111_1111_0100 10进制:-12
intd_4与intd_3的结果,竟然是一样的。
怎么回事?
这就要研究一下,SystemVerilog中是如何计算的了。
下方以intd_3的计算过程来说明:
intd_3 = -3’sd12
越靠近12的符号,越先处理。
首先是,d,表示10进制,也就是说,12是10进制的数,代表是进制的12.
在计算机内部,运算的数据都是补码形式的。
所以,假设数据是8bits的,那么此时12的补码:0000_1100
其次是,s,表示这个数是有符号的数,即最高位当作符号位。因为0000_1100,最高位是0(最左边的那个0),所以是正数。
然后是,3,这个是sized,表示数据位宽是3位,即从0000_1100中截取最低的3bits(最右边的3位数据),即100.
在然后,将截取的3bits数据展开为8bits,因为是有符号的,按照符号位展开,故100 -> 1111_1100.(如果是无符号的,那么直接在前方补0,如intb_2/3/4/5中的处理)
最后计算负号(-),按照公式-A = 0 + (~A) + 1,即:
A :1111_1100
~A: 0000_0011 (所有位取反,包括符号位和数值位)
-A: 0000_0100(加1)
所以,整个计算过程是:
'sd12:0000_1100
3’sd12:1111_1100
-3’sd12:0000_0100
类似的:
'd12: 0000_1100
3’d12:0000_0100
-3’12:1111_1100
形式为(-)(size) ’ (sign) (base)(value)
首先根据base 和 value,写出对应的二进制数值;比如’d12:0000_1100
然后根据size截取对应位,根据sign,给欠缺的位补齐,如果是signed,则根据截取的值的最高位进行补齐,如果是unsigned,则直接补0.
最后,如果有负号(-),那么就是目前的所有位(包括符号位)取反,然后加1,得到最终结果。