Guía de Estilo y Buenas Prácticas de Diseño VHDL
1. Filosofía del Curso
VHDL es un lenguaje de descripción de hardware. No estamos programando software secuencial, estamos definiendo circuitos físicos que operan en paralelo.
Regla de Oro: Si no puedes dibujar el esquema del circuito (puertas y registros) en un papel, no escribas el código.
No utilices construcciones de VHDL que no se hayan explicado en clase.
Prohibido:
variable, bucleswhile,alias, librerías no estándar, etc. Cíñete estrictamente a las estructuras enseñadas para garantizar que tu diseño sea correcto y sintetizable.
2. Formato y Legibilidad
El código se escribe una vez, pero se lee muchas veces (por ti, por tus compañeros y por el profesor). La claridad es necesaria.
2.1. Indentación (Sangrado)
Regla: Usa siempre 4 espacios.
Prohibido: No uses tabuladores (
Tab). Configura tu editor (Vivado, VS Code) para insertar espacios al pulsar Tab.Jerarquía: Todo bloque estructural (
entity,architecture,process,if,case) debe estar indentado hacia la derecha respecto a su contenedor.
2.2. Comentarios
Cabecera: Todo fichero debe comenzar con un bloque indicando: Nombre, Autor y Descripción.
Comentar el «Por qué», no el «Qué»:
No comentes lo obvio (
a <= b; -- Asigna b a a).Comenta la intención funcional (
count_next <= 0; -- Reinicia cuenta por fin de trama).
3. Convenciones de Nombres
3.1. Ficheros (.vhd)
Correspondencia: El nombre del fichero debe ser EXACTAMENTE igual al nombre de la entidad. - Ejemplo:
entity contador→ ficherocontador.vhd.Unicidad: Solo una entidad por fichero.
3.2. Testbenches
Se nombrarán igual que la entidad a probar con el sufijo
_tb. - Ejemplo:contador_tb.vhd.Se aplica la convención 3.1 para el nombre de la entidad del testbench.
3.3. Nombres de Arquitecturas
RTL: Para diseños sintetizables (lógica combinacional + registros).Behavioral: Exclusivo para testbenches (modelos de simulación).Structural: Solo para código que describe la interconexión de componentes.
3.4. Nombres de puertos
Siempre en MAYÚSCULAS (ej.:
DATA_IN,BUSY,LED_OUT).
3.5. Señales reloj y reset
Utilizaremos los identificadores siguientes:
Reloj:
CLK.RESET:
RST(RST_Nsi activo bajo).
3.6. Señales Internas
En minúsculas.
En diseño secuencial es obligatorio usar los sufijos:
_reg: salida del registro (valor actual)._next: entrada del registro (valor futuro).signal senal_reg : unsigned(3 downto 0); -- Salida del flip-flop (Q). signal senal_next : unsigned(3 downto 0); -- Entrada del flip-flop (D).
3.7. Señales activas a nivel bajo
Sufijo
_n(interno) o_N(puerto) para señales activas a “0”.
3.8. Tipos y Enumerados
Tipos definidos: Sufijo
_t(ej.:type estado_t is...).Estados: En MAYÚSCULAS con prefijo identificativo (ej.:
ST_IDLE,ST_RUN).
3.9. Constantes
En MAYÚSCULAS con prefijo
C_(ej.:C_MAX_COUNT).
3.9. Tabla Resumen
Ten esta tabla a mano mientras codificas.
Elemento |
Formato |
Sufijo/Prefijo |
Ejemplo |
Notas |
|---|---|---|---|---|
Fichero VHDL |
minúsculas |
.vhd |
contador.vhd |
Idéntico a la entidad. |
Testbench |
minúsculas |
_tb.vhd |
contador_tb.vhd |
Simulación. |
Reloj |
MAYÚSCULAS |
N/A |
CLK |
Nombre estricto. |
RST |
MAYÚSCULAS |
_N (activo bajo) |
RST, RST_N |
Nombre estricto. |
Puertos (I/O) |
MAYÚSCULAS |
_N (activo bajo) |
DATA_IN, BUSY |
|
Señales internas |
minúsculas |
_n (activo bajo) |
flag_enable |
Nunca usar mayúsculas. |
Reg. (Salida) |
minúsculas |
_reg |
count_reg |
Valor actual (Q). |
Reg. (Entrada) |
minúsculas |
_next |
count_next |
Valor futuro (D). |
Tipos de Datos |
minúsculas |
_t |
type estado_t |
Para FSMs. |
Estados (Enum) |
MAYÚSCULAS |
ST_ |
ST_IDLE, ST_RX |
Prefijo obligatorio. |
Constantes |
MAYÚSCULAS |
C_ |
C_MAX_COUNT |
Parámetros. |
1. Tipos de Datos Permitidos
4.1. Librerías
Obligatorio:
ieee.std_logic_1164.allyieee.numeric_std.all.Prohibido: Otras librerías (
std_logic_arith,std_logic_unsigned, etc.).
4.2. Uso de Tipos
Puertos: Siempre
std_logicostd_logic_vector.Aritmética interna: Usar
signedounsignedy convertir a vector solo en la salida.Máquinas de Estados: Usar tipos enumerados definidos por el usuario (
type estado_t is...).
5. Reglas de Implementación
5.1. Lógica Combinacional Simple
Para multiplexores, puertas lógicas o decodificadores sencillos, NO utilices un proceso. Usa asignaciones concurrentes.
-- Correcto: Asignación concurrente
salida <= entrada1 when (a = '1' and b = '0') else entrada2;
5.2. Metodología de «Dos Procesos» (Diseño Secuencial)
Para contadores, registros de desplazamiento y FSMs, separa explícitamente el cálculo de la memoria.
Proceso Combinacional (Cálculo de
_next)
Calcula el siguiente estado basándose en entradas y estado actual (
_reg).Regla Anti-Latch: Asigna un valor por defecto a todas las señales que son salidas del proceso al inicio del mismo.
Proceso Secuencial (Actualización de
_reg)Solo sensible a
CLKyRST.Su única tarea es
_reg <= _next.
6. Ejemplo de Referencia
Fichero: control_temporizado.vhd
----------------------------------------------------------------------------------
-- Fichero: control_temporizado.vhd
-- Autor: Estudiante de Teleco
-- Desc: Ejemplo de FSM con Datapath siguiendo la Guía de Estilo v3.0
----------------------------------------------------------------------------------
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
entity control_temporizado is
port (
CLK : in std_logic;
RST : in std_logic;
START : in std_logic;
MAX_COUNT : in std_logic_vector(3 downto 0);
DONE : out std_logic
);
end control_temporizado;
architecture RTL of control_temporizado is
-- 1. Definición de Tipos (Sufijo _t y Prefijos ST_)
type estado_t is (ST_IDLE, ST_COUNTING, ST_FINISH);
-- 2. Señales Internas (minúsculas + _reg/_next)
-- Control (FSM)
signal state_reg : estado_t;
signal state_next : estado_t;
-- Datos (Aritmética usa unsigned)
signal count_reg : unsigned(3 downto 0);
signal count_next : unsigned(3 downto 0);
signal count_init : std_logic;
signal count_inc : std_logic;
begin
-- ------------------------------------------------------------- --
-- MEF codificada con metodología de "Dos Procesos" --
-- ------------------------------------------------------------- --
-- ------------------------------------------------------------
-- Lógica Combinacional (Cálculo de _next)
-- ------------------------------------------------------------
comb_proc : process (state_reg, count_reg, START, MAX_COUNT)
begin
-- A. Valores por defecto (Anti-Latch)
count_init <= '0';
count_inc <= '0';
DONE <= '0';
state_next <= state_reg;
-- B. Máquina de Estados
case state_reg is
when ST_IDLE =>
count_init <= '1'; -- RST síncrono del contador
if (START = '1') then
state_next <= ST_COUNTING;
end if;
when ST_COUNTING =>
if (count_reg = unsigned(MAX_COUNT)) then
state_next <= ST_FINISH;
else
count_inc <= '1'; -- Incremento del contador
end if;
when ST_FINISH =>
DONE <= '1';
state_next <= ST_IDLE;
when others =>
state_next <= ST_IDLE;
end case;
end process comb_proc;
-- ------------------------------------------------------------
-- Proceso: Lógica Secuencial (Memoria)
-- ------------------------------------------------------------
sec_proc : process (CLK)
begin
if rising_edge(CLK) then
if (RST = '1') then
state_reg <= ST_IDLE;
else
state_reg <= state_next;
end if;
end if;
end process sec_proc;
-- ------------------------------------------------------------- --
-- Contador separando parte combinacional y secuencial --
-- ------------------------------------------------------------- --
-- ------------------------------------------------------------
-- Lógica Combinacional (Cálculo de _next)
-- ------------------------------------------------------------
count_next <= (others => '0') when (count_init = '1') else
(count_reg + 1) when (count_inc = '1') else
count_reg;
-- ------------------------------------------------------------
-- Proceso: Lógica Secuencial (Memoria)
-- ------------------------------------------------------------
sec_proc : process (CLK)
begin
if rising_edge(CLK) then
if (RST = '1') then
count_reg <= (others => '0');
else
count_reg <= count_next;
end if;
end if;
end process sec_proc;
end RTL;