You are on page 1of 31

Introducción a VHDL

Laboratorio de Lógica Digital


(SA6E01/SA6T01)
Prof. Ricardo Villegas
Contenido
• Motivación
• Definición de VHDL
• Partes de un programa en VHDL
• Bibliotecas
• Entidad
• Arquitectura
• Tipos de instrucción
• Estilos de descripción
• Ejemplos
Motivación

• Adquirir los conocimientos iniciales de


VHDL que permitan abordar el diseño y
descripción de circuitos digitales sencillos
e implementarlos sobre un dispositivo
lógico programable de tipo FPGA
Definición de VHDL
• VHDL ~ Acrónimo de VHSIC y HDL
– “Very High Speed Integrated Circuit” Hardware Description Language
• Lenguaje definido por el IEEE (ANSI/IEEE 1076-1993) para
describir circuitos digitales
• NO es un lenguaje de programación en el cual se indican
instrucciones en un cierto orden, las cuales serán ejecutadas luego
en forma secuencial
• El código de un “programa” en VHDL especifica la interfaz,
estructura y comportamiento de un circuito y sus componentes
– Las instrucciones tienen significado y se interpretan en forma
simultánea, de manera similar a como funcionan los elementos de un
circuito
• Incorpora características intrínsecas al hardware:
– Conexión entre componentes
– Operaciones concurrentes
– Temporización de operaciones y retardos de propagación
• Es utilizado para especificar diseños para ASICs, PLDs, FPGAs y
otros dispositivos lógicos programables
Partes de un Programa en VHDL
• Los programas VHDL consisten colecciones de unidades de
diseño, almacenadas en archivos .vhd
• Cada programa contiene al menos una declaración de entidad y una
arquitectura
– Una unidad de diseño no puede estar separada en diferentes archivos
• Un programa VHDL tiene cuatro partes o áreas principales:
-- DESCRIPCION DEL PROYECTO --
… Información opcional acerca
del diseño (nombre, autor,
-- BIBLIOTECAS A UTILZAR -- compañía, plataforma, etc.)
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
Bibliotecas: colecciones de

componentes externos que
serán importados y usados en
-- DECLARACIÓN DE LA ENTIDAD --
el diseño
entity nombre_entidad is
port (lista_de_puertos);
end nombre_entidad; Entidad: Declaración de la
interfaz de entrada y salida del
-- DESCRIPCION DE LA ARQUITECTURA -- componente (bloque funcional)
architecture nombre_arquitectura of nombre_entidad is
begin
… Arquitectura: Descripción de
end nombre_arquitectura; la operación o funcionamiento
interno del componente
Elementos del Lenguaje
• Comentarios: se usan para agregar texto explicativo y documentar el
código; el compilador ignorará en una línea todo aquello que se encuentre
después de dos guiones seguidos

-- Ejemplo de comentario
-- Otro comentario

• Identificadores: nombres que se colocan a diversos elementos de un


programa (ej: entidades, arquitecturas, señales, variables, constantes, etc.)
para identificarlos y hacer referencia a ellos
– Un identificador solo puede contener letras, dígitos decimales y el caracter ‘_’
• El primer caracter siempre debe ser una letra y el último no puede ser ‘_’
• Tampoco se permiten dos ‘_’ seguidos
• No pueden usarse palabras reservadas de VHDL como identificadores
Ejemplos:
Válidos: A10, next_state, NextState, mem_addr_enable
Inválidos: sig#3, _X10, 7segment, X10_, un__valor, Entity, signal

– Los identificadores no son sensibles a mayúsculas y minúsculas


• En general, en VHDL no hay distinción de mayúsculas y minúsculas
Ejemplos: nextstate, NextState, NEXTSTATE, nEXTsTATE
Delimitadores
• El símbolo ; (punto y coma) se utiliza como delimitador de
instrucciones, y en algunos casos como separador de elementos en
una lista de argumentos

instrucción;
declaración(argumento1; argumento2; …);

• Numerosas instrucciones de VHDL finalizan la declaración de su


contenido con un delimitador end
• Los bloques de instrucciones asociadas con algunos elementos del
lenguaje (arquitecturas, procesos, etc.) están delimitados por un par
begin/end
architecture Ejemplo …
if (a = ‘1’) then
begin
… -- bloque de instrucciones
… -- bloque de instrucciones
end if;
end Ejemplo;
Representación de Datos
• VHDL permite representar diferentes tipos de datos: numéricos (enteros y
reales), booleanos, caracteres, cadenas, etc.
– En la asignatura se manejarán solamente valores numéricos enteros

• Valores literales: representan directamente valores de algún tipo


específico
– En VHDL los números en base 10 se representan directamente, pero es posible
expresar números en otras bases
– Formato: Base#Número; Base = {2 (bin), 8 (oct), 16 (hexa)}
Ejemplos: 1845, 2#101101, 8#3025, 16#1CF2

• Los bits o caracteres simples se representan encerrados entre comillas


simples (‘ ’)
Ejemplos: ‘1’, ‘0’, ‘Z’, ‘-’
• Las cadenas de bits se representan encerradas entre comillas dobles (“ ”)
– Ejemplo: “101101”
– También es posible representar cadenas de bits expresadas en otros sistemas
– Formato: Símbolo “Cadena”; Símbolo = {B (bin), O (oct), X (hexa)}
Ejemplos: "01111", O"17", X"F9"
Tipos de Datos
• VHDL soporta diferentes tipos de datos (Bit, Integer, Real, Boolean,
String, Std_Logic, etc.); algunos están predefinidos y otros están
definidos en bibliotecas externas
– En la asignatura se manejarán los tipos relacionados con el manejo de
bits simples, vectores de bits y números enteros

Tipo Descripción

Bit Solo toma valores binarios de ‘0’ y ‘1’

Bit_Vector Arreglo de valores binarios

Similar a Bit, pero extendido para aceptar 9 valores


Std_Logic posibles: {‘0’, ‘1’, ‘Z’, ‘L’, ‘W’, ‘U’, ‘X’, ‘W’, ‘-’}

Std_Logic_Vector Arreglo de los 9 valores posibles de Std_Logic

Boolean Solo toma valores de False o True

Integer, Signed,
Valores numéricos enteros, con y sin signo
Unsigned
Tipos Std_Logic y Std_Logic_Vector
• Los tipos std_logic y std_logic_vector están contenidos en el
paquete IEEE std_logic_1164
• Aceptan 9 valores posibles:
{’U’, ’X’, ’0’, ’1’, ’Z’, ’W’, ’L’, ’H’, ’-’}

– ’0’, ’1’: valores lógicos de 0 y 1


– ’Z’: alta impedancia
– ’L’ , ’H’: 0 y 1 débiles; lógica cableada
– ’X’, ’W’: valores desconocidos; no pueden interpretarse ni como 0 ni 1
– ’U’: sin inicializar. válido solo para simulaciones; la señal aún no tiene
un valor asignado
– ’-’: valor no significativo (don’t-care)
• Solo los valores ’0’, ’1’ y ’Z’ son usados en la síntesis de circuitos

• Los operadores aritméticos no están definidos para estos tipos


– Deben realizarse conversiones con tipos signed y unsigned para poder
manejar operaciones aritméticas directamente
Objetos de Datos
• Son elementos que contienen valores de un tipo determinado
• Existen tres tipos de objetos de datos: constantes, variables y
señales
• Los objetos de datos deben ser declarados antes de usarlos
– En la declaración se les asocia un identificador, un tipo de datos y
en algunos casos se inicializan con un valor

• Constantes: toman un valor fijo que no cambia dentro de la


descripción del diseño

• Variables: almacenan un valor que puede ser modificado cuando


sea necesario; son similares a cualquier tipo de variable de un
lenguaje de programación de alto nivel

• Señales: representan terminales o conexiones reales que


almacenan o transportan valores lógicos dentro del diseño
– Las señales pueden ser sintetizadas; las variables no
Constantes y Variables
• Las constantes almacenan un valor que no puede ser cambiado; se deben inicializar
con un valor al momento de la declaración
– Utilizadas para mejorar la legibilidad del código
Declaración:

constant nombre_constante : tipo_dato := valor;

• Las variables almacenan valores que puede cambiar según sea necesario durante la
descripción del diseño
– Se utilizan solo en el contexto de procesos o subprogramas, generalmente como
índices en instrucciones de bucle o para almacenamiento temporal de valores
Declaración:

variable nombre_variable : tipo_dato;

-- Ejemplo de declaración de constantes y variables


constant VCC: integer := ‘1’;
constant GND: integer := ‘0’

variable index: integer;


variable temporal: std_logic;
Señales
• Representan terminales o conexiones (cables) entre los
elementos del circuito
– Utilizadas para conectar entre sí los puertos de E/S de los
componentes o para transportar o almacenar en forma temporal
el valor de otras señales
Declaración:
signal nombre_señal : tipo_dato;
signal nombre_señal1, nombre_señal2, … : tipo_dato;

-- Ejemplos de declaración de señales


signal temp: integer;
signal a, b, c: std_logic;
Puertos
• Los puertos o terminales son tipos especiales de señales asociadas a la
interfaz de un componente del diseño
– Determinan cuales son las entradas recibidas y producidas por el componente
– Tienen un modo y un tipo de datos asociados
• Se especifican durante la declaración de la entidad que los contiene y
pueden ser usados posteriormente en la descripción del diseño en forma
similar a cualquier otra señal, de acuerdo con el modo y tipo asociados

Modo Descripción
Representa un terminal de entrada; se puede leer
IN desde el puerto, pero no escribir en el
Representa un terminal de salida; se puede
OUT escribir en el puerto, pero no leer de el
Puerto bidireccional (entrada y salida); permite
INOUT tanto lectura como escritura
Usado como almacenamiento temporal con
BUFFER retroalimentación interna
Declaración y Manejo de Vectores de Bits
• Bit_Vector y Std_Logic_Vector son arreglos de elementos de tipo Bit o Std_Logic
– Colección indexada de varios elementos del tipo asociado
• Pueden declararse en forma descendente o ascendente
– La forma descendente es la más apropiada para representar números binarios
Declaración:

-- Declaración de vectores de tipo std_logic_vector; similar para bit_vector


nombre : std_logic_vector(ind_max downto ind_min); -- descendente
nombre : std_logic_vector(ind_min to ind_max); -- ascendente

A4A3A2A1A0
-- Ejemplos
signal A: std_logic_vector(4 downto 0); -- MSB es el 4, LSB es el 0 MSB LSB
signal B: std_logic_vector(0 to 4); -- MSB es el 0, LSB es el 4
B0B1B2B3B4

• Puede accederse a bits individuales o rangos de bits dentro del vector:


Formato: A(1)  A1 = 0
Nombre_Vector(índice) A = “11101”
Nombre_Vector(rango) A(3 downto 1)  A3A2A1 = 110
Operadores
• Operadores Lógicos: NOT, AND, OR, NAND, NOR, XOR, XNOR

• Operadores Relacionales: =, /=, <, >, <=, >=

• Operadores Aritméticos: +, -, *, /, MOD, REM, (), abs, **


– No están definidos para los tipos Std_Logic y Std_Logic_Vector

• Operadores de Asignación: <= (con signal), := (con variable)


– Usados para asignar valores a objetos tipo signal o variable

• Operador de Asociación: =>


– Usado para asociar los puertos de un componente con las señales
conectadas a ellos (Port Map), en la selección de casos de una
instrucción Case/When o con especificadores posicionales

• Operadores de Corrimiento: SLL, SRL, SLA, SRA, ROL, ROR


– Usados para realizar desplazamientos o rotaciones orientadas, hacia la
izquierda o derecha, sobre los bits de un vector
Otros Operadores
• Operador de concatenación: &
– Permite crear señales compuestas de fragmentos de valores u otras
señales
y <= "00" & a(7 downto 2);
y <= a(7) & a(7) & a(7 downto 2);
y <= a(1 downto 0) & a(7 downto 2);

• Especificadores de posición:
– Permiten especificar posiciones para la asignación de valores a los
elementos de un vector

a <= "10100000"; -- Asignación con literal de cadena de bits


-- Formas alternativas usando especificadores
a <= (7=>’1’, 6=>’0’, 0=>’0’, 1=>’0’, 5=>’1’,4=>’0’, 3=>’0’, 2=>’1’);
a <= (7|5=>’1’, 6|4|3|2|1|0 => ’0’);
a <= (7|5=>’1’, others=>’0’);

a <= "00000000“ -- Asignación con cadena de bits


a <= (others=>’0’); -- Forma alternativa con especificador others
Atributos
• Los atributos son propiedades asociadas a ciertos elementos, tales
como señales o variables, que proporcionan información adicional
acerca del elemento
• El acceso a los atributos se realiza mediante la comilla simple (‘)
Formato:
nombre_objeto'nombre_atributo

• Existen varios atributos predefinidos, pero también es posible definir


atributos personalizados
– El atributo event es uno de los más usados y devuelve un valor de
verdadero o falso para indicar si una señal ha cambiado de valor

-- Ejemplo de uso del atributo event


-- Detecta si ocurre un flanco de subida en una señal
-- (la señal ha pasado de 0 a 1)
if (clk'event and clk = '1') then
… -- bloque de instrucciones
end if;
Bibliotecas
• Las bibliotecas contienen descripciones de componentes organizados en paquetes,
que pueden ser importados y reutilizados en otros diseños
– IEEE ha desarrollado varios paquetes para representación y operaciones con diferentes
tipos numéricos, ej: std_logic_1164, std_logic_signed, std_logic_unsigned, numeric_std, etc.
• Para utilizar los componentes contenidos en una biblioteca, se emplean las
instrucciones library y use, para incorporar la biblioteca y acceder a sus paquetes y
componentes, respectivamente:

library nombre_biblioteca;
use biblioteca.paquete.componente;

-- Ejemplo del uso de bibliotecas


library ieee;
use ieee.std_logic_1164.all;

– La primera línea invoca la biblioteca llamada ieee


– La segunda línea hace visible todos los componentes contenidos en el paquete
std_logic_1164
– Es posible acceder a un componente particular de un paquete, sustituyendo el
especificador all por el nombre de la entidad del componente de interés
Entidad
• La entidad es la representación abstracta de una unidad de diseño,
componente o bloque básico de construcción de un circuito
• La declaración de una entidad establece la interfaz del componente a
través de sus puertos de entrada y salida
– Equivalente a la “caja negra” del componente
• Cada entidad tiene una o más arquitecturas asociadas

entity nombre_entidad is
port(
nombre_puerto: modo tipo_dato;
nombre_puerto: modo tipo_dato;
... -- Ejemplo de declaración de entidad
); entity Componente is
end nombre_entidad; port(
a: in STD_LOGIC;
b: in STD_LOGIC_VECTOR (2 downto 0);
f: out STD_LOGIC
);
end Componente;
Arquitectura
• En la arquitectura se describe el comportamiento o funcionamiento interno
del componente o circuito
• La arquitectura está asociada a la entidad que describe
– Pueden existir varias arquitecturas asociadas con una misma entidad
• Existen dos partes dentro del código de una arquitectura:
– El área comprendida entre la cabecera y begin está destinada para declarar
objetos que serán utilizados en la descripción
– El área delimitada entre begin/end que es donde se realiza la descripción del
diseño

architecture nomb_arquitectura of nomb_entidad is


declaraciones
begin
… -- conjunto de instrucciones
end nomb_arquitectura;

-- Ejemplo de descripción de arquitectura


architecture Descripcion1 of Componente is
signal temp: STD_LOGIC;
begin
temp <= (b(2) AND b(1) AND b(0)) OR a;
f <= NOT(temp);
end Descripcion1;
Tipos de Instrucciones
• Instrucciones Concurrentes
– Se interpretan simultáneamente, en forma similar a como funcionan los
diferentes componentes de un circuito o dispositivo real
• No importa el orden en que son escritas en el programa

-- Ejemplo de instrucciones concurrentes


f1 <= a AND b;
s <= c + d;
U1: Comparador port map(x, y, result);

• Instrucciones Secuenciales
– Son ejecutadas una a continuación de la otra, de acuerdo con un orden
específico
• En VHDL solo pueden utilizarse dentro de un proceso (bloque process)

-- Ejemplo de instrucciones secuenciales


process(a, b)
begin
if (a > b) then
v1 <= ‘1’;
else
v1 <= ‘0’;
end if;
v2 <= NOT(a);
end process;
Procesos
• El proceso es el bloque básico de ejecución secuencial
• Los procesos contienen instrucciones secuenciales que permiten modelar el
comportamiento de un circuito
– Dentro de los procesos es posible declarar y utilizar variables
• El proceso tiene una lista de sensitividad, conformada por un conjunto de señales
– Cuando el valor de una señal en la lista cambia, se activa el proceso
– Las asignaciones de señales que aparezcan dentro de un proceso solo se hacen efectivas al
finalizar la ejecución del mismo; las asignaciones de variables son inmediatas
• Un proceso equivale a una única instrucción concurrente
– Cuando una arquitectura tiene varios procesos, estos son interpretados simultáneamente
• El proceso se declara con la palabra reservada process

process (lista_de_sensitividad)
… -- Declaraciones de señales o variables -- Ejemplo de proceso
begin process(clk, clr)
… -- Instrucciones secuenciales signal q : STD_LOGIC;
begin
end process;
if clr = ‘1’ then
q <= ‘0’;
elsif clk’event AND clk = ‘1’ then
q <= D;
end if;
end process;
Estilos de Descripción
• VHDL soporta tres estilos para la descripción del diseño
en el cuerpo de una arquitectura:
– Flujo de datos (Data Flow): se representa como fluyen los
valores que transportan las señales desde las entradas hacia las
salidas del circuito
– Estructural (Structural): el diseño se describe en base a la
existencia de componentes o módulos que realizan funciones
específicas y la forma como se interconectan entre sí a través
de sus puertos para obtener las salidas deseadas
– Comportamiento (Behavioral): se utilizan los elementos e
instrucciones del lenguaje para expresar en forma algorítmica la
forma como se comporta o funciona el circuito

• Generalmente, los diseños se realizan en un estilo mixto


que combina varios de los estilos mencionados
anteriormente
Descripción de Flujo de Datos
• Consiste en especificar como son transferidos los valores lógicos de
los datos desde las entradas hasta las salidas del circuito, a través
de las diferentes señales que existen en el mismo
– Se emplean únicamente instrucciones concurrentes de asignación simple o
asignación condicional

-- Ejemplo de descripción de flujo de datos

-- Declaración de la entidad Circuito


… -- Entradas: A, B, Sel; Salida: F

-- Descripción de la arquitectura
architecture Circuito1 of Circuito is
signal S1, S2, S3 : STD_LOGIC;
begin
S3 <= Sel and B;
S2 <= S1 and A;
S1 <= not(Sel);
F <= S2 or S3;
end Circuito1;
Descripción Estructural
• Una descripción estructural se realiza usando el concepto de
“componente”
– Un circuito está constituido por componentes más pequeños que realizan
funciones específicas y especializadas
– La descripción indica los tipos de componentes y sus conexiones
– Es esencialmente una descripción textual de un diseño esquemático
• El diseño se realiza en dos fases:
1. Se declaran los componentes; instrucción component
2. Se instancian los componentes; instrucción port map
• La instanciación de componentes es un tipo de instrucción concurrente y puede ser
mezclada con otros tipos de instrucciones

Declaración de componentes
Instancia de componentes
component nombre_componente
port( [etiqueta :] nombre_componente
nombre_puerto: modo tipo_dato; port map(
nombre_puerto: modo tipo_dato; nombre_puerto => señal,
... nombre_puerto => señal,
); ...
end component; );
Ejemplo de Declaración Estructural
-- Ejemplo de descripción estructural

-- Declaración de la entidad Circuito


… -- Entradas: A, B, Sel; Salida: F

-- Descripción de la arquitectura
architecture Circuito2 of Circuito is

-- Declaración de componentes y señales


component INV port (I : in STD_LOGIC;
O : out STD_LOGIC);
component AND2 port (I1, I2 : in STD_LOGIC;
O : out STD_LOGIC);
B
I1 S3 component OR2 port (I1, I2 : in STD_LOGIC;
AND2 O O : out STD_LOGIC);
I2 I1
Sel OR2 O F signal S1, S2, S3 : STD_LOGIC;
I2
begin
S1 -- Instancias de componentes
I INV O
I1
U1: INV port map(I => Sel , O => S1);
AND2 O U2: AND2 port map(I1 => B, I2 => Sel, O => S3);
I2
S2 U3: AND2 port map(I1 => S1, I2 => A, O => S2);
A
U4: OR2 port map(I1 => S2, I2 => S3, O => F);
end Circuito2;
Descripción de Comportamiento
• Se utilizan algoritmos que describen el comportamiento del circuito
mediante instrucciones contenidas en un bloque de ejecución
secuencial (proceso)
– Una descripción de este estilo involucra la declaración de al menos un proceso
– Existen instrucciones para selección, repetición o sincronización del flujo de
ejecución

-- Ejemplo de descripción de comportamiento

-- Declaración de la entidad Circuito


… -- Entradas: A, B, Sel; Salida: F

-- Descripción de la arquitectura
architecture Circuito3 of Circuito is
begin
process (Sel, A, B)
0F=A if (Sel = ‘0’) then
F <= A;
Sel = else
F <= B;
1F=B end if;
end process;
end Circuito3;
Formatos de Instrucciones Usuales
Asignaciones Condicionales Instrucciones de Selección
(Concurrentes) (Secuenciales)

Asignación con condicional When/Else


Condicional If/Then/Else
señal <= valor1 when condición1 else
if condición1 then
valor2 when condición2 else
… -- instrucciones
...
elsif condición2 then
else valor_por_defecto;
… -- instrucciones
Asignación selectiva con With/Select/When elsif condición3 then
… -- instrucciones
with señal1 select else
señal2 <= valor1 when valor1_señal1, … -- instrucciones
valor2 when valor2_señal1, end if;

valorn when others ; Selección Case

case señal_condición is
when valor1 =>
Instrucciones de Repetición
… -- instrucciones
(Secuenciales)
when valor2 =>
Ciclo For/Loop Ciclo While/Loop
… -- instrucciones
for variable in rango loop while condición loop when others =>
… -- instrucciones … -- instrucciones … -- instrucciones
end loop; end loop; end case;
Ejemplos de Entidades
a -- Declaración de la entidad

Componente1
d entity Componente1 is
port(a, b, c : in std_logic;
b d, e : out std_logic);
c e end Componente1;

a1 -- Declaración de la entidad

Componente2
Componente2

2
a 2 a0 c1
entity Componente2 is


port(a : in std_logic_vector(1 downto 0);
c b : in std_logic_vector(1 downto 0);
2 b1 c0
b c : out std_logic_vector(1 downto 0));
b0 end Componente2;

Q3 -- Declaración de la entidad
Componente3

Componente3

rst rst
4 Q2 entity Componente3 is
up Q≡ up
Q1
port(rst, up, clk : in std_logic;
Q : out std_logic_vector(3 downto 0));
clk clk end Componente3;
Q0
Programa Ejemplo
-- Encabezado -- -- … continuación
library IEEE;
use IEEE.std_logic_1164.all; -- Declaración de señales --
signal digit : STD_LOGIC_VECTOR (3 downto 0);
-- Declaración de entidad -- signal s : STD_LOGIC_VECTOR (1 downto 0);
entity mux7seg is signal x : STD_LOGIC_VECTOR (15 downto 0);
port( begin
btn : in STD_LOGIC_VECTOR(3 downto 0); x <= X"1234";
a_to_g : out STD_LOGIC_VECTOR(6 downto 0);
an : out STD_LOGIC_VECTOR(3 downto 0) -- Instancias de componentes --
); U1 : mux44 port map(s => s, x => x, z => digit);
end mux7seg; U2 : hex7seg port map(a_to_g => a_to_g, x => digit);

-- Descripción de la arquitectura -- s(0) <= btn(3) or btn(1);


architecture mux7seg of mux7seg is s(1) <= btn(3) or btn(2);
an(0) <= not(btn(0));
-- Declaración de componentes -- an(1) <= not(btn(1));
component hex7seg an(2) <= not(btn(2));
port ( an(3) <= not(btn(3));
x : in STD_LOGIC_VECTOR(3 downto 0); end mux7seg;
a_to_g : out STD_LOGIC_VECTOR(6 downto 0)
);
end component;
component mux44
port (
s : in STD_LOGIC_VECTOR(1 downto 0);
x : in STD_LOGIC_VECTOR(15 downto 0);
z : out STD_LOGIC_VECTOR(3 downto 0)
);
end component;

You might also like