Sei sulla pagina 1di 116

75$'8&&,Ð1%$55Ð17255(6%(57+$(/,=$%(7+

(',&,Ð1/$VV
Diseño de Circuitos
con VHDL

Volnei A. Pedroni

MIT Press
Cambridge, Massachusetts
. London, England
2004 Massachusetts lnstitute ofT echno!ogy
1
DISEÑO DE CIRCUITOS
1 INTRODUCCIÓN
1.1 Acerca de VHDL.

VHDL es un lenguaje de descripción de hardware. Describe el comportamiento de un circuito


electronico o sistema, a partir del cual el circuito físico o sistema puede ser realizado
(implementado).

VHDL significa Lenguaje de Descripción de Hardware VHSIC. VHSIC es a su vez una


abreviación de Very High Speed lntegrated Circuits, una iniciativa financiada por el Departamento
de Defensa de los Estados Unidos en la década de 1980 que llevó a la creación del VHDL.
Su primera versión fue VHDL 87, más tarde fue mejorada en la versión llamada VHDL 93. VHDL
fue el primer lenguaje de descripción de hardware estandarizado por el Instituto de Ingenieros
Electricistas y Electrónicos, através del standard IEEE 1076. Un standard adicional, el IEEE
1164, fue más tarde añadido para introducir un sistema lógico de múltiples valores.

VHDL está orientado a la síntesis de circuitos además de la simulación de circuitos. Sin embargo,
a pesar de que VHDL es completamente simulable, no todas las construcciones son
sintetizables. Nosotros haremos énfasis en las que sí lo son.

Una motivación fundamental para usar VHDL (o su competidor, Verilog) es que VHDL es un
lenguaje estandard, independiente de la tecnología/vendedor, y es por tanto portable y reusable.
Las dos aplicaciones principales e inmediatas del VHDL están en el campo de los Dispositivos
Lógicos Programables (incluyendo CPLDs- Complex Programmable Logic Devices y FPGAs-
Field Programmable Gate Array) y en el campo de los ASICs (Application Specific lntegrated
Circuits). Una vez que el código VHDL ha sido escrito, puede ser usado ya sea para implementar
el circuito en un dispositivo programable (Ya sea Altera, Xilinx, Atmel, etc.) o puede ser sometido
a fundición para fabricacion de un chip ASIC. Actualmente, muchos chips comerciales complejos
(microcontroladores, por ejemplo) son diseñados usando esta aproximación.

Una nota final en relación al VHDL es que, contrario a los programas regulares de computadoras
los cuales son secuenciales, sus sentencias son inherentemente concurrentes (en paralelo). Por
esta razón, VHDL es usualmente llamado código en vez de programa. En VHDL, solo las
sentencias colocadas dentro de un PROCESS, FUNCTION, o PROCEDURE se ejecutan
secuencialmente.

1.2 Flujo del Diseño

Como se mencionó anteriormente, uno de los principales servicios del VHDL es que permite la
síntesis de un circuito o sistema en un dispositivo programable (PLD o FPGA) o en un ASIC. Los
pasos que se siguen durante este proyecto se resumen en la figura 1.1. Empezamos el diseño al
escribir el código VHDL, el cual se guarda en un archivo con la extensión .vhd y el mismo nombre
del nombre de su ENTITY. El primer paso en el proceso de síntesis es la compilación. La
compilacion es la conversión del lenguaje VHDL de alto nivel, el cual describe el circuito al nivel
Register Transfer Level (RTL), en un netlist al nivel de gates. El Segundo paso es la
optimización, la cual se desarrolla en el netlist al nivel de gates para la optimización de la
velocidad 0del área. En esta etapa, el diseño puede ser simulado. Finalmente, un software
place-and-route (ajustador) generará la disposición física para un chip PLD/FPGA o generará la
máscara para un ASIC.

\'HDLcntry
lRTI~ lcvcl)

Compilill ion

Synthcsis l Optirnizatíon 1

Optimirxd nctlist --~j


tGa.t~ levcl) Simulstkm

Pbc"1&Route

Simulation

Figura 1.1
Resúmen del flujo de diseño VHDL.

1.3 Herramientas EDA

Hay varias herramientas EDA (Electronic Design Automation) disponibles para la síntesis,
implementacion, y simulacion de circuitos usando VHDL. Algunas herramientas (place and route,
por ejemplo) se ofrecen como parte de la suite de diseño de un proveedor (e.g., Altera's Quartus
11, el cual permite la síntesis de código VHDL en chips CPLD/FPGA de Altera, o la suite de
Xilinix, para chips CPLD/FPGA de Xilinix). Otras herramientas (sintetizadores, por ejemplo),
además de ser ofrecidas como parte de las suites de diseño, pueden ser también provistas por
compañías especializadas EDA (Mentor Graphics, Synopsis, Synplicity, etc.). Ejemplos de este
último grupo son Leonardo Spectrum (un sintetizador de Mentor Graphics), Synplify (un
sintetizador de Synplicity), y ModelSim (un simulador de Model Technology, una compañía
Mentor Graphics).

Los diseños presentados en el libro fueron sintetizados en dispositivos CPLD/FPGA (apéndice A)


tanto de Altera como de Xilinx. Las herramientas usadas fueron tanto ISE combinado con
ModelSim (para chips Xilinx-apéndice B), MaxPlus 11 combinado con Advanced Synthesis
Software (para CPLDs Altera -apéndice C), o Quartus 11 (también para dispositivos Altera-
appéndice D). Leonardo Spectrum se usó también ocasionalmente.
Aunque se usaron diferentes her~amientas. EDA para implementar y probar los ejemplos
presentados en el libro (vea la lista anterior de herramientas), decidirnos estandarizar la
presentación visual de todas las gráficas de simulación. Debido a su apariencia limpia, se usó el
editor de la forma de onda de MaxPlus 11 (apéndice C). Sin embargo, simuladores más nuevos,
como ISE + ModelSirn (apéndice 8) Y Quartus 11 (apéndice D), ofrecen un conjunto más amplio
de características, las cuales permiten, por ejemplo, un análisis de tiempo más refinado. Por esta
razón, esas herramientas fueron adoptadas cuando se examinaron los detalles finos de cada
diseño.

1.4 Traduccióndel códigoVHDL en un circuito

En la figura 1.2 se representa un sumador completo. En el, a y b representan los bits de entrada
que se van a sumar, cines el bit del cargo de entrada, ses el bit de suma, y cout el bit del cargo
de salida. Como se muestra en la tabla de verdad, s debe estar en alto siempre que el número
de entradas que están en alto es impar, mientras que cout debe estar en alto cuando dos o más
entradas están en alto.

a-. s
ab cm
00 o
s coui
o o
b-+
Full ol o L o
Adder 1 o o l o
cout
cin _.,. J l o o 1
00 1 1 o
ol l o 1
1 Ü' 1 o 1
1 l l 1 )
Figura 1.2
Diagrama del sumador completo y la tabla de verdad.

En la figura 1.3 se muestra un código VHDL para el sumador completo de la figura 1.2. Como se
puede ver, consiste de una ENTITY, la cual es una descripcion de los pines (PORTS) del
circuito, y de una ARCHITECTURE, la cual describe cómo debe funcionar el circuito. Vemos en
ésta última que el bit suma se calcula comos= a+b+cin, mientras que cout se obtiene de cout =
a.b + a.cin + b.cin.

ENTITYfull ~dder IS: ....-


PORT t z , b,-cin: rnBI""'.""';
. . r"
/
e , t:·JUt .: (( ..TT t! I T J ; / \
\
EKD :·~...111 .:!ddec~ i t
1

\,'·· Circuít
AF..CHITECTURE d~t:~fVY.1 CF :'u1 l
·\...
BRGW
~ ~- ~ XOR b XDR =i~; \.,
/
cout, •.- r~ J\liC b ] Of( j;:i l~lD •:::n1 ·~'~-
\

\, ,.•'

(b J'J{D ci::i) ;

...... .. . . """
Figura 1.3
Ejemplo de código VHDL para la unidad del sumador completo de la figura 1.2.
físico, como se indica en el =
A partir del código VHDL mostrado en el lado izquierdo de la figura 1.3, se infiere un circuito
derecho de la figura. Sin embargo, hay varias maneras de
implementar las ecuaciones descritas en la ARCHITECTURE de la figura 1.3, así que el circuito
real dependerá del compilador/optimizador que se esté usando y, más importante aun, de la
tecnología del dispositivo finalmente usado. En la figura 1.4 se presentan unos pocos ejemplos.
Por ejemplo, si nuestro dispositivo final es un dispositivo lógico programable (PLD o FPGA-
apéndice A), entonces se ilustran dos posibles resultados (entre muchos otros) para cout en las
figuras 1.4(b)-(c) (en ambas, por supuesto, cout = a.b + a.cin + b.cin). Por otra parte, si nuestra
tecnología final es un ASIC, entonces una posible implementación CMOS, a nivel de
transisitores, es el de la figura 1.4(d) (la cual hace uso de transistores MOS y lógica con reloj).
Por otra parte, la herramienta de síntesis puede ser ajustada para optimizar el área o la
velocidad, lo que obviamente también afecta el circuito final.

Cualquiera que sea el circuito i~ferido a partir del código, su operacion debe ser siempre
verificada todavía al nivel de diseño (después de la síntesis), como se indica en la figura 1.1. Por
supuesto debe ser también probada al nivel físico, pero los cambios en el diseño podrían ser
demasiado costosos

Cuando se pruebe, el simulador mostrará ondas smilares a las presentadasen la figura 1.5. En
efecto, la figura 1.5 contiene los resultados de la simulacion del circuito sintetizado con el código
VHDL de la figura 1.3, el cual implementa la unidad del sumador completo de la figura 1.2. Como
puede verse, los pines de entrada (caracterizadospor una flecha de entrada con una "I" marcada
dentro) y los pines de salida (caracterizados por una flecha de salida con una "o" marcada
dentro) son los enlistados en la ENTITY de la figura 1.3. Podemos libremente establecer los
valores de las señales de entrada (a, b, y cin en este caso), y el simulador calculará y graficará la
señales de salida (s y cout). Como puede ser observado en la figura 1.5, las salidas se
comportan como se esperaba

(at (b)

a--j a-j
b --j dn-j
L.-~___,...~

(e) (d)

Figura 1.4
Ejemplos de circuitos posibles obtenidos del código del sumador completo de la figura 1.3.
ffiÓrrs 11JJ.Ons 150.[t·,:; :))J.Dns '.L--.:.OJJns 3Jllln'3 ~$J.1Jn~ 4CO.On

•a o r 1
1 l
¡-¡__
--b
rcin o· 1

....@:s o 1 1 r~ _J
-O coul 1 1

Figura 1.5
Resultados de la simulación del diseño VHDL de la figura 1.3.

1.5 Ejemplos de Diseño

Como se mencionó en el prefacio, el libro es en efecto una aproximación orientada al diseño en


la tarea de enseñar VHDL. La integración entre VHDL y Diseño Digital se logra a través de una
larga serie de ejemplos de diseño bien detallados. En seguida se muestra un resúmen de
diseños completos presentados en el libro.

• Adders (ejemplos 3.3 y 6.8 y sección 9.3)


• ALU (ejemplo 5.5 y 6.1 O)
• Barrel shifters and vector shifters (ejemplos 5.6 y 6.9 y sección 9.1)
• Comparators (sección 9.2)
• Controller, traffic light (ejemplo 8.5)
• Controller, vending machine (sección 9.5)
• Count ones (ejemplos 7.1 y 7.2)
• Counters (ejemplos 6.2, 6.5, 6.7, 7.7, y 8.1)
• Decoder (ejemplo 4.1)
• Digital filters (sección 12.4)
• Dividers, fixed point (sección 9.4)
• Flip-flops and latches (ejemplos 2.1, 5.7, 5.8, 6.1, 6.4, 6.6, 7.4, y 7.6)
• Encoder (ejemplo 5.4)
• Frequency divider (ejemplo 7.5)
• Function arith_shift (ejemplo 11. 7)
• Function conv_integer {ejemplos 11.2 y 1 ·1.S)
• Function multiplier (ejemplo 11.8)
• Function "+" overloaded (ejemplo 11.6)
• Function positive_edge (ejemplos 11.1, 11.3, y 11.4)
• Leading zeros counter (ejemplo 6.1 O)
• Multiplexers (ejemplos 5.1, 5.2, and 7.3)
• Multipliers (ejemplo 11.8 y secciones 12.1 y 12.2)
• MAC circuit (sección 12.3)
• Neural networks (sección 12.5)
• Parallel-to-serial converter (sección 9. 7)
• Parity detector (ejemplo 4.2)
• Parity generator (ejemplo 4.3)
• Playing with SSD (sección 9.8)
• Procedure min_max (ejemplos 11.9 y 11.10)
• RAM (ejemplo 6.11 y sección 9.1 O)
• ROM (sección 9.10)
• Serial data receiver (sección 9.6)
• Shift registers (ejemplos 6.3, 7.8, and 7.9)
• Signal generators (ejemplo 8.6 and section 9.9)
• String detector (ejemplo 8.4)
• Tri-state buffer/bus (ejemplo 5.3)

Por otra parte, algunos diseños adicionales y verificaciones experimentales también se proponen
como ejercicios:

• Adders and subtractors (problemas 3.5, 5.4, 5.5, 6.14, 6.16, 10.2, y 10.3)
• Arithmetic-logic units (problemas 6.13 y 10.1)
• Barrel and vector shifters (problemas 5. 7, 6.12, 9.1, y 12.2)
• Binary-to-Gray code converter (problema 5.6)
• Comparators (problemas 5.8 and 6.15)
• Count ones (problema 6.9)
• Counters (problemas 7.5 y 11.6)
• Data dela y circuit (problema 7 .2)
• Decoders (problemas 4.4 and 7.6)
• DFFs (problemas 6.17, 7.3, 7.4, y 7.7)
• Digital FIR filter (problema 12.4)
• Dividers (problemas 5.3 y 9.2)
• Event counter (problema 6.1)
• Finite-state machine (problema 8.1)
• Frequency divider, generic (problema 6.4)

• Frequency multiplier (problema 6.5)


• Function conv_std_logic_vector (problema 11.1)

• Function "not" overloaded far integers (problema 11.2)

• Function shift for integers (problema 11.4)


• Function shift for std_logic_vector (problema 11.3)

• Function BCD-SSD converter (problema 11.6)

• Function "b" overloaded for std_logic_vector (problema 11.8)


• lntensity encoder (problema 6.1 O)

• Keypad debouncer/encoder (problema 8.4)

• Multiplexers (problemas 2.1, 5.1, y 6.11)

• Multipliers (problemas 5.3, 11.5, y 12.1)


• Multiply-accumulate circuit (problema 12.3)
• Neural network (problema 12.5)
• Parity detector (problema 6.8)
• Playing with a seven-segment display (problema 9.6)
• Priority encoder (problemas 5.2 y 6.3)
• Procedure statistics (problema 11. 7)
• Random number generator plus SSD (problema 9.8)

• ROM (problema 3.4)


• Serial data receiver (problema 9.4)
• Serial data transmitter (problema 9.5)

• Shift register (problema 6.2)


• Signal generators (problemas 8.2, 8.3, 8.6, y 8. 7)

• Speed monitor (problema 9. 7)

• Stop watch (problema 10.4)

• Timers (problems 6.6 and 6.7)

• Traffic-light controller (problema 8.5)


• Vending-machine controller (problema 9.3)

Adicionalmente, se incluyen cuatro appendices sobre dispositivos lógicos programables Y


herramientas de síntesis.
• Appendix A: Programmable Logic Devices

• Appendix B: Xilinx ISE + ModelSim Tutorial


• Appendix C: Altera MaxPlus 11 + Advanced Synthesis Software Tutorial

·• Appendix O: Altera Quartus 11 Tutorial

. -~-
2 ESTRUCTURA DEL CÓDIGO

En este capítulo, se describen las secciones fundamentales que conforman una pieza de VHDL:
Declaraciones de LIBRERIAS, ENTIDAD Y ARQUITECTURA.

2.1 Unidades Fundamentales de VHDL

Como se muestra en la figura 2.1, una pieza independiente de código VHDL se compone al
menos de tres secciones fundamentales:

o Declaración LIBRARY: Contiene una lista de todas las librerías que se usan en el diseño.
Por ejemplo: ieee, std, work, etc.
o ENTITY: Especifica los pines 1/0 del circuito.
o ARCHITECTURE: Contiene el código apropiado, que describe cómo se debe comportar el
circuito.

Una librería es una colección de piezas de código usadas comúnmente. Al colocar tales piezas
en una librería les permite ser reusadas o compartidas por otros diseños.
La estructura típica de una librería se muestra en la figura 2.2. El código está generalmente
escrito en forma de FUNCTIONS, PROCEDURES, o COMPONENTS los cuales están puestos
en PACKAGES, y luego son compilados en la librería destinación.
Las unidades fundamentales de VHDL (Fig 2:1) se estudiarán en la Parte 1 del libro (hasta el
capítulo 9), mientras que las secciones relacionadas con las librerías (Fig 2:2) se verán en la
Parte 11 (capítulos 10-12).

2.2 Declaración de Librerías

Para declarar una librería (es decir, para hacerla visible en el diseño) se necesitan dos líneas de
código, una que contiene el name de la librería, y la otra una cláusula use,

LIBRARY library_name;
USE library _ name.package _ name.package _parts;

Al menos tres paquetes de tres librerías diferentes, son generalmente necesarias en un diseño:

• ieee.std_logic_l 164 (de la librería ieeei,


• standard (de la librería std), y
• work (de la librería work).
Declaraciones
[ LIBRARY

Código Básico
ENTITY VHDL

ARCHITECTURE

Figura 2.1
Secciones fundamentales de un código Básico VHDL

UBRARY

PACKAGE
¡
p::=::.i
COMPONENTS
1
j

L_~-=~~ TYPE~~~~=:~--j-=__J
CON:ST ANTS Í
l

Figura 2.2
Partes fundamentales de una librería

Sus declaraciones son como sigue:

LIBRAR Y ieee; -- El punto y coma (;) indican


USE ieee.std_logic_l 164.alJ; -- el fin de la sentencia o

LIBRAR Y std; -- declaración, mientras que el doble


USE std.standard.all; -- guión (--) indica un comentario.

LIBRAR Y work;
USE work.all;

1
Las librerías std y work mostradas arriba son visibles por default, así que no hay que declararlas;
sólo la librería ieee debe ser escrita explícitamente. 'sin embargo, esta última sólo es necesaria
cuando se emplean los datos de tipo STD_LOGIC (o STD_ULOGIC) en el diseño (los tipos de
datos se estudiarán en detalle en el siguiente capítulo).
El propósito de los tres paquetes/librerías mencionados arriba es el siguiente: El paquete
std_logic _ 1164 de la librería ieee especifica un sistema lógico multinivel; std es una biblioteca de
recursos (tipos de datos, texto i/o, etc) para el entorno de diseño VHDL; y la librería work es
donde guardamos nuestro diseño (el archivo .vhd, más todos los archivos creados por el
compilador, simulador, etc).
En efecto, la librería ieee contiene varios paquetes, incluyendo los siguientes:

• std_logic_l l64: Especifica los sistemas lógicos multivalor STD_LOGIC (de 8 niveles) y el
STD_ULOGIC (de 9 niveles).

• std_logic_arith: Especifica los tipos de datos SIGNED and UNSIGNED y las operaciones
de comparación y aritméticas relacionadas. También contiene varias funciones de
conversión ~e datos, las cuales permiten que un tipo sea convertido en otro:
conv _integer(p), conv _unsigned(p, b), conv_signed(p, b), conv_std_logic_vector(p, b).

• std_logic_signed:
Contiene funciones que permiten las operaciones con datos
STD_LOGIC_ VECTOR para desarrollarlas como si fueran de tipo SIGNED.

• std_logic _unsigned:
Contiene funciones que permiten operaciones con datos
STD_LOGIC_ VECTOR para desarrollarlas como si fueran de tipo UNSIGNED.

En el capítulo 3, todas estas librerías serán más descritas y usadas.

2.3 ENTITY
Una ENTITY es una lista con especificaciones de todos los pines de entrada y salida (PORTS)
del circuito. Su sintaxis se muestra abajo:

ENTITY entity_ name IS


PORT(
port_name: signal_mode signal_typc;
port_name: signal_mode signal_type;
... );
END entity _name;

El mode de la señal puede ser IN, OUT, INOUT, o BUFFER. Como se muestra en la figura 2.3,
IN y OUT son pines totalmente unidireccionales, mientras que INOUT es bidireccional. BUFFER,
por otra parte, se emplea cuando la señal de salida debe ser usada (leída) internamente.
El type de la señal puede ser BIT, STO_LOGIC, INTEGER, etc. Los tipos de datos se discutirán
en detalle en el capítulo 3.
Finalmente, el name de la entidad puede ser básicamente cualquier nombre, excepto palabras
reservadas VHDL (las reservadas se enlistan en el apéndice E).

Ejemplo: Consideremos la función NANO de la figura 2.4. Su entidad puede especificarse como:

ENTITY nand _gate IS


PORT (a, b: IN BIT;
x: OUT BIT);
END nand _gate;

Figura 2.3
Modos de la Señal.

a
b
Figura 2.4
Función NANO.

El significado de esta entidad es el siguiente: El circuito tiene tres pines 110, siendo dos entradas
(a y b, modo IN) y una salida (x, modo OUT). Las tres señales son del tipo BIT. El nombre que
se escogió para la entidad fue nand_gate.

2.3 ARCHITECTURE

La arquitectura es una descripción de cómo debe comportarse el circuito (Funcionamiento). Su


sintaxis es la siguiente:

ARCHITECTURE architecture_name OF entity _ name IS


[ declarations]
BEGIN
(code)
END architecture_name;
Como se muestra arriba, una arquitectura tiene dos partes: una parte declarativa (opcional)
donde las señales y constantes (entre otras) se declaran, y la parte del código (de BEGIN hacia
abajo). Como en el caso de una entidad, el nombre de una arquitectura puede ser básicamente
cualquier nombre (excepto palabras reservadas VHDL), incluyendo el mismo nombre de la
entidad.

Ejemplo: Consideremos la función NANO de la figura 2.4 una vez más.

ARCHITECTURE myarch OF nand_gate IS


BEGIN
x <= aNAND b;
END myarch;

El significado de la arquitectura anterior es: El circuito debe desarrollar la operación NANO entre
las dos señales de entrada (a, b)y asignar ("<=") el resultado al pin de salida (x). El nombre
escogido para esta arquitectura fue myarch. En este ejemplo, no hay parte declarativa, y el
código contiene una sola asignación.

2.5 Ejemplosintroductorios

En esta sección presentaremos dos ejemplos de código VHDL. Aunque todavía no hemos
estudiado las construcciones que aparecen en los ejemplos, ayudarán a ilustrar los aspectos
fundamentales con respecto a la estructura general del código. Cada ejemplo es seguido por
comentarios explicativos y los resultados de la simulación.

G ·I,
1
Q1FF --GJ

~-·-
~J
Figura 2.5
OFF con Reset Asíncrono.

1
Ejemplo 2.1: OFF con Reset Asíncrono

¡ La figura 2.5 muestra el diagrama de un Flip Flap tipo O disparado con la transición positiva de la
señal de reloj (clk), Y con una entrada de reset asíncrona (rst). Cuando rst = 'l ', la salida debe
ponerse en nivel bajo independientemente de clk. Por otra parte, la salida debe copiar la entrada
1

1
(es decir, q <= d) en el momento en que clk cambia de 'O' a 'l' (es decir, cuando se produce
una evento hacia arriba en clk).

Hay varias maneras de implementar el OFF de la figura 2.5, uno es la solución presentada abajo.
Una cosa que recordar, sin embargo, es que VHDL es inherentemente concurrente (contrario a
los programas de computadora regulares, los cuales son secuenciales), así que para
implementar un circuito con reloj (flip flops, por ejemplo) debemos "forzar" que VHOL sea
secuencial. Esto puede hacerse usando un PROCESS, como se muestra enseguida.

1 ---------------------------------------
2 LIBRAR Y ieee;
3 USE ieee.std_logic_l 164.all;
4 ---------------------------------------
5 ENTITY dff IS
6 PORT ( d, clk, rst: IN STD_LOGIC;
7 q: OUT STD LOGIC);
8 END dff;
9 ---------------------------------------
10 ARCHITECTURE behavior OF dffIS
11 BEGIN
12 PROCESS (rst, clk)
13 BEGIN
14 IF (rst=' l ') TREN
15 q <='O';
16 ELSIF ( clk'EVENT AND clk=' l ') TREN
17 q <= d;
18 END IF;
19 END PROCESS;
20 END behavior;
21 ---------------------------------------

Comentarios:

Líneas 2-3: Declaración de la librería (name de la librería y cláusula use). Recuerde que
las otras dos librería indispensables (std y work) son hechas visibles por
default.
Líneas 5-8: Entidad dff
Líneas 10-20: Arquitectura behavior.
Línea 6: Puertos de entrada (el modo input sólo puede ser IN). En este ejemplo,
todas las señales de entradas son del tipo STO_LOGIC.
Línea 7: Puerto de salida (El modo output puede ser OUT, INOUT, o BUFFER).
Aquí la salida es también del tipo STO LOGIC. .
Líneas 11-19: Parte del código de la arquitectura (desde la palabra BEGIN en adelante).
Líneas 12-19: Un PROCESS (internamente el código se ejecuta secuencialmente).
Línea 12: El PROCESS se ejecuta cada vez que una señal declarada en su lista
de sensibilidad cambia. En éste ejemplo, cada vez que rst o clk cambian, el
PROCESS se ejecuta.
Líneas 14-15: Cada vez que rst es' l' la salida se limpia, sin importar clk (reset asíncrono).
Líneas16-17: Si rst no se activa, y clk cambia (ocurre un EVENT en clk), y además tal evento
fue una transición positiva (clk = 'l '), entonces la señal de entrada (d) se
almacena en el flip-flop (q <= d).
Líneas 15--17: El operador "<=" se usa para asignar un valor a una SIGNAL. En contraste,
":=" se usaría para una VARIABLE. Todos los puertos en una entidad son
señales por default.
Líineas 1, 4, 9, y 21:
Comentarios (recuerde que " " indica un comentario). Usados solo para
organizar mejor el diseño.

Nota: VHDL no es sensible a mayúsculas y minúsculas.

Figura 2.7
OFF con función lógica NANO

Ejemplo 2.2 OFF con función lógica NANO

El circuito de la figura 2.4 fue puramente combinacional, mientras que el de la figura 2.5, fue
puramente secuencial. El circuito de la figura 2.7 es una mezcla de ambos (sin reset). En la
solución que sigue, hemos introducido a propósito una señal innecesaria (temp), sólo para
ilustrar cómo una señal debería declararse.

1 ---------------------------------------
2 ENTITY example IS
3 PORT (a, b, clk: IN BIT;
4 q: OUT BIT);
5 END example;
6 ---------------------------------------
? . ARCHITECTURE example OF example IS
8 SIGNAL temp : BIT;
9 BEGIN
1O temp <= a NAND b;
11 PROCESS (clk)
12 BEGIN
13 IF ( clk' EVENT AND clk=' l ') THEN q<=temp;
14 END IF;
15 END PROCESS;
16 END example;
17 ---------------------------------------

Comentarios:

Las declaraciones de las librerías no son necesarias en este caso, porque el dato es del tipo BIT,
el cual está especificado en la librería std (recuerde que las librerías std y work son visibles por
default).

Líneas 2-5: Entidad example


Líneas 7-16: Arquitectura example
Línea 3: Puertos de entrada (todos de tipo BIT).
Línea 4: Puerto de salida (también de tipo BIT).
Línea 8: Parte declarativa de la arquitectura (opcional). La señal temp, de tipo BIT,
fue declarada. Observe que no hay declaración de modo (mode sólo se usa
en entidades).
Líneas 9-15: Parte del código de la arquitectura (desde la palabra BEGIN en adelante).
Líneas 11-15: Un PROCESS (sentencias ejecutadas secuencialmente cada vez que la señal
clk cambia)
Líneas 10y11-15:
Aunque dentro de un proceso la ejecución es secuencial, el proceso, como
un todo, es concurrente con los otras sentencias (externas); así que la línea
1 O se ejecuta concurrentemente con el block 11-15.
Línea 10: Operación NANO Lógica. El resultado se asigna a la señal temp.
Líineas 13-14: Sentencia IF. En la transición positive de clk el valor de temp se asigna a q.
Líneas 10y13:
El operator "<=" se usa para asignar un valore a una SIGNAL. En
contraste, ":="se usaría para una VARIABLE.
Líneas 8 y 10: Pueden ser eliminadas, cambiando "q <=a NAND b" en la línea 13.
Líneas 1, 6, y 17:
Ya comentado. Sólo se usan para mejor organización del diseño.

l 2.6 Problemas

1 Problema 2:1: Multiplexor

1
1 a l7:01 sel e
f c(7:0)
00 o
1 b {7:0J ¡..___,,, 01 a
10 b
11 z
1 Sel (1:0)

Figura P2.1

El diagrama top-level de un multiplexor se muestra en la figura P2.1. De acuerdo a La tabla de


verdad, la salida debe ser igual a una de las entradas si sel= "01" (e= a) o sel=" 10" (e =b),
pero debe ser 'O' o Z (high impedance) si sel== "00" o sel= "11 ", respectivamente.

a) Complete el código VHDL de abajo.


b) Escriba comentarios relevantes respecto a su solución (como en los ejemplos 2.1 y 2.2).
c) Compile y simule su solución, checando si trabaja como esperaba.

Nota: Se usó un IF en el código, porque es más intuitivo. Sin embargo, como se verá más tarde,
también se pueden usar sentencias como WHEN o CASE para implementar el multiplexor.

1 ---------------------------------------
2 LIBRARY ieee;
3 USE ~----------
4 ---------------------------------------
5 ENTITY mux IS
6 PORT ( _, _: _ STD_LOGIC_ VECTOR (7 DOWNTO O);
7 sel: IN _
8 _:OUT STD_LOGIC_ VECTOR (7 DOWNTO O));
9 END __
10 ---------------------------------------
11 ARCHITECTURE example OF IS
12 BEGIN
13 PROCESS (a, b, _)
14 BEGIN
15 IF (sel = "00") THEN
16 e<= "00000000";
17 ELSIF ( ) THEN
18 e<= a;
19 (sel= "10") THEN
20 e<=_,
21 ELSE
22 e<= (OTHERS => '_');
23 END
24 END ----
25END
--
26 ---------------------------------------------

Figure P2.2
Figura P 2.2

Problema 2.2: Funciones Lógicas

a) Escriba un código VHDL para el circuito de la figura P2.2. Observe que es puramente
combinacional, así que no es necesario un PROCESS. Escriba una expresión para d usando
sólo operadores lógicos (ANO, OR, NANO, NOT, etc.).
b) Sintetice y simule su circuito. Después de asegurarse de que trabaja apropiadamente, abra el
archivo del reporte y cheque la expresión real implementada por el compilador. Compárela
con su expresión.
3 TIPOS DE DATOS
Con el propósito de escribir códigos VHDL apropiadamente, es esencial conocer qué tipos de
datos son permitidos, y cómo se especifican Y se usan. En este capítulo, se describen todos los
tipos de datos fundamentales, con énfasis especial en los que son sintetizables. Se incluyen
discusiones sobre la compatibilidad y la conversión de datos.

3.1 Tipos de datos pre-definidos

VHDL contiene una serie de tipos de datos predefinidos, especificados a través de los
estándares IEEE 1076 e IEEE 1164. Más específicamente, tales definiciones de tipos de datos
pueden ser encontradas en los siguientes paquetes/librerías:

• Paquete standard de la librería std: Define los tipos de datos BIT, BOOLEAN, INTEGER, Y
REAL.
• Paquete std_logic_1164 de la librería ieee: Define los tipos de datos STD_LOGIC and
STD_ULOGIC.
• Paquete std_logic_arith de la librería ieee: Define los tipos de datos SIGNED Y
UNSIGNED, además incluye varias funciones para conversón de datos, como
conv _integer(p), conv _unsigned(p, b), conv _signed(p, b), y conv _std_logic_vector(p, b).
• Paquetes std_logic_signed y std_logic_unsigned de la librería ieee: Contiene funciones
que permiten operaciones con datos STD_LOGIC_VECTOR para ser desarrolladas como si
los datos fueran de tipo SIGNED o UNSIGNED, respectivamente.

Todos los tipos de datos predefinidos (especificados en los paquetes/librerías enlistados arriba,
se describen a continuación.

• BIT (and BIT_VECTOR): 2- niveles lógicos ('O', '1 ').

Examples:

SIGNAL x: BIT;
-- x está declarada como una señal de un dígito de tipo BIT.
SIGNAL y: BIT_ VECTOR (3 DOWNTO O);
__ y es un vector de 4 bits, con el bit más a la izquierda como el bit MSB.
SIGNAL w: BIT_ VECTOR (O TO 7);
__ w es vector de 8 bits, con el bit más a la derecha como el bit MSB.

Basados en las señales anteriores, las siguientes asignaciones serían legales (para asignar un
valor a una señal, se usa el operador"<=''):

X<='}';
¡
. ¡
-- x es una señal de un solo bit (como ya se especificó), cuyo valor es
-- 'l '.Observe que se usan apóstrofes('') para un solo bit.

y<="Olll";
-- y es una señal de 4 bits (como ya se especificó), cuyo valor es"Ol 11"
-- (MSB='O'). Observe que se usan comillas (" ") para vectores.

w <= "01110001 ";


-- w es una señal de 8 bits, cuyo valor es "O 1110001" (MSB=' 1 ').

• STD_LOGIC (and STD_LOGIC_ VECTOR): sistema de 8 valores lógicos introducidos


en el standard IEEE 1164.

'X' Valor fuerte desconocido (Forcing Unknown: synthesizable unknown)


'O' O Fuerte (Forcing Low: synthesizable logic '1 ')
'1' 1 Fuerte (Forcing High: synthesizable logic 'O')
'Z' Alta Impedancia (High impedance: synthesizable tri-state buffer)
'W' Valor débil desconocido (Weak unknown)
'L' O débil Bajo débil (Weak low)
'H' 1 débil (Weak high)
' ' No importa (Don 't care)

Ejemplos:

SIGNAL x: STD _:_LOGIC;


-- x está declarada como una señal de un dígito (escalar) del tipo STD_LOGIC.

SIGNAL y: STD_LOGIC_VECTOR (3 DOWNTO O):= "0001";


-- y está declarada como un vector de 4 bits, con el bit de más a la izquierda como el
-- MSB. El valor inicial (opcional) de y es "0001 ''. Observe que se usa el operador ":="
-- para establecer el valor inicial.
La mayoría de los niveles std_logic están destinados solamente para simulación. Sin embargo,
'O', 'l', y 'Z' son sintetizables sin restricciones. Con respecto a los valores débiles ("weak'), se
resuelven en favor de los valores fuertes ("forcing") en nodos multiply-driven (vea tabla 3.1 ).
En efecto, si dos señales std_logic cualquiera están conectadas al mismo nodo, los niveles
lógicos en conflicto son automáticamente resueltos de acuerdo a la tabla 3.1.

Table 3.1
Sistema Lógico de resolución (STD_LOGIC).
X o 1 z w 1 H -
X X X X X X X X X
o X o X o o o o X
1 X X 1 1 1 1 1 X
z X o 1 z w L H X
w X o 1 w w w w X
L X o 1 L w L w X
H X o 1 H w w H X
- X X X X X X X X

• STD_ULOGIC (STD_ULOGIC_VECTOR): sistema de 9 niveles lógicos introducidos en


el standard IEEE 1164 ('U' 'X' 'O' '1' 'Z' 'W' 'L' 'H' '-')
1 ' ' ' ' 1 ' ' •

En efecto, el sistema STD_LOGIC descrito arriba es un subtipo del STD_ULOGIC. Este último
incluye un valor lógico extra, 'U', el cual se aplica a los casos no resueltos. Así que, al contrario
del STD_LOGIC, los conflictos de niveles lógicos no se resuelven automáticamente aquí, así que
los alambres nunca deben ser conectados directamente entre sí. Sin embargo, si se supone que
dos alambres de salida nunca se deben conectar juntos, este sistema lógico puede ser usado
para detectar errores de diseño.

• BOOLEAN: Verdadero, Falso


• INTEGER: Enteros de 32-bit (desde -2, 147,483,647 hasta +2, 147,483,647).
• NATURAL: Enteros no negativos (desde O hastato +2,147,483,647).
• REAL: Números Reales en el rango -1.0E38 hasta +1.0E38. No sintetizable.
• Physical literals: Usados para referirse a cantidades físicas, como time, voltage, etc. Útil
en Simulaciones. No sintetizable.
• Character literals: Single ASCII character ora string of such characters. No sintetizable.
• SIGNED y UNSIGNED: Tipos de datos definidos en el paquete std _logic _ arith de la
librería ieee. Tienen la apariencia de los STD_LOGIC_ VECTOR, pero aceptan operaciones
aritméticas, las cuales son típicas de los datos de tipo INTEGER (Los tipos SIGNED y
UNSIGNED se discutirán en detalle en la sección 3.6).

Ejemplos:

xO <='O'; , -- bit, std_Iogic, or std _ ulogic val u e 'O'


xl <= "00011111 "; -- bit_vector, std _logic _vector, -- std_ ulogic _vector, signed, o
-- unsigned
x2 <= "0001_1 l l l "; -- guión bajo permitido para facilitar la visualización
x3 <= " 1 O 1 1 1 1 " -- representación binaria del número decimal 4 7
x4 <= B" 1O1111" -- representación binaria del número decimal 47
x5 <= 0"57" -- representación octal del número decimal 4 7
x6 <= X"2F" __ representación hexadecimal del número decimal 4 7
n <= 1200; -- entero
m <= 1_200; -- entero, guión bajo permitido
IF ready THEN ... -- Booleano, se ejecuta si ready=TRUE
y<= l.2E-5; -- real, no sintetizable
q <= d after 10 ns; -- físico, no sintetizable

Ejemplo: Operaciones legales e ilegales entre datos de diferentestipos.

SIGNAL a: BIT;
SIGNAL b: BIT_ VECTOR (7 DOWNTO O);
SIGNAL e: STD _LOGIC;
SIGNAL d: STD _LOGIC_ VECTOR (7 DOWNTO O);
SIGNAL e: INTEGER RANGE O TO 255;

a<= b(5); -- legal (mismo escalar tipo: BIT)


b(O) <=.a; -- legal (mismo escalar tipo: BIT)
e<= d(5); -- legal (mismo escalar tipo: STD _LOGIC)
. d(O) <= c; -- legal (mismo escalar tipo: STD _ LOGIC)
a<=c; -- ilegal los tipos son diferentes: BIT x STD _LOGIC)
b <= d; -- ilegal (los tipos son diferentes: BIT_ VECTOR x STD _LOGIC _VECTOR)
e<=b; -- ilegal (los tipos son diferentes: INTEGER x BIT_ VECTOR)
e<= d; -- ilegal (los tipos son diferentes: INTEGER x STD - LOGIC - VECTOR)

3.2 Tipos de datos definidos por el usuario

VHDL también permite que el usuario defina sus propios tipos de datos. Enseguida mostramos
dos tipos de datos definidos por el usuario: integer y enumerated.

• Tipo integer definidopor el usuario

TYPE integer IS RANGE -2147483647 TO +2147483647;


-- Este es en efecto el tipo de dato pre-definido INTEGER.

TYPE natural IS RANGE O TO +2147483647;


-- Este es en efecto el tipo de dato pre-definido NATURAL.

TYPE my _integer IS RANGE -32 TO 32;


-- Un subconjunto de integers definidos por el usuario

·• TYPE student_grade IS RANGE O TO 100;


-- Un subconjunto de integers o naturals definidos por el usuario

• Tipos enumerated definidos por el usuario:

TYPE bit IS ('O', 'l ');


-- Este es en efecto el tipo de dato pre-definido BIT

TYPE my_logic IS ('O', '1', 'Z');


-- Un subconjunto de std_logic definido por el usuario.

TYPE bit_ vector IS ARRA Y (NATURAL RANGE < >) OF BIT;


-- Este es en efecto el tipo de dato pre-definido BIT VECTOR.
-- RANGE < > se usa para indicar que el rango está limitado.
-- NATURAL RANGE <>,por otra parte, indica que la única restricción es que el rango
-- debe ser del rango natural.

TYPE state IS (idle, forward, backward, stop);


-- Un tipo de dato enumerado, típico de máquinas de estado finitas.

TYPE color IS (red, green, blue, white );


-- Otro tipo de dato enumerado.

La codificación de los tipos enumerados se hace secuencialmente y automáticamente (a menos


que se especifique otra cosa por un atributo definido por el usuario, como se mostrará en el
capitulo 4). Por ejemplo, para el tipo de color de arriba, se necesitan dos bits (hay cuatro
estados), siendo "00" asignado al primer estado (red), "01" a el segundo (green), "10" a el
siguiente (blue), y finalmente '' 11 '' a el último estado (white).

3.3 Subtypes
Un SUBTYPE es un TYPE con una restricción. La principal razón para usar un subtipo en vez de
especificar un nuevo tipo es que, aunque las operaciones entre datos de diferentes tipos no son
permitidos. si son permitidos entre un subtipo y su correspondiente tipo base.

Ejemplo: Los subtipos siguientes fueron derivados de los tipos presentados en los previos
ejemplos.

SUBTYPE natural IS INTEGER RANGE O TO INTEGER 'HIGH;


-- Como se esperaba, NATURAL es un subtipo (subconjunto) de INTEGER.

SUBTYPE my_logic IS STD_LOGIC R.ANGE 'O' TO 'Z';


-- Recuerde que STD_LOGIC= ('X','O','l','Z','W','L','H','-').
-- Por tanto, rny _logic= ('O',' l ','Z').
SUBTYPE my_color IS color RANGE red TO blue;
-- Ya que color= (red, green, blue, white ), entonces
-- my _color= (red, green, blue ).
SUBTYPE small_integer IS INTEGER RANGE -32 TO 32;
-- Un subtipo de INTEGER.

Ejemplo: Operaciones legales e ilegales entre tipos y subtipos.

SUBTYPE my_logic IS STD_LOGIC RANGE 'O' TO 'l';


SIGNAL a: BIT;
SIGNAL b: STD_LOGIC;
SIGNAL e: my _logic;

b <=a; --ilegal (type mismatch: BIT versus STD_LOGIC)


b <=e; --legal (mismo tipo de "base" : STD _LOGIC)

3.4 Arreglos (Arrays)

Los arreglos son colecciones de objetos del mismo tipo. Pueden ser de una dimensión (1 O), de
dos dimensiones (20), o de una dimensión por una dimensión (1 Dx1 O). Pueden ser también de
dimensiones más grandes, pero generalmente no son sintetizables.
La figura 3:1 ilustra la construcción de arreglos de datos. Un valor simple (escalar) se muestra en
(a), un vector (array 1 O) en (b), un arreglo de vectores (array 1 Dx1 D) en (e), y un arreglo de
escalares (array 20) en (d).
En efecto, tos tipos de datos predefinidos (vistos en la sección 3.1) incluyen solamente las
categorías de escalares (un solo bit) y de vectores (arrays de bits de una sola dimensión). Los
tipos predefinidos sintetizables en cada una de estas categorías son los siguientes:

• Scalars: BIT, STO_LOGIC, STD_ULOGIC, y BOOLEAN.


• Vectors: BIT_VECTOR, STO_LOGIC_VECTOR, STD_ULOGIC_VECTOR,
INTEGER, SIGNED, and UNSIGNED.

o 1 o o o [QJ GJ [Q] [QJ [Q]


@] lo J o o o o o o O] @] [Q] O] @]
o o CD OJ GIJ 8U OJ
(a) (b) (e) (d)

Figure 3.1 Ilustración de (a) un escalar, (b) 1 o, (e) 1 Ox1 o, y (d) arreglos de datos 20.
Como se puede ver, no hay datos predefinidos para arreglos 20 o 1 Dx1 D, los cuales, cuando
sea necesario, deben ser especificados por el usuario. Para ello, el nuevo TYPE debe ser
primero definido, luego se puede declarar la nueva SIGNAL, VARIABLE o CONSTANT usando
ese tipo de dato. Se debe usar la siguiente sintaxis.

Para especificar un nuevo tipo de arreqlo:

TYPE type_name IS ARRA Y (especificación) OF data_type;

Para hacer uso del nuevo tipo de arreglo:

SIGNAL signal _name: type _ name [ := initial _val ue];

En esta sintaxis, se declaró una SIGNAL. Sin embargo, también podría ser una CONSTANT o
una VARIABLE. Observe que el valor inicial es opcional (solo para simulación)

Ejemplo: Arreglo 1 Dx1 D.

Suponga que queremos construir un arreglo que contenga cuatro vectores, cada uno de tamaño
de ocho bits.
Esto es un arreglo 1 Dx1 D (vea la figura 3.1 ). Llamemos a cada vector row, y al arreglo completo
matrix. Adicionalmente, supongamos que queremos que el bit de más a la izquierda de cada
vector sea su MSB (most significant bit), y que queremos que la fila superior sea la fila O.
Entonces la implementación del arreglo sería la siguiente (observe que una SIGNAL, llamada x,
de tipo matrix, se declaró como ejemplo):

TYPE row IS ARRA Y (7 DOWNTO O) OF STD_ LOGIC; -- arreglo lD


TYPE matrix IS ARRA Y (O TO 3) OF row; -- arreglo 1Dx1 D
SIGNAL x: matrix; -- señal lDxlD

Ejemplo: Otro arreglo 1 Dx1 D.

Otra manera de construir el arreglo 1 Dx1 D como el de arriba sería el siguiente:

TYPE matrix IS ARRA Y (O TO 3) OF STD_LOGIC_ VECTOR (7 DOWNTO O);

Desde el punto de vista de compatibilidad, este último podría ser más ventajoso que el del
ejemplo anterior (vea ejemplo 3.1 ).

Ejemplo: Arreglo 20.


El siguiente arreglo es realmente de dos dimensiones. Observe que su construcción no está
basada en vectores, sino más bien completamente en escalares.

TYPE matrix2D IS ARRA Y (O TO 3, 7 DOWNTO O) OF STD _LOGIC; -- 2D array

Ejemplo: Inicialización de arreglo.

Como se muestra en la sintaxis anterior, el valor inicial de una SIGNAL o una VARIABLE es
opcional. Sin embargo, cuando se requiere la inicialización, puede hacerse como en los ejemplos
siguientes.

:= "0001 "; -- para un arreglo 1 D


:= ('0','0','0','1 '); -- para un arreglo ID
·=
. (('O' ''I' ''I' ''1') ' ('1' ' '1' ''1' ' 'O'))·' -- para un arreglo l Dx ID o
-- arreglo 2D

Ejemplo: Asignaciones de arreglos legales e ilegales


Las asignaciones en este ejemplo están basadas en las siguientes definiciones de tipo y
declaraciones de señales:

TYPE row IS ARRAY (7 DOWNTO O) OF STD_LOGIC; -- Arreglo ID

TYPE array l IS ARRAY (O TO 3) OF row; -- Arreglo IDxlD

TYPE array2 IS ARRAY (O TO 3) OF STD_LOGIC _VECTOR (7 DOWNTO O);


-- Arreglo 1Dx1D
TYPE array3 IS ARRAY (O TO 3, 7 DOWNTO O) OF STD_LOGIC; -- Arreglo 2D

SIGNAL x: row;
SIGNAL y: array l ;
SIGNAL v: array2;
SIGNAL w: array3;

--------- Asignaciones escalares legales: ---------------


-- Las asignaciones escalares (un solo bit) siguientes son todas legales,
__ debido a que el tipo de "base" (escalar) es STD _LOGIC para todas las señales
-- (x, y, v, w).
X (O) <= y ( 1) (2); -- Observe dos pares de paréntesis (y es IDxlD)
X (1) <=V (2) (3); -- dos pares de paréntesis ( v es 1Dx1D)
X (2) <= W (2,1); -- un solo par de paréntesis (w es 2D)
y (1)(1) <=X (6);
y (2)(0) <=V (O) (O);
y (0)(0) <= w (3,3);
W (1,1) <=X (7);
W (3,0) <=V (0)(3);

--------- Asignaciones de vectores: .,: _


x <=y (O); -- legal (Mismo tipo de datos: ROW)
x <= v (l); -- ilegal (diferentes tipos: ROW x
-- STD_LOGIC_VECTOR)
X<= W (2); -- ilegal (w debe tener índice 20)
x <= w (2, 2 DOWNTO O); -- ilegal (diferentes tipos: ROW x
-- STD _LOGIC)
v(O) <= w (2, 2 DOWNTO O); -- ilegal (mismatch:
-- STD_LOGIC_ VECTOR x STD_LOGIC)
v(O) <= w (2); -- ilegal (w debe tener índice 2D)
y(l) <=V (3); -- illegal (tipos diferentes: ROW x
-- STD_LOGIC_ VECTOR)
y (1)(7 DOWNTO 3) <= x(4 DOWNTO O); -- legal (mismo tipo, mismo tamaño)
v (1)(7 DOWNTO 3) <= v(2)(4 DOWNTO O); -- legal (mismo tipo, mismo tamaño)
w(l, 5 DOWNTO 1) <= v(2)( 4 DOWNTO O); -- ilegal (tipos diferentes)

3.5 Arreglos de Puertos


Como hemos visto, no hay tipos de datos predefinidos para más de una dimensión. Sin embargo,
en las especificaciones de los pines de entrada o salida (PORTS) de un circuito (lo cual se hace
en la ENTITY), podríamos necesitar especificar los puertos como arreglos de vectores.
Ya que las declaraciones TYPE no se permiten en una ENTITY, la solución es declarar los tipos
de datos predefinidos por el usuario en un PACKAGE, el cual será visible al diseño total
(incluyendo así la ENTITY}. Enseguida se muestra un ejemplo.

------- Package: --------------------------


LIBRARY ieee;
USE ieee.std_logic_l 164.all;
----------------------------
PACKAGE my_data_types IS
TYPE vector array IS ARRA Y (NATURAL RANGE <>) OF
STD _LOGIC _VECTOR (7 DOWNTO O);
END my_data_types;
--------------------------------------------
------- Main code: -------------------------
LIBRARY ieee;
USE ieee.std_logic_l 164.all;
USE work.my _data_types.all; -- package definido por el usuario

·--------- ---·--··---
---------------------------
ENTITY mux IS
PORT (inp: IN VECTOR_ARRAY (O TO 3);
... );
END mux;
... '
--------------------------------------------

Como puede verse en el ejemplo anterior, se creó un tipo de dato definido por el usuario, llamado
vector _array, el cual puede contener un número indefinido de vectores de tamaño de ocho bits
cada uno (NATURAL RANGE < > significa que el rango no es fijo, con la única restricción de
que debe estar en el rango NATURAL, el cual va de O to +2, 147,483,647). El tipo de dato se
guardó en un PACKAGE llamado my_data_types, y luego se usó en una ENTITY para
especificar un PORT llamado inp. Observe en el código principal la inclusión de una cláusula
USE adicional para hacer el paquete definido por el usuario my_data_ types visible a el diseño.
Otra opción para el PACKAGE anterior sería el que se muestra enseguida, donde se incluyó una
declaración de una CONSTANT (en el capítulo 1 o se presentará un estudio detallado de
PACKAGES).

------- Package: -------------------------------


LIBRAR Y ieee;
USE ieee.std_logic_l 164.all;

PACKAGE my_data_types IS
CONSTANT b: INTEGER := 7;
TYPE vector_array IS ARRA Y (NATURAL RANGE <>) OF
STD _LOGIC _VECTOR(b DOWNTO O);
END my _data_ types;
-------------------------------------------------

3.6 Records

Los Records son similares a los arreglos, con la única diferencia de que ellos contienen objetos
de diferentes tipos.

Ejemplo:

TYPE birthday IS RECORD


day: INTEGER RANGE 1 TO 31;
month: month_name;
ENDRECORD;
3.7 Tipos de Datos Signad and Unsigned
Como se mencionó antes, estos tipos están definidos en el paquete std_logic_arith de la librería
ieee. Su sintaxis se ilustra en los ejemplos siguientes:

Ejemplo:
SIGNAL x: SIGNED (7 DOWNTO O);
SIGNAL y: UNSIGNED (O TO 3);

Observe que su sintaxis es muy similar a la de STD_LOGIC_ VECTOR, no como la de un


INTEGER, como podíamos haber esperado.
Un número UNSIGNED es un número que nunca es menor que cero. Por ejemplo "0101"
representaría el decimal 5, mientras que '11 O l '' significa 13. Si en vez de eso se usa el tipo
SIGNED, el valor puede ser positivo o negativo (en formato complemento a 2). Por lo tanto,
"O 1O1" representaría el decimal 5, mientras que '' 11O1 '' sería -3.

Para usar los tipos de datos SIGNED o UNSIGNED, se debe declarar el paquete std_logic_arith,
de la librería ieee, A pesar de su sintaxis, los tipos de datos SIGNED y UNSIGNED están
destinados principalmente para operaciones aritméticas, es decir, contrario a
STD_LOGIC_VECTOR, aceptan operaciones aritméticas. Por otra parte, no se permiten las
operaciones lógicas. Con respecto a las operaciones relacionales (comparación), no hay
restricciones.

Ejemplo: Operaciones legales e ilegales con tipos de datos signed/unsigned.

LIBRARY ieee;
USE ieee.std_logic_l 164.all;
USE ieee.std _logic _ arith.all; -- paquete extra necesario.

SIGNAL a: IN SIGNED (7 DOWNTO O);


SIGNAL b: IN SIGNED (7 DOWNTO O);
SIGNAL x: OUT SIGNED (7 DOWNTO O);

V <=a+ b; -- legal (operación aritmética OK)


w <=aANDb; -- ilegal (operación aritmética no OK)

Ejemplo: Operaciones legales e ilegales con tipos de datos std_logic_vector.

LIBRAR Y iece;
USE ieee.std - logic - 1164.all; -- no se require paquete extra

SIGNAL a: IN STD_LOGIC_ VECTOR (7 DOWNTO O);


SIGNAL b: IN STD_LOGIC_VECTOR (7 DOWNTO O);
SIGNAL x: OUT STD_LOGIC_ VECTOR (7 DOWNTO O);

<=a+ b;
V __ ilegal (operación aritmética no OK)
w <= aAND b; -- legal (operación lógica OK)

A pesar de las restricciones mencionadas arriba, hay una manera simple de permitir que los
datos de tipo STD_LOGIC_ VECTOR participen directamente en operaciones aritméticas. Para
eso, la librería ieee provee dos paquetes, std_logic_signed y std_logic_unsigned, los cuales
permiten operaciones con datos STD_LOGIC_ VECTOR para desarrollarlas como si fueran datos
de tipo SIGNED o UNSIGNED, respectivamente.

Ejemplo: Operaciones aritméticas con std_logic_vector.

LIBRAR Y ieee;
USE ieee.std _logic _ 1164.all;
USE ieee.std _ logic _ unsigned.all; -- paquete extra incluí do

SIGNAL a: IN STD_LOGIC_VECTOR (7 DOWNTO O);


SIGNAL b: IN STD_LOGIC_ VECTOR (7 DOWNTO O);
SIGNAL x: OUT STD _LOGIC _VECTOR (7 DOWNTO O);

V <=a+ b; -- legal (operación aritmetica OK), unsigned


w <=aANDb; -- legal (operación lógica OK)

3.8 Conversión de Datos

VHDL no permite operaciones directas (arithmetic, logical, etc.) entre datos de diferentes tipos.
Por tanto, a menudo es necesario convertir datos de un tipo a otro.
Esto puede hacerse de dos maneras básicas: podemos escribir una pieza de código VHDL para
eso, o invocamos una FUNCTION de un PACKAGE predefinido el cual es capaz de hacerlo por
nosotros.
Si los datos están muy relacionados (es decir, ambos operandos tienen el mismo tipo base, a
pesar de ser declarados como pertenecientes a dos tipos diferentes), entonces el std _logic _ 1164
de la librería ieee provee funciones de conversión directas (straightforward). En seguida se
muestra un ejemplo.

Ejemplo: Operaciones legales e ilegales con subconjuntos.

TYPE long IS INTEGERRANGE-100 TO 100;


TYPE short IS INTEGER RANGE -10 TO IO·
'
SIGNAL x : short;
SIGNAL y : long;

y <= 2*x + 5; -- error, no coinciden los tipos


y <=long (2*x + 5); -- OK, resulta convertido en tipo long

Se pueden encontrar algunas funciones de conversión en el paquete std _logic _ arith de la


librería ieee. Estas son:

• conv_integer (p) : Convierte un parámetro p de tipo INTEGER, UNSIGNED,


SIGNED, o STD_ULOGIC en un valor INTEGER. Observe que STD_LOGIC_ VECTOR no
está incluido.

• conv_unsigned (p, b): Convierte un parámetro p de tipo INTEGER, UNSIGNED,


SIGNED, or STD_ULOGIC a un valor UNSIGNED con tamaño de b bits.

• conv_signed (p, b): Convierte un parámetro p de tipo INTEGER, UNSIGNED, SIGNED, o


STD_ULOGIC a un valor SIGNED con tamaño de b bits.

• conv_std_logic_vector (p, b): Convierte un parámetro p de tipo INTEGER, UNSIGNED,


SIGNED, o STO- LOGIC a un valor STO- LOGIC- VECTOR con tamaño de b bits.

Ejemplo: Conversión de datos.

LIBRAR Y ieee;
USE ieee.std_logic_l 164.all;
USE ieee.std _logic _arith.all;

SIGNAL a: IN UNSIGNED (7 DOWNTO O);


SIGNAL b: IN UNSIGNED (7 DOWNTO O);
SIGNAL y: OUT STD_LOGIC_ VECTOR (7 DOWNTO O);

y <= CONV _STD_LOGIC_ VECTOR ((a+b), 8);


-- Operación legal: a+b se convierte de UNSIGNED a un
-- valor de 8-bits STD _LOGIC _VECTOR, luego se asigna a y.

Otra alternativa ya se mencionó en la sección previa. Consiste en usar el paquete


std_logic_signed o el std_logic_unsigned de la librería ieee.
Tales paquetes permiten operaciones con los datos STD_LOGIC_VECTOR para ser
desarrolladas como si los datos fueran de tipo SIGNED o UNSIGNED respectivamente.
Además de las funciones de conversión descritas arriba, algunas otras son a menudo ofrecidas
por vendedores de herramientas de síntesis.
3.9 Resumen
Los tipos de datos VHDL sintetizables se resumen en la tabla 3.2.

3.1 O Ejemplos adicionales


Cerramos este capítulo con la presentación de ejemplos adicionales que ilustran las
especificaciones y el uso del tipo de datos. El desarrollo de diseños reales a partir de cero solo
será posible después de concluir los fundamentos básicos del VHDL (capítulos 1 to 4).

Ejemplo 3.1: Tratando con tipos de datos

Las asignaciones legales e ilegales presentadas enseguida están basadas en las siguientes
definiciones de tipos y declaraciones de señales:

Tabla 3~2

Tipos de datos sintetizables.


---------------------------------------------------------------------------------------------------------------------
Data types Valores sintetizables
------------------------------------------------------------------------------------------------------------
BIT, BIT_ VECTOR 'O', '1'
STD_LOGIC, STD_LOGIC_ VECTOR 'X', 'O', 'l', 'Z' (resolved)
STD_ULOGIC, STD_ULOGIC_ VECTOR 'X', 'O', '1', 'Z' (unresolved)
BOOLEAN True, False
NATURAL From O to +2, 147, 483, 647
INTEGER From -2,147,483,647 to +2,147,483,647
SIGNED From -2,147,483,647 to +2,147,483,647
UNSIGNED From O to+2,147,483,647
User-defined integer type Subset ofINTEGER
User-defined enumerated type Collection enumerated by user
SUBTYPE Subset of any type (pre- or user-defined)
ARRA Y Single-type collection of any type above
RECORD Multiple-type collection of any types above

TYPE byte IS ARRA Y (7 DOWNTO O) OF STD_ LOGIC; -- Arreglo l D


TYPE meml IS ARRA Y (O TO 3, 7 DOWNTO O) OF STD_LOGIC; -- Arreglo 2D
TYPE mem2 IS ARRA Y (O TO 3) OF byte; -- Arreglo lDx 1 D
TYPE mem3 IS ARRA Y (O TO 3) OF STD_ LOGIC _VECTOR (O TO 7); -- Arreglo
-- lDxlD
SIGNAL a: STD _LOGIC; -- Señal escalar
SIGNAL b: BIT; -- Señal escalar
SIGNAL x: byte; -- Señal ID
SIGNAL y: STD_LOGIC_VECTOR(7 DOWNTO O); -- Señal lD
SIGNAL v: BIT VECTOR (3 DOWNTO O); -- lD signa]
SIGNAL z: STD _LOGIC _VECTOR (x'HIGH DOWNTO O); -- Señal 1 D
SIGNAL wl: mern l ; -- Señal 2D
SIGNAL w2: mern2; -- Señal lDxlD
SIGNAL w3: mem3; -- Señal lDxlD

-------- Asignaciones Escalares Legales: ---------------------


X (2) <=a; -- Mismos tipos (STD _LOGIC), indexado correcto
Y (O) <= x(O); -- Mismos tipos (STD _LOGIC), indexado correcto
Z (7) <= x(5); -- Mismos tipos (STD _LOGIC), indexado correcto
b <= v(3); -- Mismos tipos (BIT), indexado correcto
wl (0,0) <= x(3); -- Mismos tipos (STD _LOGIC), indexado correcto
w1 (2,5) =v (7); -- Mismos tipos (STD_LOGIC), indexado correcto
w2 (0)(0) <= x (2); -- Mismos tipos (STD_LOGIC), indexado correcto
w2 (2)(5) <=y (7); -- Mismos tipos (STD_LOGIC), indexado correcto
w1 (2,5) <= w2 (3) (7); -- Mismos tipos (STD _LOGIC), indexado correcto

------- Asignaciones Escalares Ilegales --------------------


b <= a; -- Tipos diferentes (BIT x STD_LOGIC)
wl (0)(2) <= x(2); -- el índice de wl debe ser 2D
w2 (2,0) <=a; -- el índice de w2 debe ser lDxlD

------- Asignaciones Legales de Vectores: ----------------------


x <="11111110";
y <= ('l','1','l','1','l','l','O','Z');
z <= "11111" & "000";
X <= (OTHERS => 'l ');

y <= (7 =>'O', 1 =>'O', OTHERS => 'l');


z <=y;
y (2 DOWNTO O) <= z (6 DOWNTO 4);
w2 (O) (7 DOWNTO O) <= "11110000";
w3 (2) <=y;
z <= w3 (1);
z (5 DOWNTO O) <= w3(1 )(2 TO 7);
w3 (1) <= "00000000";
w3 ( 1) <= (OTHERS => 'O');
w2 <= ((OTHERS=>'O'), (OTHERS=>'Ol (OTHERS=>'O'), (OTHERS=>'O'));
w3 <= ("11111100", ('O','O','O','O','Z','Z','Z','Z',),
(OTHERS=>'O'), (OTHERS=>'O'));
wl <= ((OTHERS=>'Z'), "11110000", "11110000", (OTHERS=>'O'));
------ Asignaciones ilegales de Arreglos: ----------------------
x <=y; -- Tipos diferentes
y(5 TO 7) <= z(6 DOWNTO O); -- dirección equivocada de y
w l <= (OTHERS => 'l '); -- wl es un arreglo de 2D
wl(O, 7 DOWNTO O) <="11111111 "; -- wl es un arreglo de 2D
w2 <= (OTHERS => 'Z'); -- wl es un arreglo de lDxlD
w2(0, 7 DOWNTO O) <= "11110000"; -- el índice debe ser lDxlD

-- Ejemplo de la inicialización de un arreglo independiente del tipo de dato:

FOR i IN O TO 3 LOOP
FORj IN 7 DOWNTO O LOOP
X G) <='O';

y G) <='O'
z G) <='O';
wl (i,j) <='O';
w2 (i) G) <='O';
w3 (i) G) <='O';
ENDLOOP;
ENDLOOP;
---------------------------------------------------------

Ejemplo 3.2: Bit Vs Vectores de Bits

Este ejemplo ilustra la diferencia entre la asignación de un solo bit y la asignación de un vector
de bits (es decir, BIT vs BIT_ VECTOR, STO_LOGIC vs STO_
LOGIC_VECTOR, o STD_ULOGIC vs STD_ULOGIC_VECTOR).
A continuación se presentan dos códigos VHDL. Ambos desarrollan la operación ANO entre las
señales de entrada y asigna el resultado a la señal de salida. La única diferencia entre ellos es el
número de bits en los puertos de entrada y de salida (un bit en el primero, cuatro bits en el
segundo). Los circuitos inferidos a partir de estos códigos se muestran en la figura 3.2.

ENTITY and2 IS ENTITY and2 IS


PORT (a, b: IN BIT; PORT (a, b: IN BIT_ VECTOR (O TO 3);
x: OUT BIT); x: OUT BIT _VECTOR (O TO 3));
END and2; END and2;
---------------------------------------------------
ARCHITECTURE and2 OF and2 IS ARCHITECTURE and2 OF and2 IS
BEGIN BEGJN
x <=aAND b; x <= aAND b;
END and2; END and2;
-------------------------------------------- ---------------------------------------------------

a(O)jJ- x(O}
b(O)

a(l)jJ- x(I)
h(I) .

ª(-.'))
b(2)
=fL__ ../
J
.'>
X(-)
.

a(3)jJ r- x(3)
b(J) ___/

Figura 3.2
Circuitos inferidos del código de los códigos del ejemplo 3.2

Ejemplo 3.3: Sumador

La figura 3.3 muestra el diagrama top-level de un sumador de 4-bits. El circuito tiene dos
entradas (a, b) y una salida (sum). Se presentan dos soluciones. En la primera, todas las
señales son de tipo SIGNED, mientras que en la segunda la salida es de tipo INTEGER. Note en
la solución 2 que se usó una función de conversión en la línea 13, ya que el tipo de a+b no es
igual al de sum. Observe también la inclusión del paquete std_logic _ aritli (línea 4 de cada
solución), el cual especifica los datos de tipo SIGNED. Recuerde que un valor SIGNED se
presenta como un vector; es decir, similar a STD_LOGIC_VECTOR, no como un entero.

1 ----- Solution 1: in/out=SIGNED ----------


2 LIBRAR Y ieee;
3 USE ieee.std _logic _ 1164.all;
4 USE ieee.std _logic _ arith.all;
5 ------------------------------------------
6 ENTITY adderl IS
7 PORT (a, b : IN SIGNED (3 DOWNTO O);
8 sum: OUT SIGNED (4 DOWNTO O));
9 END adder 1 ;
10 ------------------------------------------
11 ARCHITECTURE adderl OF adderl IS
12 BEGIN
13 sum <=a+ b;
14 END adderl;
15 ------------------------------------------

a{3:0)G
b (3:0) -
+ _ surn (4:0)

Figura 3.3
Sumador de 4-bits del ejemplo 3.3

100.0ns 200.0ns 3JO.Ons 400.0ns


t===:::::v===~==:---··------1.. . .--~-· - -
__ o __ . JLl_L ~_JL __ §. J _JL~_:J __~-~--I=_.~L~--J{
_¡_ .Ji •• -------~

s
o T=c=C~J:---Cl-D 4 X a }i e X o K
~-5Urn __ QQ J:._ _:!ª-___ K.__J.§._~U! __:LJ~ L __g_9 _
K_J);___l._ ~~~--_J,__Q'?_ __

Figura 3.4
Resultados de simulación del ejemplo 3:3

1 ------ Solution 2: out=INTEGER -----------


2 LIBRARY ieee;
3 USE ieee.std_logic_l164.all;
4 USE ieee.std _logic _ arith.all;
5 ------------------------------------------
6 ENTITY adder2 IS
7 PORT (a, b : IN SIGNED (3 DOWNTO O);
8 sum: OUT INTEGER RANGE-16 TO 15);
9 END adder2;
10 ------------------------------------------
11 ARCHITECTURE adder2 OF adder2 IS
12 BEGIN
13 sum <= CONV _INTEGER (a+ b );
14 END adder2;
15 ------------------------------------------

Los resultados de la simulación (para cada solución) se presentan en la figura 3.4. Observe que
los números se representan en forma hexadecimal y complemento a 2. Ya que el rango de
entrada es desde -8 a 7, su representación es 7 -7 7, 6 -7 6, ... , o -7 O, -1 -7 15, -2 -7 14, ... , -8 -7 &.
De la misma forma, el rango de salida es de -16 a 15, así que su representación es 15 -7 15, ... , O
r
7 O, -1731, ... ,-16-716. Por tanto, 2H + 4H = 06H (es decir, 2 + 4 = 6), 4H + BH = 1CH (es
decir, 4 + (-8) = -4), etc., donde H = Hexadecimal.

3.11 Problemas

Los problemas de abajo están basados en las siguientes definiciones TYPE y declaración de
señal SIGNAL:
TYPE arrayl IS ARRA Y (7 DOWNTO O) OF STD_LOGIC;
TYPE array2 IS ARRA Y (3 DOWNTO O, 7 DOWNTO O) OF STD LOGIC·
TYPE array3 IS ARRA Y (3 DOWNTO O) OF arrayl; - '

SIGNAL a: BIT;
SIGNAL b: STD_LOGIC;:
SIGNAL x : arrayl ; .
SIGNAL y: array2;
SIGNAL w: array3;
SIGNAL z: STD_LOGIC_VECTOR (7 DOWNTO O);

Problema 3.1
Determine la dimensionalidad (escalar, 1 O, 20, ar 1 Dx1 O) de las señales dadas. también, escriba
un ejemplo numérico para cada señal. .

Problema 3.2
Determine cuáles de las asignaciones de la tabla P3.2 son legales y cuáles son ilegales.
Brevemente justifique sus respuestas. También, determine la dimensionalidad de cada
asignación (en ambos lados).

Problema 3.3: Subtypes


Considere los tipos de datos predefinidos INTEGER and STD_LOGIC_VECTOR. Considere
también los tipos definidos por el usuario ARRAY1 y ARRAY2 especificados arriba. Para cada
uno, escriba un posible SUBTYPE.

Problema 3.4: ROM


Considere la implementación de una ROM (read-only memory). Puede ser hecha utilizando una
CONSTANT 1 Dx1 D. Digamos que la ROM debe estar organizada como una pila de ocho
palabras de cuatro bits cada una. Cree un arreglo llamado rom, luego defina una señal de tipo
rom capaz de resolver este problema. Escoja los valores que se almacenarán y declárelos con
su CONSTANT, es decir, "CONSTANT my_rom: rom :=(values) ;".

Problem 3.5: Sumador simple


Reescriba la solución 1 del ejemplo 3.3, pero esta vez con todas las señales de entrada y de
salida de tipo STD_LOGIC_ VECTOR. (Sugerencia: repase la sección 3.8).
Tabla P3.2

Assignment Dimensión Legal o ilegal


(en cada lado) (porqué)

a <= x(2);
b <= x(2);
b <= y(3,5);
b <= w(5)(3);
y( 1 )(O) <= z(7);
x(O) <= y(O,O);
X <= "1110000";
a <= "0000000";
y(l) <= x;
w(O) <=y;
w(l) <= (7=>'1 ', OTHERS=>'O');
y(l) <= (O=>'O', OTHERS=>'l');
w(2)(7 DOWNTO O) <= x;
w(0)(7 DOWNTO 6) <= z(5 DOWNTO 4);
x(3) <= x(5 DOWNTO 5);
b <= x(5 DOWNTO 5);
y <= ((OTHERS=>'O'), (OTHERS=>'O'),
(OTHERS=>'O'), "1000000 l ");
z(6) <= x(5);
z(6 DOWNTO 4) <= x(5 DOWNTO 3);
z(6 DOWNTO 4) <= y(5 DOWNTO 3);
y(6 DOWNTO 4) <= z(3 TO 5);
y(O, 7 DOWNTO O) <= z;
w(2,2) <= 'l';
4 OPERADORES Y ATRIBUTOS
El propósito de este capítulo, junto con los capítulos anteriores, es sentar las bases del VHDL, de
tal forma que en el siguiente capítulo podamos empezar a trabajar con el diseño de circuitos
reales. En efecto, es imposible -o poco productivo al menos- escribir cualquier código
eficientemente sin esforzarse por entender los tipos de datos, los operadores y los atributos
también.

Los operadores y los atributos constituyen una lista relativamente larga de construcciones
generales VHDL, que se examinan a menudo escasamente. Los hemos puesto juntos en un
capítulo específico con el propósito de proveer un estudio más completo y consistente.
Al final del capítulo, se presentan unos pocos diseños. Sin embargo, debido al hecho de que este
es un capítulo fundamental, los ejemplos son meramente ilustrativos, como los de los capítulos
anteriores. Como se mencionó antes, empezaremos trabajando con circuitos reales en el capítulo
5.

4.1 Operadores

VHDL provee varias clases de operadores predefinidos:

• Operadores de Asignación
• Operadores Lógicos
• Operadores Aritméticos
• Operadores Relacionales
• Operadores de Desplazamiento
• Operadores de Concatención

Cada una de estas categorías se describe enseguida.

Operadores de Asignación

Se usan para asignar valores a las señales, variables y constantes. Ellos son:

<= Se usa para asignar un valor a una SEÑAL.


Se usa para asignar un valor a una VARIABLE, una CONSTANTE, o un GENERIC.
Se usa también para establecer valores iniciales
=> Se usa para asignar valores a elementos individuales de vectores o con OTHERS.

Ejemplo: Considere las siguientes declaraciones de señales y variables:

SIGNAL x : STD _LOGIC;


VARIABLE y : STD_LOGIC _VECTOR (3 DOWNTO O); -- Leftmost bit is MSB
SIGNAL w: STD_LOGIC_ VECTOR (O TO 7); -- Rightmost bit is MSB

Entonces las siguientes asignaciones son legales:


x <= 'l '; -- 'l' se asigna a SI GNAL x usando "<="
y:= "0000"; -- "0000" se asigna a VARIABLE y usando":="
w <= "10000000"; -- LSB es 'l', los otros son 'O'
w <=(O =>'l', OTHERS =>'O'); -- LSB es 'I', los otros son 'O'

Operadores Lógicos

Se usan para desarrollar operaciones lógicas. Los datos deben ser del tipo BIT, STD_LOGIC, o
STD_ULOGIC (u, obviamente, sus respectivas extensiones, BIT_VECTOR,
STD_LOGIC_VECTOR, o STD_ULOGIC_VECTOR).

Los operadores lógicos son:

• NOT
•ANO
• OR
•NANO
• NOR
• XOR
• XNOR

Observe que el operador NOT tiene prioridad sobre los otros. El operador XNOR fue introducido
en VHDL93.

Ejemplo:

y<= NOT a AND b; -- (a'.b)


y<= NOT (a AND b); -- (a.b)'
y<= a NAND b; -- (a.b)'

Operadores Aritméticos
Se usan para desarrollar operaciones aritméticas. Los datos pueden ser del tipo INTEGER,
SIGNED-, UNSIGNED, o REAL (recuerde que estos últimos no pueden ser sintetizados
directamente). También, si se usa el paquete std_logic _signed o el paquete std _logic _unsigned
de la librería ieee, entonces pueden usarse STD_LOGIC_ VECTOR directamente en operaciones
de adición y substracción (como se vio en la sección 3.6).

+ Adición
Substracción
. Multiplicación
I División
** Exponenciación
MOD Módulo (Modulus)
REM Residuo (Remainder)
ABS Valor Absoluto

No hay restricciones de síntesis en relación a la adición y a la substracción, y lo mismo es


generalmente cierto para la multiplicación. Para la división sólo los divisores potencia de dos
(operación de desplazamiento) se permiten. Para exponenciación, sólo valores estáticos de base
Y exponente se aceptan. En relación a los operadores mod y rem, y mod x regresa el residuo de
y/x con la señal x. Mientras que y rem x regresa el residuo de y/x con la señal y. Finalmente, abs
regresa el valor absoluto. Con respecto a los últimos tres operadores (mod, rem y abs) hay
generalmente poco o ningún soporte.

Operadores de Comparación

Se usan para hacer comparaciones. Los datos pueden ser cualquiera de los ya mencionados.
Los operadores relacionales (comparación) son:

= Equal to
/= Not equal to
< Less than
> Greater than
<= Less than or equal to
>= Greater than or equal to

Operadores de desplazamiento
se usan para desplazamiento de datos. Fueron introducidos en VHDL93. Su sintaxis es como
sigue: <left operand> <shift operation> <right operand>. El operando de la izquierda debe ser
del tipo BIT_ VECTOR, mientras que el operando de la derecha debe ser INTEGER (+ o - frente
a él se aceptan). Los operadores de desplazamiento son:

• sll Shift left logic - las posiciones a la derecha se llenan con 'O's
• srl Shift right logic - las posiciones a !a izquierda se llenan con 'O's
• sla Shift left arithmetic -- El bit de más a la derecha se replica a la derecha
• sra Shift right aritmetic - El bit de más a la izquierda se replica a la izquierda
• rol Rotate left -- Rotación hacia la izquierda
• ror Rotate right -- Rotación hacia la derecha

Ejemplos, digamos que x <= "01010", entonces:


or ()Ci I 6JoJ D

Y<= X sfl 2; __ Desplazamiento lógico hacia la izquierda por 2: y<= "00100!11 ° l oc<r>
Y<= x sla 2; Desplazamiento aritmético hacia la izquierda por 2: y ~~ "0"0111"
Y<= x srl 3; Desplazamiento lógico hacia la derecha por 3: y<= "00001"
Y<= x sra 3; Desplazamiento aritmético hacia la derecha por 3: y <= "00001"
Y<= x rol 2; Rotación lógica hacia la izquierda por 2: Y<= "00101"
Y <= x srl -2; -- Igual que sll 2

Operadores de concatenación

Atributos de los datos


Se usan para agrupar valores. Los datos pueden ser de cualquiera de los tipos enlistados ara
operaciones lógicas. Los operadores de concatenación son:

&
(, ' ' )

Ejemplos

Z<= x & "l 000000"; Si x <= 'l ',entonces z <= "11000000"

Z<=('l', 'l', 'O', 'O', 'O', 'O', 'O', 'O',); z<="IIOOOOOO"

4.2 Atributos
El propósito de los atributos es dar al VHDL más flexibilidad, y también permitir la construcción de
piezas de código genéricas (código que trabajará para cualquier tamaño de vectores y arrays,
por ejemplo. Tales atributos se dividen en dos grupos:

Atributos de datos: Regresan información (un valor) con respecto a un vector de datos;
Atributos de señales: Sirven para monitorear una señal (regresa TRUE o FALSE)

En cualquiera de los casos, para usar un atributo se debe emplear"" (apóstrofes) Además de una
lista de atributos predefinidos, VHDL también permite atributos definidos por el usuario. Los
primeros se presentarán en esta sección, mientras que los últimos se discutirán en la sección 4.3.

Los atributos de datos predefinidos y sintetizables son los siguientes:

• d'LOW: Regresa el índice más bajo del arreglo.


• d'HIGH: Regresa el índice más alto del arreglo.
• d'LEFT: Regresa el índice más a la izquierda del arreglo
• d'RIGHT: Regresa el índice más a la derecha del arreglo
• d'LENGTH: Regresa el tamaño del vector
• d'RANGE: Regresa el rango del vector
• d'REVERSE_RANGE: Regresa el rango del vector en orden inverso
Ejemplo: Considere la siguiente señal:

SIGNAL d : STD_LOGIC _VECTOR (7 DOWNTO O);

Entonces:

d'LOW =O, d'HIGH = 7, d'LEFT = 7, d'RIGHT =O, d'LENGTH = 8,


d'RANGE = (7 downto O), d'REVERSE _RANGE = (O to 7).

Ejemplo: Considere la siguiente señal:

SIGNAL x: STD_LOGIC_VECTOR(O TO 7);

Entonces los cuatro estatutos LOOP que siguen son sintetizables y equivalentes:

FOR i IN RANGE (O TO 7) LOOP ...


FOR i IN x'RANGE LOOP ...
FOR i IN RANGE (x'LOW TO x'HIGH) LOOP ...
FOR i IN RANGE (O TO x'LENGTH-1) LOOP ...

Si la señal es de tipo enumerado, entonces:

• d'VAL (pos): Regresa el valor de la posición especificada


• d'POS (value): Regresa la posición del valor especificado
• d'LEFTOF(value): Regresa el valor en la posición de la izquierda del valor especificado
• d'VAL(row, column): Regresa el valor en la posición especificada; etc.

Hay poco o ningún soporte para datos de tipo enumerado.

Atributos de Señales

Consideremos una señal s. Entonces:


• s'EVENT: Regresa un valor verdadero cuando ocurre un evento en s
• s'STABLE: Regresa un valor verdadero si no ha ocurrido un evento en s
• s' ACTIVE: Regresa un valor verdadero sis = '1'
• s'QUIET <time>: Regresa un valor verdadero si no ha ocurrido ningún evento durante el
tiempo especificado
• s'LAST _EVENT: Regresa el tiempo transcurrido desde el último evento
• s'LAST _ACTIVE: Regresa el tiempo transcurrido desde el últimos= '1'
• s'LAST _VALUE: Regresa el valor de s antes del último evento; etc.
A pesar de que la mayoría de los atributos de las señales son para fines de simulación
solamente, los dos primeros de la lista anterior son sintetizables, siendo s'EVENT el más usado
de todos.

Ejemplo: Las cuatro asignaciones mostradas enseguida son sintetizables y equivalentes.


Regresan un valor verdadero cuando ocurre un evento (un cambio ocurre) en clk, Y si tal evento
es hacia arriba (en otra palabras, cuando ocurre una transición positiva en clk).

lF ( clk'EVENT AND clk=' l ')... -- Atributo EVENT usado with IF


IF (NOT clk'STABLE AND clk=' l ')... -- Atributo STABLE usado con IF
WAIT UNTIL ( clk'EVENT AND clk=' l '); -- Atributo EVENT usado con WAIT
IF RISING_EDGE(clk)... -- Llamado a una función

4.3 Atributos definidos por el usuario

Vimos anteriormente atributos del tipo HIGH, RANGE, EVENT, etc. Estos están predefinidos en
el VHDL87. Sin embargo, VHDL también permite la construcción de atributos definidos por el
usuario. Para emplear un atributo definido por el usuario, debe ser declarado y especificado. La
sintaxis es la siguiente:

Declaración de atributo:

ATTRIBUTE attribute_name: attribute_type;

Especificación del atributo:

ATTRIBUTE attribute _ name OF target_ name: class IS value;

donde:
attribute_type: cualquier tipo de dato (BIT, INTEGER, STD_LOGIC_ VECTOR, etc.)
clase: TYPE, SIGNAL, FUNCTION, etc.
va l or.· 'O' , 27 , "00 11 10 01" , etc.

Ejemplo:

ATTRIBUTE number_of_inputs: INTEGER; -- declaración


ATTRIBUTE number_of_inputs OF nand3: SIGNAL IS 3; -- especificación

inputs <= nand3 'number _ of_pins; -- attribute call, retums 3

Ejemplo: Codificador Enumerado.


Un atributo popular definido por el usuario, el cual es provisto por vendedores de herramienta de
síntesis, es el atributo enum_encoding. Por default, los datos de tipo enumerado son codificados
secuencialmente. De esta manera, si consideramos el tipo de dato enumerado color que se
muestra enseguida:

TYPE color IS (red, green, blue, white );

Sus estados se codificarán como red = "00", green = "O l ", blue = "10", y white = "11 ".
Enum _ encoding permite que la codificación por default (secuencial) sea cambiada. Por tanto el
siguiente esquema de codificación podría ser empleado, por ejemplo:

ATTRIBUTE enum_encoding OF color: TYPE IS "110010 01 ";

Un atributo definido por el usuario puede ser declarado en cualquier parte, excepto en un
PACKAGE BODY. Cuando no se reconoce por una herramienta de síntesis, simplemente es
ignorado, o se emite una advertencia.

4.4 Sobrecarga de operadores

Acabamos de ver que los atributos pueden ser definidos por el usuario. Lo mismo es cierto para
los operadores. Por ejemplo, consideremos los operadores aritméticos predefinidos vistos en la
sección 4.1 (+, -, *,/,etc.). Estos especifican las operaciones aritméticas eritre datos de ciertos
tipos (INTEGER, por ejemplo). Por ejemplo, el operador predefinido "+" no permite la suma
entre datos del tipo BIT.

Nosotros podemos definir nuestros propios operadores, usando el mismo nombre que los
predefinidos. Por ejemplo, podríamos usar ''+'' para indicar una nueva clase de suma, esta vez
entre los valores del tipo BIT_VECTOR. Esta técnica se llama sobrecarga del operador.

Ejemplo: Considere que queremos sumar un entero con un número binario de 1 bit. Entonces
podríamos usar la siguiente FUNCTION (los detalles sobre cómo construir y usar una
FUNCTION se verá en el capítulo 11 ):

--------------------------------------
FUNCTION "+" (a: INTEGER, b: BIT) RETURN INTEGER IS
BEGIN
IF (b=' l ') THEN RETURN a+ 1 ;
ELSE RETURN a;
END IF;
END"+";
--------------------------------------
Un llamado a la función podría ser el siguiente:

SIGNAL inpl, outp: INTEGERRANGE O TO 15;


SIGNAL inp2: BIT;
( ... )
outp <= 3 + inpl + inp2;
(... )

En "outp<=3+inpl +inp2;", el primer "+'' es el operador de adición predefinido (suma dos


enteros), mientras que el segundo es el operador de adición sobrecargado predefinido por el
usuario (suma un entero con un bit).

4.5 GENERIC

Como su nombre lo sugiere, GENERIC es una manera de especificar un parámetro genérico (es
decir, un parámetro estático que puede ser fácilmente modificado y adaptado a diferentes
aplicaciones). El propósito es conferir al código más flexibilidad and reutilización.
Una sentencia GENERIC, cuando se emplea, debe ser declarada en la ENTITY. El parámetro
especificado será entonces verdaderamente global (es decir, visible al diseño total, incluyendo la
ENTITY misma). Su sintaxis es como sigue.

GENERIC (parameter _name : parameter _ type := parameter _ value );

Ejemplo: La siguiente sentencia GENERIC especifica un parámetro llamado n, del tipo


INTEGER, cuyo valor de default es 8. Por lo tanto, dondequiera que se encentren en la ENTITY
misma o en la ARCHITECTURE (una o más) que siga, se asumirá que su valor es 8.

ENTITY my _ entity IS
GENERIC (n: INTEGER := 8);
PORT ( ... );
END my _ entity;
ARCHITECTURE my _architecture OF my_ entity IS

END mv architecture:
.;_

Se puede especificar más de un parámetro GENERIC en una ENTITY. Por ejemplo:

GENERIC (n: INTEGER := 8; vector: BIT _VECTOR := "00001111 ");

Enseguida se muestran ejemplos de diseño completos, ilustrando el uso de GENERIC Y otros


atributos y operadores.
4.6 Ejemplos

Mostramos ahora unos pocos ejemplos de diseño completos, con el propósito de ilustrar el uso
de los operadores, atributos y GENERIC. Recuerde, sin embargo, que hasta aquí hemos
trabajado en establecer los fundamentos del VHDL, con la discusión formal de las técnicas de
codificación empezando en el siguiente capítulo (capítulo 5). Por lo tanto, el estudiante novato
en VHDL no se debe desanimar si los ejemplos le parecen poco familiares. En vez de eso, eche
una mirada a los siguientes ejemplos, y luego, después de estudiar los capítulos del 5 al 7,
regrese y vuélvalos a examinar.

Ejemplo 4.1: DecodificadorGenérico

La Figure 4.1 muestra el diagrama top-level de un decodificador genérico m-by-n. El circuito


tiene dos entradas, sel (m bits) y ena (single bit), y la salida, x (n bits). Suponemos que n es
una potencia de 2, tal que m = log2n. Si ena = 'O', entonces todos los bits de x deben estar en
nivel alto; de otra manera, el bit de salida seleccionado por sel debe estar en nivel bajo, como se
ilustra en la tabla de verdad de la figura 4.1.

X(n-1) ena sel X


sel (m-LO) +
mxn X(n-2) o 00 l1 j l
DECODER 1 00 1110
x(1) Ol 1101
ena-> x(O)
IO 1011
11 0111

Figure 4.1
Decodificador del ejemplo 4.1.

La ARCHITECTURE siguiente es totalmente genérica, ya que los únicos cambios necesarios


para operar con diferentes valores de m y n están en la ENTITY (en sel, línea 7, y x, línea 8,
respectivamente). En este ejemplo, usamos m = 3 y n = 8. Sin embargo, aunque este trabajo es
correcto, el uso de GENERIC hubiera dejado más claro que m y n son en efecto parámetros
genéricos. Este es en efecto el procedimiento que adoptaremos en los ejemplos que siguen (por
favor, refiérase al problema 4.4).

Observe en el código siguiente el uso de los operadores "+" (línea 22), "*" (líneas 22 y 24),
":=" (líneas 17, 18, 22, 24, y 27), "<=" (línea 29), and "=>" (línea 17). Observe también el
uso de los siguientes atributos: HIGH (lineas 14-15) y RANGE (línea 20).

1 ---------------------------------------------
2 LIBRARY ieee;
3 USE ieee.std_logic_l 164.all;
4 ---------------------------------------------
5 ENTITY decoder IS
6 PORT ( ena : IN STD_LOGIC;
7 sel: IN STD_LOGIC_ VECTOR (2 DOWNTO O);
8 x: OUT STD_LOGIC_ VECTOR (7 DOWNTO O));
9 END decoder;
10 ---------------------------------------------
11 ARCHITECTURE generic _ decoder OF decoder IS
12 BEGIN
13 PROCESS ( ena, sel)
14 VARIABLE templ: STD_LOGIC_ VECTOR (x'HIGH DOWNTO O);
15 VARIABLE temp2 : INTEGER RANGE O TO x'HIGH;
16 BEGIN
17 templ := (OTHERS => '1');
18 temp2 :=O;
19 IF ( ena=' 1 ') THEN
20 FOR i IN sel'RANGE LOOP -- sel range is 2 downto O
21 IF (sel(i)='l ') THEN -- Bin-to-Integer conversion
22 temp2:=2*temp2+ 1;
23 ELSE
24 temp2 := 2*temp2;
25 END IF;
26 ENDLOOP;
27 templ(temp2):='0';
28 END IF;
29 x <= templ;
30 END PROCESS;
31 END generic _ decoder;
32 ---------------------------------------------

í rn Dns 3Cl[UJns
,_ .4Cü On s 5'JO On!

~,~;il
DIJ ·-· ---··¡i·----
·--·· ·-).~- -·----· ~J· ·-· · ü· ·-· · · --~:c
---··:T-·-· ··---x· ·· . ,:.: -· 2 . ' :(··-"'·"·~~- ··-. ·-}(. 11 > ·;s- --- ·~r-~ -5·- ·-~l--·-7· . --)~

~)' 7:,3 X 2!5 t ): 2J7 X. 139 ¡: 223 :1; 191 \ 1z1 ,(

Figure 4.2
Resultado de la Simulación del ejemplo 4.1.
La funcionalidad del decodificador anterior se puede verificar en los resultados de la simulación
de la figure 4.2. Como puede verse, todas las salidas están en nivel alto, es decir, x =
'' 11111111 '' (decimal 255), cuando ena = 'O'· Después que ena ha sido puesta en 'l', solo un
bit de salida (el seleccionado por sel) se pone en nivel bajo. Por ejemplo, cuando sel = "000"
(decimal O), x = "1111111 O" (decimal 254); cuando sel = "00 l" (decimal 1 ), x = "11111101"
(decimal 253); cuando sel = "O 10" (decimal 2), x = "11111O11" (decimal 251 ); etcétera.

Ejemplo 4.2: Detector de paridad genérico

La figura 4.3 muestra el diagrama top-level de un detector de paridad. El circuito debe proveer
una salida = 'O' cuando el número de '1 'sen el vector de entrada es par, o una salida = '1' en otro
caso. Observe en el código VHDL siguiente que la ENTITY contiene una sentencia GENERIC
(línea 3), la cual define n como 7. Este código trabajará para cualquier otro tamaño de vector,
siendo sólo necesario cambiar el valor den en esa línea. Se le invita a destacar los operadores Y
atributos que aparecen en este diseño.
Ejemplo

11101110 rango= 7 - O
O xor 1 xor 1 xor 1 xor O xor 1 xor 1 xor 1 xor O= O hay 6 1 's (par)

11101100 rango 7 - O
O xor 1 xor 1 xor 1 xor O xor 1 xor 1 xor O xor O= 1 hay 5 1 's (impar)

PARITY
input (n:O) DETECTOR
output

Figura 4.3
Detector de paridad Genérico del ejemplo 4.2.

125.0ns 291lJns 375.0ns 50J.Ons 6~5.0ns 7


y "\' \r::;-
winput [I o n 'I
¡\ ·' 2 :{ 3 ); 4 1, 5 .l' 6 '1
''--
"'· 1
-=W ouíput o ~ 1 1

Figura 4.4
Resultado de la Simulación del ejemplo 4.2.

--------------------------------------------
2 ENTITY parity_det IS
3 GENERIC (n : INTEGER := 7);
4 PORT (input: IN BIT_ VECTOR (n DOWNTO O);
5 output: OUT BIT);
6 END parity _ det;
7 --------------------------------------------
8 ARCHITECTURE parity OF parity _ det IS
9 BEGIN
10 PROCESS (input)
11 VARIABLE temp: BIT;
12 BEGIN
13 temp :='O';
14 FOR i IN input'RANGE LOOP
15 temp := temp XOR input(i);
16 ENDLOOP;
17 output <= temp;
18 END PROCESS;
19 END parity;
20 --------------------------------------------

La simulación que resulta del circuito sintetizado con el código mostrado arriba se muestra en la
figura 4.4. Observe que cuando input = "00000000" (decimal O), la salida es 'O', porque el
número de '1 's es par; Cuando input = "00000001" (decimal 1 ), la salida es 'l ', porque el
número de '1 'ses impar; y etc.

Ejemplo 4.3: Generador de paridad genérico

El circuito de la figura 4.5 debe sumar un bit al vector de entrada (a su izquierda). Tal bit debe ser
un 'O' si el número de '1 's en el vector de entrada es par, o un 'l' si es impar, tal que el vector
resultante siempre contendrá un número par de 'l 's (paridad par). Un código VHDL para el
generador de paridad se muestra enseguida. Una vez más se le invita, a destacar los
operadores y atributos usados en el diseño.

input (n-t :O) --11--1


PARITY
GENEHATOR r output (11:0)

Figure 4.5
Resultado de la Simulación del ejemplo 4.3.

1 -----------------------------------------------
2 ENTITY parity _gen 1 S
3 GENERIC (n : INTEGER := 7);
4 PORT (input: IN BIT_ VECTOR (n-1 DOWNTO O);
5 output: OUT BIT_VECTOR (n DOWNTO O));
6 END parity _gen;
7 -----------------------------------------------
8 ARCHITECTURE parity OF parity _gen IS
9 BEGIN
10 PROCESS (input)
11 VARIABLE templ: BIT;
12 VARIABLE temp2: BIT_ VECTOR (output'RANGE);
13 BE GIN
14 templ :='O';
15 FOR i IN input'RANGE LOOP
16 temp 1 := temp 1 XOR input(i);
17 temp2(i) := input(i);
18 END LOOP;
19 temp2( output'HIGH) := temp 1;
20 output <= temp2;
21 END PROCESS;
22 END parity;
23 -----------------------------------------------

La simulación que resulta se muestra en la figure 4.6. Como se puede ver, cuando input =
"0000000" (decimal O, con siete bits), output = "00000000" (decimal O, con ocho bits);
cuando input= "0000001" (decimal 1, con siete bits), output = "10000001" (decimal 129, con
ocho bits); y así sucesivamente.

:50 O ns 10J. On:3 EO O ns 2CO. O ns :2!:0 O ns 300.0n s 3:5(UJ115

g;: input
~ output

Figura 4.6
Resultado de la simulación del ejemplo 4.3.

4.7 Resumen
En las tablas 4.1 y 4.2 se presenta un resumen de operadores y atributos VHDL,
respectivamente. Las partes que no son sintetizables (o que tienen poco soporte de síntesis) se
marcan con el simbolo ">'.
Tabla 4.1

Operadores.
Tipo de operador Operadores Tipos de <Datos

Assignment <=, :=, => Any

Logical NOT, ANO, NANO, BIT, BIT_VECTOR,


OR, NOR, XOR, XNOR STO_LOGIC, STO_LOGIC_VECTOR,
- - -
STO ·uLOGIC, STO ULOGIC VECTOR

Arithmetic +, -, *' /, ** INTEGER, SIGNEO, UNSIGNED


(mod, rem, abs)•

Comparison =, t=, <, >, <=, >= All above

Shift sll, srl, sla, sra, rol, ror BIT_VECTOR

Concatenation s, (' '') Same as for logical operators, plus


SIGNED and UNSIGNED

Tabla 4.2
Attributes.

Aplicación Attributes Valor que regresa

For regular DATA d'LOW Lower array index


d'HIGH Upper array index
d'LEFT Leftmost array index
d'RIGHT Rightmost array index
d'LENGTH Vector size
d'RANGE Vector range
d'REVERSE_RANGE Reverse vector range

For enumerated d'VAL(pos)• Value in the position specified


DATA d'POS(value)• Position of the value specified
d'LEFTOF(value)• Value in the position to the left of
the value specified
d'VAL(row, column)• Value in the position specified
For a SIGNAL s'EVENT True when an event occurs on s
s'STABLE True if no event has occurred on s
s'ACTIVE) True if s is high
4.8 Problemas
Los problemas 4.1 al 4.3 están basados en las siguientes declaraciones de señales:

SIGNAL a: BIT:= 'l';


SIGNAL b: BIT_ VECTOR (3 DOWNTO O):= "1100";
SIGNAL e: BIT_ VECTOR (3 DOWNTO O):= "0010";
SIGNAL d : BIT_ VECTOR (7 DOWNTO O);
SIGNAL e : INTEGER RANGE O TO 255;
SIGNAL f: INTEGER RANGE-128 TO 127;

Problema 4.1: Operadores (llene los espacios en blanco)

xl <=a & e; -> xl <=


x2 <=e & b; -> x2 <=
x3 <=bXORc; -> x3 <=
x4 <=a NOR b(3); -> x4 <=
x5 <= b sll 2; -> x5 <=
x6 <= b sla 2; -> x6 <=
x7 <= b rol 2; -> x7 <=
---
x8 <=a AND NOT b(O) AND NOT c(l ); -> x8 <= ---
d <= (5=>'0', OTHERS=>'l'); -> d<= _

Problema 4.2: Atributos (llene los espacios en blanco)

c'LOW ->
d'HIGH ->
c'LEFT ->
d'RIGHT ->
c'RANGE ->
d'LENGTH ->
c'REVERSE _RANGE ->

Problema 4.3: Operaciones Legales e Ilegales

verifique si cada una de las siguientes operaciones es legal o ilegal. Brevemente justifique sus
respuestas

b(O) AND a
a+ d(7)
NOTbXNORc
c+d
e-f
IF (b<c)
IF (b>=a) .
IF (f/=e) .
IF (e>d)
b sra 1
e srl -2
fror 3
e*3
5**5
f/4
e/3
d<=c
d(6 DOWNTO 3) := b
e<=d
f := 100

Problema 4.4: Decodificadorgenérico

Las siguientes preguntas están relacionadas con el circuito decodificador diseñado en el ejemplo
4.1
(a) Con el propósito de que ese diseño opere con otro tamaño de vector, se debe cambiar dos
valores: el rango de sel (línea 7) y el rango de x (line 8). Ahora queremos transformar ese diseño
en uno verdaderamente genérico. Con éste propósito, introduzcamos una sentencia GENERIC
en la ENTITY, especificando el número de bits de sel (digamos, n = 3), luego reemplace los
límites superiores de los rangos de sel y de x por un atributo el cual es una función den.

Sintetice y simule su circuito con el objeto de verificar su funcionalidad.

(b) En el ejemplo 4.1, se implementó una conversión binary-to-integer (líneas 20-26).


Esta conversión pudo haberse evitado si sel hubiera sido declarada como un INTEGER.
Modifique el código, declarando sel como un INTEGER. El código debe permanecer
verdaderamente genérico, tal que el rango de sel debe estar especificado en términos de n.
Sintetice y simule su nuevo código.

Problema 4.5
Enliste todos los operadores, atributos y genéricos empleados en los ejemplos 4.2 y 4.3.
5 CÓDIGO CONCURRENTE
Habiendo terminado de exponer los fundamentos del VHDL (capítulos 1 to 4), podemos ahora
concentrarnos en el diseño mismo(código).
El código VHDL puede ser concurrente (paralelo) o secuencial. Estudiaremos el primero en este
capítulo, mientras que el último se estudiará en el capítulo 6. Esta división es muy importante, ya
que permite un mejo entendimiento del propósito de cada estatuto para cada clase de código,
además de las consecuencias de usar uno o el otro.
Los estatutos concurrentes en VHDL son WHEN y GENERATE. Además de ellos, las
Asignaciones usando solo operadores (ANO, NOT, +, *, sll, etc.) pueden ser usados también para
construir código concurrente. Finalmente, una clase especial de asignación, llamado BLOCK,
puede ser empleada en esta clase de código.

5.1 Concurrente versus Secuencial


Empezamos este capítulo revisando las diferencias fundamentales entre lógica combinacional y
lógica secuencial. Y las contrastaremos con el código concurrente y el código secuencial.

Lógica Combinacional versus Lógica Secuencial.

Por definición, lógica combinaconal es aquella en la que la salida del circuito depende solamente
de las entradas presentes (figura 5.1 (a)). Es claro entonces que, en principio, el sistema no
requiere memoria y puede ser implementado usando funciones lógicas convencionales.

En contraste, la lógica secuencial está definida como aquella en la que la salida sí depende de
entradas previas (figure 5.1 (b)). Por lo tanto, se requieren elementos de almacenamiento, los
cuales están conectados al block de lógica combinacional por medio de un lazo de
retroalimentación, tal que ahora los estados almacenados (creados por entradas previas)
también afectarán la salida del circuito.

Un error común es pensar que cualquier circuito que posee elementos de almacenamiento (flip-
flops) es secuencial. Una RAM (Random Access Memory) es un ejemplo. Una RAM puede ser
modelada como en la figura 5.2. Observe que los elementos de almacenamiento aparecen en
forward path y no en un feedback de retroalimentación. Las operaciones de lectura dependen
solamente de el vector de dirección actual aplicado a la entrada de la RAM, y .el valor obtenido
de la lectura no tiene nada que ver con los accesos de memoria previos.

Código Concurrente versus Código Secuencial

El código VHDL es inherentemente concurrente (paralelo). Sólo estatutos colocados en un


PROCESS, FUNCTION, o PROCEDURE son secuenciales. Aun cuando en el interior de estos
bloques la ejecución es secuencial, el bloque, en su conjunto, es concurrente con cualquier otro
estatuto (externo). El código concurrente también se llama código de flujo de datos.
¡
. ·1
¡

input...,. out pul


input Combinalional ouíput Combinational
Logic Logic

present next
state Storage state
Elements

(a) {b)

Figure 5.1
Lógica (a) Combinacional versus (b) Lógica secuencial.

input ..._.,. Combinational output


Logic

Storage
Elerncnts

Figure 5.2
Modelo RAM

Por ejemplo, consideremos un código con tres estatutos concurrentes (stat1, stat2, stat3).
Entonces, cualquiera de las siguientes alternativas dará el mismo circuito:

stat1 stat3 stat1


stat2 = stat2 = stat3 = etc.
stat3 stat1 stat2

Es entonces claro que, ya que el orden no importa, el código puramente concurrente no puede
ser usado para implementar circuitos síncronos (la única excepción es cuando se usa un
GUARDED BLOCK). En otras palabras, en general podemos construir sólo circuitos lógicos
combinacionales con el código concurrente. Para obtener circuitos lógicos secuenciales, se debe
usar código secuencial (capítulo 6). En efecto, con estos últimos podemos implementar ambos,
circuitos secuenciales así como circuitos combinacionales.

En este capítulo, discutiremos código concurrente, es decir, estudiaremos las sentencias que
sólo pueden ser usadas fuera de PROCESSES, FUNCTIONS, o PROCEDURES. Ellas son la
sentencia WHEN y la sentencia GENERATE. Además de ellas, las asignaciones que usan solo
operadores (lógicos, aritméticos, etc) pueden obviamente también ser usadas para crear circuitos
combinacionales. Finalmente, una clase especial de sentencia¡ llamada BLOCK, puede también
emplearse

En resumen, en código concurrente se puede usar lo siguiente:

• Operadores;
• La sentencia WHEN (WHEN/ELSE o WITH/SELECT/WHEN);
• La sentencia GENERATE;
• La sentencia BLOCK.

Cada uno de estos casos se describe enseguida.

5.2 Usando Operadores


Esta es la manera más básica de crear código concurrente. Los operadores (ANO, OR, +, -, *, sll,
sra, etc.) fueron discutidos en la sección 4.1, y en la tabla 5.1 se repite un resumen.
Los operadores pueden ser usados para implementar cualquier circuito combinacional. Sin
embargo, como se hará evidente más adelante, circuitos complejos suelen ser más fáciles de
escribir usando código secuencial, aun si el circuito no contiene lógica secuencial. En el ejemplo
siguiente, se presenta un diseño usando solamente operadores lógicos.

Operadores.
Operator type Operators Data types

Assignment <=, :=, => Any

Logical NOT, ANO, NANO, BIT, BIT_VECTOR,


OR, NOR, XOR, XNOR STD_LOGIC, STD_LOGIC_VECTOR,
STD_ULOGIC, STD_ULOGIC_VECTOR

Arithmetic +,-,*,/,** INTEGER, SIGNED, UNSIGNED


(mod, rem, abs)

Comparison =, /=, <, >, <=, >= Ali above

Shift sil, srl, sla, sra, rol, ror BIT_VECTOR

Concatenation &, (,,,) Same as for logical operators, plus


SIGNED and UNSIGNED
--------------------------------------------------------------------------~--------------------------------------------------------------------------
a
b
y
e
d

Figura 5.3 si so
Multiplexor del ejemplo 5.1.

Ejemplo 5.1: Multiplexor#1

La figura 5.3 muestra un multiplexor de 4 entradas y un bit por entrada. La salida debe ser igual a
la entrada seleccionada por los bits de selección, sl-sO. Su implementación, usando operadores
lógicos, puede hacerse como sigue

1 ---------------------------------------
2 LIBRARY ieee;
3 USE ieee.std_logic_l 164.all;
4 ---------------------------------------
5 ENTITY mux IS
6 PORT (a, b, e, d, sO, sl: IN STD_LOGIC;
7 y: OUT STD_LOGIC);
8 END mux;
9 ---------------------------------------
1 O ARCHITECTURE pure _logic OF mux IS
11 BEGIN
12 y<= (a AND NOT sl AND NOT sO) OR
13 (b AND NOT sl AND sO) OR
14 (e AND sl ANDNOT sO) OR
15 (d AND sl AND sO);
16 END pure _logic;
17 ---------------------------------------
Los resultados de la simulación, que confirman la funcionalidad del circuito, se muestran en la
figura 5.4.

~so 1

~s1 l
~;

l_~t
l 1
o
o
-:iifit- '~ 1
o
o
1
1
,~¡j

~ "J o
1

Figura 5.4
Resultados de la simulación del ejemplo 5.1.
5.3 WHEN (Simple y Selected)
Como se mencionó antes, WHEN es uno de los estatutos concurrentes fundamentales (junto con
los operadores y GENERATE). Aparece en dos formas: WHEN / ELSE (simple WHEN) y WITH /
SELECT J WHEN (selected WHEN). Su sintaxis es la siguiente.

WHEN I ELSE:

assignment WHEN condition ELSE


assignment WHEN condition ELSE
... ,

WITH I SELECT / WHEN:

WITH identifier SELECT


assignment WHEN value,
assignment WHEN value,
... ,

Siempre que se use WITH I SELECT / WHEN, se deben probar todas las permutaciones, por lo
que la palabra reservada OTHERS es a menudo útil. Otra palabra importante reservada es
UNAFFECTED, la cual debe usares cuando ninguna acción tiene l~gar.

Ejemplo:

------ With WHEN/ELSE -------------------------


outp <= "000" WHEN (inp='O' OR reset=' 1 ') ELSE
"00 l" WHEN ctl=' l' ELSE
"010";

---- With WITH/SELECT /WHEN --------------------


WITH control SELECT
output <= "000" WHEN reset,
"111" WHEN set,
UNAFFECTED WHEN OTHERS;
-----------------------------------------------
Otro aspecto importante relacionado con la sentencia WHEN es que el "WHEN value" mostrado
en la sintaxis anterior puede en efecto tomar hasta tres formas:

WHEN value -- Un solo valor


WHEN valuel to value2 -- Rango, para tipos de datos enumerados solamente
WHEN valuel 1 value2 ¡ ... - Valor 1 o valor 2 o ...

Ejemplo 5.2: Multiplexor #2


Este ejemplo muestra la implementación del mismo multiplexor del ejemplo 5.1, pero con una
representación ligeramente diferente de la entrada sel (figura 5.5). Sin embargo, en ella se usó
WHEN en vez de operadores lógicos. Se presentan dos soluciones: una usando WHEN/ELSE
(simple WHEN) y la otra con WITH/SELECT/WHEN (selected WHEN). Los resultados
experimentales son obviamente similares a los obtenidos en el ejemplo 5.1.

a
b
MUX y
e
d

sel (1 :O)

Figura 5.5
Multiplexor del ejemplo 5.2.

1 ------- Solution 1: with WHEN/ELSE --------


2 LIBRARY ieee;
3 USE ieee.std_logic_ 1164.all;
4 -------------------------------------------
5 ENTITY mux IS
6 PORT (a, b, e, d: IN STD _LOGIC;
7 sel: IN STD_LOGIC_VECTOR(l DOWNTO O);
8 y: OUT STD_LOGIC);
9 END mux;
10 -------------------------------------------
11 ARCHITECTURE muxl OF mux IS
12 BEGIN
13 y<= a WHEN sel="OO" ELSE
14 b WHEN sel="Ol" ELSE
15 e WHEN sel=" 1 O" ELSE
16 d;
17 END muxl;
18 -------------------------------------------
1 --- Solution 2: with WITH/SELECT/WHEN -----
2 LIBRAR Y ieee;
3 USE ieee.std_logic_l 164.all;
4 -------------------------------------------
5 ENTITY mux IS
6 PORT (a, b, e, d: IN STD _LOGIC;
7 sel: IN STD _ LOGIC _VECTOR (1 DOWNTO O);
·8 y: OUT STD_LOGIC);
9 ENDmux·
'
10 -------------------------------------------
11 ARCHITECTURE mux2 OF mux IS
12 BEGIN
13 WITH sel SELECT
14 y<= a WHEN "00", -- notice 11,11 instead of ";"
15 b WHEN "01 ",
16 e WHEN "10",
17 d WHEN OTHERS; -- cannot be "d WHEN "11" "
18 END mux2;
19 --------------------------------------------

En las soluciones anteriores, sel pudo haber sido declarada como un INTEGER, en cuyo caso el
código sería el siguiente:

1 ----------------------------------------------
2 LIBRARY ieee;
3 USE ieee.std_logic_l 164.all;
4 ----------------------------------------------
5 ENTITY mux IS
6 PORT (a, b, e, d: IN STD_LOGIC;
7 sel: IN INTEGER RANGE O TO 3;
8 y: OUT STD_LOGIC);
9 END mux;
1 O ---- Solution 1: with WHEN/ELSE ---------------
11 ARCHITECTURE muxl OF mux IS
12 BEGIN
13 y <= a WHEN sel=O ELSE
14 b VlHEN sel= 1 ELSE
15 e WHEN sel=2 ELSE
16 d;
17 END muxl;
18 -- Solution 2: with WlTH/SELECT/WHEN -----··--
19 ARCHITECTURE mux2 OF mux IS
20 BEGIN
21 WITH sel SELECT
22 y<=a WHENO,
23 b WHEN 1,
24 e WHEN2,
25 d WHEN 3; -- aquí, 3 u OTHERS son equivalents,
26 END mux2; -- ya que todas las opciones se prueban de cualquier manera
27 --~--------------------------------------------

Nota: Sólo una ARCHITECTURE puede ser sintetizada a la vez. Por lo tanto, siempre que
presentamos más de una solución dentro del mismo código global (como el anterior), es implícito
que todas las soluciones deben ser comentadas (con "- -"), excepto una, o una secuencia de
comandos de síntesis debe ser utilizada, con el objeto de sintetizar la solución restante. En
simulaciones, la sentencia CONFIGURATION ouede usarse oara seleccionar una arquitectura
específica.
ena

input (7:0) output (7:0)

Figura 5.6
Buffer de Tres estados del ejemplo 5.3.

Ejemplo 5.3: Buffer de Tres Estados

Este es otro ejemplo que ilustra el uso de WHEN. El buffer de tres estados de la figura 5.6 debe
proveer una salida = input cuando ena (enable) está en nivel bajo, o output = "ZZZZZZZZ"
(alta impedancia) en otro caso.

1 LIBRARY ieee;
2 USE ieee.std_logic_l 164.all;
3 ----------------------------------------------
4 ENTITY tri_state IS
5 PORT ( ena: IN STD _LOGIC;
6 input: IN STD _LOGIC _VECTOR (7 DOWNTO O);
7 output: OUT STD_LOGIC_ VECTOR (7 DOWNTO O));
8 END tri_ state;
9 ----------------------------------------------
10 ARCHITECTURE tri_state OF tri_state IS
11 BEGIN
12 output <=input WHEN (ena='O') ELSE
13 (OTHERS => 'Z');
14 END tri_ state;
15 ----------------------------------------------
Los resultados de la simulación del circuito sintetizado con el código anterior se muestran en la
figure 5.7. Como se esperaba, la salida permanece en el estado de alta impedancia cuando ena
está en nivel alto, siendo una copia de la entrada cuando ena está en nivel bajo.

100.0ns
1
~üO.Ons
1
30J.Ons
1
40J.One 1
toO.Ons
1
GLD.Ons
1
70J.Dns 1
8JO.Ons
1
900.( 1

!iP- ene
~input DO o -r-1--·-·r 1
-
2
.
- -y 3 -r -- ·-·
.4
=rv::
5
- --~(
=: ~r:--
J. ·'I ¡, ¡\

@ou1pu1 DZ z I 2 ~x 3 4 5 --~

Figura 5.7
Resultados de la simulación del ejemplo 5.3.

Ejemplo5.4: Codificador

El diagrama top-level de un codificador n-by-m se muestra en la 5.8. Suponemos que n .es una
potencia de 2, tal que m = log2n. Una y solo una de las entradas bit se espera que esté en nivel
alto a la vez, cuya dirección debe ser codificada en la salida. Se presentan dos soluciones, una
usando WHEN I ELSE, y la otra con WITH I SELECT / WHEN.

X(n-1) ___..
x(n-2) ___.,
nxm (rn-l :O)
ENCODER
X(I) ___.,
x(O)

· · 'í::·igura 5.8 <, ...


Codificador del ejemplo 5.4. ·~~
'<,
)
/
/

--~~-·Soliición l-:- con· wHEN/ELSE -------------


2 LIBRARY ieee;
3 USE ieee.std _logic _ 1164.all;
4 ---------------------------------------------
5 ENTITY encoder IS
6 PORT ( x: IN STD_LOGIC_ VECTOR (7 DOWNTO O);
7 y: OUT STD_LOGIC_ VECTOR (2 DOWNTO O));
8 END encoder;
9 ---------------------------------------------
10 ARCHITECTURE encoderl OF encoder IS
11 BEGIN
12 y<= "000" WHEN x="OOOOOOOJ 11 ELSE
13 "00 l" WHEN x=="QQQOOO 1 O" ELSE
14 "010" WHEN x=="OOOOOlOO" ELSE
15 "O 11" WHEN x="OOOO 1000" ELSE
16 100" WHEN x=="OOO 10000" ELSE
11

17 "1O1" WHEN x="OO 100000" ELSE


18 "11 O" WHEN x="O1000000" ELSE
19 "111" WHEN x=" 10000000" ELSE
20 "ZZZ";
21 END encoderl ·
'
22 ---------------------------------------------

1 ---- Solución 2: con WITH/SELECT/WHEN ------


2 LIBRARY ieee;
3 USE ieee.std_logic_1164.all;
4 ---------------------------------------------
5 ENTITY encoder IS
6 PORT (x: IN STD_LOGIC_VECTOR(7 DOWNTO O);
7 y: OUT STD _LOGIC _VECTOR (2 DOWNTO O));
8 END encoder;
9
1 O ARCHITECTURE encoder2 OF encoder IS
11 BEGIN
12 WITH x SELECT
13 y<= "000" WHEN "00000001 ",
14 "00 l" WHEN "0000001 O",
15 "010" WHEN "00000100",
16 "011" WHEN "00001000",
17 "100" WHEN "00010000",
18 "1 O l" WHEN "00100000",
19 ''110" WHEN "01000000",
20 "111" WHEN "10000000",
21 "ZZZ" WHEN OTHERS;
22 END encoder2;
23 ---------------------------------------------

Observe que el código anterior tiene una larga lista de prueba (líneas 12-20 en la solución 1,
líneas 13- 21 en la solución 2). La solución se hace aun más incómoda cuando el número de bits
de selección crece. En tal caso, la sentencia GENERATE (sección 5.4) o le sentencia LOOP
(sección 6.6) puede usarse.
Los resultados de la simulación (de cada solución) se muestran en la figura 5.9.
100.ons 2JO.Dns ~OJ.Ons 400.0ns
i)i}: DO o 2 ~ ~
l 8 ,( 16 A 32 [lCV. )1
123
2 V 3 l{ \
~·¡
.1 DZ l jl J
4 ~
5 ~
6 I 7

Figura 5.9
Resultados de la simulación del ejemplo 5.4.
,/ .. -- --- ---- --·--------~

', Ejemplo 5.5: ALU')

~-------------- --------
Un ALU (Arithmetic Logic Unit) se muestra en la figura 5.1 O. Como el nombre lo dice, es un
circuito capaz de ejecutar ambas clases de operaciones, aritméticas así como lógicas logical. Su
operación se describe en la table de verdad de la figura 5.1 O. La salida (aritmética o lógica) se
selecciona por el MSB of sel, mientras que la operación especifica se selecciona por los otros
tres bits de sel.

!!ir' a o 25)
~b DO
:U- cin o
ir sel DO º r~===:
2 Y..-- 4 =» ---
: :. :' '':-:-===;-;::::=::'."'
6-

~X
1====:-;::::::'.
~')' )ps1 X
D 2ffi l---_2s_o_____,KLS2 ~3 Á{,,___.i~:-~....., 6_·X s g

Figure 5.11
Resultados de la simulación del ejemplo 5.5. ·

a (7:0) Logic
b {7:0) Unlt

Arithrnertc
---
Unit sel (3)
sel Operation Function Unit
0000 y<=a Transfer a
OOOi y<= a+1 Incrementa
0010 y<= a-1 Decrementa
0011 y<=b Transfer b Arithmetic
0100 y<==b+l lncrement b
0101 y<= b-1 Decrernent b
01 IO y<=a+b Add a and b
o 1J1 y <=a+b+dn Add a and h with carrv
1000 y<=NOTa Complement a
1001 y<=NOTb Comp1ement b
IOIO y<= a A1\1D b ANO
1011 y <=aOR b OR Logic
llOO y <=aNAND b NANO
1101 y<=aNORb NOR
11 JO y<=aXORb XOR
1111 v <=a XNOR b XNOR

Figura 5.10
ALU del ejemplo 5.5.

La solución que se presenta, además de usar solo código concurrente, también ilustra el uso de
el mismo tipo de datos para desarrollar ambas operaciones, aritméticas y lógicas. Esto es posible
debido a la presencia del paquete std_logic_unsigned de la librería ieee (discutida en la sección
3.6). Se usan dos señales arith y logic, para mantener los resultados de las unidades aritmética
y lógica, respectivamente, siendo pasado el valor seleccionado por el multiplexor. Los resultados
de la simulación se muestran en la figura 5.11.

1 ----------------------------------------------
.2 LIBRARY ieee;
3 USE ieee.std_Iogic_l 164.all;
4 USE ieee.std_logic_unsigned.all;
5 ----------------------------------------------
6 ENTITY ALU IS
7 PORT (a, b: IN STD_LOGIC_VECTOR (7 DOWNTO O);
8 sel: IN STD_LOGIC_ VECTOR (3 DOWNTO O);
9 cin: IN STD_LOGIC;
10 y: OUT STD_LOGIC_ VECTOR (7 DOWNTO O));
11 END ALU;
12 ----------------------------------------------
13 ARCHITECTURE dataflow OF ALU IS
14 SIGNAL arith, logic: STD_LOGIC _VECTOR (7 DOWNTO O);
15 BEGIN
16 ----- Unidad Aritmética: ------
17 WITH sel(2 DOWNTO O) SELECT
18 arith <= a WHEN "000",
19 a+l WHEN "001",
20 a-1 WHEN "010",
21 b WHEN "011",
22 b+l WHEN "100",
23 b-1 WHEN "101 ",
24 a+b WHEN "110",
25 a+b+cin WHEN OTHERS;
26 ----- Unidad Lógica: -----------
27 WITH sel(2 DOWNTO O) SELECT
28 logic <= NOT a WHEN "000"
'
29 NOTb WHEN "001",
30 aAND b WHEN "010",
31 a OR b WHEN "011'\
32 a NAND b WHEN "100"
'
33 a NOR b WHEN "101"
'
34 a XOR b WHEN "110"
'
35 NOT (a XOR b) WHEN OTHERS;
36 -------- Mux: ---------------
37 WITH sel (3) SELECT
38 . y <= arith WHEN 'O',
39 logic WHEN OTHERS;
40 END dataflow;
41 ----------------------------------------------

5.4 GENERATE
GENERATE es otra sentencia concurrente (junto con los operadores y WHEN). Es equivalente al
estatuto secuencial LOOP (capítulo 6) en el sentido de que permite que una
sección de código sea repetida un número de veces, creando así varios casos de las mismas
asignaciones. Su forma general es FOR 1 GENERATE, con la sintaxis mostrada abajo. Observe
que GENERATE debe ser etiquetada.

Nota: Para un mux genérico, por favor refiérase al problema 5.1.

FOR / GENERATE:

label: FOR identificadr IN range GENERA TE


(asignaciones concunentes)
END GENERATE;
También está disponible una forma irregular, la cual usa IF/GENERATE (con un IF equivalente;
recuerde que originalmente IF es una sentencia secuencial). Aquí no se permite ELSE. En la
misma manera que IF/GENERATE puede se anidada dentro de FOR/GENERATE (sintaxis
abajo), lo opuesto puede hacerse también.

IF I GENERA TE anidada dentro de FOR I GENERATE:

label 1: POR identifier IN range GENERA TE

label2: IF condition GENERA TE


(asignaciones concurrentes)
END GENERA TE;

END GENERA TE;

Ejemplo:

SIGNAL x: BIT_ VECTOR (7 DOWNTO O);


SIGNAL y: BIT_ VECTOR (15 DOWNTO O);
SIGNAL z: BIT_ VECTOR (7 DOWNTO O);

G 1: POR i IN x'RANGE GENERA TE


z(i) <= x(i) AND y(i+8);
END GENERATE;

Una nota importante acerca de GENERATE (y lo mismo es cierto para LOOP, la cual se verá en
el capítulo 6 es que ambos límites del rango deben ser estáticos. Como ejemplo consideremos,
el siguiente código, donde choice es un parámetro de entrada (no-estático). Esta clase de código
generalmente no es sintetizable.

NotOK: FOR i IN O TO choice GENERA.TE


(sentencias concurrentes)
END GENERATE;

También debemos tener cuidado de las señales multiply-driven (no resueltas). Por ejemplo,

OK: FOR i IN O TO 7 GENERA TE


output(i)<='l' WHEN (a(i) AND b(i))='l' ELSE 'O';
END GENERATE;

Es correcto. Sin embargo, el compilador indicará que accum es multiply driven (y detiene la
compilación) en cualquiera de los dos casos siguientes
---------------------------1111!!11""!!1"!!"'!""_.. . . ~-,.- . --·· -· ·=---~--~--

NotOK: FOR i IN O TO 7 GENERATE


accum <="11111111" WHEN (a(i) AND b(i))='l' ELSE "00000000";
END GENERATE;:

NotOK: For i IN O to 7 GENERA TE


accum <= accum + 1 WHEN x(i)='l';
END GENERATE·
'

Ejemplo5.6: VectorShifter

Este ejemplo ilustra el uso de GENERATE. En el vector de salida debe ser una versión
desplazada del vector de entrada, con el doble de su ancho y una cantidad de desplazamientos
especificados por otra entrada. Por ejemplo, si el bus de entrada es de 4 bits, y el valor presente
es "1111 ", entonces la salida debe ser una de las líneas de la siguiente matriz (el vector original
está subrayado):

row(O): O O O O 1 1 1 1
row( 1 ) : O O O 1 1 1 1 O
row(2): O O 1 1 1 1 O O
row(3): O 1 1 1 1 O O O
row( 4): 1 1 1 1 O O O O

La primera fila corresponde a la misma entrada, sin desplazamiento y los bits más significativos
llenados con 'O's. Cada fila sucesiva es igual a la fila previa desplazada una posición a la
izquierda. La siguiente solución tiene la entrada inp, la salida outp, y la selección de
desplazamiento sel. Cada fila del array anterior (llamada matrix, línea 14) está definida como un
vector subtype (fine 12).
1 ------------------------------------------------
2 LIBRARY ieee;
3 USE ieee.std_logic_l 164.all;
4 ---------------------------------------------~--
5 ENTITY shifter IS
6 PORT ( inp: IN STD_LOGIC_VECTOR (3 DOWNTO O);
7 sel: IN INTEGER RANGE O TO 4;
8 outp: OUT STD_LOGIC_ VECTOR (7 DOWNTO O));
9 END shifter;
10 ------------------------------------------------
11 ARCHITECTURE shifter OF shifter IS
12 SUBTYPE vector IS STD_LOGIC_VECTOR (7 DOWNTO O);
13 TYPE matrix IS ARRA Y ( 4 DOWNTO O) OF vector;
14 SIGNAL row: matrix;
15 BEGIN
16 row(O) <= "0000" & inp;
17 Gl: POR i IN 1TO4 GENERATE
18 row(i) <= row(i-1)(6 DOWNTO O) & 'O';
19 END GENERATE;
20 outp <= row(sel);
21 END shifter:
'
22 ------------------------------------------------

Los resultados de la simulación se presentan en la figura 5.12. Como puede verse, inp =
"0011" (decimal 3) se aplicó al circuito. El resultado fue outp = "00000011 '' (decimal 3)
cuando sel = O (no desplazamiento), outp = "00000110" (decimal 6) when sel = 1 (un
desplazamiento a la izquierda), outp = "00001100" (decimal 12) cuandon sel = 2 (dos
desplazamientos a la izquierda), y así sucesivamente

100.0ns
1 .
JOJ.Ono;: :lJO.Ons 4CO.Ons
1
mo.on~ .
GCO.Ons 700 On•
1
800.0r.
j¡¡¡;inp 03 3
Dlisel DO o íl
I~ X
J l./
1\ 3 ~
~ il2_
~ou1p 03 3 'i
;, G il
11 ~ 2~ ;~

Figura 5.12
Resultados de la simulación del ejemplo 5.6

5.5 BLOCK

Hay dos clases de sentencias BLOCK: Simple y Guarded.

BLOCK Simple

La sentencia BLOCK, en su forma simple, representa solo una manera de particionar localmente
el código. Permite que un conjunto de de sentencias concurrentes sean agrupadas en un Bloque,
con el propósito de convertir el código en general más fácil de leer y más manejable (lo que
puede ser de ayuda cuando se trata de códigos largos). Su sintaxis se muestra enseguida.

label: BLOCK
[ declarative part]
BEGIN
( concurrent statements)
END BLOCK label;
Por lo tanto, el aspecto general de un código con block es el siguiente:

------------------------
ARCHITECTURE example ...
BE GIN

block!: BLOCK
BEGIN

END BLOCK block!

block2: BLOCK
BE GIN

END BLOCK block2 ·


'

END example;
------------------------

Ejemplo:

bl: BLOCK
SIGNAL a: STD_LOGIC;
BE GIN
a<= input_sig WHEN ena='l' ELSE 'Z';
END BLOCK b 1;

Un Bloque (simple o vigilado) puede ser anidado dentro de otro Bloque. La sintaxis
correspondiente es la siguiente.

label 1 : BLOCK
[parte declarativa del bloque superior]
BEGIN
[sentencias concurrentes del bloque superior]
label2: BLOCK
[parte declarativa del bloque anidado]
BEGIN
[sentencias concurrentes del bloque anidado]
END BLOCK label2;
[más sentencias concurrentes del bloque superior]
END BLOCK label 1;
Nota: Aunque las técnicas de partición de código son el propósito de la Parte 11 del libro, y la
sentencia BLOCK que acabamos de ver sirve exactamente para este propósito, un Bloque es
descrito en esta sección debido al hecho de que está contenido dentro del código principal (es
decir, no invoca ningún PACKAGE, COMPONENT, FUNCTION, o PROCEDURE extra-estas
cuatro unidades son el verdadero objeto de la Parte 11).

Bloque Vigilado (Guarded BLOCK)

Un Bloque vigilado es una clase especial de Bloque, el cual incluye una expresión adicional,
llamada expresión de guardia. Una sentencia de guardia en un Bloque vigilado se ejecuta
solamente cuando la expresión de guardia es verdadera.

Bloque vigilado:

label: BLOCK (Expresión de guardia)


[parte declarativa]
BEGIN
(sentencias de guardia y no de guardia)
END BLOCK label;

Como los siguientes ejemplos lo ilustran, aun cuando solo sentencias concurrentes pueden ser
escritas en un Bloque, con un Bloque vigilado se pueden construir circuitos secuenciales. Esto,
sin embargo, no es un enfoque de diseño habitual.

Ejemplo 5.7: Latch Implementado con un Bloque vigilado

El siguiente ejemplo implementa un latch transparente. En él, clk=' l' (línea 12) es la expresión
de guardia, mientras que q<=GUARDED d (línea 14) es una sentencia de vigilancia. Por tanto,
q<=d solo ocurrirá si clk=' l '.

1 -------------------------------
2 LIBRARY ieee;
3 USE ieee.std_logic_l 164.all;
4 -------------------------------
5 ENTITY latch IS
6 PORT (d, clk: IN STD_LOGIC;
7 q: OUT STD_LOGIC);
8 END latch;
9 -------------------------------
10 ARCHITECTURE 1atch OF latch IS
11 BEGIN
12 bl:BLOCK(clk='l')
13 BEGIN
14 q <= GUARDED d;
15 END BLOCK bl;
16 END latch ·
'
17 -------------------------------

Ejemplo 5.8: OFF Implementado con un Bloque vigilado

Aquí, se diseña un, flip flap activado con transición positiva tipo O, con reset síncrono. La
interpretación del código es similar a la del ejemplo anterior. En él, clk'EVENT AND clk=' 1'
(línea 12) es la expresión de guardia, mientras que q <= GUARDED 'O' WHEN rst='l' (línea 14)
es una sentencia de guardia. Por lo tanto, q<='O' ocurrirá cuando la expresión de guardia es
verdadera y rst es ' l'.

1 -------------------------------
2 LIBRARY ieee;
3 USE ieee.std _logic _1164.all;
4 -------------------------------
5 ENTITY dff IS
6 PORT ( d, clk, rst: IN STD_LOGIC;
7 q: OUT STD_LOGIC);
8 END dff;
9 -------------------------------
10 ARCHITECTURE dffOF dffIS
11 BEGIN
12- bl: BLOCK (clk'EVENT AND clk='l')
13 BEGIN
14 q <= GUARDED 'O' WHEN rst=' 1' ELSE d;
15 END BLOCK b l :
16 END dff;
17 ------------------------------

5.6 Problemas

Los problemas propuestos en esta sección serán resueltos usando sólo código concurrente
(operadores, WHEN, GENERATE). Después de escribir el código VHDL, sintetícelo y simúlelo
para estar seguro de que trabaja como se espera.
m
.x(O)

xt l )

x(J"-1)

sel

\Figura PS.1 [

·o· ~ 7 PRJORlTY
·r - 6 ENCODER
·o· -~ 5
·o· ~ 4
_.
'1'
_.,. 3 l T
'I'
'O'
__. 2 O .., 'O'

Figura P5.2

Problema 5.1: Multiplexor Genérico

Hemos visto el diseño de un multiplexor en los ejemplos 5.1 y 5.2. Esos circuitos eran para un
número predefinido de entradas (4 entradas) y un número predefinido de bits por entrada (1 bit).
Un verdadero mux genérico se representa en la figura P5.1. En ella, n representa el número de
bits de la entrada de selección (sel), mientras que m indica el número de bits por entrada. El
circuito tiene 2n entradas (observe que no hay relación entre m y n). Usando una sentencia
GENERIC para especificar n, y suponiendo que m = 8, diseñe este circuito.
Sugerencia: la entrada debe ser especificada como un arreglo de vectores. Por lo tanto, repase
la sección 3.5. ¿Su solución (ARQUITECTURA) requiere más de una línea de código real?

Problema 5.2: Codificador de Prioridad

La figura P5.2 muestra el diagrama top-level de un Codificador de Prioridad de 7 niveles. El


circuito debe codificar la dirección del bit de entrada de orden más alto que esté activo. "000"
debe indicar que no hay solicitud a la entrada (no hay bit activo). Escriba dos soluciones para
este circuito:

v=a/2

Figura P5.3
cin (carry in)

i
a (7:0)
+ sum (7:0)
b (7.:0) ..

cout (carry out)


Figura PS.4
(a) Usando solo operadores;
(b) Usando WHEN/ELSE (WHEN simple);

Problema 5.3: Multiplicador/Divisor Simple

Usando solo código concurrente, diseñe el Multiplicador/Divisor de la figura PS.3. El circuito tiene
dos entradas integer 8-bits (a, b) y dos salidas integer (x, y), donde x = a*b y y= a/2.
Nota: Para un divisor de punto fijo genérico, debe consultar el capítulo 9.

Problema 5.4: Sumador

Usando solo sentencias concurrentes, diseñe el sumador de 8-bit unsigned de la figura PS.4.

Problema 5.5: Signed/Unsigned Sumador/restador

En la figura P5.5, hemos añadido una entrada extra de 2-bit (sel) al circuito del problema 5.4, tal
que ahora el circuito puede operar como un sumador/restador signed o unsigned (vea la tabla de
verdad). Escriba un código concurrente VHDL para este circuito.

Nota: Después de haber resuelto este problema, usted puede comparar su solución con el
ejemplo correspondiente en el capítulo 9.

sel operation
cin
00 add unsigned
01 add signed
a (7:0) io sub unsigned
sum 11 sub signed
b (7:0) + (7:0)

sel (l:O)

e out

Figura P5.5
Tabla P5.6

Binary code Gray code

ºººº
0001 ºººº
0001
0010 0011
0011 0010
0100 0110
0101 0111
0110 0101
0111 0100
1000 1100
1001 1101
1010 1111
1011 1110
1100 1010
1101 1011
111 o 1001
1111 1000

Problema 5.6: Convertidor de Código Binario a Gray

El código binario es el más usado de todos los códigos digitales. En él, el LSB (bit menos
significativo) tiene el peso de 20, con el peso incrementado por dos por cada bit sucesivo, hasta
2n_ 1 para el bit de más peso (bit más significativo), donde n es el número de bits en la palabra
de código. El código Gray, por otra parte, se basa en la mínima distancia de Hamming entre
palabras de código vecinos, es decir, sólo un bit puede cambiar cuando pasamos de la palabra
de código j a la (j + 1 ). Ambos códigos, para n = 4, se enlistan en la tabla P5.6. Diseñe un
circuito capaz de convertir el código binario a código Gray (para n genérico ). Si es posible,
presente más de una solución.

Problema 5.7: Barrel Shifter Simple

La figure P5.7 muestra el diagrama de un barre! shifter muy simple. En este caso el circuito debe
desplazar el vector de entrada (de tamaño 8) O o 1 posiciones a la izquierda. Cuando es
realmente desplazado (shift = 1 ), el bit LSB debe ser lleno con 'O' (mostrado en la esquina
izquierda del fondo del diagrama). Si shift = O, entonces outp = inp; sino, si shift = 1, entonces
outp(O) = 'O' y outp(i) = inp(i - 1 ), para 1 s¡ s 7. Escriba el código concurrente para este
circuito.
Nota: Un barrel shifter completo (con shift =O a n_ 1, donde n es el número de bits) se verá en el
capítulo 9.

inp(7)
outp(7)

inp(6)
outpré)

inp(5)
outp(5)

inp(4)
outp(4)

inp(3)
outp(3)

inp(2)

outp(2)

inp(I)

OUtp{I)

inp(O)

shift

Figura P5.7

Problema 5.8: Comparador


Construya un circuito capaz de comparar dos vectores de 8-bit, a y b. Un pin de selección (sel)
debe determinar que la comparación sea con signo (sel = '1 ~) o sin signo (sel = 'O'). El circuito
debe tener tres salidas, xl, x2, y x3, correspondientes a a> b, a= b, anda< b, respectivamente
(figura P5.8).
Nota: Después de haber resuelto este problema, usted puede comparar su solución al ejemplo
correspondiente en el capítulo 9.

a (7:0)..,.. a>b _,.. xl


a=b __ .,. x2
b (7:0) acb ---~ x3

Figura P5.8
sel
6 CÓDIGO SECUENCIAL
Como se mencionó en el capítulo 5, el código VHDL es inherentemente concurrente. Los
PROCESSES, FUNCTIONS, y PROCEDURES son las únicas secciones de código que son
ejecutadas secuencialmente. Sin embargo, en su conjunto, cualquiera de estos bloques es aún
concurrente con cualquier otra sentencia colocada fuera de ella.

Un aspecto importante del código secuencial es que no está limitado a lógica secuencial. En
efecto, con el podemos construir circuitos secuenciales además de circuitos combinacionales El
código secuencial también se llama código funcional.

Las sentencias discutidas son todas secuenciales, es decir, se permiten solamente dentro de
PROCESSES, FUNCTIONS, o PROCEDURES. Ellas son: IF, WAIT, CASE, y LOOP.

Las VARIABLES están también restringidas para usarse en código secuencial solamente (es
decir, dentro de un PROCESS, una FUNCTION, o un PROCEDURE). Así que, contrario a una
SIGNAL, una VARIABLE nunca puede ser global, así que su valor no puede ser pasado hacia
afuera directamente.

Aquí nos concentraremos en los PROCESSES. Las FUNCTIONS y los PROCEDURES son muy
similares, pero se usan para sistemas de niveles, por tanto se ven en la Parte 11 de este libro.

6.1 PROCESOS

Un PROCESS es una sección secuencial de código VHDL. Se caracteriza por la presencia


de IF, WAIT, CASE, o LOOP, y por una lista de sensibilidad (excepto cuando se use WAIT). Un
PROCESS estar instalado en el código principal, y se ejecuta cada vez que una señal de la lista
de sensibilidad cambia (o la condición relacionada a WAIT se cumple). Su sintaxis se muestra
enseguida.

[label:] PROCESS (sensitivity list)


[VARJABLE name type [range] [:= initial_ value;]]
BEGIN
(sequential code)
END PROCESS [label];

Las VARIABLES son opcionales. Si se usan, deben ser declaradas en la parte declarativa de el
PROCESS (antes de la palabra BEGIN, como se indica en la sintaxis de arriba). El valor inicial no
es sintetizable siendo tomado en cuanta sólo en las simulaciones. El uso de una etiqueta también
es opcional. Su propósito es mejorar la lectura del código. La etiqueta puede ser cualquier
palabra, excepto palabras reservadas de VHDL (apéndice E).
Para construir un circuito síncrono, es necesario monitorear una señal (clock, por ejemplo). Una
manera común de detector un cambio en una señal es por medio del atributo EVENT (visto en
la sección 4.2). Por ejemplo, si clk es una señal que se va a monitorear, entonces clk'EVENT
regresa el valor TRUE cuando ocurre un cambio en clk (transición positiva o negativa). En
seguida se muestra un ejemplo que ilustra el uso de EVENT y de PROCESS.

Ejemplo 6.1: OFF con Reset Asíncrono #1

Un OFF (OFF, figura 6.1) es el bloque de construcción más básico de circuitos lógicos
secuenciales. En él, la salida debe copiar la entrada ya sea en la transición positiva o negativa de
la señal de reloj (flanco positivo o negativo).

d q
OFF

clk

rst

Figura 6.1
OFF con Reset Asíncrono del ejemplo 6.1

En el código que se presenta, hacemos uso de la sentencia IF (discutida en la sección 6.3) para
diseñar un OFF con reset asíncrono. Si rst = '1 ', entonces la salida debe ser q = 'O' (líneas 14-
15), sin importar el estado de clk, la salida debe copiar la entrada (es decir, q = d) en la transición
positiva de clk (líneas 16-17). El atributo EVENT se usa en la línea 16 para detectar a una
transición del reloj. El PROCESS (líneas 12-19) se ejecuta cada vez que cambia cualquiera de
las señales que aparecen en su lista de sensibilidad (clk y rst, línea 12). Los resultados de la
simulación, que confirman la funcionalidad del circuito sintetizado, se presentan en la figura 6.2.

?LO llns :un Dns ..iOJ!Jns


e i-- -, r--- -- -,
e-rst
l====:::::!..----===~L :=ll__=:::;----=_--_-=_-=_-===
_r=¡
F ~clk
o '-----------'' 1 1 1..____,r
F -BJ q
o '---~·' 1·~ ~~-

1 --------------------------------------
2 LIBRARY ieee;
3 USE ieee.std_logic_l 164.all;
4 --------------------------------------
5 ENTITY dff IS
6 PORT (d, clk, rst: IN STD_LOGIC;
7 q: OUT STD_LOGIC);
8 END dff·
'
9 --------------------------------------
1 O ARCHITECTURE behavior OF dff IS
11 BEGIN
12 PROCESS (clk, rst)
13 BEGIN
14 IF ( rst=' l ') TREN
15 q <='O';
16 ELSIF (clk'EVENT AND clk='l') TREN
17 q <= d;
18 END IF;
19 END PROCESS;
20 END behavior;
21 --------------------------------------

6.2 Señales y Variables

Las Señales y las Variables se estudiarán en detalle en el siguiente capítulo. Sin embargo, es
imposible discutir el código secuencial sin saber al menos sus características más básicas.

El VHDL tiene dos maneras de transferir valores no estáticos: por medio de una SIGNAL 0 por
medio de una VARIABLE. Una SIGNAL puede ser declarada en un PACKAGE, ENTITY o
ARCHITECTURE (en su parte declarativa), mientras que una VARIABLE sólo puede ser
declarada dentro de una pieza de código secuencial (en un PROCESS, por ejemplo).

Por lo tanto mientras que el valor de la primera puede ser global, la última es siempre local. El
valor de una VARIABLE nunca puede ser pasada al exterior de un proceso PROCESS
directamente; si es necesario debe ser asignada a una SIGNAL. Por otra parte la actualización
de una VARIABLE es inmediata, es decir, podemos pronto contar con su nuevo valor en las
líneas de texto el código. Este no es el caso con una SIGNAL (Cuando se usa en un PROCESS),
ya que su nuevo valor es generalmente garantizado que esté disponible sólo después de la
conclusión de la ejecución del PROCESS.

Finalmente, recuerde de la sección 4.1 que el operador de asignación para una SIGNAL es "<="
(p ej.: sig <= 5), mientras que para una VARIABLE es":=" (p ej.: var := 5).
6.3 IF

Como se mencionó antes, IF, WAIT, CASE, Y LOOP son las sentencias usadas en el código
secuencial. Por lo tanto, solo pueden ser usadas en el interior de un PROCESS, FUNCTION, o
PROCEDURE.

La tendencia natural para la gente es usar el IF más que cualquier otra sentencia. Aunque esto
podría, en principio, tener una consecuencia negativa (debido a que la sentencia IF/ELSE podría
inferir la construcción de un decodificador de prioridad innecesario), el sintetizador optimizará la
estructura y evitará el hardware extra. La sintaxis de IF se muestra enseguida

IF conditions THEN assignments;


ELSIF conditions TREN assignments;

ELSE assignments;
END IF;

Ejemplo:

IF (x<y) THEN temp:="l 1111111 ";


ELSIF (x=y AND w='O') THEN temp:="l 1110000";
ELSE temp:=(OTHERS =>'O');

Ejemplo 6.2: Contador de un Dígito #1

El siguiente código implementa un contador decimal progresivo de un dígito (O -79 -7 O). En la


6.3 se muestra un diagrama top-level del circuito. Contiene una entrada de un solo bit (clk) y una
salida de 4 bits (un digito). La sentencia IF se usa en este ejemplo. Se empleó una variable,
temp, para crear los cuatro flip-flops para almacenar la señal de salida de 4 bits. Los resultados
de la simulación, que confirman la operación correcta del circuito sintetizado, se muestra en la
figura 6.4.

e
o
u
clk N digit (J:O)
T
E
R

Figura 6.3
contador del ejemplo 6.2.
1 -----------~---------------------------------
2 LIBRARY ieee:
'
3 USE ieee.std_logic_l 164.all;
.4 ---------------------------------------------
5 ENTITY counter IS
6 PORT (clk: IN STD_LOGIC;
7 digit : OUT INTEGER RANGE O TO 9);
8 END counter;
9 ---------------------------------------------
!O ARCHITECTURE counter OF counter IS
11 BEGIN
12 count: PROCESS(clk)
13 VARIABLE temp : INTEGER RANGE O TO 1 O·
14 BEGIN
'
15 IF ( clk'EVENT AND clk=' l ') THEN
16 temp := temp + l;
17 IF (temp=lO) THEN temp :=O;
18 END IF;
19 END IF;
20 digit <= temp;
21 END PROCESS count;
22 END counter;
23 ---------------------------------------------

10J.Ons 2CO.Ons 200.0ns 40J.Ons

Ü"" clk o
~digit HO

Figura 6.4
Resultados de la simulación del ejemplo 6.2.

Comentario: Observe que el código anterior no tiene entrada de reset ni ningún esquema de
inicialización interna para temp (y el digito, consecuentemente). Por lo tanto, el valor inicial de
temp en el circuito físico puede ser cualquier valor de 4 bits. Si tal valor está abajo de 1 O (vea la
línea 17), el circuito contará correctamente a partir de aquí. Por otra parte, si el valor está arriba
de 1 o, se usará un número de ciclos de reloj hasta que temp alcance la cuenta completa (es
decir, 15, o "1111 "), siendo así automáticamente limpiada, a partir de donde empieza la
operación correcta. La posibilidad de usar unos pocos ciclos de reloj al inicio no es generalmente
un problema. Pero si aun así, si uno quiere evitar que, temp = 1 o, in line 17, puede ser cambiada
a temp >= 1 O, pero esto aumentará el hardware. Sin embargo, si el inicio exactamente a partir de
O es siempre necesario, entonces se debe incluir una entrada de reset (como en el ejemplo 6.7).

Observe en el código anterior que . incrementamos temp y la comparamos con 1 O, con el


propósito de resetear temp una vez que alcanza 1 O. Esta es una aproximación típica usada en
los contadores. Observe que 1 O es una constante, así que el compilador infiere un comparador
con una constante, el cual es un circuito relativamente simple para construir. Sin embargo, si en
lugar de una constante usamos un parámetro programable, se necesitaría implementar un
comparador completo, el cual requiere substancialmente más lógica que un comparador con una
constante. En este caso, una mejor solución sería cargar temp con tal parámetro, y luego
decrementarlo, recargando temp cuando se alcanza el valor O. En este caso, nuestro comparador
compararía temp con O (una constante), evitando así la generación de un comparador completo.

Ejemplo 6.3: Registro de Desplazamiento

La figura 6.5 muestra un registro de desplazamiento de 4 bits. El bit de salida (q) debe estar
cuatro transiciones positivas de reloj atrás del bit de entrada (d). También contiene un reset
asíncrono, el cual debe forzar las salidas de todos los flip-flops a 'O' cuando es activada. En este
ejemplo, se usa otra vez la sentencia IF.

d q
DFF DFF DFF' DPF

clk _ _.___--l-- _ _._._-+---+---1----4


5t ~-

Figura 6.5
Registro de Desplazamiento del ejemplo 6.3.

1 --------------------------------------------------
2 LIBRARY ieee;
3 USE ieee.std_logic_l 164.all;
4 --------------------------------------------------
5 ENTITY shiftreg IS
6 GENERIC (n: INTEGER := 4); -- # of stages
7 PORT (d, clk, rst: IN STD_LOGIC;
g q: OUT STD_LOGIC);
9 END shiftreg;
10 --------------------------------------------------
11 ARCHITECTURE behavior OF shiftreg IS
12 SIGNAL internal: STD_LOGIC_ VECTOR (n-I DOWNTO O);
13 BEGIN
14 PROCESS (clk, rst)
15 BE GIN
16 IF (rst=' 1 ') THEN
17 interna! <= (OTHERS =>'O');
18 ELSIF ( clk'EVENT AND clk=' l ') THEN
19 interna!<= d & internal(internal'LEFT DOWNTO 1);
20 END IF;
21 END PROCESS;
22 q <= intemal(O);
23 END behavior:
'
24 --------------------------------------------------

Los resultados de la simulación se muestran en la fig. 6.6. Como puede verse, q está cuatro
transiciones positivas atrás de d.

1CO.Ot's 200.011~ 300.0n~ 400.0n~ eJO.Ons GDD.OM 700.0ns BJJ.DM 501[


!'ia-clk o
!D-rst o
!IF-d
l1V
....
in1e1rn1l
q
o
DO
o
o ,~8 ~( 1
12
¡----;.
1\ 6 '(
1
3 l~
J, X o

.Figura 6.6
Resultados de la simulación del ejemplo 6.3.

6.4 WAIT

La operación WAIT es algunas veces similar a la del IF. Sin embargo, se dispone de más de una
forma de WAIT. Además, al contrario de cuando se usan 1 F, CASE, or LOOP, el PROCESS no
puede tener una lista de sensibilidad cuando se emplea WAIT. Su sintaxis se muestra abajo (hay
tres formas de WAIT).

1 WAIT UNTIL signal_condition;

1 W AIT ON signall [, signal2, ... ] ;

WAIT FOR time;


La sentencia WAIT UNTIL acepta solo una señal, por ello es más apropiada para código
síncrono que asíncrono. Ya que el PROCESS no tiene lista de sensibilidad en este caso, WAIT
UNTIL debe ser la primera sentencia en el PROCESS. El PROCESS se ejecutará cada vez que
se cumple la condición.

Ejemplo: Registro de 8 bits con Reset Síncrono.

PROCESS -- no sensitivity list


BEGIN
W AIT UNTIL ( clk'EVENT AND clk=' l ');
IF (rst='l') THEN
output <= "00000000";
ELSIF ( clk'EVENT AND clk=' l ')THEN
output <= input;
END IF;
END PROCESS;
WAIT

WAIT ON, por otra parte, acepta señales múltiples. El proceso se pone en espera hasta que
cualquiera de las señales enlistadas cambia. En el siguiente ejemplo, el PROCESS continuará su
ejecución siempre que ocurre un cambio en rst o clk.

Ejemplo: Registro de 8 bits con Reset·Asíncrono.

PROCESS
BE GIN
W AIT ON clk, rst;
IF (rst=' l ') THEN
output <= "00000000";
ELSIF ( clk'EVENT AND clk=' l ') THEN
output <= input;
END IF;
END PROCESS;

Finalmente, WAIT FOR es usada solo para simulación (generación de ondas para bancos de
pruebas). Ejemplo: WAIT FOR 5ns;

Ejemplo 6.4 OFF con Reset Asíncrono #2

El siguiente código implementa el mismo OFF del ejemplo 6.1 (figuras 6.1 y 6.2). Sin embargo,
aquí WAIT ON se usa en lugar de solo IF.
1 --------------------------------------
2 LIBRAR Y ieee·
'
3 USE ieee.std _ logic _ 1164 .all;
4 --------------------------------------
5 ENTITY dff IS
6 PORT (d, clk, rst: IN STD _LOGIC;
7 q: OUT STD_LOGIC);
8 END dff;
9 --------------------------------------
10 ARCHITECTURE dffOF dffIS
11 BEGIN
12 PROCESS
13 BEGIN
14 W AIT ON rst, clk;
15 IF (rst=' l ') THEN
16 q <='O';
17 ELSIF (clk'EVENT AND clk=' l ') THEN
18 q <= d;
19 END IF;
20 END PROCESS;
21 END dff;
22 --------------------------------------

Ejemplo 6.5: Contador de un Dígito #2

El siguiente código implementa el mismo contador decimal progresivo de un dígito del ejemplo
6.2 (figuras 6.3 y 6.4). Sin embargo, WAIT UNTIL fue usada en vez de solo IF.

1 ---------------------------------------------
2 LIBRARY ieee;
3 USE ieee.std_logic_l 164.all;
4 ---------------------------------------------
5 ENTITY counter IS
6 PORT (clk: IN STD_LOGIC;
7 digit : OUT INTEGER RANGE O TO 9);
8 END counter;
9 ---------------------------------------------
10 ARCHITECTURE counter OF counter IS
11 BEGIN
12 PROCESS -- no sensitivity list
13 VARIABLE temp: INTEGER RANGE O TO 10;
14 BE GIN
15 WAIT UNTIL (clk'EVENT AND clk='l');
16 temp := temp + 1;
17 IF (temp=lO) THEN temp :=O;
18 END iF;
19 digit <= temp;
20 END PROCESS·
'
21 END counter:
'
22 ---------------------------------------------

6.5 CASE

CASE es otr.a se~tencia usada exclusivamente para código secuencial (junto con IF, LOOP, y
WAIT). Su sintaxis se muestra enseguida.

CASE identifier IS
WHEN value => assignments;
WHEN value => assignments;

ENDCASE;

Ejemplo:

CASE control IS
WHEN "00" => x<=a; y<=b;
WHEN "O l " => x<=b; y<=c;
WHEN OTHERS => x<="OOOO"; y <="ZZZZ";
END CASE;

La sentencia CASE (secuencial) es muy similar a WHEN (combinacional). Aquí también todas las
permutaciones deben ser probadas, así que la palabra reservada OTHERS a menudo es útil.
Otra palabra reservada importante es NULL (la contraparte de UNAFFECTED), la cual debe ser
usada cuando ninguna acción tiene lugar. Por ejemplo, WHEN OTHERS => NULL;. Sin
embargo, CASE permite múltiples asignaciones para cada condición de prueba (como se mostró
en el ejemplo anterior), mientras que WHEN permite sólo una.
Como en el caso de WHEN (sección 5.3), aquí también "WHEN value" puede tomar tres formas:

WHEN value -- un solo valor


WHEN valuel to value2 -- rango, para tipos de datos enumerados
-- solamente
WHEN valuel 1 value2 I···. -"'. valuel o value2 o ...

Ejemplo 6.6: OFF con Reset Asíncrono #3

El siguiente código implementa el mismo OFF del ejemplo 6.1 (figuras 6.1 y 6.2). Sin embargo,
aquí CASE se usó en vez de solo IF. Observe que unas pocas declaraciones innecesarias se
incluyeron intencionalmente en código para ilustrar su uso.

1 ----------------------------------------------
2 LIBRARY ieee· -- Declaración inecesaria,
'
3 -- poque
4 USE ieee.std_logic_l 164.all; -- se usó BIT en vez de
5 -- STD LOGIC
6 ----------------------------------------------
? ENTITY dffIS
8 PORT (d, clk, rst: IN BIT;
9 q: OUT BIT);
10 END dff;
11 ----------------------------------------------
12 ARCHITECTURE dff3 OF dffIS
13 BEGIN
14 PROCESS (clk, rst)
15 BEGIN
16 CASE rst IS
17 WHEN 'l' => q<='O';
18 WHEN 'O' =>
19 IF ( clk'EVENT AND clk=' l ') THEN
20 q <= d;
21 END IF;
22 WHEN OTHERS => NULL; -- Innecesario, rst es d tipo
23 -- BIT
24 END CASE;
25 END PROCESS;
26 END dff3;
27 ----------------------------------------------

Ejemplo 6.7: Contador de dos Dígitos con Salida SSD

El siguiente código implementa un contador decimal progresivo de 2 bits (O -7 99 -7 O), con reset
externo asíncrono mas una conversión de código binario decimal (BCD) a display de siete
segmentos (SSD). En la figura 6.7 se muestran los diagramas del circuito y el SSO. La sentencia
CASE (líneas 31-56) se empleó para determinar la salida para determinar la señal de salida que
alimentará los SSDs. Observe que hemos escogido la siguiente conexión entre el circuito y el
SSD: xabcdefg (es decir, el MSB alimenta el punto decimal, mientras que el LSB alimenta el
segmento g).

Como puede verse este circuito es una extensión directa de la presentada en el ejemplo 6.2, con
las diferencias de que ahora dos dígitos son necesarios en vez de uno, y que las salidas deben
estar conectadas a displays SSO. La operación del circuito puede ser verificada en los
resultados de la simulación de la figura 6.8.

SSD

e
o
u
clk N
T
E
digit2
R
digitl

re set Input: "xabcdefg"

Figura 6.7
Contador de 2 Dígitos del ejemplo 6.7.

1 --------------------------------------------------
2 LIBRAR Y ieee;
3 USE ieee.std_logic_ll64.all;
4 --------------------------------------------------
5 ENTITY counter IS
6 PORT (clk, reset: IN STD_LOGIC;
7 digit l , digit2: OUT STD_LOGIC_VECTOR(6 DOWNTO O));
8 END counter;
9 --------------------------------------------------
}O ARCHITECTURE counter OF counter IS
11 BEGIN
12 PROCESS(clk, reset)
13 VARIABLE temp 1: INTEGER RANGE O TO 1 O;
14 VARIABLE temp2: INTEGER RANGE O TO 10;
15 BEGIN
16 ---- counter: ----------------------
17 IF (reset=' 1 ') THEN
18 templ :=O;
·1
1

19 temp2 :=O;
20 ELSIF ( clk'EVENT AND clk=' l ') THEN
21 templ := templ + l; 'i

22
23
IF (temp l=l O) THEN
templ :=O;
l
1

24 temp2 := temp2 + 1;
25 IF (temp2=10) THEN
26 temp2 :=O;
27 END IF;
28 END IF;
29 END IF;
30 ----BCD to SSD conversion: --------
31 CASE temp 1 IS
32 WHEN O=> digitl <= "1111110"; --7E
33 WHEN 1 => digitl <= "0110000"; --30
34 WHEN 2 => digitl <= "1101101 "; --6D
35 WHEN 3 => digitl <= "1111001 "; --79
36 WHEN 4 => digitl <= "0110011 "; --33
37 WHEN 5 => digitl <= "1011011 "; --5B
38 WHEN 6 => digitl <= "1011111 "; --5F
39 WHEN 7 => digitl <= "1110000"; --70
40 WHEN 8 => digitl <= "1111111 "; --7F
41 WHEN 9 => digitl <= "1111011 "; --7B
42 WHEN OTHERS => NULL;
43 END CASE;
44 CASE temp2 IS
45 WHEN O=> digit2 <= "1111110"; --7E
46 WHEN 1 => digit2 <= "0110000"; --30
47 WHEN 2 => digit2 <= "11O11O l "; --6D
48 WHEN 3 => digit2 <= "1111001 "; --79
49 WHEN 4 => digit2 <= "0110011 "; --33
50 WHEN 5 => digit2 <= "1011011 "; --5B
51 WHEN 6 => digit2 <= "1011111 ' ; --5F
52 WHEN 7 => digit2 <= "1110000"; --70
53 WHEN 8 => digit2 <= "1111111 "; --7F
54 WHEN 9 => digit2 <= "1111011 "; --7B
55 WHEN OTHERS => NULL;
56 END CASE;
57 END PROCESS;
5 8 END counter;
59 --------------------------------------------------
----- .,...._ .. _._____ .. w-

- .• -~--
125.0ns 2:0.Dns 375.0n3 :00.0ns 625.0ns
~ rnsgt o
..... dk
aJlY lBff:~l HS
~ temp2 HO
.u> digit1 H 58
~digit2 H 7E

Figura 6.8
Resultados de la simulación del ejemplo 6. 7.

Comentario: Observe arriba que la misma rutina se repitió dos veces (usando la sentencia
CASE). Aprenderemos, en la Part 11, cómo escribir y compilar piezas de código usadas
frecuentemente en librerías definidas por el usuario, de tal manera que se eviten dichas
repeticiones .

6.6 LOOP

· Como el nombre lo dice, LOOP es útil cuando una pieza de código debe ser realizado varias
veces. Como IF, WAIT, y CASE, LOOP se usa exclusivamente para código secuencial, así que
también solo puede ser usada dentro de un PROCESS, FUNCTION, o PROCEDURE. Hay varias
maneras de usar un LOOP, como se muestra en las siguientes sintaxis.

FOR /LOOP: El loop se repite un número fijo de veces.

[label:] FOR identifier IN range LOOP


(sentencias secuenciales)
END LOOP [label];

J
WHILE ¡LOOP: El loop se repite hasta que una condición ya no se sostiene

[label:] 'N HfLE con di ti o;LO_O_P---------·-·----


(sentencias secuenciales)
END LOOP [Jabel]; _
EXIT: usada para terminar el loop.

[label:] EXIT [Iabel] [WHEN condition];


---------
. ...

NEXT: Usada para brincar pasos de loops.

[label:] NEXT [loop_label] [WHEN condition];

Ejemplo de FOR 1 LOOP:

FOR i IN O TO 5 LOOP
x(i) <= enable ANO w(i+2);
y(O, i) <= w(i);
END LOOP·
'

En el código anterior, el loop se repetirá incondicionalmente hasta que i alcance 5 (es decir, seis
veces).

Una observación importante en relación a FOR / LOOP (similar a la hecha para GENERATE, en
el capítulo 5) es que ambos límites del rango deben ser estáticos. Así que una declaración del
tipo "FOR i IN O TO choice LOOP", donde choice es un parámetro de entrada (no estático), es
generalmente no sintetizable. . .

Ejemplo de WHILE I LOOP. En este ejemplo, LOOP se repetirá mientras i < 10.

WHILE (i < 1 O) LOOP


WAIT UNTIL clk'EVENT AND clk='l';
(otras sentencias)
ENDLOOP;

Ejemplo con EXITE: En el siguiente código, EXIT no implica un escape de la iteración presente
de el loop, sino más bien una salida definida (es decir, aun si i está todavía en el rango del dato,
la sentencia LOOP será considerada como concluida). En este caso, el loop terminará tan pronto
como un valor diferente de 'O' se encuentra en el vector de datos.

FOR i IN data'RANGE LOOP


CASE data (i) IS
WHEN 'O' => count:=count+ 1;
WHEN OTHERS => EXIT;
END CASE;
ENDLOOP;
Ejemplo con NEXT: En el siguiente ejemplo, NEXT causa que LOOP se brinque una iteración
cuando i = skip.

FOR i IN O TO 15 LOOP
NEXT WHEN i=skip; -- salta a lasiguiente iteración
( ... )
-- .. •""C.--~--, ----- ·-- --·

ENDLOOP·
'
En seguida se presentan varios ejemplos de diseño completos, ilustrando varias aplicaciones de
LOOP.

Ejemplo 6.8: Carry Ripple Adder

La figura 6.muestra un sumador carry ripple de 8 bits unsigned. El diagrama top-level muestra las
entradas y salidas del circuito: a y b son los vectores de entrada que se van a sumar, cin es el bit
del cargo de entrada, s es vector suma, y cout es el bit del cargo de salida. El diagrama one-
level-below-top muestra como los bits del cargo se propagan (ripple).

One level below top:


Top level:
ao bn ª1 b1 a·r b1
a • s
b .. + Co __., + + ------ ,
+ Cg
C¡ C2 C7
(cin (cout)
e out

So S¡ S7
Figura 6.9
8-bit Sumador carry ripple del ejemplo 6.8

Cada sección del diagrama anterior es un sumador completo (sección 1.4). Así que sus salidas
pueden ser calculadas por medio de:

Sj = ajXOR b, XOR Cj
Cj+ 1 = (aj AND bj) OR (aj AND cj) OR (bj AND cj)

Se presentan dos soluciones, siendo una genérica (es decir, para cualquier número de bits,
basado en lo que vimos en el capítulo 4) y la otra específica para un número de 8 bits. Por otra
arte ilustramos el uso de vectores y FOR/LOOP en la primera solución, y de enteros y de IF en
la segunda. Los resultados de la simulación de cualquier solución se presentan en la figura 6.10.

Nota: Veremos más acerca de sumadores en el capítulo 9.

1 ----- Solution 1: Generic, with VECTORS --------


2 LIBRAR Y ieee;
3 USE ieee.std_logic_l 164.all;
4 ------------------------------------------------
5 ENTITY adder IS
6 GENERIC (length : INTEGER := 8);
7 PORT (a, b: IN STD_LOGIC_ VECTOR (length-1 DOWNTO O);
8 cin: IN STD_LOGIC;
9 s: OUT STD_LOGIC_ VECTOR (length-1 DOWNTO O);
10 cout: OUT STD_LOGIC);
11 END adder:
'
12 ------------------------------------------------
13 ARCHITECTURE adder OF adder IS
14 BEGIN
15 PROCESS (a, b, cin)
16 VARIABLE carry: STD_LOGIC_VECTOR (length DOWNTO O);
17 BEGIN
18 carry(O) := cin;
19 FOR i IN O TO length-I LOOP
20 s(i) <= a(i) XOR b(i) XOR carry(i);
21 carry(i+l) := (a(i) AND b(i)) OR (a(i) AND
22 carry(i)) OR (b(i) AND carry(i));
23 END LOOP;
24 cout <= carry(length);
25 END PROCESS;
26 END adder;
27 ------------------------------------------------

1 ---- Solution 2: non-géneric, with INTEGERS ----


2 LIBRARY ieee;
3 USE ieee.std _logic_ 1164.all;
4 ------------------------------------------------
5 ENTITY adder IS
6 PORT (a, b: IN INTEGER RANGE O TO 255;
7 cO: IN STD_LOGIC;
8 s: OUT INTEGER RANGE O TO 255;
9 c8: OUT STD _LOGIC);
I O END adder;
11 ------------------------------------------------
12 ARCHITECTURE adder OF adder IS
13 BEGIN
14 PROCESS (a, b, cO)
is VARIABLE temp: INTEGER RANGE O TO 511;
16 BEGIN
17 IF (cO='l ') THEN temp:=l;
l8 ELSE temp:=O;
19 END IF;
20 temp := a + b + temp;
21 IF (temp > 255) THEN
22 c8 <= 'l';
23 temp := temp---256;
24 ELSE c8 <= 'O';
25 END IF;
26 s <= temp;
27 END PROCESS;
28 END adder;
29 ------------------------------------------------

100.0n$ 200.Dns 3Cü.Ons -4CO.ün5


tD-cD o 1
~a HOE
---.-~9- __t - ~~ __ L ___ª~---L--~~--·K . _.~ _ J ___ ~__ X . -~~ _J __()_t:_J ____ ~~-J
~b HOB FF }( FD ~( FC XLUl( 02 X 04 K CG X 03 X OA ~
:Vs H 12 00 X G3 X OA )~ 16 yy¿__
-acB o

Figura 6.10
Resultados de la simulación del ejemplo 6.8.

Ejemplo 6.9: Simple Barrel Shifter

La figura 6.11 muestra el diagrama de un barrel shifter muy simple. En este caso, el circuito debe
desplazar el vector de entrada (de tamaño 8) O o 1 posición a la izquierda. Cuando realmente se
displace (shift = 1 ), el bit LSB debe ser llenado con 'O' (mostrado en la esquina izquierda del
fondo del diagrama). Sí shift= O, entonces outp = inp; Si shift ;;;: 1, Entonces outp(O) = 'O' and
outp(i) = inp(i - 1 ), para 1 <i<7. A continuación se presenta un código VHDL completo, el cual
ilustra el uso de FOR/LOOP. Los resultados de la simulación aparecen en la figure 6.12.

Nota: Un barrel shifter completo (with shift =O to n-1, donde n es el tamaño del vector de entrada)
se verá en el capítulo 9.
outp(7)

inp(6)
outp(6)

Ínp(5)

outp(5)

inp(4)
outp(4)

inp(3)

outp(3)

inp(2)
outp(2)

inp(J)
outp(l)

Ínp(O)

outp(O)

Figura 6. shift
Barrel shifter simple del ejemplo 6.9.

1 ---------------------------------------------
2 LIBRAR Y ieee;
3 USE ieee.std_logic_l 164.all;
4 ---------------------------------------------
5 ENTITY barrel IS
6 GENERIC (n: INTEGER := 8);
7 PORT ( inp: IN STD _ LOGIC _VECTOR (n-1 DOWNTO O);
8 shift: IN INTEGERRANGE O TO l;
9 outp: OUT STD_LOGIC_ VECTOR (n-1 DOWNTO O));
1 O END barrel;
11 ---------------------------------------------
12 ARCHITECTURE RTL OF barrel IS
13 BEGIN
14 PROCESS (inp, shift)
15 BEGIN
16 IF (shift=O) THEN
17 . outp <= inp;
18 ELSE
19 outp(O) <= 'O';
20 POR i IN l TO inp'HIGH LOOP
21 outp(i) <= inp(i-1);
22 ENDLOOP;
23 END IF;
24 END PROCESS·
'
25 ENDRTL·
'
26 ---------------------------------------------

5U.On!l: IDO Dns


iiP inp Do t--_a__ Yi,,_:.._•a__,X .io_,·.J~.__ ffi__ K EO }: .1(0 ) . 120 . ) .140 '~
9-shiR O
1
.. üutJl DO

Figura 6.12
Resultados de la simulación del ejemplo 6.9.

Ejemplo 6.10: Leading Zeros

El siguiente diseño cuenta el número de leading zeros en un vector binario empezando del
extremo izquierdo. La solución ilustra el uso de LOOP I EXIT. Recuerde que EXIT no implica un
escape de la iteración actual de el loop, sino más bien una salida definitiva de él (es decir, aun si
i está dentro del rango especificado, la sentencia LOOP será considerada como concluida). En
este ejemplo, el loop terminará tan pronto como un '1' se encuentre en el vector de dato. Por lo
tanto, es apropiado para contar el número de ceros que preceden el primer uno.

l --------------------------------------------
2 LIBRAR Y ieee;
3 USE ieee.std_logic_l 164.all;
4 ---------------~----------------------------
5 ENTITY LeadingZeros IS
6 PORT (data: IN STD__ LOGIC_ VECTOR (7 DO\VNTO O);
7 zeros: OUT INTEGER RANGE O TO 8);
g END LeadingZeros;
9 --------------------------------------------
to ARCHITECTURE behavior OF LeadingZeros IS
11 BEGIN
12 PROCESS (data)
13 VARIABLE count: INTEGER RANGE O TO 8·
'
14 BEGIN
15 count := O;
16 FOR i IN data'RANGE LOOP
17 CASE data(i) IS
18 WHEN 'O' => count := count + 1;
19 WHEN OTHERS => EXIT;
20 END CASE;
21 END LOOP;
22 zeros <= count;
23 END PROCESS;
24 END behavior;
25 --------------------------------------------

Los resultados de la simulación, verificando la funcionalidad del circuito, se muestran, se


muestran en la figura 6.13. Con data = "00000000" (decimal O), se detectan ocho ceros; cuando
=
data "00000001" (decimal 1 ), se encuentran siete ceros; etc.

100.0ns 200.0ns 3CO.Ons 40J.Ons SCO.Ons SCO.Ons


ri§:data DO
~zeros DB

Figura 6.13
Resultados de la simulación del ejempl6.1 O.

6. 7 CASE versus IF

Aunque en principio la presencia de ELSE en la sentencia IF/ELSE podría inferior la


implementación de un decodificador de prioridad (lo cual nunca ocurriría con CASE), esto
generalmente no sucederá. Por ejemplo, Cuando IF (una sentencia secuencial) se usa para
implementar un circuito totalmente combinacional, podría inferirse un multiplexor. Por lo tanto,
después de la optimización, la tendencia general para un circuito sintetizado a partir de un código
VHDL basado en un IF es no diferir del basado en CASE.
WHEN CASE
----------------------------------------------------------------------------------------------------------------------------------
Statement type Concurrent Sequential
----------------------------------------------------------------------------------------------------------------------------------
Usage Only outside PROCESSES, Only inside
PROCESSES l
FUNCTIONS, or FUNCTIONS, or
PROCEDURES PROCEDURES
----------------------------------------------------------------------------------------------------------------------------------
All permutations must be tested Yes for WITH/SELECT/WHEN Yes
----------------------------------------------------------------------------------------------------------------------------------
Max. # of assignments per test 1 Any
----------------------------------------------------------------------------------------------------------------------------------
No-action keyword UNAFFECTED NULL

Ejemplo: El siguiente código implementa el mismo circuito multiplexor físico.

---- With IF: --------------


IF (sel="OO") TREN x<=a;
ELSIF (sel="Ol ")TREN x<=b;
ELSIF (sel="lO") TREN x<=c;

ELSEx<=d;

---- With CASE: ------------


CASE sel IS
WHEN "00" => x<=a;
WHEN "O 1" => x<=b;
"WHEN "10" => x<=c;
WHEN OTHERS => x<=d;
END CASE;
----------------------------

6.8 CASE versus WHEN

CASE y WHEN son muy similares. Sin embargo, mientras que uno es concurrente (WHEN), el
otro es secuencial (CASE). Sus principales similitudes y diferencias se resumen en la tabla 6.1.

Ejemplo: Desde un punto de vista funcional, los siguientes códigos son equivalentes.

---- \\Tith \\THEN: ----------------


\\TITH sel SELECT
x <= aWHEN "000";
bWHEN "001",
e WHEN "010",
UNAFFECTED WHEN OTHERS;
---- With CASE: ----------------
CASE sel IS
WHEN "000" => x<=a·
'
WHEN "001" => x<=b·
'
WHEN "010" => x<=c·
'
WHEN OTHERS => NULL;
ENDCASE;
--------------------------------

6.9 Bad Clocking

El compilador generalmente no es capaz de sintetizar código que contiene asignaciones a la


misma señal en ambas transiciones de la señal (clock) de referencia (es decir, en la transición
positiva Y en la transición negativa). Esto es particularmente cierto cuando la tecnología contiene
solo flip-flops activados con una sola transición (CPLOs, por ejemplo-apéndice A). En este caso,
el compilador debe mostrar un mensaje del tipo "signal does not hold value after clock edge" o
similar.

Como ejemplo, consideremos el caso de un contador que debe ser incrementado en cada
transición del reloj (positiva y negativa). Una alternative podría ser la siguiente:

PROCESS ( clk)
BEGIN
IF( clk'EVENT AND clk=' I')THEN
counter <= counter + 1;
ELSIF( clk'EVENT AND clk='O') THEN
counter <= counter + 1 ;
END IF;

END PROCESS;

En este caso, además del mensaje descrito, el compilador podría que el contador de la señal es
multiply driven. En todo caso, la compilación se suspenderá

Otro aspect importante es que el atributo EVENT debe estar relacionado a una condición de
prueba. Por ejemplo, la sentencia IF(clk'EVENT ANO clk='1 ') es correcta, pero al usar solamente
IF(clk'EVENT) el compilador tendrá que asumir una condición de prueba por defult (digamos
"ANO clk='1 "') o enviará un mensaje del tipo "clock not locally stable".
Por ejemplo, consideremos otra vez el caso de un contador que debe ser incrementado en
ambas transiciones de. Uno podría escribir:

PROCESS (clk)
BEGIN
IF( clk'EVENT) THEN
counter := counter + 1 ;
END IF;

END PROCESS;

Ya que se supone que el PROCESS anterior se ejecuta cada vez que clk cambia, uno podría
esperar que el contador se incremente dos veces por ciclo de reloj. Sin embargo, por la razón ya
mencionada, esto no sucederá. Si el compilador asume un valor por default, se sintetizará un
circuito equivocado, porque solo se considerará una transición de clk; si no se supone un valor
por default, entonces espérese un mensaje de error y sin compilación.

Finalmente si aparece una señal en la lista de sensibilidad, pero no aparece en ninguna de las
asignaciones que componen el PROCESS, entonces es probable que el compilador simplemente
la ignorará. Este hecho se ilustra con el contador de doble transición descrito anteriormente.
Oigamos que se usa el siguiente código:

PROCESS ( clk)
BE GIN
counter := counter + 1 ;

END PROCESS;

Este código refuerza la idea de que el contador de la señal sea incrementado siempre que ocurre
un evento en clk (transición positiva más transición negativa). Sin embargo en vez de eso, podría
enviarse un mensaje del tipo "ignored unnecessary pin clk".

Ejemplo: Contrario a los casos descritos anteriormente, el código de dos procesos mostrado
enseguida será correctamente sintetizable por un compilador. Sin embargo, observe que hemos
usado una señal diferente en cada proceso.

----------------------
PROCESS (clk)
BEGIN
IF( clk'EVENT AND clk=' 1 ') THEN
X<= d;
END IF;
END PROCESS;
----------------------
PROCESS ( clk)
BEGIN
IF( clk'EVENT AND clk='O') THEN
y<= d;
END IF;
END PROCESS;
----------------------

Ahora que usted sabe lo que no debe hacer, se le invita a resolver el problema 6.1.

Ejemplo 6.11: RAM

Enseguida se muestra un ejemplo de código secuencial usando, particularmente la sentencia IF.


Mostramos la implementación de una RAM (random access memory). Como puede verse en la
figura 6.14(a), el circuito tiene un bus de entrada de datos (data_in), un bus de datos de salida
(data_out), un bus de dirección (addr), más pines de clock (clk) y habilitación de escritura
(wr_ena). Cuando wr_ena se activa, en la siguiente transición positiva de clk el vector presente
en data_in debe ser almacenado en la posición especificada por addr. La salida, data_out, por
otra parte, debe constantemente mostrar el dato seleccionado por addr. Desde el punto de vista
de un registro, el circuito puede resumirse como en la figura 6.14(b).

RAM V.T_ena

d~~:rl[ ll
wordO
data in word 1 data_out
word Z 7 q
OFF
addr
dk-;;
t
clk wr ena

(a) lb)

Figura 6.14
Circuito RAM del ejemplo 6.11.

Cuando wr_ ena está en nivel bajo, q se conecta a la entrada del flip-flop, y la terminal d se abre,
así que ningún dato se escribirá en la memoria. Sin embargo, cuando wr_ena pasa a nivel alto, d
se conecta a la entrada del registro, así que en la siguiente transición positiva de clk, d
sobrescribirá sobre su valor anterior.

En seguida se muestra un código VHDL que implementa el circuito de la figura 6.14. La


capacidad escogida para la RAM es de 16 palabras de 8 bits de longitud cada una. Observe que
el código es totalmente genérico.
Nota: En la sección 9.1 O del capítulo 9 se presentará otra implementación de memoria.

---------------------------------------------------
2 LIBRARY ieee·
'
3 USE ieee.std_logic_l 164.all;
4 ---------------------------------------------------
5 ENTITY ram IS
6 GENERIC (bits: INTEGER := 8; -- # ofbits per word
7 words: INTEGER := 16); -- # of words in the memory
8 PORT ( wrena, clk: IN STD_LOGIC;
9 addr: IN INTEGER RANGE O TO words-1;
10 data_in: IN STD_LOGIC_ VECTOR (bits-1 DOWNTO O);
11 data_out: OUT STD_LOGIC_ VECTOR (bits-1 DOWNTO O));
12 END ram;
13 ---------------------------------------------------
14 ARCHITECTURE ram OF ram IS
15 TYPE vector_array IS ARRA Y (O TO words-1) OF
16 STD_LOGIC_ VECTOR (bits-1 DOWNTO O);
17 SIGNAL memory: vector_array; 1
18 BEGIN
19 PROCESS (clk, wr_ena)
20 BEGIN
21 IF (wr_ena='l') THEN
22 IF ( clk'EVENT AND clk=' 1 ') THEN
23 memory(addr) <= data_in;
24 END IF;
25 END IF;
26 END PROCESS;
27 data out<= memory(addr);
28 END ram;
29 ---------------------------------------------------

Los resultados de la simulación del circuito sintetizado con el código anterior se muestra en la
figura 6.15.
1CO.Ons '200.0ns 3JD.Ons 4010ns 5CO.Ons 600.0n~. 700.0n3 EO:
ü-·m_ena
--c::lk o
iiF o¡rJ,jr 03 3 ~ .~
'(
m 52
=-
~do:!ta_in 050 K 51 ~
o · so X o ~...!2__,
data_out
ºª X 51

Figura 6.15
Resultados de la simulación del ejemplo 6.11.

6.1 O Usando Código Secuencial para Diseñar Circuitos Combinacionales

Ya hemos visto que el código secuencial puede ser usado para implementar tanto circuitos
secuenciales como circuitos combinacionales. En el primer caso, los registros son necesarios, de
tal manera que serán inferidos por el compilador. Sin embargo, esto no debe pasar en el
segundo caso. Por tanto, si se tarta de hacer un circuito combinacional, entonces se debe
especificar claramente la tabla de verdad en el código.
Con el objeto de satisfacer este criterio, se deben observar las siguientes reglas:

Regla 1: Asegúrese de que todas las señales de entrada usadas (read) en el PROCESS
aparezcan en la lista de sensibilidad.

Regla 2: Asegúrese de que todas las combinaciones de las señales de entrada/salida se incluyen
en el código; es decir, asegúrese de que, al mirar el código, se puede obtener la tabla de verdad
completa del circuito (en efecto, esto es cierto tanto para código secuencial como para).

No cumplir con la regla 1 generalmente causará que el compilador simplemente emita una
advertencia diciendo que una señal de entrada dada no fue incluida en la lista de sensibilidad, y
luego procede como si la señal fuera incluida. A pesar de que no se producen daños, es una
buena práctica de diseño siempre tomar la regla 1 en consideración.

Con respecto a la regla 2, sin embargo, las consecuencias pueden ser más serias porque
especificaciones incompletas de las señales de salida podría causar que el sintetizador infiera
latches con el objeto de mantener sus valores anteriores. Este hecho se ilustra en el ejemplo
siguiente.

Ejemplo 6.12: Diseño combinacional erróneo

Consideremos el circuito de la figura 6.16, para el cual se han provisto las siguientes
especificaciones: x debe comportarse como un multiplexor; es decir, debe ser igual a la entrada
seleccionada por sel; Y, por otra parte, debe ser igual a 'O' cuando sel = "00", o 'l' si sel =
"O 1 ". Estas especificaciones se resumen en la tabla de verdad de la figura 6.16(b). Observe
·~-----,----e.o-e .. - • - ' • .

que es un circuito combinacional. Sin embargo, las especificaciones provistas para Y son
incompletas, como se puede observar en la tabla de verdad de la figura 6.16(b). Usando solo
estas especificaciones, el código podría ser el siguiente:

a
X
b sel :\ y sel X )' sel X y

e 00 a o 00 a o 00 a o
y 01 b 1 Ol h l 01 b l
d 10 e 10 e y 10 e X
11 d 11 d y 1t d X
sel (l :O)

(a) (b) (e) (d)


1 -----------------------------------------------------------
2 LIBRAR Y ieee;
3 USE ieee.std_logic_l 164.all;
4 -----------------------------------------------------------
5 ENTITY example IS
6 PORT (a, b, e, d: IN STD_LOGIC;
7 sel: IN INTEGER RANGE O TO 3;
8 x, y: OUT STD _LOGIC);
9 END example;
10 ----------------------------------------------------------
11 ARCHITECTURE example OF example IS
12 BEGIN
13 PROCESS (a, b, e, d, sel)
14 BEGIN
15 IF (sel=O) THEN
16 x<=a;
17 y<='O';
18 ELSIF (sel= 1) THEN
19 x<=b;
20 y<=' l ';
21 ELSIF (sel=2) THEN
22 x<=c;
23 ELSE
24 x<=d;
25 END IF;
26 END PROCESS;
27 END example;
28 ----------------------------------------------------------
Después de compilar este código, los archivos de reportes muestran que ningún flip-flops fue
inferido (como se esperaba). Sin embargo, cuando miramos los resultados de la simulación
(figura 6.17), y. Observe que, para los mismos valores de la entrada (sel
vemos algo peculiar en
= 3 = "11 "), se obtienen dos resultados diferentes para y (cuando sel= 3 es precedido por sel=
O, Y= 'O' resulta, mientras que y= ')' se obtiene cuando sel= 3 es precedido por sel= 1 ). Esto
significa que alguna clase de memoria fue en efecto implementada por el compilador.

En efecto, si vemos las ecuaciones obtenidas con Quartus 11, por ejemplo (apéndice D),
verificamos que y fue calculada como y= (sel(O) AND sel(l)) OR (sel(O) AND y) OR (sel(l)
AND y). Por lo tanto, se implementó un latch (usando AND/OR gates), el cual hace la tabla de
verdad de la figura 6.16(c).
Para evitar lógica extra requerida por el latch, se deben usar las especificaciones de la figura
6.16(d) (se usó 'X' para todos los valores desconocidos o "don't care"). Así que la línea y
<='X'; debe ser incluida debajo de las líneas 22 y 24 en el código anterior. Ahora, y puede ser tan
simple como y = sel(O).

......
RU.Uns "'"UJ.Uns .::!UJ.Um; .QUU.Uns wu.uns tlJU.Uns /UU.Uns ti

a ,_._.. 1 L __
j;jr-b a
.*»-e a
1
L--·-----~-. -
O-d n 1
i.w= s:::RI nn n X :l .:( ·1 X
-s
·' (I__
... '.l o 1 l ~ 11
a 1
-- y

Figura 6.17
Resultados de la simulación del ejemplo 6.12.

6.11 Problemas
Como los problemas que acabamos de ver, el propósito de los problemas propuestos en esta
sección es para ilustrar aun más la, construcción de código secuencial (es decir, el uso de IF,.
WAIT, CASE, y LOOP, siempre dentro de un PROCESS). Sin embargo, si usted desea conocer
más acerca de SIGNALS y VARIABLES antes de trabajar en los siguientes problemas, puede
ver el capítulo 7, y luego regresar a esta sección. Finalmente, recuerde que con código
secuencial podemos implementar circuitos lógicos secuenciales así como circuitos
combinacionales. A pesar de que va a utilizar solo código secuencial en esta sección, le
invitamos a determinar si cada circuito de los siguientes (y en los ejemplos que acabamos de
ver, hablando del tema) es realmente un circuito secuencial o combinacional.
Problema 6.1: Contador de Eventos

Diseñe un circuito capaz de contar el número de eventos de reloj (número de transiciones


positivas +transiciones negativas, figura P6.1).

clk

Figura P6.1

Problema 6.2: Registro de Desplazamiento

Escriba un código VHDL que implemente el shift-register de 4 etapas de la figura P6.2. La


solución debe ser diferente de la del ejemplo 6.3.

din-- dout
DFF DFF DFF OFF

Figure P6.2

Problema 6.3: Codificador de Prioridad

La figura P6.3 muestra el mismo codificador de prioridad del problema 5.2. El circuito debe
codificar la dirección del bit de entrada de orden más alto que está activo. La salida "000" debe
indicar que no hay solicitud a la entrada (no hay bit activo). Escriba una solución VHDL para este
circuito usando solo código secuencial. Presente dos soluciones:

(a) Con IF.


(b) Con CASE.

'O' 7 PRJOR!TY
•1• ENCODER
6
5
4 2 __.. '1 '
'O'
-i: 3 ~ ')"

'1 ' 2 o ...... 'O"


·o·

Figure P6.3
Problema 6.4: Divisor de Frecuencia Genérico

Escriba un código VHDL para un circuito capaz de dividir la frecuencia de una señal de entrada
de reloj por un entero n (figura P6.4). El código debe ser genérico; es decir, n debe ser definida
usando la sentencia GENERIC.

FREQ.
DIVIDER

Figura P6.4

Problema 6.5: Multiplicador de Frecuencia

¿Y qué acerca del problema 6.4 opuesto?, es decir, digamos que queremos multiplicar la
frecuencia por n. ¿Puede hacerse?

Problema 6.6: Timer #1

Diseñe un timer capaz de contar desde O min:OO seg a 9 min:59 seg (figura P6.6). El circuito
debe tener botones start, stop, y reset. Las salidas deben ser SSD codificadas. Considere que se
dispone de una señal de 1 HZ confiable.

rnin sec sec

clk
start
----
---->
T
I
M
111

stop
_.,. E
R
reset __..,

Figura P6.6

Problema 6.7: Timer #2

Considere el timer del problema 6.6. Sin embargo, digamos que ahora solo un botón está
disponible el cual debe desarro_llar las fu~ciones de start y stop ~lternativ~~ente, y también
resetea el circuito cuando se opnme por mas de dos segundos. Escriba un códiqo VHDL ara tal
timer (figura P6.7). Otra vez, considere que se dispone de una señal confiable de reloj de 1 Hz.
min sec sec

clk
T

start/
1
M

E
stop/ R
re set

Figure P6.7

Problema 6.8: Detector de paridad

La figura P6.8 muestra el diagrama top-level de un detector de paridad. El vector de entrada tiene
ocho bits. La salida debe ser 'O' cuando el número de '1 'sen el vector de entrada es par, o '1' en
otro caso. Escriba un código secuencial para este circuito. Si es posible, escriba más de una
solución.

PARITY
input (7:0) DETECTOR output

Figura P6.8

Tabla P6.9

Número de of unos en din(?: 1) count(2:0)


-------------------------------------------------------------------------------------------------------------------
o 000
1 001
2 010
3 /011
4 100
5 101
6 110
-------------------------------------------------------------------------------------------------------------------

Tabla PS.10
---------------- ---------------------------------------------------------------------------------------------------
Número de unos en din(7:1) dout(7:0)
----------------------------------------------------------------------------------------------------------------
o 0000000]
00000010
2 00000100
3 00001000
4 00010000
5 00100000
6 01000000
7 10000000
-------------------------------------------------------------------------------------------------------------------

Problema 6.9: Cuenta de unos

Digamos que queremos diseñar un circuito que cuente el número de 'l 's en un vector binario
dado (tabla P6.9). Escriba un código VHDL que implemente tal circuito. Luego sintetice Y pruebe
su solución.

Problema 6.1 O: Codificador de intensidad

Diseñe un codificador que recibe como entrada un vector de 7 bits din, y crea a partir de él un
vector de salida dout cuyos bits son todos 'O's, excepto el bit cuyo índice corresponde al número
de '1 'sen din. Todas las situaciones posibles se resumen en la tabla P6.1 O.

Problema 6.11: Multiplexor

Escriba un código secuencial VHDL para el circuito del problema 5.1. Si es posible, presente más
de una solución.

Problema 6.12: Desplazamiento de Vector

Escriba un código secuencial VHDL para el circuito del ejemplo 5.6. Si es posible, presente más
de una solución.

Problema 6.13: ALU

Escriba un código secuencial VHDL para el circuito del ejemplo 5.5. Si es posible, presente más
de una solución.

Problema 6.14: Sumador/Substractor con Signo/SinSigno


Resuelva el problema 5.5 usando código secuencial. Haga que el código sea tan genérico como
sea posible ..

Problema 6.15: Comparador

Resuelva el problema 5.8 usando código secuencial.

Problema 6.16: Sumador Carry Ripple

Considere el sumador carry ripple del ejemplo 6.8.


(a) Por aqué no podemos reemplazar la sentencia IF de las líneas 17-19 en la solución 2
simplemente por "temp:=cO;"?

(b) Observe que el circuito del ejemplo 6.8 es completamente combinacional, así que también
puede ser implementado usando solamente código concurrente (esto es, sin un PROCESS).
Escriba un código de ejemplo para él. Luego simule y analice los resultados.

Problema 6.17: Flip Flop D

Considere el OFF con reset asíncrono de la figura 6.1. Abajo hay varios códigos para ese circuito.
Examine cada uno de ellos y determine si trabajarían apropiadamente. Explique brevemente sus
respuestas.

LIBRAR Y ieee;
USE ieee.std_logic_l 164.all;
--------------------------------------
ENTITY dff IS
POR T ( d, clk, rst: IN BIT;
q: OUT BIT);
END dff;

----- Solución 1 ---------------------


ARCHITECTURE archl OF dffIS
BE GIN
PROCESS ( clk~ rst)
BEGIN
IF ( rst=' 1 ') THEN
q <='O';
ELSIF ( clk'EVENT AND clk=' 1 ') THEN
q <= d;
END IF;
. END PROCESS;
END arch l ;

----- Solución 2 ---------------------


ARCHITECTURE arch2 OF dff IS
BE GIN
PROCESS ( clk)
BEGIN
IF (rst=' l ')THEN
q <='O';
ELSIF ( clk'EVENT AND clk=' l ') THEN
q <= d;
END IF;
END PROCESS;
END arch2;

----- Solución 3 ---------------------


ARCHITECTURE arch3 OF dff IS
BEGIN
PROCESS (clk)
BEGIN
IF (rst='l') THEN
q <='O';
ELSIF ( clk'EVENT) THEN
q <= d;
END IF;
END PROCESS;
END arch3;

----- Solución 4 ---------------------


ARCHITECTURE arch4 OF dfflS
BEGIN
PROCESS (clk)
BEGIN
IF (rst=' l ') THEN
q <='O';
ELSIF ( clk=' l ') THEN
q <=d;
END IF;
END PROCESS;
END arch4;

----- Solución 5 ---------------------


ARCHITECTURE arch5 OF dffIS
BEGIN
PROCESS ( clk, rst, d)
BEGIN
IF (rst='l') THEN
q <='O';
ELSIF (clk='l') THEN
q <= d;
END IF;
END PROCESS;
END arch5;

Potrebbero piacerti anche