Uso de procedimientos en VHDL: Simplifique su diseño con código reutilizable
En VHDL, los procedimientos son subprogramas que permiten a los diseñadores evitar bloques de código repetitivos. Cuando la misma operación se necesita en múltiples lugares, crear un módulo completo puede ser excesivo. Un procedimiento ofrece una solución ligera y reutilizable.
Los procedimientos pueden declararse en cualquier región declarativa —arquitectura, paquete o proceso— y su ámbito se limita a esa región. Cuando se invocan, el cuerpo del procedimiento se ejecuta como si su código estuviera escrito en su lugar, dándole los beneficios de modularidad sin la sobrecarga de un componente separado.
A diferencia de las funciones, los procedimientos no retornan un valor directamente. Sin embargo, puede pasar valores de vuelta declarando señales out o inout en la lista de parámetros, permitiendo efectivamente que el procedimiento actúe como un mini-módulo con entradas y salidas.
Este post es parte de la serie Tutoriales Básicos de VHDL.
La sintaxis canónica para definir un procedimiento se ilustra a continuación:
procedure <procedure_name> ( signal|variable|constant <name1> : in|out|inout <type>; signal|variable|constant <name2> : in|out|inout <type>; ... ) is <declarations_for_use_within_the_procedure> begin <code_performed_by_the_procedure_here> end procedure;
La lista de parámetros define las entradas y salidas del procedimiento —muy parecido a un mini-módulo. Los parámetros pueden ser señales, variables o constantes. Dentro del procedimiento puede declarar objetos adicionales (constantes, variables, tipos, subtipos, alias) que son válidos solo dentro de ese bloque; no se pueden declarar señales localmente.
Debido a que los procedimientos pueden contener sentencias wait, son especialmente útiles en testbenches —por ejemplo, como conductores BFM simples o para verificar salidas del DUT.
Ejercicio
En el tutorial anterior, se construyó un módulo temporizador usando sentencias if-then-else profundamente anidadas. Cada nivel anidado añadía complejidad y reducía la legibilidad, aunque la misma operación se realizaba en diferentes conjuntos de señales. Un mejor enfoque es encapsular la lógica repetitiva dentro de un procedimiento.
El siguiente tutorial en video recorre la creación de un procedimiento VHDL:
Ejemplo: Temporizador basado en procedimiento
El código del testbench permanece sin cambios, excepto por la adición de una llamada a procedimiento para conducir el DUT:
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
entity T19_ProcedureTb is
end entity;
architecture sim of T19_ProcedureTb is
constant ClockFrequencyHz : integer := 10; -- 10 Hz
constant ClockPeriod : time := 1000 ms / ClockFrequencyHz;
signal Clk : std_logic := '1';
signal nRst : std_logic := '0';
signal Seconds : integer;
signal Minutes : integer;
signal Hours : integer;
begin
i_Timer : entity work.T19_Timer(rtl)
generic map(ClockFrequencyHz => ClockFrequencyHz)
port map (
Clk => Clk,
nRst => nRst,
Seconds => Seconds,
Minutes => Minutes,
Hours => Hours
);
Clk <= not Clk after ClockPeriod / 2;
process is
begin
wait until rising_edge(Clk);
wait until rising_edge(Clk);
nRst <= '1';
wait;
end process;
end architecture;
El módulo temporizador en sí ahora aprovecha un procedimiento para incrementar contadores:
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
entity T19_Timer is
generic(ClockFrequencyHz : integer);
port(
Clk : in std_logic;
nRst : in std_logic; -- Reset negativo
Seconds : inout integer;
Minutes : inout integer;
Hours : inout integer
);
end entity;
architecture rtl of T19_Timer is
signal Ticks : integer;
procedure IncrementWrap(
signal Counter : inout integer;
constant WrapValue : in integer;
constant Enable : in boolean;
variable Wrapped : out boolean
) is
begin
Wrapped := false;
if Enable then
if Counter = WrapValue - 1 then
Wrapped := true;
Counter <= 0;
else
Counter <= Counter + 1;
end if;
end if;
end procedure;
begin
process(Clk) is
variable Wrap : boolean;
begin
if rising_edge(Clk) then
if nRst = '0' then
Ticks <= 0;
Seconds <= 0;
Minutes <= 0;
Hours <= 0;
else
IncrementWrap(Ticks, ClockFrequencyHz, true, Wrap);
IncrementWrap(Seconds, 60, Wrap, Wrap);
IncrementWrap(Minutes, 60, Wrap, Wrap);
IncrementWrap(Hours, 24, Wrap, Wrap);
end if;
end if;
end process;
end architecture;
La forma de onda siguiente confirma que el contador de minutos hace wrap correctamente cuando el temporizador alcanza 60 minutos:

Análisis
Desde la forma de onda vemos que la funcionalidad de wrap se comporta idénticamente a la implementación original con if anidados. El cambio es puramente estructural —sin cambio en la lógica subyacente.
El primer parámetro, Counter, es una señal inout, permitiendo al procedimiento leer y actualizar su valor. El segundo y tercer parámetros, WrapValue y Enable, son constantes; se tratan como constantes en tiempo de compilación dentro del procedimiento.
El parámetro final, Wrapped, es una variable declarada como out. Sirve como un valor de retorno pseudo, indicando si el contador hizo wrap durante esa llamada.
En el proceso principal, cuatro llamadas sucesivas a IncrementWrap cascadan los contadores. La variable Wrap de la llamada anterior alimenta la entrada Enable de la siguiente llamada. Usar una variable es esencial aquí porque las actualizaciones de señal solo son visibles después de que el proceso se suspende; una variable proporciona flujo de datos procedimental inmediato.

Conclusión
- Los procedimientos actúan como subprogramas reutilizables, eliminando código duplicado.
- Los parámetros pueden ser señales, variables o constantes, ofreciendo flexibilidad.
- A diferencia de las funciones, los procedimientos pueden contener sentencias
wait, lo que los hace ideales para conductores de testbench.
Proceda al siguiente tutorial »
VHDL
- Dominando las Técnicas de Afiladora de Herramientas: Guía Práctica
- Cómo el molibdeno moldea la industria moderna: usos, beneficios y dinámica de suministro
- Ejemplo de procedimiento VHDL: Incrementando un vector Standard Logic
- Creación de listas de cadenas en VHDL: Buenas prácticas y ejemplo
- Finalizar elegantemente una simulación de testbench VHDL
- Implementación de un controlador PWM en VHDL: Diseño, simulación y demo en FPGA
- Generación de números aleatorios en VHDL: De uniforme a OSVVM
- Aprovechando procedimientos en-proceso para diseños FSM más limpios en VHDL
- Uso de funciones impuras en VHDL: Mejorando legibilidad y mantenibilidad de FSM
- Dominando funciones VHDL: Guía práctica para diseño eficiente
- Diseño de máquina de estados finitos en VHDL: Ejemplo práctico de semáforo