Вы находитесь на странице: 1из 176

UNIVERSIDAD NACIONAL DE EDUCACIÓN A DISTANCIA (UNED)

ESCUELA TÉCNICA SUPERIOR DE INGENIERÍA INFORMÁTICA

Casos prácticos de diseño


de circuitos digitales con VHDL

Texto de problemas de la asignatura


“Estructura y Tecnología de los Computadores III”
Curso 2007/08

Alfonso Urquía
Carla Martín Villalba
Departamento de Informática y Automática, UNED
Juan del Rosal 16, 28040 Madrid, España
{aurquia,carla}@dia.uned.es
http://www.euclides.dia.uned.es
Índice

1 Fundamentos 1
1.1. Lenguajes para la descripción de hardware . . . . . . . . . . . . . . 1
1.2. Ciclo de diseño de los circuitos digitales . . . . . . . . . . . . . . . 4
1.3. Propiedades de los circuitos digitales . . . . . . . . . . . . . . . . . 5
1.4. Simulación de eventos discretos . . . . . . . . . . . . . . . . . . . . 8
1.5. Test de los circuitos . . . . . . . . . . . . . . . . . . . . . . . . . . 12
1.6. Dos simuladores de VHDL’93: VeriBest y ModelSim . . . . . . . . 16

2 Conceptos básicos de VHDL 19


2.1. Definición de la entidad de diseño . . . . . . . . . . . . . . . . . . . 20
2.2. Entity . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 20
2.3. Architecture . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 21
2.3.1. Asignaciones concurrentes . . . . . . . . . . . . . . . . . . . 22
2.3.2. Bloque process . . . . . . . . . . . . . . . . . . . . . . . . . 23
2.3.3. Descripción de la estructura . . . . . . . . . . . . . . . . . . 24
2.3.4. Constantes generic . . . . . . . . . . . . . . . . . . . . . . . 28
2.4. Configuration . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 28
2.5. Señales, variables y constantes . . . . . . . . . . . . . . . . . . . . 28
2.5.1. Tipos de datos . . . . . . . . . . . . . . . . . . . . . . . . . 29
2.5.2. Atributos . . . . . . . . . . . . . . . . . . . . . . . . . . . . 34
2.5.3. Operadores . . . . . . . . . . . . . . . . . . . . . . . . . . . 35
2.6. Librerı́as . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 37
2.7. Modelado del retardo . . . . . . . . . . . . . . . . . . . . . . . . . . 38
2.7.1. Sentencia wait . . . . . . . . . . . . . . . . . . . . . . . . . 38
2.7.2. Retardos en la asignación a señales . . . . . . . . . . . . . . 39
2.7.3. Retardo inercial y de transporte . . . . . . . . . . . . . . . 39
2.7.4. Retardo delta . . . . . . . . . . . . . . . . . . . . . . . . . . 40
2.7.5. Caso práctico . . . . . . . . . . . . . . . . . . . . . . . . . . 41
2.8. Assert . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 43
2.9. Procedimientos y funciones . . . . . . . . . . . . . . . . . . . . . . 44
ii A. Urquı́a, C. Martı́n Villalba Casos Prácticos de Diseño de Circuitos Digitales con VHDL

3 Casos prácticos de diseño de circuitos combinacionales 47


3.1. Sı́ntesis de lógica combinacional . . . . . . . . . . . . . . . . . . . . 47
3.1.1. Empleo de sentencias concurrentes . . . . . . . . . . . . . . 48
3.1.2. Empleo de bloques process . . . . . . . . . . . . . . . . . . 50
3.2. Funciones lógicas . . . . . . . . . . . . . . . . . . . . . . . . . . . . 50
3.2.1. Modelado de las funciones lógicas . . . . . . . . . . . . . . . 50
3.2.2. Programación del banco de pruebas . . . . . . . . . . . . . 51
3.3. Multiplexor de 4 entradas . . . . . . . . . . . . . . . . . . . . . . . 54
3.3.1. Bloque process, sentencia if . . . . . . . . . . . . . . . . . . 55
3.3.2. Bloque process, sentencias if y case . . . . . . . . . . . . . . 57
3.3.3. Sentencias concurrentes . . . . . . . . . . . . . . . . . . . . 59
3.4. Restador completo de 1 bit . . . . . . . . . . . . . . . . . . . . . . 60
3.4.1. Descripción del comportamiento . . . . . . . . . . . . . . . 61
3.4.2. Descripción de la estructura . . . . . . . . . . . . . . . . . . 62
3.4.3. Programación del banco de pruebas . . . . . . . . . . . . . 65
3.4.4. Banco de pruebas usando un procedimiento . . . . . . . . . 68
3.4.5. Banco de pruebas usando una función . . . . . . . . . . . . 70
3.5. Sumador binario paralelo con propagación de arrastre . . . . . . . 71
3.5.1. Diseño de un sumador completo . . . . . . . . . . . . . . . 72
3.5.2. Banco de pruebas de sumador completo . . . . . . . . . . . 75
3.5.3. Diseño del sumador de 4 bits . . . . . . . . . . . . . . . . . 77
3.6. Bus bidireccional y memorias . . . . . . . . . . . . . . . . . . . . . 77
3.6.1. Memoria de sólo lectura . . . . . . . . . . . . . . . . . . . . 78
3.6.2. Memoria de lectura y escritura . . . . . . . . . . . . . . . . 79
3.6.3. Bus bidireccional . . . . . . . . . . . . . . . . . . . . . . . . 80
3.7. Unidad aritmético lógica (ALU) . . . . . . . . . . . . . . . . . . . . 82
3.7.1. Modelado mediante asignación concurrente . . . . . . . . . 83
3.7.2. Modelado mediante bloque process . . . . . . . . . . . . . . 84
3.7.3. Programación del banco de pruebas . . . . . . . . . . . . . 85
3.8. Conversor de BCD a binario . . . . . . . . . . . . . . . . . . . . . . 89
3.8.1. Circuito conversor . . . . . . . . . . . . . . . . . . . . . . . 90
3.8.2. Banco de pruebas . . . . . . . . . . . . . . . . . . . . . . . 91
3.9. Codificador 4:2 con prioridad . . . . . . . . . . . . . . . . . . . . . 93
3.9.1. Diseño del circuito . . . . . . . . . . . . . . . . . . . . . . . 93
3.9.2. Banco de pruebas . . . . . . . . . . . . . . . . . . . . . . . 94

4 Casos prácticos de diseño de circuitos secuenciales 99


4.1. Diseño de circuitos secuenciales sı́ncronos . . . . . . . . . . . . . . 99
4.1.1. Circuito detector de secuencias . . . . . . . . . . . . . . . . 100
4.2. Sı́ntesis de lógica secuencial . . . . . . . . . . . . . . . . . . . . . . 102
4.2.1. Sentencias condicionales incompletas . . . . . . . . . . . . . 102
4.2.2. Sentencias condicionales completas . . . . . . . . . . . . . . 103
4.2.3. Retardos . . . . . . . . . . . . . . . . . . . . . . . . . . . . 103
4.2.4. Inicialización . . . . . . . . . . . . . . . . . . . . . . . . . . 103
4.2.5. Bloques process . . . . . . . . . . . . . . . . . . . . . . . . . 104
Índice iii

4.3. Flip-flop JK . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 105


4.3.1. Diseño del flip-flop . . . . . . . . . . . . . . . . . . . . . . . 105
4.3.2. Banco de pruebas . . . . . . . . . . . . . . . . . . . . . . . 106
4.4. Máquinas de estado finito de Moore . . . . . . . . . . . . . . . . . 109
4.4.1. Diseño de la máquina . . . . . . . . . . . . . . . . . . . . . 110
4.4.2. Banco de pruebas . . . . . . . . . . . . . . . . . . . . . . . 113
4.4.3. Modelado estructural . . . . . . . . . . . . . . . . . . . . . 117
4.5. Máquinas de estado finito de Mealy . . . . . . . . . . . . . . . . . . 119
4.5.1. Diseño de la máquina . . . . . . . . . . . . . . . . . . . . . 119
4.5.2. Banco de pruebas . . . . . . . . . . . . . . . . . . . . . . . 126
4.6. Descripción VHDL de alto nivel . . . . . . . . . . . . . . . . . . . . 130
4.6.1. Circuito detector de secuencia . . . . . . . . . . . . . . . . . 130

APÉNDICES 133
A VeriBest VB99.0 133
A.1. Instalación . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 133
A.2. Circuito digital ejemplo: buffer triestado . . . . . . . . . . . . . . . 134
A.2.1. Modelo VHDL del buffer triestado . . . . . . . . . . . . . . 134
A.2.2. Banco de pruebas . . . . . . . . . . . . . . . . . . . . . . . 135
A.3. Edición y compilación de un modelo . . . . . . . . . . . . . . . . . 136
A.3.1. Arranque del simulador VeriBest VHDL . . . . . . . . . . . 136
A.3.2. Creación de un espacio de trabajo . . . . . . . . . . . . . . 136
A.3.3. Edición de un fichero . . . . . . . . . . . . . . . . . . . . . . 137
A.3.4. Añadir un fichero al espacio de trabajo . . . . . . . . . . . . 137
A.3.5. Compilación de un fichero . . . . . . . . . . . . . . . . . . . 138
A.3.6. Banco de pruebas . . . . . . . . . . . . . . . . . . . . . . . 140
A.4. Simulación y visualización de los resultados . . . . . . . . . . . . . 140
A.4.1. Establecer las condiciones de la simulación . . . . . . . . . 140
A.4.2. Activación del simulador . . . . . . . . . . . . . . . . . . . . 141
A.4.3. Simulación y visualización de resultados . . . . . . . . . . . 142
A.5. Depurado usando el debugger . . . . . . . . . . . . . . . . . . . . . 144

B ModelSim PE Student Edition 147


B.1. Instalación . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 147
B.2. Circuito digital ejemplo: buffer triestado . . . . . . . . . . . . . . . 148
B.2.1. Modelo VHDL del buffer triestado . . . . . . . . . . . . . . 148
B.2.2. Banco de pruebas . . . . . . . . . . . . . . . . . . . . . . . 149
B.3. Edición y compilación de un modelo . . . . . . . . . . . . . . . . . 150
B.3.1. Arranque del simulador . . . . . . . . . . . . . . . . . . . . 150
B.3.2. Creación de un proyecto . . . . . . . . . . . . . . . . . . . . 151
B.3.3. Añadir ficheros al proyecto . . . . . . . . . . . . . . . . . . 152
B.3.4. Compilación de un fichero . . . . . . . . . . . . . . . . . . . 156
B.3.5. Banco de pruebas . . . . . . . . . . . . . . . . . . . . . . . 157
B.4. Simulación y visualización de los resultados . . . . . . . . . . . . . 160
iv A. Urquı́a, C. Martı́n Villalba Casos Prácticos de Diseño de Circuitos Digitales con VHDL

B.4.1. Activación del modo simulación . . . . . . . . . . . . . . . . 160


B.4.2. Visualización de los resultados . . . . . . . . . . . . . . . . 161
B.4.3. Ejecución de la simulación . . . . . . . . . . . . . . . . . . . 162
B.4.4. Inserción de puntos de ruptura . . . . . . . . . . . . . . . . 163

Índice alfabético 167

Bibliografía 169
Fundamentos
1

Objetivos. Una vez estudiado el contenido del tema, deberı́a saber:


– Discutir la finalidad de los lenguajes para la descripción del hardware (HDL) y
algunas de las principales ventajas que presenta su uso.
– Discutir el ciclo de diseño del hardware digital y el papel que desempeñan en
el ciclo de diseño los HDL.
– Discutir los conceptos fundamentales de la simulación de eventos discretos,
en particular la gestión del reloj de la simulación y del calendario de eventos.
– Realizar, con “lápiz y papel”, la simulación de eventos discretos de circuitos
digitales, tal como se muestra en el Caso Práctico de la Sección 1.4.
– Discutir las siguientes propiedades de los circuitos digitales: el retardo de los
dispositivos, su ejecución concurrente, la marginalidad en el diseño y la fortaleza
de las señales.
– Discutir qué son los árboles de buffers y cuál es su finalidad.
– Discutir el propósito y los fundamentos del test en diseño y manufactura, ası́
como los conceptos: modelo de fallos, cobertura del test y calidad del test.
– Discutir la utilidad y composición de los bancos de pruebas.
– Instalar en su propio ordenador y realizar las operaciones básicas de manejo de
algún entorno de simulación de VHDL’93, tal como ModelSim (preferible) o
VeriBest. Estas operaciones básicas incluyen al menos: edición de modelos
y depurado usando el debugger, simulación y visualización de los resultados.

1.1 Lenguajes para la descripción de hardware


Los sistemas digitales se han ido haciendo más y más complejos durante las
pasadas décadas. Este incremento en la complejidad responde, a grandes rasgos,
a la Ley de Moore, que establece que el avance tecnológico posibilita que cada
aproximadamente 18 meses se doble el número de transistores que es posible alojar
en un circuito integrado.
2 A. Urquı́a, C. Martı́n Villalba Casos Prácticos de Diseño de Circuitos Digitales con VHDL

De esta forma, en la década de 1970 un circuito integrado tı́pico contenı́a


decenas de miles de transistores. En la década de 1980, la capacidad aumentó a
cientos de miles de transistores, y en la década de 1990 fue del orden de decenas
de millones. En la década de 2000, la capacidad de los circuitos integrados es del
orden de miles de millones de transistores.
En los años 70, cuando se fabricaba un circuito integrado, se documentaba
su funcionamiento empleando una combinación de esquemáticos (representación
gráfica de los componentes del circuito), diagramas de transición de estados y
lenguaje natural (por ejemplo, inglés). Esta documentación podı́a consistir en
varios cientos de páginas. Los ingenieros, que compraban el circuito integrado para
usarlo en sus propios diseños, tenı́an que leer esta documentación para entender
el funcionamiento del circuito integrado. Sin embargo, leer cientos de páginas
no era tarea fácil. Además, en ocasiones la documentación contenı́a errores o
ambigüedades. La consecuencia de ello era que frecuentemente los ingenieros
tenı́an problemas para emplear los circuitos integrados en el desarrollo de sus
propios sistemas.
Debido a esta situación, el Departamento de Defensa de EE.UU. buscó un
procedimiento mediante el cual los fabricantes de circuitos integrados pudieran es-
pecificar de forma precisa el funcionamiento de los circuitos. Con esta motivación,
el Departamento de Defensa de EE.UU. inició el desarrollo de un lenguaje para la
descripción del hardware, para lo cual estableció un grupo de trabajo compuesto
por expertos de varias disciplinas, pertenecientes a diferentes compañı́as.
Un lenguaje para la descripción del hardware o HDL (siglas que provienen
del inglés: Hardware Description Language) es un lenguaje, legible tanto por
las máquinas como por los seres humanos, ideado para permitir la descripción
del hardware. Un HDL describe de forma precisa y rigurosa el funcionamiento,
pudiendo ser simulado en un ordenador con el fin de reproducir exactamente el
funcionamiento del circuito integrado. La simulación por ordenador permite ob-
tener el valor de las señales de salida del circuito integrado para una determinada
secuencia de señales de entrada.
El HDL que el Departamento de Defensa de EE.UU. creó en los años 80
se llamó VHDL. Las siglas VHDL provienen de VHSIC Hardware Description
Language. VHSIC es un acrónimo de Very High Speed Integrated Circuit, que
fue el nombre del proyecto llevado a cabo por el Departamento de Defensa de
EE.UU.
La sintaxis de VHDL es muy similar a la del lenguaje de programación ADA.
En 1987, el Institute of Electrical and Electronics Engineers (IEEE) adoptó VHDL
como el estándar número 1076. El establecimiento de un estándar del lenguaje
tiene una ventaja fundamental: las compañı́as desarrolladoras de software de
simulación tienen una definición claramente establecida del lenguaje al que deben
dar soporte.
Capı́tulo 1 Fundamentos 3

Ventajas de los HDL


En la actualidad, la casi totalidad de los diseñadores de circuitos digitales de cierta
complejidad usan para realizar sus diseños lenguajes para la descripción del hard-
ware. El empleo de HDL presenta ventajas respecto al empleo de descripciones
basadas en esquemáticos. Algunas de ellas son las siguientes:

1. Puesto que una descripción HDL es simplemente un fichero de texto, es


mucho más portable que un diseño esquemático, que debe ser visualizado
y editado empleando la herramienta gráfica especı́fica del entorno de CAD
(Computer-Aided Design - Diseño asistido por ordenador) con el que se ha
creado.

2. Una descripción esquemática únicamente describe el diseño de manera es-


tructural, mostrando los módulos y la conexión entre ellos. Por el contrario,
la descripción del circuito usando un HDL puede realizarse bien mostrando
la estructura, o bien describiendo el comportamiento. Es decir, los HDL
permiten describir el comportamiento que se desea que tenga el circuito,
sin hacer ninguna referencia a su estructura. Las herramientas de sı́ntesis
permiten generar automáticamente la estructura del circuito lógico a partir
de la descripción de su comportamiento.

3. El mismo HDL que se ha usado para la descripción del circuito, puede


emplearse para describir los vectores de test y los resultados esperados
del test. Los vectores de test son los valores de las señales aplicadas a los
pines de entrada del circuito con la finalidad de probar si el funcionamiento
del circuito es correcto. Ası́ pues, pueden realizarse los programas de test
(vectores de test e instantes en los cuales son aplicados) del circuito a medida
que se diseña el propio circuito, pudiéndose con ello ir realizando diferentes
pruebas a medida que se avanza en el diseño. Como ventajas añadidas, la
descripción de los programas de test usando HDL es altamente portable y
repetible.

HDL más ampliamente usados


En la actualidad, los HDL más ampliamente usados son Verilog HDL y VHDL.
Ambos son lenguajes estándar de IEEE para el modelado y simulación de hard-
ware.

– Verilog se creó, a principios de los años 80, como un lenguaje propiedad de


la compañı́a Philip Moorby, compañı́a que años más tarde fue adquirida por
Cadence Design Systems. Posteriormente, Verilog se hizo de dominio públi-
co y se promovió como un estándar de IEEE en el año 1995, denominado
IEEE 1364.

– Como se ha explicado anteriormente, VHDL fue desarrollado en 1983


por el Departamento de Defensa de los EE.UU. con la finalidad de servir
como lenguaje estándar para la descripción de hardware. En el año 1987
4 A. Urquı́a, C. Martı́n Villalba Casos Prácticos de Diseño de Circuitos Digitales con VHDL

se convirtió en un estándar de IEEE (IEEE 1067-1987). Posteriormente, se


incorporaron mejoras al lenguaje que dieron lugar a dos actualizaciones del
estándar: la primera en 1993 (IEEE 1076-1993) y la segunda en 2001 (IEEE
1076-2001).

A principios del año 2000 se desarrolló otro HDL denominado SystemC, el


cual consiste en un conjunto de librerı́as en C++. SystemC se convirtió en el
estándar 1666 de IEEE en el año 2005.

1.2 Ciclo de diseño de los circuitos digitales


El empleo de HDL es práctica habitual en las diferentes fases del ciclo de diseño
de circuitos digitales. En la Figura 1.1 se muestra el ciclo de actividades que
se realizan durante el ciclo de diseño e implementación de circuitos digitales de
relativa complejidad.
En primer lugar, el diseñador debe establecer las especificaciones del diseño, en
términos de qué se espera que haga el circuito y qué restricciones debe satisfacer
(frecuencia de reloj, retardos, tamaño, etc.).
A continuación, el diseñador debe crear un diseño de alto nivel del circuito,
para lo cual puede emplear un lenguaje para la descripción de hardware (HDL),
por ejemplo VHDL o Verilog. Seguidamente, debe desarrollar un conjunto de
programas de test (usando también VHDL o Verilog) y, si es posible, usar estos
programas para testear el diseño de alto nivel, usando para ello una herramienta
de simulación (verificación funcional). En función de los resultados de la simula-
ción de los tests, puede ser preciso modificar el diseño de alto nivel, repitiéndose
los pasos anteriores tantas veces como sea preciso.
Una vez el diseño de alto nivel funciona adecuadamente, debe traducirse al
nivel de puertas lógicas o de transistores. Este proceso se denomina sı́ntesis. Sı́n-
tesis es la generación automática del diseño del circuito a partir de la descripción
de su comportamiento. El resultado obtenido de la sı́ntesis, denominado netlist,
es una descripción de todas las conexiones y componentes que deben componer
el circuito.
La descripción a nivel de puertas o transistores obtenida a partir de una
descripción en HDL puede diferir significativamente, dependiendo de la forma en
que se ha programado el modelo en HDL y de la herramienta de sı́ntesis empleada.
Las herramientas de sı́ntesis proporcionan numerosas opciones que permiten al
diseñador especificar cómo debe realizarse. En particular, permiten especificar el
nivel de esfuerzo a emplear por la herramienta en la optimización automática del
circuito, tanto en lo que respecta a la reducción del área del circuito como en lo
que respecta a sus prestaciones. Asimismo, las herramientas de sı́ntesis permiten
especificar qué módulos del circuito no deben ser optimizados.
El diseño a nivel de puertas o transistores debe ser vuelto a testear mediante
simulación (verificación de tiempos), usando, si es posible, el mismo conjunto
de tests que se realizaron sobre el diseño de alto nivel. El objetivo es estudiar
si el diseño se comporta como debe y si satisface todas las restricciones que se
Capı́tulo 1 Fundamentos 5

         
   

  
       

       
   

                       

                   

               
      

             !   " !   #$

   
     

Figura 1.1: Ciclo de diseño del hardware digital.

impusieron en la fase de especificación. Si se detecta un problema a este nivel,


debe volverse al correspondiente paso del ciclo de diseño.
Una vez el diseño ha superado estos tests, puede implementarse usando PLD
(Programmable Logic Device), FPGA (Field-Programmable Gate Array), ASIC
(Application-Specific Integrated Circuit), etc. Se emplean herramientas software
para fabricar (en el caso de los ASIC) o programar (en el caso de los FPGA) el
circuito integrado a partir de la netlist.
Una vez implementado, el circuito integrado puede ser testado con ayuda de
un generador de patrones (para generar los vectores de test) y un analizador
lógico u osciloscopio (para medir las salidas).

1.3 Propiedades de los circuitos digitales


Los circuitos digitales reales tienen algunas caracterı́sticas importantes que afec-
tan a la manera en que deben ser modelados y diseñados. Estas caracterı́sticas
son debidas tanto a los transistores que componen las puertas lógicas como a las
conexiones entre ellos. Entre las más importantes están las siguientes.
6 A. Urquı́a, C. Martı́n Villalba Casos Prácticos de Diseño de Circuitos Digitales con VHDL

Retardo de los dispositivos


En los sistemas fı́sicos suelen considerarse dos tipos de retardos: el retardo
inercial y el retardo puro o de transporte. Se va a emplear un motor eléctrico
como ejemplo para ilustrar la diferencia entre ambos tipos de retardo.
Cuando se enciende el motor, éste empieza a girar y su velocidad aumenta
hasta que alcanza la velocidad final. Este proceso puede llevar varios segundos,
siendo debido principalmente este retardo a la inercia del rotor del motor. Si se
apaga el motor antes de que éste alcance la velocidad final, la velocidad del motor
disminuye inmediatamente. Esto no sucederı́a en el caso de un retardo puro.
Como ejemplo de retardo puro, consideremos que el motor está en una nave
espacial rumbo a Júpiter. Los comandos para encender y apagar el motor se envı́an
desde la tierra y tardan 10 minutos en llegar a la nave. Supongamos que se envı́a
un comando para encender el motor y pasados dos minutos se envı́a otro comando
para apagarlo. El comando para apagar el motor llegarı́a 2 minutos después que el
comando para encenderlo, causando que el motor estuviese encendido durante dos
minutos. La señal recibida es exactamente igual que la enviada pero desplazada
10 minutos en el tiempo. Los retardos puros pueden representarse por simples
desplazamientos en el tiempo de la señal, ya que la señal en sı́ misma no se
modifica.
El retardo inercial es adecuado para modelar los retardos a través de dispo-
sitivos tales como los transistores y las puertas lógicas. Un cambio en la entrada
de un dispositivo se ha de mantener estable durante cierto tiempo para que este
valor se propague a su salida. Las puertas actúan ası́ como filtros paso baja.
Consideremos un inversor con un retardo de 2 ns. El inversor necesita que la
entrada se mantenga estable durante al menos 2 ns para que se produzca un
cambio en su salida. Por tanto, un pulso de 1 ns de duración no provoca cambios
en su salida, pero si los provoca un pulso de 5 ns. Si la primera transición del pulso
se recibe en el instante 100 ns, la respuesta de la puerta comienza a transmitirse
en el instante 102 ns. Por otro lado, el retardo de transporte (o puro) es adecuado
para modelar retardos a través de dispositivos con poca inercia, tales como las
lı́neas de metal construidas en el chip para conectar los dispositivos.

Ejecución concurrente
Los módulos lógicos se ejecutan concurrentemente. Cuando cambia el valor de
una señal de entrada a varios módulos, todos estos módulos deben ser ejecutados
concurrentemente. Ası́ pues, los HDL deben ser capaces de describir de manera
precisa este comportamiento concurrente y el simulador debe ser capaz de si-
mularlo. La metodologı́a aplicada para ello por el simulador es la simulación de
eventos discretos.

Diseños marginales
Los retardos de los dispositivos dependen de la condiciones de fabricación del chip.
En general, existen variaciones en el valor de los retardos de los chips fabricados
Capı́tulo 1 Fundamentos 7

en diferentes obleas, e incluso existen variaciones entre los chips fabricados en


posiciones distantes dentro de una misma oblea.
Por este motivo, no es buena idea diseñar un circuito cuyo funcionamiento
dependa de que los retardos tomen un determinado valor o que su magnitud
sea mı́nima. Este tipo de circuitos puede funcionar correctamente cuando son
simulados, ya que las señales simuladas llegan a los módulos en un determinado
orden, que viene determinado por los valores de los retardos contenidos en el
modelo. Sin embargo, si el orden de llegada de los cambios en las señales depende
del valor de los retardos, y los retardos simulados no se corresponden con los
existentes en el diseño fı́sico, entonces ese diseño producirá chips que no funcionen,
o que funcionen sólo una parte del tiempo.

Fortaleza de las señales


Las señales de los circuitos digitales reales poseen una determinada “fortaleza”,
que determina en qué medida las transiciones en el valor de la señal son abruptas
(y, por tanto, los retardos debidos a esa señal), y el número y tipo de entradas a
módulos que pueden ser conectados a esa señal.
Esta caracterı́stica de las señales, que puede ser modelada en VHDL y en
Verilog, viene determinada por los niveles de tensión del ‘0’ y del ‘1’ lógicos (por
ejemplo, para un ‘1’ lógico, en qué medida está el voltaje de la señal próximo al
voltaje de la alimentación), y por la cantidad de corriente que puede proporcionar
y aceptar el dispositivo que genera la señal.
En un circuito digital tı́pico, la transferencia de un valor lógico desde un pin
de salida de un módulo, a varios pines de entrada de otros módulos, precisa de la
transferencia de carga eléctrica hacia los pines de entrada (en el caso de ‘1’ lógico)
o hacia el pin de salida (en el caso de ‘0’ lógico). El pin de salida debe tener la
capacidad de hacer de “fuente” y de “sumidero” de toda la corriente necesaria.
Desde el punto de vista práctico, esto implica que la salida de un módulo
puede ser conectada como máximo a un determinado número de entradas de
otros módulos. En aquellos casos en que la señal deba conectarse a un número
de módulos superior a este número máximo, entonces debe emplearse un árbol de
buffers. En la Figura 1.2 se muestra un árbol de buffers que lleva una señal (out)
a 16 módulos (in 0, ..., in 15), de tal forma que la salida de los buffers se conecta
únicamente a 4 entradas.
El uso del árbol de buffers tiene un beneficio añadido: igualar los retardos
de las señales de entrada a todos los módulos, ya que el árbol de buffers está
diseñado de modo que la longitud de las lı́neas de todas sus ramas sea la misma.
Este tipo de árbol de buffers se emplea para llevar la señal de reloj a los flip-flops
en los circuitos secuenciales sı́ncronos, en los cuales es importante que la señal de
reloj llegue a todos los flip-flops aproximadamente en el mismo instante.
8 A. Urquı́a, C. Martı́n Villalba Casos Prácticos de Diseño de Circuitos Digitales con VHDL

Figura 1.2: Árbol de buffers para llevar una señal a 16 módulos.

1.4 Simulación de eventos discretos


A la hora de escribir código en cualquier lenguaje para la descripción de hardware,
resulta útil saber de qué manera se realizará la simulación de ese código. La
mayorı́a de las herramientas de simulación de HDL emplean una metodologı́a
denominada simulación de eventos discretos. En la simulación de eventos discretos
se lleva una lista global de eventos ordenados en el tiempo, que se denomina
calendario de eventos. Los eventos se representan en el calendario de eventos por
el siguiente par de valores: nuevo valor de la señal e instante de tiempo en que
está planificado que se realice esta asignación. Los eventos están ordenados de
menor a mayor instante de ejecución en el calendario.
A continuación se describe el algoritmo de la simulación, que consta de los
siguientes pasos:

Paso 1. En el instante de inicio de la simulación, se activa el evento “Inicio de


la Simulación”. Como parte de las acciones asociadas a la ejecución de este
evento, se pone el reloj de la simulación a cero y se registran los nuevos
eventos en el calendario de eventos.

Paso 2. Se extrae el primer evento del calendario.

Paso 3. Se actualiza el reloj de la simulación al instante de ejecución del evento.


Capı́tulo 1 Fundamentos 9

Paso 4. Se ejecuta el evento y, si procede, se actualiza el calendario de eventos.

Paso 5. Se comprueba si existen más eventos en el calendario de eventos. Si


existen más eventos se vuelve al paso 1. En caso contrario, se avanza al
paso 6.

Paso 6. Fin de la simulación.

El anterior algoritmo de la simulación no describe cómo se actualiza el ca-


lendario de eventos. Los pasos a seguir para actualizar el calendario de eventos
dependen del tipo de retardo del evento. Por defecto, se considera que los dispo-
sitivos tienen retardo inercial. El tratamiento de un evento sin retardo sobre una
señal se reduce al caso de un evento con retardo (ya sea inercial o de trasporte)
haciendo el valor del retardo cero.
A continuación se describen los pasos a seguir para actualizar el calendario
de eventos cuando en el nuevo evento sobre la señal existe un retardo inercial.
Vamos a considerar que la señal sobre la que se produce el evento se denomina A,
el nuevo valor de la señal es Anew , el valor del retardo inercial es ret y el instante
actual de simulación es tactual . Para actualizar el calendario de eventos hay que
seguir los siguientes pasos:

1. Se borran aquellos eventos sobre A cuyo instante de ejecución sea igual o


mayor que tactual + ret.

2. Se insertan los nuevos eventos en el calendario de eventos.

3. Todos los antiguos eventos sobre A cuya ejecución esté planificada que suce-
da en un instante de tiempo comprendido en el intervalo (tactual , tactual + ret)
y asignen a A un valor diferente de Anew se borran.

Si el evento sobre la señal A tuviese retardo de transporte (que denominamos


rettransp ) en lugar de un retardo inercial habrı́a que dar los siguientes pasos para
actualizar el calendario de eventos:

1. Se borran todos los eventos sobre A existentes en el calendario de eventos


cuyo instante de ejecución sea igual o mayor tactual + rettransp .

2. Se insertan los nuevos eventos en el calendario de eventos.

Caso práctico
Supongamos que se ha descrito el circuito mostrado en la Figura 1.3 usando un
HDL. La puerta NAND tiene un retardo de 1 ns y la puerta OR de 2 ns. Las
dos entradas, x1 y x2 , tienen el valor ‘1’ en el instante 0 ns. Las dos siguientes
asignaciones describen, respectivamente, el comportamiento de la salida de la
puerta NAND (s) y de la puerta OR (y) del circuito digital:

s ← x1 nand x2 con retraso 1 ns (1.1)


y ← s or x2 con retraso 2 ns (1.2)
10 A. Urquı́a, C. Martı́n Villalba Casos Prácticos de Diseño de Circuitos Digitales con VHDL

Figura 1.3: Circuito ejemplo.

A continuación se describen los pasos en la simulación de dicho circuito:

Paso 1. En el instante inicial el reloj de la simulación vale 0 ns y se asigna nuevo


valor a las señales x1 y x2 . Debido a ello, se ejecutan las asignaciones que
tienen en su lado derecho x1 o x2 . En este caso, se ejecutan las asignaciones
correspondientes a la puerta NAND (asignación 1.1) y a la puerta OR
(asignación 1.2). Se producen dos nuevos eventos, denominados E0 y E1 :

– El evento E0 , planificado para el instante 1 ns, se debe a la ejecución


de la asignación de la puerta NAND. En este evento se asigna a s el
valor ‘0’.
– El evento E1 se debe a la ejecución de la asignación de la puerta OR.
En este evento se asigna a y el valor ‘1’ en el instante 2 ns. Observa que
la asignación y ← x1 or 1 es equivalente a y ← 1 independientemente
del valor de x1 . Si la señal x2 valiese ‘0’ en lugar de ‘1’ el valor de y
serı́a indefinido hasta que s tuviese un valor definido.

Además, se incorpora al calendario de eventos un evento, llamado E2 ,


programado para el instante 5 ns, y cuya acción es: x2 ← 0. Los valores
de las señales y el calendario de eventos en el instante 0 ns se presentan en
las tablas siguientes:

Señal Valor
Calendario de eventos
x1 ‘1’
E0 1 ns s ← 0
x2 ‘1’
E1 2 ns y ← 1
s ‘U’ (valor indefinido)
E2 5 ns x2 ← 0
y ‘U’ (valor indefinido)

Paso 2. El simulador extrae el evento E0 del calendario y lo ejecuta. El valor de


la señal s pasa a ser cero y el reloj de la simulación vale 1 ns . El cambio en la
señal s produce que se ejecute la asignación 1.2 y se genere un nuevo evento
(E3 ). A continuación se muestran los valores de las señales y el calendario
de eventos en el instante 1 ns.

Señal Valor
Calendario de eventos
x1 ’1’
E1 2 ns y ← 1
x2 ’1’
E3 3 ns y ← 1
s ’0’
E2 5 ns x2 ← 0
y ’U’ (valor indefinido)
Capı́tulo 1 Fundamentos 11

Paso 3. El simulador extrae el evento E1 del calendario y lo ejecuta. Entonces,


el valor de la señal y pasa a ser uno y el reloj de la simulación vale 2 ns .
El cambio en la señal y no genera ningún evento. Los valores de las señales
y el calendario de eventos en el instante 2 ns se muestran a continuación.

Señal Valor
x1 ’1’ Calendario de eventos
x2 ’1’ E3 3 ns y ← 1
s ’0’ E2 5 ns x2 ← 0
y ’1’

Paso 4. El simulador extrae el evento E3 del calendario y lo ejecuta. El reloj


de la simulación vale 3 ns y los valores de las señales y el contenido del
calendario de eventos son los siguientes:

Señal Valor
x1 ’1’
Calendario de eventos
x2 ’1’
E2 5 ns x2 ← 0
s ’0’
y ’1’

Paso 5. El simulador extrae el evento E2 del calendario y lo ejecuta. Como


consecuencia, el valor de la señal x2 pasa a ser cero y el reloj de la simulación
vale 5 ns . Como resultado, se ejecutan las asignaciones 1.1 y 1.2 y se
generan dos eventos (E4 y E5 ). A continuación se muestran los valores
de las señales y el calendario de eventos en el instante 5 ns.

Señal Valor
x1 ’1’ Calendario de eventos
x2 ’0’ E4 6 ns s ← 1
s ’0’ E5 7 ns y ← 0
y ’1’

Paso 6. El simulador extrae el evento E4 del calendario y lo ejecuta. El valor


de la señal s pasa ası́ a ser uno y el reloj de la simulación pasa a valer
6 ns . Cuando esto sucede, se ejecuta la asignación 1.2. El evento E5 se
borra del calendario de eventos ya que E5 y el nuevo evento (E6 ) afectan
a la misma señal asignándole valores distintos y el lapsus de tiempo entre
ambos eventos es inferior a 2 ns. Los valores de las señales y el calendario
de eventos en el instante 6 ns se muestran a continuación.

Señal Valor
x1 ’1’
Calendario de eventos
x2 ’0’
E6 8 ns y ← 1
s ’1’
y ’1’
12 A. Urquı́a, C. Martı́n Villalba Casos Prácticos de Diseño de Circuitos Digitales con VHDL

Figura 1.4: Cronomagrama de las señales x1 , x2 , y y s del circuito ejemplo.

Paso 7. En el instante 8 ns se ejecuta el evento E6 , que no genera otros eventos.


Puesto que el calendario de eventos se encuentra vacı́o, el simulador finaliza
la ejecución. El cronomagrama de las señales x1 , x2 , y y s se muestra en la
Figura 1.4.

1.5 Test de los circuitos


El test juega un papel muy importante en el diseño de circuitos integrados. No sólo
se emplea para verificar el correcto funcionamiento del circuito ya completamente
diseñado, sino que también es una ayuda esencial para el diseñador durante la
fase de diseño del circuito.
Finalmente, el test se emplea en manufactura, para determinar qué chips
han resultado defectuosos o tienen limitadas prestaciones. Por ejemplo, puede
emplearse para separar los chips que funcionan correctamente a alta velocidad,
de los que sólo funcionan a baja velocidad (cada tipo es vendido a diferente
precio). Si el diseño se ha realizado correctamente, los chips defectuosos en los
test de manufactura se deben a problemas en los procesos de fabricación o de
encapsulado. El test realizado en manufactura tiene un impacto directo sobre el
rendimiento (porcentaje de chips fabricados que no son defectuosos), el cual tiene
un impacto directo sobre los beneficios de la compañı́a fabricante de los chips.
Esencialmente, el test consiste en fijar valores en todas las entradas del circuito
y observar qué valores se obtienen en sus salidas. A cada asignación de valores a
todas las entradas del circuito se le llama un vector de test. El programa de test
consiste en un conjunto de vectores de test, que se aplican sobre el dispositivo en
una determinada secuencia.

Test en manufactura
Un objetivo fundamental del test en manufactura es detectar problemas en el
proceso de fabricación. Las causas de mal funcionamiento de los chips más común-
mente observadas en la práctica son:

– Abiertos. Conexiones entre los dispositivos que se encuentran abiertas


debido a algún problema, por ejemplo, debido a la rotura de la lı́nea de
metal que establece la conexión.
Capı́tulo 1 Fundamentos 13

– Cortos. Conexiones que se han establecido entre diferentes dispositivos,


cuando no deberı́an haberse producido.

– Acoplos. Valores lógicos en una parte del circuito que inadvertidamente


cambian el valor lógico en otra parte del circuito.

Modelar estos diferentes tipos de defectos en el circuito es extremadamente


difı́cil. Por ello, se han desarrollado diferentes modelos simplificados de fallos.
Uno de estos modelos de fallo es considerar que el defecto de fabricación hace
que una de las conexiones internas del circuito permanezca siempre a 1, o que
permanezca siempre a 0.
En un circuito tı́pico, este tipo de fallos da lugar a un número muy elevado de
patrones de fallo. Un patrón de fallo es una determinada selección de conexiones
que se encuentran permanentemente a 1 y de conexiones que se encuentran
permanentemente a 0.
Se da la circunstancia de que varios patrones de fallo pueden desembocar en
el mismo comportamiento del circuito. Por ejemplo, si cualquiera de las entradas
de una puerta NAND se encuentra siempre a 0, el circuito se comporta de la
misma manera que si la salida del circuito se encontrara siempre a 1.
Incluso tomando en consideración que existen patrones de fallo que dan lugar
a un comportamiento equivalente (defectuoso) del circuito, el número de patrones
de fallo esencialmente distintos es extremadamente grande.
Por ello, se ha desarrollado un modelo simplificado a partir del anterior.
Consiste en suponer que en el circuito hay una única conexión que se encuentra
permanentemente a 1, o permanentemente a 0. Aunque este modelo de fallos
pudiera considerarse muy restrictivo, ha demostrado ser eficaz.
Una vez se adopta un determinado modelo de fallos, el siguiente paso es crear
un conjunto de vectores de test que permita detectar ese tipo de fallos. Para que
se produzca la detección del fallo, es preciso que la salida del circuito, en caso de
estarse produciendo el fallo, sea diferente de la salida de un circuito que funcione
correctamente. En este caso, se dice que el fallo se encuentra cubierto por el vector
de test. Por supuesto, habrá otros tipos de fallos que darán lugar, para ese vector
de test, a las mismas salidas que un circuito que funcione correctamente. Se dice
entonces que el vector de test no cubre esos otros fallos.
Según se van usando más y más vectores de test, el porcentaje de fallos
potenciales (para un determinado modelo de fallo) que son cubiertos se aproxima
al 100 %. Dado un conjunto de vectores de test, la cobertura de fallos de ese
conjunto de vectores de test (dado un modelo especı́fico de fallos) corresponde
con el porcentaje de fallos cubiertos.
El test de los circuitos secuenciales es más complicado, ya que las salidas del
circuito dependen no sólo de las entradas, sino también de su estado. Por tanto,
en este tipo de circuitos es preciso poder fijar los valores de todos los flip-flops a
voluntad. Esto puede hacerse de las dos maneras siguientes:

1. Mediante una secuencia de inicialización (secuencia de valores de las entra-


das del circuito), se lleva el circuito al estado deseado. A continuación, se
aplica el vector de test para probar el circuito en ese estado.
14 A. Urquı́a, C. Martı́n Villalba Casos Prácticos de Diseño de Circuitos Digitales con VHDL

Mediante este procedimiento, un único test consiste en una secuencia de


inicialización, seguida de otro vector de test. Este procedimiento conduce
a usar un gran número de vectores de test, muchos de los cuales son
simplemente secuencias de inicialización. Además, en algunos casos puede
no ser posible fijar todos los flip-flops a los valores deseados.

2. El segundo método consiste el usar en el diseño scan flip-flops, que son flip-
flops cuyo valor puede ser cargado desde las entradas al circuito (mientras
se realiza el test), o bien pueden ser usados del mismo modo que un flip-flop
sin modificar (durante el modo normal de funcionamiento del circuito). Los
scan flip-flops pueden construirse insertando multiplexores en la entrada D
de los flip-flops.

En el test en manufactura, la calidad de un conjunto de vectores de test


(denominado programa de test) se mide por medio de la cobertura de fallos
del programa de test (supuesto un determinado modelo de fallo) y del tiempo
necesario para aplicar todos los vectores de test al circuito, que es directamente
proporcional al número de vectores de test.
Cuanto mayor sea la cobertura de fallos, menor será el número de chips
defectuosos que superarán con éxito el proceso de inspección. Cuanto menor sea
el número de vectores de test, menor será el tiempo necesario para ejecutar el
programa de test, con lo cual podrán testearse mayor número de chips por unidad
de tiempo.

Test funcional
El test funcional se emplea en todas las etapas del proceso de diseño del circuito.
Su objetivo es verificar que el circuito realiza todas las operaciones como debiera.
En los diseños grandes, que normalmente se diseñan de manera jerárquica,
todos los subcircuitos de bajo nivel deben ser comprobados funcionalmente, usan-
do programas de test especı́ficos para cada uno, antes de ser incluidos en los
subcircuitos de más alto nivel.
Aunque todos los subcircuitos sean comprobados por separado, el subcircuito
obtenido de la composición de todos ellos debe también ser comprobado, usándose
para ello su propio programa de test.
A continuación, una vez se implementa el circuito usando alguna plataforma
hardware (ASIC, FPGA, etc.), debe volver a ser testeado de nuevo. Si es posible,
debe emplearse para testear el prototipo hardware el mismo conjunto de tests que
se ha usado en la fase de simulación. Habitualmente, el primer prototipo hardware
contiene errores. La comparación de los resultados del test, con los resultados de
las simulaciones para esos mismos tests, puede ayudar a identificar errores de
diseño y de fabricación.

Programas de test funcional


Un método para testear la funcionalidad de un circuito es probar todos los posibles
vectores de entrada. Sin embargo, en algunos circuitos esto no es posible, bien
Capı́tulo 1 Fundamentos 15

porque el número de posibles vectores es muy grande, o bien porque algunas


combinaciones de valores de las entradas no son válidas para ese determinado
circuito. Además, algunas funciones requieren de una determinada secuencia de
vectores de entrada.
En conclusión, el programa de test es algo que depende del circuito. Sin
embargo, en general se sigue el criterio de probar todos los posibles vectores
de entrada, siempre que esto sea posible.
Si el número de posibles vectores de entrada es muy grande (se tardarı́a
meses o años en probarlos todos), existen varios métodos heurı́sticos que pueden
aplicarse para reducir el número de vectores de entrada.

1. Puede emplearse el conocimiento sobre el funcionamiento de circuito para


descartar aquellos vectores de entrada que no tienen ninguna función en el
circuito, o que nunca ocurrirán en la práctica.

2. El circuito puede dividirse en varios subcircuitos, que son testeados ex-


haustivamente (usando todas las combinaciones de los vectores de entrada
para cada subcircuito). A continuación, el circuito completo puede testaerse
usando un conjunto no exhaustivo de vectores de entrada, simplemente para
comprobar que los subcircuitos han sido integrados adecuadamente.

3. Se escoge un conjunto representativo de vectores de entrada, con el fin de


ejercitar el circuito bajo condiciones normales de funcionamiento y bajo
condiciones extremas.

Al testear un circuito, es deseable poder comparar de manera automática las


salidas del circuito con las correspondientes salidas que se obtendrı́an si el circuito
funcionara correctamente. Esto puede hacerse de varias maneras.

1. Una forma es almacenar en un fichero las salidas de un circuito que funcione


correctamente, y compararlas con las salidas obtenidas.

2. Otro procedimiento consiste en calcular la salida esperada del circuito usan-


do un método diferente al empleado en el test, y comparar los resultados.
Cuando no es posible aplicar un método de cálculo alternativo al del test,
puede comprobarse si los resultados obtenidos del test son “razonables”. Por
ejemplo, si un circuito calcula la media de un conjunto de números, puede
comprobarse que el resultado obtenido sea mayor o igual que el menor de
los números del conjunto, y menor o igual que el mayor de los números del
conjunto.

Banco de pruebas
Muchas herramientas de simulación incluyen menús que permiten asignar valores
a las entradas del circuito. Sin embargo, el uso de este tipo de interfaces gráficas
de usuario puede resultar lento y el programa de test desarrollado puede no ser
exportable a otras herramientas de simulación.
16 A. Urquı́a, C. Martı́n Villalba Casos Prácticos de Diseño de Circuitos Digitales con VHDL

% &' ( ) &* + , - . ( + / 0 1 ' ) 0 , - 2

F G HIJK JL JMQ KJ L 34 5 678 64 79:


34 5 678 64 79: JM N N O KPRM N N O

UUT
? < 6: C D 8 :5 > 67E =
; <= < 8 >? :8 ? < ? < @: A 8 < A4 @9>? : A
@: A B < 69: 8 < A ? < 9 < A9
? < @ 9 < A9

Figura 1.5: Diagrama de bloques del modelo de un banco de pruebas.

Una alternativa mucho más ventajosa consiste en codificar el programa de


test usando un HDL. Es decir, implementar el programa de test en otro módulo
de código HDL, que es denominado banco de pruebas.
El banco de pruebas contendrá el circuito que está siendo probado (denomi-
nado abreviadamente UUT, del inglés “Unit Under Test”) como un subcircuito.
Todas las entradas al UUT serán generadas dentro del banco de pruebas, y todas
las salidas del circuito serán comprobadas dentro del banco de pruebas.
En resumen, el banco de pruebas debe incluir (véase el diagrama de bloques
en la Figura 1.5):
– Un subcircuito generador de los vectores de test.

– El circuito que está siendo probado (UUT).

– Un subcircuito de comprobación de los resultados obtenidos del test.


Como módulo de código en HDL, el banco de pruebas es un módulo sin
entradas ni salidas externas. Puesto que el banco de pruebas normalmente no
va a ser sintetizado en un circuito fı́sico, puede emplearse cualquier instrucción
disponible en el HDL para generar los vectores de test y analizar las salidas del
UUT, pudiéndose llegar a crear programas extremadamente complejos.
Finalmente, recalcar que cuando se diseña un circuito digital, es conveniente
diseñar también su banco de pruebas. Si el circuito se diseña jerárquicamente,
entonces cada subcircuito debe ser testeado separadamente antes de ser combi-
nado con otros subcircuitos para integrar un circuito de nivel jerárquico superior.
Asimismo, deberá desarrollarse un banco de pruebas para este circuito de nivel
superior.

1.6 Dos simuladores de VHDL’93: VeriBest y ModelSim


En este texto se proponen diferentes casos de diseño de circuitos digitales usando
el lenguaje VHDL, que el alumno debe simular en su propio ordenador. Para ello,
el alumno debe tener instalado en su ordenador un simulador de VHDL.
En esta sección se proporcionan algunas indicaciones básicas para la instala-
ción y manejo de dos simuladores de VHDL’93: VeriBest VHDL y ModelSim PE
Capı́tulo 1 Fundamentos 17

Student Edition. Cualquiera de los dos puede emplearse para la simulación de los
modelos planteados en este texto.
El simulador VeriBest VHDL fue desarrollado por la compañı́a VeriBest Inc.
Cuando esta compañı́a pasó a formar parte de la corporación Mentor Graphics,
dejó de darse soporte al simulador VeriBest VHDL, siendo éste sustituido por el
simulador ModelSim.
La única ventaja de VeriBest es que funciona para casi todas las versiones de
Windows (Windows NT 4.0, Windows 95, Windows 98, etc.). Por tratarse de una
herramienta software del año 1998, resulta adecuada para su uso en ordenadores
con limitadas prestaciones. Si éste no es el caso, es preferible emplear ModelSim
en lugar de VeriBest.
Aparte de estos dos simuladores de VHDL’93, en Internet pueden encontrarse
otros. Asimismo, existen versiones gratuitas de herramientas orientadas no sólo
a la simulación, sino también a la sı́ntesis, entre las que cabe destacar Quartus II
Web Edition, que puede descargarse gratuitamente del sitio web de la compañı́a
Altera Corporation.
Se sugiere al alumno que escoja en este punto qué entorno de simulación va
a emplear. Si decide usar VeriBest, la guı́a de instalación y uso del Apéndice A
puede serle útil. Por el contrario, si decide usar ModelSim (lo cual recomendamos),
encontrará la correspondiente guı́a en el Apéndice B.
Conceptos básicos de VHDL
2

Objetivos. Una vez estudiado el contenido del tema deberı́a saber:


– Declarar una entidad de diseño en VHDL.
– Declarar los elementos sintácticos básicos de VHDL.
– Discutir las principales caracterı́sticas de la asignación concurrente
y las diferencias entre la asignación secuencial y concurrente.
– Definir el comportamiento de un circuito mediante instanciación
y conexión de otros circuitos.
– Discutir la utilidad de la parametrización en la descripción de un circuito.
– Discutir las principales caracterı́sticas de las señales, variables y constantes
en VHDL. Usar adecuadamente cada una de ellas.
– Tipos de datos básicos en VHDL y sus principales atributos.
– Declarar y usar librerı́as VHDL y conocer las librerı́as más comúnmente usadas.
– Discutir las principales caracterı́sticas de los tipos de retardo
y modelar los distintos tipos de retardo en VHDL.
– Realizar, con “lápiz y papel”, el cronograma de las señales de un circuito
conocido el código VHDL del circuito y de su banco de pruebas.
– Declarar procedimientos y funciones y discutir la utilidad de su uso.

VHDL es un lenguaje complejo, con numerosas capacidades y librerı́as de fun-


ciones. De hecho, aunque es un lenguaje para describir hardware, posee muchas
de las capacidades de los lenguajes de programación (tales como C o Fortran),
incluyendo estructuras record, funciones, procedimientos y soporte a bloques de
código compilados separadamente.
Pese a lo anterior, para la mayor parte de las aplicaciones de VHDL al
modelado y simulación de circuitos digitales, es suficiente con emplear un pequeño
subconjunto de las estructuras y capacidades proporcionadas por el lenguaje. En
particular, se ha definido un subconjunto del lenguaje VHDL, denominado VHDL
20 A. Urquı́a, C. Martı́n Villalba Casos Prácticos de Diseño de Circuitos Digitales con VHDL

synthesis interoperability subset (estándar IEEE 1076.6), que contiene los tipos
de datos, operadores y otras capacidades de VHDL que deberı́an ser usados para
crear código VHDL sintetizable. Esto es, código a partir del cual las herramientas
de CAD puedan generar automáticamente circuitos hardware que funcionen.
Siguiendo estas reglas y centrándonos en prácticas “simples” para la codifi-
cación de alto nivel, en este capı́tulo se introducen los conceptos básicos para el
modelado y la simulación empleando VHDL.

2.1 Definición de la entidad de diseño


Se denomina entidad de diseño al bloque constitutivo básico para la descripción
del hardware en VHDL. Consta de las dos partes siguientes:

1. Entity: interfaz con el exterior, en la que se definen los puertos de conexión


(señales de entrada y/o salida) de la entidad de diseño.

2. Architecture: define el comportamiento o la estructura de la entidad de


diseño. Es decir, cómo los puertos de salida de la entidad de diseño se
relacionan con sus puertos de entrada.

A continuación, se explica cómo se define la entity y la architecture, asi


como el procedimiento que proporciona VHDL para asociar una entity a una
determinada architecture.

2.2 Entity
La entity define la interfaz externa de la entidad de diseño. Incluye:

– El nombre de la entidad de diseño.

– La lista de las señales de salida y de entrada que componen la interfaz


(normalmente se aplica el convenio de escribir primero las salidas y a con-
tinuación las entradas). A cada una de estas señales se le denomina puerto
(port). Existen tres tipos de puertos: in (entrada), out (salida) e inout
(bidireccional).

Ejemplo 2.2.1. En la Figura 2.1 se muestra la definición de las interfaces de las


puertas lógicas NOT, XOR y AND.
La palabra reservada entity, seguida del nombre de la interfaz y de las palabras
reservadas is port, indica el comienzo de la definición de la interfaz.
A continuación, se especifica el nombre de cada uno de los puertos, su direc-
ción (in, out o inout) y su tipo. En el ejemplo mostrado en la Figura 2.1, todos
los puertos son señales del tipo std logic.
Finalmente, las palabras reservadas end entity, seguidas del nombre de la
interfaz, indican el final de la definición.
Capı́tulo 2 Conceptos básicos de VHDL 21

x0 x0
x0 y0 y0 y0
x1 x1

entity not is port entity xor2 is port entity and2 is port


( y0 : out std_logic; ( y0 : out std_logic; ( y0 : out std_logic;
x0 : in std_logic ); x0, x1 : in std_logic ); x0, x1 : in std_logic );
end entity not; end entity xor2; end entity and2;

Figura 2.1: Ejemplos de interfaz (entity) de puertas NOT, XOR y AND.

En VHDL, las palabras reservadas (por ejemplo, entity, is, port, in,
out, end) y los nombres definidos por el usuario (por ejemplo, not1, xor2,
and2, x0, x1, y) pueden escribirse indistintamente en mayúsculas o en minúsculas,
puesto que en VHDL no se diferencia entre los caracteres en mayúscula y en
minúscula. Por ejemplo, es equivalente escribir entity, ENTITY y EnTiTy, ası́
como también es equivalente escribir not1 y NoT1.
Los nombres definidos por el usuario deben comenzar por una letra, seguida
opcionalmente por cualquier secuencia de letras, números y caracteres guión bajo,
con la limitación de que ni pueden aparecer dos guiones bajos seguidos, ni el guión
bajo puede ser el último caracter del nombre.

2.3 Architecture
La architecture describe el comportamiento o la estructura de la entidad de
diseño. Esta definición puede emplear:

– Una descripción estructural, en la cual el componente es descrito mediante


la conexión de componentes de más bajo nivel.

– Una descripción de su comportamiento, en la que se describe el comporta-


miento que debe tener el componente.

– Una descripción mixta de la estructura y del comportamiento, que incluya


componentes de más bajo nivel y código describiendo el comportamiento.

Ejemplo 2.3.1. En la Figura 2.2 se muestran las architecture que describen el


comportamiento de las puertas lógicas NOT, XOR y AND. Las correspondientes
entity son las definidas en la Figura 2.1.
En este ejemplo se ha dado el mismo nombre a la entity y a la architecture
de cada entidad de diseño. En general, se les puede dar nombres diferentes.

A grandes rasgos, la definición de la architecture tiene la sintaxis siguiente:

architecture <nombre architecture> of <nombre entity> is


<Declaración de se~
nales, variables y constantes locales>
22 A. Urquı́a, C. Martı́n Villalba Casos Prácticos de Diseño de Circuitos Digitales con VHDL

x0 x0
x0 y0 y0 y0
x1 x1

architecture not of not is architecture xor2 of xor2 is architecture and2 of and2 is


begin begin begin
y0 <= not x0; y0 <= x0 xor x1; y0 <= x0 and x1;
end architecture not; end architecture xor2; end architecture and2;

Figura 2.2: Architecture de las puertas NOT, XOR y AND.

<Declaración de la entity de los componentes>


begin
<Instanciación de los componentes>
<Asignaciones concurrentes y bloques process>
end architecture <nombre architecture>;

En el área de texto previa a la palabra reservada begin, es donde se declaran


las señales, variables y constantes, todas ellas locales a la definición de la archi-
tecture, ası́ como también las entity de los componentes usados en la definición
de la arquitectura.

2.3.1 Asignaciones concurrentes


Las asignaciones directamente contenidas entre las palabras reservadas begin y
end de la architecture se denominan asignaciones concurrentes, debido a
que todas ellas se ejecutan de forma concurrente. Es decir, el orden de ejecución
de las sentencias no está determinado por el orden en que se han escrito.
El instante de ejecución de una sentencia de asignación concurrente viene
determinado por los eventos en las señales a las cuales la sentencia es “sensible”.

Ejemplo 2.3.2. La sentencia de asignación concurrente

y0 <= not x0;

es ejecutada cada vez que se produce un cambio en el valor de la señal x0,


calculándose el nuevo valor de la señal y0. En la terminologı́a de VHDL, se dice
que esta sentencia, de la cual se calcula y0, es “sensible” a la señal x0.

Ejemplo 2.3.3. Dado el código mostrado a continuación, se producirá un cambio


en la señal a cada vez que cambie b, y se producirá un cambio en la señal c cada
vez que cambie u o v.

architecture archEjemplo of ...


...
begin
a <= b; -- Asignaciones concurrentes
Capı́tulo 2 Conceptos básicos de VHDL 23

c <= u and v; -- a las se~


nales: a, c
...
end archEjemplo;

Si dos sentencias de alto nivel (es decir, asignaciones concurrentes) asignan


diferentes valores a una misma señal en un determinado instante de tiempo,
entonces la señal toma el valor X. Obsérvese que en un circuito real una situación
de ese tipo podrı́a producir un daño en el circuito o resultar en la asignación del
valor 1 ó 0 a la señal de manera impredecible.

2.3.2 Bloque process


Para describir la operación de un determinado circuito, puede ser preciso emplear
una secuencia de sentencias que se ejecuten en secuencia (es decir, en el orden en
que han sido escritas). Para ello se emplea el bloque process. Una secuencia de
sentencias contenidas dentro de un bloque process es simulada ejecutándolas de
manera secuencial.
Por otra parte, los bloques process se ejecuta concurrentemente unos res-
pecto a los otros (sólo las sentencias dentro de cada bloque process se ejecutan
secuencialmente), al igual que las demás sentencias de alto nivel, puesto que un
bloque process constituye una sentencia de alto nivel dentro de la definición de
la architecture.
Las sentencias interiores a un bloque process se ejecutan repetidamente,
desde la primera sentencia del bloque hasta el punto en el cual se alcanza el final
del bloque, en un bucle infinito. Para evitar que un bloque process consuma los
recursos de CPU, debe:

– O bien incluirse sentencias wait dentro del bloque process (esperar hasta
que ocurra cierto evento, o hasta que transcurra cierta cantidad de tiempo
simulado).

– O bien definir la lista de señales a las cuales el bloque process es “sensible”.


Esta lista se escribe, entre paréntesis, a continuación de la palabra reservada
process. En este caso, el bloque process es ejecutado sólo en el instante
en que una o varias de estas señales a las que es “sensible” cambia de valor.

Ejemplo 2.3.4. El siguiente código muestra un método estándar de modelar un


biestable D disparado por el flanco de subida del reloj (clk) y con una entrada
reset ası́ncrona (reset_n) activada en LOW. Esto significa que cuando la entrada
de reset pasa de valer ’1’ a valer ’0’, entonces se inicializa el biestable: q <- ’0’,
q_n <- ’1’.

--------------------------------------------------
-- Biestable D con reset ası́ncrono activado en LOW
library IEEE;
use IEEE.std_logic_1164.all;
24 A. Urquı́a, C. Martı́n Villalba Casos Prácticos de Diseño de Circuitos Digitales con VHDL

use IEEE.numeric_std.all;

entity flipflop_D is port


( q, q_n : out std_logic;
d, clk, reset_n : in std_logic);
end entity flipflop_D;

architecture flipflop_D of flipflop_D is


begin
process(reset_n, clk) is -- Proceso activo cuando cambia
begin -- el valor de reset_n o de clk
if reset_n = ’0’ then -- Comprueba reset ası́ncrono
q <= ’0’;
q_n <= ’1’;
elsif rising_edge(clk) then -- En el flanco de subida del reloj
q <= d;
q_n <= not d;
end if;
end process;
end architecture flipflop_D;
--------------------------------------------------

2.3.3 Descripción de la estructura


VHDL permite definir circuitos de forma modular y jerárquica. Es decir, es posible
definir un circuito mediante instanciación y conexión de otros circuitos, y a su vez
usar este nuevo circuito para definir, mediante su conexión con otros circuitos,
otro circuito de un nivel jerárquico superior, y ası́ sucesivamente. A esto se
denomina realizar una descripción modular y jerárquica del hardware.
Para describir un circuito mediante la instanciación y conexión de subcircui-
tos, es necesario:

1. Escribir la declaración completa de la entity de cada clase de subcircuito.

2. Instanciar los subcircuitos, asignando un nombre a cada uno de los objetos


creados de cada entity.

3. Conectar los subcircuitos. Se hace de la forma siguiente:

– Una conexión entre subcircuitos se indica usando señales con nombres


idénticos.
– Una conexión entre el circuito y un subcircuito se indica “mapeando”
la señal del circuito con el correspondiente puerto del subcircuito. Esta
conexión entre señales puede realizarse mediante:
· Asociación posicional, es decir, mediante la posición en que la
señal se sitúa en la lista de parámetros.
Capı́tulo 2 Conceptos básicos de VHDL 25

· Asociación mediante el nombre, también llamada asignación ex-


plı́cita, en la cual la señal y su puerto asociado son incluidos en la
lista de parámetros de la forma
puerto => se~
nal

Ejemplo 2.3.5. En la Figura 2.3 se muestra el diagrama y la implementación de


un multiplexor de 2 señales de 1 bit. Cuando la señal de control s0 vale ’0’, la
señal i0 se transmite a la salida d, mientras que cuando s0 vale ’1’ es la señal
i1 la que se transmite a la salida.

X Y Z [ \]

ST

SU V
WT

^_ `_

Figura 2.3: Multiplexor de 2 señales de 1 bit: a) diagrama; b) implementa-


ción.

Como puede observarse en la Figura 2.3b, este circuito multiplexor está com-
puesto por un inversor (inv_1), dos puertas AND de dos entradas (AND2_1,
AND2_2) y una puerta OR de dos entradas (OR2_1). Las señales n1, n2 y n3
tienen por objeto describir la conexión entre los componentes.
A continuación, se muestra la descripción de la estructura del circuito en
lenguaje VHDL. Obsérvese que al instanciar cada componente, se indica qué señal
debe asociarse a cada uno de sus puertos. Una misma señal asociada a diferentes
puertos indica el establecimiento de una conexión entre esos puertos.

----------------------------------------------
-- MUX 2:1 de 1 bit
library IEEE;
use IEEE.std_logic_1164.all;

entity Mux2_1bit is
port (
d : out std_logic;
i0, i1 : in std_logic;
s0 : in std_logic );
end entity Mux2_1bit;
26 A. Urquı́a, C. Martı́n Villalba Casos Prácticos de Diseño de Circuitos Digitales con VHDL

architecture Mux2_1bit of Mux2_1bit is

component not1 is
port ( y0 : out std_logic;
x0 : in std_logic );
end component not1;

component or2 is
port ( y0 : out std_logic;
x0, x1 : in std_logic );
end component or2;

component and2 is
port ( y0 : out std_logic;
x0, x1 : in std_logic );
end component and2;

signal n1, n2, n3 : std_logic;


begin
Inv_1 : not1 port map ( x0 => s0, y0 => n1);
And2_1 : and2 port map ( x0 => i0, x1 => n1, y0 => n2);
And2_2 : and2 port map ( x0 => i1, x1 => s0, y0 => n3);
Or2_1 : or2 port map ( x0 => n2, x1 => n3, y0 => d);
end architecture Mux2_1bit;
----------------------------------------------

Ejemplo 2.3.6. El circuito multiplexor de dos señales de 1 bit puede emplearse


para diseñar un multiplexor de dos señales de 4 bits. En la Figura 2.4 se muestra
la representación esquemática del circuito. El código VHDL que describe este
circuito se muestra a continuación.

----------------------------------------------
-- MUX 2:1 de 4 bit
library IEEE;
use IEEE.std_logic_1164.all;

entity Mux2_4bit is
port ( d0, d1, d2, d3 : out std_logic;
a0, a1, a2, a3 : in std_logic;
b0, b1, b2, b3 : in std_logic;
s0 : in std_logic );
end entity Mux2_4bit;

architecture Mux2_4bit of Mux2_4bit is


Capı́tulo 2 Conceptos básicos de VHDL 27

abcdef

a3 i0 d3
b3 d
i1
s0

abcdef

a2 i0 d2
b2 d
i1
s0
abcdef

a1 i0 d1
b1 d
i1
s0

abcdef

a0 i0 d0
b0 d
i1
s0

s0
Figura 2.4: Multiplexor de 2 señales de 4 bit diseñado mediante la conexión
de 4 multiplexores de 2 señales de 1 bit.

component Mux2_1bit is
port ( d : out std_logic;
i0, i1 : in std_logic;
s0 : in std_logic );
end component Mux2_1bit;

begin
Mux2_0 : Mux2_1bit port map
( d => d0, i0 => a0, i1 => b0 , s0 => s0 );
Mux2_1 : Mux2_1bit port map
( d => d1, i0 => a1, i1 => b1 , s0 => s0 );
Mux2_2 : Mux2_1bit port map
( d => d2, i0 => a2, i1 => b2 , s0 => s0 );
Mux2_3 : Mux2_1bit port map
( d => d3, i0 => a3, i1 => b3 , s0 => s0 );
end architecture Mux2_4bit;
----------------------------------------------
28 A. Urquı́a, C. Martı́n Villalba Casos Prácticos de Diseño de Circuitos Digitales con VHDL

2.3.4 Constantes generic


Una propiedad muy relacionada con la modularidad y la jerarquı́a es la parame-
trización, que es la capacidad de modificar el valor de ciertas propiedades de un
circuito cuando es instanciado, con el fin de adaptarlo a la aplicación en concreto
a la que vaya a destinarse al formar parte del circuito de nivel jerárquico superior.
La parametrización es una propiedad fundamental en la reutilización del código,
ya que permite adaptar un mismo fragmento de código a diferentes usos.
La palabra reservada generic se usa para definir aquellas constantes del
dispositivo a las que se desea asignar valor cuando el dispositivo es instanciado,
es decir, cuando es usado como un subcircuito de otro circuito de mayor nivel
jerárquico. Ejemplos tı́picos de constantes genéricas son el valor de determinados
retardos, el número de bits de un bus de señales, etc. Cuando una entity con
constante generic es instanciada como un subcircuito, puede cambiarse el valor
de las constantes generic para definir diferentes subcircuitos, con diferentes
valores de los retardos, anchura de los buses, etc. El caso práctico descrito en
la Sección 3.6 ilustra el empleo de constantes generic.

2.4 Configuration
Se emplea una pareja entity-architecture para describir en VHDL las enti-
dades de diseño (es decir, circuitos y subcircuitos) que pueden ser compilados
separadamente.
El hecho de que se definan separadamente la interfaz (entity) y la arquitectura
(architecture) facilita la definición de varias arquitecturas para una misma
entidad de diseño (con una única interfaz). Por ejemplo, pueden definirse varias
arquitecturas de una misma entidad de diseño, correspondientes a diferentes
versiones del circuito: velocidad baja, media y alta.
En este caso, cuando se emplee esa entidad de diseño debe indicarse explı́-
citamente qué arquitectura hay que emplear. Esto puede hacerse mediante la
definición de una configuración (configuration).

2.5 Señales, variables y constantes


En VHDL se emplean variables, señales y constantes para describir la operación
del circuito. Las señales corresponden con las señales lógicas reales existentes en
el circuito. Las variables pueden o no corresponder con señales fı́sicas reales. Las
constantes corresponden a magnitudes cuyo valor no cambia durante la simulación
(tı́picamente retardos, número de lı́neas de buses, número de bits de palabras,
etc.).
Las variables siempre deben usarse dentro de bloques process. Aparte de esta
restricción, pueden ser usadas con relativa libertad.
Por el contrario, hay que ser cuidadoso con el empleo de las señales. Las
señales definidas en el port de una entity tienen una dirección, lo cual condiciona
Capı́tulo 2 Conceptos básicos de VHDL 29

su uso: no puede leerse el valor de una señal de salida (out), ni asignarse un


valor a una señal de entrada (in). Las señales declaradas en la definición de la
architecture puede ser usadas tanto en la parte derecha como en la izquierda
de las asignaciones.
Un criterio general respecto al uso de las variables y las señales es el siguiente:

– Emplear una variable cuando vaya a usarse sólo dentro de un bloque pro-
cess.

– Emplear una señal para datos a los que deba asignarse valor fuera del bloque
process, o para datos que necesitan ser transferidos desde un puerto de
entrada o a un puerto de salida. Esto último es equivalente a decir que los
port sólo pueden ser señales.

Para asignar valor a una variable o constante se emplea :=, mientras que
se emplea <= para asignar valor a una señal. Sólo puede asignarse valor a las
variables en los bloques process. Puede asignarse valor a las señales mediante
asignaciones concurrentes o en los bloques process.
La diferencia fundamental entre una asignación a una señal y una asignación a
una variable, ambas realizadas dentro de un bloque process, es que la asignación
a la señal se ejecuta concurrentemente con la siguiente sentencia del bloque
process, mientras que la asignación a la variable se ejecuta antes que la siguiente
sentencia del bloque process.
Dos ejemplos tı́picos de uso de las variables son los siguientes:

1. Cuando hace falta realizar una serie de cálculos para poder asignarle valor
a una señal, se definen nuevas variables, se hacen los cálculos usando esas
variables, y finalmente se asigna el resultado de los cálculos a la señal.

2. Puesto que una señal de salida (es decir, un puerto out) no puede ser leı́da,
puede ser necesario definir una variable, leer y escribir sobre esa variable
tantas veces como sea necesario, y finalmente asignar esa variable a la señal
de salida.

Asimismo, existe una diferencia importante en el retraso asociado a una


asignación de una variable y de una señal. Este punto es discutido en la Sección
2.7.
Pueden definirse constantes en VHDL usando la palabra reservada constant.
Las sentencias de definición de constantes pueden situarse en los bloques entity
y architecture, antes de la palabra reservada begin. También pueden definirse
constantes dentro de la definición de un paquete (package), en cuyo caso deben
ser incluidas mediante una cláusula use.

2.5.1 Tipos de datos


Tı́picamente, la información se comunica dentro de un sistema digital usando
señales de valor binario (0 ó 1). En los sistemas de lógica positiva, cuando el
voltaje de la señal tiene un valor “alto” (3.3 ó 5 voltios en la tecnologı́a CMOS),
30 A. Urquı́a, C. Martı́n Villalba Casos Prácticos de Diseño de Circuitos Digitales con VHDL

representa un 1 lógico, y cuando toma un valor “bajo” (0 voltios en la tecnologı́a


CMOS) representa un 0 lógico.
Aunque todas las señales son interpretadas en los sistemas digitales como 0 y
1 lógicos, no es siempre posible modelar y simular los sistemas digitales usando
sólo señales 0 lógico y 1 lógico. Un motivo es que el valor de algunas señales
puede no ser conocido en determinado intervalo de tiempo de la simulación, por
ejemplo porque esas señales todavı́a no hayan sido inicializadas, es decir, no se
les haya asignado valor. Por otra parte, una señal puede tener un nivel de voltaje
intermedio (que puede ser interpretado como un 0 lógico o un 1 lógico), por
ejemplo debido a que está producida por una puerta lógica con una salida “débil”.
En VHDL se emplean tipos de datos para modelar las señales. Estos tipos de
datos pueden ser los estándar o bien tipos definidos por el usuario. El usuario
puede definir sus propios tipos de datos, bien como un subconjunto de tipos de
datos estándar, o bien puede definir sus propios tipos enumerados.
Los tipos más comunes en el modelado de señales digitales son bit y std logic.
A continuación se describen ambos tipos.

bit y std_logic
Una variable, señal o constante del tipo bit sólo puede tomar dos valores: 0 y
1 (obsérvese que los valores se escriben sin comillas). Ası́ pues, este tipo es útil
para realizar modelos sencillos de sistemas digitales.
Las variables, señales o constantes del tipo std logic pueden tomar nueve
valores. Además de los valores ’0’ y ’1’ (obsérvese que en este caso los valores se
escriben entre comillas simples), pueden tomar otros valores usados para modelar
valores intermedios o desconocidos de la señal. De estos valores, los más comunes
son los tres siguientes:

’U’ El valor de la señal está sin inicializar. Es decir, a la


señal no se le ha asignado todavı́a un valor.
’X’ No puede determinarse el valor de la señal, quizá
debido a un conflicto en las salidas (por ejemplo, una
puerta lógica intenta poner a ‘0’ la señal mientras otra
puerta lógica intenta ponerla a ‘1’).
’Z’ Alta impedancia, es decir, la señal ha quedado desco-
nectada.

Los restantes posibles valores de una señal del tipo std logic son: ’W’ (des-
conocida débil), ’L’ (cero débil), ’H’ (uno débil) y ’-’ (don’t care).
Por lo general, en los modelos mostrados en este texto se empleará el tipo
std logic para representar las señales binarias.

bit_vector y std_logic_vector
Los conjuntos de señales pueden agruparse formando lo que se denominan buses.
Análogamente, los conjuntos de variables pueden agruparse en vectores. Los
buses y vectores pueden modelarse en VHDL mediante los tipos bit vector (un
Capı́tulo 2 Conceptos básicos de VHDL 31

conjunto de señales o variables de tipo bit) y std logic vector (un conjunto de
señales o variables de tipo std logic).
Una desventaja de los tipos de datos bit vector y std logic vector es que
no pueden realizarse operaciones aritméticas sobre este tipo de señales. Esto
es razonable, ya que en los circuitos digitales no pueden realizarse operaciones
aritméticas directamente sobre los buses de señales, sólo pueden realizarse opera-
ciones lógicas. La forma de representar los valores literales de estos tipos de datos
se muestran en la Tabla 2.1.

Tabla 2.1: Valores literales.


Literales
bit 0, 1
std logic ’U’, ’0’, ’1’, ’Z’, ’W’, ’L’, ’H’, ’-’
bit vector Strings (cadenas de caracteres delimitadas por dobles
std logic vector comillas) de sus tipos básicos.
Para especificar la base, se antepone la letra:
B (para dı́gitos binarios)
O (para dı́gitos en octal)
X (para dı́gitos en hexadecimal)
El caracter _ (guión bajo) puede usarse como marcador
(es ignorado por el compilador de VHDL) con el fin de
facilitar la lectura de los números.
Por ejemplo, las siguientes son tres formas de expresar el
número sin signo 29:
B"01_1101" O"35" X"1D"
integer Sus literales están expresados por defecto en base 10.
real Para especificar valores en otras bases, es necesario usar #
para delimitar el valor, con la base precediendo el primer
#.
Las constantes de tipo real se representan usando un
punto decimal para separar la parte entera de la parte
decimal, y un E (o e) precediendo el valor del exponente.
Por ejemplo, a continuación se muestran diferentes for-
mas de expresar el número decimal 29:
2#01_1101# 8#35# 16#1D#
2.9e1 2.9E1 29

unsigned y signed
En aquellos casos en que resulte útil modelar operaciones aritméticas realizadas
sobre buses, pueden usarse los tipos de datos unsigned y signed. Ambos tipos
de datos están definidos usando como tipo de datos base std logic, con lo cual
son vectores de valores std logic.
Ası́ pues, la diferencia entre el tipo de datos std logic vector y los tipos
de datos unsigned y signed es que para el tipo de datos std logic vector
32 A. Urquı́a, C. Martı́n Villalba Casos Prácticos de Diseño de Circuitos Digitales con VHDL

están definidas las operaciones lógicas, pero no las aritméticas, mientras que para
los tipos de datos unsigned y signed están definidas las operaciones lógicas y
aritméticas.
Puede cambiarse el tamaño (es decir, el número de bits) de los datos unsigned
y signed mediante la función resize. El parámetro size representa el nuevo
número de bits del dato.

Tabla 2.2: Funciones para cambio de tamaño de unsigned y signed.


Tipo de dato Función
unsigned resize(arg,size)
signed resize(arg,size)

real e integer
También existen tipos de datos estándar que no se corresponden necesariamente
con señales en los circuitos fı́sicos. Resultan útiles para realizar descripciones del
comportamiento de los circuitos y para modelar los tests. Los tipos de datos
integer (32 bits) y real (64 bits) se definen de manera similar a como se hace en
los lenguajes de programación. Lo mismo sucede con las operaciones aritméticas
para este tipo de datos. En la Tabla 2.1 se muestra la forma de representar los
valores literales de los tipos integer y real.

time y string
Los tipos de datos time y string son útiles, en el proceso de depuración (debug-
ging) del modelo, para mostrar mensajes que son generados durante la simulación.
Las variables del tipo time son usadas para representar el tiempo simulado. La
unidad por defecto de este tipo de variables es el fs (femtosegundo = 10−15 s). Los
valores del tiempo pueden representarse en otras unidades escribiendo la unidad
de tiempo tras el valor del tiempo, el cual es escrito como una constante entera
o real. Las unidades de tiempo disponibles son: fs, ps, ns, us (microsegundos),
ms, sec, min y hr (horas). Además, existe una función estándar (llamada now,
sin argumentos), que devuelve el valor actual del tiempo simulado.
Para mostrar mensajes de texto y valores de datos en la pantalla, es preciso
convertir todos los argumentos de la sentencia report (la sentencia “print” de
VHDL) a tipos de dato string. Como en la mayorı́a de los lenguajes de progra-
mación, un string se define simplemente como un array de caracteres.

Tipos enumerados
Además de los tipos estándar de datos descritos anteriormente, es posible definir
tipos enumerados de datos.
Por ejemplo, supongamos una señal llamada opcode, que representa el código
de operación de un circuito. Suponiendo que sólo puede tomar cuatro valores
Capı́tulo 2 Conceptos básicos de VHDL 33

(suma, resta, salto y parar), entonces es posible definir un nuevo tipo (type),
llamado, por ejemplo, opcode_type, de la manera siguiente:

type opcode_type is ( SUMA, RESTA, SALTO, PARAR );

y declarar opcode del tipo opcode_type.


Este tipo de construcción hace el código VHDL más sencillo de entender. Sin
embargo, esta forma de realizar el modelo no permite especificar explı́citamente
el código binario correspondiente a cada uno de los códigos de operación.
Una forma alternativa de programar el ejemplo anterior es definir SUMA, RESTA,
SALTO y PARAR como constantes (constant) de dos bits, y definir opcode como
una señal que sea un vector de dos bits.

Conversión entre tipos


El compilador del lenguaje VHDL comprueba el tipo de los datos, mostrando
un error si en alguna operación se emplean tipos para los cuales esa operación
no está explı́citamente permitida. La finalidad de ello es reducir los errores de
programación, si bien también obliga a realizar conversiones de tipos, incluso
entre tipos que son esencialmente el mismo (como, por ejemplo, unsigned y
std logic vector).
Las funciones para la conversión de tipos están definidas en las librerı́as
estándar y packages, tı́picamente en el package en el que se define el tipo. Por
ejemplo, entre las funciones incluidas en el package IEEE.numeric std están:

to unsigned Convierte de integer a unsigned


to integer Convierte de unsigned a integer
Asimismo, la conversión entre tipos cercanos puede realizarse usando funcio-
nes cuyo nombre coincide con el nombre de los tipos. Por ejemplo, unsigned(t)
convierte una señal t del tipo std logic vector al tipo unsigned.

Tabla 2.3: Funciones para la conversión de tipos.


Conversión de: a: Función
std logic vector unsigned unsigned(arg)
std logic vector signed signed(arg)
unsigned std logic vector std_logic_vector(arg)
signed std logic vector std_logic_vector(arg)
integer unsigned to_unsigned(arg,size)
integer signed to_signed(arg,size)
unsigned integer to_integer(arg)
signed integer to_integer(arg)
integer std logic vector integer → unsigned/signed → std logic vector
std logic vector integer std logic vector → unsigned/signed → integer

Obsérvese en la Tabla 2.3 que en la conversión del tipo integer a los tipos
unsigned o signed, es preciso especificar el número de bits (size) de la señal
del tipo unsigned o signed resultante.
34 A. Urquı́a, C. Martı́n Villalba Casos Prácticos de Diseño de Circuitos Digitales con VHDL

2.5.2 Atributos
Puede considerarse que los atributos son propiedades de los tipos de datos. Existen
conjuntos estándar de atributos que son soportados para diferentes propósitos.
No todos los atributos son soportados para sı́ntesis. En la Tabla 2.4 se muestra
un conjunto de atributos estándar que son soportados por la mayorı́a de las
herramientas de sı́ntesis.

Tabla 2.4: Atributos soportados por la mayorı́a de las herramientas de


sı́ntesis.
Atributo Significado
<tipo>’ Indica que el argumento es del tipo <tipo>
<tipo>’base Tipo base de <tipo>
<tipo>’left Primer (más a la izquierda) valor en <tipo>
<tipo>’right Último (más a la derecha) valor en <tipo>
<tipo>’low Valor más pequeño en <tipo>
<tipo>’high Valor más grande en <tipo>
<vector>’range Rango de ı́ndices de un vector
<vector>’reverse_range Rango de ı́ndices del vector, en orden inverso
<vector>’length Número de valores en el rango del vector
<array>’range(n) Rango de ı́ndices en la dimensión n del array
<array>’reverse\_range(n) Rango de ı́ndices, en la dimensión n del array,
en orden inverso
<array>’length(n) Número de valores en el rango de la dimensión
n del array
<se~
nal>’stable true mientras no hay cambios en <se~nal>
<se~
nal>’event true sólo cuando hay un cambio en <se~nal>

El primer atributo, <tipo>’, se usa para especificar el tipo de una señal o de


un valor. Por ejemplo,

unsigned’("00")

establece que el string "00" se usa como un vector del tipo unsigned, en lugar
de como bit vector o std logic vector.
Hay atributos para tipos escalares de datos, para arrays de una dimensión
(vectores), para arrays de n dimensiones, y para señales. En la Tabla 2.4 se ha
empleado la terminologı́a siguiente:

<tipo> un tipo de datos escalar, estándar o definido por el usuario.


<vector> un tipo array unidimensional.
<array> un tipo array.
nal> una señal.
<se~
n un valor entero.
Capı́tulo 2 Conceptos básicos de VHDL 35

Asimismo, existen atributos que resultan útiles para programar bancos de


prueba y que, por tanto, no necesitan ser sintetizados. Un atributo particular-
mente útil es

<tipo>’image(se~
nal)

que devuelve un string con el valor del tipo <tipo>de la señal <señal>. Este
atributo se usa para convertir el valor de una señal a un string, de modo que
pueda ser mostrado en la consola (con el fin de depurar o monitorizar).
La lista completa de atributos soportados por VHDL es bastante extensa. No
obstante, sólo son necesarios unos pocos para programar la mayor parte de los
tipos de circuitos digitales y bancos de pruebas.
Por ejemplo, en VHDL’87 se emplea

clk’event and ( clk = ’1’ )

para modelar el flanco de subida de la señal de reloj. Sin embargo, puesto que
este predicado es también cierto cuando la señal clk cambia del valor U (no
inicializado) o del valor X (desconocido forzado) a 1, en VHDL’93 se usa

rising_edge(clk)

para modelar el flanco de subida de la señal clk.


Otro atributo usado frecuentemente es

<tipo>’range

el cual se emplea para especificar (por ejemplo, en un bucle for) el rango completo
de ı́ndices de un determinado tipo de dato.

2.5.3 Operadores
Los operadores de VHDL’93 están resumidos en la Tabla 2.5.
En la Tabla 2.6 se muestra el tipo de dato obtenido al realizar operaciones
aritméticas entre operandos del tipo unsigned, signed, e integer.
Tabla 2.5: Operadores de VHDL’93

Categorı́a Operador Significado


Misceláneos ** Exponenciación
abs Valor absoluto
not NOT lógico
Multiplicación / División * Multiplicación
/ División
mod Módulo
rem Resto
Unitarios (signo) + Identidad
– Negación (complemento a 2)
Suma / Resta + Suma
– Resta
& Concatenación
Desplazamiento sll Desplazamiento lógico izquierda
srl Desplazamiento lógico derecha
sla Desplazamiento aritmético izquierda
sra Desplazamiento aritmético derecha
rol Rotación lógica izquierda
ror Rotación lógica derecha
Relacional = Comprueba igualdad
/= Comprueba desigualdad
< Menor que
<= Menor o igual que
> Mayor que
>= Mayor o igual que
Lógico and AND lógica
or OR lógica
nand NAND lógica
nor NOR lógica
xor OR exclusiva lógica
xnor NOR exclusiva lógica

Tabla 2.6: Tipo obtenido como resultado de las operaciones aritméticas.


Operando 1 Operando 2 Resultado
unsigned unsigned unsigned
unsigned integer unsigned
integer unsigned unsigned
signed signed signed
signed integer signed
integer signed signed
Capı́tulo 2 Conceptos básicos de VHDL 37

2.6 Librerías
En VHDL, una librerı́a de diseño contiene la definición de un conjunto de tipos
de datos, ası́ como la definición de los operadores y funciones que pueden aplicarse
sobre estos tipos de datos. Existe un buen número de librerı́as de diseño estándar
y de librerı́as especı́ficas, que son proporcionadas junto con las herramientas de
simulación.
A excepción de los tipos bit y bit vector, todos los demás tipos precisan de
la inclusión de alguna librerı́a de diseño. Por ejemplo, es necesario usar la librerı́a
de IEEE (que es proporcionada en todos los simuladores) para poder usar los
tipos de datos std logic, std logic vector, unsigned y signed.
VHDL permite organizar las librerı́as, estructurando su contenido en sub-
librerı́as denominadas packages. Un beneficio añadido de ello es que incluir
únicamente los tipos de datos necesarios para el diseño reduce el tamaño del
código y simplifica la simulación del programa en VHDL.
Por este motivo, además de especificar qué librerı́as deben ser incluidas,
conviene que el diseñador indique qué paquetes en concreto de la librerı́a son
usados en la definición del circuito. Si no se especifica el paquete, o si un mismo
objeto está definido en varios paquetes, es preciso referirse a él usando la notación
punto:

librerı́a.paquete.objeto

Entre los paquetes más comúnmente usados, cabe mencionar los siguientes, per-
tenecientes a la librerı́a IEEE:

IEEE.std logic 1164 Incluye la definición de los tipos de datos


std logic y std logic vector, y de las operacio-
nes en las que intervienen estos tipos de datos.
IEEE.numeric std Incluye la definición de los tipos de datos unsig-
ned y signed, y de las operaciones más comunes
realizadas sobre estos tipos de datos.
IEEE.math real Incluye la definición de las operaciones en las que
intervienen números reales (tipo real). Estos son
números reales en coma flotante de 64 bits según
el estándar de IEEE.

Ası́ pues, es frecuente incluir, antes de la definición de la entidad de diseño,


las tres sentencias siguientes:

library IEEE;
use IEEE.std_logic_1164.all;
use IEEE.numeric_std.all;

La primera sentencia indica que va a emplearse la librerı́a de IEEE. Las otras


dos indican que los paquetes IEEE.std logic 1164 y IEEE.numeric std deben estar
listos para su uso en el código VHDL que sigue a continuación. Por supuesto, si
38 A. Urquı́a, C. Martı́n Villalba Casos Prácticos de Diseño de Circuitos Digitales con VHDL

en el código no se usan los tipos de datos unsigned y signed, entonces puede


omitirse la tercera sentencia.
Las herramientas de simulación y sı́ntesis con VHDL suelen incluir otras
librerı́as, que pueden ser examinadas desde la propia herramienta.
Existen librerı́as y paquetes que son cargados por defecto, con lo cual no
necesitan ser incluidas. Las más notables son las dos siguientes:

work Librerı́a por defecto donde se compilan todos


los tipos, las funciones, entity, architecture,
package, etc. definidos por el usuario.
std Contiene la mayorı́a de las definiciones y cons-
trucciones estándar soportadas por VHDL.

2.7 Modelado del retardo


Puesto que los dispositivos y las conexiones entre los dispositivos tienen retardos
asociados, para simular de manera precisa el comportamiento de los circuitos
es necesario modelar adecuadamente su retardo. De hecho, hay circuitos que no
funcionan adecuadamente cuando son simulados si no se toman en consideración
los retardos que se producen en ellos.
Una recomendación cuando se modelan circuitos digitales es asignar algún
retardo (incluso un retardo arbitrario, como 1 ns) a todas las operaciones al
nivel de transferencia entre registros usadas en el código VHDL que describe el
circuito. Obsérvese, no obstante, que esos retardos no son soportados al realizar la
sı́ntesis: algunas herramientas de sı́ntesis simplemente los ignoran, mientras que
otras obligan al diseñador a poner esos retardos a cero o a eliminarlos del código.
Los retardos pueden ser modelados mediante varios métodos. A continuación
se describen algunos de ellos.

2.7.1 Sentencia wait


El método más sencillo de modelar un retardo es emplear la sentencia wait,
indicando el número de unidades de tiempo que debe durar la espera. Por ejemplo,
la sentencia:

wait for 10 ns;

dentro de un bloque process, hace que la ejecución del bloque se detenga durante
10 nanosegundos.
Pueden usarse otras formas de la sentencia wait. Por ejemplo, la sentencia:

wait;

dentro de un bloque process, hace que éste se quede esperando indefinidamente,


con lo cual se detiene la ejecución del bloque.
Capı́tulo 2 Conceptos básicos de VHDL 39

Asimismo, las construcciones:

wait until <condición>;


wait until <lista de se~
nales>;

dentro de un bloque process, detienen la ejecución del bloque hasta que la


condición booleana se haga verdadera, o hasta que alguna de las señales de la
lista cambie de valor, respectivamente.
Si la sentencia:

wait until <lista de se~


nales>;

es la primera sentencia de un bloque process (esta en concreto es la única forma


de uso de la sentencia wait permitida para sı́ntesis), entonces es equivalente a
usar <lista de se~nales> como la lista de señales a las que el bloque process es
sensible.

2.7.2 Retardos en la asignación a señales


Pueden especificarse retardos en las asignaciones a señales usando la palabra
reservada after. Por ejemplo, puede modelarse el comportamiento de una puerta
NAND con un retardo de propagación de 2 ns mediante la sentencia:

y <= x0 nand x1 after 2 ns;

Cuando se encuentra esta sentencia en la simulación, se emplean los valores


actuales de x0 y x1 para calcular el resultado de la operación x0 nand x1. Este
resultado no se asigna a y hasta transcurridos 2 ns.
Sin embargo, esto no implica que la siguiente sentencia no sea ejecutada
hasta que transcurran los 2 ns. Al contrario, la siguiente sentencia es ejecutada
inmediatamente, aun cuando estas sentencias sean parte de un bloque process.
Ası́ pues, el cambio en la señal y no habrá ocurrido en el instante en el cual se
ejecute la siguiente sentencia.
Para especificar que la simulación se detenga durante un periodo de tiempo
antes de que la siguiente sentencia sea ejecutada, debe usarse el comando wait.

2.7.3 Retardo inercial y de transporte


Cuando se realiza una descripción jerárquica del circuito, cobran importancia los
conceptos de retardo inercial y retardo de transporte.
Un dispositivo lógico real tiene la propiedad de que un glitch en un puerto
de entrada, con una duración inferior al retardo de propagación del dispositivo,
no tiene efecto sobre la salida del dispositivo. Se denomina glitch a un cambio
temporal (un pico de subida o bajada) e inesperado en el voltaje.
Por ejemplo, si una puerta NAND tiene un retardo de propagación de 1 ns,
entonces un glitch de 0.5 ns (un 0 ó 1 temporal, de duración 0.5 ns) en una de
sus entradas no produce ningún cambio en su salida.
40 A. Urquı́a, C. Martı́n Villalba Casos Prácticos de Diseño de Circuitos Digitales con VHDL

Este tipo de comportamiento del retardo se denomina retardo inercial y es el


modelo del retardo usado por defecto para todos los dispositivos en VHDL.
Otro tipo alternativo de modelo del retardo, en el cual todos los glitches a
la entrada se manifiestan en la salida, se denomina retardo de transporte. Este
tipo de comportamiento se modela usando la palabra clave transport tras el
operador de asignación (<=).
El modo recomendado de modelar el retardo en el código VHDL sintetizable
es el retardo inercial.

2.7.4 Retardo delta


Es importante tener en cuenta que todas las operaciones que involucran señales
poseen un retardo, dado que todas las señales en los circuitos fı́sicos experimentan
retardos cuando pasan a través de los dispositivos y las conexiones.
En vista de ello, aunque no se especifique de manera explı́cita en el código
VHDL el retardo, todas las señales son simuladas sometiéndolas a un retardo en
cada operación de asignación o instanciación de un subcircuito.
Ası́ pues, cuando se ejecuta una sentencia en la que se asigna un nuevo
valor a una señal, se aplica por defecto un retardo de valor delta. Es decir, un
retardo infinitesimal, inferior al incremento de tiempo más pequeño que puede
ser especificado en VHDL, que es un femtosegundo (1 fs = 10−15 s).
Como consecuencia de este método de retardo delta empleado en la simula-
ción, cuando se asigna un valor a una señal en VHDL, hay dos eventos de interés:

1. Se calcula el nuevo valor y se planifica el cambio en la señal.

2. Transcurrido un tiempo delta, se asigna a la señal su nuevo valor.

Este comportamiento no tiene un efecto apreciable para las sentencias de


asignación que están fuera de bloques process, que en cualquier caso se ejecutan
concurrentemente.
Sin embargo, tiene un efecto importante en las asignaciones a señales que
están dentro de bloques process:

1. Se planifica el cambio en la señal antes de que se ejecute la siguiente


sentencia.

2. El cambio en el valor de la señal debido a la primera sentencia ocurre después


de que se haya planificado el cambio debido a la siguiente sentencia, para
lo cual se usan los valores de las señales en el instante actual.

Ası́ pues, una cadena de asignaciones a señales contenida en un bloque pro-


cess se comporta de manera diferente a un conjunto de sentencias en un lenguaje
de programación. Por ejemplo, suponga el siguiente fragmento de código VHDL:

process (clk) is
begin
if rising_edge(clk) then
b <= a;
Capı́tulo 2 Conceptos básicos de VHDL 41

c <= b;
...

Puesto que b y c son señales, existe un retardo delta antes de que se produzca
la asignación del nuevo valor a b. Antes de que transcurra este retardo, se calcula
el nuevo valor de la variable c, usándose para ello el valor “antiguo” de b. En este
ejemplo, la señal c adquiere el valor que tenı́a la señal b en el anterior ciclo de
reloj, dado que el proceso es activado únicamente en los flancos de subida de la
señal de reloj.
La discusión anterior acerca del retardo delta no aplica a las asignaciones a
variables. De hecho, ni siquiera es posible asociar un retardo a una asignación
a una variable (no pueden usarse sentencias de la forma a := b after c ns;).
Las asignaciones a variables ocurren inmediatamente, sin retardos delta, lo cual es
razonable considerando que las variables en VHDL están ideadas para ser usadas
como las variables de los programas de los lenguajes de programación.
Ası́ pues, dada una cadena de asignaciones a variables contenida dentro de
un bloque process, estas asignaciones a variables se realizan de manera estric-
tamente secuencial (de la misma forma que se ejecutan las sentencias en C o en
Fortran).

2.7.5 Caso práctico


El modelo mostrado a continuación pretende ilustrar los conceptos relacionados
con el retardo expuestos en esta sección, ası́ como la diferencia entre las señales
y las variables en lo que respecta al retardo.
En primer lugar, se muestra el código de una puerta NAND con un retardo
inercial del 2 ns, y a continuación el código del banco de pruebas.

-------------------------------------
-- Puerta NAND con retardo inercial
library IEEE;
use IEEE.std_logic_1164.all;

entity nand2 is port


( y0 : out std_logic;
x0, x1 : in std_logic);
end entity nand2;

architecture nand2 of nand2 is


begin
y0 <= x0 nand x1 after 2 ns; -- Retardo inercial de 2 ns
end architecture nand2;
-------------------------------------
42 A. Urquı́a, C. Martı́n Villalba Casos Prácticos de Diseño de Circuitos Digitales con VHDL

-------------------------------------------
-- Banco de pruebas de diferentes retardos
library IEEE;
use IEEE.std_logic_1164.all;

entity retardo_bp is
end entity retardo_bp;

architecture retardo_bp of retardo_bp is


signal s1, s2, s3, s4 : std_logic;
signal in1, in2 : std_logic;
component nand2 is port
( y0 : out std_logic;
x0, x1 : in std_logic);
end component nand2;
begin
-- Crear el UUT para el test
g0 : component nand2 port map (s1, in1, in2);
s2 <= in1 nand in2 after 2 ns; -- Misma forma de onda que s1
process is
variable var1, var2 : std_logic;
begin
for i in 0 to 4 loop -- Itera 5 veces
var1 := in1 nand in2;
var2 := var1; -- var2 debe ser igual a var1
s3 <= in1 nand in2;
s4 <= s3; -- s4 debe ser igual al valor
-- antiguo de s3
wait for 10 ns; -- Repetir para 0, 10, 20, 30 y 40 ns
end loop;
wait; -- Detiene el proceso
end process;

-- Crear los vectores de test


in1 <= ’1’;
in2 <= ’0’, -- in2 comienza a 0
’1’ after 10 ns, ’0’ after 11 ns, -- Pulso de 1 ns
-- en el instante 10 ns
’1’ after 20 ns, ’0’ after 22 ns, -- Pulso de 2 ns
-- en el instante 20 ns
’1’ after 26 ns, ’0’ after 29 ns; -- Pulso en el instante 26 ns
end architecture retardo_bp;
-------------------------------------------
Capı́tulo 2 Conceptos básicos de VHDL 43

Las formas de onda obtenidas de la simulación se muestran en la Figura 2.5.


La señal in2 comienza con el valor 0 y tiene pulsos en los instantes 10, 20 y 26
ns. Sin embargo, el pulso en el instante 10 ns es más corto que el retardo de
propagación de la puerta NAND y de la asignación a la señal s2. Por ello, las
señales s1 y s2 ignoran ese pulso.

Figura 2.5: Formas de onda obtenidas de simular el banco de pruebas.

Debido al retardo de 2 ns, el valor de las señales s1 y s2 no está definido


hasta el instante 2 ns. Por ello, estas señales inicialmente tienen el valor U.
Inicialmente, la señal s3 está indefinida. Toma el valor 0 en el instante 10 + ∆
ns, puesto que in1 e in2 valen 1 en el instante 10 ns. Finalmente, cambia al valor
1 en el instante 30 + ∆ ns.
La señal s4 va un ciclo retrasada respecto a s3.
La variable var1 toma los mismos valores que s3, excepto que la variable var1
no tiene el retardo delta (∆) de la variable s3.
La variable var2 toma los mismos valores que la variable var1.

2.8 Assert
La sentencia assert se usa para hacer comprobaciones de condiciones lógicas que,
dado el valor esperado en ese punto del estado del programa, deberı́an valer true.
Se emplea frecuentemente para depurar el código. Su sintaxis es:

assert <condición_booleana> report <string>


severity <valor>;

Mientras la condición booleana es true, la sentencia no realiza ninguna acción.


Cuando la condición se hace false, la sentencia muestra el texto <string> en la
consola.
La clausula severity se usa para indicar qué gravedad tiene la violación de
la condición booleana. Posibles valores de <valor> son:

note No es un error.
warning Aviso.
error Error.
failure Error severo que hace que termine la simulación.
44 A. Urquı́a, C. Martı́n Villalba Casos Prácticos de Diseño de Circuitos Digitales con VHDL

2.9 Procedimientos y funciones


Dos construcciones que pueden ser útiles en la descripción de las arquitecturas
son los procedimientos (bloques procedure) y las funciones (function), ya que
contribuyen a hacer el código VHDL más legible, portable y compacto.
Las funciones son usadas como operadores en las sentencias de asignación,
mientras que los procedimientos son usandos de forma más general, para describir
tareas que deben ejecutarse concurrentemente o tareas contenidas en bloques
process.
Las funciones y los procedimientos deben ser definidos dentro de la sección
de declaración de una architecture o de un bloque process. Es decir, tras la
sentencia architecture o process y antes del begin de esa arquitectura o bloque
process.
Los bloques procedure permiten a los diseñadores manejar pequeños frag-
mentos de código reutilizable. Algunas de sus caracterı́sticas más destacables son
las siguientes:

– Desde dentro de un procedimiento se puede acceder a todas las señales,


variables y constantes del bloque desde el que es llamado el procedimiento.

– Pueden pasarse argumentos (variables o señales) al procedimiento, que


pueden ser in, out e inout.

· Puede modificarse en el procedimiento el valor de los argumentos decla-


rados como out o inout, pero no el valor de los argumentos declarados
como in.
· Puede leerse en el procedimiento el valor de los argumentos declarados
como in o inout, pero no puede leerse dentro del procedimiento el
valor de los argumentos declarados como out.
· Si no se especifica la dirección de un argumento del procedimiento, se
asume por defecto que es in.
· Un argumento out o inout es por defecto una variable, a menos que
se indique explı́citamente que es una señal.
· Se considera que un argumento in es una constante dentro del bloque
del procedimiento. No obstante, si el argumento in es una señal, enton-
ces los cambios que se produzcan en la señal fuera del procedimiento se
producirán igualmente en el valor de la señal dentro del procedimiento.

– Dentro de un procedimiento pueden definirse variables locales, a las que no


se puede acceder desde fuera del procedimiento.

– A excepción del uso de las variables locales, el efecto de usar un proce-


dimiento es equivalente a reemplazar la llamada al procedimiento por el
código del procedimiento.

Las dos diferencias fundamentales entre los procedimientos y las funciones en


VHDL son las siguientes:
Capı́tulo 2 Conceptos básicos de VHDL 45

– La función debe devolver un valor al código que la llama.

– Los argumentos de la función deben ser de tipo in, con lo cual no es necesario
especificar su dirección.

El caso práctico descrito en la Sección 3.4 ilustra el empleo de procedimientos


y funciones.
Casos prácticos de diseño de
3
circuitos combinacionales

Objetivos. Una vez estudiado el contenido del tema deberı́a saber:


– Diseñar circuitos lógicos combinacionales empleando VHDL, tales como fun-
ciones lógicas, multiplexores, sumadores y restadores binarios, buses, ALUs,
conversores de código y decodificadores, describiendo el comportamiento y/o
la estructura del circuito.
– Diseñar y simular bancos de pruebas para circuitos combinacionales.

3.1 Síntesis de lógica combinacional


Cuando el objetivo de la descripción del circuito mediante VHDL es la sı́ntesis,
es útil saber cómo escribir código VHDL para crear determinadas estructuras
circuitales.
El comportamiento y las salidas de un bloque lógico combinacional dependen
únicamente del valor actual de las entradas. No dependen del valor pasado de las
entradas, ni tampoco del estado.
Ası́ pues, el código VHDL que describe un circuito combinacional no de-
be tener “historia”, ni tampoco debe describir dependencia respecto al estado.
También, debe evitarse incluir retardos temporales en la descripción VHDL del
circuito, ya que los retardos del circuito real serán dependientes del hardware en
particular que se emplee para implementar el circuito.
Existen varios métodos para describir circuitos combinacionales en VHDL.
De hecho, el mismo tipo de circuito puede ser descrito empleando diferentes
sentencias VHDL. Por ejemplo, un multiplexor 2:1 puede definirse indicando su
estructura (conexión de las correspondientes puertas lógicas) o describiendo su
48 A. Urquı́a, C. Martı́n Villalba Casos Prácticos de Diseño de Circuitos Digitales con VHDL

comportamiento, mediante una sentencia concurrente de asignación a una señal,


tal como:
out <= in1 when (sel=’1’) else in0;
A continuación, se describe un método para la descripción de circuitos combi-
nacionales que es sencillo de entender, aplicable de manera general y ampliamente
usado.

3.1.1 Empleo de sentencias concurrentes


Los circuitos lógicos combinacionales pueden ser descritos empleando sentencias
concurrentes de asignación a señales. Este tipo de sentencias modelan de manera
correcta el comportamiento de los dispositivos combinacionales, que están activos
durante todo el tiempo de manera concurrente.

– En la parte izquierda de una sentencia de asignación concurrente debe


aparecer, o bien una señal local de la architecture, o bien una señal de la
interfaz (definida en la entity) del tipo out o inout.

– En la parte derecha de la asignación concurrente pueden aparecer señales


locales de la architecture y también señales de la interfaz, del tipo in o
inout.

Las herramientas de sı́ntesis pueden sintetizar las puertas lógicas simples a


partir de las operaciones lógicas primitivas de VHDL. A continuación, se muestran
dos ejemplos:

Puerta NAND nand_out <= i0 nand i1;


Puerta OR-exclusiva xor_out <= i0 xor i1;

También, pueden sintetizarse arrays de puertas lógicas a partir de este mis-


mo tipo de sentencias. Por ejemplo, la siguiente sentencia describe un array de
inversores:
Array de inversores inv_vec <= not i0_vec;
donde inv_vec e i0_vec son std logic vector.

El que la herramienta de sı́ntesis cree una única puerta lógica o un array de


puertas lógicas, depende del tipo de señales usadas en la sentencia de asignación
concurrente. Por ejemplo, las siguientes sentencias dan lugar a un buffer triestado
y a un array de buffers triestado, respectivamente.

Buffer triestado tri_out <= i0 when (sel=’1’) else ’Z’;


Array de buffers triestado tri_vec <= i0_vec when (sel=’1’)
else (others => ’Z’);
donde tri_vec e i0_vec son std logic vector.

Es posible sintetizar multiplexores y decodificadores que están descritos me-


diante sentencias condicionales del tipo siguiente:
Capı́tulo 3 Casos prácticos de diseño de circuitos combinacionales 49

Decodificador 2:4 dec_vec <= "0001" when (sel_vec = "00")


else "0010" when (sel_vec = "01")
else "0100" when (sel_vec = "10")
else "1000";

y también es posible emplear sentencias with, por ejemplo:

Multiplexor 4:1 with sel_vec select


mux41_out <= i0 when "00",
i1 when "01",
i2 when "10",
i3 when others;

De hecho, es preferible usar cláusulas with para describir multiplexores y


decodificadores, ya que el empleo de cláusulas condicionales puede dar lugar
a la sı́ntesis de circuitos innecesariamente complejos. Esto es debido a que las
condiciones de las cláusulas condicionales en general no tienen que ser excluyentes
entre sı́, cosa que sı́ sucede siempre con las condiciones de las cláusulas with.
Es posible también realizar una descripción del circuito basada únicamente
en la operación que se desea que realice. Por ejemplo:

Multiplexor 4:1 mux41_out <= i0_vec( TO_INTEGER(unsigned(sel_vec)) );


donde i0_vec y sel_vec son std logic vector.

donde se emplean las funciones de conversión de tipo TO INTEGER y unsig-


ned, que están definidas en el package IEEE.numeric std.
Finalmente, los circuitos que realizan operaciones aritméticas pueden ser des-
critos aplicando las correspondientes operaciones aritméticas a los tipos de datos
adecuados. Por ejemplo, los operandos std logic vector deben ser convertidos
a unsigned antes de emplear los operandos suma o multiplicación. Por ejemplo:

Sumador add_uvec <= unsigned(i0_vec) + i1_uvec;


donde i1_uvec y add_uvec son unsigned.
Multiplicador mult_uvec <= unsigned(i0_vec) * i1_uvec;
donde i1_uvec y mult_uvec son unsigned.

Sin embargo, este tipo de descripción da lugar a la sı́ntesis de los tipos estándar
de circuitos aritméticos. Dependiendo de la opción seleccionada en la sı́ntesis, las
unidades aritméticas sintetizadas pueden ser circuitos lentos que usan un número
pequeño de puertas lógicas (si se escoge la opción “optimizar el área”) o bien
circuitos rápidos que utilizan gran número de puertas lógicas (se se escoge la
opción “optimizar la velocidad”).
Para crear tipos especı́ficos de unidades aritméticas, tales como tipos especia-
les de sumadores o multiplicadores rápidos, puede ser necesario describirlos o bien
indicando su estructura, o bien mediante una descripción de su comportamiento
a más bajo nivel, tal como se explica a continuación.
50 A. Urquı́a, C. Martı́n Villalba Casos Prácticos de Diseño de Circuitos Digitales con VHDL

3.1.2 Empleo de bloques process


Aunque las sentencias concurrentes de asignación a señal son útiles para crear
estructuras combinacionales simples, es necesario disponer de otro método para
crear circuitos más complejos. En concreto, cierto número de cláusulas de VHDL
(tales como if, case, for, etc.) sólo pueden ser usadas dentro de bloques process.
Los bloques process pueden ser usados para describir lógica combinacional.
Para que el circuito resultante de la sı́ntesis sea combinacional, deben respetarse
las siguientes reglas:

1. Todas las entradas del circuito deben estar incluidas en la lista de señales
a las que es sensible el bloque process.

2. Ninguna otra señal debe estar incluida en dicha lista.

3. Ninguna de las sentencias internas al bloque process debe ser sensible al


flanco de subida o de bajada de ninguna señal.

A continuación, se muestran varios ejemplos sencillos de diseño de circuitos


combinacionales, empleando tanto sentencias concurrentes como bloques pro-
cess.

3.2 Funciones lógicas


En esta sección se describe el modelado de dos funciones lógicas y de su banco
de pruebas. Las dos funciones lógicas (F y G), que dependen de 3 variables (a, b
y c), son las siguientes:

F = a and b or not c
G = a and b or not b and c

3.2.1 Modelado de las funciones lógicas


A continuación se muestra el código VHDL que describe las funciones lógicas.
Obsérvese que el orden en el cual deben realizarse las operaciones booleanas
debe indicarse explı́citamente mediante paréntesis en el código VHDL (en caso
contrario se obtiene error). Es decir, las funciones lógicas deben escribirse de la
forma siguiente:

F = ( a and b ) or not c
G = ( a and b ) or ( not b and c )

--------------------------------------
-- Funciones lógicas:
-- F = ab + c’
-- G = ab + b’c
Capı́tulo 3 Casos prácticos de diseño de circuitos combinacionales 51

library IEEE; use IEEE.std_logic_1164.all;

entity funcLog_F_G is port


( F, G : out std_logic;
a, b, c : in std_logic );
end entity funcLog_F_G;

architecture funcLog_F_G of funcLog_F_G is


begin
F <= (a and b) or not c;
G <= (a and b) or (not b and c);
end architecture funcLog_F_G;
--------------------------------------

La interfaz externa del circuito que implementa las funciones lógicas es des-
crita en la entity llamada funcLog_F_G. En ella se declaran los dos puertos de
salida (F, G) seguidos de los tres puertos de entrada (a, b, c). Todos los puertos
son del tipo std logic ya que representan señales transmitidas por el cableado
de los circuitos.
La definición de la architecture comienza especificando el nombre de la
entity. En este caso, se ha dado el mismo nombre a la entity y a la architecture.
En general se les puede dar nombres diferentes.
En el cuerpo de la architecture (es decir, a continuación de la palabra
reservada begin) se describe cómo se calculan los puertos de salida a partir de
los puertos de entrada.

3.2.2 Programación del banco de pruebas


Una vez modelado el circuito, debe programarse su banco de pruebas. Puesto que
el banco de pruebas no va a ser sintetizado, puede emplearse para su programa-
ción cualquier instrucción VHDL disponible (incluso aquellas que darı́an lugar
a circuitos no sintetizables). Instrucciones útiles de este tipo son wait, assert y
report, que permiten controlar el progreso de la simulación, comprobar y mostrar
sus resultados.
En este caso, la finalidad del banco de pruebas es únicamente generar las
23 posibles entradas al circuito. Normalmente, los propios programas de test
contienen los algoritmos necesarios para determinar si las salidas del circuito
son las esperadas y muestran los correspondientes mensajes en aquellos casos en
que no lo sean. Por simplicidad, en este caso esta labor la asume el diseñador.
Es decir, observando las señales de salida del circuito y comparando con la tabla
de la verdad de las funciones lógicas, el diseñador determina si el funcionamiento
del circuito es el esperado.
Como programa VHDL, el banco de pruebas es un tipo especial de pareja
entity-architecture, que no tiene ni entradas ni salidas externas. Por este
motivo, la entity del banco de pruebas no contiene ningún puerto.
52 A. Urquı́a, C. Martı́n Villalba Casos Prácticos de Diseño de Circuitos Digitales con VHDL

Internamente, el banco de pruebas tiene conexiones al UUT. Se han definido


señales internas al banco de pruebas para todas las conexiones al UUT:

signal y0, y1 : std_logic; -- Conectar salidas UUT


signal x0, x1, x2 : std_logic; -- Conectar entradas UUT

La conexión del UUT en el banco de pruebas se realiza instanciando el UUT


como un subcircuito dentro del banco de pruebas. En este caso, la conexión se
realiza nombrando explı́citamente los puertos:

uut : component funcLog_F_G port map


( F => y0, G => y1,
a => x0, b => x1, c => x2 );

Obsérvese que la señal y su puerto asociado son incluidos en la lista de


parámetros de la forma siguiente:

puerto => se~


nal

La architecture del banco de pruebas contiene un proceso (bloque process)


en el cual se generan los vectores de test y se introducen como entradas del UUT.
A continuación, se muestra el código VHDL del banco de pruebas.

--------------------------------------
-- Banco de pruebas
library IEEE;
use IEEE.std_logic_1164.all;
use IEEE.numeric_std.all;

entity bp_funcLog_F_G is
end entity bp_funcLog_F_G;

architecture bp_funcLog_F_G of bp_funcLog_F_G is


signal y0, y1 : std_logic; -- Conectar salidas UUT
signal x0, x1, x2 : std_logic; -- Conectar entradas UUT

component funcLog_F_G is port


( F, G : out std_logic;
a, b, c : in std_logic);
end component funcLog_F_G;

begin
-- Instanciar y conectar UUT
uut : component funcLog_F_G port map
( F => y0, G => y1,
a => x0, b => x1, c => x2 );
gen_vec_test : process
Capı́tulo 3 Casos prácticos de diseño de circuitos combinacionales 53

variable test_in : unsigned (2 downto 0); -- Vector de test


begin
test_in := B"000";
for count in 0 to 7 loop
x2 <= test_in(2);
x1 <= test_in(1);
x0 <= test_in(0);
wait for 10 ns;
test_in := test_in + 1;
end loop;
wait;
end process gen_vec_test;
end architecture bp_funcLog_F_G;
--------------------------------------

El bloque process se emplea para encapsular una secuencia de sentencias que


serán ejecutadas secuencialmente. En el código del banco de pruebas, el bloque
process tiene la estructura siguiente:

gen_vec_test : process
variable ...
begin
...
end process gen_vec_test;

donde las variables se declaran antes de la palabra reservada begin, y las senten-
cias a ejecutar secuencialmente se escriben a continuación de la palabra begin.
Una variable (variable) es conceptualmente diferente a una señal (signal),
puesto que la variable puede no corresponder con una señal fı́sica. La variable
simplemente se usa como ayuda en la descripción de la operación del circuito. La
asignación a una variable se representa mediante :=, mientras que la asignación
a una señal se representa mediante <=.
En el código del banco de pruebas, la variable test_in se usa para almacenar
en un mismo vector de tres bits las entradas al UUT, de modo que este vector
pueda ser incrementado (con el fin de generar todas las posibles combinaciones de
vectores de test) empleando un bucle for. Observa que la variable test_in se ha
declarado de tipo unsigned ya que se emplea para realizar operaciones aritméticas.
La longitud del vector se especifica por el rango (2 downto 0). El primer número
del rango (2) indica el ı́ndice del bit más significativo del vector, y el segundo
número del rango (0) indica el ı́ndice del bit menos significativo del vector.
La sentencia for en VHDL tiene el formato siguiente:

for <variable> in <rango> loop


...
end loop;

donde <variable> es una nueva variable temporal, con un rango entero (<rango>),
que no necesita ser definida previamente.
54 A. Urquı́a, C. Martı́n Villalba Casos Prácticos de Diseño de Circuitos Digitales con VHDL

La sentencia wait se emplea para esperar durante un número determinado de


unidades de tiempo. En el código del banco de pruebas, se emplea

wait for 10 ns;

para esperar hasta que el UUT pueda producir las salidas correspondientes a las
entradas aplicadas. En este caso, podrı́a haberse escogido cualquier otro tiempo
de espera, ya que en el modelo del UUT no se especificó ningún retardo.
La segunda sentencia wait, que está situada al final de código, no tiene
ninguna indicación acerca del tiempo que hay que esperar. Este tipo de sentencia
wait se emplea para detener el proceso, ya que “espera para siempre”.
Como resultado de la simulación del banco de pruebas, se obtienen las formas
de onda mostradas en la Figura 3.1.

Figura 3.1: Formas de onda obtenidas de simular el banco de pruebas.

3.3 Multiplexor de 4 entradas

En la Figura 3.2 se muestra un multiplexor de 4 entradas (i3, i2, i1, i0), dos
entradas de selección (s1, s0) y una salida (d). En esta sección se describen
diferentes maneras de modelar el multiplexor, ası́ como bancos de pruebas que
permite simular tests sobre los modelos del circuito.
ghi jkl

i0
i1
d
i2
i3 s0 s1

Figura 3.2: Multiplexor de 4 entradas.


Capı́tulo 3 Casos prácticos de diseño de circuitos combinacionales 55

3.3.1 Bloque process, sentencia if


A continuación, se muestra el código VHDL del MUX 4:1 que describe el com-
portamiento del multiplexor mediante una sentencia if incluida en un bloque
process.

--------------------------------------
-- MUX 4x1
library IEEE; use IEEE.std_logic_1164.all;

entity mux_4x1 is port


( d : out std_logic;
i3, i2, i1, i0 : in std_logic;
s1, s0 : in std_logic );
end entity mux_4x1;

architecture mux_4x1 of mux_4x1 is


begin
process (i3, i2, i1, i0, s1, s0)
begin
if (s1=’0’and s0=’0’) then
d <= i0;
elsif (s1=’0’and s0=’1’) then
d <= i1;
elsif (s1=’1’and s0=’0’) then
d <= i2;
else
d <= i3;
end if;
end process;
end architecture mux_4x1;
--------------------------------------

Obsérvese que el bloque process es sensible a las señales i3, i2, i1, i0, s1,
s0. Esto significa que se ejecutará el contenido del bloque cada vez que alguna
de estas señales cambie de valor.
A continuación, se muestra el código de un banco de prueba que aplica algunos
vectores de test al multiplexor (es sólo un pequeño ejemplo, no se trata de un
programa de test exhaustivo para este circuito).

--------------------------------------
-- Banco de pruebas
library IEEE;
use IEEE.std_logic_1164.all;
56 A. Urquı́a, C. Martı́n Villalba Casos Prácticos de Diseño de Circuitos Digitales con VHDL

use IEEE.numeric_std.all;

entity bp_mux_4x1 is
end entity bp_mux_4x1;

architecture bp_mux_4x1 of bp_mux_4x1 is


signal d : std_logic; -- Conectar salida UUT
signal i0, i1, i2, i3,
s0, s1 : std_logic; -- Conectar entradas UUT

component mux_4x1 is port


( d : out std_logic;
i3, i2, i1, i0 : in std_logic;
s1, s0 : in std_logic );
end component mux_4x1;

begin
-- Instanciar y conectar UUT
uut : component mux_4x1 port map
( d => d,
i0 => i0, i1 => i1, i2 => i2, i3 => i3,
s0 => s0, s1 => s1 );
gen_vec_test : process
begin
i0 <= ’0’; i1 <= ’0’; i2 <= ’1’; i3 <= ’0’;
s0 <= ’0’; s1 <= ’0’;
wait for 5 ns;
i0 <= ’1’;
wait for 5 ns;
s0 <= ’1’;
wait for 10 ns;
s0 <= ’0’; s1 <= ’1’;
wait for 10 ns;
s0 <= ’1’;
wait;
end process gen_vec_test;
end architecture bp_mux_4x1;
--------------------------------------

En la Figura 3.3a se muestran las formas de onda obtenidas al simular el


banco de pruebas.
Un error que se comete a veces consiste en olvidar incluir en la lista
alguna de las variables a las que es sensible el bloque process. La consecuencia
de este error es que el bloque process no se ejecutará cuando cambie el valor de
Capı́tulo 3 Casos prácticos de diseño de circuitos combinacionales 57

la variable no incluida en la lista, con lo cual el modelo simulado no reproducirá


correctamente el circuito real.
Por ejemplo, supongamos que en el modelo del multiplexor no se incluyen las
entradas i3, i2, i1, i0 en la lista de variables a las que es sensible el bloque
process. Es decir, supongamos que por error la architecture del multiplexor se
define de la forma siguiente:

--------------------------------------
-- MUX 4x1
-- ERROR al definir la sensibilidad del bloque process
architecture mux_4x1 of mux_4x1 is
begin
process (s1, s0) -- Error: no se incluyen i3,i2,i1,i0
begin
if (s1=’0’and s0=’0’) then
d <= i0;
elsif (s1=’0’and s0=’1’) then
d <= i1;
elsif (s1=’1’and s0=’0’) then
d <= i2;
else
d <= i3;
end if;
end process;
end architecture mux_4x1;
--------------------------------------

Este modelo no reproduce adecuadamente el comportamiento de un multi-


plexor, como puede observarse en la Figura 3.3b. Obsérvese que es este caso la
salida d no reproduce el cambio en el valor de la entrada i0 que se produce en
el instante 5 ns. En el instante 5 ns la entrada i0 pasa de valer ’0’ a valer ’1’,
mientras que el valor de la salida d no cambia: sigue siendo ’0’. Esto es debido a
que el cambio en el valor de i0 no dispara la ejecución del bloque process, con
lo cual el valor de la salida no se actualiza al nuevo valor de la entrada i0.

3.3.2 Bloque process, sentencias if y case


A continuación, se muestra el código VHDL del MUX 4:1 que describe el com-
portamiento del multiplexor mediante sentencias if y case incluidas en un bloque
process.

--------------------------------------
-- MUX 4x1
library IEEE; use IEEE.std_logic_1164.all;
58 A. Urquı́a, C. Martı́n Villalba Casos Prácticos de Diseño de Circuitos Digitales con VHDL

mn

on

Figura 3.3: Formas de onda obtenidas de simular el banco de pruebas:


a) modelo del multiplexor correcto; b) modelo del multiplexor erróneo.

entity mux_4x1 is port


( d : out std_logic;
i3, i2, i1, i0 : in std_logic;
s1, s0 : in std_logic );
end entity mux_4x1;

architecture mux_4x1 of mux_4x1 is


begin
process (i3, i2, i1, i0, s1, s0)
variable sel : integer;
begin
if (s1=’0’and s0=’0’) then
sel := 0;
elsif (s1=’0’and s0=’1’) then
sel := 1;
elsif (s1=’1’and s0=’0’) then
sel := 2;
else
sel := 3;
end if;
case sel is
when 0 =>
d <= i0;
when 1 =>
d <= i1;
when 2 =>
Capı́tulo 3 Casos prácticos de diseño de circuitos combinacionales 59

d <= i2;
when others =>
d <= i3;
end case;
end process;
end architecture mux_4x1;
--------------------------------------

3.3.3 Sentencias concurrentes


A continuación, se muestra la descripción del circuito multiplexor usando una
sentencia concurrente, en la cual se asigna valor a la señal d en función del valor
que tomen las entradas al circuito.

--------------------------------------
-- MUX 4x1
library IEEE; use IEEE.std_logic_1164.all;

entity mux_4x1 is port


( d : out std_logic;
i3, i2, i1, i0 : in std_logic;
s1, s0 : in std_logic );
end entity mux_4x1;

architecture mux_4x1_concurrente of mux_4x1 is


begin
d <= i0 when (s1=’0’and s0=’0’) else
i1 when (s1=’0’and s0=’1’) else
i2 when (s1=’1’and s0=’0’) else
i3;
end architecture mux_4x1_concurrente;
--------------------------------------

Con el fin de ilustrar el empleo de señales del tipo integer, a continuación


se muestra una variación del modelo anterior en el cual se describe el comporta-
miento del circuito mediante dos sentencias concurrentes. En la primera, se asigna
valor a la señal integer sel en función del valor de las entradas de selección. En
la segunda, se asigna valor a la salida del circuito en función de las entradas de
datos y del valor de la señal entera. A continuación se muestra el código.

--------------------------------------
-- MUX 4x1
library IEEE; use IEEE.std_logic_1164.all;
60 A. Urquı́a, C. Martı́n Villalba Casos Prácticos de Diseño de Circuitos Digitales con VHDL

Figura 3.4: Formas de onda obtenidas de simular el banco de pruebas,


empleando la descripción del comportamiento del multiplexor.

entity mux_4x1 is port


( d : out std_logic;
i3, i2, i1, i0 : in std_logic;
s1, s0 : in std_logic );
end entity mux_4x1;

architecture mux_4x1_concurrente of mux_4x1 is


signal sel : integer;
begin
sel <= 0 when (s1=’0’and s0=’0’) else
1 when (s1=’0’and s0=’1’) else
2 when (s1=’1’and s0=’0’) else
3;
d <= i0 when sel = 0 else
i1 when sel = 1 else
i2 when sel = 2 else
i3;
end architecture mux_4x1_concurrente;
--------------------------------------

En la Figura 3.4 se muestran las formas de onda resultado de la simulación.

3.4 Restador completo de 1 bit


En esta sección se describe el modelado de un circuito restador completo de 1
bit y de su banco de pruebas. Emplearemos este caso de estudio para introducir
algunos conceptos nuevos.
VDHL permite describir la architecture de un circuito mediante su com-
portamiento y también mediante su estructura, es decir, indicando cómo están
conectados los subcircuitos que lo componen. En primer lugar se realizará una
descripción del circuito basada en el comportamiento y, a continuación, se hará
una descripción basada en su estructura.
Capı́tulo 3 Casos prácticos de diseño de circuitos combinacionales 61

3.4.1 Descripción del comportamiento


A continuación se muestra la tabla de la verdad del circuito restador de 1 bit.
Este circuito calcula el resultado (res) y el acarreo (acarreo) obtenidos de realizar
la resta (a–b) de dos bits (a,b).

a b res acarreo
0 0 0 0
0 1 1 1
1 0 1 0
1 1 0 0

Un circuito restador completo de 1 bit tiene una entrada adicional: el acarreo


de entrada. Conectando varios de estos circuitos, puede obtenerse un restador de
números de varios bits. A continuación, se muestra el código VHDL de un restador
completo de 1 bit. Obsérvese que la architecture describe el funcionamiento del
circuito, sin entrar en detalles acerca de su implementación.

-----------------------------------------
-- Restador completo de 1 bit
library IEEE;
use IEEE.std_logic_1164.all;
use IEEE.numeric_std.all;

entity rest_completo is port


( res, acarreo_out : out std_logic;
a, b, acarreo_in : in std_logic);
end entity rest_completo;

architecture rest_completo_comport of rest_completo is


signal result : unsigned ( 1 downto 0 );
begin
result <= (’0’ & a) - (’0’ & b) - (’0’ & acarreo_in);
acarreo_out <= result(1);
res <= result(0);
end architecture rest_completo_comport;
-----------------------------------------

La interfaz externa del restador completo es descrita en la entity llamada


rest_completo. En ella se definen los dos puertos de salida (res, acarreo_out)
seguidos de los tres puertos de entrada (a, b, acarreo_in). Todos los puertos de
entrada y de salida se definen del tipo std logic, con el fin de facilitar el uso del
restador como subcircuito en otros circuitos: se emplean señales del tipo std logic
y std logic vector para modelar las señales transmitidas por el cableado de los
circuitos fı́sicos.
62 A. Urquı́a, C. Martı́n Villalba Casos Prácticos de Diseño de Circuitos Digitales con VHDL

La definición de la architecture incluye el nombre de la entity. Se define


una señal del tipo unsigned de 2 bits (llamada result), con el fin de almacenar
el resultado de la operación de sustracción. Al declararla, se indica que la señal
tiene 2 bits, especificando para ello su rango: ( 1 downto 0 ). Si no se especifica
el rango, las señales del tipo unsigned tienen por defecto 32 bits.
El tipo de la señal debe ser unsigned, a fin de permitir el uso del operador
sustracción (–).
Las señales de entrada, de 1 bit, deben ser extendidas a 2 bits (concatenando
un 0), de modo que el resultado de la resta pueda ser almacenado en una señal
de 2 bits del tipo unsigned.
Finalmente, el resultado de la resta se asigna a res y acarreo_out. Obsérvese
que es posible realizar las asignaciones:

acarreo_out <= result(1);


res <= result(0);

porque cada elemento de una señal del tipo unsigned es del tipo std logic, que
es exactamente el tipo de las señales res y acarreo_out.

3.4.2 Descripción de la estructura


En la Figura 3.5 se muestra un circuito restador completo de 1 bit. Para su
definición, se emplean puertas OR-exclusiva de 2 entradas (xor2), AND de dos
entradas (and2), OR de tres entradas (or3) e inversor (not1).


p r pss t u v u z {
t

~ƒ ~…
}

x u{v p
p ~
r
q st y
~
p r pss t u v wx ~€

Figura 3.5: Diagrama de un circuito restador completo de 1 bit.

Obsérvese que, a fin de facilitar la descripción del modelo, se han etiquetado


las señales internas (not a, c, d, e, f) y las puertas lógicas (g0, ..., g6). La definición
de la entity y architecture de cada una de estas puertas lógicas se muestra a
continuación.
Capı́tulo 3 Casos prácticos de diseño de circuitos combinacionales 63

--------------------------------------
-- OR exclusiva de 2 entradas: xor2
library IEEE; use IEEE.std_logic_1164.all;

entity xor2 is port


( y0 : out std_logic;
x0, x1 : in std_logic );
end entity xor2;

architecture xor2 of xor2 is


begin
y0 <= x0 xor x1;
end architecture xor2;
--------------------------------------

--------------------------------------
-- Inversor de 1 entrada: not1
library IEEE; use IEEE.std_logic_1164.all;

entity not1 is port


( y0 : out std_logic;
x0 : in std_logic );
end entity not1;

architecture not1 of not1 is


begin
y0 <= not x0;
end architecture not1;
--------------------------------------

--------------------------------------
-- AND de 2 entradas: and2
library IEEE; use IEEE.std_logic_1164.all;

entity and2 is port


( y0 : out std_logic;
x0, x1 : in std_logic );
end entity and2;

architecture and2 of and2 is


begin
y0 <= x0 and x1;
end architecture and2;
--------------------------------------
64 A. Urquı́a, C. Martı́n Villalba Casos Prácticos de Diseño de Circuitos Digitales con VHDL

--------------------------------------
-- OR de 3 entradas: or3
library IEEE; use IEEE.std_logic_1164.all;

entity or3 is port


( y0 : out std_logic;
x0, x1, x2 : in std_logic );
end entity or3;

architecture or3 of or3 is


begin
y0 <= x0 or x1 or x2;
end architecture or3;
--------------------------------------

Para componer el circuito restador usando las puertas lógicas anteriores, es


necesario instanciar los componentes necesarios y conectarlos. Para ello, es preciso
escribir la entity de cada uno de los componentes, instanciar los componentes y
describir la conexión entre ellos. A continuación, se muestra el código del circuito
restador, donde la architecture describe la estructura del circuito.

-----------------------------------
-- Restador completo de 1 bit
library IEEE;
use IEEE.std_logic_1164.all;
use IEEE.numeric_std.all;

entity rest_completo is port


( res, acarreo_out : out std_logic;
a, b, acarreo_in : in std_logic);
end entity rest_completo;

architecture rest_completo_estruc of rest_completo is


signal not_a, c, d, e, f : std_logic;
-- Declaración de las clases de los componentes
component xor2 is port
( y0 : out std_logic;
x0, x1 : in std_logic );
end component xor2;
component not1 is port
( y0 : out std_logic;
x0 : in std_logic );
end component not1;
component and2 is port
Capı́tulo 3 Casos prácticos de diseño de circuitos combinacionales 65

( y0 : out std_logic;
x0, x1 : in std_logic );
end component and2;
component or3 is port
( y0 : out std_logic;
x0, x1, x2 : in std_logic );
end component or3;
begin
-- Instanciación y conexión de los componentes
g0 : component xor2 port map (c, a, b);
g1 : component xor2 port map (res, c, acarreo_in);
-- g2 : component not1 port map (not_a, a);
g2 : component not1 port map (y0 => not_a, x0 => a);
g3 : component and2 port map (d, not_a, acarreo_in);
g4 : component and2 port map (e, not_a, b);
g5 : component and2 port map (f, b, acarreo_in);
g6 : component or3 port map (acarreo_out, d, e, f);
end architecture rest_completo_estruc;
-----------------------------------

En el modelo anterior, se realiza la conexión entre los componentes mediante


asociación posicional. Es posible también usar asignación implı́cita. Por ejemplo:

g2 : component not1 port map (y0 => not_a, x0 => a);

3.4.3 Programación del banco de pruebas


En este caso, en el código del banco de pruebas se comprueban las salidas ob-
tenidas del UUT con las salidas esperadas. Es decir, el propio banco de pruebas
comprueba si el comportamiento del circuito es correcto y en caso de que no lo
sea generará el correspondiente mensaje. Se usará la descripción estructural del
restador para modelar el UUT, y su descripción del comportamiento para obtener
las salidas “correctas”, que se compararán con las salidas del UUT.
La architecture del banco de pruebas contiene un proceso (bloque process)
en el cual se generan los vectores de test, se introducen como entradas del UUT y
se comprueban las salidas del UUT. A continuación, se muestra el código VHDL
del banco de pruebas.

--------------------------------------------------
-- Banco de pruebas del restador completo de 1 bit
library IEEE;
use IEEE.std_logic_1164.all;
use IEEE.numeric_std.all;

entity bp_rest_completo is -- El banco de pruebas no tiene


66 A. Urquı́a, C. Martı́n Villalba Casos Prácticos de Diseño de Circuitos Digitales con VHDL

end entity bp_rest_completo; -- ni entradas ni salidas

architecture bp_rest_completo of bp_rest_completo is


signal res, acarreo_out : std_logic; -- Para conectar el UUT
signal a, b, acarreo_in : std_logic; -- Para conectar el UUT

component rest_completo is port


( res, acarreo_out : out std_logic;
a, b, acarreo_in : in std_logic);
end component rest_completo;

begin
-- Instanciar y conectar UUT
uut : component rest_completo port map
(res, acarreo_out, a, b, acarreo_in);
-- Crear vectores de test y comprobar salidas del UUT
gen_vec_test : process
variable test_in : unsigned (2 downto 0); -- Vector de test
variable esperado : unsigned (1 downto 0); -- Salida esperada
variable num_errores : integer := 0; -- Numero de errores
begin
test_in := B"000";
for count in 0 to 7 loop
a <= test_in(2);
b <= test_in(1);
acarreo_in <= test_in(0);
wait for 10 ns;
esperado := (’0’ & a) - (’0’ & b) - (’0’ & acarreo_in);
if (esperado /= ( acarreo_out & res )) then -- Comprueba resultado
report "ERROR : Esperado (" & -- Report del error
std_logic’image(esperado(1)) &
std_logic’image(esperado(0)) &
") /= actual (" &
std_logic’image(acarreo_out) &
std_logic’image(res) &
") en el instante " &
time’image(now);
num_errores := num_errores + 1;
end if;
test_in := test_in + 1;
end loop;
report "Test completo. Hay " &
integer’image(num_errores) &
" errores.";
wait;
Capı́tulo 3 Casos prácticos de diseño de circuitos combinacionales 67

end process gen_vec_test;


end architecture bp_rest_completo;
--------------------------------------------------

El banco de pruebas no tiene ni entradas ni salidas externas. Por ese motivo,


la entity del banco de pruebas no contiene ningún puerto (port):

entity bp_rest_completo is
end entity bp_rest_completo;

La conexión del UUT en el banco de pruebas se realiza instanciando el restador


binario como un subcircuito dentro del banco de pruebas. Aunque la conexión
se realiza mediante asociación posicional, podrı́a haberse realizado la asociación
nombrando explı́citamente los puertos:

uut : component rest_completo port map


(res => res, acarreo_out => acarreo_out,
a => a, b => b, acarreo_in => acarreo_in);

Se han definido señales internas al banco de pruebas para todas las conexiones
al UUT. Aunque en este ejemplo si lo sean, los nombres de las señales no tienen
que ser idénticos a los nombres de los puertos del UUT.
Se ha definido un proceso (process) para generar las formas de onda de las
entradas al UUT, y en ese mismo proceso se han incluido las sentencias para
comprobar si las salidas del UUT coinciden con las esperadas.
Es esencial tener en cuenta que el método empleado para calcular las sali-
das “esperadas” del UUT debe ser diferente del método empleado en el propio
UUT para obtener las salidas. En este ejemplo, el UUT contiene una descripción
estructural de la arquitectura del restador, mientras que las salidas “esperadas”
(variable esperado) se calculan a partir de una descripción del comportamiento
del restador:

esperado := (’0’ & a) - (’0’ & b) - (’0’ & acarreo_in);

El comando report se usa para escribir texto en la consola. El argumento


del comando (esto es, el texto a escribir) debe ser del tipo string. Por ejemplo,
cadenas de caracteres concatenadas mediante el operador &. Por ello, todo lo que
se desee mostrar deben ser convertido previamente al tipo string.
Por ejemplo, std_logic’image(res) se usa para convertir el valor de res,
que es del tipo std logic, a un dato del tipo string.
Asimismo, now es una función predefinida que devuelve el tiempo simulado
como un dato del tipo time. Puede usarse time’image(now) para obtener una
representación del tipo string del tiempo actual de la simulación.
Como resultado de la simulación del banco de pruebas, se obtienen las formas
de onda y el mensaje en la consola mostrados en la Figura 3.6.
68 A. Urquı́a, C. Martı́n Villalba Casos Prácticos de Diseño de Circuitos Digitales con VHDL

Figura 3.6: Formas de onda y mensaje en la consola obtenidos de simular


el banco de pruebas.

3.4.4 Banco de pruebas usando un procedimiento


Frecuentemente, en un banco de pruebas es preciso comparar el valor esperado de
una señal con el valor obtenido de la simulación del circuito. Si ambos valores no
coinciden, entonces se muestra un mensaje de error y se incrementa el contador
del número de errores.
A continuación, se muestra el código del banco de pruebas para el circuito
restador completo de 1 bit, programado empleando un procedimiento que realiza
la comparación entre el valor esperado y el actual, y que, en su caso, muestra los
correspondientes mensajes de error.

--------------------------------------------------
-- Banco de pruebas del restador completo de 1 bit
-- empleando un procedimiento
library IEEE;
use IEEE.std_logic_1164.all;
use IEEE.numeric_std.all;

entity bp_rest_completo is -- El banco de pruebas no tiene


end entity bp_rest_completo; -- ni entradas ni salidas

architecture bp_rest_completo_procedure of bp_rest_completo is


signal res, acarreo_out : std_logic; -- Para conectar el UUT
signal a, b, acarreo_in : std_logic; -- Para conectar el UUT

procedure error_check( esperado, actual : in unsigned;


num_errores : inout integer ) is
begin
if (esperado /= actual) then -- Comprueba resultado
report "ERROR : Esperado (" & -- Report del error
Capı́tulo 3 Casos prácticos de diseño de circuitos combinacionales 69

std_logic’image(esperado(1)) &
std_logic’image(esperado(0)) &
") /= actual (" &
std_logic’image(actual(1)) &
std_logic’image(actual(0)) &
") en el instante" &
time’image(now);
num_errores := num_errores + 1;
end if;
end procedure error_check;

component rest_completo is port


( res, acarreo_out : out std_logic;
a, b, acarreo_in : in std_logic);
end component rest_completo;

begin
-- Instanciar y conectar UUT
uut : component rest_completo port map
(res, acarreo_out, a, b, acarreo_in);
-- Crear vectores de test y comprobar salidas del UUT
gen_vec_test : process
variable test_in : unsigned (2 downto 0); -- Vector de test
variable esperado : unsigned (1 downto 0); -- Salida esperada
variable num_errores : integer := 0; -- Numero de errores
begin
test_in := B"000";
for count in 0 to 7 loop
a <= test_in(2);
b <= test_in(1);
acarreo_in <= test_in(0);
wait for 10 ns;
esperado := (’0’ & a) - (’0’ & b) - (’0’ & acarreo_in);
error_check( esperado, acarreo_out & res, num_errores );
test_in := test_in + 1;
end loop;
report "Test completo. Hay " &
integer’image(num_errores) &
" errores.";
wait;
end process gen_vec_test;
end architecture bp_rest_completo_procedure;
--------------------------------------------------
70 A. Urquı́a, C. Martı́n Villalba Casos Prácticos de Diseño de Circuitos Digitales con VHDL

3.4.5 Banco de pruebas usando una función


El código anterior del banco de pruebas puede modificarse con el fin de emplear
una función en lugar de un procedimiento. A continuación, se muestra una posible
forma de modificar el código. Obsérvese que se ha sustituido la cláusula if, que
compara el valor esperado con el valor actual, por una sentencia assert. El motivo
es únicamente ilustrar el uso de assert.

--------------------------------------------------
-- Banco de pruebas del restador completo de 1 bit
-- empleando un procedimiento
library IEEE;
use IEEE.std_logic_1164.all;
use IEEE.numeric_std.all;

entity bp_rest_completo is -- El banco de pruebas no tiene


end entity bp_rest_completo; -- ni entradas ni salidas

architecture bp_rest_completo_funcion of bp_rest_completo is


signal res, acarreo_out : std_logic; -- Para conectar el UUT
signal a, b, acarreo_in : std_logic; -- Para conectar el UUT

function error_check( esperado, actual : unsigned;


tnow : time ) return integer is
begin
assert ( esperado = actual ) -- Comprobacion usando assert
report "ERROR : Esperado (" & -- Report del error
std_logic’image(esperado(1)) &
std_logic’image(esperado(0)) &
") /= actual (" &
std_logic’image(actual(1)) &
std_logic’image(actual(0)) &
") en el instante " &
time’image(tnow)
severity error; -- Opcion severity
if ( esperado /= actual ) then
return 1; -- Indica error
else
return 0; -- Indica que no hay error
end if;
end function error_check;

component rest_completo is port


( res, acarreo_out : out std_logic;
a, b, acarreo_in : in std_logic);
Capı́tulo 3 Casos prácticos de diseño de circuitos combinacionales 71

end component rest_completo;

begin
-- Instanciar y conectar UUT
uut : component rest_completo port map
(res, acarreo_out, a, b, acarreo_in);
-- Crear vectores de test y comprobar salidas del UUT
gen_vec_test : process
variable test_in : unsigned (2 downto 0); -- Vector de test
variable esperado : unsigned (1 downto 0); -- Salida esperada
variable num_errores : integer := 0; -- Numero de errores
begin
test_in := B"000";
for count in 0 to 7 loop
a <= test_in(2);
b <= test_in(1);
acarreo_in <= test_in(0);
wait for 10 ns;
esperado := (’0’ & a) - (’0’ & b) - (’0’ & acarreo_in);
num_errores := num_errores +
error_check( esperado, acarreo_out & res, now );
test_in := test_in + 1;
end loop;
report "Test completo. Hay " &
integer’image(num_errores) &
"errores.";
wait;
end process gen_vec_test;
end architecture bp_rest_completo_funcion;
--------------------------------------------------

3.5 Sumador binario paralelo con propagación de


arrastre
En esta sección se describe el modelo de un sumador de 4 bits, compuesto a
partir de la conexión de cuatro sumadores completos de 1 bit. En primer lugar se
realizará el modelo del sumador completo de 1 bit mediante la conexión de puertas
lógicas AND, OR y XOR. A continuación, se usará este modelo de sumador
completo para componer el sumador de 4 bits.
72 A. Urquı́a, C. Martı́n Villalba Casos Prácticos de Diseño de Circuitos Digitales con VHDL

3.5.1 Diseño de un sumador completo


Un sumador completo es un circuito con tres bits de entrada (xi , yi , ci ) y dos
salida: el bit suma (si ) y el bit acarreo (Ci+1 ). El funcionamiento del circuito está
descrito por la tabla de la verdad siguiente:

ci xi yi ci+1 si
0 0 0 0 0
0 0 1 0 1
0 1 0 0 1
0 1 1 1 0
1 0 0 0 1
1 0 1 1 0
1 1 0 1 0
1 1 1 1 1

Simplificando las funciones lógicas mediante mapas de Karnaugh, se llega a


las expresiones siguientes:

ci+1 = xi yi + xi ci + yi ci
si = xi ⊕ yi ⊕ ci

En la Figura 3.7 se muestra el circuito del sumador completo.


‡†

‰ˆ 


‹Š Œ

’‘

‹ Ž
”“ Š
+

’•

Figura 3.7: Sumador completo.

Las puertas lógicas AND, OR y XOR se modelan con un retardo de 10 ns. A


continuación, se muestran los modelos de las puertas lógicas.

--------------------------------------
-- AND de 2 entradas con retardo
Capı́tulo 3 Casos prácticos de diseño de circuitos combinacionales 73

library IEEE; use IEEE.std_logic_1164.all;

entity and2 is
generic ( DELAY : time := 10 ns );
port ( y0 : out std_logic;
x0, x1 : in std_logic );
end entity and2;

architecture and2 of and2 is


begin
y0 <= ( x0 and x1 ) after DELAY;
end architecture and2;
--------------------------------------

--------------------------------------
-- OR de 3 entradas con retardo
library IEEE; use IEEE.std_logic_1164.all;

entity or3 is
generic ( DELAY : time := 10 ns );
port ( y0 : out std_logic;
x0, x1, x2 : in std_logic );
end entity or3;

architecture or3 of or3 is


begin
y0 <= ( x0 or x1 or x2 ) after DELAY;
end architecture or3;
--------------------------------------

-----------------------------------------
-- OR exclusiva de 2 entradas con retardo
library IEEE; use IEEE.std_logic_1164.all;

entity xor2 is
generic ( DELAY : time := 10 ns );
port ( y0 : out std_logic;
x0, x1 : in std_logic );
end entity xor2;

architecture xor2 of xor2 is


begin
y0 <= ( x0 xor x1 ) after DELAY;
end architecture xor2;
74 A. Urquı́a, C. Martı́n Villalba Casos Prácticos de Diseño de Circuitos Digitales con VHDL

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

En este caso, en lugar de declarar los componentes en la architecture del


sumador, se han definido los componentes en un package, que se ha llamado
puertasLogicas_package, y éste se ha usado en la definición de la architecture.
La definición del package se muestra a continuación.

-----------------------------------
-- package de componentes
-- Puertas lógicas
library IEEE;
use IEEE.std_logic_1164.all;

package puertasLogicas_package is

component xor2 is
generic ( DELAY : time := 10 ns );
port ( y0 : out std_logic;
x0, x1 : in std_logic );
end component xor2;

component and2 is
generic ( DELAY : time := 10 ns );
port ( y0 : out std_logic;
x0, x1 : in std_logic );
end component and2;

component or3 is
generic ( DELAY : time := 10 ns );
port ( y0 : out std_logic;
x0, x1, x2 : in std_logic );
end component or3;

end package puertasLogicas_package;

La definición del sumador completo es la siguiente:

-----------------------------------
-- Sumador completo de 1 bit
library IEEE;
use IEEE.std_logic_1164.all;
use work.puertasLogicas_package.all;
Capı́tulo 3 Casos prácticos de diseño de circuitos combinacionales 75

entity sum_completo is port


( s, C_out : out std_logic;
x, y, C_in : in std_logic);
end entity sum_completo;

architecture sum_completo_estruc of sum_completo is


signal n1, n2, n3, n4: std_logic;
begin
-- Instanciación y conexión de los componentes
XOR2_1 : component xor2 port map
(x0 => x, x1 => y, y0 => n1 );
XOR2_2 : component xor2 port map
(x0 => C_in, x1 => n1, y0 => s );
AND2_1 : component and2 port map
(x0 => x, x1 => y, y0 => n2 );
AND2_2 : component and2 port map
(x0 => x, x1 => C_in, y0 => n3 );
AND2_3 : component and2 port map
(x0 => y, x1 => C_in, y0 => n4 );
OR3_1 : component or3 port map
(x0 => n2, x1 => n3, x2 => n4, y0 => C_out );
end architecture sum_completo_estruc;
-----------------------------------

3.5.2 Banco de pruebas de sumador completo


Para comprobar el correcto funcionamiento de este circuito, se puede emplear
un banco de pruebas muy similar al que se diseñó para el restador de 1 bit.
En el banco de pruebas se compara el resultado obtenido de la descripción de
la estructura del sumador, con el resultado obtenido de la descripción de su
comportamiento. Se muestra un mensaje si ambos resultados no coinciden y se
lleva la cuenta del número de errores, mostrando al final de la simulación un
mensaje con el número total de errores. A continuación, se muestra el código del
banco de pruebas.

--------------------------------------------------
-- Banco de pruebas del sumador completo de 1 bit
library IEEE;
use IEEE.std_logic_1164.all;
use IEEE.numeric_std.all;

entity bp_sum_completo is -- El banco de pruebas no tiene


end entity bp_sum_completo; -- ni entradas ni salidas
76 A. Urquı́a, C. Martı́n Villalba Casos Prácticos de Diseño de Circuitos Digitales con VHDL

architecture bp_sum_completo of bp_sum_completo is


signal s, C_out,
x, y, C_in : std_logic; -- Para conectar el UUT

component sum_completo is
port ( s, C_out : out std_logic;
x, y, C_in : in std_logic);
end component sum_completo;

begin
-- Instanciar y conectar UUT
uut : component sum_completo port map
(s => s, C_out => C_out, x => x, y => y, C_in => C_in);
-- Crear vectores de test y comprobar salidas del UUT
gen_vec_test : process
variable test_in : unsigned (2 downto 0); -- Vector de test
variable esperado : unsigned (1 downto 0); -- Salida esperada
variable num_errores : integer := 0; -- Numero de errores
begin
test_in := B"000";
for count in 0 to 7 loop
C_in <= test_in(2);
x <= test_in(1);
y <= test_in(0);
wait for 50 ns;
esperado := (’0’ & x) + (’0’ & y) + (’0’ & C_in);
if (esperado /= ( C_out & s )) then -- Comprueba resultado
report "ERROR : Esperado (" & -- Report del error
std_logic’image(esperado(1)) &
std_logic’image(esperado(0)) &
") /= actual (" &
std_logic’image(C_out) &
std_logic’image(s) &
") en el instante " &
time’image(now);
num_errores := num_errores + 1;
end if;
test_in := test_in + 1;
end loop;
report "Test completo. Hay " &
integer’image(num_errores) &
" errores.";
wait;
end process gen_vec_test;
end architecture bp_sum_completo;
Capı́tulo 3 Casos prácticos de diseño de circuitos combinacionales 77

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

En la Figura 3.8 se muestra el resultado de la simulación del banco de pruebas.


Obsérvese que, debido al retardo de las puertas lógicas, desde el instante inicial
hasta el instante 20ns las salidas del sumador toman el valor ’U’ (indefinido).
Asimismo, los cambios en las señales de entrada tardan 20ns en propagarse a las
señales de salida.

Figura 3.8: Simulación del banco de pruebas del sumador completo.

3.5.3 Diseño del sumador de 4 bits


En la Figura 3.9 se muestra un sumador binario paralelo de 4 bits con propagación
del arrastre.
« ­ ¬ ± ³ ² · ¹ ¸ ± ­
ª ° ¶ ¼ ¼

š™ œ› š™ œ› ¦¥ ¨§ ¦¥ œ›
 î ÅÄ Æº É ÇÈ
¿ÀÁ ¢¡   –— ˜ ž ¢¡   –— ˜ ž ¢¡   –— ˜ ©£ ¢¡   –— ˜ ž
+ + + +

Ÿ ¤£ ¤£ Ÿ

¯ µ » ¾
® ´ º ½

Figura 3.9: Sumador binario paralelo de 4 bits con propagación del arrastre.

3.6 Bus bidireccional y memorias


Se pretende modelar dos unidades de memoria y un bus que conecta ambas.
Para simplificar, se supone que las unidades de memoria tienen capacidad para
almacenar una única palabra de N bits. Una de las memorias tiene capacidad de
lectura y escritura. La otra sólo lectura. Además de las dos memorias, se modela
un bus de N lı́neas que puede leer de ambas memorias y escribir en la memoria
que admite escritura. A continuación, se describe el modelado mediante VHDL
de este sistema.
78 A. Urquı́a, C. Martı́n Villalba Casos Prácticos de Diseño de Circuitos Digitales con VHDL

3.6.1 Memoria de sólo lectura


Los puertos de la memoria son los siguientes:
– Señal de entrada de 1 bit (OE_n). Cuando esta señal se pone a ’0’, habilita
la operación de lectura de la memoria. Cuando está a ’1’, la operación de
lectura está deshabilitada.

– Vector de salida de N bits (data). Contiene el dato almacenado en me-


moria (palabra de N bits) una vez ejecutada la operación de lectura. Es-
tá a alta impedancia cuando la operación de lectura está deshabilitada
(OE_n = ’1’).
A continuación, se muestra el código VHDL que describe la interfaz y el
funcionamiento de esta memoria. Se definen dos constantes generic: WORD_SIZE,
que contiene el número de bits de la palabra (N ) y READ_DELAY, que contiene el
tiempo de retardo entre que se habilita la señal de lectura hasta que el dato está
disponible.

-------------------------------------------
-- Fuente de datos unidireccional (lectura)
library IEEE; use IEEE.std_logic_1164.all;

entity fuenteUnidireccional is
generic ( WORD_SIZE : integer := 8; -- Bits por palabra,
-- por defecto 8
READ_DELAY : time := 10 ns); -- Retardo en la lectura,
-- por defecto 10 ns
port ( data : out std_logic_vector(WORD_SIZE-1 downto 0);
-- Datos de salida
OE_n : in std_logic); -- Habilita lectura
end entity fuenteUnidireccional;

architecture fuenteUnidireccional of fuenteUnidireccional is


begin
rom : process (OE_n)
begin
if (OE_n = ’0’) then
data <= ( 0 => ’1’, others => ’0’) after READ_DELAY;
else
data <= (others => ’Z’);
end if;
end process rom;
end architecture fuenteUnidireccional;
-------------------------------------------

La sentencia
Capı́tulo 3 Casos prácticos de diseño de circuitos combinacionales 79

data <= ( 0 => ’1’, others => ’0’ ) after READ_DELAY;

indica que debe asignarse al vector de señales data, una vez transcurrido el
retardo de tiempo READ_DELAY, una palabra del tamaño de data, con todos
sus bits igual a ’0’ excepto el menos significativo, que debe valer ’1’ (es decir,
data <= "00...01";). Esta palabra es la que se encuentra almacenada en la
memoria y es la que se lee cada vez que se habilita la operación de lectura.
Análogamente, la sentencia

data <= (others => ’Z’);

asigna al vector de señales data una palabra, con el mismo número de bits que
data, con todos sus bits al valor ’Z’ (alta impedancia).

3.6.2 Memoria de lectura y escritura


Los puertos de esta memoria son los siguientes:

– Señal de entrada de 1 bit (OE_n). Cuando esta señal se pone a ’0’, habilita
la operación de lectura de la memoria. Cuando está a ’1’, la operación de
lectura está deshabilitada.

– Señal de entrada de 1 bit (WE_n). Cuando esta señal se pone a ’0’, habilita
la operación de escritura en la memoria. Cuando está a ’1’, la operación de
escritura está deshabilitada.

– Vector de entrada y salida de N bits (data).

------------------------------------------------------
-- Fuente de datos bidireccional (lectura y escritura)
library IEEE; use IEEE.std_logic_1164.all;

entity fuenteBidireccional is
generic ( WORD_SIZE : integer := 8; -- Bits por palabra,
-- por defecto 8 bits
READ_DELAY : time := 10 ns; -- Retardo en la lectura,
-- por defecto 10 ns
WRITE_DELAY : time := 10 ns); -- Retardo en la escritura,
-- por defecto 10 ns
port ( data : inout std_logic_vector(WORD_SIZE-1 downto 0);
-- Se~
nal de datos bidireccional
OE_n : in std_logic; -- Habilita lectura
WE_n : in std_logic ); -- Habilita escritura
end entity fuenteBidireccional;

architecture fuenteBidireccional of fuenteBidireccional is


80 A. Urquı́a, C. Martı́n Villalba Casos Prácticos de Diseño de Circuitos Digitales con VHDL

signal data_stored : std_logic_vector(WORD_SIZE-1 downto 0);


-- Datos almacenados internamente
begin
ram : process (OE_n, WE_n, data)
begin
if (OE_n = ’0’) then
data <= data_stored after READ_DELAY;
elsif ( WE_n = ’0’) then
data_stored <= data after WRITE_DELAY;
else
data <= (others => ’Z’);
end if;
end process ram;
end architecture fuenteBidireccional;
------------------------------------------------------

3.6.3 Bus bidireccional


A continuación, se muestra el código del bus de datos que se emplea para realizar
varias operaciones de lectura y escritura sobre las memorias. Al instanciar las
memorias, se asignan nuevos valores al tamaño de la palabra, que pasa a ser 16
bits, y a los retardos:

– Memoria de sólo lectura: retardo en la lectura de 20 ns.

– Memoria de lectura y escritura: retardo en la lectura de 30 ns y retardo en


la escritura de 40 ns.

Las operaciones que se realizan son las siguientes:

1. tiempo = 0 (instante inicial). Se asigna valor ’1’ a las señales OE1_n,


OE2_n y WE_n, es decir, inicialmente se encuentras deshabilitadas las ope-
raciones de lectura y escritura en las memorias. También, en el instante
inicial, se asigna el valor 0x0fc3 a la señal writeData del banco de pruebas,
cuya finalidad es almacenar el valor que va a ser escrito en la memoria.

2. tiempo = 100 ns. Se habilita la operación de escritura, para ello se pone


a ’0’ la señal WE_n. A consecuencia de ello, en el instante tiempo = 140 ns
se escribe el valor 0x0fc3 en la memoria.

3. tiempo = 200 ns. Se deshabilita la operación de escritura, poniendo la


señal WE_n al valor ’1’. Se habilita la operación de lectura de la memoria de
sólo lectura, para lo cual se pone la señal OE2_n a ’0’. A consecuencia de
ello, el valor 0x0001 está disponible en el bus en el instante tiempo = 220
ns.

4. tiempo = 300 ns. Se deshabilita la lectura de la memoria de sólo lectura,


para lo cual se pone la señal OE2_n a ’1’. Finalmente, se habilita la lectura
Capı́tulo 3 Casos prácticos de diseño de circuitos combinacionales 81

de la memoria de lectura y escritura, para lo cual se pone la señal OE1_n a


’0’. A consecuencia de ello, en el instante tiempo = 330 ns el valor 0x0fc3
está disponible en el bus.

A continuación, se muestra el código VHDL que describe las operaciones


realizadas sobre las memorias mediante el empleo del bus.

-----------------------------------------------
-- Conexión de la fuente de datos bidireccional
-- y la fuente unidireccional mediante un bus
library IEEE; use IEEE.std_logic_1164.all;

entity tb_bus is
constant WORD_SZ : integer := 16; -- Bits por palabra
constant PERIOD : time := 100 ns; -- Periodo ciclo reloj
end entity tb_bus;

architecture tb_bus of tb_bus is


signal data : std_logic_vector(WORD_SZ-1 downto 0);
-- Datos en el bus
signal OE1_n : std_logic; -- Habilita lectura memoria lectura/escritura
signal OE2_n : std_logic; -- Habilita lectura memoria sólo lectura
signal WE_n : std_logic; -- Habilita escritura
signal writeData : std_logic_vector(WORD_SZ-1 downto 0);
-- Datos a escribir
component fuenteBidireccional is
generic ( WORD_SIZE : integer := 8; -- Bits por palabra
READ_DELAY : time := 10 ns; -- Retardo en la lectura
WRITE_DELAY : time := 10 ns); -- Retardo en la escritura
port ( data : inout std_logic_vector(WORD_SIZE-1 downto 0);
-- Se~
nal de datos bidireccional
OE_n : in std_logic; -- Habilita lectura
WE_n : in std_logic ); -- Habilita escritura
end component fuenteBidireccional;

component fuenteUnidireccional is
generic ( WORD_SIZE : integer := 8; -- Bits por palabra
READ_DELAY : time := 10 ns); -- Retardo en la lectura

port ( data : out std_logic_vector(WORD_SIZE-1 downto 0);


-- Se~
nal de datos bidireccional
OE_n : in std_logic); -- Habilita lectura
end component fuenteUnidireccional;

begin
82 A. Urquı́a, C. Martı́n Villalba Casos Prácticos de Diseño de Circuitos Digitales con VHDL

-- Instanciar las fuentes de datos, asignando valor a sus constantes generic


U1 : component fuenteBidireccional
generic map (WORD_SZ, 30 ns, 40 ns) -- Asigna valor constantes generic
port map (data, OE1_n, WE_n);
U2 : component fuenteUnidireccional
generic map (WORD_SZ, 20 ns ) -- Asigna valor constantes generic
port map (data, OE2_n);
data <= writeData when ( WE_n = ’0’) else ( others => ’Z’);
vectoresTest : process is
begin
OE1_n <= ’1’; OE2_n <= ’1’; WE_n <= ’1’; -- Deshabilita se~
nales
writeData <= B"0000_1111_1100_0011"; -- Dato a escribir (=0x0fc3)
wait for PERIOD;
WE_n <= ’0’; -- Habilita escritura (se escribe 0x0fc3)
wait for PERIOD;
WE_n <= ’1’; -- Deshabilita escritura
OE2_n <= ’0’; -- Habilita lectura desde la fuente unidireccional
-- El dato en el bus debe ser 0x0001
wait for PERIOD;
OE2_n <= ’1’; -- Deshabilita lectura de la fuente unidireccional
OE1_n <= ’0’; -- Habilita lectura desde la fuente bidireccional
-- El dato en el bus debe ser 0x0fc3
wait for PERIOD;
wait;
end process vectoresTest;
end architecture tb_bus;
-----------------------------------------------

En la Figura 3.10 se muestra el resultado obtenido de la simulación.

Figura 3.10: Formas de onda obtenidas de simular el circuito.

3.7 Unidad aritmético lógica (ALU)

Una unidad aritmético lógica (ALU) es un circuito que, dependiendo del valor de
sus entradas de selección de función, realiza una operación lógica o aritmética, de
entre un conjunto de operaciones posibles, sobre uno o dos operandos.
Capı́tulo 3 Casos prácticos de diseño de circuitos combinacionales 83

Este tipo de circuito puede ser descrito mediante una asignación concurrente
a una señal, o bien mediante varias asignaciones incluidas dentro de un bloque
process.
En general, un circuito combinacional puede ser descrito mediante un bloque
process siempre que todas las señales de entrada al circuito combinacional sean
incluidas en la lista de variables a las que es sensible el bloque process.
A continuación, se muestran dos posibles formas de modelar una ALU: la
primera usando una asignación concurrente y la segunda usando un bloque pro-
cess. Ambas versiones dan lugar a circuitos combinacionales equivalentes. En la
Tabla 3.1 se muestran las operaciones entre los operandos A y B que realiza la
ALU, en función del valor de la entrada de selección de función de 3 bits mode.

mode Operación Descripción


000 A∗2 Multiplicar por 2 (equivale a desplazamiento a la izqda)
001 A+B Suma
010 A−B Resta
011 −A Complemento a dos
1 0 0 A and B AND lógico
101 A or B OR lógico
1 1 0 A xor B XOR lógico
111 not A Complemento de todos los bits

Tabla 3.1: Tabla de operaciones de la ALU

3.7.1 Modelado mediante asignación concurrente


Para ilustrar el empleo de las clases package para almacenar constantes globales,
a continuación se muestra un package con las las constantes que definen el
tamaño de palabra de los operandos y el tamaño de la palabra de selección de la
operación.

----------------------------------------------
-- Definición de constantes globales de la ALU
package ALU_CONSTANTS is
constant WIDTH : integer := 16;
-- Núm. bits de los operandos
constant SEL_BITS :
integer := 3;
-- Núm. bits selección de operación
end package ALU_CONSTANTS;
----------------------------------------------

A continuación, se muestra el código que define el comportamiento de la ALU


mediante una única sentencia de asignación concurrente a una señal.
84 A. Urquı́a, C. Martı́n Villalba Casos Prácticos de Diseño de Circuitos Digitales con VHDL

----------------------------------------------
-- ALU
-- architecture: sentencia concurrente
library IEEE;
use IEEE.std_logic_1164.all;
use IEEE.numeric_std.all;
use work.ALU_CONSTANTS.all;

entity ALU is
port ( C : out std_logic_vector (WIDTH-1 downto 0);
A, B : in std_logic_vector (WIDTH-1 downto 0);
mode : in std_logic_vector (SEL_BITS-1 downto 0) );
end entity ALU;

architecture ALU_concurrente of ALU is


begin
C <= std_logic_vector (signed(A)+signed(A)) when (mode="000")
else std_logic_vector (signed(A)+signed(B)) when (mode="001")
else std_logic_vector (signed(A)-signed(B)) when (mode="010")
else std_logic_vector (-signed(A) ) when (mode="011")
else A and B when (mode="100")
else A or B when (mode="101")
else A xor B when (mode="110")
else not A;
end architecture ALU_concurrente;
----------------------------------------------

3.7.2 Modelado mediante bloque process


El comportamiento de la ALU también puede ser descrito empleando un bloque
process sensible a tres señales: los dos operandos y la señal de selección de la
operación.

----------------------------------------------
-- ALU
-- architecture: bloque process
library IEEE;
use IEEE.std_logic_1164.all;
use IEEE.numeric_std.all;
use work.ALU_CONSTANTS.all;

architecture ALU_bloqueProcess of ALU is


begin
process (A, B, mode) is
Capı́tulo 3 Casos prácticos de diseño de circuitos combinacionales 85

begin
case mode is
when "000" => C <= std_logic_vector(signed(A)+signed(A));
when "001" => C <= std_logic_vector(signed(A)+signed(B));
when "010" => C <= std_logic_vector(signed(A)-signed(B));
when "011" => C <= std_logic_vector(-signed(A));
when "100" => C <= A and B;
when "101" => C <= A or B;
when "110" => C <= A xor B;
when others => C <= not A;
end case;
end process;
end architecture ALU_bloqueProcess;
----------------------------------------------

3.7.3 Programación del banco de pruebas


Como hemos visto en otros ejemplos, el banco de pruebas está tı́picamente for-
mado por las tres partes siguientes: el dispositivo que va a ser probado (UUT),
el código para la generación de los vectores de test y el código para comprobar
los resultados del test.
Aún en el caso de una ALU sencilla como esta, examinar que la ALU realiza
correctamente las operaciones para todos los posibles valores de los operadores
consumirı́a bastante tiempo. En la práctica esta técnica serı́a inviable, por lo cual
debe seleccionarse un conjunto de vectores de test, por ejemplo, atendiendo a los
criterios siguientes:

– Se escogen valores de los operandos entorno al cero. Por ejemplo: −2, −1,
0, 1 y 2.

– Se escogen valores de los operandos en el lı́mite inferior de su rango. Si


MIN_NEG_DATA representa el valor mı́nimo que puede tomar el operando,
entonces se escogen los valores MIN_NEG_DATA, . . . , MIN_NEG_DATA+4 para cada
uno de los operandos.

– Se escogen valores de los operandos en el lı́mite superior de su rango. Si


MAX_POS_DATA representa el valor máximo que puede tomar el operando,
entonces se escogen los valores MAX_POS_DATA-4, . . . , MAX_POS_DATA para cada
uno de los operandos.

– Finalmente, se escogen algunos valores “al azar”, más o menos distribuidos


uniformemente en el rango de los operandos.

Se ha definido un package con las constantes globales del banco de pruebas,


cuyo valor es calculado a partir de las constantes globales de la ALU.
86 A. Urquı́a, C. Martı́n Villalba Casos Prácticos de Diseño de Circuitos Digitales con VHDL

----------------------------------------------
-- Definición de constantes globales
-- del banco de pruebas de la ALU
use work.ALU_CONSTANTS.all;
package TB_ALU_CONSTANTS is
constant SEL_MAX : integer := 2**SEL_BITS - 1;
constant MAX_POS_DATA : integer := 2**(WIDTH-1) - 1;
constant MIN_NEG_DATA : integer := -2**(WIDTH-1);
constant DELAY : time := 10 ns;
end package TB_ALU_CONSTANTS;
----------------------------------------------

A continuación se muestra el código del banco de pruebas.

----------------------------------------------
-- Banco de pruebas para la ALU
library IEEE;
use IEEE.std_logic_1164.all;
use IEEE.numeric_std.all;
use work.ALU_CONSTANTS.all;
use work.TB_ALU_CONSTANTS.all;

entity TB_ALU is
constant PERIOD : time := 100 ns;
end entity TB_ALU;

architecture TB_ALU of TB_ALU is


signal A,B,C : std_logic_vector (WIDTH-1 downto 0);
signal mode : std_logic_vector (SEL_BITS-1 downto 0);

component ALU is
port ( C : out std_logic_vector (WIDTH-1 downto 0);
A, B : in std_logic_vector (WIDTH-1 downto 0);
mode : in std_logic_vector (SEL_BITS-1 downto 0) );
end component ALU;

-- Procedure que calcula C (expected_C) y lo compara con el


-- valor de C que se pasa como argumento (actual_C)
-- Si ambos valores no coinciden, se muestra un mensaje y se
-- incrementa el contador de errores (error_count)
procedure check_ALU
( i, j, k : in integer;
actual_C : in std_logic_vector (WIDTH-1 downto 0);
error_count : inout integer ) is
Capı́tulo 3 Casos prácticos de diseño de circuitos combinacionales 87

variable expected_C : integer;


begin
case k is
when 0 => expected_C := i*2;
when 1 => expected_C := i+j;
when 2 => expected_C := i-j;
when 3 => expected_C := -i;
when 4 => expected_C := TO_INTEGER(signed(
std_logic_vector(TO_SIGNED(i,WIDTH)) and
std_logic_vector(TO_SIGNED(j,WIDTH)) ));
when 5 => expected_C := TO_INTEGER(signed(
std_logic_vector(TO_SIGNED(i,WIDTH)) or
std_logic_vector(TO_SIGNED(j,WIDTH)) ));
when 6 => expected_C := TO_INTEGER(signed(
std_logic_vector(TO_SIGNED(i,WIDTH)) xor
std_logic_vector(TO_SIGNED(j,WIDTH)) ));
when others => expected_C := TO_INTEGER(signed(
not std_logic_vector(TO_SIGNED(i,WIDTH)) ));
end case;
expected_C := TO_INTEGER(TO_SIGNED(expected_C,WIDTH));
-- Trunca el resultado a WIDTH bits
assert( expected_C = TO_INTEGER(signed(actual_C)) )
report "ERROR. Ops: " & integer’image(i) & "," & integer’image(j) &
", Operacion: " & integer’image(k) &
", resultado esperado: " &
integer’image(expected_C) &
", resultado actual: " &
integer’image(TO_INTEGER(signed(actual_C))) &
"en el instante " &
time’image(now);
if (expected_C /= TO_INTEGER(signed(actual_C))) then
error_count := error_count + 1;
end if;
end procedure check_ALU;
-- Fin de la definición del procedure

begin
UUT : component ALU port map (C, A, B, mode);

-- bloque process para generar los vectores de test y


-- comprobar el resultado
main : process is
variable error_count : integer := 0;
begin
88 A. Urquı́a, C. Martı́n Villalba Casos Prácticos de Diseño de Circuitos Digitales con VHDL

report "Comienza la simulación";

-- Vectores de test: operandos con valor próximo a cero


for i in -2 to 2 loop
for j in -2 to 2 loop
for k in 0 to SEL_MAX loop
A <= std_logic_vector(TO_SIGNED(i,WIDTH));
b <= std_logic_vector(TO_SIGNED(j,WIDTH));
mode <= std_logic_vector(TO_SIGNED(k,SEL_BITS));
wait for DELAY;
check_ALU(i, j, k, C, error_count);
end loop;
end loop;
end loop;

-- Vectores de test: operandos con valor próximo al mı́nimo


for i in MIN_NEG_DATA to MIN_NEG_DATA+4 loop
for j in MIN_NEG_DATA to MIN_NEG_DATA+4 loop
for k in 0 to SEL_MAX loop
A <= std_logic_vector(TO_SIGNED(i,WIDTH));
b <= std_logic_vector(TO_SIGNED(j,WIDTH));
mode <= std_logic_vector(TO_SIGNED(k,SEL_BITS));
wait for DELAY;
check_ALU(i, j, k, C, error_count);
end loop;
end loop;
end loop;

-- Vectores de test: operandos con valor próximo al máximo


for i in MAX_POS_DATA-4 to MAX_POS_DATA loop
for j in MAX_POS_DATA-4 to MAX_POS_DATA loop
for k in 0 to SEL_MAX loop
A <= std_logic_vector(TO_SIGNED(i,WIDTH));
b <= std_logic_vector(TO_SIGNED(j,WIDTH));
mode <= std_logic_vector(TO_SIGNED(k,SEL_BITS));
wait for DELAY;
check_ALU(i, j, k, C, error_count);
end loop;
end loop;
end loop;

-- Vectores de test: operandos con valores al azar


for i in 0 to 9 loop
for j in 0 to 9 loop
for k in 0 to SEL_MAX loop
Capı́tulo 3 Casos prácticos de diseño de circuitos combinacionales 89

A <= std_logic_vector(TO_SIGNED(41*i-273,WIDTH));
b <= std_logic_vector(TO_SIGNED(89*j-384,WIDTH));
mode <= std_logic_vector(TO_SIGNED(k,SEL_BITS));
wait for DELAY;
check_ALU(41*i-273, 89*j-384, k, C, error_count);
end loop;
end loop;
end loop;

wait for DELAY;

-- Informe mostrando el resultado del test


if (error_count=0) then
report "Finaliza la simulación: 0 errores";
else
report "Finaliza la simulación: " & integer’image(error_count) & "errores";
end if;

wait; -- Termina la simulación


end process main;

end architecture TB_ALU;


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

3.8 Conversor de BCD a binario


En los circuitos lógicos digitales se emplean diferentes códigos binarios. En oca-
siones, dos circuitos que usan diferente código necesitan comunicarse entre sı́,
siendo preciso emplear otro circuito para realizar la conversión de un código a
otro. Como ejemplo de este tipo de circuitos conversores de código, en esta sección
de describirá el diseño de un conversor para números en código BCD de longitud
fija a código binario.
En el código BCD (binary-coded decimal), cada grupo de cuatro bits conse-
cutivos es convertido a un dı́gito decimal. El número completo es interpretado
como un número decimal compuesto por estos dı́gitos decimales. Por ejemplo,
0101 1001BCD es interpretado como 5910 , ya que los primeros cuatro bits (0101)
corresponden a un 5 decimal y los últimos cuatro bits (1001) corresponden a un 9
decimal. El equivalente binario al número 5910 es 0011 10112 . El circuito descrito
en esta sección deberı́a realizar la conversión de 0101 1001BCD a 0011 10112 .
Existen varios algoritmos de conversión de código BCD a binario, los cuales
tı́picamente requieren la realización de una secuencia de operaciones sobre el
número BCD de entrada, que aparentemente deberı́an ser implementadas usando
un circuito secuencial. Sin embargo, el algoritmo descrito a continuación puede
90 A. Urquı́a, C. Martı́n Villalba Casos Prácticos de Diseño de Circuitos Digitales con VHDL

ser transformado en una secuencia de puertas lógicas, y por tanto puede ser
implementado usando un circuito combinacional.

Paso 1. bcd <- bcd_data_input;


bin <- 0 (mismo número de bits que bcd)
Paso 2. For count <- 1 to bcd_bit_size do begin
Paso 2a. {bcd,bin} <- {bcd,bin} >> 1;
Paso 2b. For cada secuencia de 4 bits en bcd do
If secuencia de 4 bits > 7 then
restar 3 de esa secuencia de 4 bits;
end // del bucle For
Paso 3. bin contiene el número convertido

3.8.1 Circuito conversor


La constante global que almacena el número de bits del número en BCD, se
declara en un package, que será usado desde la descripción del circuito y desde
la descripción del banco de pruebas.

------------------------------------------
-- Definición de constantes globales
package BCD_CONST is
constant LENGTH : integer := 16;
-- Longitud (# bits) del número BCD
end package BCD_CONST;
------------------------------------------

A continuación se muestra la descripción de un circuito que ejecuta el algo-


ritmo de conversión de BCD a binario descrito anteriormente.

--------------------------------------
-- Circuito conversor de BCD a binario
library IEEE;
use IEEE.std_logic_1164.all;
use IEEE.numeric_std.all;
use work.BCD_CONST.all;

entity bcd_to_bin is
port( bin: out std_logic_vector(LENGTH-1 downto 0);
bcd: in std_logic_vector(LENGTH-1 downto 0) );
end entity bcd_to_bin;

architecture bcd_to_bin of bcd_to_bin is


begin
process (bcd) is -- bloque sensible a cambios en la entrada
variable bcd_concat_bin: unsigned(2*LENGTH-1 downto 0);
variable temp : unsigned(3 downto 0);
Capı́tulo 3 Casos prácticos de diseño de circuitos combinacionales 91

begin
bcd_concat_bin := unsigned(bcd) & TO_UNSIGNED(0,LENGTH);
for i in 0 to LENGTH-1 loop -- Paso 2
bcd_concat_bin := bcd_concat_bin srl 1; -- Paso 2a
for j in 0 to (LENGTH/4)-1 loop -- Paso 2b
temp := bcd_concat_bin(LENGTH+j*4+3 downto LENGTH+j*4);
if (temp(3) = ’1’) then -- Si la secuencia de 4 bits
temp := temp - "0011"; -- es mayor que 7, se resta 3
end if;
bcd_concat_bin(LENGTH+j*4+3 downto LENGTH+j*4) := temp;
end loop; -- end for Paso 2b
end loop; -- end for Paso 2
bin <= std_logic_vector(bcd_concat_bin(LENGTH-1 downto 0));
end process;
end architecture bcd_to_bin;
--------------------------------------

Obsérvese que un bloque process puede dar lugar a un circuito combinacional


si en la lista de señales a las cuales el bloque es sensible incluye todas las entradas
al circuito. Dado que ese bloque process serı́a activado cada vez que una de las
señales de entrada cambia, este código representa un circuito combinacional.
Igualmente, un bucle for no implica necesariamente que el circuito sinteti-
zado deba ser secuencial. En este caso, el bucle for únicamente representa la
interconexión de puertas lógicas combinacionales.

3.8.2 Banco de pruebas


A continuación se muestra el código del banco de pruebas del circuito conversor.
Para probar el circuito, se generan todos los posibles números en BCD con LENGTH
bits. En este caso, todos los posibles números de 16 bits. Puesto que un número
BCD de 16 bits puede representar cualquier número entero comprendido entre 0
y 999910 , ese será el rango de números que se emplee en el test.

----------------------------------------------
-- Banco de pruebas para el circuito conversor
-- de BCD a binario
library IEEE;
use IEEE.std_logic_1164.all;
use IEEE.numeric_std.all;
use work.BCD_CONST.all;

entity bp_bcd_to_bin is
constant MAX_BCD : integer := 9999; -- Valor máximo de entrada
constant DELAY : time := 10ns; -- Retardo usado en el test;
end entity bp_bcd_to_bin;
92 A. Urquı́a, C. Martı́n Villalba Casos Prácticos de Diseño de Circuitos Digitales con VHDL

architecture bp_bcd_to_bin of bp_bcd_to_bin is


signal bin: std_logic_vector(LENGTH-1 downto 0); -- Salida de UUT
signal bcd: std_logic_vector(LENGTH-1 downto 0); -- Entrada a UUT

-- Declaración del componente (UUT)


component bcd_to_bin is
port( bin: out std_logic_vector(LENGTH-1 downto 0);
bcd: in std_logic_vector(LENGTH-1 downto 0) );
end component bcd_to_bin;

begin
-- Instancia la unidad a testear
UUT : component bcd_to_bin port map(bin,bcd);

-- Genera vectores de test y comprueba resultados


main: process is
variable temp : unsigned (LENGTH-1 downto 0);
variable digit : unsigned (LENGTH-1 downto 0); -- Un digito BCD
variable digits : unsigned (LENGTH-1 downto 0); -- Todos digitos
variable expected : unsigned (LENGTH-1 downto 0);
variable error_count : integer := 0; -- Número de errores
begin
report "Comienza la simulación.";

-- Generar todos los posibles valores


for i in 0 to MAX_BCD loop
temp := TO_UNSIGNED(i,LENGTH);
for j in 0 to (LENGTH/4-1) loop
digit := temp mod 10; -- Obtiene el digito BCD menos significativo
digits(j*4+3 downto j*4) := digit(3 downto 0);
temp := temp/10;
end loop;
bcd <= std_logic_vector(digits); -- Asigna vector de test
expected := TO_UNSIGNED(i, LENGTH);
wait for DELAY;
assert (expected = unsigned(bin))
report "ERROR: Resultado esperado " &
integer’image(TO_INTEGER(expected)) &
", resultado obtenido " &
integer’image(TO_INTEGER(unsigned(bin))) &
" en el instante " & time’image(now);
if (expected /= unsigned(bin)) then
error_count := error_count + 1;
end if;
end loop;
Capı́tulo 3 Casos prácticos de diseño de circuitos combinacionales 93

wait for DELAY;


-- Informe final
if (error_count = 0) then
report "Simulación finalizada sin errores";
else
report "ERROR: Hay " & integer’image(error_count) & " errores.";
end if;
wait; -- Final de la simulación
end process main;
end architecture bp_bcd_to_bin;

3.9 Codificador 4:2 con prioridad


Un codificador es un circuito que convierte un valor decimal en su equivalente
binario (realiza la función inversa a un decodificador). Este circuito, que tiene 2N
entradas y N salidas, presenta en la salida el código binario correspondiente a la
entrada activada.
El codificador no funciona correctamente si en un determinado instante se
produce más de una entrada al circuito. En aquellos casos en que deba con-
templarse esta situación, se emplean circuitos codificadores con prioridad, en los
cuales queda definido qué entrada debe codificarse cuando se presenten varias en
un determinado instante.
Asimismo, el codificador tiene una salida que se activa cuando hay alguna
entrada al circuito. Obsérvese que cuando no hay ninguna entrada, la salida del
codificador no es válida.

3.9.1 Diseño del circuito


A continuación, se muestra el código VHDL de un codificador 4:2 con prioridad.
La entrada 3 tiene mayor prioridad que la 2, ésta mayor que la 1 y finalmente la
entrada 0 es la de menor prioridad. La salida valida se pone a ’1’ cuando hay al
menos una entrada al circuito.

-------------------------------------------
-- Codificador 4:2 con prioridad
library IEEE;
use IEEE.std_logic_1164.all;

entity codificador_4_2_prioridad is
port ( valida : out std_logic; -- ’1’ si hay entrada
codificada : out std_logic_vector(1 downto 0);
i3, i2, i1, i0 : in std_logic );
end entity codificador_4_2_prioridad;
94 A. Urquı́a, C. Martı́n Villalba Casos Prácticos de Diseño de Circuitos Digitales con VHDL

architecture codificador_4_2_prioridad of codificador_4_2_prioridad is


begin
process (i3, i2, i1, i0) is -- Activado cuando cambia alguna entrada
begin

if ( (i3=’1’) or (i2=’1’) or (i1=’1’) or (i0=’1’) ) then


valida <= ’1’; -- Indica que la salida es válida
else
valida <= ’0’; -- Salida no válida, puesto que no hay entrada
end if;

if (i3=’1’) then codificada <= "11";


elsif (i2=’1’) then codificada <= "10";
elsif (i1=’1’) then codificada <= "01";
else codificada <= "00";
end if;

end process;
end architecture codificador_4_2_prioridad;
-------------------------------------------

Obsérvese que el bloque process es activado cuando cambia cualquiera de las


entradas, ya que el bloque es sensible a estas cuatro señales.
Se emplean sentencias if-elsif para inspeccionar de manera priorizada las
entradas.

3.9.2 Banco de pruebas


A continuación, se muestra el código del banco de pruebas.

-----------------------------------------------------
-- Banco de pruebas del codificador 4:2 con prioridad
library IEEE;
use IEEE.std_logic_1164.all;
use IEEE.numeric_std.all;

entity bp_codificador_4_2 is
constant MAX_COMB : integer := 16; -- Num. combinaciones entrada
constant DELAY : time := 10 ns; -- Retardo usado en el test
end entity bp_codificador_4_2;

architecture bp_codificador_4_2 of bp_codificador_4_2 is


-- Salidas UUT
Capı́tulo 3 Casos prácticos de diseño de circuitos combinacionales 95

signal valida : std_logic;


signal codificada : std_logic_vector(1 downto 0);
-- Entradas UUT
signal i3, i2, i1, i0 : std_logic;

component codificador_4_2_prioridad is
port ( valida : out std_logic;
codificada : out std_logic_vector(1 downto 0);
i3, i2, i1, i0 : in std_logic );
end component codificador_4_2_prioridad;

begin -- Cuerpo de la arquitectura


UUT : component codificador_4_2_prioridad port map
(valida, codificada, i3, i2, i1, i0);

main : process is
variable temp : unsigned (3 downto 0); -- Usado en los cálculos
variable esperado_valida : std_logic;
variable esperado_codificada : std_logic_vector(1 downto 0);
variable error_count : integer := 0;
begin
report "Comienza la simulación";
-- Generar todos los posibles valores de entrada
for i in 0 to (MAX_COMB-1) loop
temp := TO_UNSIGNED(i,4);
i3 <= std_logic(temp(3));
i2 <= std_logic(temp(2));
i1 <= std_logic(temp(1));
i0 <= std_logic(temp(0));
-- Calcular el valor esperado
if (i=0) then
esperado_valida := ’0’;
esperado_codificada := "00";
else
esperado_valida := ’1’;
if (i=1) then esperado_codificada := "00";
elsif (i<=3) then esperado_codificada := "01";
elsif (i<=7) then esperado_codificada := "10";
else esperado_codificada := "11";
end if;
end if;

wait for DELAY; -- Espera y compara con las salidas de UUT

if ( esperado_valida /= valida ) then


96 A. Urquı́a, C. Martı́n Villalba Casos Prácticos de Diseño de Circuitos Digitales con VHDL

report "ERROR en la salida valida. Valor esperado: " &


std_logic’image(esperado_valida) &
", valor actual: " &
std_logic’image(valida) &
" en el instante: " &
time’image(now);
error_count := error_count + 1;
end if;

if ( esperado_codificada /= codificada ) then


report "ERROR en la salida codificada. Valor esperado: " &
std_logic’image(esperado_codificada(1)) &
std_logic’image(esperado_codificada(0)) &
", valor actual: " &
std_logic’image(codificada(1)) &
std_logic’image(codificada(0)) &
" en el instante: " &
time’image(now);
error_count := error_count + 1;
end if;

end loop; -- Final del bucle for de posibles valores de entrada

-- Informe del número total de errores


if (error_count = 0) then
report "Simulación finalizada sin errores";
else
report "ERROR: Hay " &
integer’image(error_count) &
" errores.";
end if;

wait; -- Final de la simulación


end process main;
end architecture bp_codificador_4_2;
-----------------------------------------------------

La ejecución del banco de pruebas indica que no hay ningún error en el


circuito. En la Figura 3.11 se muestra el resultado de la simulación.
Figura 3.11: Formas de onda obtenidas de simular el banco de pruebas.
Casos prácticos de diseño de
4
circuitos secuenciales

Objetivos. Una vez estudiado el contenido del tema deberı́a saber:


– Diseñar en VHDL máquinas de estado finito de Moore y de Mealy sintetizables,
realizando el diseño en base a la descripción de su estructura y/o comporta-
miento.
– Diseñar y programar en VHDL bancos de pruebas de circuitos secuenciales.

Muchos problemas de diseño pueden ser resueltos usando máquinas de estado


finito. Una máquina de estado finito consiste esencialmente en un conjunto de
estados (codificados usando flip-flops) y transiciones entre estos estados, gober-
nadas por un conjunto de bits de condición. Es esta sección trataremos algunos
aspectos del diseño de máquinas de estado finito de Moore y de Mealy usando
VHDL.

– Máquina de Moore. Una máquina de estado finito de Moore (o simplemente,


“máquina de Moore”) es una máquina de estado en la cual las salidas del
circuito dependen del estado actual y no del valor actual de las entradas.

– Máquina de Mealy. Las salidas de una máquina de Mealy dependen del


estado actual y también del valor actual de las entradas.

Ambos tipos de máquina pueden ser diseñados de manera sistemática usando


un método de diseño de máquinas de estado finito descrito en la siguiente sección.

4.1 Diseño de circuitos secuenciales síncronos


Las máquinas de Moore y Mealy pueden ser diseñadas de manera sistemática
siguiendo los pasos descritos a continuación:
100 A. Urquı́a, C. Martı́n Villalba Casos Prácticos de Diseño de Circuitos Digitales con VHDL

1. Dibujar el diagrama de estados del circuito.

2. Crear un conjunto de variables de estado y codificar los estados del diagrama


de estados usando estas variables de estado.

3. Escribir la tabla de transición del estado usando el diagrama dibujado en el


Paso 1 y la codificación de los estados del Paso 2.

4. Formular, a partir de la tabla de transición del estado del Paso 3, las


funciones lógicas simplificadas para el nuevo estado y las salidas.

5. Diseñar el circuito empleando un flip-flop por cada variable de estado, y


lógica combinacional para las funciones de transición del estado y de salida
obtenidas en el Paso 4.

4.1.1 Circuito detector de secuencias


El método anterior puede aplicarse al diseño de un circuito que detecte la secuen-
cia 101. El circuito tiene una única entrada, por la que recibe bits en serie, y una
única salida, en la que genera un bit 1 cuando detecta la secuencia 101 en los
bits de entrada, y genera un 0 en caso contrario. Observese que también deben
detectarse las secuencias cuando se encuentran solapadas, por ejemplo: 10101
El primer paso del diseño es dibujar el diagrama de estados del circuito,
que consiste en un conjunto de estados y (posiblemente) transiciones etiquetadas
entre los estados. En la Figura 4.1 se muestra el diagrama de transición para el
circuito detector de la secuencia 101.
ÊË Ê

s0 ÌÍ Î
ÌÍ Î

ÊË Ê
ÊË Ê s1
s2
ÏË Ï

Figura 4.1: Diagrama de estados del circuito detector de la secuencia 101.

Cada estado del diagrama “recuerda” una porción de la secuencia 101. Las
transiciones entre los estados están etiquetadas x/y, donde x corresponde con el
valor de la entrada que produce la transición, e y corresponde con el valor de
la variable de salida dado el estado en el que empieza la transición y el valor
de entrada x. Dado que la salida depende del estado actual y de la variable de
entrada, este tipo de diagrama corresponde con una máquina de Mealy.
En este tipo de diagrama debe tenerse en cuenta que debe escribirse una
transición desde cada estado por cada posible valor que puede tomar la entrada
en ese estado.
Capı́tulo 4 Casos prácticos de diseño de circuitos secuenciales 101

El segundo paso del método de diseño consiste en codificar los estados.


Puesto que hay tres estados, son necesarias dos variables de estado: A y B. Por
simplicidad en la exposición, realizaremos una codificación binaria de los estados:

Estado A B
S0 0 0
S1 0 1
S2 1 0

En general, unas codificaciones de los estados conducen a circuitos más sen-


cillos que otras, aunque las diferencias tı́picamente no son muy grandes.
El tercer paso del método de diseño consiste en escribir la tabla de transición
de estados y salidas. Esto puede hacerse de manera sencilla a partir del diagrama
de transición de estados mostrado en la Figura 4.1 y de la tabla anterior de
codificación de los estados. La tabla de transición de estados y salidas es la
siguiente:

Estado actual Entrada Próximo estado Salida


A B x NA NB y
S0 : 0 0 0 S0 : 0 0 0
S0 : 0 0 1 S1 : 0 1 0
S1 : 0 1 0 S2 : 1 0 0
S1 : 0 1 1 S1 : 0 1 0
S2 : 1 0 0 S0 : 0 0 0
S2 : 1 0 1 S1 : 0 1 1

El cuarto paso consiste en obtener las funciones lógicas simplificadas que


relacionan el próximo estado y la salida con el estado actual y la entrada. Estas
funciones son:

NA = x B (4.1)
NB = x (4.2)
y=xA (4.3)

Finalmente, el quinto paso consiste en sintetizar el circuito secuencial sı́n-


crono que implemente las funciones lógicas anteriores. Si se usan flip-flops D, las
entradas al flip-flop corresponden con el nuevo estado (DA = N A, DB = N B),
mientras que las salidas del flip-flop corresponden con el estado actual (QA = A,
QB = B). En la Figura 4.2 se muestra el circuito.
102 A. Urquı́a, C. Martı́n Villalba Casos Prácticos de Diseño de Circuitos Digitales con VHDL

Figura 4.2: Circuito detector de la secuencia 101.

4.2 Síntesis de lógica secuencial


El comportamiento y la salida de un bloque de lógica secuencial depende del valor
actual de sus entradas y de sus variables de estado. El valor de las variables de
estado se almacena tı́picamente en elementos de memoria, ya sea en latches o en
flip-flops.

– Suele llamarse latches a aquellos circuitos cuyo estado cambia únicamente


cuando su entrada enable está a un determinado nivel (’0’ ó ’1’). A conti-
nuación, se muestra parte de la architecture de un latch-D.

process (enable, D) is
begin
if (enable = ’1’) then
q <= D;
end if;
end process;

– Suele llamarse flip-flops a aquellos circuitos cuyo estado cambia o bien en


el flanco de subida del reloj, o bien en el flanco de bajada del reloj.

4.2.1 Sentencias condicionales incompletas


Obsérvese que el latch se define empleando una cláusula if-then sin else. Se
denomina sentencias condicionales incompletas a este tipo de sentencias. Este
punto es importante, ya que muestra que las sentencias condicionales incompletas
(if, case, etc. sin else) son sintetizadas mediante latches. Esto es debido a que
la salida debe mantener su valor si ninguna de las condiciones de la cláusula se
satisface.
Capı́tulo 4 Casos prácticos de diseño de circuitos secuenciales 103

Un motivo por el cual podrı́a pensarse en omitir el caso else, es que sea
indiferente el valor que se asigne a las señales en este caso (ya que en la práctica
nunca se producirá). Si no deseamos que el circuito se sintetice mediante un latch,
debemos incluir el caso else en la sentencia condicional y asignar a las señales el
valor ’X’ (don’t care).

4.2.2 Sentencias condicionales completas


Una caracterı́stica inherente a las sentencias if-elsif-else es que las condiciones
no tienen forzosamente que ser excluyentes entre sı́. La herramienta se sı́ntesis
asume, por tanto, que deben comprobarse las condiciones en un cierto orden de
prioridad, generando la lógica para ello. Esto da lugar a circuiterı́a innecesaria en
el caso en que las condiciones sean excluyentes.
En aquellos casos en que las condiciones de la sentencia condicional completa
sean excluyentes entre sı́, es preferible emplear sentencias case o with. Esto
es debido a que las sentencias case y with se sintetizan de manera natural en
multiplexores o estructuras equivalente a multiplexores, que son rápidas y ocupan
relativamente poco área.

4.2.3 Retardos
En la Sección 3.1 se explicó que en la descripción para sı́ntesis de los circuitos
combinacionales debe evitarse el uso de retardos. Lo mismo aplica a la descripción
de circuitos secuenciales. Los retardos en el hardware son dependientes de la
tecnologı́a empleada en su fabricación y están sujetos a la variabilidad del proceso
de fabricación, por ello es extremadamente difı́cil construir circuitos que presenten
un determinado retardo.
Ası́ pues, no es posible sintetizar sentencias tales como wait for x ns. Igual-
mente, no es posible sintetizar sentencias que empleen la cláusula after. Algunas
herramientas de sı́ntesis ignoran estas sentencias, mientras que otras muestran
mensajes de error.
Cuando es preciso emplear retardos para describir adecuadamente el circuito,
puede definirse un retardo constante en la parte superior del código
constant DEL : time := 1 ns;
y usar este retardo en el código del circuito. Por ejemplo:
A <= B after DEL; Puede asignarse un valor positivo a esta constante
de retardo para realizar la simulación del circuito y posteriormente asignarle el
valor cero cuando vaya a realizarse la sı́ntesis.
Obsérvese que esta discusión acerca de los retardos aplica a los circuitos, no
a los bancos de prueba, que no necesitan ser sintetizados.

4.2.4 Inicialización
Debe evitarse inicializar las variables y las señales al declararlas, ya que este tipo
de inicialización no puede ser sintetizada.
104 A. Urquı́a, C. Martı́n Villalba Casos Prácticos de Diseño de Circuitos Digitales con VHDL

La inicialización de una variable o señal implica una acción que se realiza


únicamente una vez al comienzo de la simulación. Si es preciso realizar una acción
al comienzo de la simulación, entonces debe situarse en la secuencia de acciones
que se ejecutan cuando se activa la señal de reset. Estas acciones se definen
tı́picamente dentro de un bloque process sensible a la señal de reset.

4.2.5 Bloques process


La descripción de la architecture de los circuitos secuenciales se basa funda-
mentalmente en el empleo de bloques process. Las asignaciones a señales dentro
de los bloques process deben cumplir que:

– La señal en la parte izquierda de la asignación concurrente debe ser una


señal definida dentro del bloque process, o una señal out o inout de la
interfaz del circuito.

– Las señales en la parte derecha de la asignación concurrente deben ser


señales definidas dentro del bloque process, o señales in o inout de la
interfaz del circuito.

– No se debe asignar valor a una determinada señal dentro de más de un


bloque process. Es decir, cada señal debe ser evaluada en un único bloque
process. Aunque VHDL no impide que se asigne valor a una misma señal en
varios bloques process, esta práctica da lugar a circuito difı́ciles de depurar
y tı́picamente no es soportada por las herramientas de sı́ntesis comerciales.

Para asignar valor a las salidas de los flip-flops y latches dentro de un bloque
process, pueden emplearse sentencias de asignación a señal (usan el operador
<=) y sentencias de asignación a variable (usan el operador :=). Las asignaciones
a variable tienen efecto inmediatamente, mientras que las asignaciones a señal
tienen efecto en un instante de tiempo delta unidades de tiempo posterior al
tiempo simulado actual (suponiendo que no se ha especificado el retraso en la
asignación empleando la cláusula after).
Cuando se emplean bloques process para describir un circuito secuencial,
debe indicarse la lista de sensibilidad de cada bloque process con el fin de con-
trolar cuándo se activa el bloque. Cuando se especifica una lista de sensibilidad,
el simulador no ejecuta el bloque process hasta que no se produce un cambio en
alguna de las señales que componen la lista.
Obsérvese que es posible controlar la ejecución del bloque process mediante
la lista de sensibilidad y también mediante el empleo de cláusulas wait dentro del
cuerpo el bloque process. Sin embargo, no es recomendable emplear este segundo
método (uso de cláusulas wait dentro del bloque process), ya que puede dar lugar
a circuitos no sintetizables.
Si un bloque process no tiene lista de sensibilidad, entonces ese bloque se
ejecuta continuamente, con lo cual su simulación es muy ineficiente. Por este
motivo, es recomendable que todo bloque process tenga su lista de sensibilidad.
Capı́tulo 4 Casos prácticos de diseño de circuitos secuenciales 105

4.3 Flip-flop JK
En esta sección se describe el diseño de un flip-flop JK con reset ası́ncrono activado
al nivel LOW. Este circuito puede encontrarse en dos estados: Q=’0’ y Q=’1’.
La tabla de verdad del circuito, considerando únicamente las entradas J (entrada
set), K (entrada reset), el estado actual (Qt ) y el siguiente estado Qt+1 es la
mostrada a continuación. Las transiciones de estado se producen en el flanco de
subida del reloj.

J (set) K (reset) Nuevo estado


0 0 Qt+1 = Qt
0 1 Qt+1 = 0
1 0 Qt+1 = 1
1 1 Qt+1 = not Qt

ÐÑ ÑÐ

ÓÒ

0 ÒÓ
1
Figura 4.3: Transición de estados de un flip-flop JK. En los arcos del
diagrama se muestra el valor de las señales JK. El bit ’X’ es“don’t care”(por
ejemplo, “0X” representa “00” ó “01”). La transición de reset se representa
mediante una lı́nea punteada.

Cuando la entrada de reset pasa de valer ’1’ a valer ’0’, el circuito pasa al
estado Q=’0’. Se denomina reset ası́ncrono porque la transición al estado ’0’ se
produce en el instante en que cambia la señal de reset, con independencia del
valor de la señal de reloj. La transición de reset se representa mediante una lı́nea
punteada en la Figura 4.3.
El circuito tiene dos salidas: Q y Q. La salida Q es igual al estado y la salida
Q es su inversa: Q = not Q.

4.3.1 Diseño del flip-flop


A continuación, se muestra el código VHDL del flip-flop JK con reset ası́ncrono
activado al nivel LOW. La architecture contiene un bloque process que es
sensible a la señal de reset y a la señal de reloj. En el cuerpo del bloque process
se examina primero la señal de reset, ya que en caso de estar activa esa señal (con
valor ’0’) la máquina debe pasar al estado Q=’0’.

------------------------------------------------
-- Biestable JK con reset ası́ncrono en nivel LOW
library IEEE;
use IEEE.std_logic_1164.all;
106 A. Urquı́a, C. Martı́n Villalba Casos Prácticos de Diseño de Circuitos Digitales con VHDL

entity flipflop_JK is
port ( q, q_n : out std_logic;
clk, J, K, reset_n : in std_logic );
end entity flipflop_JK;

architecture flipflop_JK of flipflop_JK is


signal q_interna : std_logic;
begin
q <= q_interna;
q_n <= not q_interna;
process (reset_n, clk) is
variable JK : std_logic_vector(1 downto 0);
begin
if (reset_n = ’0’) then
q_interna <= ’0’;
elsif rising_edge(clk) then
JK := J & K;
case (JK) is
when "01" => q_interna <= ’0’;
when "10" => q_interna <= ’1’;
when "11" => q_interna <= not q_interna;
when others => null;
end case;
end if;
end process;
end architecture flipflop_JK;
------------------------------------------------

4.3.2 Banco de pruebas


En el caso de los circuitos combinacionales, el objetivo del programa de test es
comprobar (cuando esto es posible) todas las posibles combinaciones de valores
de las entradas al circuito. En los circuitos secuenciales, el programa de test debe
recorrer (cuando esto es posible) todos los arcos del diagrama de estado, para
cada uno de los valores de las entradas que producen la transición.
En el caso del biestable JK, esto implica testear 8 transiciones. En la Figura 4.4
se indica el orden en que el programa de test recorrerá los arcos (número inscrito
en una circunferencia), y qué valores de las entradas se aplicará en cada caso para
producir la transición.
En el banco de pruebas se ha definido un procedure, que comprueba que los
valores actuales de la salida del flip-flop coinciden con los esperados, mostrando
el correspondiente mensaje en caso de que no coincidan.
Capı́tulo 4 Casos prácticos de diseño de circuitos secuenciales 107

Ø ÔÔ Ý ÔÔ
Ù ÕÖ Þ ÖÕ
Û ÕÖ
ß ××

0 1
à

Ú ÖÕ
Ü ××

Figura 4.4: Orden en que el programa de test recorre los arcos del diagrama
de transiciones.

Obsérvese que la sentencia wait que hay al final del bloque process finaliza
la ejecución de dicho bloque, pero no la simulación, ya que la simulación de
las sentencias de asignación concurrente a las señales de reset y reloj se realiza
indefinidamente. Por tanto, la simulación del banco de pruebas no finaliza por sı́
misma, siendo preciso fijar su duración: 900 ns.

--------------------------------------
-- Banco de pruebas del flip-flop JK
library IEEE;
use IEEE.std_logic_1164.all;
use IEEE.numeric_std.all;

entity bp_flipflopJK is
end entity bp_flipflopJK;

architecture bp_flipflopJK of bp_flipflopJK is


constant PERIODO : time := 100 ns; -- Reloj
signal q, q_n : std_logic; -- Salidas UUT
signal clk : std_logic := ’0’; -- Entradas UUT
signal J, K, reset_n : std_logic;

component flipflop_JK is
port ( q, q_n : out std_logic;
clk, J, K, reset_n : in std_logic );
end component flipflop_JK;

-- Procedimiento para comprobar las salidas del flip-flop


procedure comprueba_salidas
( esperado_q : std_logic;
actual_q, actual_q_n : std_logic;
error_count : inout integer) is
begin
-- Comprueba q
if ( esperado_q /= actual_q ) then
report "ERROR: Estado esperado (" &
108 A. Urquı́a, C. Martı́n Villalba Casos Prácticos de Diseño de Circuitos Digitales con VHDL

std_logic’image(esperado_q) &
"), estado actual (" &
std_logic’image(actual_q) &
"), instante: " &
time’image(now);
error_count := error_count + 1;
end if;
-- Comprueba q_n
if ( (not esperado_q) /= actual_q_n ) then
report "ERROR: q_n esperado (" &
std_logic’image((not esperado_q)) &
"), valor actual (" &
std_logic’image(actual_q_n) &
"), instante: " &
time’image(now);
error_count := error_count + 1;
end if;
end procedure comprueba_salidas;

begin
-- Instanciar y conectar UUT
uut : component flipflop_JK port map
(q, q_n, clk, J, K, reset_n);

reset_n <= ’1’,


’0’ after (PERIODO/4),
’1’ after (PERIODO+PERIODO/4);
clk <= not clk after (PERIODO/2);

gen_vec_test : process is
variable error_count : integer := 0; -- Núm. errores
begin
report "Comienza la simulación";

-- Vectores de test y comprobación del resultado


J <= ’0’; K <= ’0’; wait for PERIODO; -- 1
comprueba_salidas(’0’,q,q_n,error_count);
J <= ’0’; K <= ’1’; wait for PERIODO; -- 2
comprueba_salidas(’0’,q,q_n,error_count);
J <= ’1’; K <= ’0’; wait for PERIODO; -- 3
comprueba_salidas(’1’,q,q_n,error_count);
J <= ’0’; K <= ’1’; wait for PERIODO; -- 4
comprueba_salidas(’0’,q,q_n,error_count);
J <= ’1’; K <= ’1’; wait for PERIODO; -- 5
comprueba_salidas(’1’,q,q_n,error_count);
Capı́tulo 4 Casos prácticos de diseño de circuitos secuenciales 109

J <= ’0’; K <= ’0’; wait for PERIODO; -- 6


comprueba_salidas(’1’,q,q_n,error_count);
J <= ’1’; K <= ’0’; wait for PERIODO; -- 7
comprueba_salidas(’1’,q,q_n,error_count);
J <= ’1’; K <= ’1’; wait for PERIODO; -- 8
comprueba_salidas(’0’,q,q_n,error_count);
J <= ’0’; K <= ’0’; -- Deja el flip-flop en el estado ’0’

-- Informe final
if (error_count = 0) then
report "Simulación finalizada sin errores";
else
report "ERROR: Hay " &
integer’image(error_count) &
" errores.";
end if;

wait; -- Final del bloque process, pero como


-- la architecture tiene sentencias de
-- asignación concurrente, esta sentencia
-- wait no finaliza la simulación
end process gen_vec_test;
end architecture bp_flipflopJK;
--------------------------------------

La simulación del banco de pruebas se realiza con cero errores. En la Figura 4.5
se muestra el resultado obtenido de la simulación.

Figura 4.5: Resultado de la ejecución del banco de pruebas del flip-flop JK.

4.4 Máquinas de estado finito de Moore


Hay varias maneras de escribir código VHDL para una máquina de Moore. En
primer lugar, puede escogerse describir el comportamiento o la estructura del
circuito. En la mayorı́a de los casos es preferible describir el comportamiento
110 A. Urquı́a, C. Martı́n Villalba Casos Prácticos de Diseño de Circuitos Digitales con VHDL

del circuito, ya que este tipo de descripción suele ser menos propensa a errores
y las herramientas de sı́ntesis convertirán estos diseños en implementaciones
optimizadas.
En la Figura 4.6 se muestra una máquina de Moore sencilla. La transición
entre los tres estados depende del valor de la entrada, x. La salida del circuito, z,
vale 1 en el estado S2 y 0 en los demás estados. Este código puede ser adaptado
fácilmente para la descripción de otras máquinas de Moore.

Sá/ 0 1
0

1 Sâ /1
0
Sã / 0 0

Figura 4.6: Maquina de estado finito de Moore.

4.4.1 Diseño de la máquina


A continuación se muestra el código VHDL que describe la máquina de Moore
mostrada en la Figura 4.6. En primer lugar, se define un package con las constan-
tes que serán usadas en el circuito y en el banco de pruebas. Definir las constantes
globales de esta manera facilita realizar cambios globales y la legibilidad del
código.

-------------------------------------------------------
-- Paquete con la definición de las constantes globales
library IEEE;
use IEEE.std_logic_1164.all;
package STATE_CONSTANTS is
constant STATE_BITS: integer := 2; -- Bits codifican estado
constant S0: std_logic_vector(1 downto 0) := "00"; -- Estados
constant S1: std_logic_vector(1 downto 0) := "01";
constant S2: std_logic_vector(1 downto 0) := "10";
end package;
-------------------------------------------------------

El código VHDL que describe el comportamiento de la máquina de estado


finito mostrada en la Figura 4.6 es el siguiente.

------------------------------------------------------
-- Máquina de Moore
library IEEE;
Capı́tulo 4 Casos prácticos de diseño de circuitos secuenciales 111

use IEEE.std_logic_1164.all;
use work.STATE_CONSTANTS.all;

-- Definición de la entidad
entity maquinaMooreSimple is
port( z : out std_logic; -- Se~
nal de salida
state : out std_logic_vector(STATE_BITS-1 downto 0);
-- Estado actual de la máquina
reset_n : in std_logic; -- Se~nal reset activada en bajo
clk : in std_logic; -- Se~nal de reloj
x : in std_logic); -- Se~
nal de entrada
end entity maquinaMooreSimple;

-- Definición de la arquitectura
architecture maquinaMooreSimple of maquinaMooreSimple is
signal internal_state: std_logic_vector(STATE_BITS-1 downto 0);
begin
state <= internal_state; -- Muestra el estado

-- Genera la salida
salida: process(internal_state) is
begin
case internal_state is
when S0 => z <= ’0’;
when S1 => z <= ’0’;
when S2 => z <= ’1’;
when others => z <= ’X’;
end case;
end process salida;

-- Genera el siguiente estado


proximo_estado: process(reset_n,clk) is
begin
if (reset_n = ’0’) then -- Reset ası́ncrono
internal_state <= S0;
elsif rising_edge(clk) then -- En flanco subida del reloj
case internal_state is
when S0 => -- Estado actual: S0
if (x = ’1’) then
internal_state <= S1;
else
internal_state <= S2;
end if;
when S1 => -- Estado actual: S1
if (x = ’0’) then
112 A. Urquı́a, C. Martı́n Villalba Casos Prácticos de Diseño de Circuitos Digitales con VHDL

internal_state <= S2;


end if;
when S2 => -- Estado actual: S2
if (x = ’0’) then
internal_state <= S0;
end if;
when others => -- Por completitud
internal_state <= "XX";
end case;
end if;
end process proximo_estado;

end architecture maquinaMooreSimple;


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

En el código anterior, puede observarse que:

– La interfaz del circuito está compuesta por dos puertos de salida (la salida
y el estado actual) y tres puertos de entrada (señal de reset ası́ncrono, reloj
y entrada). Cuando la señal de reset (reset_n) pasa de valer 1 a valer 0,
entonces la máquina pasa al estado S0 .

– Se ha definido una señal interna a la architecture, llamada internal_state,


que almacena el estado actual en que se encuentra la máquina. Cabe pregun-
tarse por qué no se usa directamente la señal state, ya que ambas señales
representan lo mismo y, de hecho, la sentencia
state <= internal_state;
hace que ambas tengan el mismo valor. El motivo es que, por ser state
una señal de salida de la interfaz, no puede ser leı́da en el cuerpo de la
architecture. Puesto que internal_state es una señal interna, puede ser
leı́da y escrita.

– La architecture contiene dos bloques process:

1. El primero, que es activado cuando hay un cambio en internal_state,


describe los cambios en la señal de salida, z.
2. El segundo, que es activado cuando cambia la señal de reset ası́ncrono
(reset_n) o el reloj (clk), describe los cambios en el estado de la
máquina, actualizando el valor de la señal internal_state.
Puesto que se comprueba antes el valor de reset_n, esta señal tiene
prioridad sobre la señal de reloj.
Se emplea la función estándar de VHDL rising edge para representar
que las transiciones en el estado sólo se producen en el flanco de subida
de la señal de reloj.

– Se ha añadido una cláusula when other al final de los dos bloques case,
con el fin de contemplar todos los casos posibles. Obsérvese que se asigna
Capı́tulo 4 Casos prácticos de diseño de circuitos secuenciales 113

el valor ’X’ (don’t care) a la señal de salida. Esta es una buena práctica,
ya que con ello se ayuda a la herramienta de sı́ntesis a optimizar el circuito
combinacional para la señal de salida (z).

4.4.2 Banco de pruebas


A continuación, se muestra el código VHDL de un banco de pruebas que puede
usarse para comprobar el funcionamiento de la máquina de estado finito. El
programa de test ejercita completamente la máquina: todos los arcos de las
transiciones son recorridos al menos una vez.
En la Figura 4.7 se indica el instante de tiempo en el cual se produce la
transición entre los estados. La constante T es el periodo de la señal de reloj, que
en el código VHDL del banco de pruebas de denomina PERIODO y toma el valor
100 ns. La señal de reloj, que inicialmente vale 0, tiene un periodo (PERIODO)
de T = 100 ns. Esto implica que los flancos de subida de la señal de reloj se
producen en los instantes: 0.5 · T = 50 ns, 1.5 · T = 150 ns, 2.5 · T = 250 ns, . . .
que son precisamente los instantes en que se producen las sucesivas transiciones
en el estado, según se muestra en la Figura 4.7. Para generar la señal de reloj se
emplea la siguiente sentencia concurrente:
clk <= not clk after ( PERIODO/2 );
donde se asume que la señal de reloj ha sido inicializada al valor ’0’. Obsérvese
que de esta forma se crea una señal de reloj infinitamente larga, con lo cual la
simulación no finalizará automáticamente, sino que hay que definir el instante de
finalización.
íìí î
⋅ ü òóôõö÷ö øùù úû
= =

Sä / 0
ëìí î
ñìí î


ðìí î
⋅ ïìí î

S å /1
ýþÿ 

Sæ / 0
é ê
è ⋅
ç

Figura 4.7: Transiciones en el estado realizadas durante el test.

En el código del banco de pruebas, se define un procedimiento para comparar


el valor esperado del estado y la salida de la máquina con los actuales. De esta
forma el código se hace más fácilmente comprensible.

------------------------------------------------------
-- Banco de pruebas para la máquina de Moore
library IEEE;
use IEEE.std_logic_1164.all;
use IEEE.numeric_std.all;
114 A. Urquı́a, C. Martı́n Villalba Casos Prácticos de Diseño de Circuitos Digitales con VHDL

use work.STATE_CONSTANTS.all;

-- Definición de la entity
entity bp_maquinaMooreSimple is
constant PERIODO : time := 100 ns; -- Periodo reloj
end entity bp_maquinaMooreSimple;

-- Definición de la architecture
architecture bp_maquinaMooreSimple of bp_maquinaMooreSimple is
signal z : std_logic;
signal state : std_logic_vector(STATE_BITS-1 downto 0);
signal reset_n : std_logic;
signal clk : std_logic := ’0’; -- Inicializada a ’0’
signal x : std_logic;

-- Declaración del componente: UUT


component maquinaMooreSimple is
port( z : out std_logic; -- Se~
nal de salida
state : out std_logic_vector(STATE_BITS-1 downto 0);
-- Estado actual de la máquina
reset_n : in std_logic; -- Se~nal reset activada en bajo
clk : in std_logic; -- Se~nal de reloj
x : in std_logic); -- Se~
nal de entrada
end component maquinaMooreSimple;

-- Procedimiento para comprobar el resultado


procedure comprueba_state_z
( esperado_state : std_logic_vector(STATE_BITS-1 downto 0);
esperado_z : std_logic;
actual_state : std_logic_vector(STATE_BITS-1 downto 0);
actual_z : std_logic;
error_count : inout integer ) is
begin
-- Comprueba el estado
assert ( esperado_state = actual_state )
report "ERROR : estado esperado (" &
std_logic’image(esperado_state(1)) &
std_logic’image(esperado_state(0)) &
"), estado actual (" &
std_logic’image(actual_state(1)) &
std_logic’image(actual_state(0)) &
") en el instante " &
time’image(now);
if ( esperado_state /= actual_state ) then
error_count := error_count + 1;
Capı́tulo 4 Casos prácticos de diseño de circuitos secuenciales 115

end if;
-- Comprueba la salida
if ( esperado_z /= actual_z ) then
report "ERROR: salida esperada (" &
std_logic’image(esperado_z) &
"), salida actual (" &
std_logic’image(actual_z) &
") en el instante " &
time’image(now);
error_count := error_count + 1;
end if;
end procedure comprueba_state_z;

-- Cuerpo de la architecture
begin
-- Instancia UUT
UUT : component maquinaMooreSimple port map
( z, state, reset_n, clk, x );

-- Genera un único pulso LOW para reset_n


-- En el instante PERIODO/4 se resetea la máquina
reset_n <= ’1’,
’0’ after ( PERIODO/4 ),
’1’ after ( PERIODO + PERIODO/4 );

-- Genera se~
nal clk, asumiendo que se inicializó a 0
-- Flanco de subida en los instantes:
-- PERIODO/2, PERIODO+PERIODO/2, 2*PERIODO+PERIODO/2, ...
clock : clk <= not clk after ( PERIODO/2 );

-- main process:
-- genera vectores de test y comprueba resultados
main : process is
variable error_count : integer := 0; -- Num. errores
begin
report "Comienza la simulación";
x <= ’0’; -- Valor inicial de entrada a UUT
wait for PERIODO;
-- En el instante PERIODO, el estado deberı́a ser S0
comprueba_state_z(S0, ’0’, state, z, error_count);
wait for PERIODO;
-- En el instante 2*PERIODO, el estado deberı́a ser S2
comprueba_state_z(S2, ’1’, state, z, error_count);
x <= ’1’;
wait for PERIODO;
116 A. Urquı́a, C. Martı́n Villalba Casos Prácticos de Diseño de Circuitos Digitales con VHDL

-- En el instante 3*PERIODO, el estado deberı́a ser S2


comprueba_state_z(S2, ’1’, state, z, error_count);
x <= ’0’;
wait for PERIODO;
-- En el instante 4*PERIODO, el estado deberı́a ser S0
comprueba_state_z(S0, ’0’, state, z, error_count);
x <= ’1’;
wait for PERIODO;
-- En el instante 5*PERIODO, el estado deberı́a ser S1
comprueba_state_z(S1, ’0’, state, z, error_count);
wait for PERIODO;
-- En el instante 6*PERIODO, el estado deberı́a ser S1
comprueba_state_z(S1, ’0’, state, z, error_count);
x <= ’0’;
wait for PERIODO;
-- En el instante 7*PERIODO, el estado deberı́a ser S2
comprueba_state_z(S2, ’1’, state, z, error_count);
x <= ’1’; -- El estado final es S2
wait for PERIODO;
if (error_count = 0) then
report "Simulación finalizada con 0 errores";
else
report "ERROR: hay " &
integer’image(error_count) &
" errores.";
end if;
wait; -- Final de la ejecución del bloque process.
-- La simulación continua debido a la sentencia de
-- asignación a la se~
nal clk
end process main;
end architecture bp_maquinaMooreSimple;

En la Figura 4.8 se muestran las formas de onda obtenidas al ejecutar el banco


de pruebas. El test de ejecuta con cero errores.

Figura 4.8: Resultado de la ejecución del test.


Capı́tulo 4 Casos prácticos de diseño de circuitos secuenciales 117

4.4.3 Modelado estructural


Ahora veremos cómo describir la máquina de estado finito de la Figura 4.6
empleando código VHDL estructural. Usando código estructural se tiene mayor
control acerca de la lógica que se emplea en el diseño, con lo cual pueden conse-
guirse circuitos más optimizados que los dados por las herramientas de sı́ntesis a
partir de la descripción del comportamiento. Sin embargo, implica realizar parte
del diseño manualmente, con el consiguiente riesgo de cometer errores.
Para emplear código VHDL estructural, en primer lugar hay que decidir qué
componentes van a usarse en el diseño. Emplearemos puertas lógicas básicas
(AND, OR, inversor, NAND, NOR y XOR), ası́ como flip-flops tipo D tales como
el descrito en el Ejemplo 2.3.4.
A continuación, debemos obtener las funciones lógicas para el cálculo de la
salida y del siguiente estado. La tabla de transición de estados y salidas para la
máquina descrita en la Figura 4.6 es la siguiente:

Estado actual Entrada Próximo estado Salida


A B x NA NB z
S0 : 0 0 0 S2 : 1 0 0
S0 : 0 0 1 S1 : 0 1 0
S1 : 0 1 0 S2 : 1 0 0
S1 : 0 1 1 S1 : 0 1 0
S2 : 1 0 0 S0 : 0 0 1
S2 : 1 0 1 S2 : 1 0 1

Las funciones lógicas simplificadas que relacionan el próximo estado (N A,


N B) y la salida (z), con el estado actual (A, B) y la entrada (x) son:

NA = x A + x A (4.4)
NB = x A (4.5)
z=A (4.6)

Puede escribirse el siguiente código VHDL estructural a partir de la funciones


lógicas anteriores. Se define una nueva architecture para la entity del circuito
anteriormente definida.

------------------------------------------------------
-- Máquina de Moore, dise~
no estructural
library IEEE;
use IEEE.std_logic_1164.all;

-- Definición de la arquitectura
architecture maquinaMooreSimple_estruc of maquinaMooreSimple is
signal A, B : std_logic; -- Variables de estado actuales
signal NA, NB : std_logic; -- Próximas variables de estado
118 A. Urquı́a, C. Martı́n Villalba Casos Prácticos de Diseño de Circuitos Digitales con VHDL

-- Componente: flip-flop D
component flipflop_D is
port ( q, q_n : out std_logic;
d, clk, reset_n : in std_logic);
end component flipflop_D;

begin
state <= A & B; -- Muestra estado actual en el puerto de salida

-- Conexiones de los flip-flops


-- Las salidas q_n se dejan sin conectar
dff_A: component flipflop_D port map
( q => A, d => NA, clk => clk, reset_n => reset_n );
dff_B: component flipflop_D port map
( q => B, d => NB, clk => clk, reset_n => reset_n );

-- Funciones para el cálculo del nuevo estado y la salida


NA <= ((not x) and (not A)) or (x and A);
NB <= x and (not A);
z <= A;
end architecture maquinaMooreSimple_estruc;
------------------------------------------------------

Puede emplearse el banco de pruebas descrito en la Sección 4.4.2 para testear


esta descripción del circuito. Se obtienen los mismos resultados que se obtuvieron
cuando se hizo el test de la descripción del comportamiento (véase la Figura 4.8).
Los resultados del test se muestran en la Figura Figura 4.9.

Figura 4.9: Resultado de la ejecución del test.


Capı́tulo 4 Casos prácticos de diseño de circuitos secuenciales 119

4.5 Máquinas de estado finito de Mealy


En las máquinas de Mealy, las salidas del circuito dependen del estado actual y
del valor actual de las entradas. Ası́ pues, aunque la máquina permanezca en un
determinado estado, sus salidas pueden cambiar si cambian las entradas.
Como ejemplo de implementación de una máquina de Mealy, consideremos
la máquina para el reconocimiento de la secuencia de bits 0110 mostrada en la
Figura 4.10. Obsérvese que se permite el solapamiento de secuencias (por ejemplo,
0110110).
La salida de la máquina es un ’1’ lógico cada vez que se detecta el patrón
0110 en la secuencia de bits de entrada, que se supone que está sincronizada con
el reloj de la máquina. El tiempo que transcurre entre la entrada del último ’0’
del patrón y la salida del ’1’ es igual al retardo de una puerta lógica. Para los
demás bits de la secuencia de entrada, la salida de la máquina es ’0’.
 

 
  S  
 
S  
 
S
 
S

Figura 4.10: Diagrama de estado de una máquina de Mealy para el


reconocimiento de la secuencia 0110.

4.5.1 Diseño de la máquina


Además de la entrada serie de la secuencia de bits (x) y la entrada del reloj (clk),
la máquina tiene una entrada de reset sı́ncrono activada en ’0’ (reset_n). Esto
significa que si cuando se produce un flanco de subida de la señal del reloj, la
entrada reset_n vale ’0’, entonces se resetea la máquina, es decir, pasa al estado
S0.
La máquina tiene dos salidas: el estado actual de la máquina (state) y la
salida de detección del patrón 0110 (z).
Las constantes globales, que son usadas tanto en el diseño del circuito como
en el banco de pruebas, son definidas en el package mostrado a continuación.

----------------------------------------
-- Definición de las constantes globales
library IEEE;
use IEEE.std_logic_1164.all;
120 A. Urquı́a, C. Martı́n Villalba Casos Prácticos de Diseño de Circuitos Digitales con VHDL

package seq0110_CONST is
constant STATE_BITS : integer := 2; -- Num. bits del estado
constant S0 : std_logic_vector(1 downto 0) := "00";
constant S1 : std_logic_vector(1 downto 0) := "01";
constant S2 : std_logic_vector(1 downto 0) := "10";
constant S3 : std_logic_vector(1 downto 0) := "11";
end package seq0110_CONST;
----------------------------------------

A continuación se muestra el código VHDL que describe el comportamiento


de la máquina. Obsérvese que se han definido dos bloques process: uno para
generar la salida, que es sensible al estado y a la entrada, y otro para generar el
próximo estado y resetear al máquina, que es sensible únicamente a la señal de
reloj. Puesto que la máquina tiene reset sı́ncrono, este segundo bloque process
no es sensible a la señal de reset.

--------------------------------------------------
-- Máquina de Mealy detectora de la secuencia 0110
library IEEE;
use IEEE.std_logic_1164.all;
use work.seq0110_CONST.all;

-- Definición de la entity
entity seq0110 is
port ( z : out std_logic; -- Se~
nal de salida
state : out std_logic_vector(STATE_BITS-1 downto 0);
-- Estado actual
reset_n : in std_logic; -- Reset sı́ncrono activado LOW
clk : in std_logic; -- Se~
nal de reloj
x : in std_logic ); -- Bit de entrada
end entity seq0110;

-- Definición de la architecture
architecture seq0110 of seq0110 is
signal internal_state : std_logic_vector(STATE_BITS-1 downto 0);
begin
state <= internal_state;

-- Cálculo de la salida
calculo_salida: process (internal_state, x) is
begin
if ( (internal_state = S3) and (x = ’0’) ) then
z <= ’1’;
else
z <= ’0’;
Capı́tulo 4 Casos prácticos de diseño de circuitos secuenciales 121

end if;
end process calculo_salida;

-- Cálculo del próximo estado


proximo_estado: process (clk) is
begin
if ( (reset_n = ’0’) and rising_edge(clk) ) then -- Reset sı́ncrono
internal_state <= S0;
elsif rising_edge(clk) then -- Flanco de subida del reloj
case internal_state is
when S0 =>
if (x = ’0’) then -- Primer bit del patrón
internal_state <= S1;
else
internal_state <= S0;
end if;
when S1 =>
if (x = ’1’) then -- Segundo bit del patrón
internal_state <= S2;
else
internal_state <= S1;
end if;
when S2 =>
if (x = ’1’) then -- Tercer bit del patrón
internal_state <= S3;
else
internal_state <= S1;
end if;
when others =>
if (x = ’0’) then -- Cuarto bit del patrón
internal_state <= S1;
else
internal_state <= S0;
end if;
end case;
end if;
end process proximo_estado;
end architecture seq0110;
--------------------------------------------------

El bloque process usado para generar el próximo estado corresponde di-


rectamente con el diagrama mostrado en la Figura 4.10. La señal de reset no
se ha incluido en la lista de señales a las que es sensible el bloque. Ası́ pues,
este bloque sólo es activado cuando se produce un cambio en la señal de reloj:
la condición if ( (reset_n = ’0’) and rising_edge(clk) ) sólo se comprueba
122 A. Urquı́a, C. Martı́n Villalba Casos Prácticos de Diseño de Circuitos Digitales con VHDL

cuando se produce un cambio en la señal de reloj. De esta forma, se implementa


un reset sı́ncrono.
El bloque process usado para generar la señal de salida podrı́a reemplazarse
por la siguiente sentencia concurrente:

z <= ’1’ when ( (internal_state = S3) and (x = ’0’) ) else ’0’;

que es activada cada vez que se produce un cambio en alguna de las señales de
la parte derecha de la asignación.
Puesto que éste es un bloque combinacional, la duración de la señal ’1’ de
salida puede ser más pequeña que un ciclo de reloj, ya que su duración depende
del tiempo durante el cual la entrada x siga valiendo ’0’ mientras la máquina
permanezca en el estado S3.
Para garantizar que la salida ’1’ tiene una duración de al menos un ciclo de
reloj, es necesario hacer pasar la señal de salida por un flip-flop D. Esto puede
hacerse añadiendo a la descripción de la arquitectura el siguiente bloque process:

ffD_salida: process (clk) is


begin
if ( rising_edge(clk) ) then
z_long <= z;
end if;
end process ffD_salida;

y haciendo que z_long sea la salida del circuito. La definición del circuito, modi-
ficada de la forma descrita anteriormente, es mostrada a continuación.

--------------------------------------------------
-- Máquina de Mealy detectora de la secuencia 0110
library IEEE;
use IEEE.std_logic_1164.all;
use work.seq0110_CONST.all;

-- Definición de la entity
entity seq0110 is
port ( z_long : out std_logic; -- Se~
nal de salida
state : out std_logic_vector(STATE_BITS-1 downto 0);
-- Estado actual
reset_n : in std_logic; -- Reset sı́ncrono activado LOW
clk : in std_logic; -- Se~
nal de reloj
x : in std_logic ); -- Bit de entrada
end entity seq0110;

-- Definición de la architecture
architecture seq0110 of seq0110 is
signal internal_state : std_logic_vector(STATE_BITS-1 downto 0);
signal z : std_logic; -- Se~
nal de salida obtenida
Capı́tulo 4 Casos prácticos de diseño de circuitos secuenciales 123

-- a partir del estado actual


-- y la entrada actual, mediante
-- un circuito combinacional
begin
state <= internal_state;

-- Cálculo de la salida
-- z <= ’1’ when ( (internal_state = S3) and (x = ’0’) ) else ’0’;
calculo_salida: process (internal_state,x) is
begin
if ( (internal_state = S3) and (x = ’0’) ) then
z <= ’1’;
else
z <= ’0’;
end if;
end process calculo_salida;

-- Se hace pasar la salida por un flip-flop D para garantizar que


-- se mantiene su valor un ciclo de reloj
ffD_salida: process (clk) is
begin
if ( rising_edge(clk) ) then
z_long <= z;
end if;
end process ffD_salida;

-- Cálculo del próximo estado


proximo_estado: process (clk) is
begin
if ( (reset_n = ’0’) and rising_edge(clk) ) then -- Reset sı́ncrono
internal_state <= S0;
elsif rising_edge(clk) then -- Flanco de subida del reloj
case internal_state is
when S0 =>
if (x = ’0’) then -- Primer bit del patrón
internal_state <= S1;
else
internal_state <= S0;
end if;
when S1 =>
if (x = ’1’) then -- Segundo bit del patrón
internal_state <= S2;
else
internal_state <= S1;
end if;
124 A. Urquı́a, C. Martı́n Villalba Casos Prácticos de Diseño de Circuitos Digitales con VHDL

when S2 =>
if (x = ’1’) then -- Tercer bit del patrón
internal_state <= S3;
else
internal_state <= S1;
end if;
when others =>
if (x = ’0’) then -- Cuarto bit del patrón
internal_state <= S1;
else
internal_state <= S0;
end if;
end case;
end if;
end process proximo_estado;
end architecture seq0110;
--------------------------------------------------

Para mostrar el funcionamiento del circuito, puede diseñarse un pequeño


banco de pruebas que introduzca algunos vectores de test. A continuación, se
muestra un ejemplo de este tipo de banco de pruebas.

------------------------------------------------------
-- Banco de pruebas que introduce algunos vectores de
-- test en la máquina detectora de la secuencia 0110
library IEEE;
use IEEE.std_logic_1164.all;
use IEEE.numeric_std.all;
use work.seq0110_CONST.all;

entity bp1_seq0110 is
constant PERIODO : time := 100 ns; -- Periodo reloj
end entity bp1_seq0110;

architecture bp1_seq0110 of bp1_seq0110 is


signal z_long : std_logic; -- Salida de la máquina
signal state : std_logic_vector(STATE_BITS-1 downto 0);
-- Estado actual
signal reset_n : std_logic; -- Reset sı́ncrono activado LOW
signal clk : std_logic := ’0’; -- Se~
nal de reloj
signal x : std_logic; -- Entrada a la máquina

-- Declaración del componente


component seq0110 is
port ( z_long : out std_logic;
Capı́tulo 4 Casos prácticos de diseño de circuitos secuenciales 125

state : out std_logic_vector(STATE_BITS-1 downto 0);


reset_n : in std_logic;
clk : in std_logic;
x : in std_logic );
end component seq0110;

begin
-- Instanciar UUT
UUT: component seq0110 port map
( z_long, state, reset_n, clk, x );

-- Generar un pulso LOW en la entrada de reset


reset_n <= ’1’,
’0’after ( PERIODO/4 ),
’1’after ( PERIODO + PERIODO/4 );

-- Generar la se~
nal de reloj,
-- asumiendo que ha sido inicializada a ’0’
clk <= not clk after ( PERIODO/2 );

-- Generar algunos vectores de test


main : process is
begin
report "Comienza la simulación";
x <= ’0’; wait for 2*PERIODO;
x <= ’1’; wait for PERIODO;
x <= ’1’; wait for PERIODO;
x <= ’0’; wait for PERIODO;
x <= ’1’; wait for PERIODO;
x <= ’1’; wait for PERIODO;
x <= ’0’; wait for PERIODO;
x <= ’1’; wait for PERIODO;
wait; -- Detiene este bloque process, pero no
-- finaliza la simulación debido a que
-- hay asignaciones concurrentes
end process main;
end architecture bp1_seq0110;

Ejecutando este banco de pruebas durante 1200 ns, se obtienen las señales
mostradas en la Figura 4.11. Obsérvese que la señal z vale ’1’ mientras el circuito
se encuentra en el estado S3 y la entrada vale ’0’. La señal z está conectada a la
entrada de un flip-flop D, cuya salida es la señal z_long, que mantiene su valor a
’1’ durante un ciclo completo de reloj.
126 A. Urquı́a, C. Martı́n Villalba Casos Prácticos de Diseño de Circuitos Digitales con VHDL

Figura 4.11: Resultado de la simulación del circuito detector del patrón


0110.

4.5.2 Banco de pruebas


El banco de pruebas anterior da cierta información acerca del comportamiento del
circuito, pero no lo prueba de manera sistemática. A continuación, se muestra el
código de un banco de pruebas que testea sistemáticamente el circuito, pasando
al menos una vez por cada uno de los arcos de transición entre estados de la
máquina. El orden en el cual el banco de pruebas recorre los arcos de transición
de la máquina es mostrado en la Figura 4.12. El código del banco de pruebas es
mostrado a continuación.
4

2
10 S 5 7 11
3

S S
1 6
13

9 S 8 12

Figura 4.12: Orden en que el programa de test recorre los arcos del diagrama
de estado de la máquina.

------------------------------------------------------
-- Banco de pruebas - Máquina detectora secuencia 0110
library IEEE;
use IEEE.std_logic_1164.all;
use IEEE.numeric_std.all;
use work.seq0110_CONST.all;

entity bp_seq0110 is
constant PERIODO : time := 100 ns; -- Periodo reloj
end entity bp_seq0110;

architecture bp_seq0110 of bp_seq0110 is


signal z_long : std_logic; -- Salida de la máquina
signal state : std_logic_vector(STATE_BITS-1 downto 0);
Capı́tulo 4 Casos prácticos de diseño de circuitos secuenciales 127

-- Estado actual
signal reset_n : std_logic; -- Reset sı́ncrono activado LOW
signal clk : std_logic := ’0’; -- Se~
nal de reloj
signal x : std_logic; -- Entrada a la máquina

-- Declaración del componente


component seq0110 is
port ( z_long : out std_logic;
state : out std_logic_vector(STATE_BITS-1 downto 0);
reset_n : in std_logic;
clk : in std_logic;
x : in std_logic );
end component seq0110;

-- Procedimiento para comprobar si se produce error


procedure comprueba_estado_salida
( esperado_state : std_logic_vector(STATE_BITS-1 downto 0);
esperado_z : std_logic;
actual_state : std_logic_vector(STATE_BITS-1 downto 0);
actual_z : std_logic;
error_count : inout integer) is
begin
-- Comprueba el estado
assert( esperado_state = actual_state )
report "ERROR: Estado esperado (" &
std_logic’image(esperado_state(1)) &
std_logic’image(esperado_state(0)) &
"), estado actual (" &
std_logic’image(actual_state(1)) &
std_logic’image(actual_state(0)) &
"), instante: " &
time’image(now);
if ( esperado_state /= actual_state ) then
error_count := error_count + 1;
end if;

-- Comprueba salida
assert( esperado_z = actual_z )
report "ERROR: Salida esperada (" &
std_logic’image(esperado_z) &
"), salida actual (" &
std_logic’image(actual_z) &
"), instante: " &
time’image(now);
if ( esperado_z /= actual_z ) then
128 A. Urquı́a, C. Martı́n Villalba Casos Prácticos de Diseño de Circuitos Digitales con VHDL

error_count := error_count + 1;
end if;
end procedure comprueba_estado_salida;

begin
-- Instanciar UUT
UUT: component seq0110 port map
( z_long, state, reset_n, clk, x );

-- Generar un pulso LOW en la entrada de reset


reset_n <= ’1’,
’0’after ( PERIODO/4 ),
’1’after ( PERIODO + PERIODO/4 );

-- Generar la se~
nal de reloj,
-- asumiendo que ha sido inicializada a ’0’
clk <= not clk after ( PERIODO/2 );

-- Generar vectores de test y comprobar el resultado


main : process is
variable error_count : integer := 0; -- Núm. errores
begin
report "Comienza la simulación";
x <= ’0’; wait for PERIODO; -- Comprueba reset, empieza en S0
comprueba_estado_salida(S0,’0’,state,z_long,error_count);
x <= ’1’; wait for PERIODO; -- Sigue en S0
comprueba_estado_salida(S0,’0’,state,z_long,error_count);
x <= ’0’; wait for PERIODO; -- Va a S1
comprueba_estado_salida(S1,’0’,state,z_long,error_count);
x <= ’0’; wait for PERIODO; -- Sigue en S1
comprueba_estado_salida(S1,’0’,state,z_long,error_count);
x <= ’1’; wait for PERIODO; -- Va a S2
comprueba_estado_salida(S2,’0’,state,z_long,error_count);
x <= ’0’; wait for PERIODO; -- Va a S1
comprueba_estado_salida(S1,’0’,state,z_long,error_count);
x <= ’1’; wait for PERIODO; -- Va a S2
comprueba_estado_salida(S2,’0’,state,z_long,error_count);
x <= ’1’; wait for PERIODO; -- Va a S3
comprueba_estado_salida(S3,’0’,state,z_long,error_count);
x <= ’1’; wait for PERIODO; -- Va a S0
comprueba_estado_salida(S0,’0’,state,z_long,error_count);
x <= ’0’; wait for PERIODO; -- Va a S1
comprueba_estado_salida(S1,’0’,state,z_long,error_count);
x <= ’1’; wait for PERIODO; -- Va a S2
comprueba_estado_salida(S2,’0’,state,z_long,error_count);
Capı́tulo 4 Casos prácticos de diseño de circuitos secuenciales 129

x <= ’1’; wait for PERIODO; -- Va a S3


comprueba_estado_salida(S3,’0’,state,z_long,error_count);
x <= ’0’; wait for PERIODO/4; -- Va a S1
comprueba_estado_salida(S3,’0’,state,z_long,error_count);
-- Salida ’0’ en S3
wait for 3*(PERIODO/4);
comprueba_estado_salida(S1,’1’,state,z_long,error_count);
-- Salida ’1’ en S1
wait for PERIODO; -- Sigue en S1
comprueba_estado_salida(S1,’0’,state,z_long,error_count);
wait for PERIODO; -- Tests finalizados

if (error_count = 0) then
report "Simulación finalizada sin errores";
else
report "ERROR: Hay " &
integer’image(error_count) &
" errores.";
end if;

wait; -- Detiene este bloque process, pero no


-- finaliza la simulación debido a que
-- hay asignaciones concurrentes
end process main;
end architecture bp_seq0110;

El test se ejecuta durante 1500 ns, sin que se produzca ningún error. En la
Figura 4.13 se muestra la evolución de las señales durante los primeros 1400 ns.

Figura 4.13: Resultado de la simulación del programa de test.


130 A. Urquı́a, C. Martı́n Villalba Casos Prácticos de Diseño de Circuitos Digitales con VHDL

4.6 Descripción VHDL de alto nivel


Las herramientas de sı́ntesis actuales son capaces de generar circuitos eficientes
a partir de una descripción RTL (register-transfer level) del circuito. De hecho, a
menos que el diseñador esté muy familiarizado con la arquitectura hardware en la
que va a implementarse el circuito, generalmente se obtienen mejores circuitos si
se realiza una descripción VHDL de alto nivel del circuito y se emplea una buena
herramienta de sı́ntesis, en lugar de diseñar manualmente (al nivel de puertas
lógicas o transistores) el circuito.
Debido a esto, el método de diseño de hardware recomendado actualmente
es realizar una descripción VHDL de alto nivel del circuito y emplear una buena
herramienta de sı́ntesis para obtener la netlist para la arquitectura hardware de la
implementación. Cuando se describe el comportamiento del circuito a alto nivel,
la herramienta de sı́ntesis tiene mayor libertad para optimizar su estructura,
produciendo circuitos más eficientes.
Por ejemplo, si el diseñador realiza una descripción estructural basada en
puertas NAND, o emplean una secuencia de ecuaciones lógicas para describir
el circuito, entonces la herramienta de sı́ntesis sólo puede eliminar las puertas
redundantes y simplificar las funciones lógicas. En cambio, si el diseñador describe
el comportamiento esperado de ese mismo circuito, la herramienta de sı́ntesis
puede producir un diseño lógico completamente diferente que sea más eficiente
que el considerado originalmente por el diseñador.
Para ilustrar cómo puede realizarse una descripción VHDL de alto nivel a
partir de una descripción algorı́tmica, consideraremos nuevamente el diseño de
un circuito detector de patrones en una secuencia de bits.

4.6.1 Circuito detector de secuencia


Supongamos que deseamos diseñar un circuito para la detección de la siguiente
secuencia de entrada serie: 0111 1110 (esta secuencia de emplea frecuentemente
como marcadora de final de paquete). El siguiente algoritmo permite resolver este
problema:

Paso 1. prev_data <- 1111 1111; /* Almacena 8 bits anteriores */


Paso 2. while (true) do /* Se repite indefinidamente */
data_in <- siguiente dato de entrada;
prev_data <- prev_data << 1 /* Desplazamiento izqda */
prev_data[0] <- data_in; /* Se almacena data_in en LSB */
if (prev_data == 0111 1110) then
detectado <- 1; /* Secuencia detectada */
else
detectado <- 0; /* Secuencia no detectada */
end while

El código VHDL del circuito detector de secuencia puede escribirse direc-


tamente basándose en el algoritmo anterior. A continuación, se muestran dos
versiones de la descripción del circuito: una en la cual prev_data es una variable
Capı́tulo 4 Casos prácticos de diseño de circuitos secuenciales 131

y otra en la cual es una señal. Ambas descripciones de la arquitectura son


igualmente válidas.

-------------------------------------------
-- Circuito detector de secuencia 0111 1110
library IEEE;
use IEEE.std_logic_1164.all;
use IEEE.numeric_std.all;

entity detector_sec is
port ( detectado : out std_logic;
reset_n : in std_logic;
clk : in std_logic;
data_in : in std_logic );
end entity detector_sec;

architecture detector_sec1 of detector_sec is


begin
process (reset_n, clk) is
variable prev_data : unsigned (7 downto 0);
begin
if (reset_n = ’0’) then
prev_data := B"1111_1111";
elsif rising_edge(clk) then
prev_data := prev_data sll 1;
prev_data(0) := data_in;
if (prev_data = B"0111_1110") then
detectado <= ’1’;
else
detectado <= ’0’;
end if;
end if;
end process;
end architecture detector_sec1;
-------------------------------------------

La única diferencia entre la descripción en VHDL y la descripción algorı́tmica,


aparte del uso de la sintaxis de VHDL, es que en el código VHDL no se ha incluido
la sentencia
data_in <- siguiente dato de entrada;
En el código VHDL no es necesario realizar la asignación del siguiente bit de
la secuencia de entrada a data_in porque se supone que los bits de datos entran
en sincronı́a con el flanco de subida de la señal de reloj.
A continuación, se muestra otra forma de describir la architecture del cir-
cuito. En este caso, prev_data es una señal.
132 A. Urquı́a, C. Martı́n Villalba Casos Prácticos de Diseño de Circuitos Digitales con VHDL

-------------------------------------------
architecture detector_sec2 of detector_sec is
signal prev_data : unsigned (7 downto 0);
begin
process (reset_n, clk) is
begin
if (reset_n = ’0’) then
prev_data <= B"1111_1111";
elsif rising_edge(clk) then
prev_data <= (prev_data(6 downto 0) & data_in);
if ((prev_data(6 downto 0) & data_in) = B"0111_1110") then
detectado <= ’1’;
else
detectado <= ’0’;
end if;
end if;
end process;
end architecture detector_sec2;
-------------------------------------------

La sentencia
prev_data <= (prev_data(6 downto 0) & data_in);
realiza un desplazamiento lógico de un bit hacia la izquierda e inserta data_in en
el bit menos significativo.
Puesto que la asignación a señales no tiene efecto inmediatamente, sino un
delta de tiempo posterior al tiempo simulado actual, esta operación de des-
plazamiento se ejecuta concurrentemente con la sentencia if que comprueba la
igualdad con B"0111_1110". Puesto que el valor de prev_data todavı́a no ha sido
actualizado en el momento en que se realiza la comparación, es necesario realizar
la comparación usando el valor de prev_data anterior al desplazamiento.
VeriBest VB99.0
A

Objetivos. Instalar en su propio ordenador y realizar las operaciones básicas de


manejo del entorno de simulación de VHDL’93 VeriBest. Estas operaciones básicas
incluyen al menos:
– Edición y compilación de modelos.
– Simulación y visualización de los resultados.
– Depurado usando el debugger.

A.1 Instalación
La versión de evaluación VB99.0 presenta la limitación siguiente: el modelo no
puede superar las 2000 lı́neas o las 2000 referencias a componentes. Para instalar
Veribest VB99.0, pueden seguirse los pasos siguientes:

1. Ejecute el fichero setup.exe, que se encuentra dentro del directorio VHDL Si-
mulator.

2. Acepte los términos de la licencia.

3. Escoja el directorio en el cual desea que se instale el simulador.

4. Seleccione para su instalación “VeriBest VHDL Simulator”, que es la opción


señalada por defecto.

5. El programa de instalación copia todos los ficheros necesarios en el disco,


creando en el grupo de programas de Windows un nuevo grupo llamado
VeriBest VB99.0. Dentro de éste hay una carpeta, “VeriBest VHDL Simu-
lator”, en la que se encuentra el simulador VHDL (VeriBest VHDL), un
tutorial y la documentación en lı́nea.
134 A. Urquı́a, C. Martı́n Villalba Casos Prácticos de Diseño de Circuitos Digitales con VHDL

A.2 Circuito digital ejemplo: buffer triestado


Va a emplearse el modelo de un buffer triestado para ilustrar las explicaciones
acerca del manejo del simulador. Este tipo de componente se emplea comúnmente
para conectar varios dispositivos a un mismo bus. Tal como se muestra en la
Figura A.1, el buffer triestado tiene dos entradas (d y E) y una salida (y). La
salida puede tomar tres valores: 0, 1 y Z (alta impedancia). El estado de alta
impedancia es equivalente a un interruptor abierto. Dependiendo del valor de la
entrada E, la salida puede tomar el valor de la entrada o el valor Z.

E E Y
0 Z
d y
1 d
a) b)

Figura A.1: Buffer triestado: a) sı́mbolo lógico; b) tabla de verdad.

A.2.1 Modelo VHDL del buffer triestado

-------------------------------------------
-- Buffer triestado
library IEEE;
use IEEE.std_logic_1164.all;

entity Buffer_TriEstado is port


( E : in std_logic;
d : in std_logic;
y : out std_logic);
end entity Buffer_TriEstado ;

architecture Behavioral of Buffer_TriEstado is


begin
process (E, d)
begin
if (E = ’1’ ) then
y <= d ;
else
y <= ’Z’;
end if;
end process;
end architecture Behavioral;
-------------------------------------------
Apéndice A VeriBest VB99.0 135

A.2.2 Banco de pruebas


El siguiente banco de pruebas genera las 22 posibles combinaciones de entradas
al buffer.

--------------------------------------
-- Banco de pruebas
library IEEE;
use IEEE.std_logic_1164.all;
use IEEE.numeric_std.all;

entity bp_Buffer_TriEstado is
end entity bp_Buffer_TriEstado;

architecture bp_Buffer_TriEstado of bp_Buffer_TriEstado is


signal y : std_logic; -- Conectar salida UUT
signal d, E : std_logic; -- Conectar entradas UUT

component Buffer_TriEstado is port


( E, d : in std_logic;
y : out std_logic);
end component Buffer_TriEstado;

begin
-- Instanciar y conectar UUT
uut : component Buffer_TriEstado port map
( E => E, d => d, y => y);
gen_vec_test : process
begin
E <= ’0’;
d <= ’0’;
wait for 5 ns;
d <= ’1’;
wait for 5 ns;
E <= ’1’;
wait for 10 ns;
d <= ’0’;
wait;
end process gen_vec_test;
end architecture bp_Buffer_TriEstado;
--------------------------------------
136 A. Urquı́a, C. Martı́n Villalba Casos Prácticos de Diseño de Circuitos Digitales con VHDL

A.3 Edición y compilación de un modelo


En esta sección se describe cómo editar y compilar modelos con el simulador
VeriBest VHDL.

A.3.1 Arranque del simulador VeriBest VHDL


Seleccione el icono VeriBest VHDL del grupo de programas Inicio → Programas
→ Veribest VB99.0 → Veribest VHDL Simulator.

A.3.2 Creación de un espacio de trabajo


Para crear un espacio de trabajo, puede seguir una de las dos opciones siguientes:

1. Despliegue el menú “Workspace” y seleccione la opción “New... ”

2. Seleccione el comando “New...” del menú “File”. Se mostrará una ventana


en la que tiene que seleccionar la opción “VHDL Workspace”.

Tras seguir una de estas dos opciones, se mostrará una ventana (véase la
Figura A.2). Teclee en dicha ventana el nombre del espacio de trabajo, que en
este caso se ha llamado bufferTriestado.

Figura A.2: Espacio de trabajo.

Aparecerá en el lateral izquierdo de la ventana principal del simulador una


nueva ventana con el tı́tulo bufferTriestado.vpd. Inicialmente, la ventana sólo
muestra una carpeta vacı́a, denominada bufferTriestado source (véase la Figura
A.3).
En dicha ventana ubicaremos todos los ficheros necesarios para simular el
buffer triestado, que en este caso son dos: la descripción del circuito (bufferTries-
tado.vhd) y de su banco de pruebas (bp bufferTriestado.vhd). Al igual que el buffer
Apéndice A VeriBest VB99.0 137

Figura A.3: Entorno de simulación tras crear el espacio de trabajo.

se ha definido en un único fichero, podrı́a haberse definido en dos: un fichero con


el código de la interfaz y otro con el código de la arquitectura.

A.3.3 Edición de un fichero


Puede crearse un nuevo fichero utilizando el comando “New...” del menú “File”.
Obtendrá una ventana en blanco en la que puede teclear el código VHDL. Escriba
el código que se muestra en la sección A.2.1. Una vez haya concluido, guárdelo con
el nombre bufferTriestado.vhd mediante el comando “Save”, situado en el menú
“File”.

A.3.4 Añadir un fichero al espacio de trabajo


Incluya el fichero bufferTriestado.vhd en el espacio de trabajo bufferTriestado.vpd.
Hay dos formas equivalentes de hacerlo:

1. Haga clic con el puntero del ratón sobre el botón “+”, situado en la esquina
superior derecha de la ventana del espacio de trabajo bufferTriestado.vpd.

2. O bien, utilice el comando “Add Files into Workspace...” situado en el menú


“Workspace”.

Tras realizar este paso obtendrá una ventana para la selección de un fichero.
Seleccione el fichero bufferTriestado.vhd. La ventana principal del simulador tiene
que quedar tal y como se muestra en la Figura A.4.
138 A. Urquı́a, C. Martı́n Villalba Casos Prácticos de Diseño de Circuitos Digitales con VHDL

Figura A.4: Entorno de simulación tras incluir el fichero bufferTriestado.vhd


el espacio de trabajo.

A.3.5 Compilación de un fichero


Para establecer las opciones de compilación, seleccionamos la opción “Settings...”
del menú “Workspace”, o bien recurrimos al icono “Workspace Settings” que está
situado en la barra de herramientas. Con ello se mostrará una ventana, en la
cual seleccionamos la pestaña “Compile”. De este modo, accedemos al cuadro de
diálogo donde se muestran, entre otras, las siguientes opciones de compilación:

“Debug” Activando esta opción el archivo seleccionado será compilado


con la opción de depuración. Con esta opción activa antes de
una compilación, es posible utilizar todos los comandos del
menú Debug durante la fase de simulación. Si se desea que
todos los archivos del espacio de trabajo sean compilados con
esta opción, basta con seleccionar la carpeta del espacio de
trabajo en la ventana y activar la opción.
“Index Checks” Si esta opción se encuentra activa, el compilador comprueba la
existencia de errores en los ı́ndices de los arrays.
“Range Checks” Si esta opción se encuentra activa, el compilador comprueba la
existencia de errores en los rangos de los subtipos que se hayan
definido.
Apéndice A VeriBest VB99.0 139

Compile el fichero. Para ello seleccione el comando “Compile”, que está situado
en el menú “Workspace”.
El resultado de la compilación se muestra en la ventana de información,
situada en la parte inferior de la ventana principal. Observe que la ventana de
información contiene las tres pestañas siguientes:

“General” Proporciona información sobre cualquier acción que se realice


en la herramienta.
“Build” Muestra la información referente al proceso de compilación
de ficheros. En el caso de que haya habido errores en la
compilación muestra la lı́nea de código donde aparece cada
error y el tipo de error que es.
“Simulate” Proporciona información sobre la fase de simulación.

Cuando el proceso no da errores, lo guardamos (“Save”). La unidad compilada


se almacena en la librerı́a WORK. Para ver su ubicación, se selecciona el comando
“Library Browser” ubicado en el menú “Library”, o se pincha en el icono corres-
pondiente. Aparecen las diferentes librerı́as, IEEE, STD, VB, y en rojo WORK,
WORKLIB. Si pinchamos en ésta, aparecen la interfaz (entity) y arquitectura
(architecture) de los diferentes circuitos que hayamos compilado. Podemos ver
información de fecha y opciones de compilación en la parte derecha de la ventana
(ver Figura A.5). Observe que el chip asociado a la interfaz aparece en color
blanco y el asociado a la arquitectura en color rojo.
Se puede reinicializar la librerı́a en la que se está trabajando mediante el
comando “Reinitialize Lib environment” situado en el menú “Workspace”. Al
reinicializar la librerı́a, desaparecen las unidades compiladas.

Figura A.5: Library Browser.


140 A. Urquı́a, C. Martı́n Villalba Casos Prácticos de Diseño de Circuitos Digitales con VHDL

A.3.6 Banco de pruebas


1. Cree un nuevo fichero con el código que se muestra en la sección A.2.2. Una
vez haya concluido, guárdelo con el nombre bp bufferTriestado.vhd.

2. Incluya el fichero bp bufferTriestado.vhd en el espacio de trabajo buffer-


Triestado.vpd. La ventana principal del simulador tiene que quedar tal y
como se muestra en la Figura A.6. El orden de compilación de un fichero se
puede modificar mediante las flechas situadas en la esquina superior derecha
de la ventana del espacio de trabajo bufferTriestado.vpd.

Figura A.6: Entorno de simulación tras incluir el banco de pruebas en el


espacio de trabajo.

3. Compile el fichero bp bufferTriestado.vhd.

A.4 Simulación y visualización de los resultados


En esta sección se describen los pasos a seguir para realizar la simulación y la
visualización de resultados, usando el buffer triestado como ejemplo.

A.4.1 Establecer las condiciones de la simulación


Para fijar las condiciones de la simulación, siga los pasos siguientes:

1. Seleccione la opción “Settings...” del menú “Workspace” o haga clic sobre


el icono correspondiente, denominado “Workspace Settings”, de la barra de
Apéndice A VeriBest VB99.0 141

Figura A.7: Opciones de simulación.

herramientas. A continuación, se abrirá la ventana mostrada en la Figura


A.7.

2. Para acceder al cuadro de diálogo con las opciones de simulación, seleccione


la pestaña “Simulate” de la ventana.

3. Despliegue la carpeta “WORK” para visualizar los elementos sobre los que
se puede realizar una simulación. Obtendrá las interfaces (entity) y ar-
quitecturas (architecture) que ha programado en los pasos anteriores.
Para realizar la prueba de la puerta lógica debe seleccionar la arquitectura
BP BUFFER TRIESTADO (que es la que contiene la prueba) y la interfaz
que lleva asociada esa arquitectura (BP BUFFER TRIESTADO). Para
ello, seleccione la arquitectura BP BUFFER TRIESTADO de la interfaz
BP BUFFER TRIESTADO con el cursor del ratón (haga clic sobre ella)
y pulse el botón “Set”. Tras esta acción, los campos “Entity” y “Arch” se
rellenarán automáticamente con los nombres de la interfaz y de la arqui-
tectura. Por último, activamos la opción “Trace On” (que nos permite vi-
sualizar las formas de onda resultantes). Esto también se logra desplegando
Simulate→Trace.

4. Fijadas las condiciones de simulación, pulse el botón “Aceptar”.

A.4.2 Activación del simulador


Para realizar la simulación hay que arrancar el simulador. Esto se puede realizar
de dos formas: mediante la opción “Execute Simulator” del menú “Workspace”, o
mediante el icono correspondiente, denominado “Execute Simulator”, situado en
la barra de herramientas.
Mediante cualquiera de las dos opciones, el simulador se activa. Durante
el proceso de activación del simulador aparecerá una ventana de aviso (véase
142 A. Urquı́a, C. Martı́n Villalba Casos Prácticos de Diseño de Circuitos Digitales con VHDL

la Figura A.8) en la que se indica que, al no encontrar una licencia, se está


utilizando el simulador en modo limitado. Pulse el botón “Aceptar” para continuar
trabajando.

Figura A.8: Mensaje de aviso sobre la ausencia de licencia.

Tras la activación del simulador, en la ventana denominada “Simulate”, situa-


da en la parte inferior del espacio de trabajo, aparece un texto. En la última lı́nea
del texto se indica si ha habido errores o avisos (warnings).

A.4.3 Simulación y visualización de resultados


Una vez activada la simulación, ya puede empezar a realizar simulaciones. Para
realizar simulaciones puede elegir una de las siguientes opciones:

1. Presionar el botón de color verde, denominado “Run”, que está situado en


la barra de herramientas (véase la Figura A.9).

2. Seleccionar la opción “Run” o “Run Forever” del menú “Simulate”.

Los siguientes controles de la barra de herramientas del entorno (ver Figura


A.9) nos permiten controlar la simulación:

Run Tiempo de Unidades del Stop Quit


simulación tiempo de
simulación

Figura A.9: Botones para controlar la simulación.

– Lista desplegable. Permite seleccionar las unidades del tiempo de simula-


ción. Por defecto, la unidad de tiempo es nanosegundos (ns).
Apéndice A VeriBest VB99.0 143

– Casilla numérica (junto al botón “Run”). Permite indicar el tiempo de


simulación.

– Botón “Run”. Permite ejecutar una simulación.

– Botón “Stop”. Permite detener la simulación.

– Botón “Quit”. Permite salir del simulador.

Para visualizar los resultados de la simulación, podemos o bien pinchar con


el ratón sobre el icono “WaveForm Window”, que está situado en la barra de
herramientas, o bien ejecutar el comando “New WaveForm Window”, que se
encuentra en el menú “Tools...”
Obtendrá una ventana con una escala de tiempos, en la que no se visualiza
ninguna señal. Para seleccionar las señales, pulse el botón “Add signals” en la
ventana de visualización de señales. Dicho botón se encuentra indicado en la
Figura A.10.

Add signals

Figura A.10: Selección de las señales a visualizar.

Obtendrá una nueva ventana, mostrada también en la Figura A.10, en la que


puede seleccionar las señales que desea representar. Pueden seleccionarse señales
tanto de la arquitectura del banco de pruebas (E, d e y), como de la arquitectura
del buffer (E, d e y).
Para seleccionar las señales que corresponden a la arquitectura del banco de
pruebas, pulse sobre el botón “Add All”. Pulse “Close” para cerrar la ventana. Se
obtiene una ventana como la mostrada en la Figura A.11.
Para salir del simulador, podemos hacer clic con el ratón sobre el icono “Quit”,
que se encuentra indicado en la Figura A.9.
144 A. Urquı́a, C. Martı́n Villalba Casos Prácticos de Diseño de Circuitos Digitales con VHDL

Figura A.11: Resultados de la simulación.

A.5 Depurado usando el debugger


Para poder hacer uso del depurador se tienen que haber compilado los ficheros
con la opción “Debug” habilitada y se ha de activar el simulador.
Una vez activado el simulador, aparece el menú “Debug”. Hasta que no se
inicie la simulación no aparecerán habilitados todos los comandos del depurador.
Entre los comandos del depurador habilitados antes de iniciar la simulación, cabe
destacar los siguientes (véase la Figura A.12):

Insert/remove Examine Show


breakpoint breakpoints
Clear all
breakpoint New watch
window
Call stack

Figura A.12: Opciones de depuración antes del inicio de la simulación.

– “Insert/Remove a breakpoint”: nos permite introducir un punto de ruptura


(breakpoint) o eliminar un punto de ruptura que habı́amos introducido
previamente.
Apéndice A VeriBest VB99.0 145

– “Clear all breakpoints”: nos permite eliminar todos los puntos de ruptura
que estaban introducidos.

– “New watch window”: abre una ventana que nos permite observar la evolu-
ción de las señales de forma numérica. Esta ventana, mostrada en la Figura
A.13, dispone de hasta 4 paneles de observación independientes (“Watch1”
a “Watch4”).
Para añadir a uno de los cuatro paneles los elementos a observar, pulse el
botón “Add Watch...” y obtendrá una ventana cuyo tı́tulo es “Add watch”
(véase la Figura A.13), en la que puede seleccionar tanto las señales de
forma independiente (se selecciona la señal y se pulsa el botón “Watch”),
como todas las señales de un elemento (se selecciona el componente o bloque
en la parte izquierda de la ventana y se pulsa el botón “Watch block”).

Figura A.13: Ventanas para observar la evolución de las señales.

– “Show Breakpoints”: abre una ventana que tiene como tı́tulo “Breakpoints”,
en la que se muestran todos los puntos de ruptura existentes. En la ventana
“Breakpoints” existe un botón denominado “Condition...” Pulsando este
botón se abre una ventana, denominada “Source Breakpoint Condition”, en
la que puede establecer condiciones de activación para un punto de ruptura
determinado.
Desde la ventana “Source Breakpoint Condition” podrá indicar que el punto
de ruptura permanezca activo únicamente para una instancia o proceso
especı́fico. De esta forma, cuando se establecen condiciones, el simulador
se detiene únicamente en el punto de ruptura que hay dentro del proceso
especificado, no en todos los procesos en los que está el punto de ruptura.

– “Call stack”: nos permite conocer la próxima lı́nea de código VHDL que se
ejecutará cuando se continúe con la simulación. Si se realiza doble clic sobre
146 A. Urquı́a, C. Martı́n Villalba Casos Prácticos de Diseño de Circuitos Digitales con VHDL

una de las entradas que aparecen en la “Call Stack”, se obtendrá una nueva
ventana en la que se muestra el código fuente VHDL que se indica en la
entrada que ha seleccionado.
En el caso de que el diseño que está ejecutando contenga subprogramas
anidados, en el momento en que se entre a ejecutar un subprograma, la ven-
tana “Call Stack” se incrementará con una nueva entrada correspondiente a
la llamada al subprograma. Cuando concluya la ejecución del subprograma,
la correspondiente entrada en la ventana será eliminada.

Para empezar el proceso de depuración hay que comenzar la simulación. Una


vez comenzada la simulación, se habilitarán, entre otros, los siguientes comandos
de depuración (véase la Figura A.14):

– “Continue”: continúa la ejecución de la simulación hasta el siguiente punto


de ruptura o hasta que concluya el tiempo de simulación.

– “Step”: avanza la simulación una lı́nea del código fuente VHDL.

Step Continue

Figura A.14: Opciones de depuración una vez iniciada la simulación.


ModelSim PE Student Edition
B

Objetivos. Instalar en su propio ordenador y realizar las operaciones básicas de


manejo del entorno de simulación ModelSim PE Student Edition. Estas operaciones
básicas incluyen al menos:
– Edición y compilación de modelos.
– Simulación y visualización de los resultados.
– Depurado de modelos.

B.1 Instalación
El grupo Mentor Graphics, desarrollador de ModelSim, ofrece de manera gratuita
una versión de evaluación temporal (180 dı́as) del simulador. El simulador Model-
Sim es una herramienta muy completa y potente, de hecho varias herramientas
de sı́ntesis desarrolladas por fabricantes de circuitos FPGA ofrecen la posibilidad
de simular los modelos usando ModelSim.
Los pasos a seguir para la descarga e instalación se describen a continuación.
Durante todo el proceso debe disponerse de conexión a Internet.

1. Descargar el fichero ejecutable de instalación (aproximadamente 60MB) de


la dirección:

http://www.model.com/resources/student edition/download.asp

para lo cual en primer lugar tendrá que rellenar un formulario electrónico


con sus datos y señalar una casilla que indica que sólo va a usar la herra-
mienta para fines educativos.

2. Ejecutar dicho fichero, el cual realiza la instalación del simulador. En la fase


final de la instalación, el programa de instalación se conecta a una página
web en la cual hay un formulario para la solicitud de la licencia.
148 A. Urquı́a, C. Martı́n Villalba Casos Prácticos de Diseño de Circuitos Digitales con VHDL

3. En la hoja de solicitud de licencia, debemos indicar a qué dirección de


correo electrónico deseamos que nos envı́en el fichero de licencia. En esa
dirección de correo recibiremos un correo con el fichero de licencia y las
indicaciones de dónde debe guardarse. La licencia tiene una validez de 180
dı́as, transcurridos los cuales debe repetirse la instalación y la solicitud de
la licencia. La licencia sólo es válida para el ordenador en el que se hizo la
descarga del ejecutable. Si se quiere instalar ModelSim en otro ordenador,
debe repetirse el proceso de descarga del ejecutable y solicitud de la licencia.

B.2 Circuito digital ejemplo: buffer triestado


Va a emplearse el modelo de un buffer triestado para ilustrar las explicaciones
acerca del manejo del simulador. Este tipo de componente se emplea comúnmente
para conectar varios dispositivos a un mismo bus. Tal como se muestra en la
Figura B.1, el buffer triestado tiene dos entradas (d y E) y una salida (y). La
salida puede tomar tres valores: 0, 1 y Z (alta impedancia). El estado de alta
impedancia es equivalente a un interruptor abierto. Dependiendo del valor de la
entrada E, la salida puede tomar el valor de la entrada o el valor Z.

E
E Y
0 Z
d y
1 d
a) b)

Figura B.1: Buffer triestado: a) sı́mbolo lógico; b) tabla de verdad.

B.2.1 Modelo VHDL del buffer triestado

-------------------------------------------
-- Buffer triestado
library IEEE;
use IEEE.std_logic_1164.all;

entity Buffer_TriEstado is port


( E : in std_logic;
d : in std_logic;
y : out std_logic);
end entity Buffer_TriEstado ;

architecture Behavioral of Buffer_TriEstado is


begin
process (E, d)
Apéndice B ModelSim PE Student Edition 149

begin
if (E = ’1’ ) then
y <= d ;
else
y <= ’Z’;
end if;
end process;
end architecture Behavioral;
-------------------------------------------

B.2.2 Banco de pruebas


El siguiente banco de pruebas genera las 22 posibles combinaciones de entradas
al buffer.

--------------------------------------
-- Banco de pruebas
library IEEE;
use IEEE.std_logic_1164.all;
use IEEE.numeric_std.all;

entity bp_Buffer_TriEstado is
end entity bp_Buffer_TriEstado;

architecture bp_Buffer_TriEstado of bp_Buffer_TriEstado is


signal y : std_logic; -- Conectar salida UUT
signal d, E : std_logic; -- Conectar entradas UUT

component Buffer_TriEstado is port


( E, d : in std_logic;
y : out std_logic);
end component Buffer_TriEstado;

begin
-- Instanciar y conectar UUT
uut : component Buffer_TriEstado port map
( E => E, d => d, y => y);
gen_vec_test : process
begin
E <= ’0’;
d <= ’0’;
wait for 5 ns;
d <= ’1’;
wait for 5 ns;
150 A. Urquı́a, C. Martı́n Villalba Casos Prácticos de Diseño de Circuitos Digitales con VHDL

E <= ’1’;
wait for 10 ns;
d <= ’0’;
wait;
end process gen_vec_test;
end architecture bp_Buffer_TriEstado;
--------------------------------------

B.3 Edición y compilación de un modelo


En esta sección se describe cómo editar y compilar modelos con el simulador
ModelSim. Para ilustrar las explicaciones, se va a usar el modelo del buffer
triestado descrito anteriormente.

B.3.1 Arranque del simulador


Seleccione el icono ModelSim PE del grupo de programas Inicio → Programas
→ ModelSim PE Student Edition 6.3c → ModelSim. Inicialmente aparecerá la
ventana de bienvenida. Si desea que no vuelva a aparecer marque la casilla “Don’t
show this dialog again”. Para cerrar esta ventana y acceder a la aplicación pulse
el botón “Close”.

Menús
Iconos

Workspace

Transcript

Figura B.2: Ventana principal de ModelSim.

Se abrirá entonces la ventana principal del entorno (véase la Figura B.2), que
cuenta con los elementos siguientes:
Apéndice B ModelSim PE Student Edition 151

“Workspace” Panel situado a la izquierda de la ventana principal. Al


arrancar la aplicación este panel tiene una única pestaña
denominada “Library”. En esta pestaña aparecen los nombres
lógicos de las librerı́as de recursos.
“Transcript” Panel de texto situado en la parte inferior de la ventana
principal. Este panel tiene una doble finalidad:
1. Mostrar los mensajes producidos por la ejecución de
comandos.
2. Permitir teclear comandos en lı́nea. Se mantiene un
histórico de todos los comandos ejecutados. Usando las
teclas ↑ y ↓ se puede acceder a comandos anteriores y
posteriores para ejecutarlos de nuevo.

Barra de menús
Barra de iconos

B.3.2 Creación de un proyecto


Para crear un proyecto, debe seguir los pasos siguientes:

1. Seleccione la opción File → New → Project. Aparecerá la ventana de diálogo


para la creación de proyectos (véase la Figura B.3). En dicha ventana se
establece el nombre del proyecto, el directorio en el que desea ubicarse y el
nombre de la librerı́a por defecto.

Figura B.3: Ventana de diálogo para la creación de un proyecto.

2. En la casilla “Project Name” teclee bufferTriestado como nombre del pro-


yecto.

3. En la casilla “Project Location”, seleccione el directorio dónde va a ubicar


los ficheros del proyecto. Puede ayudarse del botón “Browse...” para mo-
verse por el disco. Si el directorio introducido no existe, la herramienta le
pedirá confirmación para su creación. En este directorio se creará el fichero
bufferTriestado.mpf.
152 A. Urquı́a, C. Martı́n Villalba Casos Prácticos de Diseño de Circuitos Digitales con VHDL

Figura B.4: Entorno de simulación tras crear un nuevo proyecto.

4. En la casilla “Default Library Name”, se escribe el nombre de la librerı́a


de trabajo. Por defecto aparece work y, en general, puede emplearse este
nombre. El nombre dado a la librerı́a será el que, una vez creado el proyecto,
la herramienta asigne automáticamente a un directorio ubicado debajo del
indicado en el cuadro “Project Location”. En este directorio se almacenarán
las unidades de diseño VHDL compiladas. En la Figura B.3 se muestra el
cuadro de diálogo una vez realizados estos pasos.

5. Pulse el botón “OK”.

B.3.3 Añadir ficheros al proyecto


Al crear un proyecto, se producen los siguientes cambios en el entorno de simu-
lación (véase la Figura B.4):

– Aparece una nueva pestaña en el panel “Workspace” denominada “Project”.


En dicha pestaña se muestran los ficheros que forman parte del proyecto.
Observe que si la pestaña “Project” está seleccionada se muestra un menú
llamado “Project”. Por el contrario, si la pestaña “Library” está seleccionada
no se muestra el menú “Project” sino un menú denominado “Library”.

– Se muestra el nombre del proyecto en la barra de estado de la parte inferior


izquierda de la ventana principal.

– Se abre una ventana de diálogo denominada “Add items to the Project”. Es-
ta ventana, que permite añadir elementos al proyecto, incluye las siguientes
opciones (véase la Figura B.4):
Apéndice B ModelSim PE Student Edition 153

“Create New File” Permite crear un nuevo fichero de diseño.


“Add Existing File” Permite incluir un fichero ya existente en el proyecto
actual copiándolo al directorio del proyecto o referen-
ciándolo desde su ubicación actual.
“Create Simulation” Permite crear configuraciones para simulación.
“Create New Folder” Permite crear directorios virtuales. Estos directorios tie-
nen, sobre la pestaña “Project” del panel “Workspace”,
un aspecto similar al de los directorios del sistema
operativo. Estos directorios son internos al proyecto y
no se crean realmente en el disco.

Para crear un nuevo fichero se pueden usar las opciones de la ventana de


diálogo “Add items to the Project”. Se pueden acceder a estas mismas opciones
a través del menú Project → Add to Project.

Inserción de un fichero nuevo en el proyecto


Para crear un fichero nuevo se pueden seguir los siguientes pasos:

1. Realizar una de las dos siguientes opciones:

– Seleccionar el icono “Create New File” en el cuadro de diálogo “Add


items to the Project” mostrado en la Figura B.4.
– O bien, seleccionar del menú el comando Project → Add to Project
→ New File... Para poder usar el menú, si está abierta la ventana de
diálogo “Add items to the Project”, hay que cerrarla presionando el
botón “Close”.

Aparece una ventana de diálogo denominada “Create Project File”. Esta


ventana tiene los siguientes elementos (ver Figura B.5):

“File Name” Permite especificar la ubicación y nombre del fichero


fuente. El botón “Browse...” nos permite especificar la
ubicación del fichero navegando a través de las carpetas
del sistema. Si especificamos un nombre del fichero,
sin indicar ningún directorio, éste se guardará en el
directorio del proyecto.
“Add File As Type” Nos permite seleccionar el tipo de fichero.
“Folder” Lista desplegable donde aparecen todos los directorios
existentes en el proyecto. En el caso de que no se
haya creado ningún directorio esta lista sólo tendrá un
elemento: “Top Level”.

2. Complete los cuadros de la ventana de diálogo “Create Project File” del


siguiente modo:

– En el cuadro “File Name” escriba bufferTriestado.vhd o bufferTriestado.


154 A. Urquı́a, C. Martı́n Villalba Casos Prácticos de Diseño de Circuitos Digitales con VHDL

– En la lista desplegable “Add file as type” seleccione VHDL.


– Pulse “OK”. Si ha añadido el fichero a través del cuadro de diálogo
“Add items to the Project” y no quiere añadir por el momento más
elementos al proyecto cierre dicha ventana. Ello lo puede hace pulsando
el botón “Close”.

Figura B.5: Ventana de diálogo “Create Project File”.

Una vez finalizado este proceso se crea un fichero denominado bufferTriesta-


do.vhd en el directorio del proyecto. En la Figura B.6 se muestra la ventana
principal tras seguir estos pasos. Observe que en la pestaña “Project” del
panel “Workspace” aparece la información sobre el fichero creado. La infor-
mación mostrada es la siguiente:

“Name” Nombre del fichero.


“Status” Sı́mbolo que refleja el estado del fichero. Existen los siguientes
tres sı́mbolos:
– ?: El fichero aún no ha sido compilado.
– X: El fichero se ha compilado y contiene errores.

– : El fichero ha sido compilado con éxito.

“Type” Indica el tipo de fichero (VHDL, Verilog, Folder, Simulation).


“Order” Indica la posición del fichero en la secuencia de compilación
cuando hay varios ficheros fuente. El primer fichero de la
secuencia de compilación es aquél con un número menor.
“Modified” Muestra la fecha y hora en que el fichero fue modificado por
última vez.

3. Al crear el fichero, se abre automáticamente una ventana del editor de texto


del entorno con el fichero vacı́o como muestra la Figura B.6.

4. Edite, empleando la ventana del editor de texto mostrada en la Figura B.6,


el código VHDL mostrado en la Sección B.2.1.

5. Salve el fichero seleccionando la opción File → Save del menú de la ventana


del editor o bien pulsando el icono correspondiente. De al fichero el nombre
bufferTriestado.vhd.
Apéndice B ModelSim PE Student Edition 155

Figura B.6: Entorno de simulación tras crear un nuevo fichero.

Figura B.7: Ventana de diálogo “Add File to Project”.

Inserción de un fichero existente en el proyecto


A continuación, se describen los pasos que habrı́a que seguir para incorporar al
proyecto un fichero ya existente:

– Seleccionar del menú el comando Project → Add to Project → Existing


File... También se puede realizar la misma acción desde la ventana de diálogo
“Add items to the Project” seleccionando la opción “Add Existing File”.
Aparece una ventana de diálogo denominada “Add File to Project” (véase
la Figura B.7). Esta ventana tiene los siguientes elementos:
156 A. Urquı́a, C. Martı́n Villalba Casos Prácticos de Diseño de Circuitos Digitales con VHDL

“File Name” Permite seleccionar el fichero fuente. El botón “Brow-


se...” nos facilita la selección de dicho fichero navegando
a través de las carpetas del sistema.
“Add File As Type” Nos permite seleccionar el tipo de fichero.
“Folder” Lista desplegable donde aparecen todos los directorios
existentes en el proyecto. En el caso de que no se
haya creado ningún directorio esta lista sólo tendrá un
elemento: “Top Level”.
“Copy to project direc- Realiza una copia fı́sica del fichero desde su localización
tory” al directorio del proyecto.
“Reference from current El fichero se incluye en el proyecto, pero no se copia al
location” directorio del mismo.

– Localice y seleccione el fichero en el cuadro “File Name” (puede ayudarse


del botón “Browse...”). Seleccione VHDL de la lista deplegable “Add file as
type” y “Top Level” de “Folder”. Por último, seleccione la opción “Copy to
project directory” y pulse “OK”.

B.3.4 Compilación de un fichero


Para verificar que el código VHDL es correcto, es necesario compilar el fichero.
Al compilar el fichero se genera el fichero binario que posteriormente se empleará
en la simulación. Para compilar el fichero podemos seguir una de las opciones
siguientes:

– Seleccionar la opción Compile → Compile All. Mediante esta opción se


compilan todos los ficheros del proyecto. El orden de compilación que se
sigue es el indicado en la columna “Order” del panel “Workspace”.

– Seleccionar la opción Compile → Compile Selected. Mediante esta opción


se compila únicamente el fichero seleccionado.

– Situar el ratón en el panel “Workspace” de la ventana principal y pulsar el


botón derecho. Aparece un menú contextual con varias opciones para lanzar
directamente la compilación. Mediante la opción Compile → Compile Out-
of-Date de este menú se compila únicamente los ficheros que no hayan sido
compilados con éxito anteriormente. Es decir, todos los que no presenten el

icono en la columna “Status”.

– Teclear vcom bufferTriestado.vhd en el panel “Transcript”.

La unidad compilada se almacena en la librerı́a work. Para ver su ubicación,


se selecciona la pestaña “Library” del panel ”Workspace”. Pulsando sobre el signo
“+” que aparece a la izquierda de la librerı́a work podemos ver su contenido
(véase la Figura B.8). En la librerı́a existe una interfaz (entity) denominada
bufferTriestado y una arquitectura (architecture) llamada behavioral.
Apéndice B ModelSim PE Student Edition 157

Figura B.8: Contenido de la librerı́a work tras compilar el fichero buffer-


Triestado.vhd.

Errores de compilación
A continuación, se describe qué ocurre cuando existen errores de compilación en
un fichero. Para ello vamos a modificar el fichero bufferTriestado.vhd. Introduci-
mos un error quitando el ; de la lı́nea 15 del fichero. Al guardar el fichero su nuevo
“status” es ?. Al compilar el fichero su “status” cambia a X (véase la Figura B.9).
También aparece un mensaje de error en color rojo en el panel “Transcript”.
El mensaje de error del panel “Transcript” nos informa de que existen errores
de compilación en el fichero bufferTriestado.vhd. Si hacemos doble clic con el ratón
sobre el mensaje de error se muestra una ventana de diálogo (véase la Figura B.9).
Dicha ventana contiene en color rojo un mensaje con información sobre el tipo de
error que se ha producido y el número de lı́nea en que aparece. Si hacemos doble
clic con el ratón sobre dicho mensaje se abre la ventana de edición con la lı́nea del
código que ha producido el error marcada en color naranja (véase la Figura B.9).
En este caso, la lı́nea 16 aparece en color naranja debido a que hemos eliminado
el ; que debiera haber al final de la lı́nea 15.

B.3.5 Banco de pruebas


Se va a crear un nuevo fichero con el código del banco de pruebas, que se va a
guardar con el nombre bp bufferTriestado.vhd. El código del banco de pruebas se
muestra en la Sección B.2.2. Para crear el fichero, siga los siguientes pasos:

– Seleccione del menú el comando Project → Add to Project → New File · · ·

– Complete la ventana de diálogo denominada “Create Project File” del si-


guiente modo:
158 A. Urquı́a, C. Martı́n Villalba Casos Prácticos de Diseño de Circuitos Digitales con VHDL

Figura B.9: Entorno de simulación cuando hay errores de compilación en el


fichero bufferTriestado.vhd.

– En el cuadro “File Name” escriba bp bufferTriestado.


– En la lista desplegable “Add file as type” seleccione VHDL.
– Pulse “OK”.

Tras seguir estos pasos, el panel “Workspace” queda tal como se muestra
en la Figura B.10. La columna “Status” del fichero bp bufferTriestado.vhd
tiene el icono ?, ya que aún no ha sido compilado. El fichero tiene el
número 1 en la columna “Order”. Esto indica que si usamos la opción de
compilación Compile → Compile All, el fichero bp bufferTriestado.vhd se
compilará después que el fichero bufferTriestado.vhd. Compile el fichero
bp bufferTriestado.vhd siguiendo algunas de las opciones descritas en la
sección B.3.4.
Existen ocasiones en que el orden de compilación de los ficheros puede
no ser el correcto en función de la estructura del código VHDL y de las
reglas que el lenguaje impone. Por ejemplo, considere el caso de que haya
un fichero llamado paquete.vhd donde se defina un paquete, y otro fichero,
denominado uso paquete.vhd, que use dicho paquete. El fichero paquete.vhd
ha de ser compilado antes que el fichero uso paquete.vhd. En caso contrario,
se produce un error de compilación.
Se puede modificar el orden de compilación del siguiente modo:

– Situar el ratón en el área del panel “Workspace”.


– Apretar el botón derecho del ratón. Aparece ası́ un menú textual.
– Seleccionar la opción Compile → Compile Order... del menú. Aparece
una ventana denominada “Compile Order” (ver Figura B.11).
– Puede cambiar el orden de posición del fichero en la secuencia de
compilación seleccionando dicho fichero en la ventana “Compile Order”
y pulsando sobre los botones (ver Figura B.11).
Figura B.10: Panel “Workspace” tras insertar el fichero
bp bufferTriestado.vhd.

Botones para cambiar el


orden en la secuencia de
compilación

Figura B.11: Ventana “Compile Order”.


160 A. Urquı́a, C. Martı́n Villalba Casos Prácticos de Diseño de Circuitos Digitales con VHDL

B.4 Simulación y visualización de los resultados


En esta sección se describen los pasos a seguir para realizar la simulación y la
visualización de los resultados, usando el buffer triestado como ejemplo.

B.4.1 Activación del modo simulación


Para iniciar el simulador se selecciona en la pestaña “Library” la interfaz (entity)
que queremos simular. En este caso, seleccionamos bp bufferTriestado. Con el
botón derecho de ratón sobre esta interfaz seleccionamos la opción “Simulate”
(véase la Figura B.12).
Observe que la ventana principal del simulador se modifica. Cabe destacar los
cambios siguientes:

– Aparecen las tres pestañas siguientes en el panel “Workspace”:

“sim” Muestra la jerarquı́a de diseño.


“Files” Muestra los ficheros fuente.
“Memories” Herramienta de análisis para los arrays de registros del
sistema (si hay alguno).

– Aparece el panel “Objects”. Este panel muestra las variables, registros, etc.,
su valor y sus caracterı́sticas.

Para interaccionar con el simulador y visualizar los resultados de la simulación,


la herramienta dispone de un conjunto de paneles. Estos paneles pueden formar
parte de la ventana principal del simulador o pueden ser separados de dicha venta-
na haciendo clic con el ratón sobre el botón “undocked” (véase la Figura B.13a).
Puede volver a insertar el panel en la ventana principal presionando el botón
“docked” (véase la Figura B.13b). Podemos seleccionar los paneles a mostrar
usando el menú “View”. A continuación, se comenta brevemente la funcionalidad
de algunos paneles:

“Dataflow” Permite visualizar, de modo gráfico, la conectividad entre


los elementos (procesos, sentencias de asignación concurrente,
etc.) del modelo y rastrear eventos.
“List” Muestra, en modo texto, los valores de las señales y variables
en un formato tabular.
“Process” Muestra la lista de procesos junto con información sobre su
estado.
“Objects” Muestra la lista de señales de la interfaz (entity) seleccionada
en la pestaña “Sim”.
“Wave” Permite visualizar la forma de onda de las señales y variables.
Apéndice B ModelSim PE Student Edition 161

Figura B.12: Activación del modo simulación.

a) b)

Figura B.13: Botones: a) “undocked”; y b) “docked”.

B.4.2 Visualización de los resultados


Las señales se pueden visualizar en el panel “Wave”. Este panel se puede separar
de la ventana principal pulsando el botón “undocked” (véase la Figura B.13a).
Podemos añadir señales de interés al panel “Wave” siguiendo uno de los dos
siguientes procedimientos:

– Seleccionar todas las señales que queremos visualizar del panel “Objects”.
Arrastrar la selección con el ratón y llevarla hasta el panel “Wave”.

– Pulsar sobre el panel “Objects” con el botón derecho del ratón. En el menú
que aparece podemos realizar las dos siguiente acciones:

1. Incluir en el panel “Wave” todas las señales que aparecen en el panel


“Objects”. Para ello hacemos clic en la opción Add to Wave → Signals
in Region.
2. Mostrar una selección de las señales del panel. Para ello hacemos clic
en la opción Add to Wave → Selected Signals. Para seleccionar un
162 A. Urquı́a, C. Martı́n Villalba Casos Prácticos de Diseño de Circuitos Digitales con VHDL

conjunto de señales pulsamos el botón “Shift” del teclado al mismo


tiempo que hacemos clic con el ratón sobre las señales que queremos
seleccionar. Para quitar señales del conjunto seleccionado mantenemos
pulsado el botón “Control” mientras hacemos clic con el ratón sobre
las señales que queremos quitar.

Caben destacar las siguientes caracterı́sticas del panel “Wave” (véase la Figu-
ra B.14):

– Se puede adaptar la información visualizada en el panel “Wave” usando los


diferentes iconos de zoom. A continuación se describe la funcionalidad de
los iconos de zoom:

“Zoom In” Amplia la escala de tiempos.


“Zoom Out” Reduce la escala de tiempos.
“Zoom Full” Cambia el rango de la escala de tiempo de modo que vaya desde
el instante inicial hasta el instante actual de simulación.

– Podemos añadir cursores presionando el botón “Insert Cursor”. Al pie del


cursor se indica el instante de tiempo en que se encuentra situado. Además,
aparece el valor de cada señal en dicho instante de tiempo en el área que hay
junto a los nombres de las señales. Se puede eliminar un cursor presionando
el botón “Delete Cursor” una vez hayamos seleccionando dicho cursor.

B.4.3 Ejecución de la simulación


Los siguientes botones nos permiten controlar la simulación y realizar el depurado
del modelo (ver Figura B.15):

“Run” Ejecuta la simulación durante el tiempo indicado por defecto


en el cuadro de la ventana principal (la simulación puede
detenerse antes, si se han introducido puntos de ruptura, o
manualmente o por la ejecución de alguna sentencia del banco
de pruebas).
“Continue Run” Continúa la simulación en curso hasta agotar el tiempo de
simulación por defecto (la simulación puede detenerse antes
por los motivos indicados en el párrafo anterior).
“Run - All”: Ejecuta la simulación durante tiempo indefinido. Esta podrá
detenerse si se han incluido puntos de ruptura en el código o
si se interrumpe con el botón siguiente. En la zona de estado
de la ventana principal (parte inferior) se muestra el tiempo
de simulación.
Apéndice B ModelSim PE Student Edition 163

Zoom In Zoom Out Zoom Full Zoom In Insert Delete Find Find Next
On Active cursor cursor Previous Transition
Cursor Transition

Figura B.14: Panel “Wave”.

“Break” Detiene la simulación en curso.


“Restart” Reinicia la simulación. Carga de nuevo el modelo binario,
sitúa el tiempo de simulación en cero y, opcionalmente, puede
mantener el formato dado a algunas ventanas, los puntos de
ruptura, etc.
“Step” Ejecuta la simulación hasta la siguiente sentencia de código.
El valor de las variables en ese punto se puede visualizar en el
panel “Objects”.
“Step Over” Ejecuta funciones y procedimientos en un solo paso.

B.4.4 Inserción de puntos de ruptura


A continuación, se describen los pasos a seguir para insertar punto de ruptura
(breakpoint) en el código:

– Seleccionamos la unidad de diseño en cuyo código queremos introducir el


punto de ruptura. Las unidades de diseño se muestran en la pestaña “Sim”
del panel “Workspace”.
164 A. Urquı́a, C. Martı́n Villalba Casos Prácticos de Diseño de Circuitos Digitales con VHDL

Restart Run Length Run Continue Run All Step Step Over
Run

Figura B.15: Botones para la simulación y depurado del modelo.

– Hacemos doble clic sobre la unidad de diseño seleccionada. Aparece ası́ un


panel con el código de dicha unidad de diseño.

– En el código mostrado en el panel podemos insertar puntos de ruptura


usando el ratón. Las lı́neas en las que podemos introducir puntos de ruptura
son aquellas cuyo número de lı́nea está en color rojo. Para introducir el
punto de ruptura hacemos clic con el ratón en la columna BP de la lı́nea
donde queremos introducir el punto de ruptura.

Para modificar los puntos de ruptura podemos acceder a una ventana de diá-
logo denominada “Modify Breakpoints”. Para ello, seguimos los pasos siguientes:

– Hacemos clic con el botón derecho del ratón en el área del panel donde se
muestra el código de la unidad de diseño seleccionada.

– En el menú textual que aparece seleccionamos la opción “Breakpoints...”.

A continuación, se describen los pasos a dar para introducir un punto de rup-


tura en la lı́nea número 15 del fichero bufferTriestado.vhd (véase la Figura B.16):

– Hacemos doble clic sobre la unidad de diseño uut. Aparece ası́ un panel que
muestra el código del fichero bufferTriestado.vhd.

– Hacemos clic con el ratón a la izquierda del número de lı́nea 15. Aparecerá
un cı́rculo rojo indicando la existencia del punto de ruptura. Para poder
modificar el punto de ruptura podemos situarnos con el ratón sobre el cı́rculo
y hacer clic con el botón derecho. Se despliega un menú de texto que nos
permite deshabilitar el punto de ruptura (“Disable Breakpoint”) y quitar el
punto de ruptura (“Remove Breakpoint”).
Figura B.16: Inserción de puntos de ruptura.
Índice alfabético

after, 103 Descripción del hardware


Alta impedancia, 134, 148 mediante esquemático, 3
Arbol de buffers, 7 mediante lenguaje, 3
Architecture, 20, 21 modular y jerárquica, 24
comportamiento, 21, 55, 61 Detector de secuencias, 100, 130
estructura, 21, 62, 117 Diagrama de estados, 100
Register-Transfer Level, 130 downto, 53
Asignación concurrente, 22, 48, 59, 83
Atributos, 34 Ejecución concurrente, 6
Entidad de diseño, 20
Banco de pruebas, 16, 51, 55, 65, 75, 85, Entity, 20
91, 94, 106, 113, 124, 126 Estándar IEEE
Buffer triestado, 48, 134, 148 1067-1987 (VHDL’87), 4
Bus bidireccional, 80 1076-1993 (VHDL’93), 4
1076-2001 (VHDL-AMS), 4
CAD, 3 1076.6 (VHDL sintetizable), 20
Calendario de eventos, 8 1364-1995 (Verilog), 3
case, 57, 103 1666-2005 (SystemC), 4
Ciclo de diseño, 4
Circuito integrado Fallo
ASIC, 5 Abierto, 12
FPGA, 5 Acoplo, 13
PLD, 5 Corto, 13
Codificador Modelo, 13
4:2 con prioridad, 93 Patrón, 13
Configuración, 28 Flip-flop, 102
Constantes generic, 28, 78 JK, 105
Conversor for, 53
BCD a binario, 89 Función, 44, 70
lógica, 50
Decodificador, 48
168 A. Urquı́a, C. Martı́n Villalba Casos Prácticos de Diseño de Circuitos Digitales con VHDL

Glitch, 39 de 1 bit, 61
Retardo, 38, 103
HDL, 2 de Transporte, 39
ventajas, 3 Inercial, 39
if, 55, 102 scan flip-flops, 14
Inicialización, 103 Sumador
Latch, 102 completo de 1 bit, 72
Ley de Moore, 1 de 4 bits, 77
Librerı́as VHDL, 37 SystemC, 4
IEEE.math real, 37 Sı́ntesis, 4
IEEE.numeric std, 37 de lógica secuencial, 102
IEEE.std logic 1164, 37 Tabla de transición de estados, 100
Literales, 31 Test, 12
Memoria Calidad, 14
de lectura y escritura, 79 Cobertura de fallos, 13
de sólo lectura, 78 Funcional, 14
Modelo de fallos, 13 Manufactura, 14
Multiplexor, 48 Modelo de fallos, 13
4:1, 54 Programa, 12
Máquina de estado finito, 99 Programa de test, 3
de Mealy, 99, 119 Vector, 12
de Moore, 99, 109 Vector de test, 3
método de diseño, 99 Tipo de datos
bit, 30
Netlist, 4 enumerado, 32
now, 32, 67 integer, 59
std logic, 30
Operadores, 35 string, 32
package, 37, 74, 85, 90, 110 time, 32
Palabras reservadas, 21 Unidad Aritmético Lógica, 82
Parametrización, 28 UUT (Unit Under Test), 16
Procedimiento, 44, 68
procedure, 106 Verificación
process, 23, 50, 55, 84, 104 de tiempos, 4
Puerto, 20 funcional, 4
in, 20 Verilog HDL, 3
inout, 20 VHDL, 2
out, 20 VHDL sintetizable, 20

Reloj de la simulación, 8 wait, 38, 54, 103, 104


Rendimiento, 12 when, 48
report, 32, 67 with, 49, 103
Restador
completo de 1 bit, 61
Bibliografía

Armstrong, J. & Gray, F. (2000), VHDL Design, Representation and Synthesis,


Prentice Hall.

Brown, S. & Vranesic, Z. (2006), Fundamentos de Lógica Digital con Diseño


VHDL, Mc Graw-Hill.

Lee, S. (2006), Advanced Digital Logic Design: Using VDHL, State Machines and
Syntesis for FPGAs, Thomsom Canada Limited.

Mentor Graphics Corporation (2008), ModelSim LE/PE User’s Manual. Software


Version 6.3e. Disponible en: http://www.model.com/resources/resources\
_manuals.asp.

Pardo, F. & Boluda, J. A. (2004), VHDL, Lenguaje de Sı́ntesis y Modelado de


Circuitos, RA-MA.

Perry, D. L. (2002), VHDL: Programming by Example, McGraw-Hill.

Salcic, Z. & Smailagic, A. (2000), Digital Systems Design and Prototyping, Kluwer
Academic Publishers.

Vahid, F. & Lysecky, R. (2007), VHDL for Digital Design, Wiley.

VeriBest Inc. (1998), Documentación en lı́nea de VeriBest VB99.0. Suministrada


con VeriBest VB99.0.

Вам также может понравиться