Best Practices

Naming conventions, prefixes, and best practices for readable and maintainable VHDL code.

Why Coding Rules?

In a real VHDL project, a file may be read by dozens of people over years. Coding rules ensure:

  • Readability: understand a signal's role at first glance
  • Maintainability: quickly locate a bug
  • Consistency: same style throughout the team
  • Code review: facilitates error detection

Naming Prefixes

Ports (external interface)

PrefixVHDL ModeMeaningExample
i_inInput porti_clk, i_data, i_rst
o_outOutput porto_valid, o_data
io_inoutBidirectional portio_bus, io_sda

Internal Signals

PrefixMeaningExample
w_Unregistered signal — wire, combinationalw_sum, w_mux_out
r_Registered signal — flip-flop, D latchr_counter, r_data

Other Identifiers

PrefixMeaningExample
c_Constantc_CLK_FREQ, c_MAX_COUNT
g_Generic (entity parameter)g_WIDTH, g_DEPTH
t_User-defined typet_state, t_data_array
v_Variable (inside a process)v_temp, v_index
P_Process (label)P_WRITE_FSM, P_READ_DATA
f_Functionf_log2, f_parity

Complete Examples

entity uart_tx is
  generic (
    g_CLK_FREQ  : integer := 100_000_000;  -- g_ for generic
    g_BAUD_RATE : integer := 115_200
  );
  port (
    i_clk   : in  std_logic;               -- i_ input
    i_rst   : in  std_logic;               -- i_ input
    i_data  : in  std_logic_vector(7 downto 0);
    i_valid : in  std_logic;
    o_tx    : out std_logic;               -- o_ output
    o_ready : out std_logic
  );
end entity uart_tx;
 
architecture rtl of uart_tx is
  constant c_BIT_PERIOD : integer := g_CLK_FREQ / g_BAUD_RATE;  -- c_ constant
 
  type t_state is (IDLE, START, DATA, STOP);  -- t_ type
 
  signal r_state   : t_state;                         -- r_ registered
  signal r_counter : integer range 0 to c_BIT_PERIOD; -- r_ registered
  signal r_shift   : std_logic_vector(7 downto 0);    -- r_ registered
  signal w_tx_bit  : std_logic;                       -- w_ combinational
 
  -- f_ for a function
  function f_parity(v_data : std_logic_vector) return std_logic is
    variable v_p : std_logic := '0';
  begin
    for i in v_data'range loop
      v_p := v_p xor v_data(i);
    end loop;
    return v_p;
  end function f_parity;
 
begin
 
  P_TX_FSM : process (i_clk)  -- P_ for processes
  begin
    -- ...
  end process P_TX_FSM;
 
end architecture rtl;

Additional Naming Conventions

Case

-- VHDL keywords: lowercase
entity, architecture, process, signal, begin, end, if, then, else
 
-- Constants and generics: UPPERCASE or mixed
constant c_MAX_VALUE : integer := 255;
generic (g_DATA_WIDTH : integer := 8);
 
-- Types: t_ + snake_case
type t_uart_state is (IDLE, START, DATA, STOP);
 
-- FSM states: UPPERCASE
type t_state is (IDLE, WAIT_START, SEND_DATA, DONE);

Files

  • One file per entity
  • Filename = entity name: uart_tx.vhd
  • Extension: .vhd (VHDL) or .vhdl (less common)

Architecture

  • Use rtl for synthesizable code
  • Use tb for testbenches
architecture rtl of my_component is   -- synthesizable code
architecture tb  of tb_my_component is  -- testbench

What to Avoid

-- BAD : non-descriptive names
signal a, b, c, x : std_logic;
signal temp1, temp2 : unsigned(7 downto 0);
 
-- BAD : mixed styles
signal DATA_OUT : std_logic;    -- inconsistent
signal data_in  : std_logic;
 
-- BAD : no prefix -> impossible to know if it's a register
signal counter  : unsigned(7 downto 0);   -- registered or combinational?
 
-- GOOD : clear prefixes
signal r_counter : unsigned(7 downto 0);  -- clearly a register
signal w_carry   : std_logic;             -- clearly combinational

Prefix Reference Table

PrefixTypeDirection / Nature
i_PortInput (in)
o_PortOutput (out)
io_PortBidirectional (inout)
w_SignalCombinational (wire)
r_SignalRegistered (flip-flop)
c_ConstantFixed value
g_GenericEntity parameter
t_TypeUser type
v_VariableLocal process variable
P_ProcessProcess label
f_FunctionVHDL function