**Lesson 05: Expressions, Operands, and Operators**

## Expressions

Arithmetic and logical operators are used to build expressions. Expressions perform operations on one or more operands, the operands being vectored or scalared nets, registers, bit-selects, part-selects, function calls, or concatenations thereof.

[operand1] <operator> [operand2]

## Operators

- Special Operators
- Arithmetic Operators
- Unary (Sign) Operators
- Bitwise Operators
- Boolean Logical Operators
- Reduction Operators
- Shift Operators
- Relational Operators
- Assignments

- Special Operators
- Arithmetic Operators
- Unary (Sign) Operators
- Bitwise Operators
- Boolean Logical Operators
- Reduction Operators
- Shift Operators
- Relational Operators
- Assignments

## Special Operators

**Special Operators**

Operator | Description | Example | |
---|---|---|---|

[ ] | Bit-select or part-select | ||

( ) | Parentheses | ||

? : | Conditional | sel? m : n | if sel is true, return m; else return n |

{ } | Concatenation | {m,n} | concatenate m to n, creating a larger vector |

{{ }} | Replication | {n{ }} | replicate inner concatenation n-times |

**Bit-Selects**

A bit-select is the selection of a single bit from a wire, register, or parameter vector. The value of the expression in brackets ([ ]) selects the bit you want from the vector. The selected bit must be within the declared range of the vector. The following simple example shows a bit-select with an expression.

wire [7:0] a, b, c;

assign c[0] = a [0] & b[0];

**Part-Selects**

A part-select is the selection of a group of bits from a wire, register, or parameter vector. The part-select expression must be constant-valued in the Verilog language, unlike the bit-select operator. If a variable is declared with ascending indices or descending indices, the part-select (when applied to that variable) must be in the same order.

You can also write the expression in the example of the wire operands as shown in the example below.

assign c[7:0] = a[7:0] & b[7:0];

**Conditional Operator**

The conditional operator has three operands separated by two operators in the following format:

*(cond_expr)* **?** *true_expr* **:** *false_expr* ;

The *true_expr* or the *false_expr* is evaluated and used as a result depending on whether *cond_expr* evaluates to true or false.

**Concatenation Operator**

Concatenation combines one or more expressions to form a larger vector. In the Verilog language, you indicate concatenation by listing all expressions to be concatenated, separated by commas, in curly braces ({ }). Any expression except an unsized constant is allowed in a concatenation. For example, the concatenation {1'b1, 1'b0, 1'b0} yields the value 3'b100.

Unsized constant numbers are not allowed in concatenations because the size of each operand in the concatenation is needed to calculate the complete size of the concatenation.

**Replicate Operator**

{ 3{2'b10} } = 6'b101010

## Examples of concatnation operators

*// A = 1'b1; B = 2'b00; C = 2'b10; D = 3'b110;*

Y = {B, C}; *// Result Y is 4'b0010*

Y = {A, B, C, D, 3'b001}; *// Result Y is 11'b10010110001*

Y = {A, B[0], C[1]}; *// Result Y is 3'b101*

Use concatenation to change A[15:0] to swap the upper 8-bits with the lower 8-bits, giving the value to vector W.

W = { Z[7:0], Z[15:8] };

## Arithmetic Operators

**Arithmetic Operators**

Arithmetic operators perform simple arithmetic on operands. The Verilog arithmetic operators follow.

Operator | Description | Example | |
---|---|---|---|

+ | Binary addition | m + n | add n to m |

- | Binary subtraction | m - n | subtract n from m |

* | Binary multiplication | m * n | multiply m by n |

/ | Binary division | m / n | divide m by n |

% | Modulus (remainder) | m % n | modulus of m / n (remainder of m / n) |

** | Power (exponent) | m ** n | m to the power of n (new in Verilog-2001) |

**Arithmetic Operation Rules**

For most operators (there are exceptions) all operands in the expression are used to determine how the operation is performed:

- If any operand is real, then floating-point arithmetic will be performed.
- If any operand is unsigned, then unsigned arithmetic will be performed.
- If all operands are signed, then signed arithmetic will be performed.
- An operand can be "cast" to signed or unsigned using the $signed and $unsigned system functions (added in Verilog-2001).

## Binary operators take two operands

A = 4'b0011; B = 4'b0100; *// A and B are register vectors*

D = 6; E =4; F = 2; *// D, E and F are integer*

A + B *// Add A and B. Evaluates to 4'b0111*

B - A *// Subtract A from B. Evaluates to 4'b0001*

A * B *// Multiply A and B. Evaluates to 4'b1100*

D / E *// Divide D by E. Evaluates to 1. Truncates any fractional part.*

F = E ** F; *// E to the power F, yields 16*

## Examples of modulus operators

Modulus operators produce the remainder from the division of two numbers. They operate similarly to the modulus operator in the C programming language.

13 % 3 *// Evaluates to 1*

16 % 4 *// Evaluates to 0*

-7 % 2 *// Evaluates to -1, take sign of the first operand*

7 % -2 *// Evaluates to +1, take sign of the first operand*

## Unary (Sign) Operators

**Unary (Sign) Operators**

The operators + and - can also work as *unary* operators. They are used to specify the positive or negative signs of the operand. Unary + (positive) or - (negative) operators have higher precedence than the binary + (addition) or - (subtraction) operators.

Operator | Description | Example | |
---|---|---|---|

+ | Positive number | +m | positive m |

- | Negative number | -m | negative m (2's complement) |

-6 *// Negative 6*

+3 *// Positive 3*

## Negative numbers

Negative numbers are represented as 2's complement internally in Verilog. It is advisable to use negative numbers only of the integer or real in expressions. You should avoid negative numbers of the type <sss>'<base><nnn> in expressions because they are converted to unsigned 2's complement numbers and hence yield unexpected results.

*// Advisable to use integer or real numbers*

-10 / 5 *// Evaluates to -2**// Do not use number of type <sss>`<base><nnn>*

-'d10 / 5 *// Is equivalent (2's complement of 10) / 5 = (2^32 - 10)/5*

*// when 32 is the default machine word width.*

*// The evaluates to an incorrect and unexpected result.*

## Bitwise Operators

**Bitwise Operators**

Bitwise operators act on the operand bit by bit. The Verilog bitwise operators follow.

Operator | Description | Example | |
---|---|---|---|

~ | Bitwise not | ~m | invert each bit of m |

& | Bitwise and | m & n | AND each bit of m with each bit of n |

| | Bitwise or | m | n | OR each bit of m with each bit of n |

^ | Bitwise xor | m ^ n | exclusive-or each bit of m with each bit of n |

^~ or ~^ | Bitwise xnor | m ~^ n | exclusive-nor each bit of m with each bit of n |

Each bit is operated, the result is the size of the largest operand and the smaller operand is left extended with zeros to the size of the bigger operand.

## Boolean Logical Operators

**Boolean Logical Operators**

Logical operators generate a 1 or a 0, according to whether an expression evaluates to TRUE (1) or FALSE (0). The Verilog logical operators follow.

Operator | Description | Example | |
---|---|---|---|

! | Logical NOT | !m | is m not true? (1-bit True/False result) |

&& | Logical AND | m && n | are both m and n true? (1-bit True/False result) |

|| | Logical OR | m || n | are either m or n true? (1-bit True/False result) |

- Logical operators always evaluate to a 1-bit value. 0 (false), 1 (true), or x (ambiguous).
- If an operand is not equal to zero, it is equivalent to a logical 1 (true condition).

If an operand is equal to zero, it is equivalent to a logical 0 (false condition).

If any operand bit is x or z, it is equivalent to x (ambiguous condition) and is normally treated by simulators as a false condition. - Logical operators take variables or expressions as operands.

The use of parentheses to group logical operations is highly recommended to improve readability. Also, the user does not have to remember the precedence of operators.

## Examples of boolean logical operators

*// Logical operations*

A = 3; B = 0;

A && B *// Evaluates to 0. Equivalent to (logical-1 && logical-0)*

A || B *// Evaluates to 1. Equivalent to (logical-1 || logical-0)*

!A *// Evaluates to 0. Equivalent to not(logical-1)*

!B *// Evaluates to 1. Equivalent to not(logical-0)**// Unknowns*

A = 2'b0x; B = 2'b10;

A && B *// Evaluates to x. Equivalent to (x && logical-1)*

// Expressions

(a == 2) && (b == 3) *// Evaluates to 1 if both (a == 2) and (b == 3) are true*

*// Evaluates to 0 if either is false*

## Logical operator vs bitwise operators

It is important to distinguish bitwise operators ~, &, and | from logical operators !, &&, ||. Logical operators always yield a logical value 0, 1, x, whereas bitwise operators yield a bit-by-bit value. Logical opertors perform a logical operation, not a bit-by-bit operation.

*// X = 4'b1010, Y = 4'b0000*

X | Y *// Bitwise operation. Result is 4'b1010*

X || Y *// Logical operation. Equivalent to 1 || 0. Result is 1*

## Reduction Operators

**Reduction Operators**

Reduction operators take a single vectored (multiple bit) operand, performs the appropriate bit-wise reduction on all bits of the operand, and returns a single bit result. The Verilog reduction operators follow:

Operator | Description | Example (m = 5'b10101) | ||
---|---|---|---|---|

& | Reduction AND | & m | AND all bit in m together (1-bit result) | => 1'b0 |

| | Reduction OR | | m | OR all bit in m together (1-bit result) | => 1'b1 |

~& | Reduction NAND | ~& m | NAND all bit in m together (1-bit result) | => 1'b1 |

~| | Reduction NOR | ~| m | NOR all bit in m together (1-bit result) | => 1'b0 |

^ | Reduction XOR | ^ m | XOR all bit in m together (1-bit result) | => 1'b1 |

~^ or ^~ | Reduction XNOR | ~^ m | XNOR all bit in m together (1-bit result) | => 1'b0 |

Verilog has a **special syntax restriction** on using both **reduction** and **bitwise** operators within the same expression — even though the reduction operator has higher precedence, parentheses must be used to avoid confusion with a logical operator.

a & **(**&b**)**

a | **(**|b**)**

## Examples of reduction operators 1

For example, the four bits of **a** are **and**ed together to produce **y1**.

module Reduction (a, y1, y2, y3, y4, y5, y6); input [3:0] a; output y1, y2, y3, y4, y5, y6; reg y1, y2, y3, y4, y5, y6; always @(a) begin y1 = &a; //reduction and : y1 = a[0] & a[1] & a[2] & a[3] y2 = |a; //reduction or : y2 = a[0] | a[1] | a[2] | a[3] y3 = ^a; //reduction xor : y3 = a[0] ^ a[1] ^ a[2] ^ a[3] y4 = ~&a; //reduction nand: y4 = a[0] ~& a[1] ~& a[2] ~& a[3] y5 = ~|a; //reduction nor : y5 = a[0] ~| a[1] ~| a[2] ~| a[3] y6 = ~^a; //reduction xnor: y6 = a[0] ~^ a[1] ~^ a[2] ~^ a[3] end endmodule

## Shift Operators

**Shift Operators**

A shift operator takes two operands and shifts the value of the first operand right or left by the number of bits given by the second operand.

The Verilog shift operators follow.

Operator | Description | Example | |
---|---|---|---|

<< | Shift left | m << n | shift m left n-times and fill with zeros |

>> | Shift right | m >> n | shift m right n-times and fill with zeros |

<<< | Arithmetic shift left | m <<< n | shift m left n-times, filling with 0 (new in Verilog-2001) |

>>> | Arithmetic shift right | m >>> n | shift m right n-times; fill with values of sign-bit if the expression is signed, otherwise fill with 0 (Verilog-2001) |

The logical shift will insert 0's to the vacated bits on the left or right. On the other hand, arithmetic shift right (>>>) will sign extend, padding the left side with the value of the MSb (sign bit) when shifting to the right. Left shift is the same between both logical (<<) and arithmetic (<<<), since zeros are inserted in both cases.

## Examples of shift operators

*// X = 4'b1100*

X >> 1 *// Result is 4'b0110. Shift right 1 bit. 0 filled in MSb position.*

X << 1 *// Result is 4'b1000. Shift left 1 bit. 0 filled in LSb position.*

X << 2 *// Result is 4'b0000. Shift left 2 bit.*X <<< 1

*// Result is 4'b1000.*

X >>> 1

*// Result is 4'b1110.*

X >>> 3

*// Result is 4'b1111.*

X >>> 0

*// Result is 4'b1100.*

integer a, b, c;

*// Signed data type*

a = 0;

b = -10;

*// 11111...10110 binary*

c = a + (b >>> 3);

*// Results in -2 decimal, due to arithmetic shift*

## Relational Operators

**Equality and Relational Operators (return X if an operand has X or Z)**

Relational operators compare two operands and results a 1 bit scalar boolean value. A true comparison evaluates to 1; a false comparison evaluates to 0. All comparisons assume unsigned quantities. The circuitry synthesized for relational operators is a bit-wise comparator whose size is based on the sizes of the two operands.

The Verilog relational operators follow.

Operator | Description | Example | |
---|---|---|---|

== | Logical equality | m == n | is m equal to n? (1-bit True/False result) |

!= | Logical inequality | m != n | is m not equal to n? (1-bit True/False result) |

> | Logical greater than | m > n | is m greater than n? (1-bit True/False result) |

>= | Logical greater than or equal to | m >= n | is m greater than or equal to n? (1-bit True/False result) |

< | Logical less than | m < n | is m less than n? (1-bit True/False result) |

<= | Logical less than or equal to | m <= n | is m less than or equal to n? (1-bit True/False result) |

If there are any unknown(x) or high-impendance (z) bits in the operands, the expression takes an unknown value (x). These operators function exactly as the corresponding operators in the C programming language.

**Identity Operators (Compare Logic Values 0, 1, x, and z)**

Operator | Description | Example | |
---|---|---|---|

=== | m === n | is m identical to n? (1-bit True/False result) | |

!=== | m !== n | is m not identical to n? (1-bit True/False result) |

It is important to note the difference between the logical equality operators (==, !=) and identity operators (===, !==).

- == tests logical equality (tests for 1 and 0, all other will result in x)
- === tests 4-state logical equality (tests for 1, 0, z and x)

== can be synthesized into a hardware (xor gate), but === can not be synthesized as x is not a valid logic level in digital, it is in fact having voltages in between 0 and 1. And z is not itself any logic, it shows disconnection of the circuit.

## Assignments

**Assignments**

The assignment is the basic mechanism for getting values into nets and registers. An assignment consists of two parts, a left-hand side and a right-hand side, separated by the equal sign (**=**). The right-hand side can be any expression that evaluates a value. The left-hand side indicates the variable that the right-hand side is to be assigned to. The left-hand side can take one of the following forms, depending on whether the assignment is a continuous assignment or a procedural assignment:

Legal Left-hand Side Forms in Assignment Statements | |
---|---|

Statement | Left-hand Side |

Continuous Assignment | Net (vector or scalar) Constant bit-select of a vector net Constant part-select of a vector net Constant word select of memory |

Procedural Assignment | Register (vector or scalar) Bit-select of a vector register Constant part-select of a vector register Memory element Concatenation of any of the above four items |

## Continuous Assignment

**Continuous Assignment (Dataflow Modeling)**

All assignment statements (with keyword assign) outside of an **always** block are called **continuous assignments**. They are always **active**, concurrent, occur simultaneously, and are not sequential. The output of the operation on the *Right-Hand Side* (RHS) of the = symbol is continuously assigned to the variable on the *Left-Hand Side* (LHS)

*// assign net = expression;***assign** a = b & c;

LHS must be a scalar or vector of **nets**, and assignment must be performed **outside** procedure statements.

You can read "Lesson 09: Dataflow Modeling" for detailed information about the continuous assignment.

## Procedural Assignment

Procedural assignments occur within procedures such as always, initial, task, and function and are used to place values onto variables. LHS must be a scalar or vector of **registers**, and only active (evaluated and loaded) when control is transferred to it. After that, the value of the register remains until it is reassigned by another procedural assignment.

There are two types of procedural assignments:

**Blocking Assignment**

Blocking assignments are executed in the order specified in the sequential block, i.e. a blocking assignment waits for previous blocking assignment of the same time to complete before executing.

*// register = expression*

b = a; *// assign a value to b, now b become to a*

c = b; *// assign b (value a) to c. The final results: c = a, b = a.*

**Non-Blocking Assignment**

Nonblocking assignments are executed concurrently within the sequential blocks, i.e. a nonblocking assignment executes without waiting for other nonblocking assignments of occurring at the same time to complete

*// register <= expression*

b <= a; *// assign a to b*

c <= b; *// assign old b to c. The final result: c = b, b = a*

## Procedural Continuous Assignments

Procedural Continuous Assignments also called Quasi-Continuous Assignments. Procedural statements allow expressions to be continuously assigned to nets or variables and are of two types.

- assign ... deassign
- force ... release

**assign ... deassign**

Similar to procedural assignment, however, the quasi-continuous assignment becomes **active** and **stays active** from the point of the assignment until it is **deactivated** through deassignment. When active, quasi-continuous assignment **overrides** any procedural assignment to the register.

**begin**

...

assign register = expressions; *// Activate quasi-continuous*

...

register = expression2; *// No effect. Overridden by active quasi-continuous*

...

assign register = expression3; *// Becomes active and overrides previous quasi-continuous*

...

deassign register; *// Disable quasi-continuous*

...

register = expression4; *// Executed*

...**end**

**force ... release**

These are similar to the **assign - deassign** statements but can also be applied to nets and variables. The LHS can be a bit-select of a net, part-select of a net, variable or a net but cannot be the reference to an array and bit/part select of a variable. The force statment will override all other assignments made to the variable until it is released using the release keyword.

reg o, a, b; initial begin force o = a & b; ... release o; end

Procedural continuous assignments place the assign inside an always/initial block. It is **not** synthesizable and should not be used. It is used for very special modeling cases.