【Verilog】表達式位寬與符號判斷機制


緣起於p1課下alu算數位移設計。查了好多資料,最后發現還是主要在翻譯官方文檔。浪費了超多時間啊,感覺還是沒搞透,還是先以應用為導向放一放,且用且歸納

1.表達式位寬 expression bit length

身為硬件描述語言,Verilog表達式運算過程中必然要嚴肅考慮位寬問題

表達式的位寬由式中操作數和語境決定

表達式按位寬確定方式分為兩類:

  • self-determined expression
    位寬僅有表達式自身確定,不會受語境影響也不影響語境中其他表達式(在復合表達式中某些位置上的子表達式,如i>>j中的表達式ji?j:k中的表達式i)。
  • context-determined expression
    位寬由表達式本身和其所屬表達式(父子表達式)共同決定(如阻塞賦值操作的RHS位寬由其自身和LHS被賦值變量的位寬決定)。

下表中i,j,k表示"單操作數表達式",L(i)表示表達式i的位寬

截自verilog-std-1364-2005

注意:RHS中context-determined表達式位寬受左值LHS影響,這點和符號性判斷不同
這點尚未弄清存疑,且看示例

例0:縮減運算符相關(包含了優先級內容)

module trial(
	 output C,
	 output D,
	 output E,
	 output F,
	 output [7:0] Da,
	 output [7:0] Ea
    );
	wire [7:0] A = 8'b1011_1100;
	wire B = 1;
	
	assign C = ^A;		// expect:1 ; got:1
	assign D = ^A && B;	// expect:1 ; got:1
	assign E = ^A & B;	// expect:0 ; got:1 ---> 縮減運算符優先級低了
	assign F = ^(A & B);	// expect:0 ; got:0
	assign Da = ^A && B;
	assign Ea = ^A & B;
endmodule

 
image
 

例1:所謂中間值位寬

reg [15:0] a,b,ans;
assign ans = (a + b) >> 1; //結果本意是將結果右移一位保留溢出的高位

根據i >> j規則,j為self-determined表達式不影響總表達式位寬,i為(a + b)位寬和左值ans均為16,因而總表達式位寬為16。a + b運算結束值即為16位,溢出被丟棄,所以達不成原本的目的。
修改為ans = (a + b + 0) >> 1;強行將位寬改為0(Integer)的32位,便可達成目的。
 

例2:三元運算符表達式位寬

reg [3:0] a,b,c;
reg [4:0] d;
initial begin
    a = 9; b = 8; c = 1;
    $display("%b", c ? (a&b) : d);
end

根據i ? j : k規則,i為self-determined表達式不影響總表達式位寬,max{L(j),L(k)}為d的5位,因而總表達式位寬為5,輸出01000
 

例3:綜合由語境決定位寬

reg [3:0] a;
reg [5:0] b;
reg [15:0] c;
initial begin
    a = 4'hf; b = 6'ha;
    $display("%h", a*b); // a*b 位寬為6
    c = a ** b;   // a ** b 位寬是L(a)為4,受左值c的影響位寬最終為16。 c獲得值16'hac61
    $display("%h", c);
    c = {a ** b}; // a ** b 位寬是L(a)為4,在{}內每一項均為self-determined表達式,最終位寬為4。 c獲得值4'h1再擴展成16'h1
    $display("%h", c);
end

最終輸出

16
ac61
1

 

2.表達式符號性 expression signedness

Verilog計算表達式前,需要確定表達式的符號性,規則如下:

  • 僅取決於RHS操作數,與LHS無關(與位寬確定有別,如assign a = b ? c : d;中LHS符號性與a自身無關)
  • 十進制數視為signed
  • 進制表示數視為unsigned,除非使用進制前加s特殊標明(4'd3無符號,4'sd3有符號)
  • 位選擇(不論是否選全)、位拼接(不論操作數)結果視為unsigned
  • 比較表達式結果視為unsigned
  • 實數強轉整形表達式結果視為signed
  • self-determined expression:符號性取決於其中操作數
  • context-determined expression:
    • 若存在操作數為real,則結果視為real
      • 若存在操作數為unsigned,則結果視為unsigned
      • 若所有操作數為signed,則結果視為signed
  • 變量本身是unsigned(不過存了01串罷了,不要因為reg [3:0]a = 2'sb11就認為變量a是signed),除非聲明時附加關鍵字signed

確定整個表達式的符號性后,便會向內層表達式傳遞符號性,直至各操作數。
$signed(exp)函數計算傳入的exp並返回與其值和位寬均相同的數據,將其符號性改為signed。可以看作屏蔽了外部表達式的符號性傳遞。

例:含三元運算符的表達式

testbench中使ALUop恆為3'd5A=4'b1101

input [3:0] A,
input [3:0] B,
input [2:0] ALUOp,
output [3:0] C

 

assgin C = (ALUOp == 3'd5) ? A >>> B : 4'sd0;

分析
在三元運算符(ALUop == 3'd5)屬於self-determined表達式,不會影響符號性判斷。因而看后半部分。4'sd0為符號數;A >>> B表達式中B為self-determined表達式(操作數),所以符號性僅看AA無符號,因而總表達式RHS無符號。

傳遞符號性后,A無符號數經算數位移值為4'b0110,再賦給C

 

assgin C = (ALUOp == 3'd5) ? $signed(A) >>> B : 4'sd0;

分析
$signed()使$signed(A)表達式有符號,則$signed(A) >>> B表達式有符號,則總表達式RHS有符號。

傳遞符號性后,$signed(A)A相當於被$signed()隔絕,仍無符號)被視為有符號數,算數位移后值為4'b1110

 

assgin C = (ALUOp == 3'd4) ? A + B :
           (ALUOp == 3'd5) ? $signed(A) >>> B : 4'sd0 ;

分析
嵌套式三元運算符的結構。A + B表達式無符號(其中中AB無符號),因而總表達式RHS無符號。

傳遞符號性:(ALUOp == 3'd5) ? $signed(A) >>> B : 4'sd0無符號;$signed(A) >>> B無符號;$signed(A)無符號(A$signed()保護),算數位移后值為4'b0110

 

assgin C = (ALUOp == 3'd4) ? A + B :
           (ALUOp == 3'd5) ? $signed($signed(A) >>> B) : 4'sd0 ;

分析
同上,總表達式RHS無符號。

傳遞符號性:(ALUOp == 3'd5) ? $signed(A) >>> B : 4'sd0無符號;$signed($signed(A) >>> B)無符號。$signed(A) >>> B被保護,因而$signed(A)仍視為有符號,算數位移后值為4'b1110


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM