未闻verilog---表达式的赋值即位宽和符号的确定

表达式的位宽和符号

计算表达式的步骤

计算表达式的步骤如下

  1. 基于表达式位长确定的规则,确定表达式的位长。
  2. 基于表达式符号确定的规则,确定表达式的符号。
  3. 把表达式( 或者self-determined subexpression ) 的类型和位长向下传播到表达式的上下文决定( context-detemined) 的操作数上。通常,上下文决定操作数的类型和位长与运算结果的类型和位长相同。但是也有两个例外:如果运算结果是real,但是它有一个上下文决定且不是real的操作数,那么这个操作数就按照self-determined处理,然后再把它转换为real;在比较操作中,如果两个操作数既不全是self-determined也不全是context-determined,那么这两个操作数就互相影响,他们就如同是context-determined操作数一样,从而产生由它们决定的类型和位长,这时操作数的类型和位长独立于表达式的其他部分。但是比较操作的结果总是1-bit的无符号数。
  4. 当传播到达一个简单的操作数时,这个操作数就转换到传播来的类型和位长,如果操作数必须被扩展,那么只有当传播类型是signed时,操作数才做符号扩展。

表达式位长规则

  1. 表达式的位长(或者表达式的size)由表达式的操作数表达式所处的上下文决定。
  2. 自决定表达式(self-determined expression)就是表达式的位长完全由表达式决定,例如表示延迟的表达式。
  3. 上下文决定表达式(context-determined expression)就是表达式的位长既由表达式本身的位长决定,也有这样的事实决定(表达式本身是另一个表达式的一部分)。例如赋值RHS的位长既依赖于其本身,也依赖与LHS的位长。
  4. 如果不想让乘法丢失溢出的位,那么就要把结果赋值给一个位长足够大的变量,这样才能够保存运算的最大结果。
  5. 在计算表达式时,中间结果就取操作数的最大位长(如果是赋值,也包含LHS)
  6. 有了{},则中间结果的位宽由里面的表达式自决定。

image

举几个例子

reg  [3:0] a=15;
reg  [3:0] b=2;
reg  [4:0] c;
initial
    c = a + b;

输出结果是

image

虽然a和b都是4位,但因为在c=a+b; 中c的位长为5位,所以a和b计算的位长由上下文中c的位长决定,所以按照5位来计算,最后c为10001;

reg  [3:0] a=15;
reg  [3:0] b=2;
reg  [4:0] c;
initial
    c = {a + b};

这个例子与上一个例子不同之处在于给a+b 加上了{} ,结果为

image

从上面提到,有了{},则中间结果的位宽由里面的表达式自决定,不再考虑上下文,所以就按4位位长进行计算,因为4位计算会有数据溢出,溢出后的4位数据为0001,因为c是无符号数,将中间结果赋值给c时,位长要短于c,需要扩充位数,补0,所以c的结果为00001;

reg [8:0] a=510,b=25;
reg [7:0] c=254,d=25;
initial
    begin
        if((a+b)>=(c+d))
            $display("a+b is large than c+d");
        else
            $display("a+b is not large than c+d");
        if((a+b+0)>(c+d+0))
            $display("a+b+0 is large than c+d+0");
        else
            $display("a+b+0 is not large than c+d+0");
        if((a+b+10'b0)>(c+d+10'b0))
            $display("a+b+10'b0 is large than c+d+10'b0");
        else
            $display("a+b+10'b0 is not large than c+d+10'b0");
    end

endmodule

输出结果

image

按照数据运算这三个都应该输出前面大于后面

对于第一个判断语句(a+b)>=(c+d) 来说,根据上下文,最大的位长为a和b的9位,a+b的9位运算和c+d 的8位运算都发生了溢出,如果考虑溢出后的数据,两个的数据相等,但是因为要根据上下文的位长进行计算,所以后面c+d 的运算按照9位进行,所以后面的语句计算没有发生溢出,所以后面的要大。

对于第二个判断语句(a+b+0)>(c+d+0)来说,+0 ,因为没有声明位宽的0默认位长为32位,所以a+bc+d 的计算都按照32位长进行计算,所以没有发生溢出,所以a+b 要大于c+d

对于第三个判断语句(a+b+10'b0)>(c+d+10'b0) 来说,里面有一个+10'd0 ,所以运算按照10位来进行,所以没有发生溢出,所以a+b 要大于c+d

表达式类型

表达式类型(signed或unsigned)规则如下

  1. 表达式类型只依赖于操作数,不依赖于LHS(如果是赋值表达式,就存在LHS)。
  2. 十进制数是符号数(signed)
  3. 如果没有sign标志,那么带base的数是无符号数(unsigned)
  4. bit-select的结果是无符号数(unsigned),不管操作数是符号数还是无符号数
  5. part-select的结果是无符号数(unsigned),不管操作数是符号数还是无符号数,即使part-select的内容是整个向量。
  6. 连接操作的结果是无符号数,不管操作数是符号数还是无符号数。
  7. 比较操作的结果是无符号数,不管操作数是符号数还是无符号数。
  8. real强制转换integer的结果是符号数(signed)。
  9. 任何自决定(self-determined)操作数的符号和位长都由操作数自身决定,独立于表达式的其他部分。

对于非自决定(nonself-determined)的操作数,遵从下面的规则。

  1. 如果某个操作数是real,那么结果是real。
  2. 如果某个操作数是无符号操作数,那么结果是无符号操作数,不管是什么操作。
  3. 如果所有操作数是符号整数,那么结果才是符号整数,不管是什么操作。

注意:一位有符号数只有0和-1,有符号数0就是0,有符号数1就代表着-1(符号位为负,只能表示-1)

举个例子

reg signed [3:0] a=15;
reg  [3:0] b=2;
reg [9:0] d;
reg  signed [4:0] c;
initial
    begin
        c = a + b;
        d = a;
    end

结果

image

表达式类型只依赖于操作数,不依赖于LHS,所以我们先看RHS,右式包含着操作数a+b,因为a,b中b不是有符号变量,也就是说操作数中存在无符号变量,所以a+b 中a,b还是按照无符号变量计算。当计算时位长按照c的位长5位来计算,因为这里a和b是4位,所以要对a和b进行补位,因为a和b按照无符号变量,所以补0。下面的d=a ,d是10位长,a赋值给d要进行补位,右式的操作数a是有符号变量,所以a要用符号位来补位。

reg signed [3:0] a=15;
reg signed [3:0] b=2;
reg [9:0] d;
reg  signed [4:0] c;
initial
    begin
        c = a + b;
        d = a;
    end

结果

image

表达式类型只依赖于操作数,不依赖于LHS,所以我们先看RHS,右式包含着操作数a+b,因为a,b中a,b都是有符号变量,也就是说操作数都是有符号变量,所以a+b 中a,b还是按照有符号变量计算。当计算时位长按照c的位长5位来计算,因为这里a和b是4位,所以要对a和b进行补位,因为a和b是有符号变量,所以补符号位进行计算,计算结果发生溢出,所以结果为00001。

执行赋值的步骤

计算赋值的步骤如下:

  1. 根据赋值位长确定原则,确定RHS的位长
  2. 如果需要,就扩展RHS。不管LHS的符号是什么,扩展时都不考虑LHS的符号,只有当RHS是signed,才做符号扩展。
  3. 赋值时,如果RHS的位长大于LHS的位长,那么直接把多出的位丢弃,以匹配LHS的位长。(有可能把符号位截去)
posted @ 2022-03-13 10:01  孤独野猪骑士  阅读(1142)  评论(0编辑  收藏  举报