SINTESIS Y DESCRIPCIÓN DE CIRCUITOS DIGITALES UTILIZANDO VHDL
ANTECEDENTES
En los últimos diez años la industria
electrónica ha tenido una gran evolución en el
desarrollo de sistemas digitales; desde
computadoras personales, sistemas de audio y
vídeo hasta dispositivos de alta velocidad para las
comunicaciones. Productos hechos con una alta
tecnología que permite aumentar la funcionalidad,
disminuir costos, mejorar el aprovechamiento de
la energía, así como una marcada tendencia hacia
la miniaturización. Esto ha sido posible gracias a
la implementación de herramientas de diseño
asistidos por computadora, conocidas como
herramientas CAD (Computer Aided Design),
aunque específicamente se hace uso de
herramientas EDA (Electronic Design
Automation), que es el nombre que se le da a
todas las herramientas CAD para el diseño de
sistemas electrónicos. Este software de diseño
electrónico que facilita a los ingenieros el
desarrollo de circuitos es cada vez mas sofisticado
y, además, contamos con computadoras cada vez
más veloces y de mayor capacidad de
procesamiento. Ambos, hardware y software,
constituyen actualmente herramientas muy
importantes que simplifican el trabajo de diseño
electrónico. Además de facilitar el trabajo, el uso
de herramientas EDA también aceleró los
procesos de diseño. Esta situación condujo a
adoptar nuevas metodologías para el diseño y
evaluación de los circuitos electrónicos. El uso de
las herramientas EDA junto con los dispositivos
lógicos programables, que pueden ser utilizados
en diferentes aplicaciones e inclusive
reprogramados, cambiaron bastante el concepto
de diseño de circuitos digitales.
VHDL es un lenguaje que se creó para el
diseño, modelado y documentación de circuitos
complejos. Actualmente se le utiliza para la
síntesis de circuitos digitales utilizando
dispositivos lógicos programables. Es así como
los dispositivos lógicos programables y VHDL,
Very High Speed Integrated Circuit (VHSIC)
Hardware Description Language, constituyen los
elementos fundamentales para estas nuevas
metodologías de diseño.
El presente trabajo considera los dispositivos
lógicos programables, enfocándonos en los PLDs,
CPLDs y FPGAs. Ya que el principal motivo por
el que debemos aprender a utilizar VHDL es el de
diseñar circuitos lógicos utilizando este tipo de
dispositivos. Se expondrán los estilos elementales
de codificación, exponiendo las principales
características de VHDL como lenguaje para
síntesis de circuitos. Finalmente se desarrolla la
implementación de filtros digitales utilizando
FPGAs.
i
IEC FRANCISCO JAVIER TORRES VALLE
SINTESIS Y DESCRIPCIÓN DE CIRCUITOS DIGITALES UTILIZANDO VHDL
ÍNDICE
ANTECEDENTES
1. LENGUAJES DE DESCRIPCIÓN DE HARDWARE 1
1.1. INTRODUCCIÓN. 2
1.2. EL CONCEPTO DE HERRAMIENTAS CAD-EDA. 2
1.3. LENGUAJES DE DESCRIPCIÓN DE HARDWARE. 4
1.3.1. VENTAJAS DE LOS HDLS 5
1.4. VHDL 5
1.5. METODOLOGÍA DE DISEÑO UTILIZANDO VHDL 6
2. DISPOSITIVOS LÓGICOS PROGRAMABLES 9
2.1. CONCEPTOS FUNDAMENTALES 10
2.2. DISPOSITIVOS LÓGICOS PROGRAMABLES 10
2.2.1. MATRIZ GENÉRICA PROGRAMABLE 10
2.3. COMPLEX PROGRAMMABLE LOGIC DEVICES 11
2.3.1. MATRIZ DE INTERCONEXIONES PROGRAMABLES 11
2.3.2. BLOQUES LÓGICOS 11
i
2.3.3. DISTRIBUCIÓN DE PRODUCTOS 12
2.3.4. MACROCELDAS 12
2.3.5. CELDA DE ENTRADA/SALIDA 13
2.4. FIELD PROGRAMMABLE LOGIC DEVICES 13
2.4.1. CELDAS LÓGICAS 14
3. SINTAXIS DEL LENGUAJE 17
3.1. INTRODUCCIÓN A LA DESCRIPCIÓN EN VHDL DE CIRCUITOS
18
DIGITALES
3.1.1. MULTIPLEXORES 18
3.1.2. COMPARADORES 19
3.1.3. EL ESTILO DE “PROGRAMACIÓN” EN VHDL 20
3.2. IDENTIFICADORES 21
3.3. OBJETOS DE DATOS 21
3.3.1. CONSTANTES 21
ii
IEC FRANCISCO JAVIER TORRES VALLE
SINTESIS Y DESCRIPCIÓN DE CIRCUITOS DIGITALES UTILIZANDO VHDL
3.3.2. VARIABLES 22
3.3.3. SEÑALES 22
3.3.4. ALIAS 22
3.4. TIPOS DE DATOS 22
3.4.1. TIPOS ESCALARES 22
3.4.2. TIPOS COMPUESTOS 25
3.4.3. SUBTIPOS 27
3.4.4. TIPOS PREDEFINIDOS EN VHDL 27
3.4.5. TIPOS NO SOPORTADOS EN VHDL PARA SÍNTESIS 27
3.5. OPERADORES 28
3.5.1. OPERADORES LÓGICOS 28
3.5.2. OPERADORES DE COMPARACIÓN 28
3.5.3. OPERADORES DE ADICIÓN 28
3.5.4. OPERADORES DE MULTIPLICACIÓN 29
3.5.5. OPERADORES MISCELÁNEOS 29
3.5.6. OPERADORES DE ASIGNACIÓN 29
3.5.7. OPERADORES DE ASOCIACIÓN 30
3.5.8. OPERADORES DE CORRIMIENTO 31
3.5.9. OPERACIONES CON VECTORES 31
3.6. ATRIBUTOS 32
3.7. ENTIDADES 32
3.7.1. GENÉRICOS 33
3.7.2. PUERTOS 33
3.7.3. MODOS 33
3.8. ARQUITECTURAS 34
3.9. DESCRIPCIONES DE FLUJO DE DATOS 34
3.9.1. INSTRUCCIONES CONCURRENTES 35
3.9.2. ESTRUCTURAS DE EJECUCIÓN CONCURRENTE 35
3.9.3. ALU 35
3.10. DESCRIPCIONES COMPORTAMENTALES 38
3.10.1. INSTRUCCIONES SECUENCIALES 38
3.10.2. PROCESOS 38
3.10.3. DIFERENCIAS ENTRE SEÑALES Y VARIABLES 39
3.10.4. ESTRUCTURAS DE EJECUCIÓN SECUENCIAL 40
3.11. DESCRIPCIONES ESTRUCTURALES 42
iii
IEC FRANCISCO JAVIER TORRES VALLE
SINTESIS Y DESCRIPCIÓN DE CIRCUITOS DIGITALES UTILIZANDO VHDL
3.11.1. COMPONENTES 42
3.11.2. INSTANCIACIÓN DE COMPONENTES 43
3.11.3. SENTENCIAS DE GENERACIÓN 44
3.12. SUBPROGRAMAS 47
3.12.1. PROCEDIMIENTOS 47
3.12.2. FUNCIONES 47
3.12.3. LLAMADO A SUBPROGRAMAS 48
3.12.4. SOBRECARGA DE OPERADORES 50
3.13. LIBRERÍAS 50
3.13.1. SÍNTESIS DE LIBRERÍAS EN WARP 50
3.13.2. PAQUETES 52
4. DESCRIPCIÓN DE CIRCUITOS DIGITALES 54
4.1. PROYECTOS EN WARP 5.0 55
4.2. SIMULACIÓN DE PROYECTOS 57
4.2.1. PROCESO DE SIMULACIÓN 57
4.3. COMPARADORES 60
4.4. MULTIPLEXORES 65
4.4.1. DESCRIPCIÓN DE FLUJO DE DATOS 65
4.4.2. DESCRIPCIÓN COMPORTAMENTAL 66
4.4.3. DESCRIPCIÓN ESTRUCTURAL 67
4.5. SUMADORES 68
4.5.1. SUMADOR TOTAL 68
4.5.2. SUMADOR DE CUATRO BITS 69
4.5.3. SYNTHESIS OFF 70
4.6. REGISTROS 71
4.7. CONTADORES 73
4.8. ALU DE CUATRO BITS 76
4.8.1. DESCRIPCIÓN ESTRUCTURAL 77
4.8.2. DESCRIPCIÓN COMPORTAMENTAL 78
4.9. MÁQUINAS DE ESTADO 79
5. IMPLEMENTACIÓN DE FILTROS DIGITALES EN FPGA'S 83
5.1. INTRODUCCIÓN 84
5.2. ANTECEDENTES 84
iv
IEC FRANCISCO JAVIER TORRES VALLE
SINTESIS Y DESCRIPCIÓN DE CIRCUITOS DIGITALES UTILIZANDO VHDL
5.3. MARCO TEÓRICO 84
5.3.1. FILTROS FIR 84
5.3.2. FILTROS IIR 85
5.3.3. METODOLOGÍA DE DISEÑO PARA FILTROS DIGITALES 86
5.4. IMPLEMENTACIÓN EN FPGA'S 86
5.5. DISEÑO DE UN FILTRO PASA-BAJAS 86
5.6. RESULTADOS 93
CONCLUSIONES 95
BIBLIOGRAFÍA 97
v
IEC FRANCISCO JAVIER TORRES VALLE
CAPÍTULO I: LENGUAJES DE DESCRIPCIÓN DE HARDWARE
LENGUAJES DE
I
IEC FRANCISCO JAVIER TORRES VALLE
DESCRIPCIÓN DE
HARDWARE
1
CAPÍTULO I: LENGUAJES DE DESCRIPCIÓN DE HARDWARE
1.1 INTRODUCCIÓN
A mediados de los años setenta se produce una
fuerte evolución en los procesos de fabricación de
los circuitos integrados, promoviendo el desarrollo
de circuitos digitales hasta la primera mitad de los
años ochenta. En aquellas épocas el esfuerzo de
diseño se concentraba en los niveles eléctricos para
establecer características e interconexiones entre
los componentes básicos al nivel de transistor. El
proceso de diseño era altamente manual y tan sólo
se empleaban herramientas como PSPICE para
simular esquemas eléctricos con modelos
previamente caracterizados a cada una de las
distintas tecnologías. A medida que pasaban los
años, los procesos tecnológicos se hacían más y
más complejos. Los problemas de integración iban
en aumento y los diseños eran cada vez más
difíciles de depurar y de dar mantenimiento.
Inicialmente los circuitos MSI (Medium Scale Integration) y LSI (Low Scale Integration) se
diseñaron mediante el desarrollo de prototipos
basados en módulos simples. Cada uno de estos
módulos estaba formado por compuertas ya
probadas, pero este método poco a poco iba
quedándose obsoleto conforme aumentaba la
complejidad y tamaño de los circuitos. A finales de
los años setenta se constata el enorme desfase que
existía entre tecnología y diseño.
La considerable dificultad que puede llegar a
tomar el fabricar un circuito de alta escala de
integración, involucra riesgos y costos de diseño
desmesurados e imposibles de asumir por las
empresas. Es entonces, cuando diversos grupos de
investigadores empiezan a crear y desarrollar los
llamados “lenguajes de descripción de hardware”,
lenguajes en los que no fuera necesario
caracterizar eléctricamente cada componente del
circuito al nivel de transistor para así enfocarse
solamente en el funcionamiento lógico del sistema.
Empresas tales como IBM con su IDL, el TI-HDL
de Texas Instruments, ZEUS de General Electric,
etc., así como los primeros prototipos empleados
en las universidades, empezaron a desarrollarse
buscando una solución a los problemas que
presentaba el diseño de sistemas complejos. Sin
embargo, estos lenguajes nunca alcanzaron el nivel
de difusión y consolidación necesarios por motivos
distintos. Unos, los industriales, por ser propiedad
de la empresa permanecieron encerrados en ellas y
no estuvieron disponibles para su estandarización y
mayor difusión, en tanto que los universitarios
perecieron por no disponer de soporte ni
mantenimiento adecuado.
1.2 EL CONCEPTO DE
HERRAMIENTAS CAD-EDA
CAD son las siglas de Computer Aided Design,
o diseño asistido por computadora el cual
constituye todo un proceso de trabajo utilizando
técnicas de análisis apoyadas en gráficos mediante
sofisticadas herramientas de software las cuales
facilitan el estudio de los problemas asociados con
el diseño en cuestión. El concepto CAD se
relaciona con el dibujo como parte importante en
el proceso de diseño pero, además, el diseño de un
circuito debe cumplir con los requerimientos
especificados por el equipo de diseño, por las
normas de calidad existentes, los costos, etc. por lo
que las herramientas CAD intervienen en todas las
fases del diseño. Ya que no sólo son importantes
por acelerar el desarrollo del sistema al permitir
que varias personas puedan trabajar
simultáneamente en distintas etapas del diseño
sino que, además, es posible verificar el
funcionamiento del circuito mediante la
simulación del sistema. Todo esto simplifica la
tarea del equipo de diseño y conduce a la
conclusión del prototipo en menos tiempo. EDA,
Electronic Design Automation, es el nombre que
se le da a todas las herramientas de hardware y
software en el diseño de sistemas electrónicos.
Porque no sólo el software es importante, también
lo es el hecho de que las computadoras cada día
son más veloces y de mayor capacidad de
procesamiento, lo cual influye en el proceso de
diseño de circuitos electrónicos.
El diseño de hardware tiene un problema
fundamental, que no existe en desarrollo de
software. Este problema es el alto costo del ciclo
diseño
reinicio del ciclo, ya que el costo del prototipo
generalmente suele ser bastante elevado. Se
impone la necesidad de reducir este ciclo de diseño
para no incluir la fase de desarrollo del prototipo
más que al final del proceso, evitando la repetición
de varios prototipos que es lo que encarece el
ciclo. Para ello se introduce la fase de simulación y
verificación de circuitos utilizando herramientas
EDA, de tal forma que no sea necesario
implementar físicamente un prototipo para
comprobar el funcionamiento del circuito.
desarrollo del prototipo pruebas
IEC FRANCISCO JAVIER TORRES VALLE
2
CAPÍTULO I: LENGUAJES DE DESCRIPCIÓN DE HARDWARE
i
i
i
En el ciclo de diseño de circuitos, las
herramientas EDA están presentes en todas las
fases. Primero en la fase de generación del sistema
que puede representarse mediante un diagrama
esquemático, a bloques o de flujo.
Se encuentran también en la fase de simulación
y comprobación de circuitos, donde diferentes
herramientas permiten verificar el funcionamiento
del sistema. Estas simulaciones pueden ser de
eventos, funcionales, digitales o eléctricas, de
acuerdo al nivel de simulación requerido. Después
están las herramientas EDA utilizadas en la
síntesis y programación de circuitos digitales en
dispositivos lógicos programables. Existen,
además, las herramientas EDA orientadas a la
fabricación de circuitos. En el caso del diseño de
hardware estas herramientas sirven para la
realización de PCBs (Printed Circuit Boards o
placas de circuito impreso), o para desarrollar
circuitos integrados de aplicación especifica
conocidos como ASICs (Application Specific
Integrated Circuits). Este ciclo de diseño de
hardware se muestra en la figura 1.1.
IDEA
DESCRIPCIÓN
DEL CIRCUITO
SÍNTESIS
A continuación se mencionan las principales
características y finalidad de algunas herramientas
EDA que intervienen en el diseño de circuitos.
I. Lenguajes de descripción de circuitos.
Son lenguajes mediante los cuales es posible
describir el funcionamiento y estructura de un
circuito eléctrico o digital. La descripción puede
ser mediante bloques donde se muestra la
arquitectura del diseño, o de comportamiento, es
decir, se describe el funcionamiento del circuito en
vez de especificar los elementos de los que está
compuesto.
II. Diagramas esquemáticos.
Es la forma clásica de describir un diseño
electrónico y la más extendida ya que era la única
usada antes de la aparición de las herramientas de
EDA. La descripción está basada en un “plano”
donde se muestran los diferentes componentes
utilizados en el circuito.
III. Grafos y diagramas de flujo.
Es posible describir un circuito o sistema
mediante diagramas de flujo, redes de Petri,
máquinas de estados, etc. En este caso sería una
descripción gráfica y además sería
comportamental, porque no es una descripción
mediante componentes.
no
no
¿FUNCIONA?
s
SIMULACIÓN
FUNCIONAL
¿FUNCIONA?
s
PRUEBAS AL DISEÑO
FINALIZA EL
PROCESO DE
DISEÑO
ANÁLISIS
TEMPORAL
¿FUNCIONA?
s
PROGRAMACIÓN
DEL
DISPOSITIVO
ELABORACIÓN
DEL PROTOTIPO
Figura 1.1 Flujo de diseño en el desarrollo de
sistemas electrónicos
IEC FRANCISCO JAVIER TORRES VALLE
IV. Simulación de eventos.
Estas herramientas se usan para la simulación de
circuitos a grandes rasgos. En esta simulación, los
componentes más importantes son elementos de
no
alto nivel como discos duros, buses de
comunicaciones, memorias RAM etc.
V. Simulación funcional.
Bajando al nivel de compuertas digitales se
puede realizar una simulación funcional de las
mismas. Este tipo de simulación comprueba la
operación de circuitos digitales a partir del
comportamiento lógico de sus elementos con el fin
de comprobar el funcionamiento en conjunto del
circuito mediante unos estímulos dados. Similar a
lo que se realiza en un laboratorio.
VI. Simulación digital.
Esta simulación, también exclusiva de los
circuitos digitales, es como la anterior con la
diferencia de que se tienen en cuenta los retardos
3
CAPÍTULO I: LENGUAJES DE DESCRIPCIÓN DE HARDWARE
de propagación de cada compuerta. Es una
simulación muy cercana al comportamiento real
del circuito y prácticamente garantiza el
funcionamiento correcto del circuito en cuestión.
En las herramientas EDA este tipo de simulación
se conoce como análisis temporal o timing.
VII. Simulación eléctrica.
Es la simulación de más bajo nivel donde las
respuestas del sistema se verifican al nivel de
transistor. Sirven tanto para circuitos analógicos
como digitales y su respuesta es prácticamente
idéntica a la realidad ya que se prueban retardos de
tiempo, niveles de voltaje, disipación de potencia,
etc.
VIII. Diseño de PCBs
Con estas herramientas es posible realizar el
trazado de pistas para la fabricación de placas de
circuitos impresos.
IX. Diseño de circuitos integrados
Son herramientas EDA que sirven para la
realización de circuitos integrados. Las
capacidades gráficas de estas herramientas
permiten la realización de las diferentes máscaras
que intervienen en la realización de éstos.
X. Diseño con dispositivos programables.
Estas herramientas facilitan la programación de
dispositivos, ya sean PALs, PLDs, CPLDs o
FPGAs.
1.3 LENGUAJES DE
DESCRIPCIÓN DE
HARDWARE
Los lenguajes de descripción de hardware
(HDLs) son utilizados para describir la
arquitectura y comportamiento de un sistema
electrónico los cuales fueron desarrollados para
trabajar con diseños complejos.
Comparando un HDL con los lenguajes para el
desarrollo de software vemos que en un lenguaje
de este tipo un programa que se encuentra en un
lenguaje de alto nivel (VHDL) necesita ser
ensamblado a código máquina (compuertas y
conexiones) para poder ser interpretado por el
procesador. De igual manera, el objetivo de un
HDL es describir un circuito mediante un conjunto
de instrucciones de alto nivel de abstracción para
que el programa de síntesis genere (ensamble) un
circuito que pueda ser implementado físicamente.
La forma más común de describir un circuito es
mediante la utilización de esquemas que son una
representación gráfica de lo que se pretende
realizar. Con la aparición de herramientas EDA
cada vez más complejas, que integran en el mismo
marco de trabajo las herramientas de descripción,
síntesis, simulación y realización; apareció la
necesidad de disponer de un método de
descripción de circuitos que permitiera el
intercambio de información entre las diferentes
herramientas que componen el ciclo de diseño. En
principio se utilizó un lenguaje de descripción que
permitía, mediante sentencias simples, describir
completamente un circuito. A estos lenguajes se
les llamó Netlist puesto que eran simplemente eso,
un conjunto de instrucciones que indicaban las
interconexiones entre los componentes de un
diseño. A partir de estos lenguajes simples, que ya
eran auténticos lenguajes de descripción hardware,
se descubrió el interés que podría tener el describir
circuitos utilizando un lenguaje en vez de usar
esquemas. Sin embargo, se siguieron utilizando
esquemas puesto que desde el punto de vista del
ser humano son mucho más sencillos de entender,
aunque un lenguaje siempre permite una edición
más rápida y sencilla.
Conforme las herramientas de diseño se
volvieron más sofisticadas, y la posibilidad de
desarrollar circuitos digitales mediante dispositivos
programables era más viable, apareció la necesidad
de poder describir los circuitos mediante un
lenguaje de alto nivel de abstracción. No desde un
punto de vista estructural, sino desde el punto de
vista funcional. Este nivel de abstracción se había
alcanzado ya con las herramientas de simulación,
ya que para poder simular partes de un sistema era
necesario disponer de modelos que describieran el
funcionamiento de bloques del circuito o de cada
componente si fuera necesario. Estos lenguajes
estaban sobre todo orientados a la simulación, por
lo que poco importaba que el nivel de abstracción
fuera tan alto que no fuera sencillo una realización
o síntesis a partir de dicho modelo. Con la
aparición de técnicas para la síntesis de circuitos a
partir de lenguajes de alto nivel de abstracción, se
comenzaron a utilizar los lenguajes de simulación
para sintetizar circuitos. Que si bien alcanzan un
altísimo nivel de abstracción, su orientación era
básicamente la de simular, por lo que los
resultados de una síntesis a partir de descripciones
IEC FRANCISCO JAVIER TORRES VALLE
4
CAPÍTULO I: LENGUAJES DE DESCRIPCIÓN DE HARDWARE
con estos lenguajes no eran siempre las más
optimas.
Además, los lenguajes de descripción de
hardware al formar parte de las herramientas EDA
permiten el trabajo en equipo. Así, al estructurar el
desarrollo del proyecto, cada integrante del equipo
de diseño puede trabajar en subproyectos antes de
integrar todas las partes del sistema.
1.3.1 VENTAJAS DE LOS HDLS
Una metodología de diseño que utiliza un HDL
posee varias ventajas sobre la metodología
tradicional de diseño a nivel compuerta. Algunas
de estas ventajas son listadas a continuación.
• Es posible verificar el funcionamiento del
sistema dentro del proceso de diseño sin
necesidad de implementar el circuito.
• Las simulaciones del diseño, antes de que éste
sea implementado mediante compuertas,
permiten probar la arquitectura del sistema
para tomar decisiones en cuanto a cambios en
el diseño.
• Las herramientas de síntesis tienen la
capacidad de convertir una descripción hecha
en un HDL, VHDL por ejemplo, a
compuertas lógicas y, además, optimizar dicha
descripción de acuerdo a la tecnología
utilizada.
• Esta metodología elimina el antiguo método
tedioso de diseño mediante compuertas,
reduce el tiempo de diseño y la cantidad de
errores producidos por el armado del circuito.
• Las herramientas de síntesis pueden
transformar automáticamente un circuito
obtenido mediante la síntesis de un código en
algún HDL, a un circuito pequeño y rápido.
Además, es posible aplicar ciertas
características al circuito dentro de la
descripción para afinar detalles (retardos,
simplificación de compuertas, etc.) en la
arquitectura del circuito y que estas
características se obtengan en la síntesis de la
descripción.
• Las descripciones en un HDL proporcionan
documentación de la funcionalidad de un
diseño independientemente de la tecnología
utilizada.
• Un circuito hecho mediante una descripción
en un HDL puede ser utilizado en cualquier
tipo de dispositivo programable capaz de
soportar la densidad del diseño. Es decir, no es
necesario adecuar el circuito a cada
dispositivo porque las herramientas de síntesis
se encargan de ello.
• Una descripción realizada en un HDL es más
fácil de leer y comprender que los netlist o
circuitos esquemáticos.
1.4 VHDL
VHDL es un lenguaje de descripción de
hardware utilizado para describir circuitos en un
alto nivel de abstracción el cual está siendo
rápidamente aceptado como un medio estándar de
diseño. VHDL es producto del programa Very High Speed Integrated Circuit (VHSIC)
desarrollado por el Departamento de Defensa de
los Estados Unidos a finales de la década de los
70's. El propósito era hacer un estándar para
diseñar, modelar, y documentar circuitos
complejos de tal manera que un diseño
desarrollado por una empresa pudiera ser
entendido por otra y, además, pudiera ser
procesado por software con propósitos de
simulación.
VHDL es reconocido como un estándar de los
lenguajes HDL por el Instituto de Ingenieros en
Electricidad y Electrónica – IEEE – como su
estándar 1076 el cual fue ratificado en 1987, y por
parte del Departamento de Defensa de los Estados
Unidos como el estándar MIL-STD-454L En 1993
el estándar IEEE-1076 se actualizó y un estándar
adicional, el IEEE-1164, fue adoptado. Para 1996
el estándar IEEE-1076.3 se convirtió en un
estándar de VHDL para síntesis siendo éste el que
se utiliza en el diseño de sistemas digitales. Los
estándares más utilizados en síntesis de circuitos
por la mayoría de las herramientas de diseño son el
IEEE-1164 y el IEEE-1076.3. En la actualidad
VHDL es un estándar de la industria para la
descripción, modelado y síntesis de circuitos
digitales. Por esto, los ingenieros de la mayoría de
las áreas de electrónica, si no es que todas, deben
aprender a programar en VHDL para incrementar
su eficiencia.
VHDL divide los circuitos en dos “vistas”
entidades y arquitecturas. La entidad modela al
circuito, componente o sistema externamente
IEC FRANCISCO JAVIER TORRES VALLE
5
CAPÍTULO I: LENGUAJES DE DESCRIPCIÓN DE HARDWARE
definiendo a este mediante un nombre y sus
conexiones que vienen siendo las entradas y
salidas del circuito. En tanto que la arquitectura,
que es la vista interna, define el funcionamiento
del circuito. Después de definir las interfaces de la
entidad, otras entidades pueden utilizar a la
primera como un subcircuito, al mismo tiempo que
todas están siendo desarrolladas, es decir, están
siendo detalladas en su funcionamiento. Este
concepto de vistas externas e internas es propio de
VHDL y permite segmentar un sistema en bloques.
Así, una entidad es relativa a otras entidades a
través de sus conexiones y comportamiento. Por lo
que es posible experimentar cada entidad con
diferentes arquitecturas sin necesidad de cambiar
el resto del diseño. Y obviamente cada entidad
puede ser reutilizada en otros sistemas aunque no
hayan sido diseñadas específicamente para estos.
Un modelo de hardware de VHDL es mostrado
en la siguiente figura.
Figura 1.2 Modelo de Hardware de VHDL
Una entidad en VHDL, que ya es todo un
diseño, posee una o más conexiones hacia los
sistemas que la rodean. Una entidad puede estar
compuesta de otras entidades, de procesos y por
componentes, todos ellos trabajando
concurrentemente. Cada entidad está definida por
su arquitectura la cual se forma de instrucciones en
VHDL, ya sean aritméticas, asignaciones a señales
o de simples instanciaciones de componentes.
Los PROCESS en VHDL son utilizados para
modelar tanto circuitos secuénciales como
combinacionales utilizando un estilo de
descripción secuencial. Para interconectar procesos
distintos se utilizan SIGNALS que no son otra
cosa que simples cables.
Una señal posee una fuente (driver) y uno más
destinos (receptores) y un tipo de dato que le
proporciona características de interconexión. Por
ejemplo, una señal que se define como tipo bit
puede manejar los valores binarios ‘0’ y ‘1’
solamente, en tanto que una señal que se define
como bit_vector puede manejar mas de una
posición binaria.
La forma de diseñar circuitos en VHDL se
divide en tres categorías de acuerdo a su
complejidad: flujo de datos, comportamental, y
estructural. Estos tres estilos de diseño se detallan
a continuación.
• F
LUJO DE DATOS
En este estilo el diseño del circuito no es
complicado por lo que basta con describir como
fluyen los datos través de la entidad, de las
entradas hacia las salidas. La operación del sistema
está definida en términos de un conjunto de
transformaciones de datos expresadas como
instrucciones concurrentes.
• C
OMPORTAMENTAL
El diseño es un poco más complicado ya que
requiere de varias decisiones antes de definir los
datos de salida correctos. Por lo que se requiere de
una descripción algorítmica del funcionamiento
del circuito para facilitar el diseño del sistema. En
VHDL esto se obtiene expresando el
funcionamiento del diseño mediante una estructura
PROCESS la cual se compone de instrucciones
secuénciales.
• E
STRUCTURAL
Una descripción estructural se utiliza en
circuitos que requieren de más de una función,
hablando en términos de hardware, para realizar la
finalidad del sistema. Para ello segmentamos el
sistema en subcircuitos o componentes para
facilitar el diseño. Cada componente es
caracterizado en particular ya sea utilizando una
descripción de flujo de datos o comportamental. Y
a la entidad donde se describen las interconexiones
de estos componentes recibe el nombre de
descripción estructural.
Lo que ha hecho que VHDL sea en un tiempo
tan corto el lenguaje de descripción de hardware
más utilizado por la industria electrónica, es su
independencia con la metodología utilizada por
cada diseñador, su capacidad de descripción a
diferentes niveles de abstracción, y en definitiva la
IEC FRANCISCO JAVIER TORRES VALLE
6
CAPÍTULO I: LENGUAJES DE DESCRIPCIÓN DE HARDWARE
posibilidad de poder reutilizar en diferentes
aplicaciones un mismo código.
1.5 METODOLOGÍA DE DISEÑO
UTILIZANDO VHDL
I. Definición de los requerimientos del
sistema.
Antes de comenzar a realizar la descripción del
diseño, es muy importante que se tenga una idea
clara de los objetivos y requerimientos. Tales
como: funciones del circuito, máxima frecuencia
de operación, y los puntos críticos del sistema.
Esto servirá para poder definir a grandes rasgos
cual será la arquitectura del circuito y así comenzar
a realizar la descripción.
II. Descripción del circuito en VHDL.
Antes de comenzar a escribir el código es
recomendable seleccionar alguna metodología de
diseño como: Top-Down, Bottom-Up, o Flat. Los
dos primeros involucran la creación de diseños
jerárquicos que generalmente son grandes, y el
último es utilizado normalmente en el diseño de
circuitos pequeños.
La metodología Top-Down consiste en dividir
el sistema en varios bloques de tal manera que se
puedan resolver los problemas por separado,
además, cada bloque a su vez se puede dividir en
otros bloques si es necesario. El objetivo es que
cada bloque tenga una función especifica
representada mediante un componente que
desempeñe dicha función. Bottom-Up es todo lo
contrario, comenzamos por caracterizar los
componentes básicos del circuito y con estos
formamos bloques de mayor tamaño que
representen un circuito más complejo que sus
partes individuales. La metodología Flat es
comúnmente utilizada para diseños pequeños,
donde los requerimientos son pocos y no muy
complejos por lo que no nos distraen y no
perdemos de vista la funcionalidad del circuito.
Este método de diseño es el que utilizamos
cotidianamente en el diseño de circuitos digitales,
y se le llama Flat por que no es necesario
seccionar el circuito para poder diseñarlo.
Después de decidir cual será la metodología que
debemos implementar entonces comenzamos a
describir el circuito de acuerdo con lo que se había
establecido. Es recomendable utilizar algún tipo de
diagrama a bloques con la descripción del
funcionamiento de cada bloque, diagramas de
estado, o usar alguna tabla de funcionamiento
donde se resumen las funciones de cada bloque en
particular. Obviamente existe la posibilidad de
cometer errores en VHDL, pero generalmente
estos son de son de sintaxis, como ";" al final de
cada instrucción, o simplemente por no utilizar
adecuadamente alguna instrucción. Algunas
ocasiones se podrán tener problemas al tratar de
sintetizar el código y esto se debe a que se comete
el error de pensar en términos de programación en
vez de enfocarnos en la descripción del circuito.
Cuando se utiliza VHDL el objetivo principal es
el diseño de hardware y para ello debemos de
utilizar técnicas de síntesis apropiadas al lenguaje,
ya que se suele cometer el error de comenzar a
programar en vez de describir y esto provoca que
nos olvidemos del objetivo que es el hardware.
LA CLAVE PARA DESCRIBIR Y SINTETIZAR
FÁCILMENTE CIRCUITOS DIGITALES CON
VHDL ES PENSAR EN TÉRMINOS DE
COMPUERTAS Y REGISTROS Y NO EN
FUNCIÓN DE VARIABLES Y SUBRUTINAS
III. Simulación de la descripción en VHDL.
La simulación del código, o simulación
funcional, nos permite detectar y corregir errores
antes que se implemente en el dispositivo. La
modularidad implementada facilita la evaluación
del circuito, porque al describir el circuito por
bloques podemos analizar cada uno por separado
antes de unirlos. Esta simulación equivale a la
depuración de programas en los lenguajes de
computación.
IV. Síntesis
Síntesis consiste en reducir una descripción
realizada en un lenguaje de alto nivel de
abstracción a un nivel de compuerta que pueda ser
implementada en un circuito. Dicho de otra
manera, síntesis es el proceso mediante el cual una
descripción es convertida en un listado de
conexiones (netlist) entre las compuertas, registros,
multiplexores, etc. de un dispositivo lógico
programable.
Por ejemplo, una compuerta XOR puede ser
sustituido por su equivalente: A XOR B =
A'B+AB', o una instrucción IFpuede ser en
algunas ocasiones una compuerta AND, en otras
IEC FRANCISCO JAVIER TORRES VALLE
7
CAPÍTULO I: LENGUAJES DE DESCRIPCIÓN DE HARDWARE
una OR, o inclusive toda una función booleana que
involucra diferentes tipos de compuertas. Por lo
que el proceso de síntesis depende del dispositivo
utilizado. Generalmente una misma función es
implementada de diferentes formas de acuerdo al
dispositivo que estemos utilizando y esto no
cambia la funcionalidad del diseño y será la
misma si se selecciona el componente adecuado a
la complejidad del diseño. El proceso utilizado
para sintetizar un código en un CPLD es conocido
como Fitting o ajuste y consiste en adaptar las
ecuaciones booleanas en los diferentes bloques
lógicos del dispositivo. Cuando se utiliza un FPGA
el proceso empleado se le llama Place And Route
y consiste en adecuar las ecuaciones a través de
varias celdas lógicas. Aunque la finalidad es la
misma, la manera en que se sintetiza un código en
un CPLD es totalmente distinta a la síntesis de
circuitos utilizando FPGAs.
Por otro lado la optimización en la conversión
del código VHDL a ecuaciones booleanas depende
de tres factores:
I. La descripción del circuito.
II. Los recursos disponibles en el dispositivo
seleccionado.
III. Las directivas de síntesis seleccionadas por el
diseñador.
La descripción es el punto más importante
porque de esto dependen los otros dos. En la
descripción no solamente tenemos que “decir”
como funciona el circuito, además, tenemos que
describir en que “forma” debe de hacerlo. No es lo
mismo describir el diseño de un sumador de cuatro
bits utilizando cuatro módulos que realizan la
suma basándose en propagación de bits de acarreo
entre estos, a describir un circuito que realice la
suma de manera paralela sin utilizar
retroalimentaciones. Finalmente suman pero no lo
hacen igual. Los recursos afectan la forma en que
son implementadas las ecuaciones lógicas en el
dispositivo. Por ejemplo, un contador de 4 bits con
borrado asíncrono no puede ser implementado en
un 16V8, porque el registro de la macrocelda de
salida del dispositivo no cuenta con esta
característica. Finalmente las directivas de síntesis influyen directamente en el proceso de
cálculo de las ecuaciones que son implementadas
en el dispositivo. Algunas de estas directivas son:
asignación de pines, sintetizar para maximizar
velocidad, sintetizar para optimizar área, y algunas
que son descritas en el mismo código, como por
ejemplo forzar a que un nodo no sea simplificado o
eliminado y pueda ser retenido a la salida de una
macrocelda. Cuando se sintetiza para maximizar la
frecuencia generalmente quedan funciones con
varios términos e incluso hay términos que se
repiten en las ecuaciones de los nodos de salida,
pero esto se hace para evitar la retroalimentación.
V. Simulación del código sintetizado
Aún y cuando la simulación funcional se haya
realizado con éxito, debemos volver a evaluar el
circuito que realmente quedó sintetizado en el
dispositivo. Ya que las sustituciones de funciones,
como el caso de la compuerta XOR, dependerán de
las características del dispositivo utilizado. Y es
posible que ciertas funciones se ejecuten en más
tiempo de los esperado y esto altere el
funcionamiento del resto del diseño. Simular el
código sintetizado en el circuito permite verificar
los retrasos de tiempo de un nodo a otro, evaluar la
máxima frecuencia de operación del circuito y
verificar que éste funcione adecuadamente. En
dado caso que el código no pudiera ser sintetizado
podemos tratar de mejorar la descripción, es decir,
mejorar el diseño tratando de eliminar registros,
compuertas, buffers, etc., encontrar algún error en
la descripción, cambiar las directivas de síntesis o
definitivamente seleccionar otro dispositivo.
VI. Programación del dispositivo
Después de completar la descripción, la síntesis
y la simulación del circuito con éxito, el siguiente
paso es generar el archivo que nos permite
implementar físicamente nuestro diseño en un
dispositivo programable. Todos los programas de
VHDL para síntesis generan un archivo con el que
podemos programar el dispositivo. Ya sea JEDEC,
JTAG, BITSTREAM, etc. de acuerdo al tipo
dispositivo y fabricante.
IEC FRANCISCO JAVIER TORRES VALLE
8
CAPÍTULO II: DISPOSITIVOS LÓGICOS PROGRAMABLES
II
DISPOSITIVOS LÓGICOS
PROGRAMABLES
9
IEC FRANCISCO JAVIER TORRES VALLE
CAPÍTULO II: DISPOSITIVOS LÓGICOS PROGRAMABLES
2.1 CONCEPTOS
FUNDAMENTALES
La fabricación de dispositivos de lógica
programable se basa en los siguientes dos
conceptos.
UNCIONALIDAD COMPLETA
• F
La cual se fundamenta en el hecho de que
cualquier función lógica se puede realizar
mediante una suma de productos.
• C
ELDAS DE FUNCIONES UNIVERSALES.
También denominadas generadores de
funciones, son bloques lógicos configurados para
procesar cualquier función lógica, similares en su
funcionamiento a una memoria. En estas celdas se
almacenan los datos de salida del circuito
combinacional en vez de implementar físicamente
la ecuación booleana.
2.2 DISPOSITIVOS LÓGICOS
PROGRAMABLES
Un dispositivo lógico programable, o PLD
(Programmable Logic Device), es un dispositivo
cuyas características pueden ser modificadas y
almacenadas mediante programación. El
dispositivo programable más simple es el PAL
(Programmable Array Logic). El circuito interno
de un PAL consiste en una matriz de conexiones,
un matriz de compuertas AND y un arreglo de
compuertas OR. Una matriz de conexiones es una
red de conductores distribuidos en filas y columnas
con un fusible en cada punto de intersección,
mediante la cual se seleccionan cuales entradas del
dispositivo serán conectadas al arreglo AND cuyas
salidas son conectadas al arreglo OR y de esta
manera obtener una función lógica en forma de
suma de productos.
La mayoría de los PLDs están formados por una
matriz de conexiones, una matriz de compuertas
AND, y una matriz de compuertas OR y algunos,
además, con registros. Las matrices pueden ser
fijas o programables. Con estos recursos se
implementan las funciones lógicas deseadas
mediante un software especial y un programador
de dispositivos. El tipo más sencillo de matriz
programable, que data de los años 60, era una
matriz de diodos con un fusible en cada punto de
intersección de la misma. En la figura 2.1 se
muestran los circuitos básicos para la mayoría de
los PLDs.
Figura 2.1 Estructuras comúnmente utilizadas en
PLDs
2.2.1 MATRIZ GENÉRICA PROGRAMABLE
Una Matriz Genérica Programable, GAL
(Generic Array Logic), es una denominación que
utilizaba originalmente Lattice Semiconductor y
que más tarde se licenció a otros fabricantes. Un
GAL en su forma básica es un PLD con una matriz
AND reprogramable, una matriz OR fija y una
lógica de salida programable mediante una
macrocelda. Esta estructura permite implementar
cualquier función lógica en forma de suma de
productos con un numero de términos definido. En
los PLDs no reprogramables la síntesis de las
ecuaciones lógicas se realiza mediante la quema de
fusibles en cada punto de intersección de los pines
de entrada con las compuertas. En un GAL el
fusible se reemplaza por una celda CMOS
eléctricamente borrable (EECMOS) y mediante
programación se activa o desactiva cada celda
EECMOS. Una celda activada conecta su
correspondiente intersección de fila y columna, y
una celda desactivada desconecta dicha
intersección. Con esta estructura se puede aplicar
cualquier combinación de variables de entrada, o
sus complementos, a una compuerta AND para
generar cualquier operación producto que se desee.
A continuación se muestran las estructuras típicas
de un dispositivo GAL y la macrocelda de salida
del GAL22V10.
10
IEC FRANCISCO JAVIER TORRES VALLE
CAPÍTULO II: DISPOSITIVOS LÓGICOS PROGRAMABLES
Figura 2.2 Estructura típica de un GAL
FIGURA 2.3 Macrocelda de un GAL22V10
2.3 CPLD
Un CPLD (Complex Programmable Logic
Device) extiende el concepto de un PLD a un
mayor nivel de integración ya que permite
implementar sistemas más eficientes porque
utilizan menos espacio, mejoran la confiabilidad
en el circuito, y reducen costos. Un CPLD se
forma con múltiples bloques lógicos, cada uno
similar a un PLD. Los bloques lógicos se
comunican entre sí utilizando una matriz
programable de interconexiones lo cual hace más
eficiente el uso del silicio y conduce a un mejor
desempeño. A continuación se explican
brevemente las principales características de la
arquitectura de un CPLD.
multiplexores. La primera se basa en una matriz
de filas y columnas con una celda EECMOS en
cada intersección. Al igual que en el GAL esta
celda puede ser activada para conectar/desconectar
la correspondiente fila y columna. Esta
configuración permite una total interconexión
entre las entradas y salidas de los bloques lógicos.
Sin embargo, estas ventajas provocan que
disminuya el desempeño del dispositivo además de
aumentar el consumo de energía y el tamaño del
componente. En la interconexión mediante
multiplexores, existe un multiplexor por cada
entrada al bloque lógico. Las vías de interconexión
programables son conectadas a las entradas de un
numero fijo de multiplexores por cada bloque
lógico. Las entradas de selección de estos
multiplexores son programadas para permitir que
sea seleccionada únicamente una vía de la matriz
de interconexiones por cada multiplexor, la cual se
propaga hacia el bloque lógico. Cabe mencionar
que estos multiplexores no tienen acceso a todas
las vías de la matriz por lo que la rutabilidad se
incrementa usando multiplexores de mayor
tamaño, permitiendo así que cualquier
combinación de señales de la matriz de
interconexión pueda ser enlazada hacia cualquier
bloque lógico. Sin embargo, el uso de grandes
multiplexores incrementa el tamaño de dispositivo
y reduce su desempeño.
2.3.1 MATRIZ DE INTERCONEXIONES
PROGRAMABLES
La matriz de interconexiones programables,
PIM Programmable Interconect Matrix (véase la
figura 2.4), permite unir los pines de entrada/salida
a las entradas del bloque lógico, o las salidas del
bloque lógico a las entradas de otro bloque lógico,
o inclusive a las entradas del mismo bloque. La
mayoría de los CPLDs usan una de dos
configuraciones para esta matriz: interconexión mediante arreglo o interconexión mediante
11
IEC FRANCISCO JAVIER TORRES VALLE
Figura 2.4 Arquitectura Básica de un CPLD
2.3.2 BLOQUES LÓGICOS
Un bloque lógico es muy similar a un PLD, cada
uno de ellos poseen generalmente una matriz de
compuertas AND, una matriz de compuertas OR y
una configuración para la distribución de los
CAPÍTULO II: DISPOSITIVOS LÓGICOS PROGRAMABLES
productos en las diferentes macroceldas del boque.
El tamaño del bloque lógico es una medida de la
capacidad del CPLD, ya que de esto depende el
tamaño de la función booleana que pueda ser
implementada dentro del bloque. Los bloques
lógicos usualmente tienen de cuatro a veinte
macroceldas. La cantidad de bloques lógicos que
puede poseer un CPLD depende de la familia y
fabricante del dispositivo.
familia MAX se colocan 4 productos por
macrocelda los cuales pueden ser compartidos con
otras macroceldas. Cuando un producto puede ser
únicamente utilizado por una macrocelda se le
conoce como termino - producto dirigido, y
cuando estos pueden ser utilizados por otras
macroceldas se le llama termino - producto compartido. Mediante estos productos
compartidos se mejora la utilización del
dispositivo, sin embargo, esto produce un retardo
adicional al tener que retroalimentar un producto
hacia otra macrocelda y con esto disminuye la
velocidad de trabajo del circuito. La forma en que
son distribuidos los productos repercute en la
flexibilidad que proporciona el dispositivo para el
diseñador. Además, que estos esquemas
proporcionan también flexibilidad para los
algoritmos del programa de síntesis que es el que
finalmente selecciona la mejor forma en que deben
ser distribuidas las ecuaciones lógicas en el
componente.
Figura 2.5 Estructura de un Bloque Lógico en
dispositivos de las familias MAX340 y MAX5000
2.3.3 DISTRIBUCIÓN DE PRODUCTOS
Existen pequeñas diferencias en cuanto a la
distribución de los productos en un CPLD, esto
dependerá de la familia del dispositivo y del
fabricante. Obviamente el tamaño de las sumas
sigue siendo el factor más importante para la
implementación de funciones lógicas. Pero cada
fabricante distribuye los productos de diferente
forma.
La familia MAX de CPLDs que fue
desarrollada por Cypress Semiconductor
conjuntamente con Altera Corporation, siendo
los primeros en sacar al mercado unan familia de
CPLDs, Altera la llamó MAX5000 y Cypress por
su parte la clasificó como MAX340, la
distribución de productos no es igual a la de un
PLD. En un dispositivo como el 22V10 tenemos
que la suma de productos es fija por cada
macrocelda -8, 10, 12, 14 o 16 productos-, en la
Figura 2.6 Distribución de Productos en
dispositivos de las familias MAX340 y MAX5000
2.3.4 MACROCELDAS
Las macroceldas de un CPLD son similares a las
de un PLD. Estas también están provistas con
registros, control de polaridad, y buffers para
utilizar salidas con alta impedancia. Por lo general
un CPLD tiene macroceldas de entrada/salida,
macroceldas de entrada y macroceldas internas
u ocultas (buried macrocells), en tanto que un
22V10 tiene solamente macroceldas de
entrada/salida. Una macrocelda interna es similar a
una macrocelda de entrada/salida, sólo que esta no
puede ser conectada directamente a una terminal
del dispositivo. La salida de una macrocelda
12
IEC FRANCISCO JAVIER TORRES VALLE
CAPÍTULO II: DISPOSITIVOS LÓGICOS PROGRAMABLES
interna va conectada directamente a la matriz de
interconexiones programable. Por lo que es posible
manejar ecuaciones y almacenar el valor de salida
de estas internamente utilizando los registros de
estas macroceldas.
En la figura 2.7 se muestran la arquitectura
interna de un CPLD de la familia FLASH 370 de
Cypress Semiconductors. En esta podemos
apreciar las macroceldas de entrada/salida,
macroceldas ocultas y celdas de entrada/salida con
las que cuenta el dispositivo.
Figura 2.7 Macroceldas de entrada/salida, macroceldas ocultas y celdas de entrada/saliad en dispositivos
de la familia FLASH 370
Las macroceldas de entrada, como la que se
muestra en la figura 2.8, son utilizadas para
proporcionar entradas adicionales para las
funciones lógicas. En el diagrama se muestra la
macrocelda de entrada de la familia FLASH 370.
En general las macroceldas de entrada incrementan
la eficiencia del dispositivo al ofrecer algunos
registros adicionales con los que se pueden
almacenar el valor de la terminal de entrada.
2.3.5 CELDA DE ENTRADA/SALIDA
En la figura 2.7 se puede apreciar una celda de
entrada/salida, que bien podría considerarse parte
del bloque lógico, pero no necesariamente tienen
que estar a la salida de un bloque lógico. La
función de una celda de entrada/salida es permitir
el paso de una señal hacia dentro o hacia el
exterior del dispositivo. Dependiendo del
fabricante y de la arquitectura del CPLD estas
celdas son pueden ser consideradas o no parte del
bloque lógico.
2.4 FPGA
La arquitectura de un FPGA (Field
Figura 2.8 Macrocelda de entrada en dispositivos
de la familia FLASH 370
Programmable Gate Array) consiste en arreglos de
varias celdas lógicas las cuales se comunican unas
con otras mediante canales de conexión verticales
13
IEC FRANCISCO JAVIER TORRES VALLE
CAPÍTULO II: DISPOSITIVOS LÓGICOS PROGRAMABLES
y horizontales tal y como se muestra en la figura
2.9.
Figura 2.9 Arquitectura básica de un FPGA
2.4.1 CELDAS LÓGICAS
Cada celda lógica es funcionalmente similar a
los bloques lógicos de un CPLD. La diferencia
está en que un FPGA normalmente utiliza
generadores de funciones en vez de compuertas.
Cada uno de estos generadores es como una
memoria en donde en vez de implementar la
función lógica mediante compuertas, se precalcula
el resultado y se almacena en el generador. Las
entradas al generador funcionan como un bus de
direcciones, y mediante las diferentes
combinaciones de las entradas al generador se
selecciona el resultado correcto. Esto le da una
gran densidad al dispositivo ya que se maneja un
gran número de generadores, pero el tiempo de
propagación al implementar una función lógica en
estos generadores es menor al que se necesitaría si
utilizáramos compuertas. La estructura de las
celdas lógicas y las formas en que estas pueden ser
interconectadas, tanto salidas como entradas de la
celda, varían de acuerdo al fabricante. En general
una celda lógica tiene menos funcionalidad que la
combinación de sumas de productos y macroceldas
de un CPLD, pero como cada FPGA tienen una
gran cantidad de celdas lógicas es posible
implementar grandes funciones utilizando varias
celdas lógicas en cascada. Además de las celdas
lógicas también es importante la tecnología
utilizada para crear las conexiones entre los
canales, las más importantes son las siguientes.
• ANTIFUSE
Al igual que la tecnología PROM, un FPGA que
utiliza este tipo de tecnología sólo se puede
programar una sola vez y utilizan algo similar a un
fusible para realizar las conexiones. Una vez que
éste es programado ya no se puede recuperar. La
diferencia radica en que en un fusible normal se
desactiva deshabilitando la conexión, en tanto que
en estos anti - fusibles cuando son programados se
produce una conexión por lo que normalmente se
encuentran abiertos. La desventaja obvia es que no
son reutilizables, pero por el contrario disminuyen
considerablemente el tamaño y costo de los
dispositivos.
• SRAM
Las celdas SRAM son implementadas como
generadores de funciones para remplazar la lógica
combinacional mediante compuertas y, además,
son usadas para controlar multiplexores e
interconectar las celdas lógicas entre ellas. En estas
el contenido se almacena mediante un proceso de
configuración en el momento de encendido del
circuito que contiene al FPGA. Ya que al ser
SRAM, el contenido de estos bloques de memoria
se pierde cuando se deja de suministrar la energía.
La información binaria de las celdas SRAM
generalmente se almacena en memorias seriales
EEPROM conocidas como memorias de
configuración. En el momento de encendido del
circuito toda la información binaria es transferida a
las celdas del FPGA mediante el proceso de
configuración el cual es generalmente automático
y el propio FPGA contiene un circuito interno que
se encarga de hacer todo el proceso.
Un FPGA que tiene una gran cantidad de
canales de interconexión tiende a tener pequeñas
celdas lógicas con muchas entradas y salidas en
comparación con el número de compuertas que
tiene la celda, este tipo de FPGAs generalmente
utilizan tecnología ANTIFUSE. Un FPGA que
tiene una estructura pequeña en canales de
interconexión tiende a tener grandes celdas lógicas
con pocas entradas y salidas en comparación con el
número de compuertas que hay en la celda. Este
tipo de FPGA generalmente está fabricado con
tecnología SRAM. Una arquitectura con celdas
lógicas pequeñas permite utilizar todos los
recursos del dispositivo. Sin embargo, si las celdas
lógicas son muy pequeñas entonces tendremos que
utilizar un gran número de estas para poder
implementar funciones lógicas de varios términos,
lo cual agrega un tiempo de retardo por cada celda
lógica implementada. Cuando el tamaño de la
celda lógica es grande sucede lo contrario, en este
tipo de celdas lógicas es posible utilizar un gran
número de compuertas por lo que podemos
IEC FRANCISCO JAVIER TORRES VALLE
14
CAPÍTULO II: DISPOSITIVOS LÓGICOS PROGRAMABLES
implementar funciones lógicas de varios términos
con pocas celdas lógicas. El que el tamaño de la
celda sea grande no afecta la frecuencia máxima de
trabajo porque estamos hablando de que existe un
gran numero de compuertas que pueden ser usadas
en la función paralelamente, siendo el mismo
tiempo de retardo para todas. Sin embargo, cuando
las funciones son pequeñas en comparación con el
tamaño de la celda no es necesario utilizar todas
las compuertas de la celda, por lo que este tipo de
celdas no son precisamente las más indicadas para
desempeñar pequeñas funciones. La tecnología
SRAM es utilizada por Altera, Lucent
Technologies, Atmel, Xilinx y otros. La tecnología
ANTIFUSE es utilizada por Cypress, Actel,
QuickLogic, y Xilinx. A continuación se muestran
algunas celdas lógicas de distintos fabricantes.
Figura 2.10 Bloque Lógico Configurable de la familia XC4000 de Xilinx, Inc.
IEC FRANCISCO JAVIER TORRES VALLE
15
CAPÍTULO II: DISPOSITIVOS LÓGICOS PROGRAMABLES
Figura 2.11 Elemento Lógico de la familia APEX20K de Altera Corporation
Figura 2.12Modulo Lógico de la familia ACT3 de Actel Corporation
IEC FRANCISCO JAVIER TORRES VALLE
16
CAPÍTULO III: SINTAXIS DEL LENGUAJE
SINTAXIS DEL
III
IEC FRANCISCO JAVIER TORRES VALLE
LENGUAJE
17
CAPÍTULO III: SINTAXIS DEL LENGUAJE
3.1 INTRODUCCIÓN A LA
DESCRIPCIÓN EN VHDL DE
CIRCUITOS DIGITALES
En este capítulo se discutirán los elementos
fundamentales de VHDL que son comúnmente
utilizados en síntesis de circuitos. Primero se
exponen el diseño de multiplexores y
comparadores con VHDL para hacer una
analogía con la metodología convencional de
diseño. Ya que es muy importante comprender
porque VHDL es un lenguaje para describir y no
para programar. Posteriormente se expondrán los
elementos básicos del lenguaje, tales como:
identificadores, objetos de datos, tipos de datos,
operadores y tipos de instrucciones.
3.1.1 MULTIPLEXORES
Antes de examinar la descripción en VHDL de
multiplexores, analizaremos el funcionamiento
interno y la metodología tradicional de diseño
utilizada en este tipo de circuitos para después
realizar la descripción del circuito en VHDL. En
la figura 3.1 se describe externamente a un
multiplexor y la tabla resume su funcionalidad.
ENTRADA SALIDA
x0
x1
s0
z0
s0 z0
0 x0
1 x1
Figura 3.1 Multiplexor 2 a 1
La tabla de verdad completa sería la siguiente.
ENTRADAS SALIDA
s0 x0 x1 z0
0 0 0 0
0 0 1 0
0 1 0 1
0 1 1 1
1 0 0 0
1 0 1 1
1 1 0 0
1 1 1 1
Utilizando cualquier técnica de simplificación
de ecuaciones obtenemos: z0 = s0’·x0+s0·x1. Y el
circuito quedaría como se muestra en la figura
3.2.
Figura 3.2 Circuito del Multiplexor 2 a 1
En VHDL podemos describir el circuito ya sea
mediante la descripción completa de todas las
combinaciones de las entradas, utilizando la tabla
simplificada de funcionamiento o si lo deseamos
es posible realizar la descripción compuerta por
compuerta del circuito. Al primer estilo se le
conoce como de flujo de datos y en este debemos
describir como fluyen los datos de entrada hacia
la salida. A continuación se muestra la
descripción de flujo de datos del multiplexor con
VHDL utilizando la tabla completa de
funcionamiento del mismo. Las palabras en
negritas son palabras reservadas en VHDL y los
comentarios comienzan con dos guiones (--).
ENTITY multiplexor IS
PORT (s0, x0, x1: IN bit;
z0: OUT bit);
END multiplexor;
ARCHITECTURE data_flow OF multiplexor IS
SIGNAL temp: bit_vector (2 DOWNTO 0);
BEGIN
z0 <= '0' WHEN temp = "000" ELSE
'0' WHEN temp = "001" ELSE
'1' WHEN temp = "010" ELSE
'1' WHEN temp = "011" ELSE
'0' WHEN temp = "100" ELSE
'1' WHEN temp = "101" ELSE
'0' WHEN temp = "110" ELSE
'1';
temp <= s0 & x0 & x1; -- Concatenación
-- de las entradas en un
-- solo bus.
END data_flow;
Las descripciones en VHDL son creadas a
partir de dos estructuras que son fundamentales
IEC FRANCISCO JAVIER TORRES VALLE
18
CAPÍTULO III: SINTAXIS DEL LENGUAJE
para el lenguaje: la entidad y la arquitectura.
Básicamente la entidad es la estructura en la que
se define cuales son las entradas y salidas del
circuito que deseamos representar, la cual
podemos asociar con una “caja” en la que se que
precisan cuales son las interfaces de
comunicación con el exterior, siendo la
arquitectura donde se detalla el comportamiento
interno de esa “caja”. Observe que en la
descripción anterior se utilizó un objeto de datos
llamado SIGNAL para crear el bus “temp” y
concatenar “s0”, “x0” y “x1” en un solo objeto y
así facilitar la descripción. A continuación
utilizaremos la tabla simplificada para diseñar el
multiplexor, ya que si observamos la salida
depende fundamentalmente de la entrada de
selección “s0”, por lo que atendiendo a esta
característica la descripción de flujo de datos
quedaría tal y como se muestra a continuación.
ENTITY multiplexor IS
PORT (s0, x0, x1: IN bit;
z0: OUT bit);
END multiplexor;
ARCHITECTURE data_flow OF multiplexor IS
BEGIN
z0 <= x0 WHEN s0 = '0' ELSE x1;
END data_flow;
En ambas descripciones hemos definido el
funcionamiento de la salida apoyándonos en las
entradas. Note que existe cierto “paralelismo” de
las entradas hacia las salidas, es decir, no importa
cual combinación de entradas se dé, sólo una
opción será asignada a la salida. Por lo que no
importa cual orden se haya seguido en la
descripción del circuito. Y esta es una de las
principales características de VHDL, es decir, no
importa tanto el orden de las instrucciones, lo cual
no es así en lenguaje de programación de
software. Tal vez este “paralelismo” se perciba
con mayor detalle realizando la descripción del
circuito compuerta por compuerta utilizando la
ecuación simplificada del circuito obtenida
anteriormente.
ENTITY multiplexor IS
PORT (s0, x0, x1: IN bit;
z0: OUT bit);
END multiplexor;
ARCHITECTURE data_flow OF multiplexor IS
SIGNAL not_s0, and1, and2: bit;
BEGIN
z0 <= and1 OR and2;
and1 <= not_s0 AND x0;
not_s0 <= NOT s0;
and2 <= s0 AND x1;
END data_flow;
La descripción anterior también es de flujo de
datos y no sigue ningún orden en particular en el
uso de las instrucciones y esto se ha hecho para
destacar el comportamiento paralelo o
concurrente de VHDL. Observe que cada
ecuación describe a cada una de las compuertas
que se muestran en la figura 3.2, por lo cual no
hubiera importado el orden que hayamos seguido
siempre y cuando se realicen las conexiones
correctamente.
Pensemos en el circuito implementado
físicamente en el laboratorio. Cada una de estas
compuertas posee características eléctricas que les
asignan un funcionamiento definido. Estas
particularidades eléctricas cumplen con leyes
físicas que se están cumpliendo todo momento y,
entonces, no importa como se hayan ordenado
los circuitos entre sí lo importante es realizar
correctamente las conexiones para obtener la
función deseada. En VHDL se trata de emular ese
comportamiento, por lo tanto el orden que se haya
seguido en cada una de las instrucciones
anteriores no es importante, ya que hicimos
correctamente la interconexión entre las
compuertas.
3.1.2 COMPARADORES
La figura 3.3 representa a un comparador y la
siguiente tabla resume su funcionalidad.
ENTRADASSALIDAS
x_may_y equals x_men_y
x > y 1 0 0
x = y 0 1 0
x < y 0 0 1
IEC FRANCISCO JAVIER TORRES VALLE
19
CAPÍTULO III: SINTAXIS DEL LENGUAJE
Figura 3.3 Comparador
En el diseño convencional de un comparador
tendríamos que realizar una tabla de todos los
posibles valores lógicos de las salidas respecto a
las entradas. Lo cual en este caso sería de 256
combinaciones, dado que tenemos ocho bits de
entrada para obtener las tres ecuaciones de salida.
En VHDL basta con describir de una forma
general el funcionamiento del hardware y el
sintetizador se encargará de generar toda esta
tabla de 256 combinaciones y obtener las
ecuaciones lógicas de las tres salidas. El código
mostrado a continuación corresponde al
comparador mostrado en la figura 3.3.
ENTITY comparador IS
PORT ( x: IN bit_vector (3 DOWNTO 0);
END comparador;
ARCHITECTURE data_flow OF comparador IS
BEGIN
equals <= '1' WHEN x = y ELSE '0';
x_may_y <= '1' WHEN x > y ELSE '0';
x_men_y <= '1' WHEN x < y ELSE '0';
END data_flow;
y: IN bit_vector (3 DOWNTO 0);
equals: OUT bit;
x_may_y: OUT bit;
x_men_y: OUT bit);
Nótese que en la primera declaración de
puertos, dentro de la entidad del comparador, se
definen dos bus de entrada de cuatro bits de
magnitud (x, y), en cambio las salidas son de
solamente un bit. En la entidad lo único que
hacemos es describir como es el circuito, o
aquello del circuito que permite a la entidad
comunicarse hacia otras entidades, sin mencionar
para nada su comportamiento interno. Y es en la
arquitectura, después del BEGIN, es donde se
realiza la descripción del comportamiento del
circuito atendiendo únicamente a la funcionalidad
del mismo, es decir, no es necesario analizar cada
caso en particular de las 256 posibles
combinaciones.
3.1.3 EL ESTILO DE “PROGRAMACIÓN”
N VHDL
E
Haciendo una comparación con un lenguaje de
programación de alto nivel podemos ver que el
código es similar en cuanto a las sentencias
utilizadas, sin embargo, no es así en el flujo de
ejecución de las instrucciones. Un código de
programación en VHDL no es precisamente un
“programa”, ya que un programa es un conjunto
de instrucciones que se ejecutan paso a paso para
llevar a cabo una tarea determinada, y en este
caso no podemos decir que las instrucciones se
estén ejecutando de esta manera, porque esto no
corresponde en la realidad al comportamiento de
un circuito. En VHDL las instrucciones se están
ejecutando en todo momento lo cual sí se asemeja
al comportamiento real de un circuito. Así cuando
cambie alguna señal de entrada cambiará
inmediatamente la salida y, por consiguiente,
estamos describiendo cual es el verdadero
funcionamiento del circuito. La forma en que se
“programa” en VHDL al principio resultará un
tanto extraña, pero si asociamos éste código con
el circuito que estamos describiendo, podemos
darnos cuenta que en él los componentes siempre
están activos, y es esto es precisamente lo que
describimos mediante VHDL. Tal vez alguna vez
ha utilizado PSPICE o algún programa de
entrada esquemática de diseño para modelar y
simular circuitos, estos también son para la
descripción de circuitos. En PSPICE la
descripción se realiza mediante un listado de
conexiones (netlist) entre los componentes, en
tanto que en los otros lo hacemos de manera
gráfica y en ambos se considera que todos los
componentes siempre están funcionando para que
la simulación o modelado del diseño sea de
acuerdo a la realidad. Por esto en VHDL el orden
de las instrucciones no es tan importante como en
el caso de un lenguaje de programación de
software, porque las instrucciones se están
ejecutando al mismo tiempo y así sí se modela
adecuadamente un circuito. Posteriormente se
explicarán los tipos de instrucciones y sus
diferencias, ya que VHDL si permite la
“descripción secuencial” utilizando instrucciones
de esta naturaleza dentro de una estructura
llamada PROCESS. En esta estructura las
instrucciones se ejecutan “paso a paso” como en
los lenguajes de programación de software. Pero
de cualquier manera esta estructura siempre esta
activa, como si fuera un componente o subcircuito
del diseño, por lo que todo lo que se obtenga
dentro del proceso se ejecutará paralelamente con
el resto de las instrucciones que están fuera de
esta estructura.
Otro punto importante es el dispositivo lógico
programable que estemos utilizando, ya que si
éste no tiene la capacidad para realizar lo que
“dice” nuestra descripción nunca podremos
IEC FRANCISCO JAVIER TORRES VALLE
20
CAPÍTULO III: SINTAXIS DEL LENGUAJE
sintetizar el código. Por ejemplo, si en el
dispositivo que usemos no es posible que las
salidas puedan ser programadas para que trabajen
con alta impedancia, aún y cuando la descripción
sea correcta nunca podremos sintetizarla en el
dispositivo.
Al principio generalmente se comete el error de
tratar de “programar” como si fuera C++, Pascal,
Visual Basic o cualquier otro lenguaje de
programación de software, además de olvidar que
el PLD, CPLD, o FPGA que utilicemos tiene
características propias que deben ser consideradas
cuando se hace la descripción. Pero basta con
recordar que estamos diseñando hardware y que
por lo tanto no se trata de un lenguaje secuencial
de programación para software.
3.2 IDENTIFICADORES
Un identificador se define como un conjunto de
caracteres con el cual podemos representar
diferentes elementos dentro de una descripción.
En VHDL un identificador está compuesto por
una secuencia de uno o más caracteres
alfabéticos, numéricos, o del carácter de
subrayado. Las condiciones que debe de seguir un
identificador son las siguientes:
• VHDL permite la utilización de las letras
mayúsculas (A.. Z), minúsculas (a.... z),
dígitos (0...9), y el carácter de subrayado (_).
• El primer carácter de un identificador debe
ser una letra.
• El ultimo carácter de identificador no puede
ser el carácter de subrayado. Además, el
carácter de subrayado no puede aparecer dos
o más veces consecutivas.
• Mayúsculas y minúsculas son consideradas
idénticas. Así, Signal_A, signal_a, y
SIGNAL_A se refieren al mismo
identificador.
• Los comentarios en VHDL comienzan con
dos guiones consecutivos (--), y se extienden
hasta el final de la línea. Los comentarios
pueden aparecer en cualquier lugar dentro de
una descripción en VHDL.
• VHDL define un grupo de palabras
reservadas, llamadas "palabras clave"
(keywords), las cuales no pueden ser usadas
como identificadores.
EJEMPLOS
-- Este es un comentario.
ENTITY contador IS -- comentario al final
-- de una línea
Los siguientes ejemplos son de identificadores
válidos en VHDL.
Mi_entidad
Mux4a2
TTL_7490
A continuación se muestran ejemplos de
identificadores no válidos en VHDL.
3er_Modulo -- un identificador no
-- puede iniciar con un
-- dígito
_salida_x -- o con el carácter de
-- subrayado
M__24xmax -- no se permiten dos
-- caracteres de
-- subrayado seguidos
My_design_ -- un identificador no
-- debe terminar con un
-- carácter de subrayado
Unidad& -- el caracter "&", no
-- es un carácter válido
SIGNAL -- palabra reservada
3.3 OBJETOS DE DATOS
Un objeto de datos en VHDL es un elemento
que toma un valor de algún tipo de dato
determinado. Según sea este tipo de dato, el
objeto poseerá un conjunto de propiedades que se
le podrán aplicar, como las operaciones en las que
el objeto puede ser usado. En VHDL los objetos
de datos son generalmente de una de tres clases:
constantes, variables o señales.
3.3.1 CONSTANTES
Una constante es un elemento que puede tomar
un único valor de un tipo dado. A las constantes
se les debe asignar un valor en el momento de la
declaración. Una vez que se le ha asignado algún
valor, éste no puede ser cambiado dentro de la
descripción del diseño. Las constantes pueden ser
IEC FRANCISCO JAVIER TORRES VALLE
21
CAPÍTULO III: SINTAXIS DEL LENGUAJE
declaradas dentro de las entidades, arquitecturas,
procesos o paquetes. Las constantes que se
declaren en un paquete pueden ser utilizadas en
cualquier descripción en la que se este utilizando
dicho paquete. Por otra parte las constantes
declaradas dentro de una entidad pueden ser
utilizadas por la o las arquitecturas en las que se
este haciendo la descripción de dicha entidad, y
aquellas constantes que sean declaradas dentro de
una arquitectura o proceso, son válidas
únicamente dentro de la estructura
correspondiente.
D
ECLARACIÓN DE CONSTANTES
CONSTANT identificador: tipo := valor;
EJEMPLO
CONSTANT byte: integer := 8;
3.3.2 VARIABLES
Los objetos de datos de la clase variable son
similares a las constantes, con la diferencia que su
valor puede ser modificado cuando sea necesario.
Las variables en VHDL son similares a cualquier
tipo de variable de un lenguaje de programación
de alto nivel. A las variables también se les puede
asignar un valor inicial al momento de ser
declaradas. Se utilizan únicamente en los
procesos y subprogramas (funciones y
procedimientos). Las variables generalmente se
utilizan como índices, principalmente en
instrucciones de bucle, o para tomar valores que
permitan modelar componentes. Las variables no
representan conexiones o estados de memoria.
DECLARACIÓN DE VARIABLES
VARIABLE identificador: tipo [:=valor];
EJEMPLO
VARIABLE aux1, aux2: bit;
3.3.3 SEÑALES
representan elementos de memoria o conexiones y
si pueden ser sintetizadas.
Los puertos de una entidad son implícitamente
declarados como señales en el momento de la
declaración, ya que estos representan conexiones.
También pueden ser declaradas en las
arquitecturas antes del BEGIN, lo cual nos
permite realizar conexiones entre diferentes
estructuras de programación. La asignación de
valores a un objeto de datos del tipo señal no es
inmediata como en el caso de las variables, esto
se explicará más detalladamente cuando se
exponga la estructura PROCESS y los tipos de
instrucciones.
DECLARACIÓN DE SEÑALES
SIGNAL identificador: tipo [:=valor];
EJEMPLOS
SIGNAL A, B: bit := '0'; -- el valor
-- inicial es
-- opcional
SIGNAL dato: bit_vector (7 DOWNTO 0);
3.3.4 ALIAS
Un ALIAS no es precisamente un objeto de
datos. La instrucción ALIAS permite que
utilicemos un identificador diferente para hacer
referencia a un objeto de datos, o a parte de él, ya
existente. Este no es un objeto de datos nuevo,
sino que nos permite manipular fragmentos del
objeto de datos original para facilitar la
programación. Al modificar el ALIAS se
modifica el objeto de datos al que señala.
DECLARACIÓN DE ALIAS
ALIAS identif: tipo IS identif2 <rango>;
EJEMPLO
ALIAS instr: bit_vector (3 DOWNTO 0) IS
dato (7 DOWNTO 4);
Un objeto de la clase señal es similar a un
objeto de la clase variable, con una importante
diferencia: las señales si pueden almacenar o
pasar valores lógicos, mientras que una variable
no lo puede hacer. Las señales, por lo tanto,
IEC FRANCISCO JAVIER TORRES VALLE
3.4 TIPOS DE DATOS
Un tipo de dato especifica el grupo de valores
que un objeto de datos puede tomar así como las
operaciones que son permitidas con esos valores.
En VHDL es sumamente importante el tipo de
22
CAPÍTULO III: SINTAXIS DEL LENGUAJE
dato, los objetos de datos no pueden tomar o no se
les puede asignar un objeto de datos de otro tipo,
y no todas las operaciones se pueden utilizar con
los diferentes tipos de datos a menos que se
utilicen las librerías adecuadas en las que estén
definidas funciones para la conversión de tipos.
Además, es posible que el usuario defina subtipos
y tipos compuestos, modificando los tipos
básicos, así como definir tipos particulares con
combinaciones de los diferentes tipos. A
continuación se discutirán las dos categorías de
tipos de datos más utilizadas en síntesis: escalares
y compuestos.
3.4.1 TIPOS ESCALARES
Los tipos escalares tienen un orden especifico
lo cual permite que sean usados con diferentes
operadores. Existen cuatro clases de tipos
escalares: enteros, reales o de punto flotante,
enumerados, y físicos.
•
ENTERO
VHDL permite especificar la gama del entero
(integer) de manera diferente. Sin embargo, la
gama debe extender desde por lo menos -(2^31-1)
a +(2^31-1), o - 2147483648 a +2147483647.
Una señal o variable declarada como tipo entero y
que tenga que ser sintetizada en elementos
lógicos, debe ser limitada con un rango.
EJEMPLO
VARIABLE n: integer RANGE -15 TO 15;
• REAL
El rango de valores que puede tomar este tipo
de dato se encuentra entre -1.038E38 a
+1.038E38. El Real rara vez es usado en síntesis y
en la gran mayoría de las herramientas de
software de VHDL para síntesis no es posible
utilizar este tipo de dato.
• ENUMERADOS
Un tipo enumerado es un tipo de dato con un
grupo de posibles valores asignados por el
usuario. Los tipos enumerados se utilizan
principalmente en el diseño de maquinas de
estado.
TYPE nombre IS ( valor [,valor...] );
El orden en el que los valores son listados en la
declaración del tipo enumerado define el orden
léxico para ese tipo.
EJEMPLOS
a) En este ejemplo se define un tipo enumerado
llamado “arith”, y los posibles valores son add,
sub, mul, y div.
TYPE arith IS (add, sub, mul, div);
b) Ahora se define un tipo enumerado llamado
“estados”, con 4 posibles valores: estado0,
estado1, estado2 y estado3.
TYPE estados IS ( estado0, estado1,
estado2, estado3 );
Existen varios tipos de datos enumerados,
algunos predefinidos en los programas de síntesis,
para el lenguaje pero generalmente los siguientes
tipos enumerados son los más comúnmente
utilizados para síntesis de circuitos.
B
OOLEAN
El tipo BOLEAN es un tipo enumerado con
dos valores, FALSE y TRUE, donde FALSE <
TRUE. Las funciones lógicas y de comparación
retornan siempre un valor booleano.
Cuando en una operación lógica o de
comparación se utilza un tipo de dato no
booleano, el bit por ejemplo, existen funciones de
conversión que permiten realizar dichas
operaciones con distintos tipos de datos. En el
caso del bit se utiliza la siguiente función.
boolean_var := (bit_var = '1');
BIT
El bit es un tipo enumerado que representa
valores binarios: '0' y '1'. Las operaciones lógicas
en las participa este tipo de dato regresan valores
binarios mediante las siguiente función.
IF (boolean_var) THEN
bit_var := '1';
ELSE
bit_var := '0';
END IF;
D
ECLARACIÓN DE UN TIPO ENUMERADO
IEC FRANCISCO JAVIER TORRES VALLE
23
CAPÍTULO III: SINTAXIS DEL LENGUAJE
CHARACTER
El tipo character es un tipo enumerado que
contiene el conjunto de los símbolos contenido
en el ASCII.
STD_LOGIC
El tipo std_logic es similar al tipo bit pero con
la excepción que éste no esta definido dentro del
lenguaje. El paquete std_logic_1164 de la IEEE
define al std_logic como un tipo de dato el cual
puede tomar los valores 'U', 'X', '0', '1', 'Z', 'W', 'L',
'H', '-'. Para poder utilizar este tipo de dato es
necesario incluir el paquete dentro de la
descripción utilizando las siguientes dos líneas
antes de la declaración de la entidad.
LIBRARY ieee;
USE ieee.std_logic_1164.ALL;
El significado de los valores del std_logic se
muestra en la siguiente tabla.
'U' -- Uninitialized 'W' -- Weak Unknow
'X' -- Forcing 'L' -- Weak 0
'0' -- Forcing 0 'H' -- Weak 1
'1' -- Forcing 1 '-' -- Don't care
'Z' -- High Impedance
Los valores '0', '1', 'L' y 'H', se utilizan en
síntesis de circuitos, los valores 'Z' y '-' tienen
restricciones sobre como y donde pueden ser
usados. Los valores 'U', 'W' y 'X' se utilizan
únicamente para simulación y evaluación de
diseños mas no para síntesis. Para la mayoría de
los diseños se utiliza este tipo de dato ya que es
más completo que el tipo bit por proporcionar los
valores 'Z' y '-'.
S
OBRECARGA DE UN TIPO ENUMERADO
Es posible cargar el valor de algún tipo
enumerado incluyendo dicho valor en la
definición de dos o más tipos enumerados.
Cuando se utilice en una descripción dos o más
tipos que usen el mismo valor generalmente el
programa de síntesis identifica de cual tipo
proviene, pero bajo ciertas condiciones esta
determinación es imposible. En estos casos es
necesario indicar explícitamente de cual tipo se
trata. En el siguiente ejemplo se muestra como
realizar esta indicación explicita.
TYPE color is (red, green, yellow, blue,
violet);
TYPE primary_color IS (red, yellow, blue);
. . .
SIGNAL A: color;
SIGNAL B: primary_color;
SIGNAL C: bit;
SINAL D: std_logic;
. . .
A <= color'(red); -- Se indica a que
-- tipo estamos
-- haciendo
-- referencia
B <= blue; -- Posiblemente el
-- programa de síntesis
-- marque error en este
-- caso
C <= '1'; -- En estas dos
-- asignaciones el
D <= '1'; -- programa de síntesis
-- identifica de que
-- tipo se trata
CODIFICACIÓN DE LOS TIPOS ENUMERADOS
Los tipos enumerados se ordenan de acuerdo a
sus valores. Los programas de síntesis
automáticamente codifican binariamente los
valores del tipo enumerado para que estos puedan
ser sintetizados. Algunos programas los hacen
mediante una secuencia binaria ascendente, otros
buscan cual es la codificación que mejor conviene
para tratar de minimizar el circuito o para
incrementar la velocidad del mismo una vez que
la descripción es sintetizada. También es posible
asignar el tipo de codificación mediante directivas
de síntesis.
El siguiente ejemplo muestra la forma en que el
programa de síntesis Foundation de Xilinx, Inc.
codifica un tipo enumerado de cinco posibles
valores.
TYPE color IS (red, green, yellow, blue,
violet);
La codificación sería la siguiente: red="000",
green="001", yellow="010", blue="011",
violet="100".
Para realizar la codificación manualmente se
deben utilizar directivas de síntesis que son
propias de cada programa. Para ver ejemplo de
cómo se utilizan consulte la ayuda del programa y
IEC FRANCISCO JAVIER TORRES VALLE
24
CAPÍTULO III: SINTAXIS DEL LENGUAJE
busque la sección de "directivas de síntesis" o
"codificación de tipos enumerados".
• FÍSICOS
Los tipos físicos son usados para especificar
unidades de medida, ya sea de tiempo o para
determinar medidas eléctricas. El único tipo
predefinido es el “time”, mediante el cual se
pueden establecer medidas para simular los
retardos de tiempo o para generar diferentes
señales que nos permitan simular nuestro diseño.
La unidad básica del tipo time es el
femtosegundo, y de éste se forman diferente
múltiplos.
TYPE time IS RANGE -2147483647 TO
UNITS
fs;
ps = 1000 fs;
ns = 1000 ps;
us = 1000 ns;
ms = 1000 us;
sec = 1000 ms;
min = 60 sec;
hr = 60 min;
ENDUNITS;
2147483647
Los tipos físicos no tienen ningún significado
en síntesis, sólo son utilizados para simulación de
circuitos.
IEC FRANCISCO JAVIER TORRES VALLE
25
CAPÍTULO III: SINTAXIS DEL LENGUAJE
3.4.2 TIPOS COMPUESTOS
Un tipo compuesto es un tipo de dato formado
con elementos de otros tipos. Existen dos formas
de tipos compuestos: ARRAYS y RECORDS.
Un ARRAY es un objeto de datos que consiste
en una “colección” de elementos del mismo tipo.
Los arreglos pueden ser de una o más
dimensiones. Los elementos individuales de un
arreglo pueden ser utilizados especificando un
valor dentro del arreglo. Elementos múltiples de
un arreglo pueden ser utilizados especificando
más valores.
Un RECORD es un objeto de datos que
consiste en una “colección” de elementos de
diferentes tipos. La estructura RECORD en
VHDL es análoga a los RECORDS utilizados en
Pascal o a las estructuras en C. Los campos
individuales de un RECORD pueden ser
utilizados usando los nombres de los elementos.
También se puede utilizar más de un campo.
EJEMPLOS
Las siguientes líneas corresponden a la
declaraciones de un tipo ARRAY.
TYPE word IS ARRAY (0 TO 15) OF std_logic;
TYPE matriz IS ARRAY (0 TO 13, 0 TO 18) OF
TYPE valores IS ARRAY (0 TO 127) OF
A continuación se muestra como declarar
objetos de datos utilizando estos tipos.
SIGNAL mensaje1, mensaje2: word;
SIGNAL arreglo_matriz: matriz;
std_logic;
integer;
VARIABLE valor_actual: valores;
Algunas posibles maneras de asignar valores a
elementos de estos objetos son:
mensaje1(0) <= '1'; -- asignación de valor
-- al elemento '0' de
-- mensaje1
mensaje(5) <= '0'; -- asignación de valor
-- al quinto elemento de
-- mensaje1
mensaje2 <= mensaje1; -- hace mensaje1
-- igual a mensaje2,
-- esto es permitido
-- ya que se trata de
-- dos objetos de datos
-- del mismo tipo
mensaje2 (63) <= arreglo_matriz (5, 13);
-- transfiere el valor
-- de un elemento de
-- arreglo_matriz a un
-- elemento de mensaje2,
-- noté que ambos son
-- arreglos del tipo
-- std_logic_vector
A continuación se muestra un ejemplo de una
declaración del tipo RECORD.
TYPE operacion IS (add, sub, mul, div);
TYPE instruccion IS RECORD
operador: operacion;
op1: integer;
op2: integer;
ENDRECORD;
Aquí está la declaración de dos objetos usando
la declaración del tipo RECORD anterior.
VARIABLE inst1, inst2: instruccion;
A continuación se muestran algunas posibles
maneras de asignar valores a elementos de estos
objetos de datos.
inst1.operador := add; -- asigna un valor
-- a "operador"del
-- RECORD inst1
inst2.operador := sub; -- asigna un valor
-- a "operador" de
-- inst2
inst1.op1 := inst2.op2;
IEC FRANCISCO JAVIER TORRES VALLE
26
CAPÍTULO III: SINTAXIS DEL LENGUAJE
inst2 := inst1;
ARREGLOS RESTRINGIDOS
Un arreglo restringido (Constrained Array) es
aquel que está explícitamente definido mediante
rango entero especifico de un tipo de datos ya
existente. Cuando se declara un objeto de datos
con arreglo restringido, el objeto posee el mismo
rango.
E
JEMPLO:
TYPE byte IS ARRAY (7 DOWNTO 0) OF bit;
-- Este es un arreglo restringido cuyo
-- rango es: (7, 6, 5, 4, 3, 2, 1, 0)
ARREGLOS INDEFINIDOS
Un arreglo indefinido o sin restricciones
(Unconstrained Array) es aquel que no está
delimitado mediante un rango entero especifico.
Un objeto de datos declarado con arreglo
indefinido deberá ser delimitado o de lo contrario
no podrá ser sintetizado.
E
JEMPLO
TYPE bit_vector IS ARRAY
VARIABLE v: bit_vector(5 DOWNTO -5);
(integer RANGE <>) OF bit;
A continuación se exponen algunos tipos
compuestos comúnmente utilizados en síntesis de
circuitos utilizando VHDL.
BIT_VECTOR
Los valores asignados al tipo bit_vector deben
ser especificados con comillas dobles (" ") y los
valores asignados al tipo bit simple son asignados
con comillas simples (' '). El prefijo 'X' o 'x'
denota un valor hexadecimal; los prefijos 'O' y 'o'
denotan un valor octal; el prefijo 'B' o 'b' denota
un valor binario. Si ningún prefijo es
especificado, se asume el prefijo binario. Las
asignaciones en hexadecimal y octal deben usarse
únicamente si el valor puede combinarse
directamente con el tamaño del vector. Por
ejemplo, sí 'a' es un bit_vector ( 0 TO 6 ),
entonces la asignación a <= x"B", no podrá
hacerse porque el numero hexadecimal 'B' usa
cuatro de bits y no equipara el tamaño del vector
al que está siendo asignado.
El tipo std_logic_vector al igual que el
bit_vector es simplemente un arreglo de
elementos del tipo std_logic. La forma de
utilizarlo es similar a la del bit_vector.
S
IGNED & UNSIGNED
El estándar 1076.3 de la IEEE es un paquete
para VHDL en el cual se definen nuevos tipos de
datos además de funciones aritméticas y lógicas
para ser utilizadas por herramientas de síntesis.
Éste define dos paquetes: el numeric_std y el
numeric_bit en los que se define dos nuevos tipos
de datos: signed y unsigned. Estos tipos son
parecidos a los tipos std_logic_vector o bit_vector
y son parte de una norma emergente (IEEE
1076.3) para desempeñar operaciones numéricas
sobre señales vectorizadas. El paquete
numeric_bit define a estos tipos (unsigned y
signed) como un vector cuyos elementos son del
tipo bit y el paquete numeric_std define los
mismos pero con elementos del tipo std_logic.
El propósito de estos dos tipos es el de
representar números enteros positivos y negativos
en forma binaria. Para ambos tipos, el bit más
significativo está a la izquierda. El tipo signed se
utiliza para representar un número entero con
signo en forma binaria con complemento a dos, y
el unsigned es solamente un número entero sin
signo en forma binaria. El paquete numeric_std
define funciones y operadores aritméticos,
relacionales, lógicos y de asignación para ser
utilizados con estos tipos de datos. Signed,
unsigned y std_logic_vector son tipos diferentes
por lo que no se pueden mezclar. Sin embargo,
varias funciones de conversión, tales como
to_unsigned, son definidas para la conversión
entre los tipos.
E
JEMPLOS
x1 <= "0001";
IEC FRANCISCO JAVIER TORRES VALLE
27
CAPÍTULO III: SINTAXIS DEL LENGUAJE
3.4.3 SUBTIPOS
Un subtipo es un “subgrupo” de un tipo
predefinido. Los subtipos son útiles para crear
tipos de datos con limitaciones sobre tipos
mayores.
ECLARACIÓN DE SUBTIPOS
D
SUBTYPE identif IS tipobase RANGE <rango>;
EJEMPLOS
SUBTYPE byte IS bit_vector (7 DOWNTO 0);
SUBTYPE digito IS integer RANGE (0 TO 9);
Estos ejemplos definen dos subtipos llamados
byte y digito. Las señales o variables que son
declaradas como byte son del tipo
std_logic_vector de 8 bits en orden descendente.
Las señales o variables que sean declaradas como
tipo digito serán del tipo entero, consistiendo de
los posibles valores de los enteros del 0 al 9,
inclusive.
En el siguiente ejemplo se muestra como se
pueden crear subtipos de datos a partir de aquellos
tipos que sean definidos por el usuario.
EJEMPLOS
TYPE arith IS (add, sub, mul, div);
SUBTYPE add IS arith RANGE add TO sub;
SUBTYPE mul IS arith RANGE mul TO div;
Los únicos subtipos predefinidos son el natural
y el positive.
paquete STANDAR, que es utilizado por la
mayoría de las herramientas de síntesis, no es
utilizado por completo. A continuación se
muestra una parte del paquete STANDAR donde
se encuentran los tipos y subtipos predefinidos
más utilizados.
PACKAGE standard IS
TYPE boolean IS (FALSE, TRUE);
TYPE bit IS ('0', '1');
TYPE character IS (
Dentro del estándar VHDL de la IEEE se
describen dos paquetes en los que se especifica el
conjunto de tipos de datos y operaciones en las
que dichos tipos de datos pueden ser utilizados,
estos paquetes son: STANDARD y TEXTIO.
El paquete STANDAR de tipos de datos esta
incluido en todos archivos fuente de VHDL, es
decir, que no es necesario declararlo dentro de
código para poder utilizarlo. El paquete TEXTIO
define tipos de datos y operaciones para estos
tipos para la comunicación con el software de
síntesis que se este utilizando. Este no es
necesario para la síntesis de circuitos y algunos
programas de síntesis no lo soportan. De hecho, el
IEC FRANCISCO JAVIER TORRES VALLE
Algunos tipos no son muy utilizados aunque
existen dentro del lenguaje, como el characer o el
string, y hay otros que no son soportados por las
herramientas de síntesis. Los tipos no soportados
son ignorados y por lo tanto no pueden ser
sintetizados. Cada herramienta de síntesis define
cuales son los tipos, objetos o estructuras de
lenguaje que son o no soportados por la misma, a
continuación se muestran lo tipos y objetos no
soportados por el FOUNDATION.
- Tipos físicos
- Tipos reales o flotantes.
- Objetos de datos ACCESS. Un ACCESS
equivale a un apuntador y no es soportado por que
no tiene ningún sentido en hardware.
28
CAPÍTULO III: SINTAXIS DEL LENGUAJE
- Objetos de datos FILE. Estos se utilizan para
almacenar datos en RAM o ROM de la
computadora.
IEC FRANCISCO JAVIER TORRES VALLE
29
CAPÍTULO III: SINTAXIS DEL LENGUAJE
3.5 OPERADORES
Un operador nos permite construir diferentes
tipos de expresiones mediante los cuales podemos
calcular datos utilizando los diferentes objetos de
datos con el tipo de dato que maneja dicho objeto.
En VHDL existen distintos operadores de
asignación con lo que se transfieren valores de un
objeto de datos a otro, y operadores de asociación
que relacionan un objeto de datos con otro, lo cual
no existe en ningún lenguaje de programación de
alto nivel.
El uso de los operadores que aquí son
expuestos dependerá del software utilizado, ya
que no es regla que los utilicen todos. Para
conocer las operaciones que pueden ser utilizadas
así como los paquetes incluidos en el software, es
recomendable revisar las librerías del programa.
De no encontrarse algún operador especial para
ser utilizado con algún tipo de dato especifico, es
necesario sobrecargar los operadores o en
ocasiones crearlo. Como sobrecargar operadores y
como crear funciones se expone dentro del tema
de subprogramas. Para poder utilizar la mayoría
de estos operadores con los tipos signed, unsigned
y std_logic_vector, basta con utilizar el paquete
donde se encuentran declarados estos tipos,
porque dentro de los mismos paquetes ya se
encuentran sobrecargada varias funciones
aritméticas y lógicas para que sean utilizadas con
estos tipos, en temas posteriores se incluyen las
funciones que se encuentran en los paquetes
std_logic_1164, numeric_std y numeric_bit.
Los operadores lógicos AND, OR, NAND,
NOR XOR, XNOR, y NOT están definidos para
ser usados con los tipos bit y boolean. Para
utilizar estos operadores, excepto el operador
NOT, los operandos deben ser del mismo tamaño.
XNOR, NOT
Los operadores lógicos no tiene orden de
precedencia por lo que para expresiones en las
que se utilice más de un operador lógico es
necesario indicar mediante paréntesis cual es el
orden en que se debe realizar el cálculo.
EJEMPLOS
x <= y AND z OR w
-- esta forma de utilizar los
-- op. lógicos, es incorrecta y
-- producirá un error cuando sea
-- compilado el código
x <= y AND ( z OR w )
-- forma correcta de utilizar los
-- op.lógicos
3.5.2 OPERADORES DE COMPARACIÓN
Estos tipos de operadores se utilizan para
ejecutar pruebas de igualdad, desigualdad, o de
magnitud entre dos objetos de datos. Los
operandos que participen en la prueba deben ser
del mismo tipo y el resultado de la operación es
del tipo boolean. Los operadores de igualdad y
desigualdad (= y /=) pueden ser utilizados para
todos los tipos de datos predefinidos en el
lenguaje Los operadores de magnitud (“<” menor
que, “>” mayor que, “<=” menor o igual que, y
“>=” mayor o igual que) están definidos para ser
utilizados con tipos escalares.
EJEMPLO
SIGNAL x, y: bit_vector ( 3 DOWNTO 0)
SIGNAL z : bit;
z <= '1' WHEN x >= z ELSE '0';
3.5.3 OPERADORES DE ADICIÓN
Los operadores + y - son frecuentemente
utilizados para describir sumas y restas además de
signos positivo y negativo. Están definidos para
ser utilizados con el tipo entero. El operador “&”
permite concatenar cadenas de bits obteniendo
una de mayor tamaño. Los tres operadores tienen
la misma precedencia, por lo que para
instrucciones en la que se utiliza más de un
operador de este tipo es recomendable indicar
mediante paréntesis el orden de las operaciones.
IEC FRANCISCO JAVIER TORRES VALLE
30
CAPÍTULO III: SINTAXIS DEL LENGUAJE
Para poder realizar operaciones de suma o resta
entre un entero y un objeto de datos que
represente una cadena de bits, lo mejor es declarar
este objeto de datos como signed o unsigned e
incluir el paquete numeric_std o el numeric_bit,
ya que en estos se sobrecargaron los operadores
“+” y “-” para que pudieran ser utilizados de esta
manera. De lo contrario resultaría en un error de
compilación al realizar dichas operaciones. Por
otra parte no es posible realizar sumas entre
bit_vectors de diferente tamaño, y tampoco
podremos asignar el resultado de una suma o resta
entre dos bit_vectors a un bit_vector de diferente
longitud. Si se desea obtener el acarreo de la suma
del resultado de una operación aritmética entre
dos bit_vectors de la misma longitud, a un
bit_vector que sea de mayor longitud en un bit, se
permite utilizar el operador de concatenación para
incrementar el tamaño solamente en el primer
bit_vector que participa en la operación, con lo
cual se indica que deseamos obtener el acarreo de
la suma.
EJEMPLOS
SIGNAL conteo: integer RANGE 0 TO 255;
SIGNAL x, y, z: signed( 7 downto 0);
SIGNAL r, m: signed( 8 downto 0);
conteo <= conteo + 1;
x <= y + z + 5;
r <= '0'z + x; -- de esta manera se
-- obtiene el acarreo de
-- la suma
m <= r +1;
3.5.4 OPERADORES DE MULTIPLICACIÓN
Son los operandos “*” y el “/” que se utilizan
para la multiplicación y para la división
respectivamente. Los dos operandos tienen el
mismo orden de precedencia al igual que los
operandos MOD y REM.
Todos los operandos de multiplicación están
definidos para ser utilizados con operandos del
mismo tipo, siendo estos del tipo entero o
bit_vector. El resultado es entonces del mismo
tipo que los operandos por lo que también el
objeto de datos que recibe el resultado de la
operación deberá ser del mismo tipo que los
operandos.
La operación REM se define como se muestra
a continuación:
A REM B = A-(A/B)*B
La división es entera, por lo que los operandos
deben ser del tipo entero. El resultado toma el
signo de A. MOD calcula el módulo de dos
números. Se define como:
A MOD B = A-B*N
Donde N es un entero. El resultado toma el
signo de B.
3.5.5 OPERADORES MISCELÁNEOS
En esta categoría se encuentran los operadores
“abs” y “**”. El operador “abs” devuelve el valor
absoluto de un operando del tipo entero. El
operador ** se utiliza para elevar el primer
operador a una potencia definida por el segundo
operando, ambos deben ser del tipo entero.
EJEMPLO
CONSTANT r: integer := 2;
VARIABLE i: integer;
FOR n IN 0 TO 5 LOOP
i := i + r**n;
END LOOP;
3.5.6 OPERADORES DE ASIGNACIÓN
En VHDL existen dos tipos de operadores de
asignación los cuales son: "<=" y ":=". El
operador ":=" se utiliza para asignar un valor
inicial a constantes, variables y señales en el
momento de la declaración, pero para el resto de
la descripción únicamente utilizaremos ":=" para
ser usado con variables y "<=" para ser usado con
señales.
ASIGNACIÓN A VARIABLES
nombre_variable := expresión;
ASIGNACIÓN A SEÑALES
nombre_señal <= expresión;
Las asignaciones a variables solamente pueden
ocurrir dentro de los procesos o subrutinas, las
asignaciones a señales pueden ocurrir en
cualquier lugar dentro de la descripción.
IEC FRANCISCO JAVIER TORRES VALLE
31
CAPÍTULO III: SINTAXIS DEL LENGUAJE
Para realizar asignaciones a objetos de datos de
tipos compuesto, se pueden realizar utilizando
agregados. Los agregados son una lista de varios
valores encerrados entre paréntesis y separados
mediante comas de tal forma que el primer
elemento de la lista es asignado al primer
elemento del objeto, el segundo elemento de la
lista es asignado al segundo elemento del objeto
de datos etc. Así mediante una sola instrucción se
asignan varios valores al objeto de datos.
EJEMPLOS
TYPE op IS (suma, resta, mult, div);
TYPE reg_datos IS RECORD
operador: op;
x: integer;
y: bit;
END RECORD;
. . .
VARIABLE registro: reg_datos;
SIGNAL vec1, vec2: bit_vector(0 TO 3);
. . .
vec1 <= ('0', '1', '1', '0');
-- asignación mediante agregados
vec2 <= vec1;
-- también esta es una asignación
-- mediante agregados
registro := ( resta, 13, '1' );
-- asignación a variable del tipo
-- record mediante agregados
vec2 <= ( '1', OTHERS => '0' );
-- en esta asignación se hace '1'
-- el elemento 0 de vector2 y el resto
-- se hacen cero
3.5.7 OPERADORES DE ASOCIACIÓN
En diseños jerárquicos generalmente se hace
uso de varios componentes, los cuales son
entidades que realizan ciertas funciones
especificas. Para poder especificar las conexiones
de puertos entre dichos componentes y con los
puertos de la entidad principal es necesario
utilizar el operador de asociación "=>". El orden
con el que se asocian dichas conexiones depende
del orden en el que fueron declarados los puertos
del componente, además, deben ser del mismo
tipo y del mismo modo. Diseños jerárquicos y
componentes se explicaran detalladamente en
temas posteriores. A continuación se muestra un
ejemplo de cómo utilizar este operador de
asociación.
EJEMPLO
LIBRARY mi_libreria;
USE mi_libreria.sumadores.ALL;
ENTITY sumador IS
PORT ( ci: IN bit;
x: IN bit_vector(3 DOWNTO 0);
y: IN bit_vector(3 DOWNTO 0);
z: OUT bit_vector(3 DOWNTO 0);
co: OUT bit);
END sumador;
ARCHITECTURE a_sumador OF sumador IS
SIGNAL carry1: bit;
SIGNAL carry2: bit;
SIGNAL carry3: bit;
El componente “add” esta declarado dentro del
paquete “sumadores” de la librería “mi_libreria”,
y esta declarado de la siguiente manera.
------------------------------------------
-- SUMADORES
------------------------------------------
-- paquete compilado en la librería
-- "mi_librería"
PACKAGE sumadores IS
· · ·
COMPONENT add
PORT ( ci: IN bit;
x0: IN bit;
y0: IN bit;
z0: OUT bit;
co: OUT bit );
END COMPONENT;
· · ·
END PACKAGE;
Observe como los puertos de la entidad
“sumador”y las conexiones entre los bloques u0,
u1, u2 y u3, se hicieron de acuerdo al orden en
que los puertos están declarados en el
componente. En el bloque u0 primero se hace la
conexión del puerto "ci" del componente con el
puerto “ci”de la entidad mediante le operador de
IEC FRANCISCO JAVIER TORRES VALLE
32
CAPÍTULO III: SINTAXIS DEL LENGUAJE
asociación "=>", después se hace la conexión del
puerto x0 del componente con el elemento 0
(LSB) del vector x de la entidad, y así
sucesivamente hasta realizar todas las conexiones
del componente “add”utilizado en el bloque u0.
Lo mismo se hace con el bloque u1. En los
bloques u2 y u3, las conexiones se realizaron con
una notación equivalente pero simplificada. Los
nombres no tienen que ser necesariamente los
mismos e inclusive pueden ser diferentes, ya que
cada puerto es un objeto de datos local para la
entidad en la que fue declarado. Es importante
mencionar que dentro del paquete “sumadores” se
encuentra la entidad y la arquitectura
correspondiente al componente “add”, en los que
se describe el mismo.
3.5.8 OPERADORES DE CORRIMIENTO
Incluidos en los paquetes numeric_std y
numeric_bit, estos operadores realizan
operaciones de desplazamiento o de rotación con
los elementos de un vector del tipo signed o
unsigned.
DESPLAZAMIENTOS LÓGICOS SLL Y SRL
Desplazan los bits de un vector n veces a la
izquierda (SLL) o a la derecha (SRL),
introduciendo ceros en los lugares que quedan
libres.
EJEMPLO
x SRL 3 -- desplaza 3 lugares a la
-- derecha los bits del vector "x"
DESPLAZAMIENTOS ARITMÉTICOS SLA Y SRA
También desplazan los bits de un vector n
veces a la izquierda (SLA) o a la derecha (SRA),
introduciendo ceros en los lugares que quedan
libres, pero conservan el signo.
ROTACIONES ROL Y ROR
Se desplazan los bits de un vector n veces a la
izquierda (ROL) o a la derecha (ROR),
introduciendo los bits que son desplazados en los
lugares que van quedando libres.
ROL ROR
Figura 3.4 Instrucciones ROR y ROL
3.5.9 OPERACIONES CON VECTORES
Todas las herramientas de síntesis
proporcionan algún tipo de paquete en el que se
encuentre definidas funciones que facilitan la
descripción del diseño. Dentro de estos paquetes
se encuentran funciones que están hechas
específicamente para ser utilizadas con vectores y
como por lo general es preferible utilizar vectores
estos paquetes son de gran ayuda.
Synopsys desarrolló paquetes basados en el
paquete std_logic_1164, que son utilizados por
varias herramientas de síntesis existentes en el
mercado, como por ejemplo FOUNDATION de
Xilinx, Inc. y MAX+PLUS II de Altera
Corporation. Estos paquetes son:
- std_logic_arith
- std_logic_signed
- std_logic_unsigned
La compañía Actel también desarrolló su
propio paquete de síntesis:
- asyl.arith
Y los paquetes que fueron desarrollados por la
IEEE específicamente para síntesis de circuitos
digitales.
- numeric_bit
- numeric_std
Además del paquete que es el más utilizado por
la mayoría de los paquetes de síntesis.
- std_logic_1164
Todos estos paquetes son los más conocidos y
utilizados para síntesis de circuitos, por lo que
para poder utilizarlos primero debemos de incluir
la librería en que fueron compilados para
posteriormente hacer referencia al paquete que
deseamos utilizar (una librería puede tener más de
un paquete) como se muestra a continuación.
EJEMPLO
LYBRARY ieee; -- llamado a la librería
USE ieee.std_logic_1164.ALL; -- referencia
IEC FRANCISCO JAVIER TORRES VALLE
33
CAPÍTULO III: SINTAXIS DEL LENGUAJE
-- o carga del paquete
-- std_logic_1164
-- "ALL" es para
-- indicar que
-- deseamos utilizar
-- todos los tipos de
-- datos y funciones
-- incluidas en el
-- paquete
USE ieee.numeric_std.ALL; -- referencia
-- al paquete
-- numeric_std
3.6 ATRIBUTOS
Un atributo es una propiedad que es asociada a
señales, entidades o arquitecturas. Estos atributos
proporcionan información que nos puede ser útil
dentro de una descripción en VHDL. Los
atributos se utilizan mediante la comilla simple,
por ejemplo el atributo 'event, que probablemente
sea el más utilizado, nos permite detectar cuando
sucede una transición de estado en una señal, por
lo que es muy útil en descripciones de circuitos
secuenciales.
REFERENCIA A ATRIBUTOS
nombre_objeto'nombre_atributo
EJEMPLO
IF ( clk'event and clk = '1' ) THEN
A <= '1' ;
END IF;
En el ejemplo anterior se utiliza el atributo
'event, indicado en color verde, para detectar una
transición en la señal clk, y al mismo tiempo
comprobamos si esta transición fue positiva. Si
ambas condiciones se cumplen entonces se asigna
un '1' lógico a "A". El atributo 'event se utiliza
solo para señales de clk ya que de otra manera no
es posible sintetizar una transición en un
dispositivo lógico programable, por lo que
también debemos indicar que tipo de transición
estamos utilizando.
Existen más atributos y a continuación se
mencionan algunos que son útiles en
descripciones para síntesis.
A
TRIBUTOS PARA ARREGLOS
'left
Obtiene el valor que se encuentra a la
izquierda de un arreglo.
´right
Regresa el dato que se encuentra a la
derecha del arreglo.
´high
Permite obtener el mayor elemento de
un objeto de arreglo.
´low
Proporciona el valor más pequeño del
arreglo.
'lenght
Con este atributo se obtiene el número
de elementos de un arreglo.
Un arreglo es un objeto de datos que esta
compuesto por varios elementos de un tipo
sencillo, como lo son los bit_vector y
std_logic_vector.
ATRIBUTOS DE SEÑALES
'event
El atributo event es del tipo boolean y
retorna un valor verdadero cuando
ocurre una transición en la señal a la
que hace referencia.
EJEMPLOS
TYPE secuencia IS integer RANGE 0 TO 10;
SIGNAL conteo: secuencia;
Una entidad es la abstracción de un circuito, ya
sea desde un complejo sistema electrónico hasta
una simple compuerta lógica. La entidad
únicamente describe la forma externa del circuito,
aquí se enumeran las entradas y salidas del
diseño. Una entidad es análoga a un símbolo
esquemático de los diagramas electrónicos, el
cual describe las conexiones del dispositivo hacia
el resto del diseño.
IEC FRANCISCO JAVIER TORRES VALLE
34
CAPÍTULO III: SINTAXIS DEL LENGUAJE
DECLARACION DE ENTIDADES
ENTITY identificador IS
GENERIC ( cte_1: tipo := valor;
PORT ( puerto_1: modo tipo;
) ;
cte_2: tipo := valor;
· · ·
cte_n: tipo := valor
);
puerto_2: modo tipo;
· · ·
puerto_n: modo tipo
END identificador ;
Note que la ultima línea de declaración de
puerto o de genéricos no lleva punto y coma al
final de la línea.
EJEMPLO
En este ejemplo se realiza la entidad de un
multiplexor 4 a 1 que se muestra en la figura 3.5.
ENTITY mux_4_1 IS
PORT (a, b, c, d: IN bit;
mux_signal: IN
x: OUT bit );
END mux_4_1;
bit_vector(1 DOWNTO 0);
y: IN bit_vector(msb DOWNTO 0);
equals: OUT bit;
x_may_y: OUT bit;
x_men_y; OUT bit);
END comparador;
3.7.2 PUERTOS
Cada entrada y salida de la entidad se declara
dentro de la región puertos (PORT), en el
momento de la declaración se debe indicar el
modo y tipo del puerto. Los puertos los podemos
asociar con los pines de un símbolo esquemático
y, al igual que estos, algunos son únicamente
entradas, otros salidas, o incluso bidirecionales.
Un puerto es implícitamente un objeto de datos
del tipo señal porque representa conexiones en el
diseño, y puede ser utilizado en expresiones de
programación dentro de la arquitectura que
describe a dicha entidad. Cada puerto debe tener
un nombre, un modo y se debe especificar el tipo
de dato mediante el cual manipularemos dicho
puerto en la descripción.
3.7.3 MODOS
El modo indica la forma en que los datos
fluyen a través del circuito. Estos pueden ser de
uno de cuatro tipos:
Figura 3.5 Multiplexor de 4 bits a 1
3.7.1 GENÉRICOS
Esta instrucción es opcional y se utiliza para
declarar propiedades y constantes del circuito.
Estas constantes se utilizan al igual que las que se
declaran por el usuario, por lo que nos permiten
modelar circuitos en los que se pueden cambiar
propiedades, tamaños de los buses de entrada o
salida del circuito. Se utilizan generalmente en
paquetes.
EJEMPLO
ENTITY comparador IS
GENERIC(msb: integer := 3);
PORT( x: IN bit_vector(msb DOWNTO 0);
IEC FRANCISCO JAVIER TORRES VALLE
- IN
- OUT
- INOUT
- BUFFER
Si no se indica ningún modo en la declaración,
se asume que es del tipo IN. Un puerto del modo
IN describe un pin del circuito que únicamente
puede ser utilizado como entrada por lo que
solamente podremos leer datos de dicho puerto y
nunca escribir sobre él. Por el contrario, un puerto
que sea declarado del modo OUT podrá ser
utilizado para escribir datos pero no para ser
leído, este representa un pin que únicamente es
salida del circuito y que en él no existe ningún
tipo de retroalimentación hacia dentro del diseño.
Un puerto INOUT indica aquellos puertos que
son pueden ser utilizados bidireccionalmente
mientras que un puerto del modo BUFFER es
utilizado para salidas que tienen retroalimentación
interna. La diferencia entre el modo BUFFER y el
INOUT, es que el INOUT es retroalimentado
desde el pin de salida del circuito, en tanto que
35
CAPÍTULO III: SINTAXIS DEL LENGUAJE
como un puerto del modo BUFFER lo hace
internamente no puede ser usado como
bidireccional.
Figura 36 Modos de direccionamiento para
puertos
IEC FRANCISCO JAVIER TORRES VALLE
36
CAPÍTULO III: SINTAXIS DEL LENGUAJE
3.8 ARQUITECTURAS
Los pares de entidades y arquitecturas se
utilizan para representar la descripción completa
de un diseño. Una arquitectura, describe el
funcionamiento de la entidad a la que hace
referencia. Si una entidad la asociamos con una
"caja" en la que se enumeran las interfaces de
conexión hacia el exterior, entonces la
arquitectura representa la estructura interna de esa
caja. Por ejemplo, el símbolo esquemático de un
74LS04 representaría la entidad del diseño, y la
forma en que las compuertas son conectadas
internamente corresponden a la arquitectura del
circuito, y así ambos describen completamente el
circuito.
Figura 3.7 Entidad, Símbolo Esquemático
EJEMPLO
ENTITY mux_4_1 IS
PORT ( a, b, c, d: IN bit;
mux_signal: IN
x: OUT bit );
END mux_4_1;
ARCHITECTURE a_mux_4_1 OF mux_4_1 IS
BEGIN
x <= a WHEN mux_signal = "00" ELSE
b WHEN mux_signal = "01" ELSE
c WHEN mux_signal = "10" ELSE
d WHEN mux_signal = "11";
END a_mux_4_1;
bit_vector(1 DOWNTO 0);
Una arquitectura describe el comportamiento,
estructura o flujo de datos de la entidad a la que
hace referencia. Una entidad puede tener más de
una arquitectura, pero cuando se compile se
indica cual es la arquitectura que queremos
utilizar. Para describir el funcionamiento de la
entidad se puede hacer uso de cualquiera de los
tres estilos siguientes:
- Descripción de Flujo de Datos
- Descripción Comportamental
Figura 3.8 Arquitectura, Estructura Interna
DECLARACIÓN DE ARQUITECTURA
ARCHITECTURE identificador OF entidad IS
-- declaraciones de la arquitectura
BEGIN
-- Código de Descripción
-- instrucciones concurrentes
-- ecuaciones booleanas
-- PROCESS
-- instrucciones secuenciales
END identificador_arquitectura;
Antes del BEGIN se escriben todas las
declaraciones que se necesiten dentro de la
descripción, tales como: señales, constantes,
funciones, alias, componentes, tipos de datos etc.
Después del BEGIN es donde se realiza todo el
código de descripción del circuito.
- Descripción Estructural
Los tres estilos son diferentes, pero esto no
significa que se tenga que utilizar únicamente un
estilo. De hecho lo mejor es tratar de utilizar los
tres como mejor nos convenga. En el siguiente
tema se explica el estilo de descripción de flujo de
datos, así como el tipo de instrucciones que
participan en este estilo.
3.9 DESCRIPCIONES DE FLUJO
DE DATOS
Una descripción de flujo de datos consiste en
especificar como los datos son transferidos de las
entradas a las salidas. Cabe mencionar que
algunos autores distinguen las descripciones de
flujo de datos de las comportamentales, en tanto
que para otros ambos estilos son del tipo
comportamental. La principal diferencia entre
estas es el tipo de instrucciones que utilizan,
además que en un estilo comportamental se utiliza
el bloque PROCESS en tanto que en el estilo en
cuestión no se utiliza.
IEC FRANCISCO JAVIER TORRES VALLE
37
CAPÍTULO III: SINTAXIS DEL LENGUAJE
En este estilo de descripción se utilizan
únicamente asignaciones mediante expresiones en
las que se indica como cambian los puertos de
salida en función de los puertos de entrada, ya
sean asignaciones condicionales mediante
instrucciones concurrentes o simples ecuaciones.
Un ejemplo de descripción de flujo de datos es el
comprador utilizado en el primer tema de este
capítulo, en éste los datos son los que indican la
forma en que cambian las salidas y por esto se le
llama de flujo de datos.
3.9.1 INSTRUCCIONES CONCURRENTES
En lenguajes de programación como C o
Pascal, cada instrucción de asignación es
ejecutada una después de otra en un orden
especifico. El orden en el que las instrucciones
son ejecutadas es determinado por el orden de las
instrucciones en el archivo. Dentro de una
arquitectura en VHDL, no existe un orden
especifico de ejecución de las asignaciones. El
orden en el que las instrucciones son ejecutadas
depende de los eventos ocurridos en las señales,
similar al funcionamiento de un circuito.
En VHDL todos los bloques son concurrentes,
es decir que se están ejecutando en todo
momento. Después se explicará el bloque
PROCESS, el cual está compuesto por una serie
de instrucciones que sí se ejecutan en el orden en
el que fueron especificadas. Las instrucciones
concurrentes se utilizan fuera de un bloque
PROCESS, a diferencia de las instrucciones
secuenciales que únicamente se utilizan dentro del
bloque concurrente PROCESS y en
subprogramas.
3.9.2 ESTRUCTURAS DE EJECUCIÓN
CONCURRENTE
• ASIGNACIÓN CONDICIONAL WHEN... ELSE
S
INTAXIS
signal_name <= valor_a WHEN condición ELSE
valor_b WHEN condición ELSE
valor_c WHEN condición ELSE
valor_d WHEN condición ELSE
· · ·
valor_n WHEN condición ELSE
otro_valor;
EJEMPLO
gray <= "00" WHEN binario = x"0" ELSE
"01" WHEN binario = x"1" ELSE
"11" WHEN binario = x"2" ELSE
"10";
• ASIGNACIÓN WHIT... SELECT... WHEN
S
INTAXIS
WITH identificador SELECT
signal_name1 <= expresión WHEN valor1,
valor_a WHEN valor2,
valor_b WHEN valor3,
· · ·
valor_n WHEN OTHERS ;
EJEMPLO
WITH states SELECT
salida <= "000" WHEN state0,
"001" WHEN state1,
"010" WHEN state2,
"100" WHEN state3,
"000" WHENOTHERS;
No olvidar la coma al final de cada línea,
excepto en la ultima que lleva punto y coma.
ECUACIONES BOOLEANAS
•
signal_name <= ecuación_booleana;
EJEMPLOS
x <= y AND z;
a <= ( b OR c OR d ) AND e ;
-- cuando se utilice más de un operador
-- lógico es necesario utilizar paréntesis
op1 <= op2 NOR op3 NOR op4;
3.9.3 ALU
A continuación se muestra la tabla de
funcionamiento de una pequeña unidad aritmético
— lógica la cual consta de dos bits de entrada, un
bit de salida, acarreo de entrada y acarreo de
salida.
TABLA DE FUNCIONAMIENTO
ENTRADASSALIDAS
s1s0z co
IEC FRANCISCO JAVIER TORRES VALLE
38
CAPÍTULO III: SINTAXIS DEL LENGUAJE
0 0 x AND y 0
0 1 x OR y 0
1 0 x XOR y 0
1 1 x + y + ci acarreo de la suma
ÓDIGO DE DESCRIPCIÓN
C
LIBRARY ieee;
USE ieee.std_logic_1164.ALL;
USE ieee.numeric_std.ALL;
ENTITY alu IS
PORT ( x, y: IN std_logic;
END alu;
ARCHITECTURE a_alu OF alu IS
SIGNAL seleccion: unsigned(1 DOWNTO 0);
SIGNAL suma: std_logic;
SIGNAL and_op: std_logic;
SIGNAL or_op: std_logic;
SIGNAL xor_op: std_logic;
SIGNAL acarreo: std_logic;
BEGIN
and_op <= x AND y ;
WITH seleccion SELECT
seleccion <= s1 & s0;
suma <= x XOR y XOR ci;
or_op <= x OR y;
acarreo <= (x AND y) OR
xor_op <= x XOR y;
co <= acarreo WHEN seleccion = 3 ELSE
END a_alu;
s0, s1: IN std_logic;
ci: IN std_logic;
z: OUT std_logic;
co: OUT std_logic);
z <= or_op WHEN "01",
and_op WHEN "00",
suma WHEN "11",
xor_op WHEN "10",
'0' WHENOTHERS;
(x AND ci) OR
(y AND ci);
'0' ;
Este circuito se sintetizo en un GAL22V10
utilizando WARP 5.0 de Cypress
Semiconductors. Obsérvese que en el código de
descripción de esta alu no existe ningún orden en
las ecuaciones, asignaciones o instrucciones, de
hecho el orden en el que se coloquen las
instrucciones no importa dentro de una
descripción, recordemos que VHDL describe
circuitos y por lo tanto todas las asignaciones
(conexiones) siempre están funcionando al igual
que todos los dispositivos dentro de un circuito.
Las señales suma, acarreo, and_op, or_op y
xor_op son las salidas de varios bloques del
circuito, cada uno con una función distinta. El bus
"seleccion" se compone de los dos bits de entrada
s0 y s1, estas se juntan en este bus únicamente
para facilitarnos la descripción. Y mediante los
bloques de la instrucción WITH... SELECT...
WHEN y la instrucción WHEN... ELSE se
asignan los datos correspondientes a cada salida
de a cuerdo a las combinaciones de los bits s0 y
s1.
Figura 3.9 Diagrama a bloques de la ALU
El que hayamos realizado la descripción con
tantos bloques no significa necesariamente que
cuando el compilador sintetice el código respete
todos esos bloques y quede exactamente como lo
describimos dentro del dispositivo que
seleccionamos. El compilador de WARP
interpreta nuestra descripción y la sintetiza dentro
del dispositivo utilizando el mínimo de
compuertas posible al mismo tiempo que trata de
respetar la descripción del código, además, que
por lo general trata de evitar retroalimentaciones
IEC FRANCISCO JAVIER TORRES VALLE
39
CAPÍTULO III: SINTAXIS DEL LENGUAJE
para que el dispositivo funcione a altas
velocidades. De hecho en ocasiones es posible
que existan todavía macroceldas libres, pero
como el compilador evita retroalimentaciones,
entonces no las usa. Como indicar que se usen
esas macroceldas libres se explicará
posteriormente, ya que este circuito sí puede
quedar dentro de un GAL16V8 utilizando
directivas de síntesis. A continuación se muestran
las ecuaciones, la asignación de pines y el
informe de utilización del dispositivo obtenidos
por el compilador de WARP.
------------------------------------------
ECUACIONES
------------------------------------------
PLD Compiler Software: MAX2JED.EXE
02/APR/1999 [v4.02 ] 5.2 IR 17
PLD Compiler Software: PLA2JED.EXE
02/APR/1999 [v4.02 ] 5.2 IR 17
PINOUT INFORMATION (06:15:24)
Messages:
Information: Checking for duplicate NODE
logic.
None.
IEC FRANCISCO JAVIER TORRES VALLE
Information: Output Logic Product Term
Utilization.
Completed Successfully
------------------------------------------
40
CAPÍTULO III: SINTAXIS DEL LENGUAJE
3.10 DESCRIPCIONES
COMPORTAMENTALES
Las descripciones comportamentales son
similares a un lenguaje de programación de alto
nivel, por su alto nivel de abstracción. Mas que
especificar la estructura o la forma en que se
deben conectar los componentes de un diseño, nos
limitamos a describir su comportamiento. Una
descripción comportamental consiste de una serie
de instrucciones, que ejecutadas secuencialmente,
modelan el comportamiento del circuito. La
ventaja de una descripción comportamental es que
no necesitamos enfocarnos a un nivel de
compuerta para implementar un diseño. En
VHDL una descripción comportamental
necesariamente implica el uso de por lo menos un
bloque PROCESS.
3.10.1 INSTRUCCIONES SECUENCIALES
Las instrucciones secuenciales son aquellas que
son ejecutadas serialmente, una después de otra.
La mayoría de los lenguajes de programación,
como C o Pascal, utilizan este tipo de
instrucciones. En VHDL las instrucciones
secuenciales son implementadas únicamente
dentro del bloque PROCESS
3.10.2 PROCESOS
Un proceso es el bloque básico concurrente de
codificación secuencial. Contiene una serie de
instrucciones secuenciales que permiten modelar
el comportamiento del circuito, sin embargo, el
bloque PROCESS equivale a una sola instrucción
concurrente. Un proceso puede ser utilizado
dentro de cualquier arquitectura definiendo para si
mismo una región de declaraciones y otra para la
codificación secuencial, similar a una
arquitectura. La región de codificación puede
contener únicamente instrucciones secuenciales
(IF, CASE, FOR, etc.) en tanto que la región de
declaraciones permite designar constantes,
señales, tipos de datos o algún alias.
SINTAXIS
PROCESS ( lista sensible )
-- declaraciones
BEGIN
-- instrucciones secuenciales
END PROCESS;
La lista sensible define cuales señales provocan
que las instrucciones dentro del bloque comiencen
a ser ejecutadas. Los cambios en alguna de las
señales provocan que el proceso sea llamado. Un
proceso que no tenga lista sensible debe utilizar
una instrucción WAIT para especificar cuando
deben ser ejecutadas las instrucciones dentro del
bloque. La mayoría de las herramientas de síntesis
tienen problemas si las lista sensible no está
completamente especificada. Estas consideran
que mediante el proceso estamos modelando
lógica combinacional o secuencial. La lista
sensible es parcialmente declarada cuando alguna
de las señales que intervienen en lado derecho de
una ecuación o de alguna instrucción secuencial
no es mencionada dentro de la lista. El que la lista
no este completa generalmente produce que no
sea posible modelar totalmente la funcionalidad
del diseño y por lo tanto no es posible obtener las
ecuaciones durante el proceso de síntesis.
El funcionamiento del proceso es similar a un
microprocesador que funciona únicamente con
interrupciones. La señales dentro de la lista
sensible hacen a su vez de entradas de
interrupción y las instrucciones secuenciales se
encuentran dentro de una rutina única de servicio
de interrupción. Cuando alguna de las señales de
la lista sensible cambia, provoca que el proceso
comience a funcionar y a ejecutar toda esta rutina
de ejecución secuencial con la particularidad de
que los que resulte de este procesamiento se
asigne únicamente al final de la estructura. Por lo
que podemos manipular los valores de las señales
y esto no implica que cambien con cada
asignación sino solamente hasta que se termina de
ejecutar todo el proceso. Y como las asignaciones
a los nodos del circuito se hacen al final, entonces
todo la estructura del proceso es similar a un
dispositivo de ejecución secuencial, como un
microprocesador, que forma parte del diseño. Esta
comparación con un microprocesador no implica
que siempre debamos especificar una señal de
reloj para el funcionamiento de la estructura, o
que únicamente nos permita modelar circuitos
secuenciales. De hecho, si suponemos que la
frecuencia de trabajo de este "microprocesador"
es muy grande, entonces las instrucciones dentro
de la estructura se ejecutan tan rápido que
prácticamente lo podríamos considerar
combinacional. Si alguna señal de reloj es
especificada, entonces estamos limitando a que
IEC FRANCISCO JAVIER TORRES VALLE
41
CAPÍTULO III: SINTAXIS DEL LENGUAJE
las instrucciones dentro del proceso sean
ejecutadas únicamente dentro de alguna transición
de esta señal, lo cual no permite describir
circuitos secuenciales.
JEMPLO
E
A continuación se muestra el código de
descripción comportamental del comparador de la
figura 3.10.
ENTITY comparador IS
PORT( x: IN bit_vector(3 DOWNTO 0);
END comparador;
ARCHITECTURE comparador OF comparador IS
BEGIN
PROCESS(x, y)
BEGIN
END PROCESS;
END comparador;
y: IN bit_vector(3 DOWNTO 0);
equals: OUT bit;
x_may_y: OUT bit;
x_men_y: OUT bit);
equals <= '0';
x_may_y <= '0';
x_men_y <= '0';
IF x = y THEN
equals <= '1';
END IF;
IF x > y THEN
x_may_y <= '1',
END IF;
IF x < y THEN
x_men_y <= '1';
END IF;
Figura 3.10 Comparador
Este ejemplo corresponde al mismo comprador
utilizado en el tema 3.1.2. Se definen 2 vectores
de 4 bits y 3 salidas de 1 bit. Esta arquitectura
únicamente tiene una instrucción concurrente: el
bloque PROCESS, el cual es sensible a los
vectores de entrada. Siempre que ocurra un
cambio en alguno de estos, el proceso será
llamado y generará la lógica de salida. La lista
sensible está completa porque, si observamos, el
estado de las salidas depende únicamente de las
entradas.
Cada instrucción será ejecutada en orden
secuencial y cuando todas hallan sido ejecutadas,
entonces se asigna el valor procesado a los nodos
que se vieron afectados durante el proceso. Una
vez que se terminó de ejecutar el proceso, éste se
mantendrá inactivo hasta que alguno dos
elementos de la lista sensible cambie.
Cuando se utilicen procesos se debe tener
cuidado de no olvidar alguna combinación posible
de entradas y/o salidas retroalimentadas que tal
vez no estemos considerando o que no
necesitamos. En estos casos es recomendable
utilizar el tipo std_logic o, si son vectores, algún
tipo que se base en este. Los valores '-' y 'Z' del
std_logic son permitidos en síntesis siempre y
cuando se utilicen correctamente.
E
JEMPLO
ARCHITECTURE simplifica OF entidad_x IS
SIGNAL y_tmp:std_logic_vector(1 DOWNTO 0);
BEGIN
PROCESS(s)
BEGIN
IF (s = 0) OR (s = 3) THEN
-- s es un vector del tipo unsigned
y_tmp <= '1';
ELSIF s = 1 THEN
y_tmp <= '0';
ELSE
y_tmp <= '-';
END IF;
END PROCESS;
y <= y_tmp WHEN enable = '0' ELSE 'Z';
-- "y" y "y_tmp" son tipo std_logic
END simplifica;
En el ejemplo anterior únicamente nos
importan las combinaciones s = 3, s = 1, y s = 0.
En algunos programas de VHDL para síntesis, y
también dependiendo de la arquitectura del
dispositivo, la asignación de un "no importa" nos
va a permitir que se simplifique la ecuación de
y_tmp, quedando como:
y_tmp = s(1) +s(0)'
De no utilizarla posiblemente quede de la
siguiente forma:
y_tmp = s(0)'·s(1)' + s(0)·s(1)
IEC FRANCISCO JAVIER TORRES VALLE
42
CAPÍTULO III: SINTAXIS DEL LENGUAJE
3.10.3 DIFERENCIAS ENTRE SEÑALES Y
VARIABLES
Un objeto de datos del tipo señal es muy
diferente a uno del tipo variable. Ya se había
mencionado que las señales pueden ser
sintetizados en elementos lógicos y/o conexiones,
lo cual no es posible con un variable. Una señal
representa un nodo de conexión entre elementos
lógicos (compuertas, registros, buffers, etc.).
Inclusive un mismo nodo puede recibir más de un
nombre para facilitar la descripción, sin que esto
implique más términos en las ecuaciones de
salida. Una señal que se vea involucrada dentro
de un proceso no recibe inmediatamente el valor
asignado, sólo hasta el final del mismo. Una
variable que sea utilizada dentro de un proceso sí
recibe el valor de forma inmediata, por lo que son
muy útiles para poder obtener el estado de salida
deseado para alguna señal de salida. Una variable
funciona exactamente igual que cualquier variable
de cualquier lenguaje de programación de
software.
Podemos decir que una señal está formada por
dos partes: un valor actual y un valor futuro (o
valor en proceso). El valor futuro es el que se
calcula dentro del proceso y una vez que se
termina el proceso, los valores futuros de todas
las señales se convierten en valores actuales. Al
valor futuro se le conoce como driver. En VHDL
para síntesis el driver nunca es afectado fuera de
un proceso, fuera de éste siempre estamos
modificando el valor actual.
Otro detalle importante en VHDL para síntesis,
es que el valor actual de una señal no puede verse
modificado más de una vez dentro de la
arquitectura, porque las señales representan
conexiones y esto equivaldría a unir dos cables. Y
esto generalmente resultará en un error de
compilación durante el proceso de síntesis.
EJEMPLOS
ARCHITECTURE no_valida1 OF senial IS
BEGIN
z <= x AND y;
z <= x OR y;
END no_valida1;
ARCHITECTURE no_valida2 OF senial IS
BEGIN
PROCESS(x, y)
BEGIN
z <= x OR y; -- driver de z = x OR y
END PROCESS; -- finalizado el proceso,
-- valor actual de z = x OR y
z <= x AND y; -- ERROR, se vuelve a
-- modificar el valor actual de z
END no_valida2;
ARCHITECTURE valida1 OF senial IS
BEGIN
PROCESS(x, y)
BEGIN
z <= x AND y; -- driver de z = x AND y
z <= x OR y; -- se modifica el driver
-- de z, driver de z = x OR y
END PROCESS; -- finalizado el proceso,
-- valor actual de z = x OR y
ENDvalida1;
IEC FRANCISCO JAVIER TORRES VALLE
43
CAPÍTULO III: SINTAXIS DEL LENGUAJE
3.10.4 ESTRUCTURAS DE EJECUCIÓN
SECUENCIAL
• IF - THEN - ELSE
S
INTAXIS
IF condición THEN
· · ·
ELSIF condición THEN
· · ·
END IF;
EJEMPLO
SIGNAL conteo: unsigned(3 DOWNTO 0);
· · ·
IF conteo = X"9" THEN
conteo <= ( OTHERS => '0' ) ;
ELSE
conteo <= conteo + 1;
END IF;
ASE - WHEN
• C
CASE expresión IS
WHEN alternativa1 =>
· · ·
WHEN alternativa2 =>
· · ·
WHEN OTHERS =>
· · ·
END CASE;
EJEMPLO
TYPE estados IS (estado1, estado2,
SIGNAL estado_maquina: estados;
SIGNAL motor, alarma: bit;
CONSTANT encendido: bit := '1';
CONSTANT apagado: bit := '0';
· · ·
CASE estado_maquina IS
WHEN estado0 =>
motor <= apagado;
WHEN estado1=>
motor <= encendido;
WHEN (estado3 OR estado4) =>
alarma <= encendido;
WHEN OTHERS =>
motor <= apagado;
alarma <= apagado;
La instrucción WAIT es utilizada en procesos
que no tienen una lista sensible, ya que esta
instrucción define implícitamente la lista sensible
del proceso. A continuación se muestran las 3
formas de utilizar la instrucción WAIT.
WAIT ON -- espera los cambios de las
-- señales especificada
WAIT UNTIL -- espera a que se cumpla la
-- condición especificada
WAIT FOR -- detiene la simulación
-- durante el tiempo
-- especificado
La instrucción WAIT ON no es aceptada por la
mayoría de los herramientas de síntesis, WAIT
FOR solo se utiliza para simulaciones. La única
forma en que puede ser utilizada la instrucción
WAIT en síntesis sin tener problemas es
utilizándola como WAIT UNTIL.
EJEMPLO
PROCESS
BEGIN
WAIT UNTIL rising_edge( clk ) ;
-- la función rising_edge viene
-- incluida en el paquete
-- std_logic_1164 y
-- equivale a utilizar:
-- clk'event AND clk = '1'
IF reset = '1' THEN
IEC FRANCISCO JAVIER TORRES VALLE
44
CAPÍTULO III: SINTAXIS DEL LENGUAJE
y <= (OTHERS => '0');
ELSE
y <= y + 1;
END IF;
END PROCESS;
IEC FRANCISCO JAVIER TORRES VALLE
45
CAPÍTULO III: SINTAXIS DEL LENGUAJE
3.11 DESCRIPCIONES
ESTRUCTURALES
En el siguiente ejemplo se muestra el código
para una descripción estructural correspondiente
al circuito de la figura 3.11.
Figura 3.11 Descripciones Estructurales
LIBRARY mi_librería;
USE mi_libreria.compuertas.ALL;
ENTITY structural IS
PORT ( x, y: IN bit;
z: OUT bit);
END structural;
ARCHITECTURE estructural OF structural IS
SIGNAL nodo1: bit;
SIGNAL nodo2: bit;
SIGNAL nodo3: bit;
SIGNAL nodo4: bit;
SIGNAL nodo5: bit;
BEGIN
U1: not_gate PORT MAP(x, nodo1);
-- (entrada, salida)
U2: not_gate PORT MAP(y, nodo2) ;
-- (entrada, salida)
U3: and_gate PORT MAP(nodo1, y, nodo3);
-- (entrada, entrada, salida)
U4: and_gate PORT MAP(nodo3, nodo2,
nodo4 );
U5: and_gate PORT MAP(nodo2, x, nodo5);
U6: or_gate PORT MAP(nodo4, nodo5, z);
-- (entrada, entrada, salida)
END estructural;
Esta descripción utiliza entidades descritas y
compiladas previamente dentro del paquete
"compuertas" de la librería "mi_librería". Una
descripción estructural es similar a un netlist de
PSPICE. Se declaran los componentes que se
utilizan y después, mediante los nombres de los
nodos, se realizan las conexiones entre
compuertas.
Las descripciones estructurales son útiles
cuando se trata de diseños jerárquicos. Este
ejemplo pretende mostrar como son este tipo de
descripciones, aunque no es una aplicación
práctica utilizar este estilo con circuitos sencillos
como el anterior.
3.11.1 COMPONENTES
Un componente representa a una entidad
declarada en un diseño o librería, la utilización de
componentes es útil en diseños jerárquicos como
se mostró en el ejemplo anterior. Para poder
utilizar una entidad que está dentro de otro
diseño, es necesario llamar la librería y el paquete
dentro del cual se encuentra esta entidad.
DECLARACIÓN DE COMPONENTES
La declaración de componentes se realiza
dentro de paquetes o en la región declarativa de
una arquitectura. Es preferible declarar
componentes dentro de los paquetes ya que estos
son reutilizables, y por esta razón sólo se verán
declaración de componentes dentro de paquetes y
no en arquitecturas, aunque también sea posible.
A continuación se muestra la sintaxis de
declaración de componentes.
SINTAXIS
COMPONENT identificador
PORT( senial { , senial}: modo tipo;
senial { , senial}: modo tipo;
senial: { , senial}: modo tipo
);
END COMPONENT;
EJEMPLO
COMPONENT add
PORT ( a, b, ci: IN std_logic;
suma, co: OUT std_logic);
END COMPONENT;
DECLARACIÓN DE COMPONENTES CON
GENÉRICOS
COMPONENT identificador
GENERICS( generico{ , generico }:
[ modo ] tipo [ := valor ];
· · ·
generico{ , generico }:
[ modo ] tipo [ := valor ]
);
PORT( senial { , senial}: modo tipo;
IEC FRANCISCO JAVIER TORRES VALLE
46
CAPÍTULO III: SINTAXIS DEL LENGUAJE
· · ·
senial: { , senial}: modo tipo
);
END COMPONENT;
EJEMPLO
COMPONENT add_n
GENERICS(w: integer := 8);
PORT(a, b: IN bit_vector(w-1 DOWNTO 0);
ci: IN bit;
suma: OUT bit_vector(w-1 OWNTO 0 );
co: OUT std_logic
) ;
END COMPONENT;
3.11.2 INSTANCIACIÓN DE COMPONENTES
La instanciación de componentes es una
instrucción concurrente que especifica la
interconexión de las señales del componente
dentro del diseño en el que está siendo utilizado.
Existen dos formas de hacer la instanciación de
componentes: por asociación de identificadores o
asociación por posición.
ASOCIACIÓN POR IDENTIFICADORES
En este tipo de instanciación es necesario
utilizar el operador de asociación "=>" para
indicar como se conectan los puerto del
componente con lo puertos o señales de la
arquitectura en la que está siendo utilizado dicho
componente. Observe que en la asociación " a =>
b ", "a" pertenece al componente y "b" es una
señal, variable o incluso una ecuación booleana
en la que intervienen objetos de datos que
pertenecen de la arquitectura donde se usa el
componente.
En la asociación por posición no es necesario
nombrar los puertos del componente. Sólo se
colocan las señales, variables, o expresiones en el
lugar donde deseamos que sean conectadas. Es
importante considerar el orden en el que fueron
declarados los puertos del componente porque
este orden es el debemos utilizar cuando se haga
la instanciación del componente.
SIGNAL carry_in, carry_out: std_logic;
SIGNAL x, y, z: std_logic_vector(3
DOWNTO 0);
BEGIN
-- add_n es el componente de ejemplo en
-- "declaración de componentes con
-- genéricos"
u1: add_n GENERIC MAP(4);
END a_reg8;
PORT MAP(x, y, carry_in, z,
carry_out);
3.11.3 SENTENCIAS DE GENERACIÓN
Las sentencias de generación de componentes
permiten crear una o más copias de un conjunto
de interconexiones, lo cual facilita el diseño de
circuitos mediante descripciones estructurales.
• F
OR.. GENERATE
Esta instrucción genera un número finito de
conexiones o de instrucciones concurrentes
mediante rango discreto.
S
INTAXIS
etiqueta: FOR indice IN rango GENERATE
{ instucciones_concurrentes }
END GENERATE;
La etiqueta es necesaria y el índice de bucle es
una variable del tipo entero que no necesita ser
declarada anteriormente.
c(2*i + 1) <= a(i) NOR x;
c(2*i) <= b(i) NOR x;
END GENERATE;
Figura 3.12 For... Generate
El uso más común de las instrucciones de
generación es para crear múltiples copias de
componentes y procesos. En el siguiente ejemplo
se muestra como utilizar estas instrucciones con
componentes y en la figura 3.13 se muestra el
circuito resultante.
COMPONENT comp
PORT (x : IN bit;
y : OUT bit);
END COMPONENT;
· · ·
SIGNAL a, b: bit_vector(0 TO 7);
. . .
gen: FOR i IN a'RANGEGENERATE
u: comp PORT MAP (x => a(i),
JEMPLO
E
El siguiente ejemplo muestra como conectar
dos arreglos de cuatro bits un tercer arreglo de
ocho bits.
SIGNAL a, b : bit_vector(3 DOWNTO 0);
SIGNAL c : bit_vector(7 DOWNTO 0);
SIGNAL x : bit;
. . .
genera: FOR i IN 3 DOWNTO 0 GENERATE
IEC FRANCISCO JAVIER TORRES VALLE
y => b(i));
49
CAPÍTULO III: SINTAXIS DEL LENGUAJE
END GENERATE gen;
Figura 3.13 Instaniación de Componentes
utilizando la inst. For... Generate
• IF.. GENERATE
If... Generate realiza la instrucción de
instanciación o la instrucción concurrente sólo si
la condición de prueba es válida.
S
INTAXIS
etiqueta: IF condición GENERATE
{ instucciones_concurrentes }
END GENERATE;
El uso es similar a la instrucción secuencial
IF... THEN, la diferencia es que en esta no se
pueden utilizar la condiciones extras ELSE o
ELSIF. El siguiente ejemplo muestra la
descripción de un registro de conversión serieparalelo de N bits. La información serial DATA
es almacenada en los registros CONVERT a
través de cnexiones mediante la señal S, en cada
transición positiva del reloj. El circuito resultante
se muestra en la figura 3.14.
ARCHITECTURE behavior OF converter IS
SIGNAL s: bit_vector(convert'RANGE);
BEGIN
g: FOR i IN convert'RANGEGENERATE
-- Desplaza el bit del registro (N-2)
-- en el registro superior (N-1).
-- Ya que el bit N-1 se pierde en
-- cada transición del reloj.
g1: IF (i = convert'LEFT) GENERATEPROCESS(clk, s)
BEGIN IF clk'EVENTAND clk='1' THEN
convert(i) <= s(i-1);
END IF;
END PROCESS;
END GENERATE;
-- Desplaza los bits intermedios
-- hacia arriba
g2: IF (i > convert'RIGHTAND
i < convert'LEFT) GENERATE
s(i) <= s(i-1) AND convert(i);
DOWNTO 0));
PROCESS(clk, s)
BEGIN
IF clk'EVENTAND clk='1' THEN
convert(i) <= s(i-1);
END IF;
END PROCESS;
END GENERATE;
-- Almacena el bit de entrada DATA en el
-- primer registro
g3: IF (i = convert'RIGHT) GENERATEPROCESS(clk,s)
BEGIN
IF clk'EVENTAND clk='1' THEN
convert(i) <= data;
END IF;
END PROCESS;
s(i) <= convert(i);
END GENERATE;
END GENERATE;
END behavior;
Como podrá observar en la figura 3.14 las
retroalimentaciones en algunas ocasiones se
realizaron desde la salida Q de cada registro y en
otros usando la salida negada. Esto dependerá del
programa de síntesis utilizado y del dispositivo
empleado.
IEC FRANCISCO JAVIER TORRES VALLE
50
CAPÍTULO III: SINTAXIS DEL LENGUAJE
Figura 3.14 Diseño de circuitos utilizando la inst. If... Generate
IEC FRANCISCO JAVIER TORRES VALLE
51
CAPÍTULO III: SINTAXIS DEL LENGUAJE
3.12 SUBPROGRAMAS
Los subprogramas son secuencias
independientes de instrucciones y declaraciones
que pueden ser llamadas en repetidas ocasiones
dentro de una arquitectura, proceso, o cuerpo de un
paquete en VHDL. Existen dos tipos de
subprogramas: procedimientos y funciones.
Desde el punto de vista del hardware, un
llamado a un subprograma es similar a la
instanciación de un componente, con la diferencia
que el subprograma forma parte del circuito en el
cual esta siendo utilizado. La instanciación de un
componente o módulo, implica la síntesis de dos o
más niveles de jerarquía en el diseño. Un
subprograma sintetizado generalmente es un único
circuito combinacional (utilícese un proceso si se
desea crear un circuito secuencial).
Los subprogramas se declaran habitualmente en
paquetes y los cuerpos de dichos subprogramas
son implementados en el cuerpo del paquete en el
que fueron declarados. Aunque es posible definir
los subprogramas dentro de otras estructuras
(arquitecturas y procesos), no es común que se
haga, además, que algunos sintetizadores
restringen la utilización de ellos sólo dentro de
paquetes. Acerca de dichas restricciones en el uso
de subprogramas, consúltese los manuales de
referencia de VHDL o manuales de usuario del
sintetizador que se este utilizando.
3.12.1 PROCEDIMIENTOS
Un procedimiento es un algoritmo que puede
regresar uno o varios valores y que, además, puede
o no tener parámetros. Estos se utilizan
generalmente para descomponer grandes
descripciones comportamentales en pequeñas
secciones, las cuales a su vez pueden ser utilizadas
por distintos procesos dentro de la descripción.
Los parámetros que se utilizan en el llamado de
un procedimiento deben ser constantes, variables,
o señales. Además, también debe especificarse el
modo ya sea IN, OUT, o INOUT. A menos que se
especifique, un parámetro se considera como una
constante si se utiliza en el modo IN, y por
omisión una variable si se utiliza el modo INOUT
o OUT.
Los procedimientos pueden ser utilizados de
manera concurrente o secuencial, es decir, ya sea
fuera o dentro de un proceso. Si alguno de los
parámetros es un variable, entonces el
procedimiento puede ser utilizado sólo
secuencialmente. Recordemos que las variables
solamente pueden ser declaradas dentro procesos,
procedimientos y funciones y por esto un
procedimiento que utilice una variable como
parámetro puede ser invocado únicamente dentro
del proceso en el que se encuentra declarada dicha
variable.
Una variable declarada dentro de un
procedimiento existe solamente en el momento de
ejecución del mismo, similar a la declaración de
variables dentro de procesos.
DECLARACIÓN DE PROCEDIMIENTOS
PROCEDURE procedimiento ( lista de
parámetros );
CUERPO DEL PROCEDIMIENTO
PROCEDURE procedimiento (lista de
parámetros ) IS
-- declaraciones
BEGIN
-- instrucciones secuenciales
END procedimiento;
EJEMPLO
PACKAGE ejemplo IS
-- declaración de procedimiento
PROCEDURE procedimiento(a: IN bit ;
b: INOUT bit);
END ejemplo;
PACKAGE BODY ejemplo IS
-- cuerpo del procedimiento
PROCEDURE procedimiento ( a: IN bit ;
b: INOUT bit) IS
BEGIN
b := a AND b ;
END;
END ejemplo;
3.12.2 FUNCIONES
Una función es un algoritmo que retorna un
único valor y puede o no tener parámetros de
entrada. Las funciones se utilizan generalmente
para:
(1) Convertir objetos de datos de un tipo a otro.
(2) Como simples funciones que realizan
operaciones para las más frecuentes
situaciones de diseño. Los parámetros de una
función siempre son del modo IN y deben
IEC FRANCISCO JAVIER TORRES VALLE
47
CAPÍTULO III: SINTAXIS DEL LENGUAJE
ser señales o constantes. Además, cualquier
variable declarada dentro de la función
existe solamente dentro de la función.
ECLARACIÓN DE FUNCIONES
D
FUNCTION identificador (lista de
parámetros) RETURN tipo;
CUERPO DE LA FUNCIÓN
FUNCTION identificador (lista de
-- declaraciones
BEGIN
-- instrucciones secuenciales
END identificador ;
parámetros) RETURN tipo IS
EJEMPLO
FUNCTION cuenta_unos(
VARIABLE temp: integer := 0;
BEGIN
FOR i IN vec1'low TO vec1'high LOOP
IF vec1 (i) = '1' THEN
END IF;
END LOOP;
RETURN temp;
END cuenta_unos;
vec1: std_logic_vector)
RETURN integer IS
temp := temp + 1;
3.12.3 LLAMADO A SUBPROGRAMAS
Como ya mencionamos un subprograma puede
tener o no tener parámetro. Además, en la
declaración de un subprograma se define el
nombre, modo, y tipo de dato para cada parámetro.
Cuando el subprograma es llamado, cada
parámetro recibe un valor. El valor que recibe el
parámetro (con su tipo correspondiente) puede ser
el resultado de una expresión, el valor de un
variable, o de una señal. El modo en el que es
declarado el parámetro especifica la forma en que
puede ser utilizado, similar a los puertos en una
entidad.
- IN: lectura.
- OUT: escritura.
- INOUT: lectura y escritura.
Un parámetro que es declarado en el modo OUT
o INOUT debe ser una variable o una señal, ya sea
para tipos simples como el bit, o arreglos como el
bit_vector. Cuando el subprograma es un
procedimiento, puede tener múltiples parámetros
que pueden utilizar los modos: IN, INOUT, o
OUT. Los procedimientos son usados cuando se
desea actualizar o modificar algún dato. Un
ejemplo puede ser un procedimiento con un
parámetro INOUT tipo bit_vector el cual invierte
los bits del vector.
Si por el contrario el subprograma es una
función, esta puede tener múltiples parámetros,
todos del modo IN. Una vez que se ejecuta la
función, esta retorna un único valor. Este valor
debe ser especificado con un tipo determinado. Un
ejemplo es la función ABS que regresa el valor
absoluto del parámetro.
LLAMADO A PROCEDIMIENTOS
El llamado a un procedimiento se invoca por su
nombre, y este utiliza los parámetros que le son
listados.
Cada expresión puede ser el identificador de una
señal, variable, o alguna operación. Al igual que en
la instanciación de componentes, la asociación de
los parámetros puede ser por el nombre o por
posiciones.
a: IN bit_vector(1 DOWNTO 0);
b: IN bit_vector(1 DOWNTO 0);
c: INOUT bit_vector(1 DOWNTO 0)) IS
BEGIN
c := a AND b ; -- al no especificarse
-- como señales los parámetros INOUT
-- son variables por omisión
END;
procedimiento(a =>( entA AND entC ),
b => entB,
c => sal0);
procedimiento(entA, entC, sal1) ;
IEC FRANCISCO JAVIER TORRES VALLE
48
CAPÍTULO III: SINTAXIS DEL LENGUAJE
El siguiente ejemplo muestra un procedimiento
local (declarado dentro de un proceso) llamado
SWAP el cual compara y ordena dos elementos de
un arreglo. El procedimiento es llamado varias
veces para acomodar todos los elementos del
arreglo.
PACKAGE data_types IS
TYPE dat_element IS integer RANGE 0 TO 3;
TYPE data_array IS ARRAY (1 TO 3) OF
END data_types;
USE work.data_types.ALL;
ENTITY sort IS
PORT(in_array: IN data_array;
out_array: OUT data_array);
END sort;
ARCHITECTURE example OF sort IS
BEGIN
PROCESS(in_array)
PROCEDURE swap(data: INOUT data_array;
low, high: IN integer)
VARIABLE temp: data_element;
BEGIN IF (data(low) > data(high)) THEN
temp := data(low);
data(low) := data(high);
data(high) := temp;
END IF;
END swap;
VARIABLE my_array: data_array;
BEGIN
my_array := in_array;
swap(my_array, 1, 2);
swap(my_array, 2, 3);
swap(my_array, 1, 2);
out_array <= my_array;
END PROCESS;
END example;
dat_element;
IS
LLAMADO A FUNCIONES
Una función es llamada por su nombre y utiliza
los parámetros que le son dados. Las funciones
regresan un único valor.
La instrucción RETURN termina un
subprograma. Si el subprograma es una función es
necesario utilizar la instrucción RETURN, en el
caso de los procedimientos es opcional. La sintaxis
es la siguiente.
En una función la expresión proporciona el
valor de retorno de la función. Cada función debe
de tener al menos una instrucción de retorno. El
tipo de datos que maneja la expresión de retorno
debe coincidir con el tipo de dato de retorno
declarado en la función.
EJEMPLO
PACKAGE ejemplo_return IS
FUNCTION ejemplo_func (a, b, c: bit)
RETURN bit;
END ejemplo_return;
PACKAGE BODY ejemplo_return IS
FUNCTION ejemplo_func (a, b, c: bit)
RETURN bit IS
BEGIN
IF (c = '1') THEN
RETURN(a XOR b);
ELSE
RETURN NOT(a XOR b);
END IF;
END ejemplo_func;
END ejemplo_return;
LIBRARY ieee;
USE ieee.std_logic_1164.ALL;
USE work.ejemplo_return.ALL;
-- la librería "work" es la librería del
-- presente proyecto
ENTITY uso_funcion IS
PORT ( SIGNAL in1, in2, in3: IN bit;
SIGNAL valor_de_retorno: OUT bit);
END uso_funcion;
IEC FRANCISCO JAVIER TORRES VALLE
49
CAPÍTULO III: SINTAXIS DEL LENGUAJE
ARCHITECTURE funcion OF uso_funcion IS
BEGIN
valor_de_retorno <= ejemplo_func(in1,
in2, in3);
END funcion;
En el siguiente ejemplo, la función OPERATE
realiza las funciones AND y OR con los operandos
de entrada A y B. LA operación realizada depende
del valor del parámetro OPERATION. El circuito
resultante se muestra en la figura 3.15.
FUNCTION operate(a, b, operation: bit)
RETURN bit IS
BEGIN
IF (operation = '1') THENRETURN (a AND b);
ELSE RETURN (a OR b);
END IF;
END operate;
Figura 3.15 Circuito generado mediante el uso de
funciones
3.12.4 SOBRECARGA DE OPERADORES
La sobrecarga de operadores consiste en definir
nuevas funciones para utilizar tipos de datos con
los que no estaba definido anteriormente el
operador. Así, por ejemplo el operador AND no
está definido de manera predeterminada para ser
utilizado con los tipos std_logic_vector, unsigned
y signed. Pero dentro de los paquetes
std_logic_1164, numeric_std, y numeric_bit, que
es donde se definen estos tipos de datos, se
sobrecarga el operador AND para poder utilizarlo
con estos tipos de datos. También es posible crear
operadores para ser utilizados con los tipos de
datos definidos por el usuario.
EJEMPLO
TYPE mi_bit IS ('0', '1', 'x') ;
-- tipo de datos definido por el usuario
-- Sobrecarga de los operadores AND y OR
-- para ser utilizados con el nuevo tipo
-- de datos
FUNCTION "AND" (input1, input2: IN mi_bit)
FUNCTION "OR" (input1, input2: IN mi_bit)
· · ·
SIGNAL a, b, c: mi_bit;
· · ·
c <= ( a OR b ) AND c;
RETURN mi_bit;
RETURN mi_bit;
Cuando se sobrecarga un operador en VHDL, es
necesario que el nombre del operador se encuentre
entre comillas dobles " " para que el programa de
síntesis lo interprete como operador. Si no se hace
así entonces se considera a la función como tal y
no como un operador sobrecargado.
3.13 LIBRERÍAS
Una librería consiste en una colección de
unidades de diseño analizadas previamente con lo
cual se facilita la utilización de estas en nuevos
diseño. Para incluir una librería se utiliza la
siguiente sintaxis.
LIBRARY identificador_librería;
La cláusula LIBRARY permite utilizar la
librería especificada únicamente para la unidad de
diseño en la cual se declara. Una unidad de diseño
es una entidad, paquete, arquitectura, o cuerpo de
paquete.
EJEMPLO
LIBRARY mi_libreria;
3.13.1 SÍNTESIS DE LIBRERÍAS EN WARP
Para sintetizar librerías en WARP de Cypress
Semiconductors necesitas hacer lo siguiente:
1. – Dentro de Galaxy selecciona: File > New >
Project [ Target - Library ]
IEC FRANCISCO JAVIER TORRES VALLE
50
CAPÍTULO III: SINTAXIS DEL LENGUAJE
2. – A continuación proporcionas la información
del nombre de la librería, nombre del
proyecto, y localización del proyecto en disco
duro. Cabe mencionar que es posible crear
cualquier número de proyectos dentro del
mismo directorio, y todos compilando la
misma librería. Por ejemplo, podemos crear
un proyecto con el nombre "multiplexores"
para compilar dentro de la librería
"mi_libreria" en el directorio
"c:\vhdl_proj\mi_libreria". Diseñar todas las
unidades de diseño deseadas dentro de esta
librería y compilarlas en la misma. Después
podemos otro proyecto con el nombre
"comparadores" para compilar en la librería
"mi_libreria" en el directorio
"c:\vhdl_proj\mi_libreria". Diseñar otras
unidades de diseño y compilarlas. Cuando se
incluya la librería "mi_librería" en otros
proyectos podemos utilizar cualquier unidad
de diseño que se encuentre ya sea en el
proyecto de librería "multiplexores" o en el de "comparadores". Esto es posible porque
ambos proyectos se compilaron en una
librería con el mismo nombre y en el mismo directorio.
Como ya se menciono anteriormente, en una
librería puedes incluir todas las unidades de diseño
que desees, siendo unidades de diseños las
estructuras: ENTITY, ARCHITECTURE,
PACKAGE, o PACKAGE BODY. Por lo general
en los archivos de librería se utilizan paquetes.
Para incluir una librería creada por el usuario en
algún proyecto en particular necesitar hacer lo
siguiente:
1. – Seleccionas Project > Library Manager...
2. – Dentro del cuadro de dialogo del
administrador de librerías, seleccionas Assign
y después haces click en el botón Add...
3. – Después aparece un cuadro de dialogo en el
cual puedes agregar archivos .vhd al proyecto
de librería. Si ya los tienes, puedes copiarlos
al directorio o buscarlos mediante el botón
Browse... agregarlos al proyecto. Si no los
tienes sólo haz click en Finalizar y
posteriormente podrás crear los archivos del
proyecto de librería.
IEC FRANCISCO JAVIER TORRES VALLE
3. – Ahora se te pide el nombre de la librería que
vas a incluir y la ruta en donde se encuentran
los archivos de la librería. Por ejemplo, en
Library podrías poner la librería del ejemplo
anterior "mi_libreria". Y en el Path escribes
la ruta del directorio donde se encuentra
compilada la librería. Debes escribir toda la
ruta tal y como aparece en MS-DOS. Esta
librería se creo en el directorio
"c:\vhdl_proj\mi_libreria", pero la librería se
compilo en el directorio
"c:\vhdl_proj\mi_libreria\mi_libreria" y el
nombre MS-DOS del directorio es "
C:\vhdl_p~1\mi_lib~1\mi_lib~1".
51
CAPÍTULO III: SINTAXIS DEL LENGUAJE
4. – Después que agregaste la librería, para
incluirla basta con que escribas lo siguiente:
LIBRARY mi_libreria;
Una vez declarada en la descripción podrás
utilizar todas las unidades de diseño que se hayan
compilado en la librería.
El nombre de la librería de todo proyecto que
estés realizando es "work". Por lo que si deseas
crear un paquete en particular en el proyecto
puedes incluirlo en cualquier unidad de diseño de
la siguiente manera.
USE work.identificador_paquete.ALL;
Donde identificador_paquete es el nombre del
paquete que creaste en el mismo proyecto.
EJEMPLO
Crea un nuevo proyecto en WARP y en un
archivo de texto copia toda la siguiente
descripción.
PACKAGE swap IS
FUNCTION swap4(data: IN bit_vector
RETURN bit_vector;
END swap;
PACKAGE BODY swap IS
FUNCTION swap4 (data: IN bit_vector
RETURN bit_vector IS
VARIABLE tempo: bit_vector
BEGIN
tempo := data(1 DOWNTO 0)&
data(3 DOWNTO 2);
( 3 DOWNTO 0 ) )
( 3 DOWNTO 0 ) )
( 3 DOWNTO 0 );
RETURN tempo ;
END; END swap ;
-- instanciación de un paquete que se
-- encuentra en el mismo proyecto
USE work.swap.ALL;
ENTITY swap_ent IS
PORT (x:IN bit_vector(3 DOWNTO 0);
END swap_ent;
ARCHITECTURE swap_ent OF swap_ent IS
BEGIN
y <= swap4(x) ;
END swap_ent;
y: OUT bit_vector(3 DOWNTO 0));
3.13.2 PAQUETES
Un paquete en VHDL es una colección de
declaraciones que pueden ser utilizadas por otras
descripciones en VHDL. Un paquete en VHDL
consiste de dos secciones: la declaración del
paquete y el cuerpo del paquete.
Para incluir un paquete en otra descripción se
sigue la siguiente sintaxis:
USE libreria.identificador_paquete.ALL ;
De esta manera el paquete indicado es visible
para la unidad de diseño en la cual está siendo
utilizado. Mediante "ALL" indicamos que
deseamos incluir todas las declaraciones de
funciones, componentes, tipos de datos, subtipos
de datos, procedimientos, etc. que encuentren en
dicho paquete.
DECLARACIÓN DEL PAQUETE
PACKAGE identificador IS
-- declaración de subprograma
-- declaración de tipo de datos
-- declaración de subtipos
-- declaración de constantes
-- declaración de señales
-- declaración de componentes
-- declaración de atributos
-- especificación de atributos
-- instrucción USE
END identificador;
CUERPO DEL PAQUETE
PACKAGE BODY identificador IS
-- declaración de subprograma
-- cuerpo del subprograma
-- declaración de tipo de datos
IEC FRANCISCO JAVIER TORRES VALLE
52
CAPÍTULO III: SINTAXIS DEL LENGUAJE
-- declaración de subtipos
-- declaración de constantes
-- instrucción USE
END identificador;
En la declaración del paquete se hace mención
de todo aquello que puede ser utilizado por otras
descripciones cuando se incluye el paquete. El
cuerpo del paquete proporciona definiciones y
declaraciones adicionales, así como la descripción
completa de funciones y procedimientos que
fueron declarados previamente en el paquete.
E
JEMPLO
PACKAGE v3_tbl IS
SUBTYPE v3 IS std_logic_vector(0 TO 2);
TYPE v3_array IS ARRAY(0 TO 7) OF v3;
CONSTANT v3_table : v3_array := (
FUNCTION int2v3 (ia: integer) RETURN v3;
END v3_tbl;
compilar la librería "mi_libreria". Crea un nuevo
archivo de texto y copia la siguiente descripción en
él.
LIBRARY ieee;
USE ieee.std_logic_1164.ALL;
PACKAGE multiplexores IS
COMPONENT mux_2_a_1
GENERIC(msb: integer);
PORT( selec: IN std_logic;
END COMPONENT;
END multiplexores;
x: IN std_logic_vector
(msb DOWNTO 0);
y: IN std_logic_vector
(msb DOWNTO 0);
z: OUT std_logic_vector
(msb DOWNTO 0));
LIBRARY ieee;
USE ieee.std_logic_1164.ALL;
ENTITY mux_2_a_1 IS
GENERIC ( msb: integer := 3 ) ;
-- debe declararse siempre un valor
-- inicial para que en caso de no ser
-- especificado en el momento de la
-- instanciación, el componente tome un
-- valor por omisión
PORT(selec: IN std_logic;
x: IN std_logic_vector
(msb DOWNTO 0);
y: IN std_logic_vector
(msb DOWNTO 0);
z: OUT std_logic_vector
(msb DOWNTO 0));
END mux_2_a_1;
ARCHITECTURE a_mux_2_a_1 OF mux_2_a_1 IS
BEGIN
z <= x WHEN selec = '1' ELSE
y WHEN selec = '0';
END a_mux_2_a_1 ;
Sintetiza el proyecto y después crea otro para
utilizar el paquete anterior. Para agregar la librería
a este nuevo proyecto hazlo desde el administrador
de librerías. Crea un nuevo archivo de texto y
copia la siguiente descripción en él.
LIBRARY ieee;
USE ieee.std_logic_1164.ALL;
USE mi_libreria.multiplexores.ALL;
-- referencia al paquete multiplexores
-- que se encuentra dentro
-- de la librería "mi_libreria"
ENTITY multiplexor IS
PORT(a,b,c,d: IN std_logic_vector
(3 DOWNTO 0);
selec: IN std_logic_vector
(1 DOWNTO 0);
salida: OUT std_logic_vector
(3 DOWNTO 0));
END multiplexor;
ARCHITECTURE estructural OF multiplexor IS
SIGNAL salida1: std_logic_vector
(3 DOWNTO 0);
SIGNAL salida2: std_logic_vector
(3 DOWNTO 0);
BEGIN
-- instanciación del componente mux_2_a_1
u1: mux_2_a_1 PORT MAP
(a, b, selec(0), salida1);
u2: mux_2_a_1 PORT MAP
(c, d, selec(0), salida2);
u3: mux_2_a_1 PORT MAP
(salida1, salida2, selec(1),
salida) ;
END estructural ;
IEC FRANCISCO JAVIER TORRES VALLE
53
CAPÍTULO III: SINTAXIS DEL LENGUAJE
Como se mencionó al principio una librería es
una colección de unidades de diseño que pueden
ser incluidas es otras descripciones mediante el
llamada a la respectiva librería.
IEC FRANCISCO JAVIER TORRES VALLE
54
CAPÍTULO IV: DESCRIPCIÓN DE CIRCUITOS DIGITALES
IV
DESCRIPCIÓN DE
CIRCUITOS
IEC FRANCISCO JAVIER TORRES VALLE
DIGITALES
54
CAPÍTULO IV: DESCRIPCIÓN DE CIRCUITOS DIGITALES
4.1 PROYECTOS EN WARP 5.0
El objetivo de este capítulo es enseñarte a crear
proyectos en VHDL utilizando Warp de Cypress
Semiconductors. Así como diferentes métodos
prácticos para la síntesis de los circuitos digitales
más comunes.
PROCEDIMIENTO
1. Una vez en Windows haz click en el botón de
inicio, selecciona Programas > Warp R5.0 > Galaxy.
Figura 4.2
3. Posteriormente debe aparecer un cuadro de
dialogo como el que se muestra a continuación.
Para crear un proyecto con el que quieres
programar un dispositivo debes de seleccionar la
segunda opción (Project [Target - Device]).
4. Cuando selecciones la opción de Project [Target - Device] aparecerá una ventana que te
pide que pongas un nombre a tu proyecto, escribe
el nombre de nuevo. En el segundo cuadro de texto
te pide que especifiques el directorio en donde
debe de guardar tu proyecto, puedes hacer un
directorio nuevo desde esa misma ventana con solo
escribir el nombre, por ejemplo c:\nuevo, o puedes
buscar una carpeta ya existente con la opción
Browse. Cuando hayas terminado de especificar
los nombres haz click en el botón de Siguiente.
Figura 4.1
2. Cuando te encuentres dentro del Galaxy,
selecciona File > New.
IEC FRANCISCO JAVIER TORRES VALLE
Figura 4.3
5. Aparecerá una ventana con título Add Files to
Project, esta ventana se usa cuando ya tienes
archivos que quieres agregar a tu proyecto, pero en
esta ocasión por tratarse de un proyecto totalmente
nuevo no es necesario especificar nada dentro de
esta ventana. Solo haz click en el botón de
Siguiente.
55
CAPÍTULO IV: DESCRIPCIÓN DE CIRCUITOS DIGITALES
Figura 4.4
6. La siguiente ventana lleva el título de Select
Target Device, esta ventana es muy importante ya
que es aquí donde debes de especificar el PLD en
el que vas a trabajar. Los PLD's que se usan
cuando se está aprendiendo son los pequeños
(generalmente 16V8, 22V8 ó 22V10), estos PLD's
están en la ventana como SPLD. Haz doble click
sobre este texto, te aparecerá una lista de los
SPLD's más comunes, selecciona el SPLD que te
interese y nuevamente aparecerá una lista donde
hay varios tipos del mismo SPLD, por ejemplo
PALCE16V8-10PC/PI. Esta parte es importante,
ya que debes de seleccionar un SPLD que tenga un
encapsulado de tipo PDIP, para que lo puedas
montar en tu protoboard. En la parte inferior
aparece información sobre el SPLD que te interese.
Cuando escojas el SPLD adecuado haz click en
Finalizar.
7. Luego de lo anterior, aparecerá una ventana
que te pregunta si deseas guardar tu nuevo
proyecto, solo haz click en Sí.
8. Ahora ya tienes un nuevo proyecto donde se
encuentra suficiente información para que el
compilador te genere el archivo .jed. Pero te falta
agregar el código que habrá de compilarse.
Selecciona File > New > Text File, o puedes hacer
click en el icono de nuevo. Escribe lo siguiente
dentro del archivo de texto:
library ieee;
Elige File > Save As y en la opción de Guardar
en, selecciona el nombre de la carpeta que usaste
en el paso número 4 (c:\nuevo). Una vez que hayas
seleccionado el directorio, escribe el nombre de
archivo, se sugiere el nombre nuevo, con la
extensión .vhd, ya que de esta manera se especifica
un archivo que contiene un código en VHDL.
Luego de hacer esto, guarda tu archivo.
9. Cierra el archivo de texto.
10. Selecciona Project > Add Files, te aparecerá
una ventana que debe de tener tu archivo
nuevo.vhd , haz click en Add, y posteriormente en
OK.
Figura 4.5
IEC FRANCISCO JAVIER TORRES VALLE
Figura 4.6
11. Tu archivo de texto se ha convertido en un
archivo de VHDL y está dentro de tu proyecto,
todo lo que programes, será compilado en el
dispositivo que especificaste. En tu ventana de
proyecto (si no se encuentra abierta, la puedes
activar haciendo View > Project Window) debe de
aparecer un icono en forma de hoja que tiene el
nombre de tu proyecto. Haz click en esta hoja y te
debe de aparecer un archivo con la instrucción:
library ieee; solo que ahora la palabra library está
56
CAPÍTULO IV: DESCRIPCIÓN DE CIRCUITOS DIGITALES
en color azul porque es una palabra reservada. Esto
demuestra que haz hecho correctamente el
procedimiento.
Figura 4.7
12. Si la configuración de colores es la normal,
notarás que todas las palabras reservadas se
muestran en color azul y los comentarios en color
rojo. Ahora ya puedes comenzar a hacer tu
descripción en VHDL.
4.2 SIMULACIÓN DE
PROYECTOS
1. Una vez que se ha creado un nuevo proyecto
en Galaxy, dentro del menú Project selecciona
Compiler Options.
Figura 4.8
2. Lo anterior abrirá la ventana de opciones de
compilación, dentro de esta se encuentra una
sección para elegir el formato de los retardos para
simular el circuito Simulation—Timing Model.
Aquí es donde debes de seleccionar el formato
1164/VHDL.
Active - HDL de la empresa Aldec Inc. es un
simulador que utiliza un archivo de post - síntesis
creado por WARP. Éste es un archivo .vhd con los
retardos de tiempo del código sintetizado en el
dispositivo seleccionado. Este tema tiene por
objetivo dar una pequeña introducción a este
simulador de VHDL en las siguientes tres
secciones.
1. Formato de simulación 1164/VHDL.
2. Simulación.
3. Tipos de señales de estimulación.
FORMATO DE SIMULACIÓN 1164/VHDL
El archivo de entrada para Active - HDL es un
modelo de simulación post - síntesis generado
cuando se compila un archivo .vhd en el
dispositivo elegido. En WARP es posible crear
archivos con diferentes formatos para simulación
post - síntesis. Active - HDL requiere de un archivo
con el formato de simulación IEEE - 1164 / VHDL.
Para crear este archivo post - síntesis debes
seguir el siguiente procedimiento.
Figura 4.9
3. Asegúrate que se encuentre habilitado el
cuadro de Enable Testbench Output.
4.2.1 PROCESO DE SIMULACIÓN
El proceso de simulación lo podemos resumir en
los siguientes siete pasos.
IEC FRANCISCO JAVIER TORRES VALLE
57
CAPÍTULO IV: DESCRIPCIÓN DE CIRCUITOS DIGITALES
1. Cargar un archivo con el formato de
simulación 1164/VHDL.
2. Iniciación de la simulación.
3. Agregar señales.
4. Asignar señales de estimulación.
5. Correr la simulación.
6. Observación de la simulación.
7. Guarda la simulación.
1. - CARGA DEL ARCHIVO
El primer paso es abrir el programa Active-HDL
Sim que normalmente se encuentra en Menu Inicio
> Programas > Warp > Active-HDL Sim. Para
cargar el archivo selecciona Open Vhdl dentro del
Menú File.
2. - INICIACIÓN DE LA SIMULACIÓN
Para iniciar la simulación, activa el simulador
utilizando la opción Initialize Simulation, dentro
del menú Simulation. Después abre una ventana
para el análisis de señales Waveform Window, si es
que no se encontrara ya una abierta.. Para crear
una nueva ventana de este tipo, haz clic en el icono
dentro de la barra estándar de trabajo o selecciona
File > New Waveform..
3. - A
GREGANDO SEÑALES
El siguiente paso es agregar señales a la ventana
de análisis, para esto selecciona Add Signals...en el
menú Waveform. La ventana para agregar señales
aparecerá con una lista de todas las señales de
entrada, salida, entrada/salida y nodos internos de
conexión disponibles en el diseño. Para agregar
alguna de las señales que se encuentran en esta
lista basta con hacer doble clic sobre el nombre de
la señal. Si deseas agregar varias señales al mismo
tiempo, puedes seleccionarlas mediante la tecla
control y haciendo clic sobre cada señal que deseas
agregar para después hacer clic sobre el botón Add
que se encuentra en la parte inferior de la ventana.
Figura 4.10
Es importante mencionar que el archivo con el
formato 1164/VHDL se crea en el subdirectorio
vhd dentro del directorio de trabajo del proyecto
una vez que éste es compilado. Si se selecciona por
accidente el archivo .vhd creado por el usuario, el
compilador del programa generará varios errores y
no podrá ser simulado. Una vez que el archivo
apropiado es cargado, se desplegarán una serie de
mensajes dentro de la ventana de compilación.
Uno de los mensaje que debería aparecer cuando el
archivo es compilado correctamente es el
siguiente:
Las señales de estimulación son utilizadas para
definir diferentes impulsos a los puertos de entrada
del diseño que esta siendo simulado. Para
seleccionar alguno de estos tipos primero
selecciona la señal y después selecciona Waveform > Stimulators..., a continuación se describe
brevemente los diferentes tipos de señales de
estimulación de Active-HDL Sim.
58
CAPÍTULO IV: DESCRIPCIÓN DE CIRCUITOS DIGITALES
Figura 4.12
C
LOCK
Sirve para definir señales de reloj definidas con
los siguientes parámetros: frecuencia, valor inicial,
ciclo de trabajo y tiempo de inicio.
C
USTOM
Un estimulador personalizado se crea editando
los valores deseados en la ventana de simulación.
Estado en el modo de edición, al estimulador de
entrada se le puede asignar un estado bajo o un
estado alto presionando '1' o '0' respectivamente.
F
ORMULA
Un estimulador del tipo formula produce una
señal definida por una simple sintaxis. La señal es
definida con secuencias pares de valor - tiempo.
Con la componente tiempo indicamos el momento
en el que la señal asume el valor especificado. La
unidad del tiempo es en picosegundos. Para repetir
durante un periodo especificado, se agrega el
modificador -r. La sintaxis del estimulador tipo
formula se muestra a continuación.
Los estimuladores predefinidos son una serie de
señales tipo clock con diferentes frecuencias o
señales del tipo formula que pueden ser asignados
a las señales. Para agregar un nuevo estimulador a
esta lista, lo puedes hacer en la misma ventana
dentro del cuadro Predefined.
V
ALOR
Con este tipo de estimulador asignamos un valor
constante a la señal especificada.
H
OTKEY
Con este estimulador podemos estar cambiando
el valor de la señal presionando una tecla. Cuando
asignamos este tipo de estimulador es conveniente
asignar una lista de valores. Cada que presionemos
la tecla asignada, estaremos cambiando entre los
valores de esta lista.
Para una descripción más completa de las
características del simulador consulta la ayuda del
programa.
5. - C
ORRIENDO LA SIMULACIÓN
Para correr la simulación selecciona Simulation
> Run. La simulación se detendrá después que la
duración especificada haya sido terminada. En este
momento las señales de estimulación para los
puertos de entrada pueden ser alterados y
producirán efectos sobre la simulación cuando esta
continué. Para volver a iniciar la simulación
selecciona Simulation > Restart Simulation.
6. - O
BSERVANDO LA SIMULACIÓN
Varias propiedades pueden ser manipuladas
para mejorar la apariencia de la simulación. A
continuación se describen brevemente algunas de
estas propiedades.
B
US
La líneas individuales que forman un bus
pueden ser mostradas y editadas. Para mostrarlas
haz clic sobre "+" que se encuentra a junto al
nombre el bus. Las señales de estimulación pueden
ser asignadas a cada línea del bus o al bus
completo.
C
OLOR
Las señales de la simulación pueden ser de
diferentes colores para una mejor claridad cuando
varias señales son desplegadas. Para agregar color
a todas las señales visibles, selecciona Waveform > Colorize Waveforms, esto asignará diferentes
colores, arbitrariamente a cada señal dentro de la
ventana de simulación. Para asignar color a cada
señal, haz clic con el boton derecho sobre el
nombre de la señal y selecciona la opción
Properties..
IEC FRANCISCO JAVIER TORRES VALLE
59
CAPÍTULO IV: DESCRIPCIÓN DE CIRCUITOS DIGITALES
ZOOM
Para aumentar o reducir la escala de tiempo de
la simulación, selecciona View > Zoom > In/Out/Full.
B
OOKMARKS
Para colocar marcas sobre la ventana de
simulación primero selecciona Waveform > Select Mode. Cuando este modo se encuentra
seleccionado, es posible colocar marcas sobre
diferentes puntos de la simulación para una rápida
referencia a ciertos puntos importantes de la
misma. Para colocarlas primero haz clic con el
botón izquierdo en donde deseas colocar una
marca, después selecciona Search > Toggle Bookmark. Utilizando Next/Previous Bookmark
del mismo menú puedes cambiar entre una marca y
otra dentro de la simulación. Las marcas son
desplegadas como un triángulo azul sobre la escala
de tiempo en la ventana de simulación. Para
eliminar alguna marca selecciona Waveform > Edit Mode y después haz clic con el botón izquierdo
sobre la marca que deseas eliminar.
M
ODO DE MEDICIÓN
ventas de simulación abiertas. La extensión de los
archivos de simulación en Active-HDL Sim es
.awf.
4.3 COMPARADORES
El objetivo de este tema es crear, sintetizar, y
simular la descripción de circuitos comparadores
de magnitud utilizando WARP.
ROCEDIMIENTO
P
1. Primero crearemos un proyecto para el
ejemplo del comparador visto en el tema 3.1.2
Antes que nada debemos crear el proyecto dentro
de un directorio en el que se encontrarán todos los
archivos del proyecto (.pfg, .vhd, .jed, .rpt, etc. ).
Se sugiere crear primero una carpeta para todos los
proyectos VHDL y dentro de esa carpeta crear otra
carpeta para el presente proyecto, por ejemplo
c:\vhdl_proj\comparador_1, con el nombre
comparador_1.
Para entrar al modo de medición selecciona
Waveform > Measurement Mode. En este modo es
posible desplegar el tiempo exacto entre dos
eventos de la simulación. Para obtener esta
información coloca el puntero sobre una transición
negativa o positiva, cuando el puntero es colocado
sobre alguna transición debe cambiar a color
verde, presiona el botón izquierdo sobre la
transición y arrastra el puntero hasta otra transición
de cualquier señal dentro de la ventana de
simulación y entonces suelta el botón. La medida
exacta entre estas dos transiciones se desplegara
como una etiqueta entre las dos transiciones. Si la
etiqueta no es mostrada o no se ve completa,
amplia el alto de la fila haciendo clic con el botón
derecho sobre alguna de las señales que
intervienen en la medición y después selecciona
Properties, dentro de la venta de propiedades
aumenta la altura modificando el valor del cuadro
de texto Height. Para eliminar alguna etiqueta de
medición selecciona Waveform > Edit Mode,
después seleciona la etiqueta y presiona suprimir
7. - G
UARDANDO LA SIMULACIÓN
Existen dos formas de guardar la simulación.
Guardar solamente la simulación de la ventana
activa o guardar todas las simulaciones de las
Figura 4.13
2. Seleccionaremos un 22V10 con empaquetado
tipo DIP para sintetizar el código.
3. Ahora creamos un nuevo archivo de texto
para editar el código (File > New > Text File).
Este archivo debe ser guardado con extensión .vhd
y en la misma carpeta del proyecto. Se sugiere
guardarlo como:
c:\vhdl_proj\comparador_1\comparador1.vhd
4. A continuación se muestra la tabla de
funcionamiento de este comparador y basándose
en ella haremos el código de descripción en
VHDL. Primero utilizaremos el estilo de
IEC FRANCISCO JAVIER TORRES VALLE
60
CAPÍTULO IV: DESCRIPCIÓN DE CIRCUITOS DIGITALES
descripción de flujo de datos, que es el mismo que
se utilizó cuando se expuso el ejemplo en el tema
3.1.2.
TABLA DE FUNCIONAMIENTO
ENTRADAS SALIDAS
x < y x_men_y '1'
x < y equals '0'
x < y x_may_y '0'
x = y x_men_y '0'
x = y equals '1'
x = y x_may_y '0'
x > y x_men_y '0'
x > y equals '0'
x > y x_may_y '1'
5. Abajo se muestra el listado del comparador
correspondiente al estilo de descripción de flujo de
datos. Este listado debemos editarlo dentro del
archivo comparador_1.vhd.
ENTITY comparador IS
PORT ( x: IN bit_vector(3 DOWNTO 0);
y: IN bit_vector(3 DOWNTO 0);
x_may_y: OUT bit;
equals: OUT bit;
x_men_y: OUT bit
);
END comparador;
ARCHITECTURE comparador OF comparador IS
BEGIN
equals <= '1' WHEN x = y ELSE
'0';
x_may_y <= '1' WHEN x > y ELSE
'0';
x_men_y <= '1' WHEN x < y ELSE
'0';
END comparador;
6. Como se puede observar no se cargó ninguna
librería, y no es necesario hacerlo porque el tipo bit
es un tipo predefinido en WARP y en muchos
otros sintetizadores de VHDL. Por esto no
necesitamos de ninguna librería para poder
utilizarlo. Además, recuerde que la última
declaración de puertos no lleva ;
Una vez que se terminó de editar el código,
procedemos a guardar los cambios en el archivo y
a agregarlo al presente proyecto. Para agregarlo lo
hacemos desde el menú Project y dentro de éste
hacemos clic en Add Files... (Project > Add Files...). Una vez que aparece la ventana para
agregar archivos al proyecto, seleccionamos el
archivo comprador_1.vhd y presionamos el botón
"Add".
Si por error hacemos clic en la opción Add All
Files, todos los archivos .vhd dentro de la carpeta
del proyecto se agregaran al mismo. En este caso
el único archivo .vhd que debería estar dentro de la
carpeta del proyecto es comparador_1.vhd, lo cual
en esta ocasión no nos afectará. En caso de que
hubiera más de un archivo .vhd y no deseamos
tenerlo dentro del proyecto basta con seleccionarlo
en la ventana de proyecto y presionar la tecla
suprimir, o también desde Project > Remove
Selected Source File(s). Si la ventana de proyecto no está visible entonces seleccionamos View >
Reset Docking Windows.
Figura 4.14
7. Una vez editado y agregado el archivo al
proyecto se procede a sintetizar el código en el
22V10. Seleccionamos Compile > Project o
también lo podemos hacer presionado el icono de
compilación.
Figura 4.15
Si el archivo tiene errores, estos aparecerán en
la ventana de salida (Output Window). Dentro de
"Errors & Warnings" en la ventana de salida se
IEC FRANCISCO JAVIER TORRES VALLE
61
CAPÍTULO IV: DESCRIPCIÓN DE CIRCUITOS DIGITALES
muestra una lista completa de los errores así como
una descripción de cada error. Para acceder
rápidamente a la línea en la cual ocurrió el error,
basta con hacer doble clic sobre el error e
inmediatamente el programa se colocará sobre la
línea en donde se encuentra dicho error. Los
errores pueden ser algunos de los siguientes: omitir
algún punto y coma, no escribir correctamente
algún identificador, sintaxis incorrecta de las
instrucciones utilizadas, o uso incorrecto de los
operadores. Recordemos que VHDL es un
lenguaje en el que los tipos de datos son
sumamente importantes y no se pueden mezclar a
menos que se utilicen las librerías adecuadas.
8. La ventana de proyecto tiene 3 modos o
vistas: "Source Files View", "Hierarchy View", y
"Output Files View". En la primera se muestran los
archivos que se han agregado al proyecto. La
"Vista de Jerarquía" es útil cuando se hacen
diseños jerárquicos, ya que en esta se muestra cual
es el orden de importancia que hay entre ellos.
Dentro de la "Vista de Archivos de Salida"
aparecen los archivos que se generaron durante la
compilación, los cuales fueron creados dentro de la
carpeta del proyecto. Tales archivos de salida son:
.jed, .rpt y un .vhd que se encuentra dentro de la
carpeta "vhd" que está en la misma carpeta del
proyecto (ver tema 4.2).
las ecuaciones que resultaron durante el proceso de
síntesis, la asignación de pines, y un informe de
utilización del dispositivo. En ocasiones es
complicado realizar algunas descripciones y,
aunque el código se sintetiza, durante la
simulación hace algo diferente a lo que
esperábamos. La función del sintetizador, en este
caso WARP, es la de interpretar nuestra
descripción en VHDL para generar la lógica de
salida. En estos casos posiblemente la descripción
no corresponde exactamente a lo que queremos.
Para corregir la descripción es útil consultar las
ecuaciones, ya que en estas nos podemos dar
cuenta que es lo que estamos describiendo
realmente. En temas posteriores se presentan
algunos ejemplos en los que se exponen con más
detalle este tipo de problemas.
S
IMULACIÓN
9. Ahora que ya hemos logrado sintetizar el
código y obtenido los archivos .jed y .vhd de
postsíntesis procedemos a simular la descripción.
Las simulaciones las haremos en Active-HDL Sim
como se explicó en tema 4.2. Podemos abrir el
programa desde Galaxy desde Tools > Active-HDL Sim.
Figura 4.16
En el archivo .rpt se muestra un informe de los
resultados de la compilación. En éste se encuentran
IEC FRANCISCO JAVIER TORRES VALLE
Figura 4.17
10. Una vez iniciado el simulador, ahora
abrimos el archivo .vhd de postsíntesis como se
explica a continuación. Primero seleccionamos
File > Open VHDL.
62
CAPÍTULO IV: DESCRIPCIÓN DE CIRCUITOS DIGITALES
Figura 4.18
Para después abrir el archivo .vhd de
postsíntesis, el cual debería estar (si seguiste
correctamente todos los pasos) en el subdirectorio:
iniciamos la simulación seleccionando: Simulation > Initialize Simulation.
14. Una vez iniciada la simulación ahora
corremos la simulación. Para poder correrla
existen tres opciones: correr completamente la
simulación (el máximo es de 2ms+3), correrla y
que se detenga en un momento especifico, o
adelantar la simulación solamente por algún
tiempo. Para correr la simulación completamente
seleccionamos Simulation > Run. Si queremos
correr la simulación y especificar un tiempo en el
que debe detenerse seleccionamos Simulation >
Run Until... . Para correr la simulación "por pasos"
o por tiempos especificados, seleccionamos
Simulation > Run For. El tiempo de paso se
especifica a un lado del icono de Run For. Esta
última opción es la más practica al momento de
simular descripciones.
Figura 4.20
Ahora seleccionamos los puertos como se
explicó en el tema 4.2. En este ejercicio
seleccionaremos solamente los puertos declarados
en la entidad, tal y como se muestra en la figura
4.22
12. Lo siguiente es asignar señales de estimulo a
los puertos de entrada. Al bus "x" le asignaremos
un estimulador tipo formula usando la siguiente
formula.
tiempo de "paso" sea de 1 us. Ya que cuando
asignamos los estimuladores el valor de los buses
de entrada cambia cada 1 us. Si deseas utilizar Run
Until... bastara con especificar un tiempo de 32 us
para observar como se comporta el ciclo de
asignaciones que especificamos mediante la
formula, el tiempo mínimo para comprobar todos
los valores (por lo menos un ciclo) es de 16 us.
15. A continuación en la figura 4.23 se muestran
los resultados de la simulación. Si seguiste
correctamente todos los pasos deberías obtener
algo similar a lo mostrado en la siguiente figura.
63
CAPÍTULO IV: DESCRIPCIÓN DE CIRCUITOS DIGITALES
Figura 4.22
IEC FRANCISCO JAVIER TORRES VALLE
Figura 4.23
Figura 4.24
64
CAPÍTULO IV: DESCRIPCIÓN DE CIRCUITOS DIGITALES
4.4 MULTIPLEXORES
En este tema el objetivo es elaborar
descripciones de circuitos multiplexores utilizando
los tres estilos de descripción de VHDL.
PROCEDIMIENTO
Para la síntesis utilizaremos un 22V10 siguiendo
la siguiente tabla de funcionamiento en los tres
estilos de descripción.
TABLA DE FUNCIONAMIENTO
selec salida
00 a
01 b
10 c
11 d
4.4.1 DESCRIPCIÓN DE FLUJO DE DATOS
LIBRARY ieee;
USE ieee.std_logic_1164.ALL;
LIBRARY cypress;
USE cypress.std_arith.ALL ;
ENTITY multiplexor IS
PORT(a, b, c, d: IN std_logic_vector
(3 DOWNTO 0);
selec: IN std_logic_vector
(1 DOWNTO 0);
salida: OUT std_logic_vector
(3 DOWNTO 0));
END multiplexor;
ARCHITECTURE data_flow OF multiplexor IS
BEGIN
salida <= a WHEN selec = 0 ELSE
b WHEN selec = 1 ELSE
c WHEN selec = 2 ELSE
d WHEN selec = 3 ;
END data_flow;
El listado anterior corresponde a un multiplexor
4 a 1. El bus de salida es seleccionado mediante las
señales de selección selec(1) y selec(0)
(std_logic_vector es un arreglo de datos del tipo
std_logic). Como habrás notado se hizo el llamado
a una librería no mencionada anteriormente, la
librería "cypress". Esta librería es de Cypress
Semiconductors y fue desarrollada para facilitar la
descripción de circuitos digitales utilizando
WARP. De esta librería se llamó el paquete
std_arith, el cual contiene muchas funciones que
facilitan el uso de vectores tipo std_logic con
enteros. De no haber utilizado este paquete no
podríamos hacer ninguna de la comparaciones que
están en la asignación condicional WHEN... ELSE.
Es decir, no es posible hacer la comparación "selec
= 3" porque "selec" es del tipo std_logic_vector y
"3" es un número entero. El paquete
std_logic_1164 contiene los tipos de datos
std_logic y std_logic_vector que comúnmente
utilizamos por lo que es necesario cargar el
paquete para poder utilizar estos tipos, sin
embargo, no contiene funciones de comparación
entre tipos std_logic (o arreglos de este) y enteros.
Como la librería es de propia del sintetizador, es
decir, que siempre esta cargada dentro del área de
trabajo del proyecto o "work", podemos llamar el
paquete como se muestra a continuación.
USE work.std_arith.ALL;
SIMULACIÓN
Para la simulación se sugiere que asignes un
estimulador tipo formula a los vectores de entrada,
y al vector "selec" le asignes un estimulador tipo
"HOTKEY". Una vez que agregaste las señales a
la simulación, selecciona con el puntero el vector
"selec", después seleccionas Waveform > Stimulators..., cuando aparezca el cuadro de
estimuladores selecciona "HOTKEY" dentro de
"Stimulator type", y en "Press new hotkey" escribe
la letra "s" o cualquier otra.
Figura 4.25
Cada que presiones la tecla "s" el vector s estará
cambiando de valor, por omisión la lista de valores
de asignación incluye el '0' y el '1' solamente, en
IEC FRANCISCO JAVIER TORRES VALLE
65
CAPÍTULO IV: DESCRIPCIÓN DE CIRCUITOS DIGITALES
este caso necesitamos generar valores para un
vector de 2 bits. Para poder hacerlo, en el mismo
cuadro de dialogo cámbiate a la sección de
"Hotkeys". En esta parte aparecerán las teclas que
ya han sido asignadas dentro del archivo para ser
utilizadas como estimuladores, así como la lista de
valores de asignación de cada tecla. Para modificar
la lista de valores de la tecla "s" (la que estamos
utilizando), con el puntero colócate en el cuadro de
secuencia y escribe la nueva lista de valores.
Figura 4.26
Ahora puedes correr la simulación poco a poco
utilizando Simulation > Run For, o presionando la
tecla "F5". Y cada que lo desees presionas la tecla
"s" para cambiar el valor del vector "selec". En la
figura 4.24 se muestran los resultados de la
simulación.
A continuación se muestran las ecuaciones
obtenidas utilizando el estilo de descripción de
flujo de datos. Estas ecuaciones deben ser las
mismas para cualquier estilo que utilicemos, ya
que estamos describiendo el mismo multiplexor
sólo que de manera diferente y esto no implica que
las ecuaciones vayan a ser distintas. Cuando
compiles este multiplexor, en cualquiera de los tres
estilos, consulta las ecuaciones dentro del archivo
.rpt y verifica que sean iguales.
4.4.2 DESCRIPCIÓN COMPORTAMENTAL
LIBRARY ieee;
USE ieee.std_logic_1164.ALL;
USE work.std_arith.ALL;
ENTITY multiplexor IS
PORT(a: std_logic_vector
(3 DOWNTO 0);
b: std_logic_vector
(3 DOWNTO 0);
c: std_logic_vector
(3 DOWNTO 0);
d: std_logic_vector
(3 DOWNTO 0);
selec: std_logic_vector
(1 DOWNTO 0);
salida: OUT std_logic_vector
(3 DOWNTO 0));
END multiplexor;
ARCHITECTURE behavorial OF multiplexor IS
BEGIN
PROCESS(selec, a, b, c, d)
VARIABLE selec_int: integer;
BEGIN
selec_int := to_integer(selec);
CASE selec_int IS
WHEN 0 =>
salida <= a ;
WHEN 1 =>
salida <= b ;
WHEN 2 =>
salida <= c ;
WHEN 3 =>
salida <= d ;
WHEN OTHERS =>
NULL;
END CASE;
END PROCESS;
END behavorial;
IEC FRANCISCO JAVIER TORRES VALLE
66
CAPÍTULO IV: DESCRIPCIÓN DE CIRCUITOS DIGITALES
Dentro del proceso se hace uso de un objeto de
datos del tipo variable declarado como entero. Al
inicio del proceso se hace la asignación "selec_int
<= to_integer ( selec ) ;", esto es para poder usar
enteros en la instrucción CASE, de otra manera
tendríamos que indicar todos los casos utilizando
los valores naturales de un vector, es decir, "00",
"01", "10", y "11" para este ejemplo. Esto es
solamente para facilitar la descripción y no
significa que obtengamos una mejor síntesis del
código en el dispositivo. Es necesario que
"selec_int" sea una variable para que se le asigne
inmediatamente el valor actual del vector "selec" y
estemos describiendo el correctamente el
funcionamiento del multiplexor. Si quisiéramos
utilizar una señal en vez de una variable tenemos
que hacerlo de la siguiente manera.
ARCHITECTURE behavorial2 OF multiplexor IS
SIGNAL selec_int:integer;
BEGIN
selec_int <= to_integer( selec );
PROCESS(selec_int, a, b, c, d)
BEGIN
CASE selec_int IS
WHEN 0 =>
salida <= a ;
WHEN 1 =>
salida <= b ;
WHEN 2 =>
salida <= c ;
WHEN 3 =>
salida <= d ;
WHEN OTHERS =>
NULL;
END CASE;
END PROCESS;
END behavorial2;
Si observas con cuidado podrás ver que
seguimos describiendo exactamente los mismo.
Tanto el procesos como la asignación son de
naturaleza concurrente, por lo que selec_int tiene
siempre el valor actual de selec y lo convertimos a
un tipo entero para facilitar la descripción. Trata de
imaginar la asignación "selec_int <= to_integer (
selec )" como un circuito combinacional cuya
función es cambiar el tipo de datos con el estamos
manejando el vector selec y cuya salida (selec_int)
se la conectamos (piensa en señales como cables)
al proceso, que viene siendo otro circuito que
"procesa" la información que se le suministra y
obtiene finalmente la lógica de salida. A
continuación se muestra un diagrama a bloques
que trata de representar lo que estamos haciendo
en la arquitectura anterior (behavorial2).
Figura 4.27
4.4.3 DESCRIPCIÓN ESTRUCTURAL
Para la descripción estructural primero debemos
realizar la descripción de un multiplexor 2 a 1 para
después interconectar tres de ello como se muestra
en la figura siguiente.
Figura 4.28
Para realizar descripciones estructurales lo
recomendable es utilizar varios archivos .vhd, cada
uno para una entidad o paquete en particular. Crea
un proyecto para la descripción estructural del
multiplexor 4 a 1. Ahora crea un nuevo archivo de
texto y copia la siguiente descripción.
LIBRARY ieee;
USE ieee.std_logic_1164.ALL;
PACKAGE multiplexor IS
COMPONENT mux_2_a_1
PORT( in1: IN std_logic_vector
(3 DOWNTO 0);
in2: IN std_logic_vector
(3 DOWNTO 0);
sel: IN std_logic;
out1: OUT std_logic_vector
(3 DOWNTO 0));
IEC FRANCISCO JAVIER TORRES VALLE
67
CAPÍTULO IV: DESCRIPCIÓN DE CIRCUITOS DIGITALES
END COMPONENT;
END multiplexor;
LIBRARY ieee;
USE ieee.std_logic_1164.ALL;
ENTITY mux_2_a_1 IS
PORT (in1, in2: IN std_logic_vector
(3 DOWNTO 0);
sel: IN std_logic;
out1: OUT std_logic_vector
(3 DOWNTO 0));
END mux_2_a_1;
ARCHITECTURE data_flow OF mux_2_a_1 IS
BEGIN
out1 <= in1 WHEN sel = '0' ELSE
in2;
END data_flow;
Guarda este archivo como mux_2_a_1.vhd
dentro de la carpeta de trabajo del proyecto. Como
podrás ver estamos creando un paquete con
nombre "multiplexor" el cual se agrega a la librería
del proyecto work. Además se tienen que llamar
las librerías que se necesiten antes del paquete y
antes de la entidad. Ahora abre un nuevo archivo
de texto y copia en él la siguiente descripción.
-- mux_structural.vhd
LIBRARY ieee;
USE ieee.std_logic_1164.ALL;
USE work.multiplexor.ALL;
-- llamado al paquete multiplexor que se
-- encuentra en la librería
-- del proyecto
ENTITY multiplexor IS
PORT ( a,b,c,d: IN std_logic_vector
(3 DOWNTO 0);
selec: IN std_logic_vector
(3 DOWNTO 0);
salida: OUT std_logic_vector
(3 DOWNTO 0));
END multiplexor;
ARCHITECTURE structural OF multiplexor IS
SIGNAL salida1, salida2:
std_logic_vector(3 DOWNTO 0);
BEGIN
u1: mux_2_a_1 PORT MAP(a, b, selec(0),
salida1);
u2: mux_2_a_1 PORT MAP(c, d, selec(0),
salida2);
u3: mux_2_a_1 PORT MAP ( salida1,
salida2, selec(1), salida);
END structural;
Guarda este archivo como mux_structural.vhd,
y agrega ambos archivos al proyecto (Proyect > Add Files...). Compila el proyecto y comprueba
que las ecuaciones de salida siguen siendo las
mismas ya que estamos describiendo el mismo
funcionamiento. Dentro de la ventana de proyecto
en la "vista de jerarquía" (Hierarchy View) aparece
el orden en que los componentes están siendo
utilizados dentro del diseño jerárquico.
Figura 4.29
Una vez que has compilado y simulado este
multiplexor utilizando los tres estilos podrás ver
que no hay ninguna diferencia entre usar un estilo
u otro. Lo importante es describir el mismo
funcionamiento para obtener los mismo resultados.
De hecho, mientras estemos describiendo
exactamente lo mismo no importa el número de
líneas que se hagan, porque VHDL no es un
lenguaje de programación de software.
4.5 SUMADORES
El diseño de circuitos aritméticos eficientes es
un tema fundamental en el diseño de circuitos
digitales, por lo que es importante para el
diseñador estar familiarizado con las opciones
disponibles en la selección de algoritmos eficientes
en sus aplicaciones. Está práctica tiene por
objetivo familiarizarte en el diseño de circuitos
sumadores utilizando algoritmos eficientes en
VHDL.
4.5.1 SUMADOR TOTAL
El componente básico usado en la adición de
dos operandos es conocido como "sumador total".
Este sumador total representa el componente con
el cual podemos formar sumadores de cualquier
número de bits. A continuación se muestra la tabla
de funcionamiento y la representación esquemática
de un sumador total, y basándose en la tabla se
hará la descripción de sumador total en VHDL,
para posteriormente diseñar un circuito sumador de
4 bits utilizando un 22V10.
a, b: IN std_logic;
sum: OUT std_logic;
co: OUT std_logic);
(2 DOWNTO 0);
(1 DOWNTO 0);
"01" WHEN entradas = 1 ELSE
"01" WHEN entradas = 2 ELSE
"10" WHEN entradas = 3 ELSE
"01" WHEN entradas = 4 ELSE
"10" WHEN entradas = 5 ELSE
"10" WHEN entradas = 6 ELSE
"11" WHEN entradas = 7;
sum <= salidas(0);
co <= salidas(1) ;
END data_flow;
Si conoces las ecuaciones del circuito también
puedes utilizarlas para hacer la descripción.
ARCHITECTURE data_flow OF full_adder IS
BEGIN
sum <= a XOR b XOR C;
co <= (a AND b) OR
(a AND ci) OR
(b AND ci);
END data_flow;
Crea un nuevo proyecto en c:\vhdl_proj\prac5\
y llámalo sumador. Después crea un nuevo archivo
de texto y copia en él la descripción anterior.
Guarda el archivo de texto como full_adder.vhd
dentro de la carpeta de trabajo del proyecto.
Agrega el archivo al proyecto y compila el
proyecto utilizando la arquitectura data_flow. Abre
el reporte de compilación y observa las ecuaciones.
Ahora compila el proyecto utilizando la segunda
arquitectura data_flow. Vuele a abrir el proyecto y
observa las ecuaciones. ¿Por qué son las mismas
ecuaciones? porque estamos describiendo el
mismo funcionamiento y el estilo o el número de
líneas que utilices no importa siempre y cuando
este describiendo exactamente el mismo circuito.
4.5.2 SUMADOR DE CUATRO BITS
Para hacer la descripción utilizaremos cuatro
unidades del sumador total (u1 a u4) y las
conectaremos como se muestra continuación.
Figura 4.31
Abre un nuevo archivo de texto y copia en él la
siguiente descripción.
-- sumador de 4 bits utilizando
-- un sumador total
IEC FRANCISCO JAVIER TORRES VALLE
69
CAPÍTULO IV: DESCRIPCIÓN DE CIRCUITOS DIGITALES
LIBRARY ieee;
USE ieee.std_logic_1164.ALL;
USE work.std_arith.ALL;
USE work.adder.ALL;
ENTITY sumador IS
PORT (ci: IN std_logic;
a, b: IN std_logic_vector
(3 DOWNTO 0);
sum: OUT std_logic_vector
(3 DOWNTO 0);
co: OUT std_logic);
END sumador;
ARCHITECTURE structural OF sumador IS
SIGNAL c1, c2, c3: std_logic;
BEGIN
u1: full_adder PORT MAP (ci, a(0), b(0),
sum(0), c1 ) ;
u2: full_adder PORT MAP (c1, a(1), b(1),
sum(1), c2 ) ;
u3: full_adder PORT MAP (c2, a(2), b(2),
sum(2), c3);
u4: full_adder PORT MAP (c3, a(3), b(3),
sum(3), co);
END structural;
Guarda el archivo de texto en la carpeta de
trabajo del proyecto (c:\vhdl_proj\prac5) como
sumador.vhd. Compila el proyecto y observa lo
que sucede. Si estas usando la versión 5.0 o 5.2 de
WARP, la compilación te indicará los siguientes
errores.
Error: Logic equation has too many product
terms on signal co.
Error: Logic equation has too many product
terms on signal sum(2).
Error: Logic equation has too many product
terms on signal sum(3).
Abre el reporte de compilación y observa las
ecuaciones. La descripción no se pudo compilar
porque las ecuaciones tienen demasiadas sumas de
productos. El sintetizador de WARP siempre trata
de evitar retroalimentaciones para que el circuito
funcione con la mayor velocidad posible. Nosotros
deseamos que los nodos c1, c2, y c3 queden en un
pin de salida del 22V10 para de esta forma hacer
las conexiones como se muestran en el diagrama a
bloques del sumador de 4 bits. Para lograrlo basta
con describir la entidad como se muestra a
continuación.
ENTITY sumador IS
PORT ( ci: IN std_logic;
a, b: IN std_logic_vector
(3 DOWNTO 0);
sum: OUT std_logic_vector
(3 DOWNTO 0);
END sumador;
co, c1, c2, c3: INOUT std_logic);
De esta forma enviamos los nodos c1, c2, y c3 a
la salida de una macroceldas, en el caso del 22V10
a un pin de salida, y así evitamos que el
sintetizador elimine el nodo porque ya lo
declaramos como puerto.
4.5.3 SYNTHESIS OFF
Otra forma de evitar que se simplifique el nodo
es utilizando directivas de síntesis. En este caso
utilizaremos la directiva synthesis_off que está
incluida en WARP. Esta directiva nos permite
controlar la forma en que el sintetizador factoriza y
obtiene las ecuaciones de salida y de esta manera
evitar que la ecuación de un nodo se incluya en la
ecuación de otro nodo y así evitar
retroalimentaciones. Para entender como funciona
esta directiva observe el siguiente ejemplo.
ENTITY synthesis_off IS
PORT ( a, b, c: IN bit;
y: OUT bit);
END synthesis_off;
ARCHITECTURE simplifica_nodo OF
synthesis_off IS
SIGNAL x: bit;
BEGIN
x <= a AND b;
y <= x OR c;
END simplifica_nodo;
Cuando compilemos el archivo la ecuación del
nodo "x" se sustituye en la ecuación del puerto "y"
como se muestra abajo.
y = a * b + c
Lo que trataríamos de hacer entonces sería
declara el nodo "x" como puerto y no como señal
de interconexión, pero observa que es lo que
sucede.
x = a * b y = a * b + c
La ecuación de "x" se sigue sustituyendo en la
ecuación del puerto "y". Como habíamos
mencionado, el sintetizador siempre busca que el
circuito que le estamos describiendo funcione a la
mayor frecuencia posible. Al obtener las
ecuaciones de la forma anterior evitamos que
exista una retroalimentación desde el pin del
puerto "x", ya que si retroalimentamos tenemos
que esperar el tiempo de retardo de las compuertas
IEC FRANCISCO JAVIER TORRES VALLE
70
CAPÍTULO IV: DESCRIPCIÓN DE CIRCUITOS DIGITALES
que intervienen en las ecuaciones de "x" para que
después el valor de "x" se incorpore a las
ecuaciones del puerto "y". Por lo que el tiempo de
retardo para el puerto "y" sería mayor. Sin
embargo, aunque lo mejor es que nuestro circuito
funcione a mayor velocidad, en ocasiones
necesitamos que el nodo quede en una macrocelda
para que después se retroalimente hacia otras
ecuaciones. Ya sea por que lo necesitamos en el
diseño del circuito o por las limitaciones del
dispositivo programable. Es aquí donde las
directivas de síntesis nos permiten controlar el
proceso de síntesis. Observa el siguiente ejemplo
en el que se muestra como utilizar la directiva
synthesis_off.
ENTITY synthesis_off IS
PORT ( a, b, c: IN bit;
y: OUT bit);
END synthesis_off;
ARCHITECTURE no_simplifica_nodo OF
synthesis_off IS
SIGNAL x: bit;
ATTRIBUTE synthesis_off OF x: SIGNAL IS
true;
BEGIN
x <= a AND b;
y <= x OR c;
END no_simplifica_nodo;
Las ecuaciones que resultan del proceso de
síntesis son las siguientes.
/y = /c * /x
x = a * b
Ahora las ecuaciones tienen menos términos y
obligamos a que el nodo "x" quede en una
terminal, obligándolo a quedar en una macrocelda
para que después se retroalimente. Para el circuito
sumador de cuatro bits podemos utilizar esta
directiva de la siguiente forma.
ARCHITECTURE structural OF sumador IS
SIGNAL c1, c2, c3: std_logic;
ATTRIBUTE synthesis_off OF c1, c2, c3:
SIGNAL IS true;
BEGIN
u1: full_adder PORT MAP (ci, a(0), b(0),
sum(0), c1 ) ;
u2: full_adder PORT MAP (c1, a(1), b(1),
sum(1), c2 ) ;
u3: full_adder PORT MAP (c2, a(2), b(2),
sum(2), c3);
u4: full_adder PORT MAP (c3, a(3), b(3),
sum(3), co);
END structural;
Esta directiva sólo puede ser aplicada a señales,
para una explicación más detallada de esta y otras
directivas de síntesis consulta la ayuda del
programa (Help > Help Topics). Para diseño de
circuitos aritméticos y no aritméticos que sean
grandes o complejos, lo mejor es hacer
descripciones estructurales y utilizar las directivas
de síntesis cuando sea necesario.
4.6 REGISTROS
Existen dos métodos para implementar lógica
registrada en VHDL: mediante instanciación de
registros (utilizando librerías de componentes) o
utilizando procesos para realizar la descripción
comportamental del registro.
Por ejemplo, si se desea utilizar un registro D y
un contador de 4 bits, basta con realizar la
instanciación de dichos componentes después de
incluir los paquetes apropiados.
EJEMPLO
USE work.rtlpkg.ALL; -- paquetes de WARP
USE work.lpmpkg.ALL;
. . .
-- DSRFF: definido en rtlpkg
d1: dsrff PORT MAP(d, s, r, clk, q ;
-- Mcounter: definido en lpmpkg
c1: Mcounter GENERIC MAP (4)
PORT MAP (data, clk, one,
one, one, count, zero, rst,
zero, zero, zero, zero zero,
zero, OPEN);
Otra forma de registrar elementos es incluir un
proceso que sea sensible a las transiciones de una
señal de reloj o que espere una transición de reloj
utilizando la instrucción WAIT, de esta manera el
compilador asigna un registro a las señales
afectadas dentro del proceso. Existen 4 formas
básicas para describir registros, cada una de ellas
se explica a continuación.
PROCESS
BEGIN
WAIT UNTIL clk = '1';
. . .
END PROCESS;
Este proceso no tiene lista sensible, por lo que
comienza con una instrucción WAIT. Las
instrucciones dentro del proceso se comenzarán a
ejecutar cuando exista una transición positiva de la
IEC FRANCISCO JAVIER TORRES VALLE
71
CAPÍTULO IV: DESCRIPCIÓN DE CIRCUITOS DIGITALES
señal de reloj "clk". Todas las asignaciones a
señales dentro del proceso serán registradas, ya
que estas sólo cambian de valor en las transiciones
de reloj y lo retienen por lo menos hasta la
siguiente transición.
PROCESS (clk)
BEGIN
IF ( clk'event AND clk ='1' ) THEN
. . .
END IF;
END PROCESS;
Este proceso es sensible solamente a los
cambios en la señal "clk", como se indica en la
lista sensible. La primera instrucción, IF... THEN,
dentro del proceso restringe al resto de las
instrucciones a ser ejecutadas únicamente durante
la transición positiva de la señal "clk", por lo que
ahora también todas las señales que reciban una
asignación dentro de la instrucción IF... THEN
serán registradas y mantendrán dicho valor
recibido por lo menos hasta la siguiente transición
de reloj.
PROCESS(rst, clk)
BEGIN
IF rst = '1' THEN
. . .
ELSIF(clk'event AND clk='1') THEN
. . .
END IF;
END PROCESS;
Este proceso es sensible a los cambios en la
señal de reloj "clk" y la señal de reinicio "rst",
como es indicado en la lista sensible. Mediante
este método de descripción comportamental es
posible registrar señales y además tener un "reset"
asíncrono. La primera instrucción checa primero el
estado de la señal "rst". Las señales que son
asignadas dentro de esta porción de la estructura
IF... THEN... ELSIF, se asume que son registradas
asíncronamente con la señal de "reset" asignada, y
serán sintetizadas en registros con capacidad para
realizar dicha acción. Si la condición de "reset" no
se cumple, el resto de la instrucción IF... THEN...
ELSIF, funciona como el proceso explicado
anteriormente.
PROCESS(rst, pst, clk)
BEGIN
IF rst = '1' THEN
. . .
ELSIF pst = '1' THEN
. . .
ELSIF (clk'event AND clk='1') THEN
. . .
END IF;
END PROCESS;
Este proceso es sensible a los cambios en la
señales "clk", "rst" y "pst", como se indica en la
lista sensible. De esta forma es posible realizar la
descripción de registros con "preset" y "reset"
asíncronos. La primera instrucción dentro del
proceso checa el estado de la señal "rst". Todas las
señales que son asignadas dentro de la primera
porción de la estructura, se asume que serán
registradas mediante la señal de "rst" asíncrono. La
segunda condición checa el estado de la señal
"pst", y todas las señales que sean asignadas dentro
de esta porción del proceso son registradas
asíncronamente mediante la señal de "preset"
asíncrono "pst". Si las dos primeras condiciones no
se cumplen, el resto de la instrucción IF... THEN...
ELSIF, representa el funcionamiento síncrono del
registro.
E
JEMPLO
A continuación se muestra una forma de realizar
la descripción de un registro de 32 bits con "reset"
asíncrono.
PROCESS(r, clk2)
BEGIN
IF (r = '1') THEN
q <= x"123DEABC" ;
ELSIF (clk2'event AND clk2='1') THEN
q <= d;
END IF;
END PROCESS;
Asumiendo que "q" y "d" son declarados como
señales o puertos de 32 bits, entonces este código
ejemplifica la implementación de un registro de 32
bits con d(i) como entrada, q(i) como salida, "clk2"
como la señal de reloj, y "r" como la señal de
"reset" asíncrono para algunos registros y también
como señal de "preset" asíncrono para otros. Esto
significa que cuando se cumple la condición: r =
'1', la asignación q <= x"ABC123DE" provocará
que algunos registros sean puestos en alto mientras
que otros van a quedar en un estado de cero lógico.
EJEMPLOS
A continuación realice la descripción de los
siguientes registros de acuerdo con su tabla de
funcionamiento.
IEC FRANCISCO JAVIER TORRES VALLE
72
CAPÍTULO IV: DESCRIPCIÓN DE CIRCUITOS DIGITALES
REGISTRO NO. 1
Elabore la descripción del registro utilizando un
22V10 y posteriormente trate de implementar la
descripción en un 16V8, simule la descripción y
obtenga sus conclusiones.
T
ABLA DE FUNCIONAMIENTO
ENTRADAS SALIDAS
reset d clk q
1 0 transición positiva 0
1 1 transición positiva 1
0 - - 0
ENTITY reg1 IS
PORT(reset: IN bit;
d: IN bit;
clk: IN bit;
q: OUT bit);
END reg1;
ARCHITECTURE areg OF reg1 IS
BEGIN
PROCESS(clk, reset, d)
BEGIN
IF reset = '0' THEN
q <= '0';
ELSIF clk'event AND clk = '1' THEN
q <= d;
END IF;
END PROCESS;
END areg;
REGISTRO NO. 2
Elabore la descripción del registro utilizando un
22V10 y posteriormente utilice un 16V8, simule la
descripción en ambos casos y obtenga sus
conclusiones.
TABLA DE FUNCIONAMIENTO
ENTRADAS SALIDAS
reset d clk q
1 0 transición positiva 0
1 1 transición positiva 1
0 - transición positiva 0
ENTITY reg2 IS
PORT(reset, d,clk: IN bit;
q: OUT bit);
END reg2;
ARCHITECTURE areg2 OF reg2 IS
BEGIN
PROCESS(clk, reset, d)
BEGIN
IF clk'event AND clk = '1' THEN
IF reset = '0' THEN
q <= '0';
ELSE
q <= d;
END IF;
END IF;
END PROCESS;
END areg2;
REGISTRO NO. 3
Elabore la descripción del siguiente registro
utilizando un 22V10, simule la descripción y
obtenga sus conclusiones.
TABLA DE FUNCIONAMIENTO
ENTRADAS SALIDAS
enable dclk q
1 0 transición positiva 0
1 1 transición positiva 1
0 -- Z
LIBRARY ieee;
USE ieee.std_logic_1164.ALL;
ENTITY reg2 IS
PORT(enable: IN std_logic;
d: IN std_logic;
clk: IN std_logic;
q: OUT std_logic);
END reg2;
ARCHITECTURE areg2 OF reg2 IS
SIGNAL q_tmp: std_logic;
BEGIN
-- lógica registrada
PROCESS(clk, reset, d)
BEGIN
IF clk'event AND clk = '1' THEN
q_tmp <= d;
END IF;
END IF;
END PROCESS;
-- buffer
q <= q_tmp WHEN enable = '1' g
'Z';
END areg2;
IEC FRANCISCO JAVIER TORRES VALLE
73
CAPÍTULO IV: DESCRIPCIÓN DE CIRCUITOS DIGITALES
4.7 CONTADORES
La finalidad de un contador es computar el
número de ocurrencias de un evento que se da en
intervalos aleatorios o uniformes. En los siguientes
ejemplos se muestran diferentes tipos de
contadores y la forma más común de describir su
comportamiento con VHDL.
EJEMPLOS
LIBRARY ieee;
USE ieee.std_logic_1164.ALL;
USE ieee.numeric_std.ALL;
ENTITY counter IS
PORT( clk, load: IN std_logic;
data: IN unsigned(3 DOWNTO 0);
count: BUFFER unsigned(3 DOWNTO 0));
END counter;
ARCHITECTURE archcounter OF counter IS
BEGIN
PROCESS( clk, load, count, data )
BEGIN
IF( clk'event AND clk= '1' ) THEN
IF load = ’1’ THEN
count <= data;
ELSE
count <= count + 1;
END IF;
END IF;
END PROCESS;
END archcounter;
La instrucción USE ieee.numeric_std.ALL es
para incluir el tipo de datos unsigned, así como las
funciones aritméticas y lógicas que nos permiten
manipular objetos de datos que manejen este tipo.
En este ejemplo en particular nos interesa la
función "+" definida para ser utilizada con el tipo
unsigned y enteros. Ya que el operador "+" en
VHDL originalmente está definido únicamente
para ser utilizado con enteros. La arquitectura que
describe al contador utiliza el estilo
comportamental. En este diseño el contador
funciona ascendentemente y, además, realiza carga
paralela de datos síncronamente con la señal de
reloj dependiendo del valor del puerto de control
"load".
Dentro del proceso, la instrucción IF ( clk’event
AND clk= ’1’ ) THEN... implica que el
funcionamiento del contador, conteo y carga
paralela, tome lugar durante la transición positiva
de la señal de reloj "clk". La siguiente instrucción
IF... THEN... define la operación de conteo o de
carga paralela del circuito dependiendo de la
condición: load = '1'. A continuación se expone un
contador similar pero con reset síncrono.
LIBRARY ieee;
USE ieee.std_logic_1164.ALL;
USE ieee.numeric_std.ALL;
ENTITY counter IS
PORT (clk, load, reset: IN std_logic;
data: IN unsigned(3 DOWNTO 0);
count: BUFFER unsigned(3 DOWNTO 0));
END counter;
ARCHITECTURE archcounter OF counter IS
BEGIN
PROCESS(clk, reset, load, count, data)
BEGIN
IF ( clk’event AND clk= '1' ) THEN
IF reset = '1' THEN
count <= (OTHERS => '0');
ELSIF load = '1' THEN
count <= data;
ELSE
count <= count + 1;
END IF;
END IF;
END PROCESS;
END archcounter;
En este ejemplo se describe un contador
ascendente, con reset síncrono dependiendo de la
entrada "reset", además, con capacidad de carga
paralela de datos mediante el puerto de control
"load". Al igual que el ejemplo anterior, la
instrucción IF (clk'event AND clk = '1' ) aparece al
principio e implica que todas las operaciones del
contador se ejecuten durante la transición positiva
de la señal de reloj "clk". La subsecuente
instrucción IF describe la operación de reset
síncrono durante la transición positiva del reloj. El
resto de las operaciones, el conteo y la carga
paralela, son descritas en las siguientes cláusulas
ELSIF y ELSE dentro de la misma instrucción IF,
por lo que podemos observar que la operación de
reset tiene precedencia sobre las operaciones de
carga y conteo. Así, si reset no es '1', entonces la
operación de conteo depende de la señal "load".
Como podemos ver las operaciones de carga y
conteo son identificas al contador en el ejemplo
anterior.
Ahora se expone a continuación un contador
con reset asíncrono y con capacidad para salida en
alta impedancia.
LIBRARY ieee;
USE ieee.std_logic_1164.ALL;
USE ieee.numeric_std.ALL;
ENTITY cnt_oe IS
PORT(clk, reset, oe: IN std_logic;
count_io: INOUT std_logic_vector
(7 DOWNTO 0));
IEC FRANCISCO JAVIER TORRES VALLE
74
CAPÍTULO IV: DESCRIPCIÓN DE CIRCUITOS DIGITALES
END ldcnt;
ARCHITECTURE arch_cnt_oe OF cnt_oe IS
SIGNAL count: std_logic_vector
(7 DOWNTO 0);
BEGIN
PROCESS(clk, reset, count)
BEGIN
IF reset = '0' THEN
count <= (OTHERS => '0');
ELSIIF ( clk’event AND clk=’1’ ) THEN
count <= count + 1;
END IF;
END PROCESS;
count_io <= count WHEN oe = ’1’ ELSE
(OTHERS => 'Z');
END arch_cnt_oe;
Este diseño desempeña un contador ascendente
con reset asíncrono. Cuando se cumple la
condición: reset = '0', se produce un reset
asíncrono en el contador. Cuando esta condición
no se satisface, la operación de conteo funciona
síncronamente con la señal de reloj "clk". Además,
independientemente de las señal de reset, el uso de
los buffers de tres estados en los pines de I/O es
posible mediante el uso del puerto de entrada "oe".
Así, cuando se satisface la condición oe = '1', el
conteo es conducido hacia los pines de salida. De
lo contrario presentarán alta impedancia en los
pines del circuito. Conceptualmente, el código en
VHDL del contador se implementa de la siguiente
manera.
1 0 transición positiva descendente
0 - - 0
ENITTY counter IS
PORT(reset: IN bit;
ud: IN bit;
clk: IN bit;
conteo: INOUT integer RANGE 0 TO 15
);
END counter;
ARCHITECTURE counter OF counter IS
BEGIN
PROCESS(reset,ud,clk)
BEGIN
IF reset = '1' THEN
conteo <= 0;
ELSIF (clk'event AND clk = '1') THEN
IF ud = '1' THEN
conteo <= conteo + 1;
ELSE
conteo <= conteo - 1;
END IF;
END IF;
END counter;
CONTADOR NO. 2
ENTRADAS SALIDAS
reset up_downclk conteo
1 1 transición positiva ascendente
Figura 4.32
A continuación se elabore la descripción en
VHDL para los siguientes contadores de cuatro
bits de acuerdo a su tabla de funcionamiento y
posteriormente realice las simulaciones. Elija el
dispositivo que más convenga.
CONTADOR NO. 1
ENTRADAS SALIDAS
reset up_down clk conteo
1 1 transición positiva ascendente
IEC FRANCISCO JAVIER TORRES VALLE
1 0 transición positiva descendente
0 - transición positiva 0
ENITTY counter IS
PORT(reset: IN bit;
END counter;
ARCHITECTURE counter OF counter IS
BEGIN
END counter;
ud: IN bit;
clk: IN bit;
conteo: INOUT integer RANGE 0 TO 15
);
PROCESS(reset,ud,clk)
BEGIN
IF (clk'event AND clk = '1') THEN
IF reset = '1' THEN
conteo <= 0;
ELSIF ud = '1' THEN
conteo <= conteo + 1;
ELSE
conteo <= conteo - 1;
END IF;
END IF;
75
CAPÍTULO IV: DESCRIPCIÓN DE CIRCUITOS DIGITALES
CONTADOR NO. 3
ENTRADAS SALIDAS
reset oe up_down clk conteo
1 1 1 transición positiva ascendente
1 1 0 transición positiva descendente
0 1 - - 0
0 0 - - Z
** NOTA
Aunque se encuentre la salida del circuito en
alta impedancia, el conteo y reset asíncrono deben
seguir funcionando internamente.
LIBRARY ieee;
USE ieee.std_logic_1164.ALL;
USE ieee.numeric_std.ALL;
ENITTY counter IS
PORT(reset: IN std_logic;
ud: IN std_logic;
oe: IN std_logic;
clk: IN std_logic;
conteo: INOUT unsigned (3 DOWNTO 0)
END counter;
ARCHITECTURE counter OF counter IS
BEGIN
-- instanciación de los buffers
END counter;
);
SIGNAL count_tmp: unsigned(3 DOWNTO 0);
PROCESS(reset,ud,clk)
BEGIN
IF reset = '1' THEN
count_tmp <= (OTHERS => '0');
ELSIF (clk'event AND clk = '1') THEN
IF ud = '1' THEN
count_tmp <= count_tmp + 1;
ELSE
count_tmp <= count_tmp - 1;
END IF;
END IF;
conteo <= count_tmp WHEN oe = '1' ELSE
(OTHERS 'Z');
CONTADOR NO. 4
ENTRADAS SALIDAS
reset oe up_down clk conteo
1 1 1
transición
positiva
ascendente
0-9
1 10
transición
positiva
descendente
9-0
0 1- - 0
0 0- - Z
** NOTA
Aunque se encuentre la salida del circuito en
alta impedancia, el conteo y reset asíncrono deben
seguir funcionando internamente. En el momento
de cambio de sentido ascendente/descendente, el
contador no debe de iniciar la cuenta, por ejemplo:
si el contador está funcionando ascendentemente y
se encuentra en el número 5 cuando se cambia a
descendente, en la siguiente transición positiva se
debe continuar la cuenta con un 4, después un 3...
etc.
LIBRARY ieee;
USE ieee.std_logic_1164.ALL;
USE ieee.numeric_std.ALL;
ENITTY counter IS
PORT(reset: IN std_logic;
ud: IN std_logic;
oe: IN std_logic;
clk: IN std_logic;
conteo: INOUT unsigned (3 DOWNTO 0)
END counter;
ARCHITECTURE counter OF counter IS
BEGIN
-- instanciación de los buffers
END counter;
);
SIGNAL count_tmp: unsigned(3 DOWNTO 0);
PROCESS(reset,ud,clk)
BEGIN
IF reset = '1' THEN
count_tmp <= (OTHERS => '0');
ELSIF (clk'event AND clk = '1') THEN
IF ud = '1' THEN
count_tmp <= count_tmp + 1;
IF count_tmp = 9 THEN
count_tmp <= (OTHERS => '0');
END IF;
ELSIF ud = '0' THEN
count_tmp <= count_tmp - 1;
IF count_tmp = 0 THEN
count_tmp <= "1001";
END IF;
END IF;
END IF;
conteo <= count_tmp WHEN oe = '1' ELSE
(OTHERS 'Z');
IEC FRANCISCO JAVIER TORRES VALLE
76
CAPÍTULO IV: DESCRIPCIÓN DE CIRCUITOS DIGITALES
4.8 ALU DE CUATRO BITS
Realice la descripción en VHDL para la
siguiente unidad aritmético - lógica de acuerdo a
la tabla de funcionamiento utilizando un 22V10. El
circuito consta de 2 bus de entrada "a" y "b", de 4
bits cada uno y mediante el bus "s", de 3 bits, se
selecciona la operación a realizar en la ALU.
Dicha operación se realiza combinacionalmente y
en el momento que ocurre una transición positiva
en la señal de reloj el resultado de dicha operación
se registra en los flip-flop's tipo D del 22V10.
Además, la salida registrada será conducida hacia
los pines de salida (I/O pads) únicamente cuando
se habiliten los buffers de tres estados mediante la
entrada de control "oe", de lo contrario deberán
encontrarse en alta impedancia.
ENTRADAS SALIDAS
s(2) s(1) s(0) clk oe outputcout
0 0 0
0 0 1
0 1 0
0 1 1
1 0 0
1 0 1
1 1 0
1 1 1
transición
positiva
transición
positiva
transición
positiva
transición
positiva
transición
positiva
transición
positiva
transición
positiva
transición
positiva
- - - - 1 Z 0
** NOTA
b' = NOT b
4.8.1 DESCRIPCIÓN ESTRUCTURAL
La descripción se realiza utilizando tres
archivos, los cuales contienen: la entidad TOP, el
módulo y el paquete respectivamente. El módulo
realiza todas las operaciones dela ALU pero
a AND
0
b
0
0 a OR b0
a XOR
0
b
0
0 NOT a0
0 a + 0 0
0 a + b
0 a + b'
acarreo de
la suma
acarreo de
la suma
0 a - 1 0
solamente con un bit, y en la entidad TOP se
realiza la interconexión de cuatr de estos módulos
para formar la ALU de cuatro bits.
NTIDAD TOP
E
LIBRARY ieee;
USE ieee.std_logic_1164.ALL;
USE work.modulo_alu.ALL;
ENTITY alu IS
PORT(a: IN std_logic_vector(3 DOWNTO 0);
b: IN std_logic_vector(3 DOWNTO 0);
cin: IN std_logic ;
clk: IN std_logic ;
reset: IN std_logic ;
oe: IN std_logic ;
s: IN std_logic_vector(2 DOWNTO 0);
cout: OUT std_logic;
output: OUT std_logic_vector(3 DOWNTO 0)
);
END alu ;
ARCHITECTURE a_alu OF alu IS
SIGNAL c2, c3, c4: std_logic; SIGNAL salida_r: std_logic_vector
ATTRIBUTE synthesis_off OF c2, c3, c4:
BEGIN
x0: modulo PORT MAP(a(0), b(0), cin,
clk, reset, s, c2, salida_r(0));
x1: modulo PORT MAP(a(1), b(1), c2, clk,
reset, s, c3, salida_r(1));
x2: modulo PORT MAP(a(2), b(2), c3, clk,
reset, s, c4, salida_r(2));
x3: modulo PORT MAP(a(3), b(3), c4, clk,
reset, s, cout, salida_r(3));
-- instanciación de los biffers
output <= (OTHERS=>'Z') WHEN oe='1' ELSE
salida_r;
END a_alu;
(3 DOWNTO 0);
SIGNAL IS true;
MÓDULO
LIBRARY ieee ;
USE ieee.std_logic_1164.ALL;
ENTITY modulo IS
PORT (in1: IN std_logic;
in2: IN std_logic;
cin: IN std_logic;
clk: IN std_logic;
reset: IN std_logic;
selec: IN std_logic_vector(2 DOWNTO 0);
cout: OUT std_logic ;
salida_r: INOUT std_logic);
END modulo;
ARCHITECTURE a_modulo OF modulo IS
SIGNAL salida_comb: std_logic ;
BEGIN
PROCESS(in2, in1, selec, cin)
IEC FRANCISCO JAVIER TORRES VALLE
77
CAPÍTULO IV: DESCRIPCIÓN DE CIRCUITOS DIGITALES
CONSTANT uno: std_logic := '1'; BEGIN CASE selec ISWHEN o"0" =>
salida_comb <= in1 AND in2;
cout <= '0';
WHEN o"1" =>
salida_comb <= in1 OR in2;
cout <= '0';
WHEN o"2" =>
salida_comb <= in1 XOR in2;
cout <= '0';
WHEN o"3" =>
salida_comb <= NOT in1;
cout <= '0';
WHEN o"4" =>
salida_comb <= in1;
cout <= '0' ;
WHEN o"5" =>
salida_comb<=in2 XOR in1 XOR cin;
cout <= ( in1 AND cin ) OR
( in2 AND cin ) OR
( in2 AND in1 ); WHEN o"6" =>
salida_comb<= (NOT in2) XOR in1
XOR cin;
cout <= (in1 AND cin) OR
(( NOT in2 ) AND cin) OR
(( NOT in2 ) AND in1); WHEN o"7" =>
salida_comb<=uno XOR in1 XOR cin;
cout <= ( in1 AND cin) OR
(uno AND cin ) OR
( uno AND in1 ) ; WHEN OTHERS => NULL; END CASE; END PROCESS;
PROCESS( salida_comb, clk, reset ) BEGIN IF rising_edge( clk ) THEN
salida_r <= salida_comb;
END IF; END PROCESS;
END a_modulo;
PAQUETE
LIBRARY ieee;
USE ieee.std_logic_1164.ALL;
PACKAGE modulo_alu IS
COMPONENT modulo PORT(in1: IN std_logic;
in2: IN std_logic ;
cin: IN std_logic ;
clk: IN std_logic ;
reset: IN std_logic ;
selec: IN std_logic_vector(2 DOWNTO 0);
cout: OUT std_logic ;
salida_r: INOUT std_logic ) ; END COMPONENT; END modulo_alu;
4.8.2 DESCRIPCIÓN
COMPORTAMENTAL
LIBRARY ieee ;
USE ieee.std_logic_1164.ALL;
USE ieee.numeric_std.ALL;
ENTITY aluIS
PORT (in1: IN unsigned(3 DOWNTO 0);
in2: IN unsigned(3 DOWNTO 0);
cin, clk: IN std_logic;
oe: IN std_logic;
reset: IN std_logic;
selec: IN integer RANGE 0 TO 7;
cout: OUT std_logic ;
salida: INOUT unsigned(3 DOWNTO 0);
);
END alu;
ARCHITECTURE alu OF alu IS
SIGNAL comb, reg: unsigned(3 DOWNTO 0); SIGNAL c: unsigned(4 DOWNTO 0); SIGNAL c1,c2,c3
FOR i IN in1'range LOOP CASE selec ISWHEN 0 =>
comb(i) <= in1(i) AND in2(i);
c(i+1) <= '0';
WHEN 1 =>
comb(i) <= in1(i) OR in2(i);
c(i+1) <= '0';
WHEN 2 =>
comb(i) <= in1(i) XOR in2(i);
c(i+1) <= '0';
WHEN 3 =>
comb(i) <= NOT in1(i);
c(i+1) <= '0';
WHEN 4 =>
comb(i) <= in1(i);
c(i+1) <= '0' ;
WHEN 5 =>
comb(i) <= in2(i) XOR in1(i) XOR
c(i);
c(i+1) <= (in1(i) AND c(i)) OR
(in2(i) AND c(i)) OR
(in2(i) AND in1(i); WHEN 6 =>
comb(i) <= (NOT in2(i)) XOR
in1(i) XOR c(i);
c(i+1) <= (in1(i) AND c(i)) OR
((NOT in2(i)) AND c(i)) OR
((NOT in2(i)) AND in1(i)); WHEN 7 =>
comb(i) <= uno(i) XOR in1(i)
XOR c(i);
c(i+1) <= (in1(i) AND c(i)) OR
IEC FRANCISCO JAVIER TORRES VALLE
78
CAPÍTULO IV: DESCRIPCIÓN DE CIRCUITOS DIGITALES
(uno(i) AND c(i)) OR
(uno(i) AND in1(i)) ;
WHEN OTHERS => NULL; END CASE;
END LOOP;
END PROCESS;
PROCESS( comb, clk, reset ) BEGIN IF rising_edge( clk ) THEN
reg <= comb;
END IF; END PROCESS;
salida <= reg WHEN oe = '0' ELSE
(OTHERS => 'Z');
cout <= '0' WHEN selec = 7 ELSE
c(4);
END alu;s
4.9 MÁQUINAS DE ESTADO
Una máquina de estados es un circuito
secuencial que es diseñado para seguir un patrón
de funciones previamente definidas. Existen dos
tipos de máquinas de estado: Mealy y Moore. En
una máquina de estados de Moore, las salidas están
únicamente en función del estado presente. Si es
una máquina de estados de Mealy, las salidas están
en función del estado presente y de las entradas.
Una máquina de estados se compone de tres partes:
1. R
EGISTRO DEL ESTADO PRESENTE.
Este registro es un conjunto de n flip-flops
sincronizados con la misma señal de reloj
para almacenar el estado presente en la
máquina.
2. L
ÓGICA COMBINACIONAL PARA GENERAR EL
SIGUIENTE ESTADO
.
3. Una máquina de estados solamente puede
estar en un estado a un tiempo dado, es
decir no puede hacer dos cosas a la vez. La
lógica combinacional permite que en cada
transición activa del reloj, la máquina vaya
de un estado a otro o se mantenga en el
mismo dependiendo de las condiciones
definidas por el diseñador.
4. L
ÓGICA COMBINACIONAL DE SALIDA.
Las salidas normalmente están en función del
estado presente y/o también en función de las
entradas (Máquina de Estados de Mealy). Es
común que en una máquina de estados de
Moore se desee que las salidas estén en
función del siguiente estado en vez de utilizar
el actual cuando se utiliza una señal de reloj
de alta frecuencia.
A continuación se muestran las estructuras para
máquinas de estados de Moore y Mealy
Figura 4.33 Máquina de Estados de Moore
Figura 4.34 Máquina de Estados de Mealy
IEC FRANCISCO JAVIER TORRES VALLE
79
CAPÍTULO IV: DESCRIPCIÓN DE CIRCUITOS DIGITALES
El uso del reset garantiza un comportamiento
seguro del circuito. Esto asegura que la máquina
siempre comience en un estado conocido y válido
antes de la primera transición de reloj. Si no se
utiliza el reset, no existe una forma de predecir el
valor inicial de los flip-flops del registro de estado
durante el encendido del dispositivo en el que se
implementa la máquina de estados. Además existe
la posibilidad de que la máquina comience en un
estado no válido y entonces nunca comenzaría a
ESTADOS
S0 000 00000001 000
S1 001 00000010 001
S2 010 00000100 011
S3 011 00001000 010
S4 100 00010000 110
S5 101 00100000 100
S6 110 01000000 101
S7 111 10000000 111
SECUENCIA
BINARÍA
Cuando se implementa una máquina de estados
en un FPGA se prefiere la codificación ONE
HOT ENCODING porque estos dispositivos
cuentan con bastantes flip-flops y una máquina de
estados codificada de esta manera es más
funcionar. Por lo que el reset siempre debe ser
implementado en una máquina de estados para
asegurar un correcto funcionamiento. Se prefiere el
uso de reset asíncrono sobre el síncrono porque un
reset asíncrono no requiere ser implementado
mediante ecuaciones, minimizando la lógica
combinacional del circuito. A continuación se
muestran las tres formas más comunes de codificar
los estados en una máquina, suponiendo que utiliza
ocho estados:
ONE HOT
ENCODIG
SECUENCIA
GRAY
eficiente y las herramientas de síntesis generan
circuitos con área optimizada y mejor desempeño.
Aunque también es posible que el usuario asigne
los valores de los estado como mejor convenga.
IEC FRANCISCO JAVIER TORRES VALLE
80
CAPÍTULO IV: DESCRIPCIÓN DE CIRCUITOS DIGITALES
EJEMPLO
Figura 4.35 Diagrama de Estados
-- Máquina de Estados del tipo Mealy
LIBRARY ieee;
USE ieee.std_logic_1164.ALL;
ENTITY mealy IS
PORT ( clk: IN std_logic;
reset: IN std_logic;
entradas: IN std_logic_vector
(3 DOWNTO 0);
salidas: OUT std_logic_vector
(3 DOWNTO 0)) ;
END mealy;
ARCHITECTURE comportamental OF mealy IS
-- ONE HOT ENCODED state machine
TYPE states IS (S0, S1, S2, S3, S4);
ATTRIBUTE enum_encoding OF states: TYPE IS
-- lógica combinacional de salida
salidas <= "1000" WHEN (state= S1) ELSE
"0110" WHEN (state=S1 AND
entradas="1001") ELSE
"1100" WHEN (state=S2) ELSE
"0000" WHEN (state= S2 AND
entradas="0010") ELSE
"0011" WHEN (state=S3) ELSE
"0111" WHEN (state=S4) ELSE
"0101" WHEN (state= S4 AND
entradas="0110") ELSE
"1011"; -- asignación en el estado de
-- reset S0
END comportamental;
EJEMPLO
Elabore la descripción en VHDL del siguiente
problema mediante máquina de estados definiendo
su diagrama de estados, frecuencia de trabajo y
dispositivo a utilizar. Se desea diseñar el circuito
de control para lavadora de la siguiente figura.
Figura 4.36
El ciclo de lavado es de la siguiente manera:
1. - Suponiendo que esta vacía al principio,
cuando se presione el botón de "INICIO", activo
en ALTO, se enciende la válvula de agua fría.
2. - En el momento que el nivel del agua llegue
al SENSOR, activo en ALTO, se apaga la válvula
de agua fría y se enciende la de agua caliente
durante dos minutos.
3. - Después se apaga la válvula de agua caliente
y se enciende el motor durante cuatro minutos.
4. - Transcurridos los cuatro minutos, se apaga
el motor y se enciende la válvula de desagüe
durante tres minutos.
5. - Una vez que se ha vaciado la lavadora se
cierra la válvula de desagüe y el ciclo de lavado
comenzará nuevamente cuando se vuelva a
presionar el botón de inicio.
LIBRARY ieee;
USE ieee.std_logic_1164.ALL;
ENTITY lavadora IS
PORT( clk: IN std_logic; inicio: IN std_logic; sensor: IN std_logic;
END lavadora;
ARCHITECTURE state_machine OF lavadora IS
TYPE states IS
SIGNAL state, nex_state: states;
SIGNAL outputs: std_logic_vector
CONSTANT vaf_on: std_logic_vector
CONSTANT vac_on: std_logic_vector
CONSTANT mot_on: std_logic_vector
CONSTANT des_on: std_logic_vector
CONSTANT all_off: std_logic_vector
BEGIN
-- REGISTRO DE ESTADO
PROCESS(clk, inicio, next_state)
BEJÍN
END PROCES;
-- LÓGICA COMBINACIONAL PARA DEFINIR EL
vaf: OUT std_logic;
vac OUT std_logic;
motor: OUT std_logic;
des: OUT std_logic
);
(S0,S1,S2,S3,S4,S5,S6,S7,S8,S9,S10);
(3 DOWNTO 0);
(3 DOWNTO 0):="0001";
(3 DOWNTO 0):="0010";
(3 DOWNTO 0):="1000";
(3 DOWNTO 0):="0100";
(3 DOWNTO 0):="0000";
IF inicio = '0' THEN
state <= S10; -- todo apagado
ELSIF clk'event AND clk = '1' THEN
state <= next_state;
END IF;
IEC FRANCISCO JAVIER TORRES VALLE
81
CAPÍTULO IV: DESCRIPCIÓN DE CIRCUITOS DIGITALES
-- SIGUIENTE ESTADO
PROCESS(clk, state, sensor)
BEGIN
CASE state IS
WHEN S0 =>
ELSIF sensor='1' THEN
next_state <= S1;
END IF;
next_state <= S2;
WHEN S2 =>
next_state <= S3;
WHEN S3 =>
next_state <= S4;
WHEN S4 =>
next_state <= S5;
WHEN S5 =>
next_state <= S6;
WHEN S6 =>
next_state <= S7;
WHEN S7 =>
next_state <= S8;
WHEN S8 =>
next_state <= S9;
WHEN S9 =>
next_state <= S10;
WHEN S10 =>
next_state <= S10;
WHEN OTHERS => NULL; END CASE; END IF; END PROCESS;
-- LÓGICA COMBINACIONAL DE SALIDA
outputs <= all_off WHEN (state=S10) ELSE
END state_machine;
IF sensor='0' THEN
next_state <= S0;
WHEN S1 =>
IF inicio = '0' THEN
ELSE
next_state <= S0;
END IF;
vaf_on WHEN (state=S0 AND
sensor='0') ELSE
vac_on WHEN (state=S1) ELSE
vac_on WHEN (state=S2) ELSE
mot_on WHEN (state=S3) ELSE
mot_on WHEN (state=S4) ELSE
mot_on WHEN (state=S5) ELSE
mot_on WHEN (state=S6) ELSE
des_on WHEN (state=S7) ELSE
des_on WHEN (state=S8) ELSE
des_on WHEN (state=S9) ELSE
all_off;
IEC FRANCISCO JAVIER TORRES VALLE
82
CAPÍTULO V: IMPLEMENTACIÓN FILTROS DIGITALES EN FPGA's
V
IMPLEMENTACIÓN DE
V
IEC FRANCISCO JAVIER TORRES VALLE
FILTROS DIGITALES
EN FPGA'S
83
CAPÍTULO V: IMPLEMENTACIÓN FILTROS DIGITALES EN FPGA's
5.1 INTRODUCCIÓN
Un FPGA es un dispositivo cuyas características
pueden ser modificadas, manipuladas o
almacenadas mediante programación. La
arquitectura de un FPGA (Field Programmable
Gate Array) consiste en arreglos de múltiples
celdas lógicas las cuales se comunican unas con
otras mediante canales de conexión verticales y
horizontales. Cada celda lógica contiene arreglos
de compuertas lógicas AND y OR, así como un
número definido de registros y multiplexores.
Mediante estos recursos es posible implementar
funciones matemáticas y de almacenamiento de
datos. Dada la gran densidad de compuertas con
las que cuenta un FPGA, es posible implementar
sistemas digitales muy complejos, entre los que
destaca el filtrado digital. Además, en un FPGA es
posible realizar modificaciones de último minuto
sin que esto implique grandes alteraciones en el
hardware o en el software.
5.2 ANTECEDENTES
En las últimas tres décadas la ingeniería se ha
visto revolucionada en el campo del procesamiento
digital de señales, donde los filtros digitales
forman un apartado muy importante, ya que estos
se encuentran en una extensa gama de
aplicaciones. Desde procesamiento de audio y
vídeo hasta control de motores; donde la
utilización del filtrado digital incluye ventajas
como:
1) El ancho de banda y la calidad del filtro no
están necesariamente relacionadas.
2) Al utilizar dispositivos programables, la
función de transferencia de el filtro puede
ser transformada sin más modificaciones
que el cambio de los coeficientes en
memoria.
3) Variables como temperatura o alteraciones
en el voltaje no afectan la funcionalidad
del circuito.
4) El costo de la aplicación es relativamente
bajo.
5.3 MARCO TEÓRICO
El término filtro se utiliza comúnmente para
describir un dispositivo que discrimina aquello que
pasa a través de él. Así, por ejemplo, un filtro de
aire permite que sólo pase aire a través de éste,
evitando que las partículas de polvo presentes en el
aire lo atraviesen. Un filtro digital es un sistema
lineal e invariante en el tiempo (LTI) que modifica
el espectro en frecuencia de la señal de entrada
X(w), según la respuesta que tenga en frecuencia
H(w) (conocida como función de transferencia),
para dar lugar a una señal de salida con espectro:
Y(w) = H(w) * X(w). En cierto sentido, H(w)
actúa como una función de ponderación o función
de conformación espectral para las diferentes
componentes frecuenciales de la señal de entrada.
Los sistemas LTI se clasifican como: FIR (finite
impulse response) que se caracterizan pos ser
sistemas no recursivos, e IIR (infinite impulse
response) que se distinguen por tener
retroalimentación en la señal salida.
5.3.1 FILTROS FIR
Un filtro FIR de orden M se describe mediante
la ecuación en diferencias: y(n) = b0 x(n) + b1 x(n-
1) + b2 x(n-2) + bM x(n-M), donde la secuencia
bk son los coeficientes del filtro. En este tipo de
filtrado no existe retroalimentación. Además, la
respuesta al impulso H(w), es de duración finita ya
que si la entrada se mantiene en cero durante M
periodos consecutivos la salida también será cero.
Algunas de las ventajas de este tipo de filtros son
las siguientes:
1) Un filtro FIR puede ser diseñado para
tener fase lineal.
2) Siempre son estables porque son hechos
únicamente con ceros en el plano
complejo.
3) Los errores por desbordamiento no son
problemáticos porque la suma de
productos en un filtro FIR es
desempeñada por un conjunto finito de
datos.
4) Un filtro FIR es fácil de comprender e
implementar.
IEC FRANCISCO JAVIER TORRES VALLE
84
CAPÍTULO V: IMPLEMENTACIÓN FILTROS DIGITALES EN FPGA's
Figura 5.1 Estructura para la realización de filtros IIR
5.3.2 F
ILTROS IIR
Los filtros IIR corresponden directamente al
equivalente analógico. Una forma de diseñar filtros
IIR es creando la función de transferencia deseada
en el dominio analógico para transformarla al
dominio z y después calcular los coeficientes del
filtro IIR mediante los cuales se obtiene la
siguiente ecuación en diferencias: y(n) = b
+ b
x(n – 1) + b2 x(n – 2) + ... bM x(n –M) - a
1
– 1) - a
variables a
y(n – 2) - ....- aN y(n – N), donde las
2
y bk son los coeficientes del filtro.
k
x(n)
0
1
y(n
Dentro de las ventajas que ofrecen los filtros IIR
sobre los tipo FIR encontramos:
1) Los filtros IIR requieren menos memoria y
menos instrucciones para implementar su
función de transferencia.
2) Un filtro IIR se diseña mediante el calculo
de polos y ceros en el plano complejo. El
uso de polos confieren a un filtro IIR la
capacidad de implementar funciones de
transferencia que es imposible realizar
mediante filtros FIR.
3) Es posible trasladar un filtro IIR a un
modelo analítico.
Sin embargo, algunas consideraciones que se
deben considerar en la implementación de filtros
IIR son las siguientes:
1) Los filtros IIR no son necesariamente
estables, es tarea del diseñador buscar la
estabilidad del sistema.
2) Los filtros IIR producen en general
distorsión de fase.
3) La posibilidad desbordamiento de
resultados en la operaciones realizadas
deben ser consideradas ya que un filtro IIR
se implementa mediante sumas de
productos que están basadas en una suma
infinita.
La implementación de filtros IIR puede hacerse de
varias formas. Asumiendo el comportamiento
lineal e invariante en el tiempo del sistema, la
ecuación en diferencias de un filtro puede ser
manipulada matemáticamente para obtener una
realización con N elementos de memoria, (N + M + 1) multiplicadores y N sumadores, conocida
como Forma Directa II Transpuesta.
IEC FRANCISCO JAVIER TORRES VALLE
85
CAPÍTULO V: IMPLEMENTACIÓN FILTROS DIGITALES EN FPGA's
Figura 5.2 Implementación de filtros IIR mediante FDII-T
5.4 METODOLOGÍA DE DISEÑO
PARA FILTROS DIGITALES
El proceso de diseño de un filtro digital requiere
de los siguientes pasos.
1) Establecer las especificaciones del filtro,
como lo son: ancho de banda, atenuaciones,
ganancias, etc.
2) Determinar la función de transferencia que
cumpla las especificaciones.
3) Elaborar un diagrama a bloques con las
operaciones a realizar, el cual especifica en
hardware los elementos del circuito y sus
interconexiones.
5.5 IMPLEMENTACIÓN EN
FPGA'S
El almacenaje de un dato significa retrasar su
uso una cantidad normalmente igual al periodo de
muestreo. Este retraso se representa mediante z
-1
(retraso de una unidad), z
-2
(dos unidades), etc. Por
lo que los filtros digitales pueden realizarse usando
los elementos correspondientes a las operaciones
de multiplicación, adición y almacenaje de datos
en el FPGA, utilizando alguna de las estructuras
para la realización de sistemas LTI. Una correcta
elección de la estructura a implementar puede
optimizar significativamente la eficacia del
sistema.
5.6 DISEÑO DE UN FILTRO
PASA-BAJAS
Un filtro pasa - bajas ideal es aquel que permite
pasar todas aquellas frecuencias que se encuentran
por debajo de una frecuencia de corte especificada
(fc), atenuando las que se encuentran por encima
de esta. La siguiente ecuación en diferencias
corresponde a un filtro IIR pasa - bajas tipo
butteworth de orden 5, frecuencia de muestreo de
48.8 kHz y con una frecuencia de corte a 5 kHz:
IEC FRANCISCO JAVIER TORRES VALLE
86
CAPÍTULO V: IMPLEMENTACIÓN FILTROS DIGITALES EN FPGA's
y(n) = 0.0014*x(n) + 0.0071*x(n-1) +
0.0142*x(n-2) + 0.0142*x(n-3) + 0.0071*x(n-4) +
0.0014*x(n-5) + 2.9272*y(n-1) - 3.7016*y(n-2) +
2.4521*y(n-3) - 0.8422*y(n-4) + 0.1191*y(n-5)
1.2
1
0.8
0.6
|H(F)|
0.4
0.2
0
3
2
1
0
<) H(F)
-1
-2
-3
1
10
1
10
FUNCIÓN DE TRANSFERENCIA
2
10
2
10
A continuación se muestra la respuesta en
frecuencia del sistema en magnitud y fase.
3
10
F
3
10
F
4
10
4
10
10
10
5
5
Figura 5.3 Respuesta del filtro en magnitud y fase
La gráfica anterior sería la función de
transferencia ideal del filtro a implementar, pero
en un sistema digital todo se trabaja en el sistema
binario por lo que debemos convertir los
coeficientes obtenidos a dicho sistema. Dicha
conversión implica una cantidad considerable de
bits si es que se desea obtener la misma calidad.
Pero el utilizar más bits implica la utilización de
mayor cantidad de recursos del FPGA, el cual en
el presente trabajo es un XC4010XLPC84. De
hecho un multiplicador de 20 bits requiere del
65% de los recursos de este dispositivo, por lo
que se opto por implementar el filtro utilizando la
función de transferencia H(
ω
) del filtro anterior
con las primeras once muestras de la respuesta al
impulso del sistema LTI y realizar el diseño del
filtro utilizando la estructura FIR. Los
coeficientes utilizados son los siguientes: b(n) = ( 1, 2, 3, 4, 4, 3, 2, 1, -1, -1, -1 ), los cuales cuando
se digitalizan utilizando el formato complemento
a dos quedan de la siguiente manera: b
El diseño de la estructura FIR se realizo con
VHDL para lo cual se describieron utilizando
once registros en una configuración FIFO para
realizar los retardos z
-1
y cuyas salidas se
multiplican por el coeficiente respectivo. EL
dispositivo convertidor analógico - digital
utilizado es el AK4520A el cual tiene una
longitud de palabra de 20 bits con salida en
complemento a dos. Por lo que el filtrado se
realizo con once multiplicaciones de 20x4 y un
acumulador de dichas operaciones. La
cuantización de los coeficientes afecta la
respuesta en frecuencia del sistema, a
continuación se muestra la respuesta en
frecuencia en magnitud del filtro con lo
coeficientes cuantizados
IEC FRANCISCO JAVIER TORRES VALLE
87
Loading...
+ hidden pages
You need points to download manuals.
1 point = 1 manual.
You can buy points or you can get point for every manual you upload.