Core VHDL syntax¶
Lexical essentials¶
VHDL is case-insensitive. Clock, CLOCK, and clock denote the same basic identifier. Comments begin with two hyphens.
Readable formatting is still important even though capitalization is not semantic.
Declarations¶
Every object has a type.
constant CLOCK_HZ : positive := 100_000_000;
signal enabled : std_logic := '0';
signal count : unsigned(7 downto 0) := (others => '0');
variable result : natural;
| Object | Meaning |
|---|---|
| Constant | Fixed after elaboration |
| Signal | A time-varying connection with one or more drivers |
| Variable | Updates immediately inside its sequential scope |
| File | External stream, normally a testbench feature |
| Alias | Another name or slice view for an existing item |
Signals versus variables¶
Signal assignment uses <=. The new value is scheduled and becomes visible after the process suspends, or after its specified delay.
Variable assignment uses :=. The new value is immediately visible to the following sequential statement.
process(clk_i)
variable incremented : unsigned(7 downto 0);
begin
if rising_edge(clk_i) then
incremented := count_q + 1; -- immediate local calculation
count_q <= incremented; -- schedules register output
end if;
end process;
Classic signal-assignment surprise
Two assignments to the same signal in one process do not make a two-step calculation. The last assignment for the same simulation time wins. Use a variable for intermediate arithmetic or express the final value directly.
Literals and aggregates¶
bit_s <= '1';
vector_s <= "1010";
hex_s <= x"AF";
count_s <= 16#2A#;
all_zero <= (others => '0');
pair_s <= (7 => '1', 0 => '1', others => '0');
Time literals require a space: 10 ns, 2 us, 1 ms.
Operators¶
From common high precedence to low:
| Family | Examples |
|---|---|
| Miscellaneous | abs, not, exponentiation |
| Multiplying | *, /, mod, rem |
| Sign | unary +, unary - |
| Adding | +, -, concatenation & |
| Shift/rotate | sll, srl, rol |
| Relational | =, /=, <, >= |
| Logical | and, or, xor, xnor |
Use parentheses when the intended hardware is not instantly obvious.
Conditional concurrent assignment¶
This describes a priority selection.
Selected concurrent assignment¶
This cleanly expresses a mux without intended priority.
If statements¶
if is sequential, so it belongs inside a process, function, or procedure.
if value_i = 0 then
zero_o <= '1';
elsif value_i > threshold_i then
high_o <= '1';
else
zero_o <= '0';
high_o <= '0';
end if;
In combinational logic, assign every output on every path. In clocked logic, a missing assignment normally means the register holds its value.
Case statements¶
Every possible selector value must be covered.
case opcode_i is
when "00" => result_o <= a_i + b_i;
when "01" => result_o <= a_i - b_i;
when "10" => result_o <= a_i and b_i;
when others => result_o <= (others => '0');
end case;
others also handles meta-values such as X when the selector uses std_logic.
Loops¶
Synthesis unrolls statically bounded loops into hardware.
The loop variable is declared implicitly and exists only inside the loop.
Use a while loop mainly in testbenches unless the synthesizer can prove a static bound.
Attributes¶
Attributes make code independent of exact array bounds:
| Attribute | Meaning |
|---|---|
'left, 'right |
Leftmost and rightmost index |
'high, 'low |
Highest and lowest index |
'range, 'reverse_range |
Index range |
'length |
Number of elements |
'event |
Signal changed in current cycle |
'image |
Value converted to text |
'value |
Text converted to a value |
'pos, 'val |
Enumeration position conversion |
result_o <= resize(a_i, result_o'length) + resize(b_i, result_o'length);
for index in data_i'range loop
-- Works for ascending or descending declared ranges.
end loop;
Generate statements¶
Generate replicates or conditionally includes hardware at elaboration time.
gen_bits : for bit_index in data_i'range generate
result_o(bit_index) <= data_i(bit_index) and enable_i;
end generate;
gen_parity : if G_INCLUDE_PARITY generate
parity_o <= xor data_i;
end generate;
Generics used in generate conditions are static: they configure the synthesized circuit, not runtime behavior.
Assertions¶
Assertions are executable requirements.
Severity levels are note, warning, error, and failure. Simulator stop behavior can be configured, so test scripts should also check the tool exit status and logs.
VHDL-2008 features used here¶
process(all)automatically forms a complete sensitivity list.std.env.finishends a successful test cleanly.- Output ports can be read inside their architecture.
- Better generic packages, external names, and matching operators exist for advanced use.
Compile examples with xvhdl -2008, and set each Vivado source file type to VHDL 2008 when using the GUI.