Sei sulla pagina 1di 139

Departamento de Tecnología Electrónica

E.T.S. Ingeniería de Telecomunicación


Universidad de Málaga

VHDL
orientado a síntesis
en FPGAs

Pelegrín Camacho Lozano

Ed. Octubre 2012


ÍNDICE
INTRODUCCIÓN v
1. MODELOS Y UNIDADES DE DISEÑO EN VHDL I-1
1.1 DECLARACIÓN DE "ENTITY" 2
1.2 DESCRIPCIÓN DE "ARCHITECTURE" 3
1.3 "LIBRARY" o BIBLIOTECAS EN VHDL 6
1.4 DECLARACIÓN DE "PACKAGE" 7
1.5 DECLARACIÓN DE "PACKAGE BODY" 8
1.7 DECLARACIÓN DE "CONFIGURATION" 9

2. CARACTERÍSTICAS GENERALES DEL VHDL II - 1


2.1 LÉXICO DE FICHEROS VHDL 1
2.1.1 SEPARADORES 1
2.1.2 DELIMITADORES 1
2.1.3 COMENTARIOS 1
2.1.4 IDENTIFICADORES 1
2.1.5 PALABRAS RESERVADAS 2
2.1.6 CARACTERES LITERALES 2
2.1.7 CADENAS LITERALES 2
2.1.8 CADENAS BIT LITERALES 2
2.1.9 LITERALES NUMÉRICOS 3
2.2 CLASES DE OBJETOS : DECLARACIÓN E INICIALIZACIÓN 3
2.2.1 CONSTANTES 3
2.2.2 VARIABLES 3
2.2.3 SEÑALES 4
2.3 ASIGNACIÓN DE VALORES 4
2.3.1 ASIGNACIÓN A VARIABLES 4
2.3.2 ASIGNACIÓN A SEÑALES 6
2.4 TIPOS DE OBJETOS 5
2.4.1 TIPOS ENUMERADOS 5
2.4.2 TIPOS NUMÉRICOS 6
2.4.3 TIPOS FÍSICOS 6
2.4.4 ARRAYS 6
2.5 SUBTIPOS 8
2.6 TIPOS STD_LOGIC 9
2.7 ATRIBUTOS PREDEFINIDOS DE TIPOS Y ARRAY'S 10
2.7.1 ATRIBUTOS DE TIPOS 10
2.7.2 ATRIBUTOS DE ARRAYS 11
2.8 OPERADORES Y EXPRESIONES 12
2.8.1 OPERADORES LÓGICOS : AND OR NAND NOR XOR 12
2.8.2 OPERADORES RELACIONALES : = /= < <= > >= 13
2.8.3 OPERADORES DE ADICIÓN :+ - & 13
2.8.4 OPERADORES DE PRODUCTO : * / MOD REM 13
2.8.5 OPERADORES DE SIGNO : + - 14
2.8.6 OPERADORES MISCELANEOS : ** ABS NOT 14
2.9 SOBRECARGA DE TIPOS Y OPERADORES 14

3. SENTENCIAS CONCURRENTES III - 1


3.1 SENTENCIAS DE COLOCACIÓN DE COMPONENTES 1
3.2 SENTENCIAS PROCESS 2
3.2.1 RETARDO Y CONCURRENCIA EN EL ENTORNO DE PROCESS 3
3.3 SENTENCIAS DE ASIGNACIÓN DE VALOR A SEÑALES 6
3.3.1 RETARDOS INERCIALES Y DE TRANSPORTE 6
3.3.2 ASIGNACIONES CONDICIONALES 7
3.3.3 ASIGNACIONES SELECTIVAS 9
3.3.4 ATRIBUTOS DE SEÑALES 10
3.4 SENTENCIAS ASSERT 13
3.5 SENTENCIAS GENERATE 14

índice - iii
4. SENTENCIAS SECUENCIALES IV - 1
4.1 SENTENCIAS IF 1
4.1.1 Inferencias básicas de sentencias IF en síntesis VHDL 4
4.2 SENTENCIAS CASE 8
4.3 SENTENCIAS NULL 9
4.4 SENTENCIAS LOOP 10
4.4.1 LOOP SIMPLE 10
4.4.2 LOOP FOR 10
4.4.3 LOOP WHILE 10
4.5 SENTENCIAS NEXT 11
4.6 SENTENCIAS EXIT 12
4.7 SENTENCIAS ASSERT 13
4.8 SENTENCIAS WAIT 14
4.7.1 WAIT ON señales 14
4.7.2 WAIT UNTIL condición 14
4.7.3 WAIT FOR especificación de tiempo 14

5. SUBPROGRAMAS IV - 1
5.1 FUNCIONES 1
5.1.1 FUNCIONES DE RESOLUCIÓN 5
5.1.2 TIPOS STD_LOGIC. EMPAQUETAMIENTO IEEE 1164 9

6. MODELOS ESTRUCTURALES VI - 1
6.1 ESPECIFICACIONES DE CONFIGURACIÓN 1
6.2 DECLARACIÓN DE CONFIGURACIÓN 3
6.3 APLICACIÓN DE SENTENCIAS GENERATE 5
6.4 DESARROLLO DE PROBADORES 8

7. MODELOS DE COMPORTAMIENTO VII - 1


7.1 DESCRIPCIONES A NIVEL DE FLUJO DE DATOS 1
7.2 DESCRIPCIONES ALGORÍTMICAS 4
7.3 DESCRIPCIONES ALGORÍTMICAS PARA SÍNTESIS 4
7.4 INFERENCIAS BÁSICAS DE SÍNTESIS 5
7.5 MÁQUINAS DE ESTADOS FINITOS 10
7.5.1 MÁQUINA DE MEALY 11
7.5.2 MÁQUINA DE MOORE 14

8. INTRODUCCIÓN A LOS MODELOS ARITMÉTICOS VIII - 1


8.1 TIPOS Y PAQUETES ARITMÉTICOS EN VHDL 1
8.2 OPERACIONES CON UNSIGNED INTEGERS 2
8.3 OPERACIONES CON SIGNED INTEGERS 6

APÉNDICE A SÍNTESIS Y SIMULACIÓN DE MODELOS VHDL CON MAX+PLUS II

APÉNDICE B SÍNTESIS Y SIMULACIÓN DE MODELOS VHDL CON QUARTUS II

APÉNDICE C RELACIÓN INTEGRAL DE MODELOS

BIBLIOGRAFÍA

índice - iv
INTRODUCCIÓN

El Lenguaje de Descripción Hardware VHDL es un conjunto de recursos que permite a


sus usuarios dimensionar un HDL o lenguaje de descripción hardware acorde a sus necesidades.
La posibilidad de modelar circuitos con estructuras jerárquicas, desde el nivel de puertas hasta
niveles algorítmicos, la definición de tipos, operadores y subprogramas, el uso de paquetes
definidos por los usuarios, etc. han convertido al VHDL en un estándar de facto a nivel mundial,
desde los aspectos de descripción y simulación, para los que inicialmente se pensó, hasta los de
síntesis y desarrollo de sistemas basados en ASICs - Application Specific Integrated Circuits - y
FPGAs - Field Programmable Gate Arrays donde, efectivamente, se usa con limitación de sus
sentencias o posibilidades de modelado. Así sucede, prácticamente, con todas las herramientas
de síntesis e incluso en algunas de simulación, en las que solamente una parte de los recursos
están soportados, lo que es un cierto problema, porque no siempre son los mismos conjuntos,
formatos o inferencias de síntesis los que hay en las herramientas CAD disponibles.

En VHDL, como en cualquier idioma o lenguaje, no es preciso ser un experto para poder
expresarse y realizar modelos que sean aceptados por los compiladores poco tiempo después de
conocer los conceptos básicos. El primer pequeño problema es que, como en tantos otros
conocimientos, hay que aprenderlo secuencialmente mientras que para utilizarlo bien deberían
aprenderse muchos conceptos concurrentemente, dicho en términos VHDL que pronto se verán.
Al parecer, las opiniones de diversos autores no son coincidentes en el orden de presentar
conceptos y ejemplos, según se deduce al comparar los índices de temas en distintos libros sobre
VHDL. En cualquier caso, practicar con un programa de simulación y analizar las respuestas
ayudará mucho en la fase de aprendizaje, tanto para resolver las dudas iniciales como para ver
defectos de diseño y plantearse diseños más eficientes, un concepto poco claro que debiera
entenderse como en cualquier proyecto por la calidad o robustez del modelo, seguido del coste y
del tiempo para su desarrollo.

Esta publicación, titulada “VHDL orientado a síntesis en FPGAs”, sin hacer una
cobertura amplia y detallada con muchas páginas más, pretende ser algo más que una simple
introducción al VHDL “a complementar con los mensajes de error que dará el compilador” que,
sin duda, también enseñan, aunque no sean el mejor método para aprenderlo.
En la redacción se han considerado los conceptos fundamentales del VHDL para entender
las secciones 6, 7 y 8 y desarrollar los modelos que, a nivel académico, serán suficientes para la
realización de proyectos de sistemas digitales basados en FPGAs, utilizando herramientas de
síntesis. También se ha considerado que el aprendizaje y la práctica del VHDL requieren ya
bastante esfuerzo de abstracción como para tener que hacerlo en un idioma distinto del materno.

Solo resta desearle al lector que la publicación le resulte útil y la presentación eficiente.

El Autor

Málaga, Octubre de 2012

v
vi
1 - Modelos y unidades de diseño en VHDL
El modelo de un sistema varía según el estado del diseño y el uso a que se destina el
modelo. Inicialmente, el modelo de un sistema es un conjunto de especificaciones generales
de diversa índole. A partir de esas especificaciones generales, por una estrategia de diseño
top-down, el sistema se particiona en una serie de niveles sucesivos, siguiendo una
estructura jerárquica o árbol que representa al sistema. El proceso posterior de integración
del sistema consistirá en el ensamble o interconexión de los subsistemas siguiendo una
estrategia bottom-up. Normalmente, el desarrollo de modelos de un sistema moderno
consiste en una mezcla de las dos estrategias: descomponer el sistema en bloques en un
proceso top-down e integrar en los subsistemas modelos de nuevo desarrollo junto con otros
disponibles como resultado de desarrollos previos.
En cualquier caso, al plantearse el desarrollo del modelo de un subsistema, a cualquier
nivel dentro de la jerarquía del sistema, se consideran dos aspectos básicos:

 Estructura, definida por componentes, puertos y señales.

 Componentes son elementos - puerta, chip, módulo, etc. - cuya complejidad estará
relacionada al nivel del subsistema dentro de la estructura del sistema.
 Puertos son las interfaces por los que el elemento se interconecta a los puertos de otros
elementos para formar la estructura del nivel jerárquico que lo contiene.
 Señales son los nombres asignados a las rutas que interconectan componentes a través
de sus puertos, relacionando estructuras y comportamientos de los modelos.

 Comportamiento o funcionalidad del subsistema, definida como relación temporal


entre respuestas y estímulos que las provocan, es decir, la función de transferencia y
los retardos asociados, si los hay.

En VHDL, un sistema digital se representa como una ENTITY en la que se aplican los
conceptos anteriores al modelarla. Para esto se la considera definida con dos unidades de
diseño o descripciones interrelacionadas: la declaración de ENTITY y la descripción
funcional o ARCHITECTURE. Estos son los dos pilares básicos sobre los que se construyen
todas las descripciones en VHDL.
Las unidades de diseño son bloques de código que pueden ser compiladas y
almacenadas separadamente en alguna biblioteca - o LIBRARY- por lo que, a veces, se las
conoce como library units. Además de ENTITY y ARCHITECTURE, obligatorias en cualquier
descripción VHDL, existen otras tres unidades de diseño: PACKAGE, PACKAGE BODY y
CONFIGURATION, pero estas tres son opcionales.

ARCHITECTURE y PACKAGE BODY se consideran unidades de diseño secundarias,


asociadas, respectivamente, a unidades de diseño primarias como ENTITY y PACKAGE, sin
las que no tienen sentido las unidades secundarias asociadas. CONFIGURATION es
considerada como una unidad de diseño primaria.

I-1
1 - Modelos y unidades de diseño en VHDL

1.1 DECLARACIÓN DE “ENTITY”

Asigna nombre identificador a un elemento y describe su interfaz como un conjunto


de señales a las que se les asigna nombre, modo -entrada, salida, bidireccional- y tipo.
En su formato más simple la declaración de ENTITY es como sigue:

ENTITY identificador IS
PORT (lista_de_señales: modo tipo);
END identificador;

Por ejemplo, la declaración de ENTITY para unas puertas AND y OR podría ser:

ENTITY and2 IS ENTITY or2 IS


PORT (e1, e2: IN BIT; sal: OUT BIT); PORT (e1, e2: IN BIT; sal: OUT BIT);
END and2; END or2;

Los tipos se refieren a la estructura o características de las señales que se definen en la


ENTITY. En el ejemplo son BIT. En VHDL, el usuario puede definir sus propios tipos.

Nótese que, aparte de la diferencia de nombres de las ENTITYs, las interfaces definidas
tras las cláusulas PORT son iguales, es decir, no se hace referencia alguna a la función o
comportamiento de los elementos.
Los puertos pueden ser de cuatro modos:

IN : Para puertos de entrada a la ENTITY.


OUT : Para puertos de salida de la ENTITY.
INOUT : Para puertos bidireccionales.
BUFFER : Para puertos con driver único y conectables a nodos simples.

Los puertos modo IN pueden ser leídos dentro de la ENTITY que los contiene, es decir,
puede tomarse su valor para aplicarlo y obtener resultados, pero no pueden ser escritos
internamente, ya que ello supondría alterar el valor externo con el que acceden las señales a
la ENTITY, como resultado del valor que les asignaron sus drivers
.
Los puertos modo INOUT, al ser bidireccionales, pueden ser escritos o leídos. Es el
caso típico de los puertos conectados a un bus, o los puertos de datos de una memoria RAM.

Los puertos modo OUT tienen una restricción similar a los modo IN: El valor de un
puerto modo OUT puede ser escrito internamente, es decir, se le puede asignar un valor por
medio de unos drivers, que será el valor que sale del puerto de la ENTITY y, por tanto, el que
la ENTITY aporta al nodo o red a la que el puerto esté conectado. Sin embargo, los puertos
modo OUT no pueden ser leídos internamente dentro de la ENTITY en la que están
declarados. Existen dos razones para esto: la primera es que no habría diferencia entre un
puerto modo OUT y otro modo INOUT y la segunda razón, relacionada a lo que se
denomina valor efectivo o resuelto de una señal. Este concepto distingue entre el valor
individual que un puerto lleva al nodo donde se conecta y el valor presente en ese nodo
como consecuencia de los diferentes puertos que acceden a él. Según la fuerza de las señales
y el valor de las mismas, resultará un valor efectivo de la señal presente en el nodo, que será

I-2
1 – Modelos y unidades de diseño en VHDL

el valor real que puede ser leído. Así, el valor individual presente en una puerta de modo
OUT solo puede garantizar su inalterabilidad si al nodo al que se conecta no llega ninguna
otra señal. Esta restricción es la que define a los puertos de modo BUFFER.

Los puertos de modo BUFFER son puertos de salida cuyo valor está determinado por
un único driver y que no pueden aplicarse a nodos en los que confluya más de una señal, por
ejemplo, una salida tri-estado. Como consecuencia de esta restricción, los puertos BUFFER
pueden ser leídos dentro de la ENTITY en que se les asigna valor. Sin embargo, la restricción
hace que el empleo de este tipo de puertos sea poco frecuente.

1.2 DESCRIPCIÓN DE “ARCHITECTURE”

Las ARCHITECTUREs son unidades de diseño secundarias referenciadas en VHDL


con la palabra reservada ARCHITECTURE y se definen para una ENTITY, o unidad de diseño
primaria y describen el comportamiento, la funcionalidad o la estructura de la ENTITY.
Nótese que un elemento con una interfaz determinada puede tener distintas
ARCHITECTUREs dentro de una misma funcionalidad, lo que equivale a diferentes formas de
realizar la función, utilizando distintas configuraciones o interconexiones de elementos o,
tal vez , describiendo el funcionamiento de la ENTITY directamente, como un elemento
primitivo.

Si imaginamos la descripción inicial de un elemento, en la fase de especificación de


un diseño, la descripción de funcionamiento es casi siempre algorítmica, por lo que cabe
pensar que posibles ARCHITECTUREs algorítmicas de las puertas and2 y or2, podrían ser:
ARCHITECTURE comport OF and2 IS ARCHITECTURE comport OF or2 IS

BEGIN BEGIN
PROCESS (e1, e2) PROCESS (e1, e2)
BEGIN BEGIN
IF (e1 = ‘1’) AND (e2 = ‘1’) THEN IF (e1 = ‘0’) AND (e2 = ‘0’) THEN
sal <= ‘1’; sal <= ‘0’;
ELSE sal <= ‘0’; ELSE sal <= ‘1’;
END IF; END IF;
END PROCESS; END PROCESS;
END comport; END comport;

A cualquier nivel, un elemento o subsistema se deberá modelar según el uso a que se


vaya a destinar el modelo, por ejemplo, para simulación, para documentar sus
especificaciones y uso posterior, para síntesis, etc. Así, aún sin conocer la estructura de las
descripciones VHDL, podemos comparar tres ARCHITECTUREs diferentes de un mismo
circuito digital sencillo, un sumador de bits, cuya declaración de ENTITY es:

ENTITY sumador IS
PORT ( x,y,ci : IN BIT; sum, co : OUT BIT);
END sumador;

La primera ARCHITECTURE hace una descripción funcional, indicando el flujo de datos:

I-3
1 - Modelos y unidades de diseño en VHDL

ARCHITECTURE funcional OF sumador IS


x s1
SIGNAL s1,s2,s3 : BIT;
y sum
BEGIN
s1 <= x XOR y; ci s2
sum <= s1 XOR ci AFTER 10 ns; co
s2 <= s1 AND ci;
s3 <= x AND y;
co <= s2 OR s3 AFTER 12 ns; s3
END funcional;

Hay una correspondencia directa entre la descripción VHDL y las puertas con las que
se realiza el sumador, según el circuito adjunto. Como se verá con detalle más adelante, se
declaran las señales internas s1,s2,s3 indicando su tipo -BIT- , en una zona reservada a
declarar objetos locales a la ARCHITECTURE e inmediatamente se describe la funcionalidad
de la ENTITY, expresando por medio del delimitador <= utilizado para asignar valor a
señales, la relación entre señales de salida, sum y co , con las señales internas s1,s2,s3
queestán relacionadas a las de entrada x, y, ci utilizándo las funciones XOR, AND y OR.

La segunda ARCHITECTURE que se muestra hace una descripción estructural:

ARCHITECTURE estructural OF sumador IS

COMPONENT AND_2 PORT (e1,e2 : IN BIT; sal: OUT BIT); END COMPONENT;
COMPONENT OR_2 PORT (e1,e2 : IN BIT; sal: OUT BIT); END COMPONENT;
COMPONENT XR_2 PORT (e1,e2 : IN BIT; sal: OUT BIT); END COMPONENT;

SIGNAL s1,s2,s3 : BIT; -- declaración de señales internas

BEGIN
P1: xr_2 PORT MAP (x,y,s1); -- instantiation statements
P2: xr_2 PORT MAP (s1,ci,sum); -- sentencias de colocación o
P3: and_2 PORT MAP (s1,ci,s2); -- sentencias de mapeo posicional
P4: and_2 PORT MAP (x,y,s3);
P5: or_2 PORT MAP (sal => co, e1 =>s2, e2 => s3);
END estructural;
Es la que describe con más detalle la estructura del sumador, ya que indica a nivel de
puertas una realización concreta del circuito:

 Obsérvese que declara las mismas señales internas - s1, s2, s3- que se declararon en la
ARCHITECTURE funcional.

 Es evidente que este tipo de ARCHITECTURE requiere un diseño previo de hardware, para
establecer las interconexiones entre señales de ENTITY sumador - x, y, ci, sum, co -, las
señales internas o locales - s1, s2, s3 - y las interfaces de las ENTITY s primitivas que se
utilizan como componentes disponibles, sobre las que aquí se hace un mapeo posicional
de todas las señales por medio de las sentencias con las cláusulas PORT MAP.

Se pueden hacer dos tipos de asociaciones:

I-4
1 – Modelos y unidades de diseño en VHDL

1. Asociación posicional: usa señales reales de la ARCHITECTURE, asociadas a


puertos locales por el orden posicional en la declaración del componente:
P1: xr2 PORT MAP(x, y, s1); -- Orden de señales fijado por componente

2. Asociación nominal: relaciona explícitamente señales locales y reales por medio


del delimitador =>, con el formato local => real , por ejemplo :
P5 : or2 PORT MAP (sal => co, e1 =>s2, e2 => s3);

Al ser explícita, puede alterarse el orden de las señales en las declaraciones.

 Usa COMPONENTs locales que podrían estar disponibles en unidades de diseño


denominadas con la palabra reservada PACKAGE en VHDL. Para acceder a ellas se
deberían hacer visibles por la cláusula USE que debe preceder a la ARCHITECTURE.
 Este tipo de ARCHITECTUREs permite optimizar la configuración de un diseño y elegir
la ARCHITECTURE más idónea de cada ENTITY que interviene en el diseño bottom-up.
La tercera ARCHITECTURE es de tipo algorítmico y, aunque su comportamiento puede
intuirse, requiere un conocimiento de sentencias secuenciales que se verán con más detalle
en una sección posterior. Nótese la ausencia de referencias a hardware.
ENTITY sumador_comp IS
PORT ( x,y,ci : IN BIT; sum, co : OUT BIT);
END sumador_comp;
ARCHITECTURE comportamiento OF sumador_comp IS
BEGIN
PROCESS ( x,y,ci)
VARIABLE var : BIT_VECTOR (1 TO 3);
VARIABLE ind : INTEGER RANGE 0 TO 3;
VARIABLE suma, carry : BIT;
BEGIN
ind := 0;
var := x & y & ci;
FOR i IN 1 TO 3 LOOP
IF (var(i)) ='1' THEN ind := (ind+1);
END IF;
END LOOP;
CASE ind IS
W HEN 0 => suma := '0';carry := '0';
W HEN 1 => suma := '1';carry := '0';
W HEN 2 => suma := '0';carry := '1';
W HEN 3 => suma := '1';carry := '1';
END CASE;
sum <= suma; co <= carry;
END PROCESS;
END comportamiento;

Aunque las tres ARCHITECTUREs son del mismo sumador, es interesante comparar las
inferencias de síntesis de cada una, es decir, los recursos requeridos al sintetizar con la
misma herramienta y la misma FPGA, y si ésta es “de grano fino”, mejor la comparación.

I-5
1 - Modelos y unidades de diseño en VHDL

1.3 “LIBRARY” o BIBLIOTECAS en VHDL

Después de describir un modelo, la tarea inmediata es realizar un análisis para


comprobar que el código escrito es correcto, para lo que se verifica normalmente:

 Léxico: Solo puede tener caracteres permitidos: No puede haber Ñ o ñ, por ejemplo.
 Sintaxis: Por ejemplo, si se ha utilizado BEGIN o IF, debe existir un END o END IF.
 Semántica: Se buscan inconsistencias en la descripción, por ejemplo, a un objeto de
tipo BIT, se puede asignar ‘1’ o ‘0’, pero no 1 ni 0, ya que estos son tipo INTEGER.

El resultado de estos análisis se almacena en bibliotecas -traducción del vocablo


inglés “library”, con significado muy diferente al castellano “librería” que no debería
usarse- codificado en un formato apropiado para acceso por otras herramientas y para uso en
otras aplicaciones tales como simulación, síntesis, etc. o para realizar nuevos análisis y
utilizar los resultados en otras descripciones. En VHDL, las bibliotecas son el recurso
necesario del que se dispone en el entorno de trabajo para poder compartir las unidades de
diseño, reutilizar diseños anteriores y llevar a cabo tareas de integración o configuración de
subconjuntos, haciéndolos accesibles a los distintos usuarios y permitiendo que los modelos
de un cierto nivel jerárquico no necesiten incluir el código de los submodelos, sino que sea
suficiente hacer referencia a la biblioteca donde están descritos.
En VHDL existen dos bibliotecas predefinidas: la biblioteca STD y la WORK.
La STD está visible de forma implícita y no es necesario referirse a ella. Contiene los
paquetes STANDARD y TEXTIO. La biblioteca WORK es aquella donde se almacenan los
resultados de los análisis en curso y, al utilizarla por defecto, no es necesario llamarla.
Además, en VHDL se pueden usar las bibliotecas de recursos, a las que se accede para
referencia de datos pero en las que no se puede escribir de manera directa.
Las bibliotecas son subdirectorios o ficheros de un host, cuyo sistema operativo los
gestiona con un nombre físico. Desde el lado del usuario de VHDL, las bibliotecas se
identifican con un nombre lógico, con el cual se accede a ellas o se las hace visibles, por
medio de sentencias basadas en la cláusula USE, reservada en VHDL a este fin. La relación
entre el nombre físico y el lógico es un aspecto a contemplar desde el sistema operativo del
host, para lo cual no hay intervención del usuario de VHDL.
A las bibliotecas de recursos se accede con la palabra reservada LIBRARY, por
ejemplo:
LIBRARY chips;

La cláusula USE puede utilizarse de tres formas, con la notación de punto (.):
USE LIBRARY. paquete; USE chips. puertas;
USE paquete. objeto; USE puertas. and2;
USE LIBRARY. paquete. objeto; USE chips.puertas.and2;

en las que el nombre -sufijo- que sigue al punto (.) debe estar declarado o contenido en el
paquete o biblioteca -prefijo- que precede al mismo punto. Como alternativa para evitar
referencias largas o listas de objetos, es posible usar la cláusula .ALL; que visualiza todo lo
declarado o contenido en su prefijo.

I-6
1 – Modelos y unidades de diseño en VHDL

1.4 DECLARACIÓN DE “PACKAGE”

Cuando se tienen diseños de gran tamaño es conveniente particionar el modelo en


varios ficheros o unidades de diseño que puedan analizarse y compilarse separadamente,
manteniéndolas accesibles para los diferentes usuarios y diseñadores, para poder compartir
los desarrollos y recursos comunes y asegurar la compatibilidad de los desarrollos.
En VHDL existen cinco unidades de diseño compilables separadamente, de las que ya
se han mencionado dos, ENTITY y ARCHITECTURE. Sin embargo, desde un punto de vista de
orden en la compilación, la primera unidad a compilar es la declaración del PACKAGE,
paquete o paquete, particularmente, si en él se declaran tipos o componentes que vayan a
usarse en la ARCHITECTURE
La función de la declaración del PACKAGE es contener las declaraciones de elementos
que se repiten con cierta frecuencia en otras unidades de diseño, a fin de evitar la repetición
de código y reducir así el tamaño de las descripciones o ficheros VHDL. Su estructura es:
PACKAGE identificador IS
declaraciones de tipos, constantes, componentes, subprogramas, etc.
END identificador;

Las declaraciones más habituales son las de tipos, subprogramas y componentes.


Para que otras unidades de diseño puedan utilizar las declaraciones contenidas en el
paquete, éste deberá ser analizado y compilado previamente en bibliotecas, que serán
accesibles o visibles por medio de la cláusula USE, con el formato genérico:
USE identificador_de_biblioteca. identificador_de_package. ALL;

así, por ejemplo, en la ARCHITECTURE estructural del sumador la sentencia


USE WORK.modelos. ALL;

haría visibles los componentes xr2, or2 y and2 declarados en el paquete denominado
“modelos” dentro de la biblioteca WORK , con el siguiente formato:

PACKAGE modelos IS
COMPONENT and_2 PORT (e1,e2 : IN BIT; sal: OUT BIT); END COMPONENT;
COMPONENT or_2 PORT (e1,e2 : IN BIT; sal: OUT BIT); END COMPONENT;
COMPONENT xr_2 PORT (e1,e2 : IN BIT; sal: OUT BIT); END COMPONENT;
END modelos;

y evitar la inclusión de los tres componentes en la zona declarativa de la ARCHITECTURE.

La cláusula ALL visualiza todos los componentes del paquete, pero también pueden
utilizarse los formatos siguientes:
USE WORK.modelos. and2;
LIBRARY componentes; USE componentes.modelos.ALL;

La última línea se usaría en caso de tener la biblioteca “componentes” para almacenar el


paquete “modelos”. Como se vio, las bibliotecas especiales hay que visualizarlas con USE.

I-7
1 - Modelos y unidades de diseño en VHDL

Al ser el VHDL un lenguaje en el que el uso de tipos es una característica que afecta a
todos los objetos que contienen un valor, los tipos deberán estar declarados antes de su uso.
Por otra parte, la compatibilidad entre modelos se sustenta en que los objetos usados por los
distintos ficheros y unidades empleen los mismos tipos. Por esto es casi obligado que los
distintos diseñadores implicados en un desarrollo común compartan los paquetes y que estos
sean la primera unidad compilada.
El paquete STANDARD está dentro de la biblioteca STD y contiene la declaración de
los tipos básicos, tales como BIT, BIT_VECTOR, CHARACTER, INTEGER y REAL sin los que
sería imposible escribir código. Por esto, el paquete STANDARD está predefinido y visible
por la cláusula implícita:

USE STD. STANDARD. ALL;

Dado que el paquete STANDARD contiene un número muy reducido de tipos, existe
otro paquete estándar del IEEE: el std_logic_1164, contenido en la biblioteca IEEE. Su
uso requiere el empleo de USE y, por su importancia, se verá con algún detalle más
adelante.

1. 5 DECLARACIÓN DE “PACKAGE BODY”

Son la unidad de diseño secundaria correspondiente a las declaraciones de paquetes.


Puede existir una declaración de paquete que no requiera la existencia de esta unidad
secundaria. Esto ocurre siempre que no haya subprogramas ni constantes diferidas en la
declaración.
Una constante diferida se declara, sin asignarle valor, en la unidad primaria del
paquete y se le asigna en el cuerpo del paquete. De esta forma, si se quiere hacer
simulaciones con distintos valores de esta constante diferida, no será necesario recompilar
todas las declaraciones, sino solo el cuerpo del paquete donde se cambia de valor. Por esto,
la declaración del paquete y su cuerpo son unidades de diseño compilables separadamente.
En VHDL, como se verá más adelante, existen dos tipos de subprogramas: funciones
y procedimientos. En caso de que estos sean de uso frecuente por distintos usuarios será, tal
vez, conveniente incluirlos en los paquetes, para lo que será necesario declararlos en la
unidad primaria y posteriormente definirlos en la unidad secundaria. De forma similar a las
constantes diferidas, las distintas unidades de diseño pueden hacer referencia a
subprogramas declarados en el paquete, pero la operación de los subprogramas es
susceptible de modificaciones, al igual que las constantes diferidas. En tal caso, la
recompilación solo afectaría al cuerpo del paquete y no a la unidad primaria donde está la
declaración. El formato de los cuerpos de paquetes es :

PACKAGE BODY identificador IS


asignación de valor a constantes diferidas
definiciones de subprogramas;
END identificador;

El identificador es el mismo usado para la declaración de PACKAGE.

I-8
1 – Modelos y unidades de diseño en VHDL

1.6 DECLARACIÓN DE “CONFIGURATION”

Cuando se desea simular un diseño como el descrito con la ARCHITECTURE


estructural del sumador en el que existan ARCHITECTUREs alternativas de sus componentes,
en lugar de cambiar la ARCHITECTURE de los componentes en cada simulación, se hace una
descripción genérica de la ARCHITECTURE sin especificaciones de configuración. A cambio
se construye una unidad de diseño, la declaración de configuración, en la que con un
formato anidado se especifican, hasta el nivel jerárquico más bajo que se desee, las ENTITY
o parejas ENTITY / ARCHITECTURE con las que se desea mapear a cada referencia o
colocación de los componentes con los que se desea hacer la simulación. De esta forma, se
mantiene la unidad de diseño de la ARCHITECTURE que se compila una vez y servirá para
todas las simulaciones, pero habrá que recompilar la configuración que resulta para cada
alternativa o combinación de componentes que se desee simular.

La CONFIGURATION es una unidad de diseño primaria, pero debe ser analizada y


compilada después de la ARCHITECTURE a la que se configura. Su formato, para el ejemplo
de la ARCHITECTURE estructural del sumador, podría ser:
USE WORK. ALL;
CONFIGURATION ejemplo_de_config OF sumador IS
FOR estructural
FOR ALL: xr2
USE ENTITY WORK. xor2 (lenta); -- pareja entity (architecture x)
END FOR;
FOR ALL: and2
USE ENTITY WORK. and2 (rapida); -- pareja entity (architecture y)
END FOR;
FOR ordos: or2
USE ENTITY WORK. or2; -- entity solamente y la
END FOR; -- ARCHITECTURE, por defecto
END FOR;
END ejemplo_de_config;

En caso de que un componente se desee configurar para una ARCHITECTURE


específica, se hace referencia a la etiqueta particular de esa colocación, por ejemplo:
FOR P2: xr2
USE ENTITY WORK. xor2 (especial); -- pareja entity (architecture x)
END FOR;

y si después de una etiqueta hasta el resto de ellas, todas las referencias están configuradas
para la misma ENTITY/ARCHITECTURE, puede usarse la cláusula OTHERS:
FOR OTHERS: semisum
USE ENTITY WORK. semisum (lenta); -- pareja entity (architecture x)
END FOR;

La descripción está precedida de USE WORK.ALL; para ver desde la ARCHITECTURE a


todas las ENTITYs y declaraciones de componentes de la configuración.

I-9
2- Características generales del VHDL
En los apartados que se exponen a continuación se revisan las características generales
del lenguaje VHDL en referencia a su léxico, clases, formato y tipos de datos, así como
aquellos conceptos significativos del lenguaje por su orientación para modelar hardware.

2.1 LÉXICO DE FICHEROS VHDL


Una descripción VHDL puede constar de uno o varios ficheros. Cada fichero debe
estar constituido por el siguiente conjunto restringido de elementos del código ASCII-7:

Mayúsculas :ABCDEFGHIJKLMNOPQRSTUVWXYZ
Minúsculas :abcdefghijklmnopqrstuvwxyz
Números :0123456789
Caracteres especiales : “ # & ‘ ( ) * + , - . / : ; < = > _ |  $ % @ ?  \  ^ `  ~
Códigos de formato : Espacio (20), LF(0A), CR(0D), FF(0C), HT(09), VT(0B)

Con esos elementos se pueden confeccionar secuencias de caracteres que forman


elementos fundamentales que no pueden fraccionarse en otros. En VHDL no se diferencia
entre mayúsculas y minúsculas. Los ficheros se componen de esos elementos fundamentales
denominados elementos léxicos, de los que existen varios tipos :

2.1.1 SEPARADORES
Se permite un número variable de separadores entre elementos léxicos adyacentes,
antes del primero y después del último en una línea de texto. Son los códigos de formato.

2.1.2 DELIMITADORES
Caracteres que se usan para separar elementos léxicos y que tienen algún significado
específico en VHDL. Son los caracteres:
& ‘ ( ) * + , - . / : ; < = > |
por ejemplo, todas las sentencias en VHDL terminan con el carácter delimitador ; .
Cuando se habla de delimitadores compuestos se hace referencia a secuencias de
delimitadores con un significado especial en VHDL, por ejemplo:
=> ** := /= >= <= <> --

2.1.3 COMENTARIOS
Son elementos léxicos precedidos del delimitador -- y que finalizan con la línea
donde están. Los comentarios son los últimos elementos léxicos de una línea. Pueden seguir
a una sentencia VHDL existente en la línea o ser el único elemento léxico en la línea.
código VHDL -- comentarios precedidos de doble guión

2.1.4 IDENTIFICADORES
Son palabras reservadas en VHDL o bien los nombres que el diseñador asigna a los
objetos que utiliza en sus descripciones, por ejemplo, para nombrar constantes, variables,
señales, ENTITYs, ARCHITECTUREs, bloques, subprogramas, etc.
Los identificadores son secuencias de caracteres que empiezan por una letra, pueden
incluir letras, números y caracteres de subrayado aislados o sin duplicar
En el código VHDL no se diferencian letras mayúsculas y minúsculas, salvo que estén
entre comillas, en cuyo caso son elementos diferentes de cadenas literales. Debe evitarse el
uso de palabras acentuadas, incluso en los comentarios.

II-1
2 – Características generales del VHDL

2.1.5 PALABRAS RESERVADAS


Son elementos léxicos con algún significado especial en las expresiones del lenguaje,
por lo que no pueden ser utilizados fuera del contexto para el que están reservados. En los
ejemplos de código VHDL de este documento se presentan en MAYÚSCULAS. Son estas:
abs else linkage procedure then
access elsif literal* process to
after end loop pure* transport
alias entity type
all exit map range
and mod record unaffected*
architecture file register units
array for nand reject* until
assert function new rem use
attribute next report
generate nor return variable
begin generic not rol*
block group* null ror* wait
body guarded when
buffer of select while
bus if on severity with
impure* open signal
case in or shared* xnor*
component inertial* others sla* xor
configuration inout out sll*
constant is sra*
package srl*
disconnect label port subtype
downto library postponed*

Se han marcado con un asterisco las añadidas con la revisión VHDL-1993.

2.1.6 CARACTERES LITERALES


Están formados por un solo carácter entre dos delimitadores apóstrofo (‘ ’).
‘X’ ‘x’ ‘%’ ‘‘’ ‘Z’ ‘z’ ‘;’
Nótese que al ir entre apóstrofos, aquí sí se distingue entre ‘X’ y ‘x’.

2.1.7 CADENAS LITERALES


Similar al anterior, con secuencias de caracteres entre delimitadores comillas (“ ”).
“esto es una cadena”
Si la cadena excede una línea, deberá fraccionarse y concatenarse por el delimitador &.

2.1.8 CADENAS BIT LITERALES


Son elementos léxicos formados por cadenas de dígitos de base hexadecimal (X),
binaria (B), u octal (O), delimitados por comillas. Se pueden usar caracteres de subrayado
aislados para separar cadenas largas de bits y mejorar la legibilidad del dato.
Independientemente de la base utilizada para expresar la cadena, VHDL lo interpreta
siempre como el valor de la cadena de bits, por ejemplo, X”A” se interpreta como “1010”.

II - 2
2 – Características generales del VHDL

La interpretación de las cadenas binarias queda al criterio del diseñador: “1010” puede
interpretarse como (+10) o como (-6), en función del contexto del dato. Dos ejemplos de
cadenas bits equivalentes son:
B”11110000” B”1111_0000” X”F0”
B”100011001” B”100_011_001” O”431”

2.1.9 LITERALES NUMÉRICOS


Elementos léxicos con un valor numérico asociado. Pueden ser enteros o reales.
La base de numeración es decimal o especificada con número decimal, entre 2 y 16.
- Los reales tienen punto (.). La coma (,) no está permitida.
- Con notación exponencial se utiliza E o e. El exponente es siempre en base 10.
- Solo se permiten exponentes negativos en números reales.
- El primer carácter de un número real debe ser un número decimal.
- Se puede utilizar un carácter de subrayado para mejorar legibilidad.
- No se permiten espacios entre caracteres.
- Los números significativos que siguen a la base especificada, van entre caracteres #.
- En base hexadecimal, los números superiores a 9 se expresan con A~F o a~f.

Ejemplos correctos:
7 2E5 007 2e1 262_144 3.1416 03.1416 0.31416E1 0.31416e+1
31.416 E-1 0#255# 16#fF# 2#1111_1111#

Ejemplos incorrectos:
1,000 .5 3E-2 5E -1 0.5 e0 16# fF # 2# 1111 1111 #

2.2 CLASES DE OBJETOS: DECLARACIÓN E INICIALIZACIÓN

En VHDL, un objeto es un contenedor o portador en el que se pueden almacenar


valores de cierto tipo.
Todos los objetos tienen un tipo que determina la clase de valor que puede asignarse
al objeto. Al declararlos, se les asigna nombre y tipo. El nombre debe cumplir las reglas
mencionadas para ENTITYs y los tipos deben haber sido declarados previamente, salvo que
sean predefinidos. Hay tres clases de objetos en VHDL:

2.2.1 CONSTANTES
Tienen un valor fijo, asignado al compilarlas, no alterable durante la simulación.
Deben ser declaradas con el siguiente formato:

CONSTANT nombre_de_constante : TIPO [: = valor inicial];


Ejemplos :
CONSTANT voltaje: REAL := 5.0;
CONSTANT pulso: TIME := 100 NS;
CONSTANT tres: BIT_VECTOR := "0011";

2.2.2 VARIABLES
Son objetos normalmente utilizados como portadores temporales de valor alterable.
Solo son declarables en áreas secuenciales, como en procesos y subprogramas.
Deben declararse con el siguiente formato:
VARIABLE nombre1,.. nombre_n : TIPO [RESTRICCIONES][:= VALOR INICIAL];

II - 3
2 – Características generales del VHDL

Ejemplos:
VARIABLE temporal: INTEGER RANGE 0 TO 10 := 5;
VARIABLE frecuencia, ganancia: REAL RANGE 1.0 TO 10.0;
VARIABLE octeto: BIT_VECTOR (0 TO 7) := X”FF”;

Las variables, a diferencia de las señales, no pueden pasar valores entre subprogramas.

2.2.3 SEÑALES
Son portadores del valor de un parámetro común a varias unidades de diseño,
utilizándose en descripciones para comunicar cambios del parámetro, normalmente
asociados a un tiempo de simulación. Su relación con el hardware es evidente y, a diferencia
de las variables, solo pueden ser declaradas en áreas concurrentes.
Su formato de declaración y algunos ejemplos son como sigue:

SIGNAL nombre: tipo [ restricciones ][:= valor inicial]; SIGNAL clk: BIT := '0';
SIGNAL databus: BIT_VECTOR ( 7 DOWNTO 0) := B”0000_1111” ;
SIGNAL dos_bytes: octales(0 TO 1) := (B”0000_1111”, B”1111_1111”) ;

Las señales no deben declararse dentro de Procesos, pero se usan dentro de ellos y
como objetos para pasarles valores. Estos aspectos se verán al estudiar los Procesos .

2.3 ASIGNACIÓN DE VALORES


Son expresiones utilizadas para cambiar el valor que tienen las variables y las señales.

2.3.1 ASIGNACIÓN A VARIABLES


Las variables sustituyen inmediatamente el valor que tienen con el que se les asigna
usando el delimitador compuesto (:=):

octeto := b”1111_1110”;
frecuencia := 2.0;
temporal := temporal + 1;

2.3.2 ASIGNACIÓN A SEÑALES


La asignación simple de un valor a una señal indica el nuevo valor que será asignado
en un instante futuro. Nótese que, a diferencia de la asignación inmediata que ocurre en
variables, en las señales hay un retardo que, si no se especifica un valor determinado, tiene
una duración infinitesimal denominada retardo delta.
El delimitador empleado para asignar valor a señales es ( <= ) :

clk <= ‘0’; clk <= ‘1’ after 5 ns; databus <= x”0f” after 10 ns;

El valor asignado a la señal debe ser del tipo con el que la señal fue declarada.
Dada la importancia del concepto señal en cualquier circuito a modelar, las sentencias
de asignación de valor a señales son elementos clave y con importantes matices que se verán
al estudiar con más detalle este tipo de sentencias.

II - 4
2 – Características generales del VHDL

2.4 TIPOS DE OBJETOS

Un tipo es un conjunto de valores con un nombre que identifica al tipo.


El tipo de un objeto especifica los valores que puede tener y limita las operaciones
que pueden realizarse con sus datos a aquellas definidas para el tipo y su rango de valores.
En VHDL todos los datos que se utilizan tienen un tipo que es necesario especificar al
declarar el objeto que lleva el valor. La compatibilidad entre tipos al asignar valores es un
requisito en VHDL.
El paquete STANDARD, en la biblioteca STD, define tipos básicos como BIT ó
INTEGER, pero el usuario de VHDL puede definir tipos y operadores específicos para la
aplicación en uso, existiendo cuatro clases de tipos definibles en VHDL:

1. tipos escalares
Son tipos con valores simples y aislados.
Existen tres tipos escalares: ENUMERADOS, NUMÉRICOS y FÍSICOS.
2. tipos compuestos
Tienen valores compuestos por conjuntos de valores. Son los ARRAYS y RECORDS.
3. tipos fichero
Son tipos especiales utilizados para definir objetos relacionados con la escritura y
lectura de ficheros o archivos de datos contenidos en el sistema donde se hace la
simulación del modelo. Estos ficheros, cuyo formato puede ser especial o de texto,
pueden utilizarse como entradas para simulación del modelo o como ficheros en los
que se archivan las salidas del mismo. Por su relación al paquete TextIO, se verán en
detalle al estudiar este paquete en una sección posterior.
4. tipos acceso
Se usan en descripciones complejas. Su estudio no se considera en este documento.

2.4.1 TIPOS ENUMERADOS


Su declaración consiste en la enumeración simple de los valores que pueden tener. El
paquete STANDARD contiene la declaración de los cuatro tipos de enumeración básicos de
VHDL: boolean, bit, character y severity_level.
Para declaraciones a nivel flujo de datos, donde se describen buses y sus señales de
control, es necesario manejar señales que no pueden ser descritas con lógica binaria, por lo
que se podría definir, por ejemplo, un tipo escalar que usara cuatro valores lógicos:

TYPE cuad IS ('0','1','Z','X');

donde '0' es el valor por defecto, 'Z' = 'alta impedancia' y 'X' = 'valor indefinido'.
Para poder utilizar el tipo cuad en las descripciones se puede:
- Declararlo en la parte declarativa de la ARCHITECTURE.
- Incluirlo en un paquete, al que se llamaría con USE para habilitarlo.

La 2ª opción es la más empleada normalmente en diseños.

II - 5
2 – Características generales del VHDL

2.4.2 TIPOS NUMÉRICOS


Denominación asignada a los tipos INTEGER y REAL del paquete STANDARD. Los
rangos máximos están definidos en el paquete, pero el usuario puede definir o limitar los
rangos de estos dos tipos en sus descripciones, de forma similar a como lo hacen los
subtipos NATURAL y POSITIVE también definidos en el mismo paquete STANDARD, por
ejemplo:

TYPE centenas IS RANGE 0 TO 100; TYPE probabilidad IS RANGE 0.0 TO 1.0

2.4.3 TIPOS FÍSICOS


Se pueden definir y declarar tipos relacionados con magnitudes físicas que son de uso
frecuente en descripciones de hardware como resistencias, capacidades, frecuencia,
potencia, etc. Un ejemplo se tiene en el tipo TIME, declarado en el paquete STANDARD por
su utilidad en VHDL para modelar retardos. Para disponer de tipos físicos en modelos
relacionados con resistencias y condensadores se podrían definir los tipos :
TYPE resistencia IS RANGE 0 TO 1E16 TYPE capacidad IS RANGE 0 TO 1E16
units units
mo; -- miliohms (unidad ) ffr; -- femto faradios (unidad)
ohms = 1000 mo; pfr = 1000 ffr;
kohms = 1000 ohms; nfr = 1000 pfr;
END units; END units;

2.4.4 ARRAYS
Son tipos compuestos por elementos homogéneos, con igual subtipo. Un ejemplo se
tiene en los tipos STRING y BIT_VECTOR del PACKAGE.STD. STRING es un array de
caracteres y BIT_VECTOR es un array de bits. Los arrays se puede considerar y definir como
tipos indexables y multidimensionales, pudiendo dejarse sin definir sus dimensiones o
rangos. El formato y algunos ejemplos son como sigue:

TYPE nombre IS ARRAY (rangos o dimensiones) OF tipo de los elementos;


TYPE cuad_nibble IS ARRAY ( 3 downto 0 ) OF cuad;
TYPE cuad_byte IS ARRAY ( 7 downto 0) OF cuad;
TYPE cuad_word IS ARRAY (15 downto 0 ) OF cuad;
TYPE cuad_2por4 IS ARRAY (1 downto 0, 0 to 3) OF cuad;

Nótese que los elementos del array pueden indexarse de dos formas, en las que se
especifica el índice dentro del rango de ( izquierda a derecha ).
El array puede tener dimensiones abiertas, útil para describir diseños genéricos:

TYPE bit_vector IS ARRAY (natural range <>) OF bit; --(ver PACKAGE.STD).

El delimitador compuesto <> indica que es un array con rango abierto, cuyos límites
vendrán especificados posteriormente en la aplicación que use el tipo así declarado.
Pueden declararse tipos enumerados en relación a los índices de un array, por ejemplo:

TYPE orden IS ( uno, dos, tres, cuatro, cinco);


TYPE orden_de_array IS ARRAY ( orden RANGE uno TO cinco) OF INTEGER;

II - 6
2 – Características generales del VHDL

que nos indica que los valores almacenados de “uno” a “cinco” son enteros, que el primer
elemento del array tiene por nombre “uno” y que con él nos podemos referir a ese elemento,
sea para asignarle un valor o para leerlo después.

Una vez que los arrays están declarados, o llamado el paquete en que se hayan
incluido, se puede asignar valores a los elementos de los arrays o utilizar estos elementos
para asignar valores a objetos de tipo compatible, por ejemplo:

TYPE dispositivos IS (ram, micro, fpga, resistor, condensador, bobina);


TYPE array_activo IS ARRAY ( dispositivos RANGE ram TO fpga) OF INTEGER;
TYPE activos_pasivos IS ARRAY (dispositivos RANGE <>) OF INTEGER;

permiten asignar valores a señales declaradas como :


SIGNAL pasivos : activos_pasivos (range resistor to bobina);
SIGNAL databus : cuad_byte := "ZZZZZZZZ";

"ZZZZZZZZ" es el valor inicial forzado en la declaración, en lugar del valor “00000000” que
tendría si no hubiese inicialización, ya que el valor por defecto del tipo cuad es '0'.

En los ejemplos que siguen pueden verse posibles formas de asignación de valores a señales
relacionadas con los tipos array declarados anteriormente:

SIGNAL s1:cuad; s1 <= s16 (3);


SIGNAL s4: cuad_nibble; s4 <= s16 (2) & s16(3) & s16(4) & s16(5);
SIGNAL s8: cuad_byte; s8 <= s16 ( 15 downto 8 );
SIGNAL s16: cuad_word; s16 (7 downto 0) <= s4 & s8( 3 downto 0 );

Además de la indexación por enteros, si la declaración del array especifica un tipo o


tipos como indicación del rango discreto de ese array, la indexación está definida por una
lista o tabla cuyos elementos estan indexados por filas y columnas ordenadas igual que los
elementos de los tipos que describen los rangos discretos del nuevo tipo, al igual que los
elementos aij de una matriz de i filas y j columnas:

TYPE cuad_2dim IS ARRAY ( cuad,cuad ) OF cuad;

este TYPE estará definido por una tabla de (4 x 4), siendo el orden de filas y columnas el
definido para el tipo cuad, es decir , ('0','1','Z','X') , ('0','1','Z','X').
La inicialización de los valores de una señal del tipo array multidimensional se efectúa
dentro de paréntesis anidados, separados por comas, en el mismo orden o dirección en que
están declarados los elementos del array.

SIGNAL s_2_4: cuad_2por4 := (('0','1','1','Z'), ('Z','0','0','0'));

Algunas herramientas de síntesis no soportan los arrays multidimensionales, por lo


que se hace necesario descomponerlos en arrays unidimensionales, por ejemplo :

CONSTANT memdim : INTEGER := 3;


TYPE memdato IS ARRAY (0 TO memdim, 7 DOWNTO 0 ) OF BIT;

el array bidimensional memdato puede sustituirse por dos arrays unidimensionales como

II - 7
2 – Características generales del VHDL

TYPE palabras IS ARRAY ( 7 DOWNTO 0 ) OF BIT;


TYPE memdato IS ARRAY ( 0 TO memdim ) OF palabras;

Con lo visto hasta aquí, y suponiendo que se tienen declarados los tipos anteriores
apropiadamente en el paquete “modelos” sería posible modelar una sencilla memoria ROM
como sigue:
USE WORK. modelos. ALL;
ENTITY memrom IS
PORT ( direc : IN INTEGER;
datos : OUT palabras);
END memrom;
ARCHITECTURE minima OF memrom IS
CONSTANT romdatos : memdato := ( (‘0’, ‘0’, ’0’, ‘0’, ‘0’, ‘1’, ‘1’, ‘1’),
(‘1’, ‘1’, ‘1’, ‘1’, ‘1’, ‘0’, ‘0’, ‘0’),
(‘0’, ‘0’, ‘0’, ‘1’, ‘1’, ‘0’, ‘0’, ‘0’),
(‘1’, ‘1’, ‘1’, ‘0’, ‘0’, ‘1’, ‘1’, ‘1’) );
BEGIN
datos <= romdatos( direc ) AFTER 25 ns;
END minima;

2.5 SUBTIPOS

Son subconjuntos de los valores de un tipo predefinido, al que se llama tipo base, del
cual se obtienen fijando alguna restricción. Los distintos subtipos obtenidos de una misma
base son totalmente compatibles entre sí y con su base, lo que permite usar con ellos todas
las funciones definidas para el tipo base.
Todos los tipos son subtipos de ellos mismos, por lo que subtipo se usa a veces para
referirse a todos los tipos y subtipos declarados de una misma base.
Los subtipos se declaran de forma similar a los tipos, indicando después de la palabra
clave SUBTYPE el nombre que se le asigna, seguido de IS y del nombre del tipo base del
que se derivan, por ejemplo :
SUBTYPE cuarteto IS bit_vector ( 3 DOWNTO 0);
SUBTYPE decadas IS integer RANGE 0 TO 9;

otros ejemplos se tienen en el paquete STANDARD :


TYPE INTEGER IS RANGE -2147483648 TO 2147483647;
SUBTYPE NATURAL IS INTEGER RANGE 0 TO INTEGER'HIGH;
SUBTYPE POSITIVE IS INTEGER RANGE 1 TO INTEGER'HIGH;

Existen tres razones principales para el uso de subtipos:


 Limitar el número de “casos posibles” en ciertas sentencias, como en las de asignación
selectiva de valor a señales o en la sentencia secuencial CASE.
 Facilitar la creación de funciones de resolución para la asignación de valor a una señal
con múltiples drivers. Este tema se revisa como caso especial de funciones.
 Ser innecesaria la conversión de tipos al hacer asignaciones entre objetos con base
común, por ejemplo, si tuviésemos definido un tipo como :
TYPE semibyte IS ARRAY ( 3 DOWNTO 0 ) OF BIT;

II - 8
2 – Características generales del VHDL

para asignar el valor de un objeto de ese tipo a otro del tipo BIT_VECTOR, sería necesario
hacer una conversión para pasar los elementos del tipo "semibyte" al tipo BIT_VECTOR, lo
cual sería innecesario si el objeto driver fuese del tipo “cuarteto” definido arriba.
La asignación de valores de un subtipo a objetos de su tipo base es siempre posible, ya
que es un subconjunto de la base. Por razón similar, un valor del tipo base puede no ser
asignable a un objeto del subtipo, por ejemplo, si se tienen los subtipos :
SUBTYPE triple IS cuad RANGE '0' TO 'Z' ;
SUBTYPE binar IS cuad RANGE '0' TO '1' ;

los objetos del subtipo "binar" son directamente asignables a objetos "triple"o "cuad" y
viceversa, pero cuidando no provocar asignaciones que sobrepasen la dimensión definida
para el subtipo destino, ya que se tendría un mensaje de error por asignación fuera de rango.
Nótese, por contra, que el subtipo "binar" no es compatible con el tipo BIT definido en
el paquete STANDARD. Aunque sus elementos son los mismos, en "binar" la base es "cuad".

2.6 TIPOS STD_LOGIC

Es evidente que para modelar o simular hardware digital, el tipo BIT del paquete
STANDARD es insuficiente ya que solo dispone de los valores 0 y 1. Por otra parte, si cada
usuario define sus propios tipos y paquetes resultarán incompatibilidades que dificultarán
los desarrollos compartidos o reutilizables. Para evitar estos inconvenientes, el IEEE
desarrolló un nuevo paquete denominado STD_LOGIC_1164, donde se declara el tipo
std_ulogic con nueve valores.
El paquete STD_LOGIC_1164 está dentro de una biblioteca denominada IEEE, por lo
que, a diferencia de los tipos bit y bit_vector, que por estar en el paquete y biblioteca
STANDARD siempre están visibles, para usar los tipos std_ulogic es necesario iniciar la
descripción con las sentencias:

libarary IEEE;
use IEEE. std_logic_1164.all;

que, al hacer visibles la biblioteca y el paquete, permiten utilizar los tipos allí declarados.
El tipo base declarado en el paquete std_logic_1164 es el tipo std_ulogic, conocido
también como MVL9 - multi value logic - y tiene sus nueve valores declarados como:

TYPE std_ulogic IS ( ‘U’ -- uninitialized


‘X’ -- forcing unknown
‘0’ -- forcing 0
‘1’ -- forcing 1
‘Z’ -- High Impedance
‘W’ -- Weak unknown
‘L’ -- Weak 0
‘H’ -- Weak 1
‘-’ -- Don’t care ) ;

y, al igual que en el paquete STANDARD, inmediatamente después se declara el tipo array

TYPE std_ulogic_vector IS ARRAY ( NATURAL RANGE <> ) OF std_ulogic;

II - 9
2 – Características generales del VHDL

El valor ‘U’ , uninitialized , valor no inicializado, se emplea para comprobar que la


lógica, particularmente la secuencial, ha sido inicializada correctamente y no tiene valores
imprevistos. Por defecto, los dispositivos secuenciales estarán inicializados en ‘U’. Cuando
comienza la simulación deben inicializarse a ‘0’ o ‘1’, pero si por olvido o fallo no
sucediese, el simulador avisará, ya que ‘U’ es el más fuerte y ningún otro le hará cambiar.
El valor ‘X’ se reserva para conflictos de señales motivados por asignación múltiple
de valores diferentes a una misma señal, por lo que se diferencia de ‘U’ reservado
únicamente para inicialización por defecto, en espera del valor impuesto por el diseñador.
El valor ‘-’ se usa exclusivamente en aplicaciones de síntesis. Durante procesos de
simulación se asimila a ‘Z’.
El sentido de usar los tipos MVL9 o std_logic_1164 se verá con más detalle al
estudiar las funciones de resolución en la sección 4.

2.7 ATRIBUTOS PREDEFINIDOS DE TIPOS Y ARRAY'S

Los atributos son valores específicos tales como datos, funciones, tipos o rangos
asociados con los objetos a que se refieren. Los atributos permiten un uso más eficiente del
lenguaje al disponer de codificaciones adicionales que simplifican las descripciones
El formato tipo es :

nombre_ de_objeto ‘'nombre_ de_atributo

2.7.1 ATRIBUTOS DE TIPOS


En los tipos enumerados y en los numéricos, INTEGER O REAL, permiten encontrar
el valor de los elementos, su posición, elemento que sigue, elemento que precede, etc. En
estos atributos predefinidos se considera que al declarar un tipo enumerado se asocia a cada
elemento un índice que indica su posición en la lista, siendo 0 para el primer elemento
enumerado e incrementando en 1 para cada elemento sucesivo. Los ejemplos muestran los
atributos predefinidos del tipo dias que se declara como:
TYPE dias IS ( lun, mar, mie, jue, vie, sab, dom);

BASE - Proporciona el nombre del tipo mar'BASE = dias


LEFT - Da el valor del elemento izquierdo del tipo dias’LEFT = lun
RIGHT - Da el valor del elemento derecho del tipo dias’RIGHT = dom
HIGH - Entrega el valor del elemento con índice más alto dias’HIGH = dom
LOW - Entrega el valor del elemento con índice más bajo dias’LOW = lun
POS - Suministra el índice del elemento referido dias’POS(jue) = 3
VAL - Suministra el valor del elemento con el índice dado dias’VAL(3) = jue
SUCC- Indica el valor de la base que sigue al referido dias’SUCC(jue) = vie
PRED - Indica el valor de la base que precede al referido dias’PRED(vie) = jue
LEFTOF - Valor del elemento a la izquierda del referido dias’LEFTOF(jue) = mie
RIGHTOF - Valor del elemento a la derecha del referido dias’RIGHTOF(lun) = mar

Otros ejemplos se obtienen del paquete STANDARD, a partir de los tipos CHARACTER y BIT:

character’POS(NUL) = 0 ; character’POS(‘0’) = 48
bit’LEFT = ‘0’ bit’RIGHT = ‘1’ bit’POS(‘0’) = 0 bit’VAL(0) = ‘0’

Nótese que NUL va directamente, mientras que el carácter ‘0’ va entre apóstrofos.

II - 10
2 – Características generales del VHDL

De forma similar, para tipos INTEGER como los subir y bajar definidos a
continuación, se tienen los ejemplos siguientes, en los que deben apreciarse las diferencias
que existen :

TYPE subir IS RANGE 0 TO 9; TYPE bajar IS RANGE 9 DOWNTO 0;


subir’LEFT = 0 bajar’LEFT = 9
subir’RIGHT =9 bajar’RIGHT = 0
subir’PRED(5) = 4 bajar’PRED(5) =4
subir’SUCC(5) = 6 bajar’SUCC(5) = 6
subir’LOW = 0 bajar’LOW = 0
subir’LEFTOF(3) = 2 bajar’LEFTOF(3) = 4
subir’RIGHTOF(4) = 5 bajar’RIGHTOF(4) = 3

2.7.2 ATRIBUTOS DE ARRAYS


Devuelven valores relativos al rango, longitud o límites del array. Dado que pueden
existir arrays multidimensionales, los atributos pueden opcionalmente hacer referencia a una
de las dimensiones del array. El formato general es :

nombre_de_array ’ atributo[(n)]
Existen los siguientes atributos de arrays:

array’LEFT(n) Devuelve el límite izquierdo del subarray de índice n.


array’RIGHT(n) Devuelve el límite derecho del subarray de índice n.
array’HIGH(n) Devuelve el límite alto del subarray de índice n.
array’LOW(n) Devuelve el límite bajo del subarray de índice n.
array’LENGTH(n) Da la longitud del subarray de índice n.
array’RANGE(n) Da el rango del subarray de índice n.
array’REVERSE RANGE(n) Da el rango inverso del subarray de índice n.

Para arrays definidos con rangos ascendentes:


array’LEFT = array’LOW
array’RIGHT = array’HIGH

Para arrays definidos con rangos descendentes :


array’LEFT = array’HIGH
array’RIGHT = array’LOW

Aplicados a un array bidimensional como


TYPE brillo is BIT_VECTOR( 7 DOWNTO 0 );
TYPE pantalla IS ARRAY ( 1 TO 640, 480 DOWNTO 1 ) OF brillo;

se tendría

pantalla'LEFT(1) 1, pantalla’LEFT(2) 480


pantalla’LOW(1) 1, pantalla’LOW (2) 1
pantalla'RIGHT(1) 640, pantalla’RIGHT(2) 1
pantalla’HIGH(1) 640, pantalla’HIGH(2) 480
pantalla’LENGTH(1) 640, pantalla’LENGTH(2) 480
pantalla’RANGE(1) 1 TO 640 pantalla’RANGE(2) 480 DOWNTO 1
pantalla’REVERSE RANGE(1) 640 DOWNTO 1 pantalla’REVERSE RANGE(2) 1 TO 480

II - 11
2 – Características generales del VHDL

Un posible uso de los atributos ‘LOW y ‘HIGH de arrays se ve en el ejemplo siguiente:

FUNCTION convertir_a_entero ( dato: BIT_VECTOR ) RETURN INTEGER IS


VARIABLE resultado : INTEGER := 0;
BEGIN
FOR n IN dato’LOW TO dato’HIGH LOOP
IF dato(n) = ‘1’ THEN
resultado := resultado + ( 2** n);
END IF;
END LOOP;
RETURN resultado;
END convertir_a_entero;

2.8 OPERADORES Y EXPRESIONES

Asociados en grupos en los que todos los operadores tienen igual prioridad y
ordenados los grupos por relación de precedencia, se tiene la clasificación siguiente:

OPERADORES LÓGICOS : AND OR NAND NOR XOR


OPERADORES RELACIONALES : = /= < <= > >=
OPERADORES DE ADICIÓN : + - &
OPERADORES DE SIGNO : + -
OPERADORES DE MULTIPLICAR : * / mod rem
OPERADORES MISCELÁNEOS : ** abs NOT

2.8.1 OPERADORES LÓGICOS: AND OR NAND NOR XOR


Definen operaciones sobre variables o señales de tipo BIT o BOOLEANO y se obtienen
resultados del mismo tipo que tengan los operandos. Dado que todos los operadores del
grupo tienen igual precedencia, según las expresiones que se manejen, puede ser necesario
el empleo de paréntesis para precisar la operación a realizar con los operandos, por ejemplo:
a := b AND c OR d AND e -- expresión ilegal
es una expresión ilegal que puede expresarse correctamente como :
a := ( b AND c) OR ( d AND e )

Nótese que los operadores AND y OR, por ser asociativos, permiten escribir indistintamente
a := b AND c AND o bien a := c AND d AND b
z := b OR c OR d o bien z := c OR b OR d

mientras que los operadores NAND y NOR, no asociativos, requieren el empleo del
operador NOT con más de dos operandos, por ejemplo, para representar la función NOR de
tres entradas, no se puede formular como :
z <= x NOR y NOR w -- es ilegal
ni tampoco como
z <= ( x NOR y ) NOR w -- legal, pero no es la función NOR
debiendo expresarse como
z <= NOT ( x OR y OR w )
que justifica la mayor prioridad de NOT.

II - 12
2 – Características generales del VHDL

2.8.2 OPERADORES RELACIONALES: = /= < <= > >=


Deben comparar objetos del mismo tipo y el resultado de operadores de este tipo es
siempre tipo booleano: cierto o falso, TRUE o FALSE. Ejemplos:
tempext := 10; tempint := 18;
( tempext < tempint ) -- resultado es TRUE
segnal_A <= 3; segnal_B <= 5;
( segnal_B <= segnal_A ) -- resultado es FALSE

En este último ejemplo puede verse el doble significado del delimitador compuesto <= ,
cuyo sentido correcto es deducido por el contexto de la expresión donde figure.

2.8.3 OPERADORES DE ADICIÓN: + - &


+ y - son operadores aritméticos, para operandos de igual tipo: entero, real o físico.
El resultado es del mismo tipo que los operandos.
El operador de concatenacion, &, enlaza dos o más elementos del mismo tipo en una
única unidad o elemento nuevo. Se utiliza en arrays unidimensionales de igual tipo base,
obteniéndose un nuevo array resultado cuya longitud es la suma de las longitudes de los
arrays operandos. Los ejemplos que siguen muestran los resultados de concatenar:
segnal_A <= ‘0’; segnal_B <= ‘1’;
segnal_A & segnal_B tiene por valor “01”
VARIABLE marca : STRING ( 1 TO 4 ); := “opel”;
VARIABLE modelo : STRING ( 5 DOWNTO 1); := “corsa”;
VARIABLE color : STRING ( 1 TO 3 ); := “roj”;
VARIABLE coche : STRING ( 1 TO 14 );
coche := marca & ‘ ‘ & modelo & ‘ ‘ & color; -- coche tiene valor “opel corsa roj”

Nótese en este ejemplo el uso de apóstrofo y dobles comillas, ya que el espacio ‘ ‘ es


un carácter y los STRING son arrays de caracteres.

2.8.4 OPERADORES DE PRODUCTO: * / MOD REM


* y / , multiplicación y división , están definidos para tipos entero y real.
Los objetos de tipo físico, puestos a la izquierda del operador * o / , pueden ser
multiplicados o divididos por enteros o reales y el resultado será del tipo físico. Dos objetos
del mismo tipo físico pueden ser divididos y el resultado es de tipo entero. Véanse ejemplos:

VARIABLE t1,t2,t3 : TIME := 10 ns; r1 := v1*r2; -- r1 vale 50 kohms


VARIABLE r1, r2, r3 : resistencia := 10 kohms; t1 := 5.0*t2; -- t1 vale 50.0 ns
VARIABLE v1, v2 : entero := 5; v2 := r1/r2; -- v2 vale 5
r1 := r2*r3; v1 := r1/v2; -- son ilegales

mod y rem están definidos solo para tipo INTEGER.


mod está definido por la expresión A = B*N + ( A mod B )
donde ( A mod B ) tiene el signo de B y un valor absoluto menor que el de B. N es un
número entero para el que se debe cumplir la expresión anterior.
rem está definido por la expresión A = ( A/B)*B + ( A rem B )
donde ( A rem B ) tiene el signo de A y un valor absoluto menor que el de B.

II - 13
2 – Características generales del VHDL

2.8.5 OPERADORES DE SIGNO : + -


Solamente afectan al signo de los operandos numéricos. Por la precedencia de los
operadores, no pueden ir en las expresiones inmediatamente detrás de los operadores de
multiplicación ni misceláneos, por lo que deberán ir entre paréntesis en tales casos.
TYPE temperatura is INTEGER RANGE -50 TO 100;
VARIABLE referencia : temperatura := 3 ;
SIGNAL radiador, congelador : temperatura;
congelador <= - referencia; -- congelador vale -3
referencia := -radiador; -- referencia vale 50
radiador/ -congelador -- es ilegal
radiador/(-congelador) -- es correcto
radiador** -congelador -- es ilegal
radiador**(-congelador) -- es correcto

2.8.6 OPERADORES MISCELÁNEOS : ** ABS NOT


** operador de exponenciación.
La base debe ser de tipo entero o real y el exponente de tipo entero.
El exponente solo puede ser negativo con bases de tipo real.
El resultado es del mismo tipo que la base.

abs Operador unario que obtiene el valor absoluto del operando.

NOT Operador lógico NOT, para tipos BIT y booleanos. Algunos ejemplos son :
VARIABLE X,Y,Z: INTEGER := 10;
VARIABLE A: REAL := 5.0;
SIGNAL S1,S2,S3 : BIT := ‘1’;

Z := X**2; -- Z vale 100;


A := 0.5 ** (-1); -- A vale 2.0
Z := X**(A); -- es ilegal
X := A** 3; -- es ilegal
Y := X**( -2 ); -- es ilegal
X := ABS ( Z - ( Y**2)) ; -- x vale 90
s1 <= s2 AND NOT s3 -- s1 recibe el valor ‘0’

2.9 SOBRECARGA DE TIPOS Y OPERADORES

En VHDL el concepto de sobrecarga - overloading - se refiere a la posibilidad de


tener objetos o elementos con más de un significado, por ejemplo, en el paquete STANDARD
tenemos ya sobrecarga en los caracteres ‘0’ y ‘1’ que se definen en la segunda declaración
del paquete como tipo BIT y en la tercera como tipo CHARACTER.
Igualmente, el usuario puede definir tipos sobrecargados, por ejemplo:
TYPE colores_primarios IS (rojo, verde, azul);
TYPE leds is (rojo, ambar, amarillo, verde, azul);

De la misma forma, se puede tener sobrecarga de operadores, por ejemplo, si se tienen


las señales w, x, y, z de tipo BIT, se podría escribir la sentencia:

w <= ( x AND y ) OR z;

II - 14
2 – Características generales del VHDL

Si posteriormente las mismas variables se tuviesen de tipo cuad, definido previamente, sería
posible mantener la expresión anterior si antes se hubieran definido los operadores AND y
OR para los tipos cuad, ya que estos operadores solo están predefinidos para los tipos BIT
y BOOLEAN. La expansión o sobrecarga de los operadores AND y OR, se hace
definiendo un nuevo operador, con igual nombre, por medio de una función que devuelve
resultados de tipo cuad a partir de operandos cuad . La función o subprograma hará el efecto
de un macrooperador, como se verá con más detalle en la sección 4 sobre subprogramas.
Las situaciones de sobrecarga se resuelven en VHDL por contexto, es decir, si los
operandos son, por ejemplo, del tipo cuad y hay una expresión donde se llama a un
subprograma existente para aplicarles la función AND u OR, el VHDL aplicará la función
sobrecargada para dichos tipos y devolverá un resultado que será acorde con el que se
espera que, puede ser de tipo BIT, INTEGER, cuad u otro cualquiera definido, siempre que
exista la función o subprograma sobrecargado que corresponda al tipo de parámetros de
entrada y salida especificados al invocarlo. Es decir, el concepto de sobrecarga se extiende
a tipos, operadores y subprogramas.
Cuando se sobrecargan operadores, al declararlos y definirlos, estos van entre
comillas, por ejemplo “AND” y “OR”, para diferenciarlos de las funciones. La razón es que
los operadores van entre los operandos mientras que los subprogramas se llaman con los
parámetros entre paréntesis. En el paquete “modelos” se tienen algunos ejemplos de
operadores sobrecargados.
A veces, existen expresiones en las que puede existir una ambigüedad que VHDL no
puede resolver por la sobrecarga que tengan los objetos, por ejemplo, en la expresión

... IF ( ‘Z’ < ‘X’ ) ...

y en un contexto donde están visibles los tipos cuad, aparte de los CHARACTER, siempre
visibles por ser declarados en el paquete STANDARD, se tendría una situación cuyo
resultado depende del tipo que se considere para los elementos sobrecargados, por ejemplo:

( ‘Z’ < ‘X’ ) es TRUE si los elementos son del tipo cuad ( ‘0’, ‘1’, ‘Z’, ‘X’)
(‘Z’ < ‘X’ ) es FALSE si los elementos son del tipo CHARACTER

Para evitar situaciones como la del ejemplo, se deben cualificar las expresiones
susceptibles de ambigüedad. Esto se hace por marcado de tipos o expresiones cualificadas
que consisten en forzar el tipo de los elementos según el formato de expresión siguiente:

TIPO’ (expresión con tipos sobrecargados)

así , la expresión ambigua anterior dejaría de serlo expresándola como :

... IF ( cuad’(‘Z’) < cuad’(‘X’) )

II - 15
3. Sentencias Concurrentes
Son las sentencias que se usan directamente dentro del cuerpo de las ARCHITECTUREs
y, a diferencia de lo habitual en los lenguajes de programación, estas sentencias no se
ejecutan en el orden en que están escritas sino que solo se ejecutan cuando cambia alguna de
las señales de las que dependen los resultados que se computan en las sentencias. Otra
característica es que todas las sentencias se ejecutan una vez al principio de la simulación.
Algunas de las sentencias que se ven en esta sección pueden ser concurrentes o
secuenciales, dependiendo del área en la que estén. Entre éstas están las ASSERT, vistas en
la sección de secuenciales, las asignaciones simples de valor a señales y las llamadas a
procedimientos.

3.1 Sentencias de COLOCACIÓN DE COMPONENTES

En VHDL, los componentes son elementos que se declaran como una caja negra y de
la que solo se describe su interfaz. El formato de declaración de componentes es:
COMPONENT nombre_de_componente -- no incluye la palabra reservada IS
PORT (local1, local2,... localn : modo y tipo);
END COMPONENT;

Tanto en los componentes como en las ENTITYs, los puertos locales se asocian a
señales físicas y, aunque similares en formato, hay diferencias importantes entre ambos:

- Una ENTITY es una unidad de diseño primaria, compilable directamente.


- Un componente es como una plantilla que, en alguna sentencia posterior a la de su
referencia, se mapeará con una ENTITY. De ahí la semejanza de sus declaraciones.

La declaración del componente puede ocurrir dentro del cuerpo de la ARCHITECTURE


que referencia al componente, pero también puede hacerse en un paquete. Es posible colocar
un componente que posteriormente se asociará a una ENTITY, al especificar la
configuración. Las sentencias de colocación de componentes los “insertan” en las
descripciones, lo que equivale a hacer una lista de los componentes que constituyen los
circuitos a describir. Ver ejemplo en “ARCHITECTURE estructural OF sumador”, en pág. I-4.
etiqueta_obligatoria : nombre_de_componente
PORT MAP ( [nombre_de_puerto => ] expresión
{, [nombre_de_puerto => ] expresión }) ;

La etiqueta es obligatoria, ya que al configurar el componente se hará por la etiqueta.


La lista de asociación de puertos, lógicamente, es obligatoria ya que hace el mapeo del
componente a que se refiere la sentencia. La lista relaciona señales locales del componente,
citadas en su declaración, con las reales de la ARCHITECTURE donde se utiliza y a las que se
conecta el componente. Puede utilizarse opcionalmente la asociación nominal indicada en el
formato o la posicional con el orden fijado por la declaración del componente. Las
expresiones que se indican en el formato de la sentencia referencian a una señal.

III - 1
3 – Sentencias concurrentes

3.2 Sentencias PROCESS

Es una sentencia concurrente que permite modelar el funcionamiento y el retardo de


un dispositivo digital y que, al igual que los subprogramas, solo admite sentencias
secuenciales en su región activa. Es la sentencia utilizada en VHDL para descripción
algorítmica y tiene el formato siguiente :

etiqueta : PROCESS  ( lista de sensibilidad ) 


-- región declarativa
BEGIN
-- región activa . Solamente sentencias secuenciales
END PROCESS etiqueta :

El área declarativa admite declaración de tipos, constantes, variables y subprogramas


locales al proceso, pero nunca de señales.
La (lista de sensibilidad) indica las señales cuyo cambio de valor inicia la ejecución
del proceso, siendo suficiente que haya un evento en cualquiera de ellas. Como indica el
formato, la lista de señales es optativa, pero en caso de no figurar, es necesario que haya
dentro de la región activa del proceso alguna sentencia WAIT, para evitar que el proceso esté
ejecutándose continuamente. La opción WAIT equivalente a la lista de sensibilidad es la
WAIT ON señales, ya que suspende la espera cuando hay un evento en cualquiera de las
señales que siguen a WAIT ON. Dado que cuando se inicia una simulación todos los procesos
se ejecutan una vez, la sentencia WAIT ON debe ser la última de las sentencias secuenciales,
a fin de permitir la ejecución de todas las que le preceden en la región secuencial del
proceso. Para evitar conflictos en la activación de un proceso, la lista de sensibilidad es
incompatible con sentencias WAIT dentro del proceso o en los posibles subprogramas
invocados desde la región secuencial.
Dentro de la región secuencial solo se permiten sentencias secuenciales. La ejecución
de éstas tiene lugar en el orden en que figuran en la descripción, por lo que, como en otros
lenguajes algorítmicos, el orden de las sentencias es significativo, a diferencia de lo que
ocurre en regiones activas concurrentes. Todas las sentencias se ejecutan en un tiempo cero.
Un proceso siempre está activo, lo que equivale a un subprograma con un bucle
iterativo infinito pero, a diferencia de los subprogramas, los procesos no pueden anidarse
por lo que si es necesario hacer anidamientos dentro del proceso se invocan subprogramas,
ya que estos actuán indistintamente como sentencias concurrentes o secuenciales.
Dado que los procesos son sensibles a señales y que éstas son el objeto de
comunicación entre los procesos, pueden existir sentencias internas a un proceso del tipo
señal_a <= expresión

que, aunque tiene el mismo formato que la asignación concurrente, es una sentencia de
asignación secuencial. Las asignaciones condicionales y selectivas de señal son sentencias
exclusivamente concurrentes por lo que no podrán utilizarse dentro de los procesos.
Si hay varias asignaciones secuenciales a una misma señal dentro de un proceso, la única
asignación efectiva será la última y lo será cuando el proceso haya terminado, ejecutándose
todas las sentencias secuenciales que lo componen.

III - 2
3 – Sentencias concurrentes

3.3 Sentencias de ASIGNACIÓN DE VALOR A SEÑALES

Estas sentencias, manteniendo su formato, pueden ser concurrentes o secuenciales,


dependiendo de su ubicación en un área de sentencias concurrentes de una ARCHITECTURE
o dentro de un área secuencial, un proceso o subprograma.
La ejecución de la sentencia ocurre siempre que hay un cambio o evento en la
expresión que define el valor que se asigna a la señal, por ejemplo:

[etiqueta_ de _reloj:] reloj <= impulsos AND permiso;

la señal reloj se activará una vez al comienzo de la simulación del modelo y posteriormente
siempre que haya un cambio en las señales impulsos y permiso, por ser la señal reloj sensible a
las señales impulsos y permiso o, expresado en otra forma habitual en VHDL, porque éstas
constituyen su lista de sensibilidad.
Siempre que un cambio en las señales drivers, escritas a la derecha del delimitador
compuesto <=, provoca un cambio en el valor de la señal destino, a la izquierda del
delimitador, se tiene un evento en la señal a la que se asigna valor. Sin embargo, pueden
ocurrir cambios en los drivers que no provoquen eventos en la señal destino, por ejemplo, si
la señal permiso fuese ‘0’, los cambios de ‘0’ a ‘1’ o de ‘1’ a ‘0’ en la señal impulsos no
ocasionarían eventos en la señal reloj. En estos casos, en la literatura americana, se dice que
en la señal destino, en lugar de eventos, hay transactions.

3.3.1 ASIGNACIONES SIMPLES

Con el formato más simple de asignación:

nombre_de_señal <= valor o expresión;

se pueden contemplar asignaciones directas de un valor:

signal_tipo_bit <= ‘1’; signal_tipo_integer <= 1;

o asignaciones con una expresión evaluable:

signal_binaria <= NOT (bit(0) AND bit(1)) ;

o asignaciones con expresiones aritméticas:

signal_integer <= integer_A + 7;

Dejamos aparte cualquier consideración de retardos que, aunque pueden ser necesarios para
describir el comportamiento de un circuito, carecen de interés a la hora de sintetizar un
modelo cuyos retardos dependerán de las características de la FPGA o el ASIC donde se
vaya a implementar el circuito. El compilador, aunque no rechace la especificación de un
retardo, no obedece a expresiones del tipo: “after XX ns; ” o similares.

III - 3
3 – Sentencias concurrentes

3.3.2 ASIGNACIONES CONDICIONALES

Su formato es
[etiqueta :] nombre <= onda1 WHEN condición1 ELSE
onda2 WHEN condición2 ELSE
....
ondaN WHEN condiciónN ELSE
ondaX;

Tan pronto una de las condiciones se cumple, es TRUE, la sentencia se ejecuta y termina. Si
no se cumple ninguna de las condiciones, se asigna el valor por defecto - ondaX -, como
muestra el ejemplo para un inversor triestado, con especificación de parámetros genéricos:

LIBRARY IEEE;
USE IEEE.std_logic_1164.ALL;

ENTITY inv_triestado IS
PORT ( e1, en: IN BIT; sal: OUT std_logic);
END inv_triestado; -- RETARDOS IGNORADOS EN SÍNTESIS

ARCHITECTURE tres_salidas OF inv_triestado IS


BEGIN
sal <= '1' AFTER 30 ns WHEN ( e1 = '0' AND en = '1' ) ELSE
'0' AFTER 25 ns WHEN ( e1 = '1' AND en = '1' ) ELSE
'Z' AFTER 20 ns; -- RETARDOS IGNORADOS EN SÍNTESIS
END tres_salidas;

La sentencia de asignación se ejecuta siempre que hay un cambio o evento en cualquiera de


las señales a las que es sensible, es decir, en este caso del inversor triestado del ejemplo,
siempre que cambie el valor de las señales e1 o en.

Nótese que en el ejemplo los valores ‘1’, ‘0’ y ‘Z’ son fijos, pero podrían ser ondas
especificadas como una relación de valores en tiempos definidos en cada caso, por ejemplo:

ENTITY generador_serie IS -- no soportada en MAX+plus II. Sí en Quartus II


PORT(ent: IN INTEGER RANGE 0 TO 3 ; sal: OUT BIT);
END generador_serie;

ARCHITECTURE reducida OF generador_serie IS


-- Asignación múltiple de valores en asignación condicional
BEGIN -- no soportada en MAX+plus II. Sí soportada en Quartus II
sal <= '1' AFTER 30 ns, '0' AFTER 40 ns WHEN ent = 1 ELSE
'1' AFTER 10 ns, '0' AFTER 20 ns WHEN ent = 2 ELSE
'1' AFTER 30 ns, '0' AFTER 40 ns WHEN ent = 3 ELSE
'0'; -- Quartus II solo considera la primera asignación de valor
END reducida; -- Asignaciones de retardos, IGNORADOS EN SÍNTESIS

En este ejemplo, la condición es de tipo INTEGER y la salida es una forma de onda que
cambia según el valor de la señal ent. La sentencia se ejecuta cada vez que cambia el valor
de la señal ent o cuando haya un cambio en la señal driver de la salida. El caso más general

III - 4
3 – Sentencias concurrentes

es que las formas de onda descritas en el ejemplo con valores discretos sean expresiones de
otras señales de entrada, por ejemplo:

ENTITY selector IS
PORT( a,b, sel1,sel2 : IN BIT; sal: OUT BIT);
END selector;

ARCHITECTURE funcional OF selector IS


SIGNAL sel : BIT_VECTOR (0 TO 1);
BEGIN
sel <= sel1 & sel2; -- retardos IGNORADOS EN SÍNTESIS
sal <= a AND b AFTER 10 ns WHEN sel = "11" ELSE
a OR b AFTER 10 ns WHEN sel = "10" ELSE
a XOR b AFTER 10 ns WHEN sel = "01" ELSE
NOT(a XOR b) AFTER 10 ns;
END funcional;

En este ejemplo, la asignación a la señal sal ocurre siempre que cambien a o b, así como
cuando cambie cualquiera de las señales de selección sel1 o sel2, además de la asignación
que siempre ocurre una vez al comienzo de la simulación.

La asignación condicional es equivalente al proceso siguiente:


ENTITY process_selectivo IS
PORT( a,b: IN BIT; sel: IN bit_vector(0 to 1); sal: OUT BIT);
END process_selectivo;

ARCHITECTURE funcional OF process_selectivo IS


BEGIN
asig_cond: PROCESS ( a , b , sel )
BEGIN
IF sel = "11" THEN sal <= a AND b;
ELSIF sel = "10" THEN sal <= a OR b;
ELSIF sel = "01" THEN sal <= a XOR b;
ELSE sal <= NOT( a XOR b);
END IF;
END PROCESS asig_cond;
END funcional;

3.3.3 ASIGNACIONES SELECTIVAS

Recuerdan a la sentencia secuencial CASE y tienen el formato siguiente:

[etiqueta :] WITH expresión SELECT


nombre <= onda1 WHEN grupo de selección1,
onda2 WHEN grupo de selección2,
....
ondaN WHEN grupo de selecciónN,
[ondaX WHEN OTHERS];

Ejemplos:

III - 5
3 – Sentencias concurrentes

ENTITY decoder_3_a_8 IS
PORT ( adr : IN BIT_VECTOR ( 2 DOWNTO 0 );
sal : OUT BIT_VECTOR ( 7 DOWNTO 0 ) ) ;
END decoder_3_a_8;
ARCHITECTURE directa OF decoder_3_a_8 IS
BEGIN
WITH adr SELECT
sal <= "00000001" WHEN "000", -- atención a "comas" (,)
"00000010" WHEN "001",
"00000100" WHEN "010",
"00001000" WHEN "011",
"00010000" WHEN "100",
"00100000" WHEN "101",
"01000000" WHEN "110",
"10000000" WHEN "111"; -- atención: "punto y coma" (;)
END directa;

La asignación selectiva de señal equivale igualmente a otro PROCESS como sigue:

asig_sel : PROCESS ( sel1, sel2 , a, b, c )


BEGIN
CASE ( sel1 & sel2 ) IS --SENTENCIA SECUENCIAL
WHEN “10” => sig <= a;
WHEN “01” => sig <= b;
WHEN OTHERS => sig <= a AND b;
END CASE;
END PROCESS asig_sel;

El ejemplo siguiente utiliza el paquete STD_LOGIC_1164 y muestra la posibilidad de


hacer un grupo de selecciones con el delimitador | que equivale a “OR”. Se incluye al
final la cláusula WHEN OTHERS, ya que en los grupos de selección anteriores no se han
indicado todas las posibles combinaciones de la señal selects que al ser std_logic presenta
valores no expresados explícitamente, pero concentradas en OTHERS.
LIBRARY IEEE;
USE IEEE.std_logic_1164.ALL;

ENTITY mux_cuatro_a_1 IS
PORT (i0,i1,i2,i3, s0,s1: IN std_logic; z:OUT std_logic);
END mux_cuatro_a_1;

ARCHITECTURE multivaluada OF mux_cuatro_a_1 IS


SIGNAL selects : std_logic_vector(0 TO 1);
BEGIN
selects <= s1&s0; -- concatenación de "s1" y "s0" en "s1s0".
WITH selects SELECT
z <= i0 WHEN "00",
i1 WHEN "01" | "0Z",
i2 WHEN "10" | "Z0",
i3 WHEN "11" | "ZZ",
'Z' WHEN OTHERS;
END multivaluada;

III - 6
3 – Sentencias concurrentes

3.3.4 ATRIBUTOS DE SEÑALES


Los atributos de señales permiten un uso más eficiente del lenguaje al disponer de
codificaciones adicionales que simplifican la descripción de aspectos del hardware tales
como la detección de flancos y sincronismos. Se utilizan para encontrar valores de señales
tales como eventos, flancos, tiempos transcurridos a partir de un instante de simulación, etc.
Hay cinco atributos que se comportan como funciones, devolviendo valores:
señal’EVENT Devuelve TRUE, si hay un evento en el tiempo delta actual.
señal’ACTIVE Devuelve TRUE, si hay un cambio en un driver en el tiempo delta actual.
señal’LAST_EVENT Devuelve el tiempo transcurrido desde el último evento en la señal.
señal’LAST_VALUE Devuelve el valor del tipo de la señal antes del último evento.
señal’LAST_ACTIVE Devuelve el tiempo transcurrido desde el último cambio en un driver.

Al hacer referencia a un “cambio en un driver “ se quiere indicar que puede haber


cambio en la señal o no, a diferencia de cuando se refiere a “evento“, que significa que hay
cambio efectivo en el valor de la señal. La diferencia entre ambos conceptos se debe a que,
dependiendo del valor de la señal en un instante, un cambio en un driver puede ordenar que
la señal adquiera un valor que ya tiene en cuyo caso no hay cambio en el valor de la señal.
Por contra, si el “cambio en el driver“ supone que la señal cambie de valor, entonces,
además de “cambio de driver “ hay “evento”. El “cambio en un driver “, en la literatura
americana se denomina transaction.

Los atributos ’ACTIVE y ’LAST_ACTIVE se relacionan a transactions, mientras EVENT y


LAST_EVENT lo están a eventos. Un ejemplo de ’EVENT describe flancos de señales reloj:
LIBRARY IEEE;
USE IEEE.std_logic_1164.ALL;
ENTITY d_flip_flop IS
PORT ( d,clk : IN std_logic; q : OUT std_logic);
END d_flip_flop;

ARCHITECTURE flanco_reloj OF d_flip_flop IS


BEGIN
PROCESS(clk)
BEGIN
IF ( clk = ‘1’) AND ( clk’EVENT ) THEN -- condición de flanco de subida
q <= d;
END IF;
END PROCESS;
END flanco_reloj;

Dado que la señal clk es de tipo std_logic en este ejemplo, si se considera como no
admisible la posible transición de ‘X’ a ‘1’ en la señal clk, se podría modificar la sentencia
reforzando la condición de flanco ascendente con el atributo ‘LAST_VALUE como sigue
IF ( clk = ‘1’) AND ( clk’EVENT ) AND ( clk’ LAST_VALUE = ‘0’ ) THEN
q <= d; -- ATRIBUTO NO RECONOCIDO EN MAX+plus II
END IF; -- RECONOCIDO Y SINTETIZADO EN QUARTUS II

que asegura completamente la transición de ‘0’ a ‘1’ en la señal clk

III - 7
3 – Sentencias concurrentes

Existen otros cuatro atributos de señal que suministran nuevas señales a partir de la
señal a que se refieren, lo que permite usarlas igual que aquellas de las que se derivan,
aportando información no disponible directamente en las señales originales. Esos atributos
son los que siguen:

señal’DELAYED ( tiempo) Proporciona una señal del mismo tipo que la referencia, con un
retraso respecto a la referencia indicado en el campo opcional.

señal’STABLE ( tiempo) Proporciona una señal booleana que es TRUE si en el tiempo


que se indica en el campo opcional no hubo un evento en la
señal referida.

señal’QUIET ( tiempo) Proporciona una señalbooleana que es TRUE si en el tiempo


que se indica no hubo “cambio en drivers” de la señal base.

señal’TRANSACTION Proporciona una señal de tipo BIT que cambia de valor con
cada TRANSACTION o “cambio en drivers” .

Las gráficas siguientes resumen los atributos de señales:


10 ns 20 ns 30 ns

ATRIBUTOS DE SEÑALES tipo resultado referencia

CAMBIOS en DRIVERS ▓ ▓ ▓
SEÑAL ORIGINAL ( orig ) ej.: bit ░ ░ ░
▓ ▓ ▓
SEÑAL’EVENT boolean valor eventos

SEÑAL’LAST_EVENT tiempo valor eventos 0 10 20 10 20 25

SEÑAL’LAST_VALUE = orig. valor eventos

SEÑAL’ACTIVE boolean valor drivers

SEÑAL’LAST_ACTIVE tiempo valor drivers 0 10 20 10 20 5

SEÑAL’DELAYED( 5 NS ) = orig. SEÑAL --

SEÑAL’STABLE ( 8 NS) boolean SEÑAL eventos

SEÑAL’QUIET ( 5 NS ) boolean SEÑAL drivers

SEÑAL’TRANSACTION bit SEÑAL drivers

0 10 20 30
S
S’delayed( 5ns )

S’delayed(15ns)

III - 8
3 – Sentencias concurrentes

De las formas de onda anteriores se pueden exponer como ejemplos de aplicación de


atributos las siguientes expresiones:

S’delayed( 15 ns) ‘1’ -- Resultados o valores que en el instante 30 ns se


S’delayed( 5 ns ) ‘0’ -- obtienen al aplicar los atributos que se indican a
S’STABLE( 15 ns) FALSE -- la señal S. Observar que se puede aplicar atributos
S’STABLE( 5 ns ) TRUE -- a las señales S’delayed(5 ns) y S’delayed(15 ns).
S’EVENT FALSE
S’LAST_EVENT 10 ns
S’LAST_VALUE ‘1’

3.4 Sentencias ASSERT

Es similar a la sentencia ASSERT secuencial, con la diferencia de que puede tener una
etiqueta que no está permitida en la sentencia secuencial y que, al ser concurrente, no puede
ir dentro de una sentencia PROCESS, pero equivale a un proceso de tipo pasivo, es decir,
uno que NO asigna valor a señales, aunque sea sensible a ellas. Al igual que la sentencia
secuencial, se emplea para verificar la ocurrencia de condiciones que se desea hacer patentes
por medio de un mensaje durante la simulación, por ejemplo, detectar valores fuera de
rangos permitidos, violación de márgenes de diseño, de tiempos de guarda tales como setup,
hold, duración de impulsos, etc. Su formato es el siguiente:

[etiqueta] : ASSERT expresión booleana


REPORT “mensaje a emitir si la expresión booleana es FALSE”
SEVERITY nivel del error;

Mientras la sentencia secuencial se ejecuta con el orden impuesto en la descripción del


proceso o subprograma que la contiene, la sentencia concurrente se ejecuta una vez al
iniciarse la simulación y, posteriormente, como las otras sentencias concurrentes, siempre
que haya un evento en alguna de las señales que intervienen en la expresión booleana y a las
que el proceso pasivo es sensible. Un ejemplo puede ser :

negativo : ASSERT ( (a(0) = ‘0’) AND ( b(0) = ‘0’) )


REPORT “operando negativo”
SEVERITY WARNING;

que equivale al proceso :

negativo : PROCESS ( (a(0) , b(0) )


BEGIN
ASSERT ( (a(0) = ‘0’) AND ( b(0) = ‘0’) )
REPORT “operando negativo”
SEVERITY WARNING;
END PROCESS negativo;

Una aplicación particular de esta sentencia es que puede usarse como proceso pasivo
dentro de un formato más complejo de la ENTITY donde está permitida una región para
sentencias concurrentes, lo que permite realizar comprobaciones aplicables a cualquiera de
las ARCHITECTUREs que describan la ENTITY, por ejemplo:

III - 9
3 – Sentencias concurrentes

ENTITY SRlatch IS
PORT ( s,r : IN BIT; q,qn : OUT BIT);
BEGIN
verificar : ASSERT NOT ( ( S = ‘1’) AND ( R = ‘1’) ) -- sentencia concurrente
REPORT “S = R = ‘1’ simultáneamente “
SEVERITY ERROR;
END Srlatch;

que verifica la condición prohibida del SR latch, probando si NO es cierta la condición.

3.5 Sentencias GENERATE

Existen numerosos circuitos digitales compuestos por módulos o células que se


repiten para realizar ciertas tareas. Contadores, memorias, registros etc. son subsistemas
donde se repite un elemento para formar estructuras expandibles, y en ciertos casos
reconfigurables, según la aplicación a que se destinan. En VHDL se dispone de sentencias
que permiten realizar descripciones de estos susbsistemas de manera eficiente, sin necesidad
de repetir las descripciones de los elementos integrantes, simplemente describiendo la forma
en que se interconectan. La sentencia GENERATE se utiliza para aplicar iteraciones sobre el
elemento o componente que se repite en esas descripciones.
Los formatos básicos de los dos tipos existentes de GENERATE son los siguientes:

etiqueta:  FOR parámetros_o_rango | IF condiciones  GENERATE


bloque de declaraciones  -- bloque optativo
BEGIN
sentencias concurrentes  
END GENERATE  etiqueta  ;

En la mayoría de los casos, las estructuras difieren en los elementos de la periferia,


por lo que suele aplicarse una regla de generación acorde con la estructura de los elementos
básicos y su modo de interconexión en el subsistema donde se repiten.

Para permitir que el modelo sea adaptable a la dimensión deseada, se puede hacer uso
de la opción GENERIC permitida al declarar ENTITYs con el formato siguiente:

ENTITY identificador IS
GENERIC (dimension : NATURAL := número de iteraciones );
PORT ( );
END identificador;

El número de iteraciones será un número entero y positivo que determinará el tamaño o


dimensión del modelo que se quiere obtener con la sentencia GENERATE.

En el ejemplo siguiente se presenta un convertidor serie-paralelo construido a partir de


elementos D-flip-flop que se repiten con la sentencia:

III - 10
3 – Sentencias concurrentes

LIBRARY IEEE;
USE IEEE. STD_LOGIC_1164.ALL;

ENTITY SaP_convertidor IS --Convertidor Serie a Paralelo


GENERIC (WIDTH: natural :=8); --Definido pata tener tamaño “byte”
PORT( clk: in std_logic;
Serial_in: in std_logic;
salidas: out std_logic_vector (WIDTH -1 downto 0));
END SaP_convertidor;

ARCHITECTURE convertidor OF SaP_convertidor IS


signal cuenta: std_logic_vector (WIDTH downto 0);
signal cuenta_next: std_logic_vector (WIDTH-1 downto 0);

BEGIN
cuenta(WIDTH) <= Serial_in;
dff_gen:
FOR i in (WIDTH-1) downto 0 GENERATE
process (clk)
begin -- Modelo de D flipflop
if (clk'event and clk ='1') THEN -- iterado con la sentencia
cuenta(i) <= cuenta_next(i); -- FOR GENERATE
end if ;
end process;
cuenta_next(i) <= cuenta(i+1); --Salidas a señal interna
END GENERATE;
salidas <= cuenta(WIDTH-1 downto 0);
END convertidor;

En el apartado 6.3 del capítulo 6 – Modelos estructurales se presentan dos ejemplos


más de aplicación de la sentencia GENERATE que incluyen, además, otros conceptos VHDL
que sería prematuro presentar aquí. No obstante, aunque esta sentencia sea sintetizable en la
mayoría de las herramientas de síntesis de FPGAs, hay matices particulares en cada
herramienta que deben observarse para obtener resultados de síntesis aceptables.

III - 11
4. Sentencias secuenciales
Se utilizan para modelar comportamiento por procedimientos algorítmicos, por lo que
su uso está permitido únicamente dentro de sentencias Process o subprogramas.

4.1 Sentencias IF

Permiten seleccionar la ejecución de diferentes grupos de sentencias en función del


resultado booleano de expresiones o condiciones. El formato general de la sentencia es

IF condición_1ª THEN -- Puede haber varios IF anidados


secuencia 1ª de sentencias;
{ ELSIF condición_2ª THEN -- Cláusulas ELSIF opcionales.
secuencia 2ª de sentencias; -- Puede haber varias cláusulas ELSIF anidadas.
[ ELSE -- Cláusula ELSE opcional. Solo puede haber
secuencia 3ª de sentencias;] -- una cláusula ELSE.
END IF ;

Este formato general contiene tres estructuras básicas como muestran los ejemplos :

IF ( semáforo = rojo ) THEN


barrera := baja; -- si se cumple la condición, si es cierta, se ejecutan
intermitente := encendido; -- las sentencias que siguen
END IF;

IF ( semáforo = rojo ) THEN


barrera := baja; -- si se cumple la condición, si es cierta, se ejecutan
intermitente := encendido; -- las sentencias que siguen y termina la sentencia IF

ELSE -- si no se cumple la condición se ejecutan las


barrera := alta; -- sentencias después de la cláusula ELSE
intermitente := apagado; -- y se termina la sentencia IF.
END IF;

IF ( semáforo = rojo ) THEN -- si se cumple condición 1ª, si es cierta, se ejecutan


barrera := baja; -- las sentencias que siguen y termina la sentencia IF.
intermitente := encendido;
-- Si no se cumple la condición 1ª, comprobar
ELSIF ( semáforo = ambar ) THEN -- si se cumple la condición 2ª. Si es cierta,
barrera := alta; -- se ejecutan las sentencias que siguen
intermitente := encendido; -- y se termina la sentencia IF.

ELSE -- si no se cumple la condición 1ª, ni tampoco la 2ª,


barrera := alta; -- se ejecutan las sentencias después de la cláusula
intermitente := apagado; -- ELSE y se termina la sentencia IF.
END IF;

IV - 1
4 – Sentencias secuenciales

El uso de cláusulas ELSIF es una alternativa al uso de IFs anidados que, aún siendo
legales en VHDL, tienen una lectura e interpretación más complejas que las resultantes con
cláusulas ELSIF. El resultado de usar cláusulas ELSIF o IFs anidados no es normalmente el
mismo. No hay equivalencia directa, aunque las descripciones hechas con IFs anidados
puedan sustituirse con sentencias basadas en ELSIFs. Vease un ejemplo:

IF semaforo = rojo THEN IF semaforo = rojo THEN


barrera := baja; barrera := baja;
ELSIF ticket = ‘1’ THEN IF ticket = ‘1’ THEN
intermitente := pulsante; intermitente := pulsante;
END IF; END IF;
END IF;

Otro aspecto importante es el uso u omisión de las cláusulas ELSE, que puede dar
lugar a descripciones con comportamientos imprevistos. El siguiente ejemplo permite ver la
importancia de las cláusulas ELSE al modelar circuitos:

Se supone que la descripción siguiente forma parte de una ARCHITECTURE en la que


se hace una descripción secuencial de la que solo se reproduce la parte relativa al ejemplo

IF ( c = ‘1’ ) THEN
IF ( a = ‘1’ OR b = ‘1’ ) THEN a a
s <= ‘1’; b
b s
ELSE c
s <= ‘0’; s
END IF;
ELSE
s <= ‘0’;
END IF;

La descripción anterior corresponde al circuito de la figura y formas de onda adjuntas.


Cuando se utilizan herramientas CAD para síntesis se infieren elementos hardware y
el resultado, aunque no evidente a primera vista, puede diferir notablemente por el empleo
u omisión de la claúsula ELSE. En el ejemplo, si se suprime la cláusula ELSE del IF
externo, el comportamiento que se describe cambia a
c
IF ( c = ‘1’ ) THEN
a s
IF ( a = ‘1’ OR b = ‘1’ ) THEN a b s
s <= ‘1’; b cc
ELSE
s
s <= ‘0’;
END IF;
END IF;

Al suprimir la cláusula ELSE externa, se infiere la existencia de un elemento donde se


guarda el último valor definido de la señal de salida para las condiciones de entradas en las
que la señal de salida no está definida en la sentencia IF-THEN externa. Nótese que en esta
descripción no se indica como responde el circuito cuando c cambia de ‘1’ a ‘0’.
Si se suprime también la otra cláusula ELSE, el comportamiento cambia de nuevo a

IV - 2
4 – Sentencias secuenciales

c
IF ( c = ‘1’ ) THEN a
IF ( a = ‘1’ OR b = ‘1’ ) THEN a b ss
salida <= ‘1’; b c
END IF; c
END IF; s

se infiere otro elemento donde se almacena la salida OR para todos los casos no incluidos en
la sentencia IF interna Así pues, para evitar imprevistos, conveniente incluir siempre la
cláusula ELSE o, al menos, revisar con atención los efectos de su omisión.

ENTITY inf_AND_LATCH IS -- EN ESTA DESCRIPCIÓN SE SIMULAN LOS TRES CASOS


PORT(permiso, dato : IN BIT;
salida, sal_latch, sal_dato : OUT BIT);
END inf_AND_LATCH;

ARCHITECTURE inferencias OF inf_AND_LATCH is


BEGIN
PROCESS (PERMISO, DATO) -- INFERENCIA DE AND
BEGIN -- DOS cláusulas ELSE
IF ( permiso = '1' ) THEN
IF dato = '1' THEN
salida <= '1';
ELSE
salida <= '0';
END IF;
ELSE
salida <= '0';
END IF;
END PROCESS;
PROCESS (PERMISO, DATO) --INFERENCIA DE LATCH
BEGIN -- UNA cláusula ELSE
IF ( permiso = '1' ) THEN
IF dato = '1' THEN
sal_latch <= dato;
ELSE
sal_latch <= '0';
END IF;
END IF;
END PROCESS;
PROCESS (PERMISO, DATO) --INFERENCIA a ENCLAVAMIENTO
BEGIN -- NINGUNA cláusula ELSE
IF ( permiso = '1' ) THEN
IF dato = '1' THEN
sal_dato <= dato;
END IF;
END IF;
END PROCESS;
END inferencias;

En las páginas siguientes se muestran algunos ejemplos y cronogramas de simulación


post-síntesis obtenidos con las alternativas comentadas en el uso de sentencias IF.

IV - 3
4 – Sentencias secuenciales
4.1.1 INFERENCIAS BÁSICAS DE SENTENCIAS “IF” EN SÍNTESIS VHDL
ENTITY inf_AND_LATCH IS
PORT(permiso, dato : IN BIT;
sal_AND, sal_latch, sal_dato : OUT BIT);
END inf_AND_LATCH;
ARCHITECTURE inferencias OF inf_AND_LATCH is … sobre la importancia de la cláusula ELSE
BEGIN
PROCESS (PERMISO, DATO)
BEGIN
IF ( permiso = '1' ) THEN
IF dato = '1' THEN
sal_AND <= '1';
ELSE
sal_AND <= '0';
END IF;
ELSE
sal_AND <= '0';
END IF;
END PROCESS;
PROCESS (PERMISO, DATO)
BEGIN
IF ( permiso = '1' ) THEN
IF dato = '1' THEN
sal_latch <= dato;
ELSE
sal_latch <= '0';
END IF;
END IF;
END PROCESS;
PROCESS (PERMISO, DATO)
BEGIN
IF ( permiso = '1' ) THEN -- TODO “IF” DEBERÍA LLEVAR UNA CLÁUSULA “ELSE” EXPLÍCITA, PORQUE, por ejemplo:
IF dato = '1' THEN -- SI dato = ‘1’ sal_dato <= dato, … PERO si dato /= ‘1’, VHDL mantendrá el valor de sal_dato que hubiera anteriormente,
sal_dato <= dato; -- lo que implica la existencia de un elemento de memoria
END IF; -- LA AUSENCIA DE “ELSE” EQUIVALE A MANTENER EL VALOR PREVIAMENTE ASIGNADO, ES DECIR, A INCLUIR UNA SENTENCIA DE FORMA:
END IF; -- ELSE
END PROCESS; -- sal_dato <= sal_dato;
END inferencias; -- equivalente a una realimentación con bucle cerrado, es decir, un elemento de memoria que conviene no olvidar…

IV - 4
4 – Sentencias secuenciales
LIBRARY ieee; USE IEEE.STD_LOGIC_1164.all; -- Flip-flop
ENTITY inf_FpFp IS
PORT (permiso, dato, reloj : IN STD_LOGIC;
salida, sal_AND : OUT STD_LOGIC);
END inf_FpFp;
ARCHITECTURE inf_FF OF inf_FpFp is
BEGIN
PROCESS ( dato, reloj )
BEGIN
IF ( reloj'EVENT AND reloj = '1' ) THEN
salida <= dato;
END IF;
END PROCESS;
sal_AND <= permiso AND dato;
end inf_FF;

LIBRARY ieee; USE IEEE.STD_LOGIC_1164.all; -- Flip-flop con preset y clear asíncronos


ENTITY inf_FpFp_asinc IS
PORT(dato, preset, clear, reloj : IN STD_LOGIC;
salida : OUT STD_LOGIC) ;
END inf_FpFp_asinc;

ARCHITECTURE inf_FFs OF inf_FpFp_asinc is


BEGIN
PROCESS ( reloj , preset, clear )
BEGIN
IF ( preset = '1' ) THEN
salida <= '1' ;
ELSIF ( clear = '1' ) THEN
salida <= '0' ;
ELSIF ( reloj'EVENT AND reloj = '1' ) THEN -- cláusula de transición de reloj aislada, después de PRESET y CLEAR
salida <= dato; -- solo afecta a la señal “dato”
END IF; -- “salida” obedece CLEAR y PRESET, antes que a flancos de reloj y “dato”
END PROCESS; -- Se cumplen condiciones de PRESET o CLEAR antes que ELSIF ↑reloj y acaba IF
end inf_FFs;

IV - 5
4 – Sentencias secuenciales

LIBRARY ieee; USE IEEE.STD_LOGIC_1164.all;


ENTITY inf_FpFp_sinc IS
PORT(dato, preset, clear, reloj : IN STD_LOGIC;
salida : OUT STD_LOGIC);
END inf_FpFp_sinc;

ARCHITECTURE inf_FFsc OF inf_FpFp_sinc is


BEGIN

PROCESS ( reloj , clear, preset ) -- Flip-flop con preset y clear síncronos


BEGIN
IF ( reloj'EVENT AND reloj = '1' ) THEN -- cláusula de transición de clk externa, incluyendo IF’s de PRESET y CLEAR
IF preset = '1' THEN -- IF’s anidados con precedencia del IF de transición de clk sobre los de CLEAR y PRESET
salida <= '1' ;
ELSIF clear = '1' THEN
salida <= '0' ;
ELSE
salida <= dato;
END IF;
END IF;
END PROCESS;
end inf_FFsc;


“salida” conmuta, por acción de CLEAR o PRESET, con el siguiente flanco ↑ clk

IV - 6
4 – Sentencias secuenciales

En los tres ejemplos siguientes se puede observar la versatilidad de las sentencias IF y


PROCESS para describir modelos combinacionales fácilmente sintetizables:

1. Multiplexor con simple sentencia IF

ENTITY if_multiplexer IS
PORT(a,b,c,d: IN BIT;
sel: IN BIT_vector(1 downto 0);
salida: OUT BIT);
END if_multiplexer;

ARCHITECTURE comparable OF if_multiplexer IS


BEGIN
PROCESS (a ,b ,c ,d , sel)
BEGIN
IF (sel="00") THEN
salida <= a;
ELSIF (sel="01") THEN
salida <= b;
ELSIF (sel="10") THEN
salida <= c;
ELSE
salida <= d;
END IF;
END PROCESS;
END comparable;

2. Decodificador con simple sentencia IF


ENTITY if_decoder IS
PORT ( sel: IN BIT_VECTOR (1 downto 0);
salida: OUT BIT_VECTOR (3 downto 0));
END if_decoder;

ARCHITECTURE comparable OF if_decoder IS


BEGIN
PROCESS (sel)
BEGIN
IF (sel="00") THEN
salida <= "0001";
ELSIF(sel="01") THEN
salida <= "0010";
ELSIF(sel="10") THEN
salida <= "0100";
ELSE
salida <= "1000";
END IF;
END PROCESS;
END comparable;

IV - 7
4 – Sentencias secuenciales

3. Registro de desplazamiento con “clear” asíncrono por cláusula OTHERS


LIBRARY IEEE;
USE IEEE.STD_LOGIC_1164.ALL;

ENTITY others_shift_register IS
PORT(clk, SI, CLR : in std_logic;
SO : out std_logic);
END others_shift_register;

ARCHITECTURE otros OF others_shift_register IS


signal temp: std_logic_vector(7 downto 0);
BEGIN
PROCESS(clk, clr)
BEGIN
IF (clr='1') THEN -- “clear” asíncrono
temp <= (OTHERS => '0'); -- cláusula OTHERS hace “clear”
ELSIF (clk'EVENT and clk ='1') THEN
temp <= temp(6 DOWNTO 0) & SI; -- concatenación de Shift_In
END IF; -- ¡¡¡ NO HAY ELSE !!!
END PROCESS;
SO <= temp(7);
END otros;

(OTHERS => '0') asigna valor ‘0’ a todos los elementos del array “temp” a los que
no se ha asignado valor anteriormente; puede hacerlo de forma asíncrona o síncrona.

4.2 Sentencias CASE

Se usan cuando, a partir de los valores de una expresión, se desea seleccionar alguna
de las opciones posibles, lo que equivale en comportamiento al de la sentencia de asignación
selectiva de valor a señales. Su formato básico es :

CASE expresión IS
W HEN selección => secuencia de sentencias;
{ W HEN selección => secuencia de sentencias 
END CASE;

cuyo significado es que si el valor de una selección es alguno de los posibles que se indican
de la expresión, deberán ejecutarse las sentencias que sigan a la correspondiente cláusula
W HEN. Es importante a tener en cuenta que deberán especificarse las acciones a tomar para
todos los casos posibles o valores que pueden tenerse para la expresión en la sentencia.

La selección puede tener varias formas :

- Un simple valor del tipo de la expresión : 5, ‘0’, “0010”, rojo, etc.


- Un rango de valores : 0 TO 9, rojo TO verde, etc.
- Una serie de valores separados por el delimitador | : 2|378, rojo|amarillo, etc.
- La palabra reservada OTHERS, equivalente a “todo lo no especificado antes”.

IV - 8
4 – Sentencias secuenciales

El siguiente ejemplo permite comparar la sentencia CASE con la asignación selectiva del
ejemplo en apartado 3.3.3 o la sentencia IF del modelo IF_decoder en la sección anterior.
LIBRARY IEEE;
USE IEEE.std_logic_1164.all;

ENTITY case_decoder_3a8 IS
PORT ( adr : IN std_logic_VECTOR (2 DOW NTO 0);
fin : OUT std_logic;
sal : OUT std_logic_VECTOR (7 DOW NTO 0)) ;
END case_decoder_3a8;

ARCHITECTURE directa OF case_decoder_3a8 IS


BEGIN
PROCESS(adr) -- En la sentencia CASE
BEGIN -- cada W HEN puede tener varias asignaciones
CASE adr IS
W HEN "000" => sal <= "00000001"; fin <= '0';
W HEN "001" => sal <= "00000010"; -- Inferencias de “latches”
W HEN "010" => sal <= "00000100";
W HEN "011" => sal <= "00001000";
W HEN "100" => sal <= "00010000"; fin <= '1';
W HEN "101" => sal <= "00100000"; -- Inferencias de “latches”
W HEN "110" => sal <= "01000000";
W HEN "111" => sal <= "10000000";
W HEN OTHERS => sal <= "ZZZZZZZZ"; fin <= 'Z';
END CASE;
END PROCESS; -- En la asignación selectiva, cada W HEN
END directa; -- solo puede tener una asignación de señal

Otros ejemplos de la sentencia CASE

CASE dato_triestado IS
W HEN '0' => entrada <= '0';
W HEN '1' | 'Z' => entrada <= '1';
END CASE;

CASE x + y + z IS
W HEN 0 => suma <= “ cero “;
W HEN 1|2 => suma <= “ bajo “;
W HEN 9|10 => suma <= “ alto” ;
W HEN (3 to 8) => suma <= “ medio” ;
W HEN OTHERS => NULL;
END CASE;

4.3 Sentencias NULL

Indican que no debe realizarse acción alguna, como al final del ejemplo anterior.

IV - 9
4 – Sentencias secuenciales

4.4 Sentencias LOOP

Se emplean para repetir una acción que, en la mayoría de los casos, ocurre mientras se
mantiene o cumple una determinada condición. Los LOOP pueden anidarse. Existen tres
tipos de sentencias LOOP con los formatos genéricos que se indican:

4.5.1 LOOP SIMPLE


LOOP
[etiqueta : [esquema repetitivo LOOP y := x**2;
secuencia de sentencias EXIT WHEN x > 10 ;
END LOOP [etiqueta ; x := x + 1;
END LOOP;

Si no se especifica un esquema iterativo, el LOOP entraría en un proceso repetitivo infinito.


Para evitar este caso, que sería rechazado por el compilador, debe incluirse alguna sentencia
para salir del bucle en función de alguna condición. Es típico el uso de sentencias EXIT.

4.4.2 LOOP FOR


[etiqueta : FOR nombre de índice IN rango discreto del índice LOOP
secuencia de sentencias
END LOOP [etiqueta ;

No es necesario declarar el índice, ya que se considera una variable local declarada al


inicializar el rango de valores entre los que se mueve. Su valor, por tanto, no es exportable.
Si en la región donde opera el LOOP existe otra variable de igual nombre pero distinto
tipo, no interaccionarán entre ellas. Pero, en general, no es buena práctica sobrecargar si no
es necesario. El índice puede ser un rango de valores de un tipo enumerado:
FOR dia IN lun TO sab LOOP FOR i IN 1 to 10 LOOP
color := negro; y := x**2;
END LOOP; END LOOP;

4.4.3 LOOP WHILE


[etiqueta : WHILE condición booleana LOOP
secuencia de sentencias a ejecutar si la condición es cierta
sentencia de alteración del valor relacionado a la condición booleana
END LOOP [etiqueta ;

Dentro del bucle no hay regiones declarativas. Las variables que intervengan en la
condición booleana deben ser declaradas previamente para que el programa pueda evaluar la
condición la primera vez que la encuentra. Las variables se alteran dentro del bucle y, al no
ser locales a él, es necesario tener presente si el valor con que quedan puede afectar a otras
secciones del área secuencial donde está el bucle y actuar en consecuencia. El ejemplo sería:
x := 1;
WHILE x <= 10 LOOP
y := x**2;
x:= x + 1;
END LOOP;

IV - 10
4 – Sentencias secuenciales

Las sentencias LOOP se emplean, principalmente, para describir funciones y modelos


algorítmicos que no tienen relación directa al hardware y tampoco son sintetizables de
manera automática, pero las herramientas CAD, desde sus comienzos compiten para hacer
más y mejor, incluso en las inferencias de síntesis. Véase un ejemplo sencillo y sintetizable:

LIBRARY IEEE;
USE IEEE.STD_LOGIC_1164.ALL;

ENTITY serial_shift_register IS -- Shift register con salida y entrada serie


PORT(clk, SI : in std_logic;
SO : out std_logic);
END serial_shift_register;

ARCHITECTURE serie OF serial_shift_register IS


signal temp: std_logic_vector(7 downto 0);

BEGIN
PROCESS(clk)
BEGIN
IF(clk'EVENT and clk ='1') THEN
FOR i IN 0 to 6 LOOP --bucle FOR LOOP
temp(i+1) <= temp(i);
END LOOP;
temp(0) <= SI;
END IF;
END PROCESS;
SO <= temp(7);
END serie;

4.5 Sentencias NEXT

Se emplean dentro de LOOPs para saltar la ejecución de las sentencias que siguen
dentro del paso iterativo en curso o, simplemente, para continuar en el inicio del siguiente
ciclo iterativo si la variable de iteración sigue dentro del rango del bucle, ya que si no
finalizará el bucle. Su formato es:
NEXT [ etiqueta_de_LOOP] [W HEN condición ] ;

y un ejemplo, relacionado con bucles LOOP de distinto tipo anidados :


bucle_1 : FOR i IN 1 TO 100 LOOP
j := 150;
bucle_2: LOOP
j := j - i;
NEXT bucle_1 W HEN j < ( i * i );
END LOOP bucle_2;
END LOOP bucle_1;

Nótese que el hecho de poner la etiqueta de un bucle permite actuar con la sentencia
NEXT dentro de bucles anidados. Si no se incluye la etiqueta, por defecto se reinicia el bucle
interno donde está la sentencia NEXT cuando se cumple la condición adjunta a W HEN.

IV - 11
4 – Sentencias secuenciales

Si se omite la condición, la sentencia es incondicional y se ejecuta siempre que la


secuencia llega a ella.
Al igual que las sentencias LOOP donde se insertan, las sentencias NEXT y EXIT,
descrita a continuación, no tienen una inferencia directa con hardware, por lo que no se
suelen incluir en modelos para síntesis, aunque se empleen en funciones sintetizables.

4.6 Sentencias EXIT

Su uso, formato y comportamiento son muy similares a los de la secuencia NEXT:

EXIT [ etiqueta_de_LOOP] [W HEN condición ] ;

solo que en lugar de saltar a la siguiente iteración, salta fuera del bucle a que se refiere la
etiqueta opcional o, por defecto, fuera del bucle que incluye la sentencia EXIT, continuando
el programa en la sentencia que sigue a la sentencia END LOOP del bucle del que se sale al
cumplirse la condición fijada a la cláusula WHEN . Si la condición no existe, la salida del
bucle se ejecuta siempre que se accede a EXIT.

El ejemplo siguiente es aplicable para EXIT o NEXT

bucle_1: FOR i IN 1 TO 10 LOOP -- i se autodeclara aquí


secuencia de sentencias 1ª ;

bucle_2 : W HILE k <= 100 LOOP -- k estará declarada previamente


secuencia de sentencias 2ª ;
NEXT bucle_1 W HEN condición 1ª ;
NEXT bucle_2 W HEN condición 2ª ;
secuencia de sentencias 3ª ; -- k se modifica aquí
END LOOP bucle_2;

END LOOP bucle_1;


y otro ejemplo con bucles anidadados:

bucle_1 : LOOP
i := i + 1;
j := 200;

bucle_2: LOOP
IF j < ( i * i ) THEN
EXIT bucle_2;
END IF;
j := j - i;
END LOOP bucle_2;

EXIT bucle_1 W HEN i > 10;


END LOOP bucle_1;

IV - 12
4 – Sentencias secuenciales

4.7 Sentencias ASSERT

Durante los procesos de simulación del modelo, el diseñador necesita información de


la evolución de señales o variables para conocer el comportamiento del modelo. En VHDL
se dispone de la sentencia ASSERT para emitir mensajes cuyo contenido está prefijado por
el diseñador en función del comportamiento que desea verificar automáticamente.

La sentencia ASSERT verifica el resultado booleano de una expresión y si ésta es cierta, si


se cumple la condición prefijada, la sentencia ASSERT no actúa. Por el contrario, si el
resultado de la verificación es falso, se emite un mensaje. El formato es :

ASSERT condición; -- expresión booleana a evaluar .


[ REPORT “mensaje”  -- emitir si el resultado de evaluar la condición es falso.
[ SEVERITY nivel  -- tipo SEVERITY del paquete STANDARD

En bastantes casos, la condición que se fija va precedida de una cláusula NOT. El


sentido de esto no es otro que fijar la actuación de la sentencia cuando la “condición
negada” es cierta. La decisión para utilizar uno u otro modo de condición es simplemente
reducir el tamaño o número de las condiciones a verificar: Puede ser más fácil y corto
verificar que NO ocurre algo incorrecto, que comprobar que ocurren los demás casos
posibles que son correctos.

ASSERT NOT ( set ='1' AND rst = '1') -- verifica si (set = rst = '1') es TRUE
REPORT " set y reset son '1' " -- mensaje del fallo a evitar detectado
SEVERITY ERROR; -- y detiene la simulación

El “mensaje” , que debe ir entre comillas, reportará un aviso cuyo significado conoce
el diseñador. En cuanto al nivel del tipo SEVERITY enviado, determinará si la simulación
debe continuar o no.
Normalmente la simulación se detiene con los niveles ERROR y FAILURE y será el
creador del modelo quien deba prejuzgar la gravedad del posible error o condición que
quiera verificar.
El nivel NOTE puede considerarse como un simple aviso, tal vez solo para avisar de
que se ha cubierto una fase o etapa de la verificación.
El nivel WARNING tiene un nivel de importancia más alto. No detiene la simulación
porque, por ejemplo, los resultados pendientes de obtener siguen siendo significativos e
inafectados, tal vez, por la causa que motivó el mensaje de nivel WARNING. No obstante, el
mensaje indica que hay algo que debe subsanarse. En cualquier caso la acción que se deriva
de un nivel de severidad, está relacionado a la herramienta CAD en que se hace la
simulación y , posiblemente, a los parámetros que determinen su acción.

Existe también una sentencia ASSERT concurrente, que actúa cuando alguna señal
referida en la condición a verificar tiene un evento o cambio de valor. El formato es idéntico
al de la sentencia secuencial, pero su ocurrencia viene determinada por el contexto de
ejecución dentro del área concurrente donde se ubica.

IV - 13
4 – Sentencias secuenciales

4.8 Sentencias WAIT

Por su relación con el parámetro tiempo, las sentencias WAIT son elementos clave en
las descripciones VHDL, empleándose en procesos y subprogramas en los que la suspensión
temporal de su ejecución permite modelar retardos, sincronismos, etc. El formato más
complejo de la secuencia es:

WAIT [ON lista  [ UNTIL condición  [ FOR tiempo  ;

Las opciones pueden combinarse, pero siempre debe existir al menos una de ellas. Si
la palabra WAIT está aislada la simulación se detiene indefinidamente. Los formatos
elementales de la sentencia son:

4.8.1 WAIT ON señales


Suspende la ejecución de un PROCESS hasta que en alguna de las señales de la lista
hay un evento o cambio en su valor. Esta opción de WAIT se utiliza como alternativa a la
“lista de sensibilidad” de un proceso, siempre que no haya otro WAIT interno.

4.8.2 WAIT UNTIL condición


La condición tiene resultado booleano y suspende la ejecución de un proceso hasta
que la condición se hace cierta. La condición se evalúa cuando cualquiera de las señales
implicadas en la condición cambia de valor. Debe tenerse en cuenta el hecho de que esta
opción de W AIT espera un evento en una señal para continuar. Así pues, cuando la condición
de espera es una expresión en la que intervienen varios objetos, al menos uno de ellos debe
ser señal y en ella deberá producirse el evento que hace cierta la condición de espera y que
activa el proceso suspendido

W AIT UNTIL (( permiso = TRUE) OR (clk = ‘1’)) ;

El proceso continúa en la sentencia que sigue a WAIT. Esta opción de W AIT es utilizada
para descripción de sincronismos y flancos de señal. Es una opción normalmente soportada
para modelar sincronismos en herramientas de síntesis.

4.8.3 WAIT FOR especificación de tiempo


Suspende la ejecución hasta que transcurre el tiempo especificado en la sentencia.
Los ejemplos siguientes muestran empleos combinados de las opciones WAIT :
W AIT; -- Espera indefinida e incondicional
W AIT FOR 50 NS ; -- Tiempo fijo de espera
W AIT ON x,y,z; -- Espera hasta el cambio de alguna señal
W AIT UNTIL y = ‘1’; -- Espera hasta que y = ‘1’
W AIT ON x,y,z FOR 1ms; -- Espera máxima 1ms hasta cambio de x,y o z
W AIT ON x,z UNTIL y = ‘1’ ; -- Espera un cambio en x, z, o y, siendo y = ‘1’
W AIT UNTIL x=y FOR 2 ms; -- Espera máxima de 2 ms hasta que x = y

El uso de W AIT FOR es frecuente para modelar retardos máximos o “time out”.

IV - 14
4 – Sentencias secuenciales

Combinado con otras opciones de W AIT puede proporcionar resultados confusos, ya


que la espera puede finalizar por un “time out” y no por la causa correcta que se espera en
el modelo. El ejemplo siguiente muestra un posible empleo de la opción para no detener la
simulación por espera de un evento que no se produce, pero que es necesario y, por tanto,
no debe ser enmascarado por un “time out” :
W AIT until ok = ‘1’; -- si la señal “ok” no cambia, la simulación se
bien <= ‘1’ after 20 ns; -- detiene indefinidamente y no puede simularse
W AIT until ok = ‘0’; -- las secciones relacionadas a la señal “bien”.
bien <= ‘0’ after 20 ns;
Para no condicionar la simulación del resto del modelo a la señal “ok”, se fuerza “time
out” y se hace uso de ASSERT para poner de manifiesto la ausencia de cambio en “ok” :
W AIT until ( ok = ‘1’) FOR 1 ms ;
ASSERT ( ok = ‘1’ )
REPORT “ ok = ‘1’ no se produjo”
SEVERITY W ARNING;
bien <= ‘1’ after 20 ns;
W AIT until ( ok = ‘0’) FOR 1 ms ;
ASSERT ( ok = ‘0’ )
REPORT “ ok = ‘0’ no se produjo”
SEVERITY W ARNING;
bien <= ‘0’ after 20 ns;

Las sentencias WAIT son utilizadas frecuentemente para la descripción algorítmica de


relojes, osciladores o generadores de ondas. Un ejemplo de descripción sintácticamente
correcta, aunque NO SINTETIZABLE, es el siguiente:

ENTITY generador IS
GENERIC (tiempo_uno: TIME := 10 ns; tiempo_cero: TIME := 20 ns);
PORT ( sincro : IN BIT ; pulsos : OUT BIT ) ;
END generador;

ARCHITECTURE algoritmica OF generador IS


BEGIN
PROCESS
BEGIN
WAIT UNTIL sincro = '1';
WHILE sincro = '1' LOOP
pulsos <= '0';
WAIT FOR tiempo_uno; --cláusula no sintetizable
pulsos <= '1';
WAIT FOR tiempo_cero; --cláusula no sintetizable
END LOOP;
END PROCESS;
END algoritmica;

La sentencia WAIT se utiliza escasamente en síntesis y, cuando se hace, ocurre con


formas muy definidas y limitando a un solo WAIT por PROCESS

IV - 15
5. Subprogramas
Los subprogramas son secuencias de declaraciones y sentencias con los que se
realizan operaciones o algoritmos que se aplican en zonas diferentes de una descripción o
que se repiten a lo largo de ella. Para evitar la repetición de código, al igual que en otros
lenguajes, el VHDL permite invocar a las subrutinas desde sentencias o expresiones
colocadas en la zona del programa donde se necesitan los resultados que suministran los
subprogramas. Existen dos tipos de subprogramas: Funciones y PROCEDUREs.
En los subprogramas cabe distinguir una declaración y un cuerpo, lo que equivale a
declarar una interfaz y describir el algoritmo que le corresponde. Posteriormente, desde
algún punto de la descripción se invoca o llama al subprograma de acuerdo con la interfaz o
estructura de su declaración. Mientras la llamada a funciones es parte de una expresión
VHDL, la llamada a PROCEDUREs es una sentencia en sí. Tanto unas como otras se pueden
considerar concurrentes o secuenciales, según el área desde la que se llaman.
Los PROCEDUREs son recursos de escaso uso en VHDL. Su estructura es compleja y
su uso en modelos sintetizables es, prácticamente, nulo, por lo que cae fuera de los objetivos
de este documento.

5.1 Funciones

Las funciones tienen siempre un cuerpo donde se define la operación que realizan a
partir de los parámetros de entrada para devolver un único valor como resultado. Aunque
no es preceptivo declarar las funciones, es conveniente hacerlo porque simplifica la
generación de código y se evitan las restricciones que conlleva la ausencia de declaración.
Hay dos situaciones en las que la declaración de la función es necesaria:

- Cuando sea recursiva, es decir, cuando pueda autollamarse.


- Si el cuerpo de la función está después de la expresión donde se llama a la función.

Las declaraciones deben hacerse en áreas declarativas con el formato:


FUNCTION nombre ( lista formal de parámetros ) RETURN tipo_ de_respuesta;

La lista formal de parámetros, en su forma más completa, tiene el formato:


(objeto nombre : modo tipo )

objeto: Puede ser CONSTANT o SIGNAL. Por defecto es CONSTANT.


No puede ser VARIABLE.
nombre: Puede ser una lista de nombres, separados por ‘,’ si son del mismo tipo.
Si los parámetros son de distinto tipo estarán separados por ‘;’ .
modo: Solo puede ser modo IN. Por esto se omite, ya que está implícito.
tipo: Para cada objeto debe indicarse su tipo. El tipo_de_respuesta puede ser
distinto del de los parámetros, caso típico en funciones de conversión.

V-1
5 - Subprogramas

Algunos ejemplos de declaraciones son:

FUNCTION binario_a_entero ( dato : BIT_VECTOR ) RETURN INTEGER ;


FUNCTION entero_a_bin ( entero: INTEGER; bits : POSITIVE ) RETURN BIT_VECTOR;
FUNCTION incremento ( dato : BIT_VECTOR ( N DOWNTO 0) ) RETURN BIT_VECTOR;

El cuerpo de la función define lo que la función hace y consiste en una relación de


sentencias secuenciales. No pueden incluirse sentencias concurrentes.

El formato del cuerpo de las funciones es:

FUNCTION nombre_de_función ( lista de parámetros ) RETURN tipo_de_respuesta IS


-- sentencias declarativas locales de la función
BEGIN
-- sentencias secuenciales
RETURN expresión ; -- puede haber varias de este formato
END nombre_de_función ;

En las sentencias declarativas se insertan objetos locales alterables, ya que los


parámetros de entrada son inalterables por ser de modo IN . Estos objetos, por ser locales, no
son utilizables fuera del cuerpo de la función donde han sido declarados.
Aunque pueden existir varias sentencias con la cláusula RETURN y una expresión
adjunta con el valor que la función devuelve, solo una de ellas se ejecutará y al hacerlo
terminará la ejecución de la función. Este tipo de repeticiones suele ir asociado a
condiciones autoexcluyentes que, al cumplirse una de ellas, bien elimina la consideración de
las otras o por el orden secuencial se considera prioritaria y es la que determina el resultado
que devuelve la función.
Las funciones se puedan considerar como macrooperadores, pero existen dos tipos de
funciones con aplicaciones muy concretas que les dan nombre:

- Funciones de Conversión, utilizadas para conversión de tipos en VHDL.


- Funciones de Resolución , aplicadas para determinar el valor que tendrá una señal a
la que varios drivers asignan valor simultáneamente.

Dos ejemplos representativos de funciones de conversión son:

FUNCTION binario_a_entero (dato: BIT_VECTOR ) RETURN INTEGER IS


VARIABLE resultado: INTEGER := 0;
BEGIN -- ‘RANGE actúa como una función y
FOR n IN dato’RANGE LOOP -- devuelve (dato_bajo TO dato_alto)
IF dato(n) = ‘1’ THEN
resultado := resultado + ( 2** n);
END IF;
END LOOP; -- operador “**” NO SOPORTADO en MAX+plus II
RETURN resultado; -- operador “**”SOPORTADO en Quartus II
END binario_a_entero;

y la función de conversión complementaria:

V-2
5 - Subprogramas

FUNCTION entero_a_bin (entero:INTEGER; bits: POSITIVE ) RETURN BIT_VECTOR IS


VARIABLE binario : BIT_VECTOR ( bits -1 DOWNTO 0 );
VARIABLE numero : INTEGER := 0;
VARIABLE cociente : INTEGER := 0;
BEGIN
numero := entero;
FOR i IN binario’RANGE LOOP -- Sintetizado con Quartus II
cociente := numero / ( 2 ** i ); -- MAX+plus II NO SOPORTA operador “**”
numero := numero REM ( 2** i );
IF ( cociente = 1 ) THEN
binario ( i ) := ‘1’ ;
ELSE
binario ( i ) := ‘0’ ;
END IF;
END LOOP;
RETURN binario;
END entero_a_bin;

A estas funciones podrían llamarlas expresiones como las siguientes:

salida <= binario_a_entero ( objeto de tipo bit_vector )


objeto bit_vector ( bits 1 DOWNTO 0 ) <= entero_a_bin ( objeto INTEGER, bits )

en las que se muestra el formato de la llamada a función que, en forma genérica, es :

expresión <= [ expresión ] identificador de función ( valor de parámetros )

Se puede probar una función simulando un modelo cuya ENTITY tenga señales de
interfaz equivalentes a las de la función, y una ARCHITECTURE que contenga a la función
en su zona declarativa y la llame en su zona activa, por ejemplo:

ENTITY binario_a_entero IS
port (entrada: in bit_vector(7 downto 0);
salida:out integer range 0 to 255);
END binario_a_entero;

ARCHITECTURE conv OF binario_a_entero IS

FUNCTION bin_a_int (dato: BIT_VECTOR ) RETURN INTEGER IS


VARIABLE resultado: INTEGER := 0;
BEGIN
FOR n IN dato'RANGE LOOP
IF dato(n) = '1' THEN
resultado := resultado + ( 2** n);
END IF;
END LOOP;
RETURN resultado;
END bin_a_int; -- ¡ Comparar con la FUNCTION de la página anterior !

BEGIN
salida <= bin_a_int(entrada);
END conv;

V-3
5 - Subprogramas

El ejemplo de función siguiente devuelve el binario de entrada incrementado en uno y


hace puesta a cero cuando el binario de entrada equivale al número en “cuenta”:
FUNCTION incremento (dato: BIT_VECTOR ( 4 DOWNTO 0) ) RETURN BIT_VECTOR IS
VARIABLE cuenta : BIT_VECTOR ( 4 DOWNTO 0 );
BEGIN
cuenta := dato;
IF cuenta = "01101" THEN -- si la cuenta es igual a 13...
cuenta := "00000" ; -- cambiarla a cero
ELSE -- y si no, incrementar como se indica
FOR i IN 0 TO 4 LOOP
IF cuenta(i) = '0' THEN
cuenta(i) := '1'; -- búsqueda de bit a incrementar (*)
EXIT; -- salir del lazo al primer cambio de 0 a 1
ELSE -- que corresponde a incrementar en 1
cuenta(i) := '0'; -- incremento de suma binaria '1'+'1' = '0'
END IF; -- pero falta el acarreo, a hacer en (*).
END LOOP;
END IF; -- salir del IF de reposición a cero
RETURN cuenta; -- devolver valor de cuenta incrementada.
END incremento;

En el paquete “modelos.vhd” se han incluido las funciones incrementar y


decrementar que serán utilizadas en modelos de contadores:
FUNCTION incrementar ( V: BIT_VECTOR ) RETURN BIT_VECTOR IS
VARIABLE bv : BIT_VECTOR(V'LENGTH-1 DOWNTO 0);
BEGIN
bv := v;
FOR i IN 0 TO bv'HIGH LOOP
IF bv(i) = '0' THEN bv(i) := '1';
EXIT;
ELSE bv(i) := '0';
END IF;
END LOOP;
RETURN bv;
END incrementar;

FUNCTION decrementar (v : BIT_VECTOR ) RETURN BIT_VECTOR IS


VARIABLE bv : BIT_VECTOR(v'LENGTH-1 DOWNTO 0);
BEGIN
bv := v;
FOR i IN 0 TO bv'HIGH LOOP
IF bv(i) = '1' THEN bv(i) := '0';
EXIT;
ELSE bv(i) := '1';
END IF;
END LOOP;
RETURN bv;
END decrementar;

V-4
5 - Subprogramas

5.1.1 FUNCIONES DE RESOLUCIÓN


Cuando en un nodo concurren varias señales y no todas con igual valor, la asignación
está indeterminada. En VHDL esta situación se asocia a una señal que tiene asignación
múltiple, por varios drivers o procesos. Un ejemplo podría ser el de un circuito con lógica
cableada y la siguiente descripción imposible, que no sería aceptada por el compilador:
USE WORK.modelos.ALL -- para usar tipos cuad.

ENTITY nodoand IS
PORT ( a,b,c :IN cuad ; z :OUT cuad);
END nodoand;

ARCHITECTURE imposible OF nodoand IS


SIGNAL mezcla: cuad;
BEGIN
mezcla <= a; -- asignaciones concurrentes al mismo nodo
mezcla <= b;
mezcla <= c;
z <= mezcla;
END imposible;

Para modelar un circuito de ese tipo es necesario resolver el conflicto entre drivers
con una función de resolución que determine el valor a asignar a la señal.

La función de resolución tiene como entrada un array abierto formado por los valores
de los drivers, actúa automáticamente al ocurrir un evento en cualquiera de ellos y devuelve
el valor resuelto que estará determinado por la función en base a la fuerza de las señales
drivers.

Si, por ejemplo, el tipo de las señales que vamos a utilizar en un diseño fuera
TYPE cuad IS ( ‘0’,’1’,’Z’,’X’);

a partir de él se podría declarar el tipo cuad_2 array de dos dimensiones


TYPE cuad_2 IS ARRAY ( cuad,cuad ) OF cuad;

La función de resolución concreta, es decir, la fuerza relativa de las señales que


acceden al nodo, es definida o elegida por el diseñador. Desde el punto de vista de
simulación, en VHDL se podrán definir varias funciones para cada caso, sin embargo, si el
objetivo final del modelo es sintetizar el diseño con alguna herramienta CAD comercial, es
probable que el conjunto de funciones soportadas esté limitado a los dos o tres casos más
habituales en hardware: triestados, and-cableada y, tal vez, or-cableada.

Una forma de definir la función de resolución se basa en describir la relación de


fuerza entre los elementos de dos drivers por medio de una tabla bidimensional, cuya
aplicación se puede extender a casos de más de dos drivers por aplicación sucesiva de las
mismas tablas basándose en que éstas son asociativas y conmutativas, es decir, para el

V-5
5 - Subprogramas

ejemplo anterior, con tres drivers a, b y c del tipo cuad definido arriba, deberá cumplirse
que
a AND b AND c = ( a AND b) AND c = ( a AND c) AND b = ( b AND c) AND a

ya que de otra forma, habría que considerar un posible resultado diferente en función del
orden en la aplicación de drivers, lo que ni corresponde a situaciones reales ni tampoco se
especifica en VHDL al considerar arrays abiertos.

La figura adjunta muestra un ejemplo de tabla bidimensional para dos drivers a y b, en


los que el elemento fuerte es el ‘0’, lo que permite asociarla a una función AND-cableada.

La tabla puede ser descrita por la constante adjunta a ella:

a 0 1 Z X
b
0 0 0 0 0 CONSTANT tabla_and : cuad_2 := ( ('0','0','0','0'),
('0','1','Z','X'),
1 0 1 Z X
('0','Z','1','X'),
Z 0 Z 1 X ('0','X','X','X'));
X 0 X X X

y a partir de la misma puede obtenerse la función “AND” sobrecargada como se indica:


FUNCTION "AND" (a,b: cuad ) RETURN cuad IS;
CONSTANT tabla_and : cuad_2 := ( ('0','0','0','0'),
('0','1','Z','X'),
('0','Z','1','X'),
('0','X','X','X'));
BEGIN
RETURN tabla_and (a,b );
END "AND";

Dado que el tipo cuad es declarado por el usuario, no hay definido para él ningún
operador y, en consecuencia, todas las operaciones o funciones a realizar con él deberán ser
definidas previamente a su uso, ya sea por inclusión en un paquete al que se tiene acceso por
empleo de la cláusula USE, o por declaración y definición en la región declarativa del
bloque donde se vaya a usar la función.

Las tablas y constantes asociadas, es decir, los contenidos de las tablas, se establecen
por el usuario y su asociación a la AND-cableada es voluntaria y caprichosa, como un
ejemplo de sobrecarga de la función AND predefinida. Se pueden definir otras funciones
cuyas tablas representen otras funciones lógicas más complejas.

V-6
5 - Subprogramas

De forma similar a la función “AND”, se puede definir una función cuya tabla
bidimensional es similar a la anterior, pero donde el elemento de mayor fuerza será ahora el
‘1’ cuad y que, por esta fuerza del elemento ‘1’, se asocia a la función “OR” :

a 0 1 Z X
b
0 0 1 1 X CONSTANT tabla_or : cuad_2 := ( ('0','1','1','X'),
('1','1','1','1'),
1 1 1 1 1
('1','1','1','1'),
Z 1 1 1 1 ('X','1','1','X'));
X X 1 1 X

a partir de la cual puede obtenerse la función “OR”, también sobrecargada, como :

FUNCTION "OR" (a,b: cuad ) RETURN cuad IS;


CONSTANT tabla_or : cuad_2 := ( ('0','1','1','X'),
('1','1','1','1'),
('1','1','1','1'),
('X','1','1','X'));
BEGIN
RETURN tabla_or (a,b );
END "OR";

Una vez definida la función de resolución, existen al menos dos posibles métodos para
obtener el valor de la señal resuelta obtenido por la función:

1º Declaración de señal resuelta

Consiste en especificar la señal resuelta y la función de resolución asociada a los


drivers en la región declarativa del bloque donde se utiliza la señal. El formato sería :

SIGNAL nombre_de_resuelta : nombre_funcion_resolución tipo_resuelto

así, para la ENTITY nodoand descrita anteriormente, pendiente de una ARCHITECTURE


posible, se podrían declarar los siguientes tipos
TYPE cuad_vector IS ARRAY ( NATURAL RANGE <> ) OF cuad; -- declaración
FUNCTION andcableada ( cables: cuad_vector ) RETURN cuad; -- declaración

y la siguiente función de resolución :


FUNCTION andcableada ( cables: cuad_vector ) RETURN cuad IS -- definición
VARIABLE union: cuad := ‘1’ ;
BEGIN
FOR i IN cables’ RANGE LOOP
union := union AND cables(i);
END LOOP;
RETURN union;
END andcableada;

V-7
5 - Subprogramas

- El parámetro de la función de resolución, al que se ha denominado cables, es un


array cuyos elementos tienen el mismo tipo que el resultado que devuelve la función, siendo
los elementos del array los valores de las señales drivers.
- Nótese que al definir el array cuad_vector de rango abierto, se permite definir a la
función sin especificar el número de drivers - cables- que acceden al nodo, y que la
función obtiene por el atributo ‘RANGE.
- La función AND, al estar entre objetos de tipo cuad, buscará la función “AND”
sobrecargada definida para este tipo.
- El bucle LOOP, se repite para el número de cables o drivers que devuelva el atributo
‘RANGE, y en cada paso del bucle se realiza la función “AND” de un nuevo cable con el
resultado resuelto de todos los anteriores.
- La variable union se inicializa a ‘1’, ya que como se ve en la tabla_AND, este
elemento no altera el valor que aporte el primer cable, por ser ‘1’ el valor más débil.

Así, podríamos definir una ARCHITECTURE posible:


USE WORK. paquete_de_usuario.ALL ; --acceso a tipos y función andcableada
ARCHITECTURE posible OF nodoand IS
SIGNAL mezcla : andcableada cuad; -- declaración de señal resuelta
BEGIN
mezcla <= a; -- asignación concurrente de señales al mismo nodo.
mezcla <= b;
mezcla <= c;
z <= mezcla;
END posible;

La declaración de SIGNAL llama a la función "andcableada" cada vez que ocurre un


cambio en alguna de las señales a, b, c, drivers de la señal resuelta "mezcla". La forma en
que se asocia el valor de los drivers con el parámetro del array de la función es una
concatenación de todos los drivers. Dicha concatenación se realiza con la asignación
múltiple de valores a la señal cuyo nombre figura en la declaración de la señal a resolver
junto con el de la función de resolución para hacerlo.

2º Declaración de un subtipo resuelto


Es similar al método anterior y consiste en los siguientes pasos:
- Declarar el tipo base, el tipo array abierto correspondiente, la función de resolución
y un subtipo con el nombre de la señal que se desea resuelta junto a la función para
hacerlo, por ejemplo :
TYPE cuad IS ( ‘0’,’1’,’Z’,’X’);
TYPE cuad_vector IS ARRAY ( NATURAL RANGE <> ) OF cuad;
FUNCTION andcableada ( cables: cuad_vector ) RETURN cuad;
SUBTYPE mezcla IS andcableada cuad;

- Declarar la señal resuelta, siendo su tipo el subtipo resuelto.

V-8
5 - Subprogramas

5.1.2 TIPOS STD_LOGIC. PAQUETE IEEE 1164


Un ejemplo importante del método anterior son los tipos resueltos std_logic del
paquete std_logic_1164, cuya declaración y definición parcial son como sigue :
TYPE std_ulogic IS ( 'U', -- Uninitialized
'X', -- Forcing Unknown
'0', -- Forcing 0
'1', -- Forcing 1
'Z', -- High Impedance
'W', -- Weak Unknown
'L', -- Weak 0
'H', -- Weak 1
'-' -- Don't care);

TYPE std_ulogic_vector IS ARRAY ( NATURAL RANGE <> ) OF std_ulogic;


FUNCTION resolved ( s : std_ulogic_vector ) RETURN std_ulogic;
SUBTYPE std_logic IS resolved std_ulogic;

y una vez definida la función de resolución en la forma que se ve en el PACKAGE BODY, por
medio de la tabla resolution_table , se pasa a definir los tipos y subtipos siguientes:

-- *** industry standard logic type ***


TYPE std_logic_vector IS ARRAY ( NATURAL RANGE <> ) OF std_logic ;
SUBTYPE X01 IS resolved std_ulogic RANGE ‘X’ TO ‘1’ ; -- ( ‘X’,‘0’,‘1’ )
SUBTYPE X01Z IS resolved std_ulogic RANGE ‘X’ TO ‘Z’ ; -- ( ‘X’,‘0’,‘1’,’Z’ )
SUBTYPE UX01 IS resolved std_ulogic RANGE ‘U’ TO ‘1’ ; -- ( ‘U’,‘X’,‘0’,‘1’ )
SUBTYPE UX01Z IS resolved std_ulogic RANGE ‘U’ TO ‘Z’; -- ( ‘U’,‘X’, ‘0’, ‘1’,’Z’ )

que permiten, utilizando tipos estandarizados por el paquete STD_LOGIC_1164, modelar o


describir hardware con varias posibilidades de valores lógicos.

PACKAGE BODY std_logic_1164 IS


-------------------------------------------------------------------
-- local types
-------------------------------------------------------------------
TYPE stdlogic_1d IS ARRAY (std_ulogic) OF std_ulogic;
TYPE stdlogic_table IS ARRAY(std_ulogic, std_ulogic) OF std_ulogic;

CONSTANT resolution_table : stdlogic_table := (


-- --------------------------------------------------------------------------------------
-- | U X 0 1 Z W L H - | |
-- --------------------------------------------------------------------------------------
( 'U', 'U', 'U', 'U', 'U', 'U', 'U', 'U', 'U' ), -- | U |
( 'U', 'X', 'X', 'X', 'X', 'X', 'X', 'X', 'X' ), -- | X |
( 'U', 'X', '0', 'X', '0', '0', '0', '0', 'X' ), -- | 0 |
( 'U', 'X', 'X', '1', '1', '1', '1', '1', 'X' ), -- | 1 |
( 'U', ‘X’, '0', '1', 'Z', 'W', 'L', 'H', 'X' ), -- | Z |
( 'U', 'X', '0', '1', 'W', 'W', 'W', 'W', 'X' ), -- | W |
( 'U', 'X', '0', '1', 'L', 'W', 'L', 'W', 'X' ), -- | L |
( 'U', 'X', '0', '1', 'H', 'W', 'W', 'H', 'X' ), -- | H |
( 'U', 'X', 'X', 'X', 'X', 'X', 'X', 'X', 'X' ) ); -- | - |

V-9
5 - Subprogramas

FUNCTION resolved ( s : std_ulogic_vector ) RETURN std_ulogic IS


VARIABLE result : std_ulogic := 'Z'; -- weakest state default
BEGIN
-- the test for a single driver is essential otherwise the
-- loop would return 'X' for a single driver of '-' and that
-- would conflict with the value of a single driver unresolved
-- signal.
IF (s'LENGTH = 1) THEN RETURN s(s'LOW);
ELSE
FOR i IN s'RANGE LOOP
result := resolution_table(result, s(i));
END LOOP;
END IF;
RETURN result;
END resolved;

Dado que estos tipos son resueltos ya, no se les puede aplicar una función de resolución.

Además de las declaraciones del tipo std_ulogic y los subtipos derivados, de los que
quizá el más importante sea el std_logic, el paquete define las funciones lógicas AND,
NAND, OR, NOR, XOR y NOT para los tipos declarados, ya que de otra forma no podrían
aplicarse esas funciones lógicas, predefinidas solo para los tipos BIT, es decir, hace
sobrecarga de dichos operadores.

También se definen en ese paquete funciones de conversión entre tipos de los paquetes
STANDARD Y STD_LOGIC_1164 :

bit y std_ulogic
bit_vector y std_ulogic_vector o std_logic_vector
std_logic_vector y std_ulogic_vector

Dado que el paquete std_logic_1164 es un standard IEEE, donde se contemplan casi


todas las funciones y valores deseables en lógica multivalor, es recomendable su uso en
diseños, en particular los tipos std_logic y std_logic_vector, ya que por su compatibilidad
estandard son reconocidos por herramientas CAD de prestigio, lo que a su vez permite
acceso a nuevos tipos o paquetes que son de facto standard, al ser compatibles o
reconocidos por otras herramientas CAD. Todo esto hace innecesario el esfuerzo de definir
nuevos tipos, así como las correspondientes funciones de manejo de los mismos y
disminuye el riesgo de incompatibilidades con futuros diseños.

Un ejemplo de aplicación de los tipos std_logic como ejemplo de funciones resueltas


es el de dos inversores triestado conectados directamente a un mismo nodo:

LIBRARY IEEE; -- Cláusulas obligatorias para visualizar


USE IEEE.std_logic_1164.all; -- biblioteca y paquete std_logic_1164

ENTITY triestados IS
PORT (enab_1, sig_1,enab_2, sig_2: IN std_logic ; sal : OUT std_logic);
END triestados;

V - 10
5 - Subprogramas

una posible ARCHITECTURE con descripción de comportamiento podría ser :

ARCHITECTURE comportam OF triestados IS


BEGIN enab_1
sig_uno: PROCESS( sig_1, enab_1)
BEGIN
sal <= 'Z'; sig_1
IF ( enab_1 = '1' ) THEN sal
sal <= sig_1 ;
END IF; sig_2
END PROCESS;
enab_2
sig_dos: PROCESS( sig_2, enab_2)
BEGIN
sal <= 'Z';
IF ( enab_2 = '1' ) THEN
sal <= sig_2 ;
END IF;
END PROCESS;
END comportam;

y otra posible ARCHITECTURE de esa misma ENTITY, con descripción en estilo funcional o
de flujo de datos puede ser :
ARCHITECTURE flujdats OF triestados IS

BEGIN
sal <= sig_1 WHEN ( enab_1 = '1' ) ELSE 'Z';
sal <= sig_2 WHEN ( enab_2 = '1' ) ELSE 'Z';
END flujdats;

V - 11
6. Modelos estructurales
Contienen una descripción de los componentes que forman el sistema y las conexiones
entre ellos, reflejando de manera precisa la estructura del circuito que describen.
Las sentencias básicas de este tipo de descripciones son las de colocación de
componentes utilizadas para incluir o poner un componente en una ARCHITECTURE y las
sentencias de especificación de configuración, identificados con ENTITYs. Las declaraciones
de componentes pueden ser locales o estar en un paquete al que se accede.
Los modelos estructurales son la base del diseño jerárquico.

6.1 ESPECIFICACIONES DE CONFIGURACIÓN

Consisten en asociar componentes con ENTITYs previamente compiladas.


La especificación permite asociar diferentes modelos a un componente según la
funcionalidad que deba tener en sus diferentes colocaciones en el circuito, así como
seleccionar para cada uno de esos modelos la ARCHITECTURE más idónea de aquellas que
tenga. Las sentencias de especificación se colocan en las áreas declarativas de las
ARCHITECTUREs con el formato siguiente:

FOR etiqueta : componente USE ENTITY biblioteca . ENTITY (ARCHITECTURE);

Los significados o referencias de cada uno de los campos anteriores son como sigue:

etiqueta : Se refiere a la usada en la sentencia de colocación del componente.

componente : Nombre del componente en su declaración.

biblioteca : Aquella donde está la ENTITY de diseño. Por defecto es WORK.

ENTITY : Nombre de la ENTITY asociada al componente.

ARCHITECTURE : Optativa. Una de las posibles de la ENTITY, si se desea especificar.


Por defecto se configura la última arquitectura compilada.

En el ejemplo siguiente se tiene una descripción estructural de un comparador de bits


utilizando puertas cuyos modelos se adjuntan para referencia. La declaración de ENTITY
describe su interfaz como bloque, mientras que la ARCHITECTURE detalla la estructura del
diseño concreto basado en los componentes correspondientes a los modelos adjuntos:

ENTITY inver IS ENTITY nand_2 IS


PORT ( e1: IN BIT; sal: OUT BIT); PORT ( e1,e2 : IN BIT; sal: OUT BIT);
END inver; END nand_2;

ARCHITECTURE normal OF inver IS ARCHITECTURE lenta OF nand_2 IS


BEGIN BEGIN
sal <= NOT e1 AFTER 10 NS; sal <= e1 NAND e2 AFTER 20 NS;
END normal; END lenta;

VI - 1
6 – Modelos estructurales

ENTITY nand_3 IS
PORT ( e1,e2,e3 : IN BIT; sal : OUT BIT);
END nand_3;
ARCHITECTURE veloz OF nand_3 IS
BEGIN
sal <= NOT ( e1 and e2 and e3 ) AFTER 5 NS;
END veloz;

a s3
m
s4 amb
b
s5
a A
s1
b B s6
igl
m > A>B amb i
s7
i = A=B igl s2
n < A<B bma s8

s9 bma

n s10

USE WORK.puertas.ALL; --paquete puertas.vhd especial para este modelo


ENTITY compbit IS
PORT( a,b,m,i,n : IN BIT; amb, igl, bma:OUT BIT);
END compbit;

ARCHITECTURE estruc OF compbit IS


FOR ALL : inver USE ENTITY WORK. inver (normal); -- Especificaciones
FOR ALL : nand_2 USE ENTITY WORK. nand_2 (lenta); -- internas
FOR ALL : nand_3 USE ENTITY WORK. nand_3 (veloz); -- de Configuración
SIGNAL s1,s2,s3,s4,s5,s6,s7,s8,s9,s10 : BIT;
BEGIN
p0 : inver PORT MAP (b,s1); -- Notar que los identificadores de los
p1 : inver PORT MAP (a,s2); -- componentes y las ENTITYs no es
p2 : nand_2 PORT MAP (a,m,s3); -- necesario que sean iguales .
p3 : nand_2 PORT MAP (m,s1,s4);
p4 : nand_2 PORT MAP (a,s1,s5);
p5 : nand_3 PORT MAP (s3,s4,s5,amb);
p6 : nand_3 PORT MAP (a,b,i,s6);
p7 : nand_3 PORT MAP (s1,i,s2,s7);
p8 : nand_2 PORT MAP (s6,s7,igl); -- Los identificadores de componentes
p9 : nand_2 PORT MAP (s2,b,s8); -- son aquellos con los que figuran en
p10 : nand_2 PORT MAP (s2,n,s9); -- el paquete donde estan.
p11 : nand_2 PORT MAP (b,n,s10);
p12 : nand_3 PORT MAP (s8,s9,s10,bma);
END estruc;

VI - 2
6 – Modelos estructurales

6.2 DECLARACIÓN DE CONFIGURACIÓN

Al ser las especificaciones de configuración internas a la ARCHITECTURE, cada


cambio de especificaciones supone recompilar la ARCHITECTURE, por lo que ese estilo de
configuración solo se emplea en sistemas pequeños, siendo preferible en diseños grandes
mantener una ARCHITECTURE genérica compilada solo una vez y configurar externamente
aquellas combinaciones de interés, que serán las unidades de diseño que se compilen
separadamente. Es una posibilidad interesante en diseño jerárquico.
La CONFIGURATION es una unidad de diseño primaria, pero deberá ser analizada y
compilada después de la ARCHITECTURE a que configura.
Aunque existen otros estilos, la forma más conveniente de configuración externa
consiste en una estructura que permite anidamientos de configuraciones hasta el nivel
jerárquico más bajo que se desee, con el formato siguiente entre dos niveles sucesivos:

CONFIGURATION ejemplo_de_config OF ENTITY_configurada IS


FOR ARCHITECTURE_configurada
.....
FOR etiqueta : componente USE ENTITY WORK. ENTITY [(ARCHITECTURE)];
END FOR;
.....
END FOR;
END ejemplo_de_config;

donde las líneas FOR -iguales a las especificaciones de configuración internas- y las END
FOR se repiten con el mismo criterio que las especificaciones de configuración internas. Si
en el ejemplo anterior existieran ARCHITECTUREs ”lenta”, “normal”, y “veloz” para las tres
puertas, se podría modelar el comparador del ejemplo con una ARCHITECTURE única:

USE WORK.puertas.ALL;
ARCHITECTURE config_exter OF compbit IS
-- No existen Especificaciones internas de Configuración
SIGNAL s1,s2,s3,s4,s5,s6,s7,s8,s9,s10 : BIT;
BEGIN
p0 : inver PORT MAP (b,s1);
p1 : inver PORT MAP (a,s2);
p2 : nand_2 PORT MAP (a,m,s3);
p3 : nand_2 PORT MAP (m,s1,s4);
p4 : nand_2 PORT MAP (a,s1,s5);
p5 : nand_3 PORT MAP (s3,s4,s5,amb);
p6 : nand_3 PORT MAP (a,b,i,s6);
p7 : nand_3 PORT MAP (s1,i,s2,s7);
p8 : nand_2 PORT MAP (s6,s7,igl);
p9 : nand_2 PORT MAP (s2,b,s8);
p10 : nand_2 PORT MAP (s2,n,s9);
p11 : nand_2 PORT MAP (b,n,s10);
p12 : nand_3 PORT MAP (s8,s9,s10,bma);
END config_exter;

y para esta ARCHITECTURE se podrán definir tantas declaraciones de configuración como


permitan los componentes empleados y las ARCHITECTUREs posibles de éstos, por ejemplo:

VI - 3
6 – Modelos estructurales

CONFIGURATION externa OF compbit IS


FOR config_exter
FOR ALL : inver USE ENTITY WORK. inver (normal);
END FOR;
FOR P2 : nand_2 USE ENTITY WORK. nand_2 (lenta);
END FOR;
FOR OTHERS : nand_2 USE ENTITY WORK. nand_2 (veloz);
END FOR;
FOR P5,P6 : nand_3 USE ENTITY WORK. nand_3 (lenta);
END FOR;
FOR P7 : nand_3 USE ENTITY WORK. nand_3 (normal);
END FOR;
FOR P12 : nand_3 USE ENTITY WORK. nand_3 (veloz);
END FOR;
END FOR;
END externa;

donde se tienen diferentes formatos de configuración del par ENTITY - ARCHITECTURE.

Cuando se utiliza un par ENTITY ARCHITECTURE en que los puertos –PORT- han
cambiado sus nombres y no se cambia la declaración del componente que los asocia, quizá
porque está declarado en un paquete que probablemente no se desea alterar para no afectar a
otros diseños que lo utilicen, dado que el mapeo se hace referenciando la etiqueta del
componente al que se asocia la nueva ENTITY, será necesario hacer una asociación de
puertos interna en la configuración, por ejemplo, si la situación fuese :

ENTITY nand_2 IS COMPONENT nand_2


PORT (a,b : IN BIT; f : OUT BIT); PORT (x,y : IN BIT; z: OUT BIT);
END nand_2; END COMPONENT;

en el ejemplo anterior la colocación P2 usando la nueva ENTITY nand_2, se modificaría a:

FOR P2 : nand_2 USE ENTITY WORK. nand_2 (nueva);


PORT MAP ( x => a, y => b, z => f ) ; ---- componente => ENTITY
END FOR;

La declaración previa del componente no es un modelo de dispositivo, sino


simplemente una referencia a su interfaz, muy similar a la de ENTITY. Sin embargo, para
que el modelo sea simulable se requiere asociarle una ENTITY de diseño formada por una
pareja ENTITY-ARCHITECTURE que encaje con la interfaz con que ha sido declarado el
componente en su colocación.
El mapeo recuerda a la colocación de un dispositivo en un zócalo puesto en una
posición etiquetada de un circuito impreso. En el zócalo -componente- se pueden colocar
distintos dispositivos -ENTITYs- y los terminales del zócalo-componente aplican sus señales
al dispositivo-ENTITY que se inserte en el zócalo. Así, el zócalo es el que tiene una etiqueta
diferente para cada referencia o posición, un nombre común a todas las referencias del
mismo componente-zocalo en el circuito impreso y una orientación de sus terminales a la
que debe adaptarse la ENTITY-ARCHITECTURE que se inserte en él, con una asociación
posicional, que no es necesaria si se hace nominalmente, terminal a terminal.

VI - 4
6 – Modelos estructurales

6.3 APLICACIÓN DE SENTENCIAS GENERATE

Un tipo de circuitos de amplio uso en sistemas de autoverificación son los basados en


LFSRs - Linear Feedback Shift Registers - que, por su fácil reconfiguración, permiten
utilizarlos como generadores pseudoaleatorios, o como analizadores de firmas con entrada
serie o con entradas paralelas. Ambos conceptos son importantes en técnicas de pruebas.
Sin entrar en el análisis de este tipo de circuitos, en la figura adjunta se muestra su
estructura como un ejemplo interesante a modelar con una ARCHITECTURE estructural que,
en este caso, será más reducida que la obtenible con una ARCHITECTURE de
comportamiento, por la funcionalidad pseudoaleatoria de estos circuitos y la
configurabilidad que se pretende dar al modelo de LFSR que se utiliza como generador
reconfigurable.

X0 X1 X2 Xn-1 Xn
D Q + D Q D Q D Q
+ +

Qd1 Qd2 Qdn-1 Qdn


clk

El circuito de la figura se denomina “LFSR con XOR internas”. Está compuesto por
DFFs y puertas XOR insertadas entre las salidas y las entradas de los DFFs. Nótese que la
inserción de puertas XOR es configurable. Es interesante mencionar de estos LFSRs que:

 No permiten la combinación o estado “0000..00”, conocido como estado de bloqueo , ya


que si se produjera, el circuito no podría evolucionar para salir de él. Existen varias
alternativas para que ese estado sea posible, añadiendo dos o tres puertas a la estructura
genérica de la figura. En tal caso se les llama generadores pseudoaleatorios exhaustivos,
porque la secuencia de estados, aparte de completa, reúne características de aleatoriedad.

 En función de las puertas XOR insertadas, la transición entre estados y el número de


n
estos será diferente. Algunas configuraciones permiten obtener los 2 -1estados posibles,
exceptuado el “000...00”, siendo n el número de DFFs. Existe un álgebra que asocia
polinomios característicos de grado n a cada configuración o estructura de XOR.

n n-1 n-2 1 0
El polinomio característico es del tipo: X + Cn-1. X + Cn-2. X +…. + C1. X + X

El valor 1 o 0 de los coeficientes Ci, determina si existe la correspondiente XOR.

Para modelar el LFSR con XOR internas, se parte de las XORs y DFFs utilizados y se
define un módulo con una puerta AND de dos entradas, una de las cuales si está a ‘1’ fija la
existencia de la conexión de realimentación a la puerta XOR y, si está a ‘0’ transforma la
función XOR en un buffer, es decir, se define el coeficiente del polinomio correspondiente.

La figura de la página siguiente describe el circuito de configuración del LFSR

VI - 5
6 – Modelos estructurales

e2 = coeficiente de poly e1 = realimentación desde Qn

e2 = ‘0’ - XOR actúa como buffer de señal Qn


e2 = ‘1’ - XOR conecta al bucle de e1

pr

d xro
D Q Nótese que si e2 = 0
clk qd xro = qd

La ENTITY que se define para el componente especial es:


ENTITY xrf IS
PORT(d,clk,pr,e1,e2: IN BIT; qd,xro : OUT BIT);
END xrf;

Los DFFs son inicializados a ‘1’ por activación de la entrada PRESET ( pr = ‘1’ ).
La entrada e2 de las puertas AND se usa para aplicar el polinomio del LFSR, mientras
que la entrada e1 está permanentemente conectada al lazo de realimentación.

La ARCHITECTURE de comportamiento de este componente específico puede ser:


ARCHITECTURE algorit OF xrf IS
SIGNAL inter : BIT; -- señal interna para evitar lectura de señal qd
BEGIN -- y el uso de modos INOUT o BUFFER.
PROCESS (d,clk,pr)
BEGIN
IF ( pr = '1' ) THEN inter <= '1';
ELSIF (clk'EVENT AND clk = '1' ) THEN inter <= d;
END IF;
END PROCESS;
xro <= inter XOR ( e1 AND e2);
qd <= inter;
END algorit;

A partir del componente XRF se puede modelar un LFSR de cuatro XRFs como :

ENTITY lfsr IS
PORT( clk : IN BIT;
pr, poly : IN BIT_VECTOR (0 TO 3) ;
qd : OUT BIT_VECTOR (0 TO 3) ) ;
END lfsr;

La señal poly se deriva de los coeficientes del polinomio característico: los de Xn y X0 son
siempre ‘1’, indicando que se realimenta siempre desde la última salida (coeficiente 1 en
Xn) a la primera entrada (coeficiente 1 en X0). Como el último DFF nunca está cargado con
XOR, su salida equivale a un buffer obtenido con una AND cerrada por su e2=’0’, es decir,
siempre será el elemento poly(N) = ’0’.

La descripción estructural del LFSR podría ser la siguiente:

VI - 6
6 – Modelos estructurales

ARCHITECTURE cuad OF lfsr IS


COMPONENT xrf
PORT(d,clk,pr,e1,e2: IN BIT; qd, xro : OUT BIT);
END COMPONENT;

SIGNAL xr0,xr1,xr2,xr3: BIT;


BEGIN
ff0 : xrf PORT MAP (xr3, clk, pr(0), xr3, poly(0), qd(0), xr0); -- poly(3) será = ‘0’ siempre
ff1 : xrf PORT MAP (xr0, clk, pr(1), xr3, poly(1), qd(1), xr1); -- para hacer xr3 = qd(3)
ff2 : xrf PORT MAP (xr1, clk, pr(2), xr3, poly(2), qd(2), xr2); -- y evitar la lectura de qd(3)
ff3 : xrf PORT MAP (xr2, clk, pr(3), xr3, poly(3), qd(3), xr3);
END cuad;

que puede generalizarse para LFSRs con N XRFs usando GENERIC y sentencias GENERATE
por medio de la descripción siguiente :

ENTITY lfsr_gen IS
GENERIC ( N : POSITIVE := 4 ); -- particularización al grado del lfsr
PORT( clk : IN BIT;
pr : IN BIT_VECTOR (0 TO (N-1)); -- Hay N DFFs
poly : IN BIT_VECTOR (0 TO (N-2)); -- Hay (N-1) puertas XOR internas
qd : OUT BIT_VECTOR (0 TO (N-1)) );
END lfsr_gen;

ARCHITECTURE cuad OF lfsr_gen IS


COMPONENT xrf
PORT(d,clk,pr,e1,e2: IN BIT; qd,xro : OUT BIT);
END COMPONENT;

SIGNAL xr : BIT_VECTOR(0 TO (N-1)); -- Hay N DFFs


SIGNAL XORen : BIT_VECTOR(0 TO (N-1)); -- Hay N puertas AND de configuración
BEGIN
XORen <= poly(0 to (N-2)) & '0'; -- Hay N coeficientes de configuración

ff0 : xrf PORT MAP(xr(N-1), clk, pr(0), xr(N-1), XORen (0), qd(0), xr(0));
GEN : FOR i IN 1 TO (N-2) GENERATE
Ffi : xrf PORT MAP( xr(i-1), clk, pr(i), xr(N-1), XORen (i), qd(i), xr(i));
END GENERATE;
ffN : xrf PORT MAP(xr(N-2), clk, pr(N-1), xr(N-1), XORen (N-1), qd(N-1), xr(N-1));
END cuad;

Nótese que por medio del array pr(i) de PRESET se inicializa la cadena de DFFs con
una determinada combinación; poco después se debe desactivar PRESET para que el
sistema evolucione libremente con las señales de reloj que conmutan a los DFFs. Esta
descripción ha de ser acorde con el modelo de los DFFs descrito por la ENTITY XRF.

La señal XORen se deriva del polinomio característico del LFSR y, a través de las
puertas AND, configura a las XOR que actúan como tales o como buffers. El polinomio
está prefijado y no cambiará durante el funcionamiento del LFSR, ya que no tendría sentido
desde un punto de vista funcional. Por tal razón, así se ha previsto en la lista de sensibilidad
del proceso que describe los DFFs.

VI - 7
6 – Modelos estructurales

6.4 DESARROLLO DE PROBADORES

Una vez desarrollado el modelo VHDL del circuito, es necesario simularlo para ver
si su funcionamiento es el esperado. El procedimiento que se sigue es desarrollar una
ENTITY de nivel superior al modelo bajo prueba, donde éste será englobado como un
componente. El conjunto formado por la unidad bajo prueba y las descripciones
adicionales para probarla constituyen lo que se denomina test_bench en la literatura
americana, que podríamos llamar banco de pruebas o simplemente probador.
El probador es un modelo simulable, pero NO S INTETIZAB LE, que genera
internamente los estímulos que necesita para probar el modelo y donde se generan
como señales, también internas, las respuestas del modelo a los estímulos. Por tanto,
el conjunto probador tiene una ENTITY sin señales de interfaz, que se declara como:

ENTITY nombre_de_probador IS
END nombre_de_probador;

y para la cual se describe la ARCHITECTURE necesaria para generar los estímulos


apropiados al modelo bajo prueba.

Las pautas básicas para desarrollar arquitecturas de probadores son las siguientes:

1. Si van a utilizarse ENTITYs declaradas en algún paquete, hacer uso de cláusulas


USE en la forma conveniente.
2. El modelo a probar se asocia a un componente declarado localmente, cuya
interfaz será igual que la del modelo a probar. La denominación de las señales
de interfaz del componente no es necesario que sea igual a las de la ENTITY a que se
va a asociar, pero suelen asignarse nombres iguales para facilitar la descripción.
3. Hacer una especificación de configuración para el componente, referenciando
la ENTITY y ARCHITECTURE que se desean probar.
4. Declarar todas las señales internas, es decir, las que van a constituir los estímulos
o entradas al componente, las que vayan a ser entradas fijas o conectadas a un nivel
fijo, como masa o alimentación y aquellas que sean las salidas del componente.
5. Describir el área ejecutable de la ARCHITECTURE, comenzando por una
colocación del componente, mapeando las señales de estímulos declaradas a
las entradas del componente declarado.
6. Generar la forma de onda o vectores de test necesarios, por medio de sentencias
de asignación de señal, procesos o algún procedimiento apropiado al modelo.
7. Realizar una simulación del probador para examinar las señales relevantes en
relación a los estímulos aplicados al modelo.

Veamos un ejemplo de probador aplicado al modelo del decodificador siguiente:

VI - 8
6 – Modelos estructurales

ENTITY decoder_3_a_8 IS
PORT ( adr : IN BIT_VECTOR ( 2 DOW NTO 0 );
sal : OUT BIT_VECTOR ( 7 DOW NTO 0 ) ) ;
END decoder_3_a_8;
ARCHITECTURE directa OF decoder_3_a_8 IS
BEGIN
WITH adr SELECT
sal <= "00000001" W HEN "000",
"00000010" W HEN "001",
"00000100" W HEN "010",
"00001000" W HEN "011",
"00010000" W HEN "100",
"00100000" W HEN "101",
"01000000" W HEN "110",
"10000000" W HEN "111";
END directa;

El banco de pruebas o probador podría describirse como:

ENTITY prob_decoder IS -- NO ES SINTETIZABLE


END prob_decoder;

y una posible ARCHITECTURE de la misma puede ser :

ARCHITECTURE probadora OF prob_decoder IS


COMPONENT decodificador -- nombre a repetir al especificar configuracion
PORT ( adr : IN BIT_VECTOR ( 2 DOW NTO 0 );
sal : OUT BIT_VECTOR ( 7 DOW NTO 0 ) );
END COMPONENT;
FOR comp1: decodificador USE ENTITY W ORK.decoder_3_a_8 (directa);
SIGNAL adr : BIT_VECTOR ( 2 DOW NTO 0 );
SIGNAL sal : BIT_VECTOR ( 7 DOW NTO 0 );
BEGIN
comp1 : decodificador PORT MAP ( adr, sal );
dir_2 : PROCESS BEGIN
adr(2) <= '0', '1' AFTER 40 ns; W AIT FOR 80 ns;
END PROCESS dir_2;

dir_1 : PROCESS BEGIN


adr(1) <= '0', '1' AFTER 20 ns; W AIT FOR 40 ns;
END PROCESS dir_1;

dir_0 : PROCESS BEGIN


adr(0) <= '0', '1' AFTER 10 ns; W AIT FOR 20 ns;
END PROCESS dir_0;
END probadora;

Para mejor seguimiento se ha mantenido la descripción completa, incluyendo


los componentes. Tal como se indicaba en el punto 1º de las pautas a seguir para
desarrollo de los probadores, podría haberse eliminado la declaración local del
componente a probar si éste se hubiese declarado en el paquete de “modelos” y
visualizado con USE.

VI - 9
6 – Modelos estructurales

Una alternativa al probador prob_decoder descrito sería combinar un generador de


estímulos, tal como el LFSR con un GENERIC (N: POSITIVE := 3) y el mismo decoder_3_a_8.
Las entradas al sistema son la señal clk del LFSR y sus arrays de configuración, mientras
que las salidas serían las salidas del decoder_3_a_8, equivalente, en parte, a lo que en
técnicas de pruebas se llamaría un “decoder_3_a_8 con BIST” -Built-In Self Test-:

ENTITY decoder_BIST is
GENERIC ( N : POSITIVE := 3 ); -- particularización al grado del lfsr
PORT( clk : IN bit;
pr : IN bit_vector (0 TO (N-1)); -- Hay N DFFs
poly : IN bit_vector (0 TO (N-2)); -- Hay (N-1) puertas XOR internas
LFSR_Qs : OUT bit_vector (0 TO (N-1)); -- Testigo de salidas internas del LFSR_3
sal : OUT bit_vector (7 DOWNTO 0));
END decoder_BIST;

ARCHITECTURE BIST OF decoder_BIST IS

COMPONENT lfsr_3 -- generador interno de estimulos


PORT( clk : IN bit; -- utilizando FOR GENERATE
pr : IN bit_vector (0 TO (N-1)); -- Hay N DFFs
poly : IN bit_vector (0 TO (N-2)); -- Hay (N-1) puertas XOR internas
qd : OUT bit_vector (0 TO (N-1)));
END COMPONENT;

COMPONENT decoder_3_a_8
PORT ( adr : IN BIT_VECTOR (2 DOWNTO 0);
sal : OUT BIT_VECTOR (7 DOWNTO 0)) ;
END COMPONENT;
signal Qn : bit_vector(0 to 2);
signal adrn : bit_vector(2 downto 0);
BEGIN
adrn <= Qn(0 to 2);
DUT: decoder_3_a_8 PORT MAP(adrn(2 DOWNTO 0), sal(7 DOWNTO 0));
GEN: lfsr_3 PORT MAP(clk, pr(0 to 2), poly(0 to 1), Qn(0 to 2));
LFSR_Qs <= Qn; --Testigo de entradas al decoder
end BIST;

Dado que en LFSR_3 no se ha incluido modificación alguna para insertar el estado ‘000’
en su secuencia, las salidas del sistema serán todas las del decoder, excepto aquella
correspondiente a la “adr = 000”.

El ejemplo siguiente de probador BIST corresponde a un sumador de nibbles con carry_in.


En este caso se utiliza un LFSR de 9 bits, repartidos en dos grupos de 4 bits utilizables
como operandos de suma y el bit restante es inyectado como carry_in.
La generación de sumandos es aleatoria, pero inicializable a un valor no igual a TODO_0’s.

VI - 10
6 – Modelos estructurales

LIBRARY IEEE;
USE IEEE.STD_LOGIC_1164.ALL;
USE IEEE.STD_LOGIC_UNSIGNED.ALL; -- Paquete para operaciones aritméticas sin signo

ENTITY BIST_adder is
GENERIC ( N : POSITIVE := 9 ); -- particularización al grado del lfsr
PORT (clk: IN std_logic;
pr: IN std_logic_vector (0 TO (N-1)); -- Hay N DFFs
poly: IN std_logic_vector (0 TO (N-2)); -- Hay (N-1) puertas XOR internas
sum_A: OUT std_logic_vector (3 DOWNTO 0); --Testigos del LFSR
sum_B: OUT std_logic_vector (3 DOWNTO 0); --Testigos del LFSR
carry_in: OUT std_logic; --Testigos del LFSR
suma: OUT std_logic_vector (3 DOWNTO 0)); --salida del sumador sin carry_out
END BIST_adder;

ARCHITECTURE BIST OF BIST_adder IS


-- ¡¡¡ Todos los ficheros deben ser con tipos std_logic !!!
COMPONENT lfsr_9_mvld --Con sentencia FOR GENERATE
PORT (clk: IN std_logic; -- y tipos std_logic para todos los
pr: IN std_logic_vector (0 TO (N-1)); -- ficheros y señales en la jerarquía
poly: IN std_logic_vector (0 TO (N-2)); -- Hay N DFFs
qd: OUT std_logic_vector (0 TO (N-1))); -- Hay (N-1) puertas XOR internas
END COMPONENT;

COMPONENT adder_4b
port (A,B : in std_logic_vector(3 downto 0); CI : in std_logic;
SUM : out std_logic_vector(3 downto 0));
END COMPONENT;

signal Qn : std_logic_vector(8 downto 0); -- señales internas


signal As : std_logic_vector(3 downto 0); -- utilizadas en las
signal Bs : std_logic_vector(3 downto 0); -- PORT MAPs
signal CIs : std_logic;
signal SUMs: std_logic_vector(3 downto 0);
BEGIN
As <= Qn(7 downto 4); -- Asignación de valores a señales internas
Bs <= Qn(3 downto 0); -- Estas tres señales son el reparto de las
CIs <= Qn(8); -- generadas por el LFSR-9

DUT: adder_4b PORT MAP (As(3 DOWNTO 0), Bs(3 DOWNTO 0), CIs, SUMs(3 DOWNTO 0));
GEN: lfsr_9_mvld PORT MAP(clk, pr(0 to N-1), poly(0 TO N-2), Qn(N-1 downto 0));

carry_in <= Qn(8); --salida Testigo del generador LFSR


sum_A <= Qn(7 downto 4); --salida Testigo del generador LFSR
sum_B <= Qn(3 downto 0); --salida Testigo del generador LFSR
suma <= SUMs(3 downto 0);
end BIST;

VI - 11
7. Modelos de comportamiento
Describen el funcionamiento del sistema al que representan sin hacer referencia al detalle de
subelementos e interconexiones que caracterizan a los modelos estructurales. Si se considera el nivel
de abstracción con que se puede describir el comportamiento de sistemas se distinguen dos estilos:

1 - Descripción a nivel de transferencias entre registros - RTL - o de flujo de datos.


2 - Descripciones algorítmicas, sin referencia explícita al sistema físico.

Sin embargo, los modelos en sí carecen de sentido: cualquier modelo se desarrolla con vistas a
una determinada aplicación, siendo la síntesis aquella aplicación que exige mayor esfuerzo para el
desarrollo de modelos, por las restricciones y matices impuestos por las herramientas de síntesis. En
los apartados que siguen se indican las características de cada uno de estos estilos y se presentan
ejemplos de modelos de varios primitivos de uso frecuente, desarrollados en alguno de los niveles de
abstracción citados y que, siguiendo los pasos descritos anteriormente en modelos estructurales,
pueden ser declarados como componentes para su utilización en una configuración o estructura de
nivel más alto.

7.1 DESCRIPCIONES A NIVEL DE FLUJO DE DATOS

En este estilo se detallan las transferencias de datos a nivel de bloques - registros - lo que
implica un diseño previo a nivel de particionado del sistema en subelementos, así como del control de
las transferencias de datos. Esto supone que en estas descripciones se utilizarán, fundamentalmente,
sentencias concurrentes para asignaciones de señales de tipos condicionales y selectivas, así como la
estructura de la descripción en bloques cuyo comportamiento está directamente asociado a este tipo
de sentencias, por lo que estas descripciones se caracterizan por :

 Declaraciones de señales que corresponden a movimientos reales de datos y señales de control


de transferencias de datos.

 Identificación con un esquema a nivel de bloques en donde se distinguen unidades funcionales


clásicas: decodificadores, multiplexores, sumadores, etc.

 Utilización de tipos con relación directa al hardware, fundamentalmente los tipos BIT,
BIT_VECTOR, STD_LOGIC, STD_LOGIC_VECTOR, o similares definidos por el usuario.

 Organización típica en bloques de datos o proceso y unidades de control.

Este tipo de descripciones corresponde a un nivel de abstracción más alto que aquel de las
descripciones estructurales a nivel de puertas o componentes, pero sigue precisando una labor de
análisis -diseño top-down- para descomponer el sistema y controlar las interacciones entre los
subelementos.

Algunos ejemplos de este tipo de modelos con estilo flujo de datos son los siguientes:

VII - 1
7. Modelos de comportamiento
Con un nivel de abstracción más elevado que en los modelos estructurales, se puede describir el
funcionamiento del sistema por el flujo de datos entre registros y buses del mismo. El movimiento de
datos se controla por señales que pueden ser generadas, por ejemplo, por máquinas de estados o
FSMs. En ese estilo de descripción, las asignaciones de valor a señales son la base del modelo VHDL
correspondiente, que implica un diseño del sistema en bloques funcionales y buses, organizados en lo
que se suele llamar data path y control path. Sin embargo, cualquier modelo se desarrolla con vistas
a un determinado fin y, en tal sentido, la síntesis es la aplicación que impone más restricciones por
las limitaciones implícitas en las herramientas de síntesis. Con esa orientación, al considerar el nivel
de abstracción de los modelos de comportamiento de sistemas sintetizables, se distinguen dos estilos:

1 - Descripciones a nivel de transferencias entre registros - RTL - o de flujo de datos.


2 - Descripciones algorítmicas, sin referencia al sistema físico.

En los apartados que siguen se indican las características de cada uno de estos dos estilos y se
presentan ejemplos de modelos de varios primitivos de uso frecuente, desarrollados en alguno de los
niveles de abstracción citados y que, siguiendo los pasos descritos anteriormente en modelos
estructurales, pueden ser declarados como componentes para su utilización en una configuración o
estructura de nivel jerárquico más alto.

7.1 DESCRIPCIONES A NIVEL DE FLUJO DE DATOS

En este estilo se detallan las transferencias de datos a nivel de bloques - registros - lo que
implica un diseño previo a nivel de particionado del sistema en subelementos, así como del control de
las transferencias de datos. Esto supone que en estas descripciones se utilizarán, fundamentalmente,
sentencias concurrentes para asignaciones de señales de tipos condicionales y selectivas, así como la
estructura de la descripción en bloques cuyo comportamiento está directamente asociado a este tipo
de sentencias, por lo que estas descripciones se caracterizan por :

 Declaraciones de señales que corresponden a movimientos reales de datos y señales de control


de transferencias de datos.

 Identificación con un esquema a nivel de bloques en donde se distinguen unidades funcionales


clásicas: decodificadores, multiplexores, sumadores, etc.

 Utilización de tipos con relación directa al hardware, fundamentalmente los tipos BIT,
BIT_VECTOR, STD_LOGIC, STD_LOGIC_VECTOR, o similares definidos por el usuario.

 Organización típica en bloques de datos o proceso y unidades de control.

Este tipo de descripciones corresponde a un nivel de abstracción más alto que aquel de las
descripciones estructurales a nivel de puertas o componentes, pero sigue precisando una labor de
análisis -diseño top-down- para descomponer el sistema y controlar las interacciones entre los
subelementos.

Algunos ejemplos de este tipo de modelos con estilo flujo de datos son los siguientes:

VII - 1
7 – Modelos de comportamiento

1- Multiplexor de 16 a 4 con asignación condicional de registros


LIBRARY IEEE;
USE IEEE.STD_LOGIC_1164.ALL;

entity MUX_16a4 is
port (S1, S0 : in std_logic;
A, B, C, D: in std_logic_vector(3 downto 0);
Z: out std_logic_vector(3 downto 0));
end MUX_16a4;

architecture buses of MUX_16a4 is


begin -- SELECCIÓN CONDICIONAL DE REGISTROS
Z <= A when S1='0' and S0='0' else
B when S1='0' and S0='1' else
C when S1='1' and S0='0' else D;
end buses;

2- Multiplexor de 32 a 8 con asignación selectiva de registros


LIBRARY IEEE;
USE IEEE.STD_LOGIC_1164.ALL;

ENTITY mux_32a8_sel IS
PORT (A, B, C, D : IN STD_LOGIC_VECTOR (7 DOWNTO 0);
SEL : IN STD_LOGIC_VECTOR (1 DOWNTO 0);
Z : OUT STD_LOGIC_VECTOR (7 DOWNTO 0));
END mux_32a8_sel;
ARCHITECTURE registrada OF mux_32a8_sel IS
BEGIN
WITH sel SELECT -- asignación SELECTIVA
Z <= A WHEN "00", -- acaba en "," no hay ELSE
B WHEN "01", -- acaba en "," no hay ELSE
C WHEN "10", -- acaba en "," no hay ELSE
D WHEN OTHERS; -- la última asignación acaba en ";"
END registrada;

3- Sumador de bytes
ENTITY sumabin IS
PORT ( a, b : IN BIT_VECTOR ( 7 DOWNTO 0 );
sum : OUT BIT_VECTOR ( 7 DOWNTO 0 );
carry : OUT BIT);
END sumabin;
ARCHITECTURE funcional OF sumabin IS
SIGNAL carry_vector : BIT_VECTOR ( 8 DOWNTO 0);
SIGNAL temp : BIT_VECTOR ( 7 DOWNTO 0);
BEGIN
temp <= a XOR b;
carry_vector <= ((A AND B) OR ( temp AND carry_vector( 7 DOWNTO 0))) & '0' ;
sum <= temp XOR carry_vector( 7 DOWNTO 0) ;
carry <= carry_vector(8);
END funcional;

VII - 2
7 – Modelos de comportamiento

4- Comparador de bits del apartado 6.1


Las ecuaciones booleanas que describen el comparador de un bit son:
amb = am + b'm + ab'
bma = b n + a' n + ba'
igl = abi + a'b'i

que expresadas como funciones y almacenadas en el paquete de “modelos” como:


FUNCTION fmn (x,y,z: BIT) RETURN BIT IS
BEGIN
RETURN ( x AND z) OR (NOT y AND z) OR (x AND NOT y) ;
END fmn;
FUNCTION figl (x,y,z: BIT) RETURN BIT IS
BEGIN
RETURN ( x AND y AND z) OR (NOTx AND NOT y AND z);
END figl;

permiten describir el comparador "compbit" con la ARCHITECTURE funcional siguiente:


USE WORK. modelos.ALL ;
ENTITY compbit IS
PORT( a,b,m,i,n : IN BIT;
amb, igl, bma : OUT BIT);
END compbit;
ARCHITECTURE funcional OF compbit IS
BEGIN
amb <= fmn ( a,b,m ) ;
bma <= fmn ( b,a,n) ;
igl <= figl ( a,b,i) ;
END funcional;

Si comparamos esta descripción con la del apartado 6.1 resulta evidente que usando subprogramas, es
decir, estableciendo modularidad en los diseños, los modelos de VHDL, aparte de tener una mejor
estructura, serán más reducidos y más fácilmente interpretables.

Unas recomendaciones simples, orientadas a síntesis, podrían ser:

1 - Usar asignaciones y sentencias concurrentes, incluida PROCESS, para:


- Circuitos de operaciones aritméticas simples, tipo suma, resta, multiplicación…
- Circuitos combinacionales: puertas, multiplexores, decodificadores, etc., etc.

2 - Usar PROCESSs con lista de sensibilidad y estructura lo más simple posible para:
- Circuitos secuenciales, en general: contadores, registros, registros de desplazamiento, máquinas
de estados (FSMs), donde existe la presencia de alguna señal de reloj.
- Crear generic ENTITYs para los circuitos repetitivos y colocar los COMPONENTs
correspondientes a nivel jerárquico más alto, usando GENERIC MAP PORT MAP.
- Suplementar los componentes secuenciales con sentencias concurrentes para describir la lógica
combinacional adjunta a los bloques secuenciales.

SIN OLVIDAR, POR SUPUESTO, QUE SIEMPRE HAY EXCEPCIONES…

VII- 3
7 – Modelos de comportamiento

7.2 DESCRIPCIONES ALGORÍTMICAS

El estilo algorítmico considera al sistema como una caja negra cuya descripción se centra
fundamentalmente en relacionar entradas y salidas, sin entrar en el detalle de cómo se obtienen unas a
partir de otras. Mientras el estilo flujo de datos indica cómo opera el sistema, el estilo algorítmico
describe qué hace el sistema, por lo que este tipo de descripciones se encuentran organizadas en
PROCESS por su capacidad de uso de sentencias secuenciales y estructuras algorítmicas del tipo IF-
THEN-ELSE, etc. A diferencia de los otros estilos de descripción, el planteamiento previo al
desarrollo del modelo consiste en:

 Asociar las especificaciones del sistema a una serie de PROCESS.


 Analizar las actividades u operaciones, para determinar que señales deben obtenerse por la
actividad del proceso y determinar que señales lo controlan o disparan.
 Utilizar las sentencias más apropiadas para el control de las operaciones del proceso.

Todo lo anterior equivale a particionar el sistema en módulos operativos cuya acción viene
determinada por la actividad de unos procesos que controlan a otros.
Si en los estilos de descripción estructural o de flujo de datos es fácil asociar hardware al
modelo, en el estilo algorítmico es típico acudir a representaciones por medio de diagramas de flujo o
grafos, tablas de estados, etc. lo que supone un nivel de abstracción por encima del utilizado en los
otros estilos de modelado de sistemas.

7.3 DESCRIPCIONES ALGORÍTMICAS PARA SÍNTESIS

Si bien no existe un estilo óptimo para todas las aplicaciones donde haya descripción de
hardware, y aunque el VHDL se utilice para describir sistemas con diferentes niveles de abstracción,
la existencia de los estilos descritos anteriormente está en parte relacionada al control que se desea
tener sobre la operación del sistema, las restricciones que se desea imponer al diseño y, también, a la
potencia o capacidad de las herramientas para síntesis.
Por síntesis se entiende, en este contexto, la capacidad de transformar de forma automática una
descripción desde un nivel de abstracción a otro de nivel inferior. Esta capacidad, hasta tiempo muy
reciente, ha estado limitada a transformaciones desde el nivel RTL hasta el de puertas lógicas, lo que
forzaba al empleo de descripciones a nivel flujo de datos cuando el destino final del modelo era un
proceso de síntesis lógica.

Hay potentes herramientas con capacidad de síntesis algorítmica, que transforman


automáticamente modelos con descripciones algorítmicas a descripciones RTL, a partir de las que se
realiza la transformación a nivel de puertas. Esto es posible porque los compiladores de
comportamiento, además de aceptar la descripción explícita de registros, pueden inferir la existencia
de otros a partir de las sentencias que definen comportamiento.

La síntesis algorítmica es de uso relativamente reciente y, por tanto, las limitaciones actuales
dependen no solo de la herramienta, sino también de su versión, condicionando el desarrollo de
modelos al soporte ofrecido por la herramienta y, más particularmente, a su estilo de inferencias, es
decir, la forma en que diseña hardware a partir del código VHDL.

Las ventajas inherentes a la síntesis algorítmica son importantes:

VII - 4
7 – Modelos de comportamiento

 Reducción de los tiempos para diseñar e introducir nuevos sistemas en el mercado y reducción
de los costes de diseño, en gran medida relacionados a tiempos de diseño.
 Reducción de los errores de diseño, especialmente cuando el tamaño de los proyectos o su
complejidad crece, aumentando la probabilidad de errores, así como la dificultad de depurar los
diseños, con incidencia en el tiempo y coste del diseño.
 Posibilidad de obtener varios diseños o alternativas para un juego de especificaciones. Esto
permite elegir la más conveniente después de simular, así como fijar estrategias de gamas o
familias de productos o actualización sin hacer rediseños básicos.
 Posibilidad de introducir cambios de especificaciones y alterar los diseños sin cambios
importantes en la planificación o en los costes.

Dado que una de las aplicaciones más importantes del VHDL es la síntesis en ASICs y FPGAs,
aun suponiendo que las ventajas citadas arriba presumiblemente condicionarán no solo el estilo de
diseño o modelado de sistemas, sino también las herramientas elegidas al efecto, se exponen algunos
modelos algorítmicos desarrollados con esa orientación.

7.4 INFERENCIAS BÁSICAS DE SÍNTESIS

Dos de los factores de mérito que se consideran para valorar la eficiencia de un circuito son su
tamaño y su velocidad. Por tanto, el diseño y el modelo deberán enfocarse a fin de reducir tamaño y
maximizar velocidad, dentro de los márgenes que fijen especificaciones como el consumo de
potencia, el coste, etc. En consecuencia, hay que modelar utilizando aquellas sentencias que infieran
el hardware deseado, pero no más, lo que supone utilizar apropiadamente las sentencias a partir de las
que se infieren los elementos básicos, es decir, puertas y registros. Registrar señales
innecesariamente, en general, implica componentes innecesarios -tamaño- y retardos -velocidad-, por
lo que interesa saber que tipo de sentencias infieren registros, ya sean sensibles a nivel - latches - o
disparados por flancos, - flip-flops -, y evitar inferencias innecesarias de registros.
Normalmente, las sentencias empleadas para detectar flancos de subida son:

IF (onda’EVENT AND onda = ‘1’ ) THEN


WAIT UNTIL (onda’ EVENT AND onda = ‘1’) ;
WAIT UNTIL (NOT onda’STABLE AND onda = ‘1’) ;

todas secuenciales y, por tanto, incluidas en PROCESSs, y de las que se inferirán flip-flops en el caso
de WAIT y flip-flops o latches según se construya la sentencia IF. La elección de un tipo de sentencia
u otro puede ser una recomendación de la herramienta de síntesis, pero, normalmente, la sentencia IF
permite mejor control de las inferencias y admite más posibilidades. También, consecuentemente,
exige más cuidado en la descripción.

En general, las reglas básicas a aplicar son:

 Los procesos síncronos, que computan valores solamente en los instantes de flancos, deben ser
sensibles a la señal de reloj utilizada.
 Los procesos asíncronos, que computan valores con los flancos de reloj y cuando se cumplen
las condiciones asíncronas, deben ser sensibles a la señal de reloj, si existe, y a las señales que
afectan al comportamiento asíncrono.

Véanse los ejemplos siguientes:

VII- 5
7 – Modelos de comportamiento

Ejemplo 1: contador con control de cuenta ascendente/descendente:

LIBRARY IEEE; USE IEEE.std_logic_1164.ALL;


USE IEEE.STD_LOGIC_UNSIGNED.ALL; -- Paquete para operaciones con números sin signo

ENTITY up_dwn_counter IS
PORT(c, clr, up_down : IN std_logic;
Q : OUT std_logic_vector(3 DOWNTO 0));
END up_dwn_counter;
ARCHITECTURE simple OF up_dwn_counter IS
SIGNAL tmp: std_logic_vector(3 DOWNTO 0);
BEGIN
PROCESS (c, clr)
BEGIN
IF (clr='1') THEN -- CLEAR ASÍNCRONO
tmp <= "0000";
ELSIF (c'event and c='1') THEN
IF (up_down='1') THEN -- UP_DOWN SÍNCRONO
tmp <= tmp + 1;
ELSE
tmp <= tmp - 1;
END IF;
END IF;
END PROCESS;
Q <= tmp;
END simple;

Ejemplo 2: registro de desplazamiento, con una entrada serie, carga asíncrona y


desplazamiento a izquierda o derecha

LIBRARY IEEE; USE IEEE.std_logic_1164.ALL;


ENTITY shift_reg_mix IS
PORT(c, SI, carga, izq_der : IN std_logic;
dato : IN std_logic_vector(7 DOWNTO 0);
sal : OUT std_logic_vector(7 DOWNTO 0));
END shift_reg_mix;
ARCHITECTURE mix OF shift_reg_mix IS
SIGNAL tmp: std_logic_vector (7 DOWNTO 0);
BEGIN
PROCESS (c, carga)
BEGIN
IF (carga='1') THEN --Carga asíncrona
tmp <= dato;
ELSIF (c'EVENT AND c='1') THEN --Entrada serie síncrona
IF (izq_der ='0') THEN --Desplazamiento hacia la izquierda
tmp <= tmp(6 DOWNTO 0) & SI; --Serial Input menos significativa
ELSE --Desplazamiento hacia la derecha
tmp <= SI & tmp(7 DOWNTO 1); --Serial Input más significativa
END IF;
END IF;
END PROCESS;
sal <= tmp;
END mix;

VII - 6
7 – Modelos de comportamiento

7.5 MÁQUINAS DE ESTADOS FINITOS o FSMs

Las FSMs son ejemplos típicos de descripciones de comportamiento. La representación más


simple de una FSM contiene los bloques y conexiones de la figura siguiente:

estado siguiente
estado actual
DD Q Lógica de
siguiente estado
reset reset D
Lógica de salidas
ck ck
entradas salidas

Las FSMs se definen como sistemas compuestos por conjuntos de entradas, salidas y estados
que determinan la evolución de la máquina en base a una función de transición entre estados.
Los estados son valores que representan los pasos o etapas por los que la FSM puede avanzar.
Las salidas están determinadas por funciones de salidas que en las FSMs de Mealy dependen
directamente de estados y entradas, mientras en las FSMs de Moore solo dependen directamente de
los estados. Hay equivalencias entre máquinas de Mealy y de Moore, pero existen diferencias en su
comportamiento y velocidad, pues su estructura y el tiempo de respuesta de las salidas es diferente.
La función de transición prepara el siguiente estado para que sea el nuevo estado actual,
activado por el flanco de la señal de reloj -ck- que provoca las transiciones de estados. La función de
transición puede determinar que el siguiente estado sea el mismo que el estado actual. La activación
de reset hará que la FSM salte a un estado inicial predeterminado.
Los cambios de entradas entre flancos de reloj pueden provocar cambios inmediatos en las
salidas de las FSM Mealy, si así lo determinan las correspondientes funciones de salida, mientras que
en las FSM Moore las salidas solo cambian con las transiciones de estados.

En VHDL, para modelar FSMs se pueden considerar los tres bloques de la figura de forma
aislada, asociar dos de ellos o considerar un único bloque para toda la FSM. Según el particionado
que se elija, se aplicarán metodologías apropiadas de síntesis para lógica combinacional y registros,
sin olvidar las restricciones de las herramientas de síntesis. Normalmente, para los estados se definen
tipos “ad hoc”, haciendo uso de los “tipos enumerados” que permite VHDL, por ejemplo:

TYPE estado_ascensor IS
(planta0, planta1, planta2, planta3);

donde se definen señales de nombre significativo, a las que se puede aplicar valores como:

SIGNAL planta_actual: estado_ascensor;


planta_actual <= planta2;

Para describir el comportamiento de una FSM se acude a diagramas de transición y tablas donde se
representan la evolución y las salidas asociadas a cada estado o transición en función de las entradas.
En los diagramas de transición cada estado se representa por un círculo o “burbuja” etiquetada con el
nombre del estado. Por medio de flechas se representa la evolución entre estados o burbujas,
indicando sobre cada flecha los valores de las entradas que provocan ese salto o transición; si no se
indican, la transición entre los dos estados es forzosa o independiente de los valores de las entradas.
En las FSM de Moore, dentro de cada burbuja se indican los valores de las salidas en ese estado.
En los apartados siguientes se verán detalles y alternativas de descripciones para ambas FSMs.

VII- 7
7 – Modelos de comportamiento

7.5.1 MÁQUINA DE MEALY


En las FSM de Mealy, sobre las flechas se indican con el formato “entrada/salida” las entradas
que provocan la transición síncrona y las salidas asíncronas que se obtienen en ese estado.
Supongamos que el diagrama de estados y la tabla correspondiente son las siguientes:

1/1

S1 ESTADO ESTADO SALIDA


1/1 1/0 ACTUAL SIGUIENTE Z
0/1 X=0 X=1 X=0 X=1
S5 0/0 S2 S1 XS3
=1 S1 11
X= 1
S2 S4 S2 1 0
0/1 S3 S5 S3 0 0
1/1 S4 S4 S1 0 1
0/0 S5 S2 S5 0 1
S4 1 S3 1/0
0/0

Si la FSM se considera con el diagrama general de tres bloques de una FSM, para describirla
con tres PROCESS, la descripción VHDL podría ser la siguiente:

ENTITY mealyfsm_TRS IS
PORT ( X, CLK, reset : IN BIT;
Z : OUT BIT);
END mealyfsm_TRS;

ARCHITECTURE comport OF mealyfsm_TRS IS

TYPE tipo_estado IS ( s1,s2,s3,s4, s5);


SIGNAL estado_actual, estado_sigte : tipo_estado;
BEGIN
estados: PROCESS(clk, reset)
BEGIN
IF reset = '1' THEN
estado_actual <= S1;
ELSIF (clk'EVENT AND clk = '1') THEN
estado_actual <= estado_sigte;
END IF;
END PROCESS;

fun_estados : PROCESS (estado_actual, X)


BEGIN
CASE estado_actual IS
WHEN s1 => IF X = '0' THEN estado_sigte <= s3;
ELSE estado_sigte <= s1;
END IF;
WHEN s2 => IF X = '0' THEN estado_sigte <= s4;
ELSE estado_sigte <= s2;
END IF;
WHEN s3 => IF X = '0' THEN estado_sigte <= s5;
ELSE estado_sigte <= s3;
END IF;

VII - 8
7 – Modelos de comportamiento

WHEN s4 => IF X = '0' THEN estado_sigte <= s4;


ELSE estado_sigte <= s1;
END IF;
WHEN s5 => IF X = '0' THEN estado_sigte <= s2;
ELSE estado_sigte <= s5;
END IF;
END CASE;
END PROCESS;

salidas : PROCESS (estado_actual, X)


BEGIN
CASE estado_actual IS
WHEN s1 => Z <= '1';
WHEN s2 => IF X = '0' THEN Z <= '1';
ELSE Z <= '0';
END IF;
WHEN s3 => Z <= '0';
WHEN s4 => IF X = '0' THEN Z <= '0';
ELSE Z <= '1';
END IF;
WHEN s5 => IF X = '0' THEN Z <= '0';
ELSE Z <= '1';
END IF;
END CASE;
END PROCESS;
END comport;

Si particionamos el modelo en dos PROCESS, uno cambia la lógica combinacional y otro la


secuencial que provoca la transición entre estados por acción de las señales clk y reset.
ENTITY mealyfsm_DOS IS
PORT ( X, CLK, reset : IN BIT; Z : OUT BIT);
END mealyfsm_DOS;
ARCHITECTURE comport OF mealyfsm_DOS IS
TYPE tipo_estado IS ( s1,s2,s3,s4, s5);
SIGNAL estado_actual, estado_sigte: tipo_estado;
BEGIN
combinacional : PROCESS ( estado_actual, X)
BEGIN
CASE estado_actual IS
WHEN s1 => IF X = '0' THEN Z <= '1'; estado_sigte <= s3;
ELSE Z <= '1'; estado_sigte <= s1;
END IF;
WHEN s2 => IF X = '0' THEN Z <= '1'; estado_sigte <= s4;
ELSE Z <= '0'; estado_sigte <= s2;
END IF;
WHEN s3 => IF X = '0' THEN Z <= '0'; estado_sigte <= s5;
ELSE Z <= '0'; estado_sigte <= s3;
END IF;
WHEN s4 => IF X = '0' THEN Z <= '0'; estado_sigte <= s4;
ELSE Z <= '1'; estado_sigte <= s1;
END IF;
WHEN s5 => IF X = '0' THEN Z <= '0'; estado_sigte <= s2;
ELSE Z <= '1'; estado_sigte <= s5;
END IF;
END CASE;
END PROCESS;

VII- 9
7 – Modelos de comportamiento

conmutacion: PROCESS(clk, reset)


BEGIN
IF reset = ‘1’ then
estado_actual <= s1;
ELSIF (clk'EVENT AND clk = '1') THEN
estado_actual <= estado_sigte;
END IF;
END PROCESS;
END comport;

Finalmente, si toda la FSM se considera como un bloque para modelarla solo con un PROCESS, la
descripción podría ser la siguiente, donde puede verse que el PROCESS único agrupa las dos
sentencias que iban separadas en la descripción con dos PROCESS
ENTITY mealyfsm_uno IS
PORT ( X, CLK, reset : IN BIT;
Z : OUT BIT);
END mealyfsm_uno;

ARCHITECTURE comport OF mealyfsm_uno IS

TYPE tipo_estado IS (s0,s1,s2,s3,s4);


SIGNAL estado_actual, estado_sigte: tipo_estado;

BEGIN
UNO: PROCESS (clk, reset, X)
BEGIN
CASE estado_actual IS -- Bloques “salidas y siguiente_estado” fusionados
WHEN s0 => IF X = '0' THEN estado_sigte <= s2; Z <= '1';
ELSE estado_sigte <= s0; Z <= '1';
END IF;
WHEN s1 => IF X = '0' THEN estado_sigte <= s3; Z <= '1';
ELSE estado_sigte <= s1; Z <= '0';
END IF;
WHEN s2 => IF X = '0' THEN estado_sigte <= s4; Z <= '0';
ELSE estado_sigte <= s2; Z <= '0';
END IF;
WHEN s3 => IF X = '0' THEN estado_sigte <= s3; Z <= '0';
ELSE estado_sigte <= s0; Z <= '1';
END IF;
WHEN s4 => IF X = '0' THEN estado_sigte <= s1; Z <= '0';
ELSE estado_sigte <= s4; Z <= '1';
END IF;
END CASE; -- Fin del bloque “salidas y siguiente_estado” fusionados
IF reset = '1' THEN -- Bloque de asignación de estado_actual
estado_actual <= s0;
ELSIF (clk'EVENT AND clk = '1') THEN
estado_actual <= estado_sigte;
END IF;
END PROCESS;
END comport;

En la descripción encapsulada en el único PROCESS puede observarse que la señal estado_actual


solo sigue a la señal estado_sigte en la sección síncrona que sigue a la detección del flanco de reloj,
mientras que las asignaciones a estado_sigte, salida Z o estado_actual por reset son asíncronas.

VII - 10
7 – Modelos de comportamiento

7.5.2 MÁQUINA DE MOORE

S1/ 0 ESTADO ESTADO SALI


1 1 ACTUAL SIGUIENTE DA
0 X=0 X=1 Z
S5/ 1 0 S2/ 1 S1 XS3
=1 S1 0
S2 S4 S2 1
0 S3 S5 S3 1
1 S4 S4 S1 0
0 S5 S2 S5 1
S4/ 0 S3/ 1
1
0

El modelo correspondiente es muy similar al del ejemplo de Mealy, aunque el etiquetado de


burbujas tiene el formato “estado/salida” y las flechas solo el valor de la entrada para esa transición.

Se repite la presentación de modelos hecha en el apartado anterior para la FSM-Mealy, con una
descripción de una FSM-Moore con tres PROCESS:

ENTITY moorefsm_TRS IS
PORT (X, CLK, reset : IN BIT;
Z : OUT BIT);
END moorefsm_TRS;
ARCHITECTURE comport OF moorefsm_TRS IS
TYPE tipo_estado IS ( s1,s2,s3,s4, s5);
SIGNAL estado_actual, estado_sigte : tipo_estado;
BEGIN
conmutacion: PROCESS(clk, reset)
BEGIN
IF reset = '1' THEN
estado_actual <= S1;
ELSIF (clk'EVENT AND clk = '1') THEN
estado_actual <= estado_sigte;
END IF;
END PROCESS;

estados: PROCESS (estado_actual, X)


BEGIN
CASE estado_actual IS
WHEN s1 =>
IF X = '0' THEN estado_sigte <= s3;
ELSE estado_sigte <= s1;
END IF;
WHEN s2 =>
IF X = '0' THEN estado_sigte <= s4;
ELSE estado_sigte <= s2;
END IF;
WHEN s3 =>
IF X = '0' THEN estado_sigte <= s5;
ELSE estado_sigte <= s3;
END IF;

VII- 11
7 – Modelos de comportamiento

WHEN s4 =>
IF X = '0' THEN estado_sigte <= s4;
ELSE estado_sigte <= s1;
END IF;
WHEN s5 =>
IF X = '0' THEN estado_sigte <= s2;
ELSE estado_sigte <= s5;
END IF;
END CASE;
END PROCESS;
salidas: PROCESS (estado_actual)
BEGIN
CASE estado_actual IS
WHEN s1 => Z <= '0';
WHEN s2 => Z <= '1';
WHEN s3 => Z <= '1';
WHEN s4 => Z <= '0';
WHEN s5 => Z <= '1';
END CASE;
END PROCESS;
END comport;

La descripción para dos PROCESS podría ser:

ENTITY moorefsm_DOS IS
PORT ( X, CLK, reset : IN BIT; Z : OUT BIT);
END moorefsm_DOS;

ARCHITECTURE comport OF moorefsm_DOS IS


TYPE tipo_estado IS ( s1,s2,s3,s4, s5);
SIGNAL estado_actual, estado_sigte : tipo_estado;
BEGIN
combinacional : PROCESS (estado_actual, X)
BEGIN
CASE estado_actual IS
WHEN s1 => Z <= '0';
IF X = '0' THEN estado_sigte <= s3;
ELSE estado_sigte <= s1;
END IF;
WHEN s2 => Z <= '1';
IF X = '0' THEN estado_sigte <= s4;
ELSE estado_sigte <= s2;
END IF;
WHEN s3 => Z <= '1';
IF X = '0' THEN estado_sigte <= s5;
ELSE estado_sigte <= s3;
END IF;
WHEN s4 => Z <= '0';
IF X = '0' THEN estado_sigte <= s4;
ELSE estado_sigte <= s1;
END IF;
WHEN s5 => Z <= '1';
IF X = '0' THEN estado_sigte <= s2;
ELSE estado_sigte <= s5;
END IF;
END CASE;
END PROCESS;

VII - 12
7 – Modelos de comportamiento

conmutacion: PROCESS(clk, reset)


BEGIN
IF reset = '1' THEN
estado_actual <= S1;
ELSIF (clk'EVENT AND clk = '1') THEN
estado_actual <= estado_sigte;
END IF;
END PROCESS;
END comport;

Por último, una descripción en un único PROCESS, en la que se hace una agrupación de las
sentencias separadas en PROCESS independientes en el modelo moorefsm_dos.vhd:

ENTITY moorefsm_UNO IS
PORT (X, CLK, reset : IN bit;
Z : OUT bit);
END moorefsm_UNO;

ARCHITECTURE comport OF moorefsm_UNO IS


TYPE tipo_estado IS (s1,s2,s3,s4,s5);
SIGNAL estado_actual, estado_sigte : tipo_estado;
BEGIN

UNO: PROCESS(clk, reset, X)


BEGIN
CASE estado_actual IS -- Bloques combinacionales fusionados
WHEN s1 => IF X = '0' THEN estado_sigte <= s3; Z <= '0';
ELSE estado_sigte <= s1; Z <= '0';
END IF;
WHEN s2 => IF X = '0' THEN estado_sigte <= s4; Z <= '1';
ELSE estado_sigte <= s2; Z <= '1'
END IF;
WHEN s3 => IF X = '0' THEN estado_sigte <= s5; Z <= '1';
ELSE estado_sigte <= s3; Z <= '1';
END IF;
WHEN s4 => IF X = '0' THEN estado_sigte <= s4; Z <= '0';
ELSE estado_sigte <= s1; Z <= '0';
END IF;
WHEN s5 => IF X = '0' THEN estado_sigte <= s2; Z <= '1';
ELSE estado_sigte <= s5; Z <= '1';
END IF;
END CASE; -- Fin de bloques combinacionales fusionados
IF (reset = '1') THEN -- Bloque de señal “estado_actual”
estado_actual <= S1;
ELSIF (clk'EVENT AND clk = '1') THEN
estado_actual <= estado_sigte;
END IF; -- Fin de bloque de “señal_actual”
END PROCESS;
END comport;

De forma similar a lo realizado en el modelo mealyfsm_uno.vhd, se han incluido los dos


bloques combinacionales en una única sentencia CASE, que permite asignaciones simultáneas
a las señales Z y estado_sigte, minimizando la descripción y la síntesis. El orden de las
sentencias secuenciales IF y CASE no importa en este PROCESS, ya que la operación de una u
otra sentencia arranca por el evento en las señales que le afectan de la lista de sensibilidad del
PROCESS, y esas señales no intervienen simultáneamente en los dos bloques descritos.

VII- 13
8. Introducción a los modelos aritméticos
El uso de funciones y operadores aritméticos es frecuente en los sistemas electrónicos
y, por tanto, en VHDL se consideran tipos y operadores apropiados para modelar y
sintetizar sistemas que incorporan sumadores, comparadores, contadores, multiplicadores y
otros módulos capaces de realizar operaciones aritméticas. Sin embargo, por la dependencia
del VHDL en los tipos de sus objetos, la descripción y síntesis de esos módulos se presta a
confusión al considerar las posibles mezclas de tipos incompatibles en los operandos y en
los resultados esperados, que dependen de las funciones que VHDL define o permite en
cada operación aritmética con los tipos en uso. Los apartados siguientes solo pretenden
hacer una presentación de los tipos y funciones de uso más frecuente, así como de los
paquetes donde tales tipos y funciones están declarados y definidos.

8.1 TIPOS Y PAQUETES ARITMÉTICOS EN VHDL

Los paquetes STANDARD y STD_LOGIC no definen funciones aritméticas para los tipos
INTEGER o STD_LOGIC_VECTOR definidos en ellos, lo que hace necesario acudir a otros
paquetes donde se definen nuevos tipos y funciones que es preciso conocer para modelar
convenientemente las operaciones aritméticas.
Los primeros paquetes aritméticos fueron desarrollados por Synopsys e incorporados
como estándares “de facto” a la biblioteca o library IEEE con los nombres std_logic_arith,
std_logic_unsigned y std_logic_signed, donde se definen los tipos unsigned y signed, una
serie de operadores aritméticos para ellos y funciones para conversión a otros tipos como
std_logic_vector. Poco después, el IEEE publicó el estándar numeric_std, recomendado para
nuevos desarrollos, aunque por razones históricas y de compatibilidad no está en la library
IEEE de algunas de las primeras herramientas CAD de VHDL. Así, es frecuente que los
ficheros *.vhd de contenido aritmético se inicien con encabezamientos como:

library ieee ; library ieee ;


use ieee.std_logic_1164.all ; use ieee.std_logic_1164.all ;
use ieee.std_logic_arith.all ; use ieee. numeric_std.all;
use ieee.std_logic_unsigned.all ;

Debe evitarse el uso simultáneo de los paquetes “arith” y “numeric”, para evitar operaciones
ambiguas. Como puede verse en los paquetes numeric_std y std_logic_arith, los nuevos tipos
se definen como:

type UNSIGNED is array (NATURAL range <>) of STD_LOGIC;


type SIGNED is array (NATURAL range <>) of STD_LOGIC;

El tipo UNSIGNED representa a los INTEGER sin signo del rango 0 a 2N -1


El tipo SIGNED representa a los INTEGER del rango -2(N-1) a 2(N-1) -1, siendo los negativos
el “complemento a 2” del correspondiente positivo.

VIII - 1
8 – Introducción a los modelos aritméticos

El uso de ambos tipos es similar al del std_logic_vector, por ejemplo:

signal A_sin_signo : unsigned(7 downto 0);


signal B_con_signo: : signed(7 downto 0);
signal C_slv : std_logic_vector (7 downto 0);

y posibles asignaciones de valor, podrían ser:

A_sin_signo <= "11111111" ; -- 255 decimal


B_con_signo <= "11111111" ; -- -1 decimal
C_slv <= "11111111" ; -- 255 decimal, solo si se usa std_logic_unsigned

8.2 OPERACIONES CON UNSIGNED INTEGERS

Extensión por concatenación: Usando el operador & se puede aumentar el rango, lo


que equivale a insertar 0’s no significativos a la izquierda:

SIGNAL octeto : unsigned(7 DOWNTO 0);


SIGNAL cuad : unsigned(3 DOWNTO 0);

Octeto <= “0000” & cuad;

Truncamiento: Es la operación inversa a la anterior:

cuad <= octeto(3 downto 0);

Comparación: Operación para comparar la igualdad o desigualdad de INTEGERs,


utilizando los operadores “=”, “<” y “>”, además de sus combinaciones /=, para “no igual”,
<= para “igual o menor que” y >= para “igual o mayor que”. El resultado de las operaciones
es TRUE-FALSE, es decir, tipo “boolean”, que es el necesario si la comparación ocurre dentro
de un IF. Si lo que se desea es asignar valor a una variable de tipo std_logic, con ‘0’,
representando a FALSE y ‘1’ representando a TRUE, será necesario hacer la conversión del
resultado “boolean” a std_logic. Posibles sentencias para comparar UNSIGNED INTEGER son:

LIBRARY IEEE;
USE IEEE.STD_LOGIC_1164.ALL;
USE IEEE.STD_LOGIC_ARITH.ALL;

ENTITY comparador_unsigned IS
port( A,B : IN unsigned(7 downto 0);
CMP : OUT STD_LOGIC);
END comparador_unsigned;

ARCHITECTURE simple OF comparador_unsigned IS


BEGIN
CMP <= '1' when A >= B else '0';
END simple;

VIII - 2
8 – Introducción a los modelos aritméticos

Incremento y decremento: son operaciones con INTEGERs equivalentes a sumas y


restas donde uno de los operandos es 1. Su aplicación es frecuente en contadores.

LIBRARY IEEE;
USE IEEE.STD_LOGIC_1164.ALL;
USE IEEE.STD_LOGIC_ARITH.ALL; -- necesaria para sumar INTEGERs

ENTITY contador_unsigned IS
port(C, CLR, UP_DOWN : in std_logic;
Q : out UNSIGNED(3 downto 0));
END contador_unsigned;

ARCHITECTURE test OF contador_unsigned IS


signal tmp: UNSIGNED(3 downto 0);
BEGIN
PROCESS (C, CLR)
BEGIN
if (CLR='1') then
tmp <= "0000";
elsif (C'event and C='1') then
if (UP_DOWN='1') then
tmp <= tmp + 1; -- ¡suma con 1 INTEGER !
else
tmp <= tmp - 1; -- ¡suma con 1 INTEGER !
end if;
end if;
END PROCESS;
Q <= tmp;
END test;

Otra alternativa podría ser si los tipos de Q y tmp fuesen STD_LOGIC_VECTOR, es decir:

En la ENTITY Q : out STD_LOGIC_VECTOR (3 downto 0));


En la ARCHITECTURE signal tmp : out STD_LOGIC_VECTOR (3 downto 0));

En este caso, manteniendo las sentencias del anterior modelo contador_unsigned, excepto las
asignaciones del IF interno que se cambian como sigue:

IF (UP_DOWN='1') THEN
tmp <= unsigned(tmp) + 1; -- ¡suma de INTEGER y UNSIGNED !
ELSE
tmp <= unsigned(tmp) - 1; -- ¡suma de INTEGER y UNSIGNED !
END IF;

con unsigned(tmp) se realiza un cambio llamado “type casting” que convierte el tipo de la
señal tmp de STD_LOGIC_VECTOR a tipo UNSIGNED, al utilizar una de las funciones que
define STD_LOGIC_ARITH para tipos UNSIGNED. La expresiones aritméticas se interpretan
como sumas de una señal tipo UNSIGNED y una constante tipo INTEGER, para devolver un
resultado tipo STD_LOGIC_VECTOR al llamar a una de las funciones definidas en
STD_LOGIC_ARITH. En la página siguiente se muestra un ejemplo más de esa particular
conversión de tipos con igual formato, como son STD_LOGIC_VECTOR y UNSIGNED.

VIII- 3
8 – Introducción a los modelos aritméticos

Sumas y Restas: son operaciones binarias donde los paquetes STD_LOGIC_ARITH Y


STD_LOGIC_UNSIGNED permiten descripciones sintetizables muy simples:

LIBRARY IEEE;
USE IEEE.std_logic_1164.all;
USE IEEE.std_logic_unsigned.all;

ENTITY suma_incr IS
PORT ( A,B : IN std_logic_vector(7 downto 0);
C,D :OUT std_logic_vector(7 downto 0));
END suma_incr;

ARCHITECTURE simple OF suma_incr IS


BEGIN
C <= A + 1;
D <= A + B;
END simple;

La sencillez de la descripción anterior se debe a las funciones definidas en el paquete


IEEE.STD_LOGIC_UNSIGNED para operaciones entre señales tipo STD_LOGIC_VECTOR y
tipo INTEGER. En este ejemplo se interpreta que todas las señales STD_LOGIC_VECTOR
representan números binarios UNSIGNED.

Otra descripción simple del mismo ejemplo, pero utilizando ahora el paquete
STD_LOGIC_ARITH, permite ver las sutilezas de las funciones definidas en algunos paquetes
y ausentes de otros:

LIBRARY IEEE;
USE IEEE.std_logic_1164.all;
USE IEEE.std_logic_arith.all; -- cambio respecto al ejemplo anterior

ENTITY sumar_incrm IS
PORT ( A,B : IN std_logic_vector(7 downto 0);
C,D :OUT std_logic_vector(7 downto 0));
END sumar_incrm;

ARCHITECTURE simple OF sumar_incrm IS

BEGIN

C <= unsigned(A) + 1;
D <= unsigned(A) + unsigned(B);

END simple;

El ejemplo hace uso del “type casting” comentado en la página anterior, aprovechando
la definición de tipos UNSIGNED y SIGNED y las funciones definidas para ellos en el paquete
STD_LOGIC_ARITH. Al tener igual formato que STD_LOGIC_VECTOR, todos pueden tener los
mismos caracteres y es posible la conversión de un tipo a otro con el “type casting”.

VIII - 4
8 – Introducción a los modelos aritméticos

El ejemplo sintetizable siguiente contempla el desbordamiento para sumas y restas:

LIBRARY IEEE;
USE IEEE.STD_LOGIC_1164.ALL;
USE IEEE.STD_LOGIC_ARITH.ALL; -- sustituible por use ieee.numeric_std.all;

ENTITY add_sub_unsigned IS
port ( a, b : in unsigned(7 downto 0);
modo : in std_logic;
s : out unsigned(7 downto 0);
ovf, unf : out std_logic);
END add_sub_unsigned;

ARCHITECTURE comport OF add_sub_unsigned IS


signal s_tmp:unsigned(8 downto 0);
BEGIN
s_tmp <= ('0' & a) + ('0' & b) WHEN modo = '0' ELSE
('0' & a) - ('0' & b);
s <= s_tmp(7 downto 0);
ovf <= '1' when s_tmp(8) > s_tmp(7);
unf <= '1' when (a < b) and (modo = '1');
END comport;

En el ejemplo se ha forzado la posibilidad de desbordamientos “ovf” en la señal s


cuando modo = ‘0’, es decir, en caso de sumas, al limitar su rango a unsigned(7 downto 0), ya
que si fuera s : out unsigned(8 downto 0) nunca habría desbordamiento. De igual manera, en
el caso de las restas x - y, en modo = ‘1’, habrá desbordamiento “unf” si x < y, ya que en
tipos unsigned no existe representación de valores negativos.

Simulación post_síntesis del modelo “add_sub_unsigned”

Es importante resaltar la importancia de las múltiples funciones de conversión


disponibles en los paquetes NUMERIC_STD, STD_LOGIC_ARITH y STD_LOGIC_UNSIGNED.
Sería prolijo detallar algunas de ellas o citar todas las posibles. El lector interesado puede
examinar los correspondientes ficheros .vhd de los paquetes, fácilmente localizables en la
web, y observar sus posibilidades. Un extracto se ve en la tabla siguiente:

VIII- 5
8 – Introducción a los modelos aritméticos

A la vista de la tabla anterior, como un ejemplo de las posibilidades que ofrecen las
funciones de conversión de tipos residentes en los paquetes ARITH y UNSIGNED, el modelo
siguiente suma_byte.vhd muestra una descripción algorítmica sintetizable y relativamente
sencilla, porque incorpora varias funciones de conversión de tipos definidas en los paquetes
y “transparentes” en la descripción. De no haberlo hecho, aparte de la imposibilidad de usar
dos veces la función “+”, la descripción hubiera sido más complicada por conflictos entre
los tipos que se utilizan en ella:

LIBRARY IEEE;
USE IEEE.STD_LOGIC_1164.ALL;
USE IEEE.STD_LOGIC_ARITH.ALL; -- los dos paquetes son necesarios
USE IEEE.STD_LOGIC_UNSIGNED.ALL; -- los dos paquetes son necesarios

ENTITY suma_byte IS
PORT ( A,B : IN STD_LOGIC_VECTOR(7 downto 0);
CI : IN STD_LOGIC;
SUM : OUT STD_LOGIC_VECTOR(7 downto 0);
CO : OUT STD_LOGIC);
END suma_byte;

ARCHITECTURE algoritmica OF suma_byte IS


SIGNAL tmp: std_logic_vector(8 downto 0);
BEGIN
tmp <= conv_std_logic_vector ((conv_integer(A) + conv_integer(B)),9);
SUM <= tmp(7 downto 0) + CI;
CO <= tmp(8);
END algoritmica;

En este ejemplo se observa la llamada a std_logic_arith y std_logic_unsigned, siendo


necesarias las dos porque las funciones -conv_std_logic_vector y conv_integer(arg) - no
están en el mismo paquete.

En los modelos UNSIGNED se pueden utilizar valores positivos dentro del rango permitido.

VIII - 6
8 – Introducción a los modelos aritméticos

Simulación post_síntesis del modelo suma_byte

8.3 OPERACIONES CON SIGNED INTEGERS

El manejo de tipos SIGNED conlleva la complejidad del bit de signo y la consideración


de su tratamiento como un bit especial al procesar señales tipo SIGNED.

Lo primero que cabe decir es que los tipos SIGNED y UNSIGNED son incompatibles y
que cualquier operación con ellos requiere la oportuna conversión. Por la misma razón, dada
la semejanza de los paquetes STD_LOGIC_SIGNED y STD_LOGIC_UNSIGNED, así como de
las funciones definidas en ellos, no deben llamarse ambos paquetes en un mismo modelo,
porque es probable que la sobrecarga de operadores cause llamadas ambiguas o mezclas de
tipos que darían errores de compilación.

Los tipos SIGNED están codificados en “complemento a 2”, que representa números
enteros de forma binaria en base a una suma de potencias de 2 y coeficientes binarios ,
lo que permite expresar un número X de n bits como:

X=− 2 + 2 + 2 + …+ 2 + 2

Esta expresión supone las siguientes propiedades de los números así codificados:

1- El número más negativo es −2 ; tiene = 1 y todos los demás coeficientes son 0’s.
2- El número más positivo es 2 − 1; tiene = 0 y todos los demás bits son 1’s.
3- El coeficiente, o bit, = 1 determina que el número es negativo, ya que la suma de
todas las potencias de 2 siguientes a 2 es menor que 2 .
4- Por razonamiento similar, el coeficiente = 0 determina que el número es positivo.
5- El rango de números así codificados es asimétrico respecto a 0, siendo uno mayor el de
los negativos, debido al coeficiente 0 para el 2 del “imposible” número más positivo.

Se presentan unas consideraciones básicas para el uso de tipos SIGNED, todas ellas en el
supuesto de una llamada previa al paquete IEEE.NUMERIC_STD.

VIII- 7
8 – Introducción a los modelos aritméticos

Representación: De la misma forma que los UNSIGNED y STD_LOGIC_VECTOR.


Posibles declaraciones de señales podrían ser:

SIGNAL u : unsigned(11 downto 0);


SIGNAL s : signed(11 downto 0);

Sería incorrecta una asignación con la expresión:

u <= s; -- por ser tipos diferentes no se pueden asignar uno a otro directamente

Serían posibles asignaciones con conversión explícita, como:

u <= unsigned (s); -- en el supuesto de que s no es negativo


s <= signed (u); -- en el supuesto de que u es menor que 2**11.

Otras declaraciones y conversiones para usar simultáneamente diversos tipos podrían ser:

SIGNAL n, m : integer range -2**7 to 2**7 – 1; -- implica un rango de 8 bits


SIGNAL a, b : signed (7 downto 0);
SIGNAL z : signed (11 downto 0);
SIGNAL z_signo : std_logic;

n <= TO_INTEGER(a);
m <= n + TO_INTEGER(b);
z <= TO_SIGNED(m, z’LENGTH); -- referencia al atributo ’LENGTH de un array
z_signo <= z(z’LEFT); -- referencia al atributo LEFT de un array

Las funciones TO_INTEGER y TO_SIGNED operan de forma inversa, la primera convierte


desde SIGNED a INTEGER y la segunda al contrario.

Extensión y truncamiento: La extensión supone extender el signo, añadiendo 1’s a la


izquierda para números negativos y 0’s para números positivos, igual que con UNSIGNEDs.
El truncamiento supone recortar bits a la izquierda, supuestamente manteniendo el bit de
signo, es decir, el truncamiento más allá del bit de signo alteraría el valor del número.

Si se desea redimensionar, es decir, extender o truncar el signo de las señales:

SIGNAL a, b : signed (7 downto 0);


SIGNAL z : signed (11 downto 0);

sería posible hacerlo con función resize, tal como indican las asignaciones siguientes:

z <= resize (a, z’LENGTH);


a <= resize (z, a’LENGTH);

pero habría que llamar al paquete NUMERIC_STD, porque los otros paquetes aritméticos no
tienen la función resize, aunque ya se ha visto que la concatenación permite fácilmente
hacer las extensiones de forma independiente a los paquetes utilizados. También se puede
hacer, por supuesto, extendiendo el bit de signo con el operador de concatenación &.

VIII - 8
8 – Introducción a los modelos aritméticos

Comparación: en el bloque de funciones BOOLEAN del paquete SIGNED se puede ver que
están definidas en él todas las posibles combinaciones de los delimitadores /, =, <, >, para
realizar las comparaciones que se deseen entre valores de tipo SIGNED.

Incremento y decremento: es igual que el modelo “contador_unsigned” visto con tipos


UNSIGNED, salvo en las declaraciones de señales Q y tmp. La evolución binaria de ambos
modelos es idéntica, siendo diferente la representación en base decimal con signo, pues los
rangos de números representables con cada tipo son diferentes, como ya se ha indicado.
LIBRARY IEEE;
USE IEEE.STD_LOGIC_1164.ALL;
USE IEEE.STD_LOGIC_ARITH.ALL;

ENTITY contador_signed is
port(C, CLR, UP_DOWN : in std_logic;
Q : out SIGNED(3 downto 0)); -- cambio a tipo SIGNED
END contador_signed;

ARCHITECTURE test OF contador_signed IS


signal tmp: SIGNED(3 downto 0); -- cambio a tipo SIGNED
BEGIN
PROCESS (C, CLR)
BEGIN
if (CLR='1') then
tmp <= "0000";
elsif (C'event and C='1') then
if (UP_DOWN='1') then
tmp <= tmp + 1; -- ¡suma con 1 INTEGER !
else
tmp <= tmp - 1; -- ¡resta con 1 INTEGER !
end if;
end if;
END PROCESS;
Q <= tmp;
END test;

Simulación post_síntesis del modelo “contador_signed”

VIII- 9
8 – Introducción a los modelos aritméticos

Sumas y Restas: son operaciones binarias en las que se considera el signo indicado por los
bits más significativos de los operandos y los procedimientos para operar con sus valores
negativos y positivos. Los paquetes STD_LOGIC_ARITH Y STD_LOGIC_SIGNED permiten
descripciones sintetizables simples.

Dado que los posibles desbordamientos positivos -overflow- o negativos -underflow-


se producen en los bits más significativos, es preciso redimensionar los operandos o el
resultado para que no existan desbordamientos y, si los hay, detectarlos y generar los
oportunos avisos para saber que el resultado binario obtenido no es correcto. En el caso de
sumas, el desbordamiento positivo se produce cuando la suma supera al máximo valor
positivo (2 − 1) representable en el rango de los n bits utilizados, mientras que el
desbordamiento negativo ocurre cuando la suma de dos números negativos rebasa el valor
(−2 ) del máximo número negativo representable con n bits. Veamos unos ejemplos:

A +66 0 1 0 0 0 0 1 0 A +67 0 1 0 0 0 0 1 1
B +61 0 0 1 1 1 1 0 1 B +61 0 0 1 1 1 1 0 1
S +127 0 1 1 1 1 1 1 1 S +128 1 0 0 0 0 0 0 0

Sin desbordamiento positivo Con desbordamiento positivo

El desbordamiento positivo hace ‘1’ al bit de signo de la suma S, distinto a los bits de signo
de los sumandos A y B. En el caso de rango SIGNED (7 downto 0) puede expresarse:

Condición de desbordamiento positivo: NOT A(7) AND NOT B(7) AND S(7)

De forma similar, el desbordamiento negativo ocurre al sumar dos números negativos y


rebasar el valor del máximo número negativo representable en “complemento a 2”
A -34 1 1 0 1 1 1 1 0 A -35 1 1 0 1 1 1 0 1
B -94 1 0 1 0 0 0 1 0 B -94 1 0 1 0 0 0 1 0
S -128 1 0 0 0 0 0 0 0 S -129 0 1 1 1 1 1 1 1

Sin desbordamiento negativo Con desbordamiento negativo

El desbordamiento negativo hace ‘0’ al bit de signo de la suma S, opuesto a los bits de signo
de los sumandos A y B. En el caso de rango SIGNED (7 downto 0) puede expresarse:

Condición de desbordamiento negativo: A(7) AND B(7) AND NOT S(7)

No hay otras condiciones de desbordamiento en sumas, porque si los sumandos tienen signo
diferente nunca puede haber desbordamiento por la limitación de representar sumandos con
valores que superen los máximos positivos o negativos “en complemento a 2”.

Si solo importa saber si hay desbordamiento, como aviso de sumas incorrectas, +128
o -129 en los ejemplos anteriores, la condición completa de desbordamiento es:

(NOT A(7) AND NOT B(7) AND S(7)) OR (A(7) AND B(7) AND NOT S(7))

VIII - 10
8 – Introducción a los modelos aritméticos

Para el caso de restas, consideradas como sumas de un número y el negativo de otro,


se pueden hallar las condiciones de desbordamiento de forma similar a lo visto con sumas,
al ver los bits de signo de operandos y resultados. Veamos unos ejemplos:

A -34 1 1 0 1 1 1 1 0 A -34 1 1 0 1 1 1 1 0
B +94 0 1 0 1 1 1 1 0 B +95 0 1 0 1 1 1 1 1
R -128 1 0 0 0 0 0 0 0 R -129 0 1 1 1 1 1 1 1

Sin desbordamiento negativo Con desbordamiento negativo

Si se considera que el sustraendo cambia su bit de signo al sumarlo al minuendo como


número negativo, en los ejemplos anteriores A y –B tienen signo -, o ‘1’, mientras que el
resultado R de la resta es ‘0’, el contrario del esperado, indicando un desbordamiento
negativo, expresable para el rango (7 downto 0) como:

Condición de desbordamiento negativo: A(7) AND NOT B(7) AND NOT S(7)

Para los desbordamientos positivos en restas, ocurre lo contrario con los bits de signo:
A +58 0 0 1 1 1 0 1 0 A +58 0 0 1 1 1 0 1 0
B -69 1 0 1 1 1 0 1 1 B -70 1 0 1 1 1 0 1 0
R +127 0 1 1 1 1 1 1 1 R +128 1 0 0 0 0 0 0 0

Sin desbordamiento positivo Con desbordamiento positivo

al rebasar el máximo número positivo representable, el bit de signo de la resta R resultante


pasa a ser el contrario del esperado, indicando que el resultado de la resta es incorrecto y,
para el rango (7 downto 0), la condición de desbordamiento positivo es expresable como:

Condición de desbordamiento positivo: NOT A(7) AND B(7) AND S(7)

La condición general de desbordamiento en restas (7 downto 0), se haría con:

Desbordamiento <= (A(7) AND NOT B(7) AND NOT S(7)) OR (NOT A(7) AND B(7) AND S(7));

De forma similar a lo indicado para las sumas, no hay otros casos de desbordamientos
en las operaciones de resta, ya que si los bits de signo de minuendo y sustraendo negado son
diferentes, sería imposible tener desbordamientos por la limitación de representar operandos
superiores a los límites de desbordamiento.

Dado que las condiciones de desbordamiento se expresan con referencia a los bits de
signo de operandos y resultados, podría utilizarse una constante genérica N que debería
declararse para el rango (N downto 0) utilizado en los modelos. De esa forma, las
condiciones de desbordamiento serían expresiones genéricas que se autodefinirían al dar
valor al genérico N.

En el ejemplo siguiente de un “sumador_restador_SIGNED”, se presentan todas las


condiciones vistas anteriormente para estas operaciones aritméticas:

VIII- 11
8 – Introducción a los modelos aritméticos

LIBRARY IEEE;
USE IEEE.STD_LOGIC_1164.ALL;
USE IEEE.STD_LOGIC_ARITH.ALL;

ENTITY sumador_restador_SIGNED IS
port ( A, B : IN signed(7 downto 0);
modo : IN std_logic;
s : OUT signed(7 downto 0);
ovf : OUT std_logic;
unf : OUT std_logic);
END sumador_restador_SIGNED;

ARCHITECTURE integral of sumador_restador_SIGNED IS


signal s_tmp: signed(7 downto 0);
BEGIN
s_tmp <= (A + B) when modo = '0' else
(A - B);
s <= s_tmp(7 downto 0);
WITH modo SELECT
ovf <= (not A(7) and not B(7) and s_tmp(7)) when '0',
(not A(7) and B(7) and s_tmp(7)) when '1',
'0' when others;
WITH modo SELECT
unf <= (A(7) and B(7) and not s_tmp(7)) when '0',
(A(7) and not B(7) and not s_tmp(7)) when '1',
'0' when others;
END integral;

Dado que, supuestamente, es más fácil interpretar un número positivo o negativo en


base decimal que un binario codificado en “complemento a 2”, para observar más
fácilmente el comportamiento de este ejemplo y de todos aquellos modelos que utilicen
valores SIGNED, las simulaciones correspondientes deberían hacerse con herramientas CAD
que soporten el tipo de representación o base numérica -radix, en inglés- normalmente
etiquetada como SIGNED DECIMAL.

VIII - 12
8 – Introducción a los modelos aritméticos

Simulación post-síntesis del modelo sumador_restador_signed, con base SIGNED DECIMAL en señales A, B y S
(Herramienta Quartus II de ALTERA)

Nótense los valores incorrectos de la salida S en aquellos intervalos en los que ovf = ‘1’ o unf = ‘1’

VIII- 13
Apéndice A

Síntesis y simulación de modelos VHDL con MAX+plus II


Desde sus comienzos a mediados de los 90’s, MAX+plus II fue una herramienta innovadora,
que integraba recursos para pasar del diseño a la ingeniería de productos basados en CPLDs y FPGAs.
Su capacidad para editar diseños VHDL o gráficos, simularlos en su propio entorno de “waveforms” y
configurar dispositivos con su “Programmer” y módulos externos de bajo costo, hacían de MAX+plus II
una herramienta diferente. Las familias FLEX10KE y ACEX, últimas soportadas en MAX+plus II,
sintetizaban diseños con millones de puertas equivalentes, pero las características de los nuevos
dispositivos de ALTERA requerían la implantación de Quartus II y la última versión de MAX+plus II se
publicó en Julio de 2003. ALTERA mantiene MAX+plus II como herramienta “legacy” para soporte de
diseños realizados con ella, y recomienda que para cualquier nuevo diseño se emplee Quartus II.

Las razones para utilizar MAX+plus II como herramienta de simulación de modelos VHDL en
nuestro entorno son, en primer lugar, la sencillez de su utilización; en segundo lugar, la potencia más
que suficiente para soportar los diseños de un curso de iniciación al VHDL y, finalmente, los detalles de
retardos observables en la simulación post-síntesis y la información que suministran sus “reports”
sobre los recursos de FPGAs utilizados en la síntesis para comparación de alternativas, porque en
simples medidas de la eficiencia de un diseño, lo primero a observar puede ser el tamaño o volumen
de recursos utilizados, es decir, el coste, y también, la velocidad relacionada de alguna forma con los
retardos. No está de más que, desde el principio, el usuario de VHDL sea consciente de tales
consideraciones fundamentales en la ingeniería.

Con la tecnologías han evolucionado tanto las herramientas CAD como el VHDL; por ejemplo, el
nuevo “1076.6 IEEE Standard for VHDL Register Transfer Level (RTL) Synthesis” fue publicado en 2004.
No es extraño que, dentro de la dispersión de recursos VHDL soportados por las herramientas de
síntesis, falten en MAX+plus II algunos incorporados desde hace poco las herramientas modernas,
aunque con variable aceptación por diseñadores que rechazan algunas inferencias de síntesis de las
nuevas sentencias o construcciones soportadas. En tales casos, siguiendo la recomendación de
ALTERA, es posible simular con Quartus II que, en honor a los valores de MAX+plus II, mantuvo hasta
su versión 9.1 una presentación en “modo MAX+plus II”. La versión Quartus II 9.1, con Service pack 2,
se puede descargar de forma gratuita de la web de ALTERA y su instalación no requiere licencia,
aunque precise más de 3GB en el HD. MAX+plus II solo pide 500 MB, lo que también es una razón
para elegirlo ante otras opciones de docencia del VHDL.

Síntesis y simulación de modelos VHDL con MAX+plus II 1/7


Instalación de MAX+ plus II desde CD versión 10.2

1º - Introducir CD y esperar pantalla inicial de instalación

2º - Elegir INSTALL FULL/CUSTOM/FLEXLM SERVER


Cargar usuario, company, etc.

3º - Elegir CUSTOM INSTALLATION


Si permite FULL se instalarán todas las opciones y ocupará casi 100 MB innecesarios

4º - INSTALAR opciones CUSTOM, marcando/desmarcando las casillas correspondientes


OPCIONES NECESARIAS SIEMPRE:
MAX+plus II, Graphic & Symbols Editor
Waveform Editor, Compiler, VHDL

DESMARCAR OPCIONES: (innecesaria ocupación de espacio en HD)


Verilog, Programmer, Sentinel driver
Dispositivos: ACEX 1K, ACEX 10K, FLEX 10KE, FLEX 6000, FLASH LOGIC

MARCAR OPCIONES:
Dispositivos: FLEX 8000, MAX3000, 7000 y 9000
TUTORIAL MAX+ plus II, MAX+ plus HELP

5º - Elegir disco del directorio de trabajo, p.ej. : C:\ max2work.

6º - Permitir folder ALTERA


Se iniciará el proceso de instalación de MAX+plus II que dura pocos minutos…
Al arrancar MAX+plus II por primera vez…
¡¡¡ No hacer caso del mensaje de “Subscription expired”!!!

7º - LICENSE SET UP
a - Preparar un directorio, p.ej. C:\flexlm, donde se instalará el fichero de licencia “license.dat”
b – Abrir el menú OPTIONS de la pantalla inicial de MAX+plus II y elegir “license set up”
Aparecerán las opciones que están como “unlicensed features”
c – Seleccionar el fichero de licencia “license.dat” que se había instalado, p.ej, en C:\flexlm
Todas las opciones se moverán a la ventana “licensed features”

8º - Crear un directorio “work”, por ejemplo D:\work o C:\work


Ese directorio work almacenará todos los resultados de compilación y simulación

En las páginas siguientes, vea un breve Tutorial sobre Síntesis y Simulación con MAX + plus II

2/7 Síntesis y simulación de modelos VHDL con MAX+plus II


1 – Abrir el fichero .vhd que se desea sintetizar. 3 –Iniciar la compilación del fichero
Aparecerá una ventana con fichero solicitado

2 – Dar al proyecto el nombre del fichero


(Es automático al picar en ese botón)

Síntesis y simulación VHDL en la aplicación


ALTERA MAX + plus II

Síntesis y simulación VHDL con MAX+plus II 3/7


Al compilar, aparecerán ventanas donde se muestran el avance de la compilación, una sucesión de mensajes y el resultado.

Si el proceso de análisis y síntesis es correcto aparecerá un mensaje informando de ello. “Aceptar” para continuar.

Si surgen errores, se podrán localizar y tener ayuda sobre ellos.

Como resultado, se generan una serie de ficheros en el directorio “work” donde, supuestamente, estaba el fichero xxx.vhd compilado.

Todos los ficheros tienen el mismo nombre que el .vhd, con extensiones codificadas que indican la información que contiene cada fichero.

El fichero xxx.rpt, por ejemplo, es un report o informe de cómo se ha sintetizado y encajado el diseño en un dispositivo EPM7032LC44-6.

El fichero xxx.snf , Simulator Netlist File, permitirá obtener datos para ver la simulación de las señales del diseño implementado en la FPGA.

Los ficheros xxx.pof y xxx.sof son ficheros para programar o configurar dispositivos directamente desde el entorno MAX+plus II

Para simular es preciso crear un fichero de estímulos, a partir del fichero xxx.snf, haciendo lo siguiente:

Síntesis y simulación VHDL con MAX+plus II 4/7


1º Abrir un Waveform editor, picando en la línea con ese nombre del menú Max+ plus II desplegable.

2º Pedir en el menú Node la opción “Enter nodes from SNF” y en la ventana emergente pedir el Tipo de señales de interés
3º En la ventana “Enter Nodes from SNF” que aparece, picar en List para que se muestren señales a visualizar en el “Waveform editor”
4º Seleccionar las señales de interés y pasarlas a la ventana derecha, picando en el botón de transferencia =>

Después de hacer la selección y dar OK, las señales a simular aparecen en el “Waveform editor”.
Síntesis y simulación VHDL con MAX+plus II 5/7
5º En el menú “File”, picar en “Save as”. Aceptar el nombre del fichero propuesto: xxx.scf (Simulator Chanel File)

Para realizar la simulación se deben definir los estímulos de todas las señales de entrada y los detalles de la simulación, por ejemplo:

a- En el menú “File” seleccionar “End time” para fijar el tiempo


de la simulación, por ejemplo, 100 us, 10 ms ...
b- En el menú “Options”, fijar el tamaño de la rejilla del eje de
tiempos, por ejemplo, 10 us. Serán los intervalos mínimos.
c- Podrá verse todo el tiempo de test con el expansor
d- Con los botones que aparecen a la izquierda de la pantalla,
seleccionar la forma de onda que se desee para cada señal
de entrada. Véanse las posibilidades que ofrecen los siete
botones inferiores, tanto para señales de grupo como para
señales aisladas.
e- Cualquier señal podrá cambiarse en intervalos a otros valores
distintos de los obtenidos con los controles
f- Si hace “doble-click” en la columna “Value”, podrá cambiar la
base con la que se despliega la señal: binary, hexa, decimal…

Síntesis y simulación VHDL con MAX+plus II 6/7


Cuando se hayan fijado las formas de onda de las entradas, se podrá simular y ver cómo responden las salidas del circuito sintetizado en la FPGA.

6º Para simular, picar el botón del simulador y esperar la finalización del proceso, leer los mensajes del simulador y ver los resultados.

Manejando botones de zoom, deslizadores de pantalla, moviendo las transiciones de estímulos a los puntos que desee o colocando el cursor en las
zonas de interés, etc. se podrán analizar en detalle las respuestas del circuito, modificar los estímulos para repetir la simulación y, si procede, cambiar el
diseño para que las respuestas sean las esperadas, porque NO OLVIDE QUE…

Sintetizar no es sinónimo de haber diseñado/descrito correctamente: puede indicar solo que la sintaxis VHDL era correcta

Simular y ver formas de onda no supone que el funcionamiento sea el esperado o deseado: solo representa un comportamiento

HAY QUE ANALIZAR LAS RESPUESTAS A LOS ESTIMULOS Y, QUIZÁS, PENSAR EN POSIBLES CAMBIOS O MEJORAS

Y si todo le parece correcto, archive el fichero que ha obtenido para editarlo posteriormente. Quedará guardado en “work” y podrá abrirlo
directamente, si lo llama desde “Abrir fichero”.

Síntesis y simulación VHDL con MAX+plus II 7/7


Apéndice B
Síntesis y simulación de modelos VHDL con QUARTUS II
Ventajas de QUARTUS II sobre MAX+plus II:
1 - No requiere licencia de instalación
2 - Soporta casi todos los recursos VHDL del standard IEEE 1076.6- 2004
3 - Acepta “Third party EDA tools”, en el supuesto de que se dispone de licencia
(Los puntos 2 y 3 son, prácticamente, innecesarios en un curso de iniciación al VHDL)

Inconvenientes de QUARTUS II respecto a MAX+plus II:


1 - Requiere casi 7 veces más espacio en el disco duro
2 - Su utilización es algo más compleja y su interfaz de usuario más enmarañada
3 - La presentación de “Waveforms” es peor que la de MAX+plus II

1º Descargar la version Quartus II Web Edition v9.1 with Service Pack 2

Desde: https://www.altera.com/download/software/quartus-ii-we/9.1

- El fichero descargable 91sp2_quartus_free.exe ocupa 1.82 GB.


- La instalación reducida ( “custom”) ocupa, aproximadamente, 3GB en el HD.
- Según las características del PC, la instalación puede durar entre 5 y 20 minutos.

2º Instalar el ejecutable descargado:


- Elegir modo “custom”
- Dejar activadas las siguientes marcas:
Quartus II, MAX 3000 support, MAX 7000 support, MAX II y TUTORIAL

3º Activar la opción para presentación de QUARTUS II en modo MAX+plus II.

En las páginas que siguen se presenta un

TUTORIAL para Síntesis y simulación de modelos VHDL con QUARTUS II

Síntesis y simulación de modelos VHDL con QUARTUS II 1/15


1 - Cargar fichero a compilar 2 – Dar al proyecto el mismo
desde la carpeta WORK nombre que el fichero cargado

Síntesis y simulación de modelos VHDL con QUARTUS II 2/15


3 – Después de picar aparecerá la ventana de abrir proyecto o crearlo.

Si es un fichero nuevo marcar “Create Project” y pulsar OK

Síntesis y simulación de modelos VHDL con QUARTUS II 3/15


4 – Picar “NEXT” en las dos ventanas siguientes

5 – Picar “NO” en la ventana de selección de nuevo directorio

Síntesis y simulación de modelos VHDL con QUARTUS II 4/15


6 – Si el fichero seleccionado tiene ficheros de nivel jerárquico más
bajo, seleccionarlos y añadirlos al proyecto

Síntesis y simulación de modelos VHDL con QUARTUS II 5/15


7 – Seleccionar familia MAX 3000, por ejemplo. 8 – No se utilizará ninguna otra herramienta EDA.
Picar “NEXT” Picar “NEXT”

Síntesis y simulación de modelos VHDL con QUARTUS II 6/15


9 – Picar “Finish”
Se ha creado el proyecto “xxx.qpf” (Quartus Project File)
QUARTUS II está preparada para compilar

10 – Picar en el icono de “Compilar”

Síntesis y simulación de modelos VHDL con QUARTUS II 7/15


11 – Si no hay mensajes de error, aparecerán las
ventanas de mensajes indicándolo.

12 – Si hay mensajes de error, aparecerán en


la ventana de mensajes

13- Picar en “ACEPTAR”


El proyecto estará preparado para simular

Síntesis y simulación de modelos VHDL con QUARTUS II 8/15


14- Hay que crear la ventana de “Waveforms”. Para ello, desplegar el menú MAX+PLUS II y picar en Waveform Editor.
15- Cuando esté abierta la ventana “Waveform, seleccionar “Enter nodes from SNF”, del menú de “Node”

Síntesis y simulación de modelos VHDL con QUARTUS II 9/15


16 – Aparecerá la ventana “Insert node or bus”, para buscar con “Node finder” las señales creadas por el compilador.

17 – En la ventana “Node finder” hay que seleccionar con “Filter” el tipo de señales a poner en la ventana “Waveforms”

Por ejemplo, “inputs”, y después de esa selección, picar en botón “List” para que se muestre la lista de “inputs”

Síntesis y simulación de modelos VHDL con QUARTUS II 10/15


18 - Aparecerá la lista de “inputs” y deberán seleccionarse las que interesen y validar con el botón “>”.

Se transferirán a la ventana “Waveforms” al pulsar “OK” en la ventana de “Node finder”

… Y TAMBIÉN EN LA VENTANA “Insert Node or Bus” que seguirá pendiente de OK


Síntesis y simulación de modelos VHDL con QUARTUS II 11/15
19 – Repetir los pasos 18 y 19 para otros tipos de señales, por ejemplo, “outputs”, etc. que pueda tener el proyecto.

20 – Abrir el menú “File” y hacer “Save as…” para dar nombre al fichero de formas de onda “xxx.vwf”

21 – Cuando el fichero esté guardado, pulsar el botón “Arrancar simulador”.

22 – Si todo ha ido bien, aparecerán los mensajes correspondientes…


Síntesis y simulación de modelos VHDL con QUARTUS II 12/15
23 - …y se podrá pedir que la aplicación muestre los resultados de la simulación, picando 1º “Aceptar” y 2º “OPEN”

Síntesis y simulación de modelos VHDL con QUARTUS II 13/15


24 - Con “End time” , se podrá fijar el intervalo de simulación.
25 - Al seleccionar una señal, se activarán los controles que permiten fijar sus valores o formas de presentación.
26 - Con el menú “View” se pueden seleccionar otros controles de presentación

Síntesis y simulación de modelos VHDL con QUARTUS II 14/15


Controles de asignación de valor a señales

27 – Seleccionando una señal en su número identificador, en la ventana “Node properties” se podrá elegir la base de presentación
de la señal: binary, hex, Signed decimal, etc.

Síntesis y simulación de modelos VHDL con QUARTUS II 15/15


Apéndice C
Relación integral de modelos
El listado siguiente presenta los modelos descritos en los capítulos de esta publicación y la
herramienta de síntesis-simulación utilizada con cada uno. En el fichero Integral de modelos.zip,
además de los ficheros .vhd, se incluyen los ficheros para simulación con MAX+plusII, identificados con
la extensión .scf -Simulation Channel File- y los ficheros .qpf -Quartus Project File- necesarios para
compilar con Quartus II y simular con los ficheros .vwf de “waveforms”, igualmente incluidos.

modelos_UNO MAX+plus II Quartus II


and_2.vhd *
or_2.vhd *
modelos.vhd *
sumador_comp.vhd *
sumador_estructural.vhd *
sumador_funcional.vhd *
sumador_packg *
xr_2.vhd *

modelos_TRES
decoder_3a8_doble.vhd *
d_flip_flop.vhd *
generador_serie.vhd *
inv_triestado.vhd *
mux_cuatro_a_1.vhd *
process_selectivo.vhd *
sap_convertidor.vhd *
selector_doble.vhd *
modelos_CUATRO
case_decoder_3a8.vhd *
generador.vhd *
if_decoder.vhd *
if_multiplexer.vhd *
inf_and.vhd *
inf_and_latch.vhd *
inf_fpfp.vhd *
inf_fpfp_asinc.vhd *
inf_fpfp_sinc.vhd *
inf_latch_clear.vhd *
others_shift_register.vhd *
serial_shift_register.vhd *
modelos_CINCO
binario_a_entero.vhd *
decrm_func.vhd *
entero_a_binario.vhd *
func_incremento.vhd *
incrm_func.vhd *
triestados.vhd *
triestados_flujdats.vhd *

Apéndice C 1/2
modelos_SEIS
adder_4b.vhd *
bist_adder.vhd *
compbit.vhd *
compbit_dos.vhd *
decoder_3_a_8.vhd *
decoder_bist.vhd *
decoder_bist_plus.vhd *
inver.vhd *
lfsr.vhd *
lfsr_3.vhd *
lfsr_4.vhd *
lfsr_8.vhd *
lfsr_9.vhd *
lfsr_9_mvld.vhd *
lfsr_gen.vhd *
nand_2.vhd *
nand_3.vhd *
puertas.vhd *
puertas_plus.vhd *
xrf.vhd *
xrf_IEEE.vhd *
modelos_SIETE
compbit_funciones.vhd *
mealyfsm.vhd *
mealyfsm_trs.vhd *
mealyfsm_uno.vhd *
moorefsm.vhd *
moorefsm_trs.vhd *
moorefsm_uno.vhd *
mux_4a1_conc.vhd *
mux_4a1_cond.vhd *
mux_4a1_sel.vhd *
shift_reg_mix.vhd *
sumabin.vhd *
up_dwn_counter.vhd *
modelos_OCHO
add_sub_unsigned.vhd *
comparador_unsigned.vhd *
contador_signed.vhd *
contador_stdlogic.vhd *
contador_unsigned.vhd *
contador_unsigned_typecasted.vhd *
sumador_restador_signed.vhd * *
sumar_incrm.vhd *
suma_byte.vhd *
suma_incr.vhd *

2/2 Apéndice C
Bibliografía
ALTERA Corp. "MAX+PLUS II Getting started", Version 6.0, 2000

ALTERA Corp. "MAX+PLUS II - VHDL", Version 5.0, 1995

ALTERA Corp. "Introduction to QUARTUS II", Version 4.1, 2004

Ashenden, P. J., "The Designer's Guide to VHDL” , 3rd Edition, Elsevier, 2008

Ashenden, P. J., “Digital Design: An Embedded Systems Approach Using VHDL”, Elsevier, 2008

Chu, Pong P., “FPGA prototyping by VHDL examples”, Wiley Interscience, 2008

Chu, Pong P., “RTL hardware design using VHDL”, Wiley Interscience, 2006

Navabi, Z., “VHDL Analysis and Modeling of Digital Systems”, McGraw-Hill, 1993

Perry, D. L., “VHDL Programming by Example”, 4th Edition, McGraw-Hill, 2002

Rushton, A., “VHDL for Logic Synthesis”, 3rd Edition, Wiley, 2011

XILINX Inc. , "XST Xilinx Synthesis Technology", Ch. 3., 2009

Potrebbero piacerti anche