Logical, relational, arithmetic, and shift operators in VHDL.
Operator Categories
VHDL has several families of operators, listed by increasing priority:
Priority
Category
Operators
1 (lowest)
Logical
and, or, nand, nor, xor, xnor
2
Relational
=, /=, <, <=, >, >=
3
Shift / rotation
shift_left, shift_right, rotate_left,
rotate_right
4
Additive
+, -, &
5
Multiplicative
*, /, mod, rem
6 (highest)
Miscellaneous
**, abs, not
Important: In VHDL, logical operators have the same priority. Use parentheses!
Logical Operators
Operate on std_logic, std_logic_vector, bit, boolean.
-- On std_logic (1 bit)w_y <= i_a AND i_b;w_y <= i_a OR i_b;w_y <= i_a XOR i_b;w_y <= NOT i_a;w_y <= i_a NAND i_b;w_y <= i_a NOR i_b;w_y <= i_a XNOR i_b;-- On std_logic_vector (bit-by-bit)w_mask <= w_data AND "11110000"; -- mask lower 4 bitsw_set <= w_data OR "00001111"; -- force lower 4 bits to 1
Priority - Warning!
-- INCORRECT : priority ambiguityw_y <= i_a AND i_b OR i_c; -- compile error!-- CORRECT : parentheses required when mixingw_y <= (i_a AND i_b) OR i_c;w_y <= i_a AND (i_b OR i_c);
Relational Operators
Return a boolean. Usable in if, when, etc.
if i_a = i_b then -- equalityif i_a /= i_b then -- not equalif r_counter < 100 then -- strictly less thanif r_counter >= c_MAX then -- greater than or equal
To compare unsigned/signed, use NUMERIC_STD. For std_logic_vector, comparison is lexicographic - use unsigned for arithmetic comparison.
Arithmetic Operators
Require IEEE.NUMERIC_STD for unsigned/signed types.
/, mod and rem exist in VHDL, but they should not be treated as free FPGA operations. Division or modulo by a variable value can infer an expensive circuit. For a fixed modulo counter, an explicit comparison is often better:
if r_count = 9 then r_count <= 0;else r_count <= r_count + 1;end if;
mod and rem produce the same result with positive integers:
7 mod 4 = 37 rem 4 = 3
The difference appears with negative values:
A mod B takes the sign of B;
A rem B takes the sign of A.
Example:
(-7) mod 4 = 1(-7) rem 4 = -3
For synthesizable RTL, keep this practical rule: on positive counters and indexes, mod is usually what you want; for efficient hardware, replace it with a comparison when the modulo is known.
Shifts and Rotations
signal w_uns : unsigned(7 downto 0);signal w_sig : signed(7 downto 0);-- Logical shift (fill with '0')w_uns <= shift_left(w_uns, 2); -- left shift by 2 (×4)w_uns <= shift_right(w_uns, 1); -- right shift by 1 (÷2)-- Arithmetic shift on signed: shift_right propagates the sign bitw_sig <= shift_right(w_sig, 1);-- Rotationw_uns <= rotate_left(w_uns, 3);w_uns <= rotate_right(w_uns, 3);
The operators sll, srl, sla, sra, rol and ror still exist in VHDL. In practice, for modern RTL with numeric_std, prefer the functions shift_left, shift_right, rotate_left and rotate_right on unsigned and signed values: the intent is clearer, overloads are easier to control, and the shift direction does not depend on a less explicit operator form.
For an unsigned, shift_right fills the left side with 0. For a signed, shift_right preserves the sign by copying the most significant bit. That is the important difference between logical and arithmetic shift.