如何確定Verilog表達式的位寬
掃描二維碼
隨時隨地手機看文章
一般規(guī)則
很多時候,Verilog中表達式的位寬都是被隱式確定的,即使你自己設計了位寬,它也是根據規(guī)則先確定位寬后,再擴展到你的設計位寬,這常常會導致結果產生意想不到的錯誤。比如:
`timescale 1ns/1ns
module tb_test();
reg [3:0] a,b;
reg [1:0] c1,c2;
initial begin
a = 4'b0111;
b = 4'b1111;
c1 = a & b;
c2 = a && b;
end
endmodule
結果是這樣的:
a & b的結果本來應該是4‘b0111 ,但是c1只有2位,所以高位被截斷,導致c1為2’b11;而a && b 的結果本來是1位的1’b1,但是c2有2位,所以會在高位補0,導致c2為2’b01。
類似的情況還有很多,為了減少設計出錯的可能性,有必要探究一下表達式的位寬確定規(guī)則。
Verilog語法規(guī)定了如下的確定表達式位寬的規(guī)則:
-
表達式的位寬由表達式中的操作數(operands)或表達式所處的上下文(context)決定。
-
自決定表達式(self-determined expression)就是表達式中所有操作數的位寬完全由自己決定。
-
上下文決定表達式(context-determined expression)就是表達式中所有操作數的位寬由整個表達式上下文環(huán)境中最大的位寬決定。
自決定表達式
這一類表達式的位寬都是根據表達式自身的位寬和運算結果來決定的。具體規(guī)則如下:

1、無位寬常數
這種情況它的位寬等同于整數integer,在大多數編譯器中,integer的默認位寬都為32位。例如modelsim環(huán)境下的測試:
`timescale 1ns/1ns module tb_test(); initial begin $display("answer = %b", (1)); //以2進制形式打印 end endmodule
打印結果是32位寬的 “1”:
answer = 00000000000000000000000000000001
2、給定位寬常數
沒什么好說的,位寬就是給定的這個數,比如 4‘d1的位寬就是4。例如:
//以2進制形式打印`timescale 1ns/1ns
module tb_test();
reg [3:0] a;
initial begin
a = 4'd1;
$display("answer = %b", a); //以2進制形式打印
end
endmodule
打印結果:
answer = 0001
3、運算(1)
i 和 j 做以下運算:+ - * / % & | ^ ^~ ~^ 時,位寬等于 i 和 j 中位寬較大者的位寬。很好理解,這些運算就是常見的 加減乘除取模 與或異或同或 運算。例如4bits數和5bits數相加:
`timescale 1ns/1ns module tb_test(); reg [3:0] a; reg [4:0] b; initial begin a = 4'd1; b = 5'd1; $display("answer = %b", (a + b)); end endmodule
打印結果是5bits:
answer = 00010
4、運算(2)
對 i 做以下運算:+ - ~ 時,位寬等于它本身。也很好理解,就是正負表達和取反,所以位寬肯定不會改變。例如:
`timescale 1ns/1ns
module tb_test();
reg [3:0] a;
initial begin
a = 4'b1001;
$display("answer = %b", (~a)); //取反
end
endmodule
打印結果仍是4bits:
answer = 0110
5、比較
二個數的比較結果只有 是 和 不是,所以位寬只需要1位,例如:=== !== == != > >= < <=。例如:
`timescale 1ns/1ns module tb_test(); reg [3:0] a,b; initial begin a = 4'd5; b = 4'd3; $display("answer = %b", (a > b)); end endmodule
打印結果是1bit:
answer = 1
6、邏輯與、邏輯或
邏輯與&& 和 邏輯或 || 的結果也只有1bit。
`timescale 1ns/1ns module tb_test(); reg [3:0] a,b; initial begin a = 4'd5; b = 4'd3; $display("answer = %b", (a && b)); end endmodule
打印結果是1bit:
answer = 1
7、規(guī)約運算(Reduction)
下面這些規(guī)約運算的結果只有1位:& ~& | ~| ^ ~^ ^~ !。規(guī)約運算就是對數據本身的所有位做同樣的對應的運算,例如規(guī)約與(該數的所有位相與):
`timescale 1ns/1ns
module tb_test();
reg [3:0] a,b;
initial begin
a = 4'b1101;
b = &a; //1 & 1 & 0 & 1
$display("answer = %b", (b));
end
endmodule
打印結果是1bit:
answer = 1
8、移位和乘方
移位和乘方運算(>> << ** >>> <<<)的結果位寬是該數本身位寬。例如移位:
`timescale 1ns/1ns
module tb_test();
reg [3:0] a;
initial begin
a = 4'b1011;
$display("answer = %b", (a >> 1));
end
endmodule
打印結果是4bits:
answer = 0101
乘方運算的結果有可能會溢出,例如:
`timescale 1ns/1ns module tb_test(); reg [3:0] a,b; initial begin a = 4'd3; b = 4'd3; $display("answer = %b", (a**b)); end endmodule
打印結果是4bits:
answer = 1011
3**3的結果原本是27,即1_1011,高位被截斷后,成了4bits的1011。
9、條件表達式
條件表達式(i ? j : k)的位寬等于 j 和 k 中的位寬較大者。例如:
`timescale 1ns/1ns
module tb_test();
reg [3:0] a;
reg [5:0] b;
reg c;
initial begin
c = 1;
a = 4'b1011;
$display("answer = %b", (c ? a : b) );
end
endmodule
打印結果是6bits:
answer = 001011
盡管c為真,所以該式的結果是a,但是位寬卻等于更寬的b,所以結果的高位會補2個0,擴展到6bits。
10、拼接
第一種拼接:{i,…,j},位寬為二者之和。例如:
`timescale 1ns/1ns module tb_test(); reg [3:0] a; reg [5:0] b; initial begin a = 4'b1011; b = 6'b001011; $display("answer = %b", ({a,b}) ); end endmodule
打印結果是4 + 6 = 10bits:
answer = 1011001011
第二種拼接:{i{j,…,k}},位寬為二者之和與系數的乘積。例如:
`timescale 1ns/1ns module tb_test(); reg [3:0] a; reg [5:0] b; initial begin a = 4'b1011; b = 6'b001011; $display("answer = %b", ({2{a,b}}) ); end endmodule
打印結果是2*(4 + 6) = 20bits:
answer = 10110010111011001011
上下文決定表達式
上下文決定表達式其實就是各種自決定表達式的集合,所以需要視具體情況而具體分析。看一個例子:
`timescale 1ns/1ns module tb_test(); reg [3:0] a; reg [5:0] b; reg [15:0] c; initial begin a = 4'hF; //15 b = 6'hA; //10 $display("a*b=%b", a*b); //10*15 c = {a**b}; //15^10 $display("a**b=%b", c); c = a**b; //15^10 $display("c=%b", c); end endmodule
打印結果:
a*b=010110
a**b=0000000000000001
c=1010110001100001
-
a*b原本是15×10=150,即1001_0110,但是結果的位寬是a、b中的較大位寬(6bits),所以被結果截斷到 01_0110;
-
a**b原本是15^10=576,650,390,625,即1000011001000011000010101010110001100001,但是乘法的結果位寬是a的位寬(4bits),所以結果被截斷到 0001;然后和 0 做拼接,相當與位寬沒變,所以結果仍是0001,最后賦值給c,c的位寬為16,所以需要在高位補0,最終結果為0000000000000001
-
第三個和第二個的區(qū)別在于沒有拼接運算符,a**b的位寬結果取決于上下文環(huán)境,即c的位寬。所以在計算時,a和b都會被先拓展到16位,然后再計算結果。