The process block: sensitivity list, sequential statements, and combinational/sequential patterns.
A process describes part of a circuit's behavior with sequential statements. It operates concurrently with other architecture blocks and may describe combinational or stateful logic.
-- General structureprocess(sensitivity_list) -- local declarations (variables)begin
-- sequential statements
end process;
Trigger reevaluation
A process with a sensitivity list executes once at simulation startup, then waits for an event on a listed signal.
For combinational logic, list every signal read:
-- All signals read in the process must be in the listprocess(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;
Omitting one can make simulation diverge from synthesis. Latch inference is a separate issue: it arises when an output needs to retain its value because some paths leave it unassigned.
For an edge-triggered register, list the clock and any asynchronous reset:
-- 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 can determine sensitivity through process(all):
This combinational process decodes the operation and assigns its output in every case. The label p_alu makes it easier to find:
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;
The next pattern stores values on an edge and uses 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;
Signal updates remain deferred even though process statements execute in order.
Express conditions and repetition
if / elsif / else tests successive conditions:
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 selects a branch by value:
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;
Cover every possible value. when others groups unnamed choices; it is unnecessary when explicit choices already cover the type. Its presence does not guarantee hardware FSM recovery from an illegal encoding.
A loop can describe several operations in one activation. Synthesis generally unrolls a fixed-bound loop into logic without adding one cycle per iteration:
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;
To avoid unintended combinational storage, cover every branch or assign a default:
-- BAD: not all branches cover all outputsprocess(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 coverageprocess(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;