Sei sulla pagina 1di 24

INTRODUCCIÓN

El lenguaje de programación VHDL (Very High Speed Integrated Circuit Hardware Description
Languaje) es una nueva metodología de diseño de circuitos digitales. Es un lenguaje que
describe el comportamiento del circuito, es decir describe el hardware VHDL como un
lenguaje para el modelado y simulación lógica el cual posee una sintaxis amplia y flexible y
permite el modelado preciso, en distintos estilos, del comportamiento de un sistema digital
conocido, y el desarrollo de modelos de simulación.

Algunas ventajas del uso de VHDL para la descripción de hardware son:

 VHDL permite diseñar, modelar y comprobar un sistema desde un alto nivel de


abstracción bajando hasta el nivel de definición estructural de puertos
 Circuitos descriptos utilizando VHDL, siguiendo unas guías para síntesis,
pueden ser utilizados por diversas herramientas de síntesis para crear e
implementar circuitos
 Los módulos creados en VHDL pueden utilizarse en diferentes diseños, lo que
permite la reutilización del código. Además, la misma descripción puede
utilizarse para diferentes tecnologías sin tener que rediseñar todo el circuito
 Está basado en un standart IEEE std 1076-1987, IEEE std 1076-1993
 Modularidad: VHDL permite dividir o descomponer un diseño hardware y su
descripción VHDL en unidades más pequeñas.
LENGUAJE VHDL

El lenguaje VHDL es utilizado para la programación de dispositivos de lógica programable como los
FPGA y CPLD. Aunque VHDL es un lenguaje de programación como cualquier otro en cuanto a que
tiene las estructuras básicas de programación, también es importante mencionar que la ejecución
de los códigos en VHDL no es igual a la ejecución de los códigos en microprocesadores y
microcontroladores.

En el lenguaje VHDL el código se compone de tres partes fundamentales: El Encabezamiento, la


Entidad (Entity) y La Arquitectura. En la entidad se declaran los puertos de entrada y salida que
conectan al dispositivo con el mundo exterior.

ESTRUCTURA BÁSICA DE UN ARCHIVO FUENTE VHDL


ENTIDAD (ENTITY)

Una entidad es la abstracción de un circuito, ya sea desde un complejo sistema electrónico o una
simple puerta lógica. La entidad únicamente describe la forma externa del circuito, en ella se
enumeran las entradas y las salidas del diseño. Una entidad es análoga a un símbolo esquemático
en los diagramas electrónicos, el cual describe las conexiones del dispositivo hacia el resto del
diseño.

entity nombre is

generic (cte1: tipo := valor1; cte2: tipo:= valor 2; …);


port (entrada1, entrada2, … : in tipo; salida1, salida2, …: out tipo; puertoi : modo tipo);

end nombre;

Los puertos pueden ser de entrada in, salida out, entrada-salida inout o buffer. Los puertos de
entrada sólo se pueden leer y no se puede modificar su valor internamente en la descripción del
comportamiento del circuito (architecture), sobre los puertos de salida sólo se puede escribir, pero
nunca tomar decisiones dependiendo de su valor (esto implica una lectura). Si es estrictamente
necesario escribir sobre un puerto a la vez que se tiene que tener en cuenta su valor el tipo sería
inout o buffer.

Además, en la entity se pueden definir unos valores genéricos (generic) que se utilizarán para
declarar propiedades y constantes del circuito, independientemente de cual sea la arquitectura. A
nivel de simulación utilizaremos generic para definir retardos de señales y ciclos de reloj, estas
definiciones no serán tenidas en cuenta a nivel de síntesis. También se puede utilizar generic para
introducir una constante que será utilizada posteriormente en la architecture, utilizaremos esa
constante para hacer nuestro circuito más general. Por ejemplo, podemos definir el
comportamiento de un banco de registros teniendo en cuenta que puede tener cualquier número
de registros, fijando el número de registros particular que queremos simular e implementar a
través de una constante del generic. Esto implica que en toda la parte de nuestro código (el que
vamos a escribir dentro de architecture) donde haga falta el número de registros utilizaremos el
nombre de la constante definida en generic, de manera análoga a como se haría en cualquier
lenguaje de programación convencional. La sentencia generic no es necesaria, en caso de que no
vayamos a utilizarla puede desaparecer de la entity.

A continuación, se presenta un ejemplo de descripción externa del circuito (entity). Para el


ejemplo sabemos que el circuito presentará dos entradas de tamaño N bits y una salida de tamaño
un bit, particularizamos la entidad para N igual a 8. Como hemos advertido anteriormente, aunque
la función de generic es permitirnos generar un código más general, una vez que definimos el
circuito, tenemos que particularizarlo, por lo que siempre debe darse un valor a las constantes del
campo generic.

A
F Y
B

entity F is

generic (N: natural: =8);

port (A, B: in bit_vector(N-1 downto 0); Y: out bit);

end F;

DECLARACIONES DE ENTIDADES

Para la declaración de una entidad hay que definir un nombre y también el nombre de los puertos
de I/O que utilizara el diseño, a continuación, mostramos un esquema básico para la declaración
de entidades. Las entidades que usaremos inicialmente serán entidades en donde solo se
declararán puertos solamente.

Dentro de las declaraciones de las entidades, hay que realizar la declaración de los puertos
utilizados en el diseño del dispositivo. Los puertos se declaran utilizando el comando port en la
cual se debe definir los nombres, modo y tipos de las señales utilizadas como I/O.

El formato para la declaración de puertos es:

Port( Nombre_puerto1 : [Modo del puerto] [Tipo de dato del puerto];


Nombre_puerto2 : [Modo del puerto] [Tipo de dato del puerto];
Nombre_puerto3: [Modo del puerto] [Tipo de dato del puerto]);

Las declaraciones de los puertos se realizan dentro de la instrucción port la cual debe terminar en
un carácter de punto y coma; además de que cada declaración de un puerto debe terminar
también en un carácter de punto y coma, con excepción de la última declaración en donde no es
necesario. La declaración de los puertos consta de un nombre del puerto seguido de un carácter
de dos puntos (:), luego se debe especificar el modo del puerto y el tipo de dato. A continuación,
se listan los modo y tipos de datos más utilizados para la declaración de puertos.

Los modos permitidos para los puertos son:

In: Define un puerto como entrada de datos del dispositivo. Solo funciona como
entrada no puede ser utilizado como puerto bidireccional.

Out: Define un puerto como salida de datos provenientes del dispositivo. No puede ser utilizado
como un puerto bidireccional. Este modo solo permite sacar datos fuera del dispositivo; el
dispositivo no puede saber que dato se encuentra en el puerto en un momento determinado ya
que este modo no permite la retroalimentación de la señal.

InOut: Define un puerto como un puerto bidireccional o sea que el puerto es de entrada y
salida; este modo permite que el dispositivo pueda leer el valor colocado como dato de salida este
modo si permite la retroalimentación.

Buffer: Define un puerto como salida, pero ofrece la posibilidad de que el dispositivo pueda
leer el dato colocado en el puerto. El puerto no es de entrada es de solo salida, pero permite
la retroalimentación.

Los tipos de datos más comunes utilizados en puertos son:

BIT y BIT_VECTOR: Este tipo de dato está definido en el estándar original de VHDL, el IEEE 1076 el
cual ya tiene varias versiones y también está definido en el estándar IEEE 1164. Estos datos
soportan valor lógico de '0' y '1'. El tipo BIT_VECTOR es un arreglo del tipo BIT cuya dimensión la
define el programador en el momento de la declaración del puerto.

STD_LOGIC y STD_LOGIC_VECTOR: Estos tipos de datos no están soportado en el estándar


original de VHDL, fueron introducidos a partir del estándar IEEE 1164. Ofrecen una mayor ventaja
que los tipos BIT, ya que además de permitir valores lógicos '0' y '1' permiten otros valores como:

Z: representa un valor que indica alta impedancia.


-: establece una condición no importa.
L: representa una señal débil de cero.
H: representa una señal débil de uno.
U: indica sin inicializar.
X: valor desconocido.
W: señal débil desconocida.

Aunque los STD_LOGIC soportan estos nuevos valores, los únicos que se pueden considerar
verdaderamente útiles son los dos primeros además de los '0' y '1' que ya existían desde los tipos
BIT. Al igual que los tipos BIT los tipos STD_LOGIC, pueden definir arreglos de vectores, que
facilitan el trabajo con puertos que guardan alguna relación.

STD_ULOGIC: Este tipo de dato es igual que el STD_LOGIC, con la diferencia de que, en el
STD_LOGIC se contempla la utilización de las funciones de resolución que se emplean cuando dos
fuentes de señales tratan de dar valor a una sola señal; por ejemplo la salida de dos elementos de
tres estados que se conectan a una misma entrada, una salida puede ser de alta impedancia y
puede tener un valor lógico; entonces cual debe ser el valor que obtenga la señal de entrada a la
que se le conectaron las dos fuentes de señales; esta decisión se resuelve mediante una función
de resolución, los tipos de datos STD_LOGIC permiten el uso de funciones de resolución mientras
que los tipos de datos STD_ULOGIC no lo permiten, esta es la principal diferencia; por lo demás
aspectos son iguales soportan los mismo valores de datos.

EJEMPLO DE DECLARACIONES DE ENTIDADES

Ahora veremos algunos ejemplos de declaraciones de entidades de los proyectos típicos al


momento de iniciar en la programación de VHDL, en cada ejemplo se expondrá un nombre del
proyecto y un objetivo específico que explicará brevemente la finalidad de la entidad.

Ejemplo 1

Nombre: Decodificador de BCD a 7 seg


Objetivo: El objetivo de esta entidad es de tomar como datos de entrada un numero en formato
BCD y calcular el dato de salida necesario para que dicho número BCD se va reflejado en una
pantalla de siete segmentos.

Diagrama esquemático correspondiente a la entidad del ejemplo 1

Del diagrama esquemático del ejemplo 1 vemos que para la declaración de la entidad
correspondiente al convertidor de BCD a 7 seg vemos que la entidad tiene 4 entradas y 7 salidas. Si
a la entidad le podemos como nombre BCD7seg la declaración sugerida seria el código que
mostramos a continuación.

Declaración de entidad:
Nombre: BCD7seg
Código necesario para la declaración de la entidad del ejemplo 1

En esta declaración de entidad de vemos que tanto las señales de entradas como las de salidas
fueron declaradas utilizando el tipo de datos STD_LOGIC, lo que implica que las señales serán
trabajadas dentro de la arquitectura bit a bit, esto puede ser útil en algunos casos y en otros no
tanto. Es por eso que expondremos otra posible declaración de la entidad de este mismo ejemplo,
pero esta vez usando como tipo de datos STD_LOGIC_VECTOR.

Código necesario para la declaración de la entidad del ejemplo 1 usando


STD_LOGIC_VECTOR

En esta ocasión se ha utilizado los arreglos vectoriales por lo que solo se necesitan dos
declaraciones de puertos lo que simplifica el desarrollo del código.

Ejemplo 2

Nombre: Sumador completo de 4 bits


Objetivo: Esta entidad tomará como datos de entrada dos números binarios de 4 bit y un bit de
acarreo de entrada, este dato se sumará dando como resultado los datos de salida; un numero
binario de 4 bit que representa el resultado de la suma y uno de un bit para el acarreo de salida.
Diagrama esquemático para la entidad del ejemplo 2

Para esta entidad es evidente que los puertos correspondientes a los números de 4 bits es
conveniente utilizar como tipo de dato a los datos STD_LOGIC_VECTOR, este mismo tipo de datos
será utilizado para el puerto de salida correspondiente al resultado de la suma; para el dato del bit
de acarreo de entrada y el bit de acarreo de salida se usaran los STD_LOGIC.

Código necesario para la declaración de la entidad del ejemplo 2

Aunque en la figura 5 el código que se utiliza para la declaración de la entidad se utilizan como
tipos de datos STD_LOGIC y STD_LOGIC_VECTOR de manera combinada, es importante señalar
que el programador puede escoger como tipo de datos para todas las señales de entrada el
STD_LOGIC que es un tipo de dato de un solo bit; la definición del tipo de dato a utilizar para la
declaración de los puertos dependerá de la destreza y estilo de programación.

Ejemplo 3

Nombre: Contador de 4 bit


Objetivo: Diseñar un dispositivo que cuente los pulsos provenientes de un generador de pulsos, la
capacidad del contador es de 4 bits. Ademas el dispositivo contara con un bit para el reinicio de la
cuenta.

Fig 6. Diagrama esquemático para la entidad del ejemplo 3

En este caso es necesario que el dispositivo pueda leer el valor presente en el puerto de salida que
representa la cuenta, es por eso que el puerto Do debe ser del modo inout, los puerto CLK y RST
son puertos del modo in y del tipo STD_LOGIC.

Fig 7. Código necesario para la declaración de la entidad del ejemplo 3

Como se menciono anteriormente el puerto DO debe ser configurado en el modo de inout y


ademas se definió como un STD_LOGIC_VECTOR cuya dimensión depende de la cantidad de bit del
contador. El objetivo de configurar DO en el modo inout es proporcionar al dispositivo la
posibilidad de retroalimentar la señal que lleva la cuenta para que pueda ser incrementada
posteriormente.
ARQUITECTURA

Los pares de entidades y arquitecturas se utilizan para representar la descripción completa de un


diseño. Una arquitectura describe el funcionamiento de la entidad a la que hace referencia, es
decir, dentro de architecture tendremos que describir el funcionamiento de la entidad a la que
está asociada utilizando las sentencias y expresiones propias de VHDL. La descripción de la

arquitectura puede ser estructural o por comportamiento.

architecture arch_name of entity_name is

-- declaraciones de la arquitectura:

-- tipos
-- señales
-- componentes

begin
-- código de descripción

-- instrucciones concurrentes

-- ecuaciones booleanes
-- componentes
process (lista de sensibilidad)

begin
-- código de descripción

end process; end arch_name;

El código VHDL propiamente dicho se escribe dentro de architecture. Cada architecture va


asociada a una entity y se indica en la primera sentencia. A continuación, y antes de begin se
definen todas las variables (señales) internas que vas a necesitar para describir el comportamiento
de nuestro circuito, se definen los tipos particulares que necesitamos utilizar y los componentes,
otros circuitos ya definidos y compilados de los cuales conocemos su interfaz en VHDL (su entity).

Desde begin hasta end escribiremos todas las sentencias propias de VHDL, pero no todas pueden
utilizarse en cualquier parte del código. Así pues, aquellas sentencias de VHDL que tengan definido
un valor para cualquier valor de la entrada (y que nosotros denominamos sentencias
concurrentes) podrán ir en cualquier parte del código, pero fuera de la estructura process. Aunque
no es el fin de este manual, puede afirmarse que todas las sentencias concurrentes se traducirán
en subcircuitos combinacionales. También fuera de la estructura process, se instanciarán los
componentes, subcircuitos ya definido sutilizados por el circuito actual, indicando cuáles son sus
entradas y sus salidas de entre las señales del circuito del que forman parte.
El process es una estructura particular de VHDL (que se describe con mucho más detalle más
adelante) que se reserva principalmente para contener sentencias que no tengan obligatoriamente
que tener definido su valor para todas las entradas (el ejemplo más común es una estructura if-
else incompleta). Esto obliga a que la estructura process almacene los valores de sus señales y
pueda dar lugar (no siempre) a subcircuitos secuenciales. Además, en simulación sólo se ejecutan
las sentencias internas a esta estructura cuando alguna de las señales de su lista de sensibilidad
cambia de valor.

ESTRUCTURA BÁSICA DE UN ARCHIVO FUENTE EN VHDL

Como hemos visto los modelos VHDL están formados por dos partes: la entidad (entity) y la
arquitectura (architecture); es en esta última donde se escriben las sentencias que describen el
comportamiento del circuito, a este modelo de programación en VHDL se le suele denominar
behavioral.

architecture circuito of nombre is

-- señales

begin
-- sentencias concurrentes process (lista de sensibilidad) begin

-- sentencias secuenciales

-- sentencias condicionales

end process
end architecture circuito;

Dentro de la arquitectura se encuentra:


-Tipos y señales intermedias necesarios para la descripción del comportamiento.

-Sentencias de asignación que deben realizarse siempre, así como sentencias concurrentes.
iii) -Uno a varios process que tienen en su interior sentencias condicionales y/o asignaciones a
señales que dan lugar a hardware secuencial.
iv)

SENTENCIAS CONCURRENTES

Las sentencias concurrentes son sentencias condicionales que tienen al menos un valor por
defecto para cuando no se cumplen ninguna de las condiciones. Aunque podría utilizarse una
sentencia común como un if con obligación de else, los desarrolladores de VHDL han preferido
utilizar dos sentencias particulares:

WHEN – ELSE

señal_a_modificar <= valor_1 when condición_1 else


valor_2 when condición_2 else

...

valor_n when condición_n else

valor_por defecto;
En esta sentencia siempre modificamos el valor de una misma señal, pero las condiciones pueden
ser independientes (actuar sobre distintas señales cada una), dónde la colocación de las
condiciones indica la preferencia de unas sobre otras, es decir, la condición 1 tiene preferencia
sobre el resto, la condición 2 sobre todas menos la 1 y así sucesivamente.

-- Ejemplos when-else

---------------------------------------------
C <= “00” when A = B else “01” when A < B else “10”;

---------------------------------------------
C <= “00” when A = B else

“01” when D = “00” else

“10”;

---------------------------------------------

WITH – SELECT – WHEN

with señal_condición select

señal_a_modificar <= valor_1 when valor_1_señal_condición,

valor_2 when valor_2_señal_condición,


...

valor_n when valor_n_señal_condición, valor_por_defecto when others;

Esta sentencia es menos general que la anterior. En este caso se modificará el valor de una señal
dependiendo de los valores de una señal condición, aparecerán como máximo tantas líneas como
valores posibles pueda tener la señal condición.
---------------------------------------------

-- Ejemplo with-select

---------------------------------------------
with entrada select

salida <= “00” when “0001”,

“01” when “0010”,

“10” when “0100”,

“11” when others;

----------------------------------------------

Desde un punto de vista de HW estas dos sentencias dan como resultado HW convencional puro,
es decir, puertas lógicas, multiplexores, decodificadores …

Sentencias Condicionales

VHDL permite utilizar otro tipo de sentencias condicionales más parecidas a los lenguajes de
programación usados. Todas estas sentencias como se explicará la sección 3.3 tiene que ir
obligatoriamente dentro de un proceso. Las sentencias condicionales más comunes en VHDL son
las siguientes:

IF – THEN – ELSE

process (lista de sensibilidad)

begin
if condición then
-- asignaciones

elsif otra_condición then

-- asignaciones

else
-- asignaciones

end if;

end process;

---------------------------------------------
-- Ejemplo

---------------------------------------------
process (control, A, B)

begin
if control = “00” then

resultado <= A + B;

elsif control = “11” then

resultado <= A – B;

else
resultado <= A;

end if;
end process;

----------------------------------------------

La sentencia if-else permite cualquier tipo de combinación y encadenamiento, exactamente igual


que ocurre en C o PASCAL o cualquier otro lenguaje de programación de alto nivel.
CASE – WHEN

process (lista de sensibilidad)

begin

case señal_condición is

when valor_condición_l =>


-- asignaciones

when valor_condición_n =>


-- asignaciones

when others =>


-- asignaciones

end case; end process;

Dentro de las asignaciones pueden parecer también sentencias if-else. Es necesario que aparezca
en la estructura when others, pero no es necesario que tenga asignaciones, se puede dejar en
blanco.

---------------------------------------------
-- Ejemplo
---------------------------------------------
process (control, A, B)

begin
case control is when “00” =>

resultado <= A+B;

when “11” => resultado <= A-B;


when others => resultado <= A;
end case; end process;
----------------------------------------------

Igual que en los lenguajes software, existen distintos tipos de bucles:

FOR – LOOP

process (lista de sensibilidad)

begin
for loop_var in range loop

-- asignaciones

end loop; end process;

Para el for range puede ser 0 to N o N downto 0.

---------------------------------------------

-- Ejemplo

---------------------------------------------
process (A)

begin

for i in 0 to 7 loop

B(i+1) <= A(i);

end loop; end process;


---------------------------------------------

WHILE – LOOP
process (lista de sensibilidad)

begin
while condición loop

-- asignaciones

end loop; end process;

---------------------------------------------

-- Ejemplo
---------------------------------------------
process (A)

variable i: natural := 0;

begin
while i < 7 loop B(i+1) <= A(i); i := i+1;

end loop; end process;

SIMULACIÓN EN VHDL

VHDL realiza la simulación siguiendo la técnica de simulación por eventos discretos (Discrete Event
Time Model). Esta es una técnica que permite avanzar el tiempo a intervalos variables, en función
de la planificación de ocurrencia de eventos (cambio de valor de alguna señal). Esto significa que
no se simula el comportamiento del circuito pico- segundo a pico-segundo, si no desde que ocurre
un evento hasta el siguiente, donde puede pasar un pico-segundo o varios segundos. Durante el
intervalo de tiempo en el que no se produce ningún evento se mantiene el valor de todas las
señales.

FASES DE LA SIMULACIÓN

La simulación consta de tres fases:

Fase 0: la simulación comienza en la fase de inicialización donde a las señales se les asignan unos
valores iniciales y se pone el tiempo a cero. La asignación se hace rellenando una lista de eventos
para el instante t = 0.

Fase 1: todas las transiciones planificadas para ese tiempo son ejecutadas. Es decir, se ejecuta el
código ordenadamente teniendo en cuenta cuales son las señales que se han modificado,
cumpliendo las normas de ejecución explicadas para los procesos.

Fase 2: Las señales que se han modificado como consecuencia de las transiciones planificadas en
el instante t se escriben en la lista de eventos planificándose para el instante t + δ. Donde δ es un
instante infinitesimal.

Se repiten la fase 1 y 2 hasta que no existen más transiciones. Además, en los instantes entre
eventos se mantienen los valores de las señales.

A continuación, para ilustrar como se realiza la simulación se describirá un ejemplo:

Un contador es un circuito que genera un número nuevo cada ciclo de reloj, En VHDL tenemos que
escribir expresamente que se quiere un número nuevo cada ciclo de reloj, como muestra el
siguiente código:

entity contador is

port (reset, clk : in std_logic;


numero : out std_logic_vector(3 downto 0));

end contador;

architecture circuito of contador is

signal interna: std_logic_vector(3 downto 0);

begin

process (reset, clk, interna)

begin
if (reset = '1')
interna <= “0000”;

elsif clk’event and clk = ‘1’ then

interna <= interna + 1;

end if; end process;


numero <= interna;

end circuito;

La señal interna está definida como un std_logic_vector(3 downto 0), aplicando las definiciones del
estándar del IEEE obtenemos que “1111” + 1 = “0000”, por lo que el código anterior representa un
contador que cuenta de 0 a 15 y vuelta a empezar.

A continuación, se presenta la simulación en PROTEUS:


REFERENCIAS:

[1]
http://ciecfie.epn.edu.ec/wss/VirtualDirectories/80/pag_personales/PChico/Materiales_DLP/semi
nario_folleto.pdf

[2] https://eprints.ucm.es/26200/1/intro_VHDL.pdf

[3] https://www.editorialpatria.com.mx/pdffiles/9786074386219.pdf

[4] https://sites.google.com/site/logicaprogramable/vhdl/lenguaje-vhdl

[5]
http://www.profesores.frc.utn.edu.ar/electronica/tecnicasdigitalesi/pub/file/Publicaciones/VHDL.
pdf

[6] https://www.youtube.com/watch?v=co3YZcOwRAc

[7] https://www.youtube.com/watch?v=AZWH6ApZxnA

Potrebbero piacerti anche