Verilog基础:仿真时x信号的产生和x信号对于各运算符的特性

相关阅读

Verilog基础icon-default.png?t=O83Ahttps://blog.csdn.net/weixin_45791458/category_12263729.html?spm=1001.2014.3001.5482


        信号爆x也许是所有IC人的噩梦,满屏的红色波形常让人头疼不已,但x信号的产生原因却常常只有几种,只要遵循一定的代码规范,就可以避免产生信号中出现x的问题。

        最常见问题就是使用了未初始化的reg型变量,因为reg型变量在被创建后使用默认值x。如果在初始化变量之前在其他地方提前使用了,便有可能造成x态的传播。为了避免,可以给所有时序逻辑中用到的reg型变量赋初值(不可综合),但更为推荐的是为所有时序逻辑中使用到的reg型变量添加复位逻辑(可综合)并确保复位,如下所示。对于组合逻辑中使用到的reg型变量,只需要确保始终有正确的驱动即可。

reg a = 0;

reg b;

always@(posedge clk, negedge rst_n)begin
    if(rst_n)
        b <= 0;
    else
        b <= ***;
end

        连续赋值语句也可能会导致x信号的产生,在连续赋值语句对wire型线网赋值时,如果出现了多个驱动源同时驱动为不同的值,并且强度一致(除z外,因为z看做没有驱动)时,会显示为不定态,直到多个驱动不冲突,如下所示。

//一个很幼稚的例子
assign a = 1'b0;
assign a = 1'b1; //赋值冲突,所以a的值为x

//一个依旧很幼稚的例子
initial begin
    b = 1'b0;
    c = 1'b1;
end

assign a = b;
assign a = c; //同样是赋值冲突,所以a的值为x


//一个复杂一点的例子
wire  a;
reg b, c;
initial begin
    b = 1'b0;
    c = 1'b0;
    #5 c = 1'b1;
    #5 c = 1'b0;
    #5 c = 1'b1;
    #5 c = 1'b0;
end

assign a = b;
assign a = c; //因为有时冲突,有时不冲突,所以a的值交替为0和x,最后为0

//一个迷惑一点的例子
wire  a;
reg b, c;
initial begin
    b = 1'b0;
    c = 1'b0;
    #25;
    #5 c = 1'b1;
    #5 c = 1'b0;
    #5 c = 1'b1;
    #5 c = 1'b0;
end

assign a = b;
assign #20 a  = c; //因为连续赋值有延迟,而25ns后每次c改变的脉冲都小于20ns,所以没有进行赋值,最后的c值为0,因此a的值一直是0

        有些运算也可能会产生x信号,下面简单介绍,但需要注意的是,它们大多只是x信号的传播者,而不是x信号的制造者。

算数运算符

        对于算术运算符,当操作数中出现了x信号时,即使结果能全部或部分确认,结果为全x值,如例1所示。

# 例1
module test;
reg [2:0]a, b;
initial begin
    a = 3'b001;
    b = 3'bx01;    
    $display("result is %b",a+b);   //结果为xxx

    a = 3'b001;
    b = 3'bx01;    
    $display("result is %b",a-b);   //结果为xxx

    a = 3'bx01;
    b = 3'b000;    
    $display("result is %b",a*b);   //结果为xxx

    a = 3'b000;
    b = 3'bx01;    
    $display("result is %b",a/b);   //结果为xxx

    a = 3'b000;
    b = 3'bx01;    
    $display("result is %b",a%b);   //结果为xxx

    a = 3'b000;
    b = 3'bx01;    
    $display("result is %b",a**b);  //结果为xxx
end
endmodule

        如果除法运算符的第二个操作数为0,结果为全x值,如果乘方运算符的第一个操作数为0,而第二个操作数为负数,结果为全x值,如例2所示。

# 例2
module test();
reg [2:0]a,b;
initial begin
    a = 3'b001;
    b = 3'b000;    
    $display("result is %b",a/b);     //结果为xxx


    a = 3'b000;
    b = -3'b001;    
    $display("result is %b",a ** b);  //结果应为xxx,但遗憾的是似乎没有仿真器遵守了这一点(结果为000)
end
endmodule

关系运算符

        对于关系运算符,当操作数中出现了x信号时,即使结果能确定,结果为1'bx,如例3所示。

​# 例3
module test;
reg [2:0]a, b;
initial begin
    a = 3'b001;
    b = 3'b1x1;    
    $display("result is %b",a<b);    //结果为x

    a = 3'b001;
    b = 3'b1x1;    
    $display("result is %b",a<=b);   //结果为x

    a = 3'bx01;
    b = 3'b000;    
    $display("result is %b",a>b);    //结果为x

    a = 3'bx01;
    b = 3'b000;   
    $display("result is %b",a>=b);   //结果为x
end
endmodule

相等运算符

        对于逻辑相等和不相等运算符即==和!=,当操作数中出现了x信号时,如果结果能确定,则结果正常输出;如果结果不能确定,结果为1'bx,如例4所示。

​# 例4
module test;
reg [2:0]a, b;
initial begin
    a = 3'b001;
    b = 3'b1x1;    
    $display("result is %b",a!=b);    //结果为1

    a = 3'b001;
    b = 3'b0x1;    
    $display("result is %b",a!=b);    //结果为x

    a = 3'b001;
    b = 3'b1x1;    
    $display("result is %b",a==b);    //结果为0

    a = 3'b001;
    b = 3'b0x1;    
    $display("result is %b",a==b);    //结果为x
end
endmodule

        对于精确相等和精确不相等运算符即===和!==,它类似于case语句种的比较,操作数中的x信号必须精确相等,因此结果只能是0或1,如例5所示。

​# 例5
module test;
reg [2:0]a, b;
initial begin
    a = 3'b101;
    b = 3'b1x1;    
    $display("result is %b",a===b);    //结果为0

    a = 3'b1x1;
    b = 3'b1x1;    
    $display("result is %b",a===b);    //结果为1

    a = 3'b101;
    b = 3'b1x1;    
    $display("result is %b",a!==b);    //结果为1

    a = 3'b1x1;
    b = 3'b1x1;     
    $display("result is %b",a!==b);    //结果为0
end
endmodule

逻辑运算符

        对于逻辑运算符,当操作数中出现了x信号时,如果结果能确定,则结果正常输出;如果结果不能确定,结果为1'bx,如例6所示。

​# 例6
module test;
reg [2:0]a, b;
initial begin
    a = 3'b101;
    b = 3'bx00;    
    $display("result is %b",a||b);   //结果为1

    a = 3'bx00;
    b = 3'bx00;    
    $display("result is %b",a||b);   //结果为x

    a = 3'bx01;
    b = 3'bx01;   
    $display("result is %b",a&&b);   //结果为1

    a = 3'bxx0;
    b = 3'bxx0;     
    $display("result is %b",a&&b);   //结果为x

    a = 3'b1x1;   
    $display("result is %b",!a);     //结果为0

    a = 3'b00x;   
    $display("result is %b",!a);     //结果为x
end
endmodule

位运算运算符

        位运算符按位对操作数进行操作,注意对于这些运算符,某位的x值不会影响其他非x位的结果。x与1结果为x,x与0结果为0,x或1结果为1,x或0结果为x,x异或、同或和取反结果为x,如下表和例7所示。

​# 例7
module test;
reg [2:0]a, b;
initial begin
    a = 3'b11x;
    b = 3'bx1x;    
    $display("result is %b",a&b);   //结果为x1x

    a = 3'bxxx;
    b = 3'b10x;    
    $display("result is %b",a|b);   //结果为1xx

    a = 3'bx0x;
    b = 3'bxx1;   
    $display("result is %b",a^b);   //结果为xxx

    a = 3'bx0x;
    b = 3'bxx1;     
    $display("result is %b",a~^b);  //结果为xxx

    a = 3'b1x0;   
    $display("result is %b",~a);    //结果为0x1
end
endmodule

规约运算符

        对于规约与运算符&,如果操作数中存在0,结果为0(不管是否含有x值),对于规约或运算符|,如果操作数中存在1,结果为1(不管是否含有x值)。其他情况下,如果操作数中有x值,则结果为1'bx。如例8所示。

​# 例8
module test;
reg [2:0]a, b;
initial begin
    a = 3'b10x;  
    $display("result is %b",&a);   //结果为0

    a = 3'b1xx;  
    $display("result is %b",&a);   //结果为x

    a = 3'b10x; 
    $display("result is %b",|a);   //结果为1

    a = 3'b00x; 
    $display("result is %b",|a);   //结果为x

    a = 3'b1xx;   
    $display("result is %b",^a);   //结果为x
end
endmodule

移位运算符

        对于逻辑移位运算符即<<和>>是补0移位,对于算数移位运算符即<<<和>>>,当作用于有符号的操作数,算数右移>>>时会在高位补符号位(最高位),其他情况下,逻辑移位和算数移位效果一样。当移位运算符的右操作数中有x值时,结果为全x值。如例9所示。

​# 例9
module test;
reg signed [2:0]b;
initial begin
    b = 3'b1x1;   
    $display("result is %b",b>>1);    //结果为01x

    b = 3'b1x1;   
    $display("result is %b",b<<1);    //结果为x10

    b = 3'bx01;   
    $display("result is %b",b>>>1);   //结果为xx0

    b = 3'bx01;   
    $display("result is %b",b<<<1);   //结果为010
end
endmodule

条件运算符?:

        对于条件运算符?:,当第一个操作数种出现x值时,会对第二个和第三个操作数每一位按照以下规则进行检测,并给出结果。如例10所示。

​# 例10
module test;
reg [2:0]a, b;
reg c;
initial begin
    a = 3'b1x0; 
    b = 3'b100;
    c = 1'bx;
    $display("result is %b",c?a:b);  # 结果为1x0
end
endmodule

连接运算符

        对于连接运算符,某一位的x值不会影响其它位,如例11所示。

​# 例11
module test;
initial begin
    $display("result is %b",{1'bx,3'b111});  //结果为x111
end
endmodule

向量的位选、域选

         当位选超出界限时,结果为1'bx。当域选超出界限时,超出的部分在返回时会用x值填充。当数组索引超出界限时,结果为全x值,如例12所示。关于向量的位选、域选的详情,可以看操作数的位选和域选

​# 例12
module test;
reg [2:0]b;
reg [2:0]c[1:0];
initial begin
b = 3'b111;   
$display("result is %b",b[3]);   //结果为x

b = 3'b111;   
$display("result is %b",b[4:2]); //结果为xx1

$display("result is %b",c[2]);   //结果为xxx
end
endmodule
评论 18
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

日晨难再

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值