The Process Block
The process block: sensitivity list, sequential statements, and combinational/sequential patterns.
What is a Process?
The process is the only place in VHDL where instructions execute sequentially (like a traditional programming language).
-- General structure
process(sensitivity_list)
-- local declarations (variables)
begin
-- sequential statements
end process;A process is a concurrent block relative to the rest of the architecture: multiple processes execute in parallel with each other, but the instructions inside a process are sequential.
The Sensitivity List
The process "wakes up" only when a signal in its sensitivity list changes.
Combinational Process
-- All signals read in the process must be in the list
process(i_a, i_b, i_sel)
begin
if i_sel = '0' then
w_mux <= i_a;
else
w_mux <= i_b;
end if;
end process;If a signal is forgotten in the sensitivity list of a combinational process, the simulation will be incorrect (implicit memory). Synthesis may generate a warning.
Sequential Process
-- Only the clock (and asynchronous reset if used)
process(i_clk)
begin
if rising_edge(i_clk) then
r_q <= i_d;
end if;
end process;VHDL-2008: process(all)
-- Automatically captures all read signals
process(all)
begin
w_result <= i_a + i_b;
end process;Combinational Pattern
architecture rtl of alu is
signal w_result : std_logic_vector(7 downto 0);
begin
p_alu : process(i_op, i_a, i_b)
begin
case i_op is
when "00" => w_result <= i_a AND i_b;
when "01" => w_result <= i_a OR i_b;
when "10" => w_result <= i_a XOR i_b;
when others => w_result <= (others => '0');
end case;
end process p_alu;
o_result <= w_result;
end architecture rtl;Note the process label (p_alu :) — good practice for readability.
Sequential Pattern (register + synchronous reset)
p_reg : process(i_clk)
begin
if rising_edge(i_clk) then
if i_rst = '1' then
r_data <= (others => '0');
r_valid <= '0';
r_counter <= (others => '0');
else
r_data <= i_data;
r_valid <= i_valid;
r_counter <= r_counter + 1;
end if;
end if;
end process p_reg;Sequential Statements Inside a Process
if / elsif / else
process(i_clk)
begin
if rising_edge(i_clk) then
if i_rst = '1' then
r_state <= IDLE;
elsif i_enable = '1' then
r_state <= ACTIVE;
else
r_state <= r_state; -- unnecessary but explicit
end if;
end if;
end process;case
process(i_clk)
begin
if rising_edge(i_clk) then
case r_state is
when IDLE =>
if i_start = '1' then
r_state <= RUNNING;
end if;
when RUNNING =>
if r_done = '1' then
r_state <= IDLE;
end if;
when others =>
r_state <= IDLE;
end case;
end if;
end process;
when othersis mandatory in acaseon non-enumerated types. It is good practice even for enumerated types (covers unexpected cases).
for / loop
process(i_clk)
variable v_sum : unsigned(15 downto 0);
begin
if rising_edge(i_clk) then
v_sum := (others => '0');
for i in 0 to 7 loop
if w_data(i) = '1' then
v_sum := v_sum + 1;
end if;
end loop;
r_popcount <= v_sum(3 downto 0);
end if;
end process;Common Mistakes
Inferred Latch (combinational logic error)
-- BAD: not all branches cover all outputs
process(i_sel, i_a, i_b)
begin
if i_sel = '0' then
w_out <= i_a;
end if;
-- i_sel = '1' → w_out not assigned → inferred latch!
end process;
-- GOOD: default value + full coverage
process(i_sel, i_a, i_b)
begin
w_out <= i_a; -- default value
if i_sel = '1' then
w_out <= i_b;
end if;
end process;Latches should be avoided on FPGAs (poor timing, inefficient resources). Always cover all cases in a combinational process.