Operators
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 bits
w_set <= w_data OR "00001111"; -- force lower 4 bits to 1Priority - Warning!
-- INCORRECT : priority ambiguity
w_y <= i_a AND i_b OR i_c; -- compile error!
-- CORRECT : parentheses required when mixing
w_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 -- equality
if i_a /= i_b then -- not equal
if r_counter < 100 then -- strictly less than
if r_counter >= c_MAX then -- greater than or equalTo compare
unsigned/signed, useNUMERIC_STD. Forstd_logic_vector, comparison is lexicographic - useunsignedfor arithmetic comparison.
Arithmetic Operators
Require IEEE.NUMERIC_STD for unsigned/signed types.
library IEEE;
use IEEE.NUMERIC_STD.ALL;
signal r_a, r_b : unsigned(7 downto 0);
signal r_sum : unsigned(8 downto 0); -- +1 bit to avoid overflow
-- Addition and subtraction
r_sum <= ('0' & r_a) + ('0' & r_b); -- sign extension
r_a <= r_a + 1; -- increment
r_a <= r_a - r_b;
-- Multiplication (note: doubles the width)
signal r_prod : unsigned(15 downto 0);
r_prod <= r_a * r_b; -- 8 × 8 = 16 bitsDivision, mod and rem
/, 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 = 3
7 rem 4 = 3The difference appears with negative values:
A mod Btakes the sign ofB;A rem Btakes the sign ofA.
Example:
(-7) mod 4 = 1
(-7) rem 4 = -3For 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 bit
w_sig <= shift_right(w_sig, 1);
-- Rotation
w_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.
Concatenation Operator &
Assemble bit vectors together.
signal w_byte : std_logic_vector(7 downto 0);
signal w_hi : std_logic_vector(3 downto 0) := x"A";
signal w_lo : std_logic_vector(3 downto 0) := x"5";
signal w_bit : std_logic := '1';
w_byte <= w_hi & w_lo; -- "10100101" = 0xA5
w_byte <= w_bit & "0110011"; -- insert a bit
w_byte <= "0000" & w_lo; -- zero extensionCommon Operations Summary
-- Test a bit
if w_flags(3) = '1' then ...
-- Mask bits
w_result <= w_data AND x"0F"; -- keep lower 4 bits
-- Truncate / extend
w_16bit <= x"00" & w_8bit; -- zero-extend 8→16 bits
w_16bit <= (15 downto 8 => w_8bit(7)) & w_8bit; -- sign-extend 8→16 bits
-- Invert all bits
w_inv <= NOT w_data;
-- Count with overflow
r_counter <= r_counter + 1; -- naturally overflows to 0 (unsigned type)📝 Test your knowledge - Chapter quiz