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

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