Expressions
An expression is composed of operators and operands, and its purpose is to obtain a calculation result according to the meaning of the operators. Expressions can be used anywhere a value appears. For example:
Example
address[9:0] + 10'b1 ; // address accumulation
flag1 && flag2 ; // logical AND operation
Operands
Operands can be of any data type, but some specific syntax structures require operands of a specific type.
Operands can be constants, integers, real numbers, nets, registers, time, bit-selects, part-selects, memories, function calls, etc.
Example
// real number
real a, b, c;
c = a + b ;
// register
reg [3:0] cprmu_1, cprmu_2 ;
always @(posedge clk) begin
cprmu_2 = cprmu_1 ^ cprmu_2 ;
end
// function
reg flag1 ;
flag = calculate_result(A, B);
// illegal operand
reg [3:0] res;
wire [3:0] temp;
always@ (*)begin
res = cprmu_2 – cprmu_1 ;
//temp = cprmu_2 – cprmu_1 ; //illegal, the assignment target in an always block cannot be wire type
end
endmodule
Operators
Verilog provides about 9 types of operators: arithmetic, relational, equality, logical, bitwise, reduction, shift, concatenation, and conditional operators.
Most operators are similar to those in C. Among operators of the same type, except for the conditional operator which associates from right to left, all other operators associate from left to right. Expressions inside parentheses are evaluated first. For example, the two forms in each group below are equivalent.
//自右向左关联,两种写法等价 A+B-C ; (A+B)-C ; //自右向左关联,两种写法等价,结果为 B、D 或 F A ? B : C ? D : F ; A ? B : (C ? D : F) ; //自右向左关联,两种写法不等价 (A ? B : C) ? D : F ; //结果 D 或 F A ? B : C ? D : F ; //结果为 B、D 或 F
Different operators have different precedence levels. The following table lists the operators in order from high to low precedence. When there are no parentheses, Verilog evaluates expressions according to operator precedence. To avoid confusion caused by operator precedence, it is recommended to use parentheses to separate expressions when precedence is uncertain.
| Operator | Symbol | Precedence |
|---|---|---|
| Unary operations | + - ! ~ | Highest |
| Multiplication, division, modulus | * / % | |
| Addition, subtraction | + - | |
| Shift | << >> | |
| Relational | < <= > >= | |
| Equality | == != === !=== | |
| Reduction | & ~& | |
| ^ ~^ | ||
| | ~| | ||
| Logical | && | |
| || | ||
| Conditional | ?: | Lowest |
Arithmetic Operators
Arithmetic operators include unary operators and binary operators.
Binary operators perform arithmetic operations on 2 operands, including multiplication (*), division (/), addition (+), subtraction (-), exponentiation (**), and modulus (%).
Example
reg [4:0] c ;
a = 4'b0010; // a has a value of 2
b = 4'b1001; // b has a value of 9
c = a+b; // result is c=b'b1011
c = b/a; // result is c=4, integer division
If any bit of an operand is X, the calculation result will also be all X. For example:
Example
c = a+b ; // result is c=4'bxxxx
When declaring variables, the width of the variable should be reasonably declared according to the operator acting on it, so as not to overflow the result. In the above example, the two variables being added are 4 bits wide, so the result register variable should be at least 5 bits wide. Otherwise, the high bits will be truncated, causing loss of the high bits of the result. For unsigned multiplication, the result variable width should be the sum of the widths of the two operands.
Example
reg [1:0] mulb;
reg [5:0] res ;
mula = 4'he ;
mulb = 2'h3 ;
res = mula * mulb ; // result is res=6'h2a, no bits lost in the data result
+ and - can also be used as unary operators to indicate the sign of an operand. Such operators have the highest precedence.
-4 //表示负4 +3 //表示正3
To represent a negative number, you can directly add a minus sign before a decimal number-, or you can specify a width. Because negative numbers are represented in two's complement, representing a negative number without specifying a width will cause the compiler to automatically assign a width during conversion, leading to unexpected results. For example:
Example
mulb = 2 ;
res = mula * mulb ; // calculation result is res=-6'd8, i.e. res=6'h38, normal
res = mula * (-'d4) ; // (4 to the 32nd power - 4) * 2, abnormal result
Relational Operators
Relational operators are greater than (>), less than (<), greater than or equal to (>=), less than or equal to (<=).
The normal result of relational operators has 2 possibilities: true (1) or false (0).
If any bit of an operand is x or z, the result of the relational expression is x.
Example
B = 3 ;
X = 3'b1xx ;
A > B // true
A <= B // false
A >= Z // X, uncertain
Equality Operators
Equality operators include logical equality (==), logical inequality (!=), case equality (===), and case inequality (!==).
The normal result of equality operators has 2 possibilities: true (1) or false (0).
Logical equality/inequality operators cannot compare x or z; when an operand contains an x or z, the result is an unknown value.
In case equality comparison, if bitwise comparison has the same x or z, the returned result can also be 1; that is, case equality can compare x or z. Therefore, the result of case equality never contains x. Examples are as follows:
Example
B = 8'h04 ;
C = 4'bxxxx ;
D = 4'hx ;
A == B // true
A == (B + 1) // false
A == C // X, uncertain
A === C // false, returns 0
C === D // true, returns 1
Logical Operators
There are mainly 3 logical operators: && (logical AND), || (logical OR), ! (logical NOT).
The result of a logical operator is a 1-bit value, where 0 represents false, 1 represents true, and x represents unknown.
If an operand is non-zero, it is equivalent to logic 1; if an operand is equal to 0, it is equivalent to logic 0. If any bit of it is x or z, it is equivalent to x.
If any operand contains x, the result of a logical operator is not necessarily x.
The operands of logical operators can be variables or expressions. For example:
Example
B = 0;
C = 2'b1x ;
A && B // false
A || B // true
! A // false
! B // true
A && C // X, uncertain
A || C // true, because A is true
(A==2) && (! B) // true; here the first operand is an expression
Bitwise Operators
Bitwise operators include: bitwise NOT (~), AND (&), OR (|), XOR (^), XNOR (~^).
Bitwise operators perform bitwise operations on each bit of the 2 operands.
If the two operands have unequal widths, the shorter operand is zero-extended on the left.
The NOT operator has only one operand, and it inverts each bit of the operand.
The following figure gives the logic rules for bitwise operators.
| & (AND) | 0 | 1 | x | || (OR) | 0 | 1 | x | |
|---|---|---|---|---|---|---|---|---|
| 0 | 0 | 0 | 0 | 0 | 0 | 1 | x | |
| 1 | 0 | 1 | x | 1 | 1 | 1 | 1 | |
| x | 0 | x | x | x | x | 1 | x |
| ^ (XOR) | 0 | 1 | x | ~^ (XNOR) | 0 | 1 | x | |
|---|---|---|---|---|---|---|---|---|
| 0 | 0 | 1 | x | 0 | 1 | 0 | x | |
| 1 | 1 | 0 | x | 1 | 0 | 1 | x | |
| x | x | x | x | x | x | x | x |
Example
B = 4'b1001 ;
C = 4'bx010 ;
~A //4'b1010
A & B //4'b0001
A | B //4'b1101
A^B //4'b1100
A ~^ B //4'b0011
B | C //4'b1011
B&C //4'bx000
Reduction Operators
Reduction operators include: reduction AND (&), reduction NAND (~&), reduction OR (|), reduction NOR (~|), reduction XOR (^), reduction XNOR (~^).
A reduction operator has only one operand. It operates on each bit of the vector operand and finally produces a 1-bit result.
Logical operators, bitwise operators, and reduction operators use the same symbols, so they are sometimes easy to confuse. The key to distinguishing these operators is to clarify the number of operands and the rules for calculating the result.
A = 4'b1010 ; &A ; //结果为 1 & 0 & 1 & 0 = 1'b0,可用来判断变量A是否全1 ~|A ; //结果为 ~(1 | 0 | 1 | 0) = 1'b0, 可用来判断变量A是否为全0 ^A ; //结果为 1 ^ 0 ^ 1 ^ 0 = 1'b0
Shift Operators
Shift operators include left shift (<<), right shift (>>), arithmetic left shift (<<<), arithmetic right shift (>>>).
Shift operators are binary operators. The two operands represent respectively the vector signal to be shifted (left of the operator) and the number of bits to shift (right of the operator).
For arithmetic left shift and logical left shift, the low bits on the right are filled with 0.
For logical right shift, the high bits on the left are filled with 0; for arithmetic right shift, the high bits on the left are filled with the sign bit to ensure the correctness of the value after scaling.
Example
B = 4'b0010 ;
A = A >> 2 ; // result is 4'b0011
A = A << 1; // result is 4'b1000
A = A <<< 1 ; // result is 4'b1000
C = B + (A>>>2); // result is 2 + (-4/4) = 1, 4'b0001
Concatenation Operator
Concatenation operator uses curly braces{,}to represent, used to concatenate multiple operands (vectors) into a new operand (vector), with signals separated by commas.
The operands of the concatenation operator must specify bit width; constants also need to specify bit width. For example:
Example
B = 1'b1 ;
Y1 = {B, A[3:2], A[0], 4'h3 }; //The result is Y1='b1100_0011
Y2 = {4{B}, 3'd4}; //The result is Y2=7'b111_1100
Y3 = {32{1'b0}}; //The result is Y3=32h0, commonly used as an initial value assignment matching bit width during register initialization
Conditional Operator
A conditional expression has 3 operands, with the structure described as follows:
condition_expression ? true_expression : false_expression
During evaluation, if condition_expression is true (logic value 1), the operation result is true_expression; if condition_expression is false (logic value 0), the evaluation result is false_expression.
assign hsel = (addr[9:8] == 2'b0) ? hsel_p1 : hsel_p2 ; //当信号 addr 高 2bit 为 0 时,hsel 赋值为 hsel_p1; 否则,将 hsel_p2 赋值给 hsel。
In fact, a conditional expression is similar to a 2-way (or multi-way) selector, and its description can be completely replaced by if-else statements.
Of course, conditional operators can also be nested to implement multi-selection logic. For example:
Example
(addr[9:8] == 2'b01) ? hsel_p2 :
(addr[9:8] == 2'b10) ? hsel_p3 :
(addr[9:8] == 2'b11) ? hsel_p4 ;