緣起於p1課下alu算數位移設計。查了好多資料,最后發現還是主要在翻譯官方文檔。浪費了超多時間啊,感覺還是沒搞透,還是先以應用為導向放一放,且用且歸納
1.表達式位寬 expression bit length
身為硬件描述語言,Verilog表達式運算過程中必然要嚴肅考慮位寬問題
表達式的位寬由式中操作數和語境決定
表達式按位寬確定方式分為兩類:
- self-determined expression
位寬僅有表達式自身確定,不會受語境影響也不影響語境中其他表達式(在復合表達式中某些位置上的子表達式,如i>>j
中的表達式j
、i?j:k
中的表達式i
)。 - context-determined expression
位寬由表達式本身和其所屬表達式(父子表達式)共同決定(如阻塞賦值操作的RHS位寬由其自身和LHS被賦值變量的位寬決定)。
下表中i
,j
,k
表示"單操作數表達式",L(i)
表示表達式i的位寬

注意: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
例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
- 若存在操作數為real,則結果視為real
- 變量本身是unsigned(不過存了01串罷了,不要因為
reg [3:0]a = 2'sb11
就認為變量a是signed),除非聲明時附加關鍵字signed
確定整個表達式的符號性后,便會向內層表達式傳遞符號性,直至各操作數。
$signed(exp)
函數計算傳入的exp
並返回與其值和位寬均相同的數據,將其符號性改為signed。可以看作屏蔽了外部表達式的符號性傳遞。
例:含三元運算符的表達式
testbench中使ALUop恆為
3'd5
,A=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表達式(操作數),所以符號性僅看A
。A
無符號,因而總表達式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
表達式無符號(其中中A
、B
無符號),因而總表達式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
。