Está en la página 1de 48

DISPOSITIVOS LOGICOS PROGRAMABLES

Lenguajes de descripcin de hardware - VHDL

Teora En esta parte del tutorial aprenders todos los secretos de la sintaxis del lenguaje VHDL, en el cual se estudiar de una forma terica y clara cmo crear un programa en VHDL. Este apartado consta de 7 lecciones distintas:

1. Introduccin
1.1. Breve resea histrica 1.2. VHDL vs MSI

2.

3.

4.

5.

6.

1.3. Qu es un PLD 1.4. Conociendo el lenguaje VHDL 1.5. Cocurrencias y seales Unidades bsicas de diseo 2.1. Cmo se declara una entidad 2.1.1.Modos 2.1.2.Tipos 2.2. Cmo se declara una arquitectura 2.2.1.Estilos 2.3. Paquetes 2.4. Libreras (incluye exposicin de librera LPM) Objetos, tipos de datos y operaciones 3.1. Objetos 3.2. Identificadores 3.3. Palabaras reservadas 3.4. Smbolos especiales 3.5. Tipos de datos 3.6. Expresiones y operadores 3.7. Atributos de los vectores Gramtica del lenguaje I 4.1. Sentencias secuenciales 4.2. Asignacin a seal 4.3. Asignacin a variable 4.4. Sentencia if 4.5. Sentencia case 4.6. Sentencia loop 4.7. Sentencia exit 4.8. Sentencia next 4.9. Sentencia null 4.10. Sentencia wait 4.11. Sentencia wait until Gramtica del lenguaje II 5.1. Sentencias concurrentes 5.2. Sentencia process 5.3. Asignacin concurrente a seal 5.4. Asignacin concurrente condicional 5.5. Asignacin concurrente con seleccin Interface, compilador e implementacin 6.1. VHDL sintetizable 6.2. Galaxy de Cypress 6.3. Nova de Cypress 6.4. Grabacin de nuestros propios diseos

Prcticas Descarga

CONCEPTOS PRELIMINARES
Esta parte del tutorial te permitir implementar desde el primer momento los ejercicios propuestos y entender el lenguaje VHDL. Lo nico que se necesita para seguir este curso es saber Electrnica Digital y tener nociones de cualquier lenguaje de programacin ya sea Pascal, C, Basic,...

El lenguaje de descripcin hardware VHDL (Very high speed Hardware Description Logic) es un lenguaje orientado a la descripcin de hardware pero con muchos elementos heredados de otros lenguajes como C o Pascal. Una vez realizado un programa en VHDL (con extensin VHD) y haberlo compilado con xito, tendremos un fichero con el mismo nombre y extensin JED, con el cual podremos grabar una PLD (Dispositivo Lgico Programable) con la misma operatividad que el fichero VHD. Al describir cualquier dispositivo en VHDL (desde una simple puerta and hasta un sistema completo) se deben definir dos elementos principales: Entidad o entity que es la interfaz del dispositivo con el exterior. Tiene por objeto decir que seales son visibles o accesibles desde el exterior, es decir los puertos o ports del dispositivo. Es describir las patillas del circuito que sern operativas. Su estructura mas general es la siguiente, donde las palabras en negrita son propias del lenguaje, y las restantes elegidas por el usuario: Entity entidad is genericos puertos declaraciones end nombre; Pero debemos fijarnos en la estructura ms habitual de las entidades que es la siguiente: Entity entidad is puertos end entidad; Arquitectura o arquitecture que es la funcionalidad que realiza el dispositivo, es decir, qu transformaciones se realizarn sobre los datos que entren por los puertos de entrada para producir la salida. Dentro de este apartado es donde se dota de operatividad al circuito. Su estructura general es la siguiente, y debe estar incluida en el mismo fichero de la entidad a la que hace referencia: Arquitectura nombre of nombre_entidadis declaraciones begin sentencias end nombre; Para acabar esta introduccin deberemos tener en cuenta una serie de detalles ms de ste lenguaje: VHDL no distingue las maysculas de las minsculas, por lo que deberemos tener cuidado al asignar nombres a las variables, especialmente si estamos acostumbrados a trabajar con C. Las variables deben empezar por una letra, no deben contener ni espacios ni smbolos como &, %, $, #, !, etc. Su longitud no est limitada, no pueden acabar con un carcter de subrayado o tener dos subrayados seguidos. Para representar un nmero de una sola cifra, deberemos situarlo entre apstrofes; as: '1' Para representar un nmero de ms de una cifra, lo representaremos as: "10011"

Leccin No 1 Introduccin

1. Breve resea histrica


A mediados de los aos setenta se produce una fuerte evolucin en los procesos de fabricacin de los circuitos integrados, y junto a las tecnologas bipolares, surge la MOS ( metal oxide semiconductor), principalmente la NMOS, promoviendo el desarrollo de circuitos digitales hasta la primera mitad de los aos ochenta. En aquellas pocas, el esfuerzo de diseo se concentraba en los niveles elctricos para establecer caractersticas e interconexiones entre los componentes bsicos a nivel de transistor. El proceso de diseo era altamente manual y tan solo se empleaban herramientas como el PSPICE para simular esquemas elctricos con modelos previamente personalizados a las distintas tecnologas. A medida que pasaban los aos, los procesos tecnolgicos se hacan ms y ms complejos. Los problemas de integracin iban en aumento y los diseos eran cada vez ms difciles de depurar y de dar mantenimiento. Inicialmente los circuitos MSI (Medium Scale Integration ) y LSI (Low Scale Integration ) se disearon mediante la realizacin de prototipos basados en mdulos ms sencillos. Cada uno de estos mdulos estaba formado por puertas ya probadas, este mtodo poco a poco, iba quedndose obsoleto. En ese momento (finales de los aos setenta) se constata el enorme desfase que existe entre tecnologa y diseo. La considerable complejidad de los chips que se pueden fabricar, implica unos riesgos y costes de diseo desmesurados e imposibles de asumir por las empresas. Es entonces, cuando diversos grupos de investigadores empiezan a crear y desarrollar los llamados "lenguajes de descripcin de hardware" cada uno con sus peculiaridades. Empresas tales como IBM con su IDL, el TI - HDL de Texas Instruments, ZEUS de General Electric, etc., as como los primeros prototipos empleados en las universidades, empezaron a desarrollarse buscando una solucin a los problemas que presentaba el diseo de los sistemas complejos. Sin embargo, estos lenguajes nunca alcanzaron el nivel de difusin y consolidacin necesarios por motivos distintos. Unos, los industriales, por ser propiedad de la empresa permanecieron encerrados en ellas y no estuvieron disponibles par su estandarizacin y mayor difusin, los otros, los universitarios, perecieron por no disponer de soporte ni mantenimiento adecuado. Alrededor de 1981 el Departamento de Defensa de los Estados Unidos desarrolla un proyecto llamado VHSIC (Very High Speed Integrated Circuit ) su objetivo era rentabilizar las inversiones en hardware haciendo ms sencillo su mantenimiento. Se pretenda con ello resolver el problema de modificar el hardware diseado en un proyecto para utilizarlo en otro, lo que no era posible hasta entonces porque no exista una herramienta adecuada que armonizase y normalizase dicha tarea, era el momento de los HDL's

2. VHDL
En 1983, IBM, Intermetrics y Texas Instruments empezaron a trabajar en el desarrollo de un lenguaje de diseo que permitiera la estandarizacin, facilitando con ello, el mantenimiento de los diseos y la depuracin de los algoritmos, para ello el IEEE propuso su estndar en 1984. Tras varias versiones llevadas a cabo con la colaboracin de la industria y de las universidades, que constituyeron a posteriori etapas intermedias en el desarrollo del lenguaje, el IEEE public en diciembre de 1987 el estndar IEEE std 1076-1987 que constituy el punto firme de partida de lo que despus de cinco aos sera ratificado como VHDL. Esta doble influencia, tanto de la empresa como de la universidad, hizo que el estndar asumido fuera un compromiso intermedio entre los lenguajes que ya haban desarrollado previamente los fabricantes, de manera que ste qued como ensamblado y por consiguiente un tanto limitado en su facilidad de utilizacin haciendo dificultosa su total comprensin. Este hecho se ha visto incluso ahondado en su revisin de 1993.

Pero esta deficiencia se ve altamente recompensada por la disponibilidad pblica, y la seguridad que le otorga el verse revisada y sometida a mantenimiento por el IEEE. La independencia en la metodologa de diseo, su capacidad descriptiva en mltiples dominios y niveles de abstraccin, su versatilidad para la descripcin de sistemas complejos, su posibilidad de reutilizacin y en definitiva la independencia de que goza con respecto de los fabricantes, han hecho que VHDL se convierta con el paso del tiempo en el lenguaje de descripcin de hardware por excelencia

3. Qu es un PLD (Dispositivo de Lgica Programable)


Un dispositivo lgico programable es un circuito integrado, formado por una matriz de puertas lgicas y flipflops, que proporcionan una solucin al diseo de forma anlogas, a las soluciones de suma de productos, productos de sumas y multiplexores. La estructura bsica de una PLD permite realizar cualquier tipo de circuito combinacional basndose en una matriz formada por puertas AND, seguida de una matriz de puertas OR. Tres son los tipos ms extendidos de PLD's, la PROM, PLA, y la PAL. PROM (Programmable Read Only Memory) Este tipo de dispositivo se basa en la utilizacin de una matriz AND fija, seguida de una matriz OR programable. La matriz programable esta formada por lneas distribuidas en filas y columnas en las cuales los puntos de cruce quedaran fijos por unos diodos en serie con unos fusibles que sern los encargados de aislar las uniones donde no se requiera la funcin lgica. La fase de programacin se realiza haciendo circular una corriente capaz de fundir el fusible en aquellas uniones donde no se desee continuidad. Por otra parte, para cada combinacin de las seales de entrada, el codificador activa una nica fila y a su vez activa aquella columna a las que esta todava unida a travs del diodo. PLA (Programmable Logic Array) Parecido en la dispositivo a la PROM, difiere de esta, en que aqu en la PLD , ambas matrices, la de puertas And, as como la de puertas Or es programable, por lo que nos vemos habilitados a incrementar el nmero de entradas disponibles, sin aumentar el tamao de la matriz. Esta estructura permite una mejor utilizacin de los recursos disponibles en el circuito integrado, de tal forma que se genera el mnimo numero de trminos necesarios para generar una funcin lgica. PAL (Programmable array Logic) Una PAL es diferente de una PROM a causa de que tiene una red Y programable y una red O fija. Con un programador PROM podemos obtener los productos fundamentales deseados quemando los eslabones y luego conseguir la suma lgica de dichos productos mediante las conexiones fijas de salida.

Encapsulado tpico de una PLD

4. Conociendo el lenguaje VHDL


El lenguaje VHDL est creado especficamente para el diseo de hardware, es decir, podremos implementar con l multitud de circuitos lgicos, tanto combinacionales como secuenciales. ste lenguaje tambin nos permite describir elementos ms complejos, como CPU's (Unidad Central de Procesamiento), manejar ficheros, retrasos en el tiempo, etc. pero no siempre se puede implementarlos; tan slo, y en segn que casos, se llegar a la simulacin. Este libro se centra en el VHDL sintetizable, es decir, con el que es posible llegar a grabar un dispositivo lgico programable. Un programa en VHDL consta de dos partes. La primera, la entidad, nos sirve para relacionar nuestro diseo con el mundo exterior, es decir, analizamos lo que tratamos de crear como una "caja negra", de la que slo conocemos sus entradas, sus salidas y la disposicin de las mismas. La segunda parte, la arquitectura, describe como trata el circuito la informacin correspondiente a las entradas para obtener las salidas.

5. Sentencias concurrentes y secuenciales


Para iniciarnos correctamente en el aprendizaje y manejo de VHDL es importante que comprendamos desde un principio la diferencia entre concurrente y secuencial. El concepto de concurrencia, se ve claramente graficado en los circuitos electrnicos donde los componentes se encuentran siempre activos, existiendo una asociacin intrnseca, entre todos los eventos del circuito; ello hace posible el hecho de que si se da algn cambio en una parte del mismo, se produce una variacin (en algunos casos casi instantnea) de otras seales. Esta comportamiento de los circuitos reales obliga a que VHDL soporte estructuras especficas para el modelado y diseo de este tipo de especificaciones de tiempos y concurrencias en el cambio de las distintas seales digitales de los diseos. Por el contrario, los asignamientos secuenciales, son ms bien propios de los SDL (soft design lenguage) en los que la programacin tiene un flujo natural secuencializado, siendo propio de este tipo de eventos las sentencias case, if, while, loop, etc ms propias de estas sintaxis. Las construcciones concurrentes del lenguaje son usadas dentro de estructuras concurrentes, por ejemplo una arquitectura tiene una naturaleza eminentemente concurrente (es decir que est activo todo el tiempo), mientras que el cuerpo de un process es en principio eminentemente secuencial. La asignacin de eventos secuenciales dentro de una estructura concurrente se ejecutar de forma concurrente, es decir, al mismo tiempo que las dems sentencias.

VHDL soporta con este motivo, tres tipos de objetos, las variables, las constantes y las seales . Como las variables y las seales pueden variar su valor mientras ejecutamos un programa, sern stas las encargadas de almacenar dichos datos, asimismo sern los portadores de la informacin. nicamente las seales pueden tener la connotacin de globalidad dentro de un programa, es decir, que pueden ser empleadas dentro de cualquier parte del programa a diferencia de las variables que solo tienen sentido en el interior de un process . Los process son estructuras concurrentes constituidas por sentencias de ejecucin secuencial, esto provocar que dentro de un process nos encontremos con sentencias similares a las de los SDL (lenguajes de descripcin de software) que nos llevan a emplear VHDL como si de otro lenguaje comn se tratara. Dentro de un process nos podemos encontrar con la declaracin y utilizacin de las variables como parmetros locales al process. De ejecucin secuencial, las variables evalan su valor dentro del cuerpo del proceso de forma inmediata, sin consumir tiempo de ejecucin, pero como estn dentro de un process, que es una estructura concurrente, este valor no ser asumido, sino hasta el final de la ejecucin de dicho process. Veamos el siguiente ejemplo de asignacin concurrente para seales:

W <= not a; x <= a and b; y <= c and w; z <= x or y;

Al producirse un cambio en la parte derecha de la estructura de asignacin ( <= NOT a) de alguna de las sentencias, la expresin es evaluada de nuevo en su totalidad, con la siguiente asignacin del nuevo valor a la seal de la izquierda. Esto puede provocar que mltiples asignaciones en el cuerpo de una arquitectura se activen simultneamente, como por ejemplo, en la imagen superior, la cual se corresponde al cdigo situado a su izquierda.

Leccin No 2 Unidades Bsicas de Diseo


1. Como se declara una Entidad
En la declaracin de entidades, se definen las entradas, salidas y tamao de un circuito, explicitando cuales son, de qu tamao (de 0 a n bits), modo (entrada, salida,...) y tipo (integer, bit,...). Las entidades pueden definir bien las entradas y salidas de un diseo ms grande o las entradas y salidas de un chip directamente. La declaracin de entidades es anloga al smbolo esquemtico de lo que queremos implementar, el cual describe las conexiones de un componente al resto del proyecto, es decir, si hay una entrada o puerto de 8 bits, o dos salidas o puertos de 4 bits, etc. La declaracin de entidades tiene la siguiente forma: entity circuito_a is Port( -- puertos de entradas -- puertos de salidas -- puertos de I/O -- puertos de buffers Cabecera del programa Se indica que a continuacin viene los puertos (o grupos seales) de entrada y/o salida Aqu se declaran las entradas y/o salidas con la sintaxis que se ver a continuacin. Las lneas empezadas por dos guiones son ignoradas por el compilador. As mismo, recordamos que el compilador no distingue las maysculas de las minsculas Se indica que se ha acabado la declaracin de puertos de entrada y/o salida, y que se ha acabado la entidad

End circuito_a;

Como hemos dicho, cada seal en una declaracin de entidad est referida a un puerto (o grupo de seales), el cual es anlogo a un(os) pin(es) del smbolo esquemtico. Un puerto es un objeto de informacin, el cual, puede ser usado en expresiones y al cual se le pueden asignar valores. A cada puerto se le debe asignar un nombre vlido. A continuacin se exponen algunos ejemplos: nombre_variable: modo tipo; Puerto a: in bit; Puerto b: in bit_vector(0 to 7); Puerto c: out bit_vector(3 downto 0); Puerto d: buffer bit; Puerto e: inout std_logic; Forma genrica de designar un puerto El primer puerto es un bit de entrada, y su nombre es "puerto a" El segundo puerto es un vector de 8 bits de entrada siendo el MSB el puerto b(0) y el LSB el puerto b(7) El tercer puerto es un vector de 4 bits de salida siendo el MSB el puerto c(3) y el LSB el puerto c(0) El cuarto puerto es un buffer de un solo bit, cuyo nombre es "puerto d" El quinto puerto es una entrada/salida del tipo estndar logic de un solo bit

Como se puede deducir de los ejemplos anteriores, seguidos del nombre del puerto y separado de ste por dos puntos, se debe indicar el tipo de puerto. El modo describe la direccin en la cual la informacin es transmitida a travs del puerto: in, out, buffer e inout. Si no se especifica nada, se asume que el puerto es del modo in.

Modo in: Un puerto es de modo in si la informacin correspondiente al mismo, entra a la entidad y se suele usar para relojes, entradas de control (como las tpicas load, reset y enable), y para datos de entrada unidireccionales. Modo out: Un puerto es de modo out si la informacin fluye hacia fuera de la entidad. Este modo no permite realimentacin ya que al declarar un puerto como out estamos indicando al compilador que el estado lgico en el que se encuentra no es legible. Esto le da una cierta desventaja pero a cambio consume menos recursos de nuestros dispositivos lgicos programables. Modo buffer: Es usado para una realimentacin interna, es decir, para usar este puerto como un driver dentro de la entidad. Este modo es similar al modo out, pero adems, permite la realimentacin y no es bidireccional, y solo puede ser conectado directamente a una seal interna, o a un puerto de modo buffer de otra entidad. Una aplicacin muy comn de este modo es la de salida de un contador, ya que debemos saber la salida en el momento actual para determinar a salida en el momento siguiente. Modo inout: Es usado para seales bidireccionales, es decir, si necesitamos que por el mismo puerto fluya informacin tanto hacia dentro como hacia afuera de la entidad. Este modo permite la realimentacin interna y puede reemplazar a cualquiera de los modos anteriores, pudindose usar este modo para todos los puertos, pero reduciremos la lectura posterior del cdigo por otra persona, y reduciendo los recursos disponibles de la dispositivo.

Como se ha comentado ms arriba, el lenguaje slo admite cuatro modos para los puertos, pero puede haber tantos tipos de seales como queramos, ya que los podemos crear nosotros mismos. VHDL incorpora varios tipos de forma estndar (por haber sido creado as), pudiendo usar otros definidos en libreras normalizadas, y los creados por el usuario. La norma internacional IEEE 1076/93 define cuatro tipos nativos para VHDL como son: Tipo boolean: puede tomar dos valores: true/true o falso/false. Un ejemplo tpico es la salida de un comparador que da verdadero si los nmeros comparados son iguales y falso si no lo son: Slo puede tomar dos valores: verdadero o falso, y es de salida equal: out boolean; (darle mas operatividad a la salida de un comparador sera superfluo) Tipo bit: Puede tomar dos valores: 0 1 (o tambin "low" o "high", segn se prefiera). Es el tipo ms usado de los nativos. Tipo bit_vector: Es un vector de bits. Debemos tener cuidado al definir el peso de los bits que lo integran, ya que segn pongamos la palabra reservada downto o to estaremos diciendo que el bit ms significativo es el nmero ms alto o el ms bajo del vector, respectivamente..

numero : bit_vector (0 to 7); En este caso el MSB es numero(0) y numero(7) el LSB numero : bit_vector (7 downto 0); En este caso el MSB es numero(7) y numero(0) el LSB Tipo integer: Para manejar nmeros enteros. Hay que advertir que el uso de enteros consume muchos recursos del dispositivo de lgica programable, siempre y cuando sea sintetizable, debido a que est prcticamente creado para la simulacin. Pero ante la necesidad de ampliar la operatividad del tipo bit, la norma IEEE 1164, defini un nuevo tipo llamado std_logic, std_ulogic, y sus derivados tales como std_logic_vector y std_ulogic_vector. Como su nombre pretende indicar, es el tipo de tipo lgico estndar, que es el ms usado en la actualidad, as como en la mayora de ejemplos de este libro. Como ejemplo, a continuacin se incluye la declaracin de una entidad correspondiente a un multiplexor de 2x1 de cuatro bits, con entrada de habilitacin o enable. El multiplexor necesita las entradas de informacin, la seal de seleccin, la de enable y las salidas de informacin.

entity multi is port ( enable: in bit; selec: in bit; in1: in bit_vector(3 downto 0); in2: in bit_vector(3 downto 0); out1:out bit_vector(3 downto 0)

Cabecera ya estudiada arriba, en la que multi es el nombre de la entidad enable es un bit de entrada (suficiente para habilitar o no) selec es otro bit de entrada, que selecciona la entrada in1 o in2, ambas de 4 bits out1 es de salida, que lgicamente, debe ser de la misma longitud que in1 e in2

end multi;

Ntese que el ltimo puerto no lleva punto y coma al final de la lnea. Si lo llevase estara incorrecto

A continuacin se muestra otro ejemplo correspondiente a la entidad para un comparador: entity compa is port ( a,b: in bit_vector(3 downto 0); igual: out bit; end compa; Cabecera de la entidad, cuyo nombre es compa a y b son las entradas de cuatro bits igual es la salida de un slo bit

Se finaliza la entidad con la palabra clave end y el nombre de la misma (compa).

Debemos recordar dos puntos ms a la hora de dar el nombre a algn puerto, que se tratarn ms adelante en el apartado de objetos: VHDL no distingue las letras maysculas de las minsculas, por lo que un puerto llamado por nosotros "EnTraDA" ser equivalente a otro que se llame "ENTRADA" o "entrada". El primer carcter de un puerto slo puede ser una letra, nunca un nmero. As mismo, no pueden contener caracteres especiales como $, %, ^, @, ... y dos caracteres de subrayado seguidos.

Estos dos detalles a tener en cuenta surgieron del comit que cre este lenguaje, por lo que no se debe considerar como un fallo de nuestra herramienta (WARP2), sino como una caracterstica ms del lenguaje.

2. Como se declara una Arquitectura


La arquitectura indica el tipo de procedimiento que se realiza con la informacin correspondiente a las seales de entrada, (declarados previamente en la entidad) para llegar a tener los puertos de salida (tambin declarados en la entidad). En la declaracin de arquitecturas es donde reside todo el funcionamiento de un circuito, ya que es ah donde se indica que hacer con cada entrada, para obtener la salida. Si la entidad es vista como una "caja negra", para la cual lo nico importante son las entradas y las salidas, entonces, la arquitectura es el conjunto de detalles interiores de la caja negra. La declaracin de arquitecturas debe constar de las siguientes partes como mnimo, aunque suelen ser ms: Cabecera de la arquitectura. En sta, archpro es un nombre cualquiera (suele empezar por "arch", aunque no es necesario) y programa es el nombre de una entidad existente en el mismo fichero Declaraciones de apoyo, que se vern en la pgina siguiente Se da comienzo al programa

architecture archpro of programa is -- declaracin de seales y otros accesorios Begin

-- ncleo del programa end archpro;

Conjunto de sentencias, bucles, procesos, funciones,... que dan operatividad al programa. Fin del programa

Como podemos apreciar, es una estructura muy sencilla, y que guarda alguna relacin con Turbo Pascal. Las sentencias entre begin y end son las que describen el circuito, y es en lo que se centra tanto este libro electrnico como cualquier otro que trate sobre VHDL. A continuacin, se muestra el cdigo fuente de un programa en VHDL de un multiplexor (esta es una de las mltiples formas de implementar un multiplexor en VHDL), el cual debe ir unido a la entidad expuesta en el apartado de la declaracin de entidades, ya que una parte sin la otra carecen de sentido.

architecture archimulti of multi is

Cabecera de la arquitectura. En esta ocasin el nombre de la arquitectura es archimulti, y el de la entidad es multi, la cual est definida anteriormente. En este programa no se necesitan seales Comienza al programa Sentencias que hacen que la entidad definida como multiplexor realice la funcin propia de su nombre. Solo hay que entender la estructura de las arquitecturas en estos momentos, por lo que este cdigo no debe ser objeto de preocupacin. Fin del programa

-- seales Begin process(enable,in1,in2) begin if enable='0' then out1<="1111"; elsif enable='1' then if(selec = '0') then out1<=in1; elsif(selec = '1') then out1<=in2; end if; end if; end process; end archimulti;

Para describir una arquitectura podremos usar cuatro estilos, teniendo cada uno, su propio nivel de abstraccin. Los estilos son: Estilo behavioral o comportamiento (funcional): Este estilo se caracteriza por incluir las sentencias y rdenes tpicas de un lenguaje de programacin ( if, then, case,...), sin importarnos como quedar la distribucin de puertas lgicas dentro de la PLD. Es necesario un proceso al ser una estructura secuencial. El siguiente fragmento de cdigo describe un comparador (usando una entidad descrita en este mismo tutorial) escrito con el estilo behavioral o de comportamiento.

architecture behavioral of compa is begin comp: process (a, b) begin if a= b then igual<='1'; else igual<='0'; end if; end process comp; end behavioral;

Como se puede apreciar en este ejemplo se utilizan los clsicos if then else de cualquier lenguaje de programacin, y adems las asignaciones son secuenciales. Esto es lo que hace esta arquitectura de comportamiento o behavioral.

Estilo dataflow o flujo de datos: Este estilo podremos encontrarlo de dos formas similares, pero ambas implican cmo la informacin ser transferida de seal a seal y de la entrada a la salida sin el uso de asignaciones secuenciales, sino concurrentes. Es decir, en este estilo no se pueden usar los procesos. El

comparador descrito de forma behavioral o de comportamiento se puede escribir usando el estilo dataflow de cualquiera de las dos formas siguientes: architecture dataflow1 of compa is begin igual<='1' when (a=b) else '0'; end dataflow1; architecture dataflow2 of compa is begin igual<= not(a(0) xor b(0)) and not(a(1) xor b(1)) and not(a(2) xor b(2)) and not(a(3) xor b(3)); end dataflow2; Esta arquitectura es del estilo dataflow porque se especifica como la informacin pasar a la salida sin usar sentencias secuenciales

Aqu de nuevo las asignaciones son concurrentes, no secuenciales.

Estilo structural o estructural: En l se describe un "netlist" de VHDL, en los cuales los componentes son conectados y evaluados instantneamente mediante seales. No se suele usar este estilo nicamente en una arquitectura ya que resulta muy enredado y difcil de modificar, siendo de verdadera utilidad cuando debemos crear una estructura grande y deseamos descomponerla en partes para manejarla mejor, y para hacer la simulacin de cada parte ms sencilla. Se suele requerir el uso de seales auxiliares, y adems paquetes y libreras accesorios, lo cual, recordemos, debe estar declarado al comienzo de la entidad.

architecture struct of compa is signal x: bit_vector(0 to 3); begin u0: xnor2 port map (a(0),b(0),x(0)); u1: xnor2 port map (a(1),b(1),x(1)); u2: xnor2 port map (a(2),b(2),x(2)); u3: xnor2 port map (a(3),b(3),x(3)); u4: and4 port map (x(0),x(1),x(2),x(3),igual); end struct;

Aqu solo se interconexionan salidas con entradas de componentes. La salida viene dada por la operatividad de los componentes, la cual no se puede saber si no conocemos el paquete del cual ha sido leda.

Estilo mixto: Es el estilo que est compuesto en mayor o menor medida de dos o ms de los estilos descritos anteriormente.

Deberemos tener en cuenta que el cdigo VHDL que escribamos no siempre va a describir una funcin de forma ptima, la cual no siempre va a poder ser reducida por la herramienta de compilacin. Esto se traduce en un peor aprovechamiento de los recursos de las PLD's. Por lo tanto, diferentes diseos producen diferentes, aunque equivalentes, ecuaciones de diseo, pudindose dar, sin embargo, disposiciones diferentes de los recursos. Es habitual el usar el estilo estructural para descomponer un diseo en unidades manejables, siendo cada unidad diseada por equipos de trabajo distintos. El estilo estructural se usa adems para tener un grado de control alto sobre la sntesis. Para concluir el apartado dedicado a las arquitecturas slo resta el recordar que tanto la entidad y la arquitectura deben ir unidas en el mismo fichero, ya que una parte carece de sentido sin la otra.

3. Paquetes
Un diseador de Hardware que utilice frecuentemente la misma tecnologa de diseo ha de hacerse, con el paso del tiempo, con una resea amplia de procedimientos, funciones, puertas y, en general, de componentes

que emplear con frecuencia. Los packages permiten agrupar un conjunto de declaraciones para que puedan ser usadas en el diseo de diferentes circuitos sin ser repetidas en la declaracin de cada uno. La estructura bsica en la declaracin de un paquete est dividida en dos partes claramente diferenciadas: La declaracin del paquete, package: donde obtenemos una visin externa y simplificada del componente. La declaracin del paquete va precedida por la palabra reservada package y finaliza con end. En el cuerpo de la declaracin nos encontramos con procedures, funciones, componentes, etc. tal y como apareceran en la parte de la declaracin de una entidad.

package nombre_del_package is
-- declaracin de procedures -- declaracin de funciones -- declaracin de tipos, etc... end nombre_del_package; Esta parte es a una entidad, lo mismo que un paquete es a un programa normal en VHDL.

La declaracin del cuerpo del paquete, package body: especifica el funcionamiento de procedures, funciones, tipos, etc. que nos permite su implementacin, de forma similar a la arquitectura. Debe llevar las palabras reservadas package body.

package body nombre_del_package is -- definicin de procedures -- definicin de funciones -- definicin de tipos, etc. end nombre_del_package;

Esta parte se corresponde con una arquitectura.

Todo esto hace posible que una vez declarados los subprogramas dentro de un package, podamos utilizarlos haciendo nicamente uso de una llamada al proceso, asignndole un nombre y la lista de parmetros necesarios. Para poder usar o llamar a un package que ha sido descrito anteriormente, debemos incluir la clusula use antes del cuerpo de la arquitectura. use work.nombre del package.nombre del componente; Para esto se deben especificar tres cosas: El nombre de la librera donde se encuentra el paquete El nombre del paquete El nombre del componente que se desee habilitar

Hay ocasiones en las que deseamos habilitar todos los componentes declarados en un paquete, ya sea por comodidad o por no saber exactamente donde se encuentra el recurso que deseamos usar. En tal caso, haramos uso de la palabra all de la siguiente forma:

use work.nombre del package.all;

Como ejemplo se muestra a continuacin la declaracin de un package que contiene a dos componentes, un contador y un decodificador.

--Primero se declaran las libreras que se van a emplear library ieee; use ieee.std_logic_1164.all; use work.std_arith.all; --Empieza la declaracin del package "UNO" package uno is component count port clk,reset: in bit; conta: buffer std_logic_vector(1 downto 0)); end component; component decoder port seleccion: in std_logic_vector(1 downto 0); enable1,enable2: in bit; salida: out std_logic_vector(3 downto 0)); end component; end package; --Declaracin de las entidades library ieee; use ieee.std_logic_1164.all; use work.std_arith.all; use work.uno.all; entity count is port clk,reset: in bit; conta: buffer std_logic_vector(1 downto 0)); end count; architecture archicount of count is begin contador: process (clk,reset) begin if (reset='1') then conta <= (others => '0') ; elsif clk'event and clk='1' then conta <= conta + 1; end if; end process contador; end archicount; --Declaracin de las arquitecturas --Descripcion del decodificador 3/8 (74ls138) library ieee; use ieee.std_logic_1164.all; use work.uno.all; entity decoder is port seleccion: in std_logic_vector(1 downto 0);

enable1,enable2: in bit; salida: out std_logic_vector(3 downto 0)); end decoder; --Descripcin del decodificador architecture archidecoder of decoder is begin decodificador: process(seleccion,enable1,enable2) begin if enable2='1' then salida<=(others=>'0'); elsif enable2='0' and enable1='0' then salida<=(others => '0'); elsif(enable1='1') then case seleccion is when "00" => salida <= "0001"; when "01" => salida <= "0010"; when "10" => salida <= "0100"; when "11" => salida <= "1000"; when others => salida <="1111"; end case; end if; end process decodificador; end archidecoder;
Para poder hacer uso, de cualquier componente del package "uno" (el decodificador o el contador), es necesario que primero se incluya la sentencia:

use work.uno.all;

4. Librera LPM (Library of Parametrized Modules)


La LPM fue propuesta en 1990 como una extensin del estndar Electronic Design Interface Format (EDIF) para permitir al diseador crear un circuito completo con independencia de la arquitectura, separando las partes fsicas y lgicas del diseo Cada componente en la librera esta definido por unos parmetros, que le permiten al diseador de hardware representar una amplia variedad de variables lgicas, evitando la repeticin del trabajo. Un diseo basado en la utilizacin de la librera LPM (library of parametrized modules) combina simultneamente, los aspectos propios de un diseo en alto nivel, con las mejoras propias de la sntesis en bajo nivel. Debido a que los componentes descritos en esta librera son aceptados por lo fabricantes, su consumo de los recurso internos viene previamente optimizado. La librera LPM System Library, en la cual se nos ofrecen mltiples mdulos, ya creados, puede facilitarnos enormemente nuestro trabajo, ya que incluye desde el generador de constantes ms sencillo hasta contadores y multiplicadores con todas las caractersticas opcionales posibles. La lista de componentes incluida en esta es la siguiente: Nombre del paquete Nombre del componente

MCCSTNT MINV MAND MOR MXOR MBUSTRI MMUX MDECODE MADD_SUB MCOMPARE MMULT MCOUNTER MLATCH MFF MSHFTREG

Mdulo de constantes Mdulo de inversores Mdulo de AND's Mdulo de OR's Mdulo de XOR's Mdulo de bus triestado Mdulo de multiplexores Mdulo de decodificador Mdulo de sumadores/restadores Mdulo de comparadores Mdulo de multiplicadores Mdulo de contadores Mdulo de latches Mdulo de flip-flops Mdulo de registros

Para usar cualquiera de stos mdulos, solamente deberemos incluir en nuestro fichero de cdigo la siguiente lnea, encima de la declaracin de entidades y de arquitecturas: use work.lpmpkg.all; Como ejemplo crearemos un multiplicador de 4 bits ( a y b), cuyo resultado, obviamente, debe ser de 8 bits ( p), y que nos permite adems sumarle otro nmero de ocho bits ( s) al resultado. Para ello deberemos invocar previamente a la librera lpmpkg tal y como habamos dicho: library ieee; use ieee.std_logic_1164.all; use work.lpmpkg.all; entity multi_lpm is port( a,b: in std_logic_vector(3 downto 0); s: in std_logic_vector(7 downto 0); p: out std_logic_vector(7 downto 0) ); end multi_lpm; use work.lpmpkg.all; architecture archimulti of multi_lpm is begin a0: mmult generic map(4,4,8,8) port map(a,b,s,p); end archimulti;

Llamamos a lpmpkg Vamos a multiplicar a y b Y vamos a sumar s El resultado es p

Llamamos a lpmpkg

Usamos el mdulo Mult.

En este ejemplo hemos hecho uso del mdulo mmult, el cual nos exige no slo introducirle las seales con las cuales operar (con la sentencia port map) sino tambin su dimensin (sentencia generic map). Como cada mdulo tiene unas especificaciones de entradas, salida y dimensiones distintas, tendremos que consultar el manual de la librera lpmpkg para conocer que entradas y salidas necesita cada mdulo. Podemos acceder a esta documentacin siguiendo estos pasos:

Conseguir el programa WARP2 Release 4.2, disponible online en la pgina de Cypress Semiconductor Inc. No es necesario si ya est instalado en el subdirectorio c:\WARP en el ordenador donde ests leyendo estas lneas. Si no lo tienes, instalado en esa direccin. Descargar el programa gratuito Acrobat Reader 3.01 y sus plug-ins. Puedes acceder a l en Internet o en el CD-ROM de donde ha sido instalado ste libro electrnico. No es necesario si ya lo tienes instalado. Una vez realizado estos pasos, aparecer debajo de estas lneas la documentacin sobre la librera lpmpkg, en el captulo 5 del documento. Si no te aparece pulsa c:\warp\doc\refmanl.pdf

Leccin No 3 Objetos, tipos de datos y operaciones


1. Objetos
En un lenguaje de descripcin de software (SDL) una variable contiene un valor y puede aceptar un nuevo valor a travs de una asignacin secuencial. Por otro lado, las constantes tienen valores prefijados a lo largo de toda la ejecucin del programa. Sin embargo, en VHDL se hace necesaria la utilizacin de un nuevo tipo de

objeto que puede emular las asignaciones concurrentes propias de los circuitos elctricos reales; este nuevo tipo de objeto son las seales. Un objeto en VHDL es un elemento que tiene asignado un valor de un tipo determinado. Segn sea el tipo de dato, el objeto poseer un conjunto de operaciones que se le podrn aplicar. En general, no ser posible realizar operaciones entre dos objetos de distinto tipo, a menos que definamos previamente un programa de conversin de tipos.

2. Identificadores
Los identificadores son un conjunto de caracteres dispuestos de una forma adecuada y siguiendo unas normas propias del lenguaje, para dar un nombre a los elementos en VHDL, por lo que es aconsejable elegir un nombre que sea representativo y que facilite la comprensin del cdigo. Las reglas a tener en cuenta a la hora de elegir un identificador son: Los identificadores deben empezar con un carcter alfabtico, no pudiendo terminar con un carcter subrayado, ni tener dos o ms de estos caracteres subrayados seguidos. VHDL identifica indistintamente tanto las maysculas como las minsculas, pudindose emplear por igual el identificador "sumador" o "SUMADOR". El tamao o extensin del identificador no est fijado por VHDL, siendo recomendable que el usuario elija un tamao que confiera sentido y significado al identificador, sin llegar a alcanzar longitudes excesivamente largas. Los identificadores pueden contener caracteres numricos del '0' al '9', sin que stos puedan aparecer al principio. No puede usarse como identificador una palabra reservada por VHDL.

2. Palabras reservadas
Las palabras reservadas son un conjunto de identificadores que tienen un significado especfico en VHDL. Estas palabras son empleadas dentro del lenguaje a la hora de realizar un diseo. Por esta razn y buscando obtener claridad en el lenguaje, las palabras reservadas no pueden ser empleadas como identificadores definidos por el usuario. Las palabras reservadas por VHDL son: Abs Access Alter Alias All And Architecture Array Asser Attribute Begin Block Else Elsif End Entity Exit File For Function Generate Generis Guarded If Nand New Next Nor Not Null Of On Open Or Others Out return select severity signal subtype then to transoprt type units until use

Body Buffer Bus Case Component Configuration Constant Disconnect Downto

In Inout Is Label Library Linkage Loop Map Mod

Package Port Procedure Process Range Record Register Rem Report

variable wait when while with xor

4. Smbolos especiales
Adems de las palabras reservadas empleadas como identificadores predefinidos, VHDL utiliza algunos smbolos especiales con funciones diferentes y especficas, tales como el smbolo "+" se utiliza para representar la operacin suma y, en este caso, es un operador. El smbolo "- -" es empleado para los comentarios realizados por el usuario, de tal forma que el programa al encontrar una instruccin precedida por "- -" la saltar ignorando su contenido. De esta forma, el programador puede hacer ms comprensible el cdigo del programa. Los smbolos especiales en VHDL son: + - / ( ) . , : ; & ' < > = | # <= => := -Para finalizar, recordar que el smbolo ms empleado por un programador es el ; ", smbolo que debe finalizar todas y cada una de las lneas del cdigo dando por terminada dicha sentencia en el programa.

5. Tipos de datos
El tipo de datos es un elemento bsico en VHDL, ya que delimita que valores puede tener un objeto y que operaciones podemos realizar con l. Aparte de los tipos ya creados, podemos crear nuevos tipos y subconjuntos de tipos. La declaracin de un tipo de datos es la sentencia VHDL utilizada para introducir un nuevo tipo. Esta declaracin est formada por un identificador que nos permitir usar el nuevo tipo al llamarlo y la descripcin del conjunto de valores que forman el tipo de datos. Para ello usamos la palabra reservada type. La declaracin puede tener varios formatos como por ejemplo: type longitud_maxima is range 2 to 50 type estados is (estado_a, estado_b, estado_c); Una vez declarado el nuevo tipo podremos usarlo para declarar objetos de este tipo, como por ejemplo:

variable est: estados; port (entrada: in estados; salida: out longitud_maxima); Cada tipo es diferente e incompatible con los dems, aunque estn declarados de la misma forma, por lo cual no podemos asignar a una seal de un tipo otra de otro tipo distinto, a menos que definamos una funcin de transformacin.

Los tipos pueden ser clasificados segn las caractersticas de lo que van a determinar: Tipos enumerados: En ste se define el conjunto de posibles valores del tipo especificado, presentando una lista que contiene a todos los valores. El primer identificador es el nombre del tipo y sirve para referenciarlo, y entre parntesis y separados por comas se adjuntan todos los valores legales del tipo.

type vocales ('a', 'e', 'i', 'o', 'u'); type direcciones is (izquierda, derecha, arriba, abajo, centro); Si no est especificado ningn valor inicial, el objeto se inicializa con el valor ms a la izquierda de los especificados en la declaracin del tipo. Es decir, un objeto del tipo "vocales" toma el valor 'a' por defecto. Tipos enteros / reales: Esta modalidad de tipo sirve para definir un objeto con valores reales y enteros. En VHDL vienen definidos el tipo integer, que puede ir desde -2147483647 hasta 2147483647, y el tipo real, que puede ir desde -1.0e38 hasta 1.0e38. Para definir un tipo de esta naturaleza hay que especificar el rango de valores que puede llegar a tener asignado un objeto, como en los ejemplos siguientes

type edad is range 0 to 150; type dias is range 31 downto 0; Si no est especificado ningn valor inicial, el objeto se inicializa con el valor ms a la izquierda de los especificados en la declaracin del tipo. Deberemos tener cuidado si hemos usado la palabra to o la palabra downto para definir el tipo, ya que se asignar un valor por defecto u otro. En el ejemplo se da por defecto a un objeto del tipo "edad" el valor 0, y a otro del tipo "das", el valor 31. Tipos fsicos: Sirven para representar magnitudes del mundo real como el tiempo, peso, capacidad, por lo que llevan, aparte de un literal numrico, la magnitud fsica a medir. Podemos asignar unidades auxiliares a la predefinida.

type time is range 0 to 1e20; units fs; ps = 1000 fs; ns = 1000 ps; us = 1000 ns; ms = 1000 us; sec = 1000 ms; min = 60 sec; hr = 60 min; end units; Si no est especificado ningn valor inicial, el objeto se inicializa con el valor ms a la izquierda de los especificados en la declaracin del tipo. Deberemos tener cuidado si hemos usado la palabra to o la palabra downto para definir el tipo, ya que se asignar un valor por defecto u otro. En el ejemplo se da por defecto a un objeto del tipo "edad" el valor 0, y a otro del tipo "dias", el valor 31.

6. Expresiones y operadores

La metodologa de programacin de un componente, basada en la descripcin por comportamiento (behavioral), puede emplear en su diseo la mayora de operadores que se encuentran habitualmente tiles en los SDL's (software design languages) En el cuadro adjunto se puede ver una relacin de los operadores predefinidos ms empleados en VHDL, as mismo se aprecia que su clasificacin atiende al tipo de dato que vaya a manejar: OPERADORES LGICOS OPERADORES RELACIONALES OPERADORES ARITMTICOS OPERADOR CONCADENACIN NOT, AND, OR, NAND, NOR, XOR = / < <= > >= Tipo de resultado: boolean + * / MOD, REM, ABS & ** Tipo de operador: integer, real, signal tipo de resultado: integer, real, signal Tipo de operador: array tipo de resultado: array Tipo de operador: boolean Tipo de resultado: boolean Tipo de operador: cualquier tipo

Los operadores lgicos, pueden ser empleados con los tipos predefinidos, BIT y BOOLEAN, dndonos como resultado un valor booleano del mismo tipo que los operadores. Para graficar un poco la importancia de emplear correctamente los distintos tipos de operadores, a continuacin lo ilustramos con la ayuda del diseo de un sumador de cuatro bits ms el carry de la etapa anterior.

En este ejemplo se aprecia una concatenacin del elemento "a" (que previamente debe de haber sido definido architecture archisumador of sumador is como un std_logic_vector), con un "0", begin dndonos como resultado un array en el process (a,b,cin) variable aux:std_logic_vector (4 downto 0); que la primera posicin la ocupa el "0" y begin despus va el elemento "a" aux:=('0' & a) + ('0' & b); if cin='1' then aux:=aux+1; elsif cin = '0' then null; end if; sum<=aux; Este mismo ejemplo nos servir para end process; graficar la utilizacin del operador suma "+", end archisumador; que lo empleamos para incrementar a la variable aux, en caso de que cin valga uno.

Los operadores relacionales tambin nos generaran un resultado de tipo booleano sin importar el tipo de operando con el que lo empleemos, como nota comentar que el operador "diferente que" viene dado por la combinacin " /= ". Los operandos de tipo aritmticos estn en la obligacin de ser empleados con elementos del mismo tipo y de devolver un resultado que a su vez este contenido en el mismo tipo que los operandos. EL signo "+", "-" dar como resultado sumas de unidades es decir que al elemento sumado le aade uno, (como se aprecia en el anterior ejemplo).

El operador concatenacin es empleado para concadenar arrays de bits, como muestra se grfica este operador con el siguiente ejemplo. aux:=('0' & a) Los elementos a concadenar deben de ser del mismo tipo. Este tipo de operador es muy empleado a la hora de trabajar con buses o registros. El resultado que nos devuelve este operador es un array de los elementos de los operandos concatenados. En nuestro ejemplo, si "a" es un array de cuatro bits, la variable "aux", pasara a tener en su primera posicin el valor "0" y a continuacin tendr el valor de los elementos de "a", de forma que "aux" pasa a tener dimensin cinco.

7. Atributos de los vectores


Un atributo nos proporciona informacin sobre ciertos elementos como las entidades, arquitecturas, tipos y seales. Hay varios atributos para seales que son muy tiles en sntesis, y especialmente en el VHDL simulable (no sintetizable). ???Ai ae trabaja con VHDL sintetizable slo se pueden utilizar algunos atributos como: Atributo 'left: se usa para manejar al elemento ms a la izquierda de un vector. Si el elemento ms a la izquierda de entrada es '0', entonces if entrada 'left ='0' then ... se ejecuta lo que sigue al then Atributo 'right: se usa para manejar al elemento ms a la derecha de un vector. if entrada'right='1' then ... Si el elemento ms a la derecha de entrada es '1', entonces se ejecuta lo que sigue al then Atributo 'length: se usa para manejar la longitud de un vector. Si la longitud de entrada (se supone, lgicamente, que es un array o vector) es 5, entonces se ejecuta lo que sigue al then. Atributo 'event: se usa para conocer si una variable ha cambiado o no, solindose usar como variable booleana: Si hay un cambio en el nivel lgico de la seal entrada, entonces se ejecuta lo que sigue al then.

if entrada'lenght=5 then ...

if entrada event=5 then ...

Leccin No 4 Gramtica del lenguaje I


1. Sentencias secuenciales
En la mayora de los lenguajes de descripcin de software, todas las sentencias de asignamiento son de naturaleza secuencial. Esto significa que la ejecucin del programa se llevara a cabo de arriba a abajo, es decir siguiendo el orden en el que se hayan dispuesto dichas sentencias en el programa, por ello es de vital importancia la disposicin de las mismas dentro del cdigo fuente.

VHDL lleva a cabo las asignaciones a seales dentro del cuerpo de un proceso (process) de forma secuencial, con lo que el orden en el que aparezcan las distintas asignaciones ser el tenido en cuenta a la hora de la compilacin. Esto hace que cuando utilicemos modelos secuenciales en VHDL, estos se comporten de forma parecida a cualquier otro lenguaje de programacin como Pascal, C, etc.

2. Asignacin a una seal


Podremos asignar un cierto valor a una seal siempre que sta haya sido declarada en la entidad en el apartado de declaracin de puertos, o bien porque la hayamos creado especficamente dentro de un process. La asignacin a una seal dentro de un proceso es siempre secuencial, es decir, la seal no cambia su valor hasta que se ha evaluado el proceso en el cual se incluye. Si no est dentro de un proceso, como por ejemplo, usando el estilo dataflow, el cambio es concurrente, es decir, la asignacin est siempre activa, y se actualiza instantneamente. Para hacer una asignacin a una seal deberemos usar el operador <=, estando la seal a asignar a la izquierda y el valor que debe tomar a la derecha. signal <= signal1 + signal2; Las seales son el objeto ms usado dentro de la sntesis de diseos, teniendo la particularidad de que los cambios en una seal son programados, no son inmediatos. Esto resulta extrao, sobre todo si comparamos su comportamiento con el de las variables, y para dejar claro este concepto veamos el siguiente ejemplo: Process Begin a <= b; b <= a; wait on a,b; end process;

La seal a tendr el valor b La seal b tendr el valor a Se acualizan los cambios AQU

En este ejemplo, las dos seales intercambian sus valores, ya que cuando se ejecuta la segunda ( b<=a), el valor de la seal a no ha cambiado todava aunque est la sentencia a<=b, ya que ninguna seal cambia de valor hasta que se hayan evaluado todas las rdenes de un proceso, y es en ese momento cuando a y b toman el valor que se les ha indicado tomar.

3. Asignacin a variable
La asignacin a una variable viene totalmente influenciada por su propia naturaleza, la cual hace que slo tengan su campo de accin en un proceso o un subprograma (reas secuenciales). Una variable no retiene sus valores dentro de un subprograma despus de cada llamada, soliendo usarse como ndices para ciclos loop y para asignaciones inmediatas. Si queremos usar una variable fuera de un proceso, deberemos asignar su valor a una seal, y operar con la seal fuera. Para hacer el asignamiento a una variable deberemos usar el operador: =, como se muestra en los ejemplos siguientes. A diferencia de las seales, el asignamiento de un valor a un variable, no tiene un retardo asociado, de manera que la variable toma el nuevo valor justo en el momento de la asignacin, de forma que las sentencias que vengan a continuacin, la variable recin asignada, tendr el nuevo valor. De esta forma, el ejemplo expuesto para seales, al ser usado para variables, no conseguimos el mismo resultado: a := b; b := a; a toma el valor b b toma el NUEVO valor de a (el de b)

En esta ocasin, no se intercambiarn los valores de ambas seales, sino que acabarn con el valor inicial de la variable b. Para conseguir que se intercambien las variables, deberemos usar una variable temporal de la siguiente forma: temp := a; a := b; b := temp; temp toma el valor de a a toma el valor de b b toma el valor de temp (que era a)

Deberemos tener en cuenta que una variable se reinicializa siempre al hacer una nueva llamada a un subprograma.

4. Sentencia if
La construccin if-then-else es usada para seleccionar un conjunto de sentencias para ser ejecutadas segn la evaluacin de una condicin o conjunto de condiciones, cuyo resultado debe ser o true o false. Su estructura es la siguiente: if (condicin) then haz una cosa; else haz otra cosa diferente; end if; Si la condicin entre parntesis es verdadera, la(s) sentencia(s) secuencial(es) seguidas a la palabra then son ejecutadas. Si la condicin entre parntesis es falsa, la(s) sentencia(s) secuencial(es) seguidas a la palabra else son ejecutadas. La construccin debe ser cerrada con las palabras end if. La sentencia if-then-else puede ser expandida para incluir la sentencia elsif, la cual nos permite incluir una segunda condicin si no se ha cumplido la primera (la cual tiene prioridad). Su estructura es la siguiente: if (condicin) then haz una cosa; elsif (otra condicin) then haz otra cosa diferente; else haz otra totalmente diferente; end if; Si se da la situacin en la cual la primera condicin es verdad ejecuta las sentencias que van despus del primer then. Si no es verdadera la primera condicin, se pasa a evaluar la segunda, y de ser esta verdad, ejecuta las sentencias que estn a continuacin del segundo then. Si ninguna de las dos es verdadera, se ejecuta lo que est detrs de la palabra else. Ntese que para que se ejecute las sentencias con el nombre "otra cosas diferente", no solo debe ser la segunda condicin verdadera, sino que adems la primera condicin debe ser falsa. Un ejemplo de esta sentencia se puede ver a continuacin:

entity multi is port( a, b, c :in bit_vector(3 downto 0); enable :in bit; control :in bit_vector(1 downto 0); d :out bit_vector(3 downto 0) ); end multi;
architecture archmul of multi is begin process (a, b, c, control, enable) begin if enable='1' then d<="1111"; elsif enable='0' then case control is when "00" => d <= a; when "01" => d <= b; when "10" => d <= c; when "11" => d <= "1111"; end case; end if; end process; end archmul;

entidad del multiplexor puertos del multiplexor

finaliza la entidad
arquitectura del multiplexor

si enable es 1 entonces d="1111" si enable no es 1 y es 0 entonces sentencia case dentro del if

se cierra la sentencia case se cierra la sentencia if con end finaliza la arquitectura

Deberemos tener cuidado al usar una sentencia if-then-else ya que podemos caer en el error de la memoria implcita. Si no incluimos la palabra else, y si no se cumple la primera condicin, las seales de salida no cambian, reteniendo el valor previo a la sentencia if. Esto puede ayudarnos (flip-flops) o bien hacer que un diseo sea totalmente errneo. Analicmoslo con un ejemplo: if (clk'event and clk='1') then q <= d; end if; Si hay un flanco de subida en la seal clk, entonces q toma el valor de d.

En este caso se dice que debe ejecutarse si hay un flanco de subida en la seal clk, pero no se dice nada si no hay cambios o si el flanco es de bajada. Es en este caso se ha definido una memoria implcita, y VHDL hace que la seal q siga con el valor que tena antes de ejecutarse la sentencia if. Esto hace que este cdigo y el que se lista a continuacin sean equivalentes:

if (clk'event and clk='1') then


q <= d;

else
q <= q;

Si hay un flanco de subisda en la seal clk, entonces q toma el valor de d, si no es as, q sigue manteniendo su valor.

end if;
Esto hace que se recomiende siempre el especificar con else que debe pasar con las seales si no se cumpla la condicin indicada con el if. En la parte prctica hay varios ejemplos con la sentencia if, pulsa aqu para ir a la parte prctica. Para evitar la inclusin de memoria implcitas se recomienda especificar siempre el comportamiento del circuito en aquellos casos en los que no se cumple la condicin de una sentencia if, o de una sentencia case.

5. Sentencia case

La sentencia case es usada para especificar una serie de acciones segn el valor dado de una seal de seleccin. Esta sentencia es equivalente a la sentencia with-select-when, con la salvedad que la sentencia que nos ocupa es secuencial, no combinacional. La estructura es la siguiente: case (seal a evaluar) is when (valor 1) => haz una cosa; when (valor 2) => haz otra cosa; ... when (ltimo valor) => haz tal cosa; end case; En el caso que la seal a evaluar (situada despus del case) tenga el "valor 1", entonces se ejecuta "una cosa", si tiene el "valor 2", se ejecuta "otra cosa", ... y si tiene el "ltimo valor", se ejecuta "tal cosa". Esta sentencia parece hecha a la medida para crear multiplexores, como se ve en el siguiente ejemplo, del cual slo estudiamos la parte correspondiente a la sentencia case: entity multi is port( a, b, c :in bit_vector(3 downto 0); enable :in bit; control :in bit_vector(1 downto 0); d :out bit_vector(3 downto 0) ); end architecture archmul of multi is begin process (a, b, c, control, enable) begin if enable='1' then d<="1111"; elsif enable='0' then case control is when "00" => d <= a; when "01" => d <= b; when "10" => d <= c; when "11" => d <= "1111"; end case; end if; end process; end archmul; Entidad del multiplexor puertos del

multiplexor

multi; finaliza la entidad arquitectura del multiplexor

sentencia if que contiene al case se evala la seal control si control vale "00" entonces d<=a si control vale "01" entonces d<=b si control vale "10" entonces d<=c si control vale "11" d valdr "1111" se cierra la sentencia case con end se cierra la sentencia if finaliza la arquitectura

Esta sentencia es muy tpica de los lenguajes de programacin y cuenta adems con una variante, muy importante en VHDL, como es dar un valor especificado a la cierta seal si no se contemplan todos los casos posibles de la seal a evaluar. Para ello se usa la palabra reservada others, que aparece en el siguiente fragmento de cdigo: case when "00" when "01" when "10" when others end case; control is se evala la seal control => d <= a; si control vale "00" entonces d<=a => d <= b; si control vale "01" entonces d<=b => d <= c; si control vale "10" entonces d<=c => d <= "1111"; si control no toma ningn valor de los especificados antes, toma el valor "1111" finaliza la arquitectura

Al igual que era recomendable especificar un else dentro de cada if, se recomienda, con ms razn el uso de others dentro de un case aunque en un principio parezca que estn especificados todos los valores posibles, ya que algunos tipos soportan ms valores aparte del nivel uno y cero lgico, como el estado Z o de alta impedancia. Pulsa aqu para ir a la prctica del multiplexor. La sentencia case tambin nos permite especificar un rango de valores posibles de la seal de seleccin, para los cuales hacer una asignacin, mediante la palabra reservada to. Como ejemplo veamos dos fragmentos de cdigo que son equivalentes: case when "000" when "001" when "010" when "011" when "100" when "101" when "110" when "111" when others end case; control => d => d => d => d => d => d => d => d => d is a; a; case a; when "000" to b; when "011" to b; when "111" b; when others b; end case; c; null;

<= <= <= <= <= <= <= <= <=

control "010" "110" =>

=> => => d

d d d <=

<= <= <=

is a; b; c; null;

6. Sentencia loop
La sentencia loop (ciclo en castellano) se usa para ejecutar un grupo de sentencias un nmero determinado de veces, y consiste tanto en un ciclo for como en un ciclo while. La sentencia for se ejecuta un nmero especfico de iteraciones basado en el valor de una variable. La sentencia while continuar ejecutando una operacin mientras una condicin de control local sea cierta. Estas sentencias son muy tpicas de los lenguajes ms usuales de programacin, usndose habitualmente para ello la variable i. A continuacin se listan sendos ejemplos para cada caso: process begin ciclo1: for i in 7 downto 0 loop entrada(i) <= ( others => '0' ) end loop; end process; (a) Cabecera del ciclo Instrucciones a ejecutar 8 veces Finalizacin del ciclo

Este fragmento de cdigo hace que uno por uno los 8 ltimos bits de la seal entrada tengan el valor lgico cero. Que se indique que deben hacerse cero 8 bits, no quiere decir que la seal entrada est formada por ms de ocho. El encabezamiento de la sentencia nos dice que se va a repetir ocho veces seguidas las instrucciones entre loop y end loop. Debemos destacar que en un ciclo for, la variable del mismo se declara automticamente, y no tenemos que incrementarla o inicializarla, ya que el programa lo hace por nosotros. La etiqueta ciclo1 se usa (aunque es opcional) para dar ms posibilidades de organizacin al programador. process (a) variable i: integer := 0; begin ciclo2: while i < 7 loop entrada(i) <= (others => '0'); i := i + 1; end loop;

Mientras i sea menor que 7 => ciclo Finaliza el ciclo

end process; En esta ocasin se usa la sentencia while, para lograr el mismo resultado que en el ejemplo anterior, es decir, inicializar los 8 ltimos bits del vector entrada a cero. Esta vez, se ejecutan las lneas entre loop y end loop mientras la variable i sea menor que siete. Es lgico que esta variable cambie dentro del ciclo, ya que de no ser as, se ejecutara para siempre. De forma distinta al ejemplo anterior, la variable del ciclo while debe ser declarada (como integer), inicializada e incrementada por nosotros, por lo que requiere ms trabajo.

7. Sentencia exit
Usada siempre dentro de un loop, la sentencia exit nos permite salir del mismo si se alcanza una condicin fijada por nosotros. Su verdadera utilidad la encontramos si diseamos controladores de memoria. A continuacin analizamos un ejemplo: process (a) begin ciclo1: for i in 7 downto 0 loop if a'length < i then exit ciclo1; entrada(i) <= ( others => '0' ); end loop; end process; Ahora se ejecuta el mismo ejemplo que expusimos en el caso de un ciclo for con la salvedad que si la variable i supera la longitud del vector a el ciclo deja de ejecutarse aunque no se hayan cumplido las veces pedidas en el encabezamiento.

8. Sentencia next
La sentencia next tambin debe estar dentro de un ciclo loop, y nos sirve para saltarnos una o ms de las ejecuciones programadas. process (a) begin ciclo1: for i in 7 downto 0 loop if i=4 then next; else entrada(i) <= ( others => '0' ); end if; end loop; end process;

Cabecera del ciclo Si i vale 4, se salta el ciclo Si no vale 4,... ... se inicializa entrada Finaliza el ciclo

Ahora se ejecuta el programa todas las veces programadas, excepto la cuarta, ya que hay una sentencia if que hace que se pase a la siguiente iteracin si la variable i vale cuatro.

9. Sentencia null
La sentencia null se utiliza, al igual que en otros lenguajes de programacin, para que dada una condicin especial no pase nada, es decir, que ninguna seal o variable cambie, y que el programa siga su curso habitual. Su comportamiento dentro de un loop es similar al de la sentencia next.

10. Sentencia wait

La sentencia wait se usa para suspender un proceso si ste no tiene lista sensitiva. Lo nico que exige esta sentencia es estar situada la final del proceso. Para entender mejor esto, basta con decir que los dos cdigos siguientes son equivalentes. process (a,b,c) begin x <= a and b and c; end process; Process Begin x <= a and b and c; wait on a,b,c; end process;

Ambos procesos se ejecutarn cuando haya un cambio en la seal a, b o c se muestra en este caso la equivalencia de una lista sensitiva y una sentencia wait explcita.

11. Sentencia wait until


No debemos confundir la sentencia wait until con la sentencia wait vista en el apartado anterior. En esta ocasin, tampoco se puede usar una lsita sensitiva con el proceso, ya que sta queda definida con la misma sentencia. Para las descripciones la frmula wait until debe estar al principio del proceso, por lo que la lgica descrita de esta manera no puede ser reseteada asincrnicamente. Veamos su uso en el caso de la arquitectura de un flip-flop d: architecture ejemplo of ffd is begin process begin wait until (clk='1'); q <= d; end process; end ejemplo; Este proceso se suspende hasta que la condicin siguiente a wait until es verdadera. Una vez que es verdad, y las asignaciones de seal se han realizado, el proceso vuelve a esperar hasta que la seal clk vuelve a valer de nuevo 1, es decir, un flanco de subida. Pulsa aqu para ir a la prctica del Flip Flop D.

Leccin No 5 Gramtica del lenguaje II


1. Sentencias concurrentes
La naturaleza propia de los circuitos elctricos obliga a VHDL a soportar un nuevo tipo de asignacin de seales, que nos permita implementar este tipo de operatividad. En ella todas las asignaciones se llevan a cabo en paralelo (al mismo tiempo). En una asignacin concurrente la seal que est a la izquierda de la asignacin es evaluada siempre que alguna de las seales de la derecha modifique su valor. Como ejemplo tenemos las siguientes sentencias de asignacin:

c <= a and b; s <= a xor b;

Si las seales de entrada (situadas a la derecha), a o b, cambian su valor, las seales de salida (situadas a la izquierda), c y s, son evaluadas, de forma que su valor se ver modificado si fuese necesario

2. Sentencia Process
La sentencia process es una de las construcciones tpicas de VHDL usadas para agrupar algoritmos. Esta sentencia se inicia (de forma opcional) con una etiqueta seguida de dos puntos ( : ), despus la palabra reservada process y una lista de variables sensibles. La lista sensible, indica que seales harn que se ejecuta el proceso, es decir, qu variable(s) debe(n) cambiar para que se ejecute el proceso. Dentro de un proceso se encuentran sentencias secuenciales, no concurrentes. Esto hace que el orden de las rdenes dentro de un proceso sea importante, ya que se ejecuta una despus de otra, y los posibles cambios que deba haber en las seales alteradas se producen despus de evaluar todo el ciclo al completo. Esta caracterstica define una de las particularidades de VHDL. La estructura de un proceso es la siguiente:

etiqueta: process (var1, var2, ...) begin sentencias secuenciales end process etiqueta;

Si cambia alguna de las variables situadas entre los parntesis, se ejecuta el proceso.

Siempre que queramos utilizar sentencias secuenciales se deber usar un proceso. Como ejemplo del uso de un proceso se muestra el siguiente fragmento de cdigo correspondiente a un flip-flop d. contador: process (clock) begin if (clock'event and clk='1') then q <= d; end if, end process contador;

Si hay un cambio en la seal clock (reloj), se ejecuta el process que contiene una sentencia if. Una vez acabado de evaluar todas las sentencias del proceso, se cambian todas las seales necesarias a la vez.

Es muy importante tener en cuenta dos cosas a la hora de usar un proceso respecto a las seales y las variables. La primera es que las variables toman instantneamente el valor especificado y que slo tienen sentido de existencia dentro de un proceso. La segunda es que las seales cambian su valor solamente al llegar al final del proceso. Esto se aprecia claramente en los dos ejemplos siguientes, cuyo comportamiento se pretende que sea el siguiente (suponiendo que hemos cargado el operador +): Si a tiene el valor "0000", entonces la salida/entrada b deber incrementar su valor en una unidad, y si despus e haber incrementado la seal b, sta vale "0001", c deber valer '1', si no es as deber valer '0'. architecture no_funciona of uno is Si hay un cambio en la seal de entrada a, entonces

begin process (a) begin if a = "0000" then b <= b + 1; end if; if b = "0001" then c <= '1'; else c <='0'; end process; end no_funciona;

se ejecuta el proceso: b se incrementa cuando se acabe de ejecutar el proceso (manteniendo el valor actual hasta el end del mismo) si a vale "1111" c vale '1' si b tiene el valor "0001"

El primer ejemplo no funciona adecuadamente si b tiene le valor inicial de "0000". Veamos porqu: si y a cambia para tomar el valor "0000", b se incrementar en una unidad al finalizar la evaluacin del proceso, por lo que b no valdr "0001" hasta entonces, por lo que c no valdr '1', que no era lo que desebamos. architecture funciona of uno is begin process (a) variable v: bit_vector(3 downto 0); begin v:=b; if a = "0000" then v := v + '1'; end if; if v = "0001" then c <= '1'; else c <='0'; b <= v; end process; end funciona;

Si hay un cambio en la seal de entrada a, entonces se ejecuta el proceso: v toma instantneamente el valor de b v se incrementa instantneamente si a vale "1111" c vale '1' si v tiene el valor "0001" b toma el valor de v

El segundo ejemplo si que funciona como habamos especificado para cualquier valor de b. Si a cambia y toma el valor "0000", la variable v toma instantneamente el valor inicial de b (esto es "0000"), y se incrementar en una unidad instantneamente por lo que valdr "0001". Entonces c tomar el nivel lgico alto, y seguido a esto, b tomar el valor incrementado de v. Los nuevos valores de b y c aparecern a la salida al acabar la evaluacin completa del proceso.

3. Asignacin concurrente a seal


En un apartado anterior vimos como era la asignacin secuencial a una seal. Pero las asignaciones a seales tambin pueden ser concurrentes. La principal forma de sta asignacin es que no se encuentra en los procesos o subprogramas, sino en las arquitecturas. La sintaxis de asignacin tiene la misma forma que si fuese secuencial, es decir, usando el operador <=.

4. Asignacin concurrente condicional


Esta asignacin es equivalente a la sentencia if, con la salvedad que es concurrente. La sintaxis a seguir es la siguiente: seal_uno <= seal_dos when condicion else seal_tres; En este caso, a seal_uno se le asigna el valor de seal_dos si se cumple lo especificado en condicin, y en caso de no cumplirse, se le asigna el valor de seal_tres. Un ejemplo muy tpico para el asignamiento concurrente condicional es el de un multiplexor. Los dos listados siguientes tienen la misma operatividad: salida <= entrada1 when control='1' process(control,entrada1,entrada2)

else entrada2;

begin if control='1' then salida<=entrada1; else salida<=entrada2; end if; end process;

La ltima asignacin tambin puede llevar condicin (slo a partir de la norma de 1993).

5. Asignacin concurrente con seleccin


Es la forma compacta y concurrente de la sentencia case, la cual tiene la siguiente sintaxis: with expresion select seal1 <= seal2 when valor_expresin_1, seal3 when valor_expresin_2; Es muy importante notar que no se incluye el punto y coma ( ;) habitual ms que al final de la sentencia, ya que de otra forma sera incorrecto. La sentencia asigna a seal1 el valor de seal2 si se da que expresion toma el valor valor_expresin_1, toma el valor seal3 si expresion toma el valor valor_expresin_2,... pudindose ampliar esta cadena de condiciones tanto como queramos. Como ejemplo veamos los siguientes fragmentos de cdigo, ambos equivalentes, que modelan a una simple Unidad Lgica: process(a, b, operacion) begin case operacin is when "00" => resul <= a and b; when "01" => resul <= a or b; when "10" => resul <= a xor b; when "11" => resul <= not(a and b); end case; end process;

with operacion select resul <= a and b when "00", a or b when "01", a xor b when "10", not (a and b) "11";

En ambos fragmentos de cdigo se realiza la operacin and a las seales a y b siendo el resultado asignado a resul si operacion vale "00", se realiza la operacin or si operacin vale "01", etc. La diferencia entre ambas rutinas es que la izquierda es concurrente y la de la derecha es secuencial.

6. Llamada concurrente a subprograma


La llamada a una funcin o a un procedimiento (los dos tipos existentes de subprogramas) la podemos encontrar tanto en una arquitectura como dentro de un proceso, teniendo en ambos casos la misma apariencia. La que nos ocupa ahora es la primera, que es la concurrente, la cual se ejecuta si cualquiera de los parmetros de entrada cambia. Debemos tener en cuenta que las funciones que vayamos a usar deben ser visibles para el compilador, es decir, que la librera que las contenga debe estar declarada correctamente. La sintaxis general es la siguiente: nombre_de_la_funcin (entradas, salidas);

Al subprograma llamado nombre_de_la_funcin se le introduce el objeto entradas y sacamos el objeto salidas. Los objetos de entrada y salida no tienen porque ser del mismo tipo, ya que dentro del subprograma puede haber cambiado.

7. Sentencias estructurales
Las sentencias estructurales (o de instantacin), son una forma ms de hacer llamadas a subprogramas en VHDL. Con ellas se puede hacer uso de un componente o circuito definido con anterioridad sin necesidad de incluirlo en la descripcin que se est realizando; slo habr que hacer una llamda a dicho componente para usarlo con las especificaciones propias del diseo actual. Se aprecia que su operatividad es muy similar a la de una librera. El lenguaje nos proporciona una serie de sentencias dedicadas a la descripcin de la estructura de hardware que son concurrentes, y aparecen en la arquitectura llamando a un modelo fuera de cualquier proceso. Estas son las sentencias estructurales, cuyo principal elemento son los componentes con su funcin port map (mapa de puertos). Componentes: Para realizar la descripcin estructural de un sistema es necesario conocer qu sistemas o componentes lo forman, indicando la interconexiones entre ellos. Para operar de esta forma, VHDL ofrece los componentes. Para ser usado, un componente debe estar declarado previamente para poder hacer referencia al mismo. Si se declara un componente en una arquitectura, podr ser usado en cualquier parte de la misma, pero si a referencia se hace en un paquete, se podr lamar en todas las arquitecturas que llamen a ese paquete. El estilo estructural es fcilmente reconocible porque la operatividad del programa no se puede leer del cdigo ya que est formado ntegramente por componentes y las seales que les unen a otros. Es decir, est formado por bloques o cajas negras a los cuales metemos informacin y sacamos las salidas, las cuales podrn o no ir a otros bloques. Para esto debemos conocer la operatividad de estos bloques, los cuales suelen estar en libreras. Para usar las puertas que estn en el paquete gatespkg debemos primero invocar a la librera ieee (lase "i e cubo") como est expuesto en la primera lnea de la entidad que debemos usar. Para usar el paquete (o sublibrera) gatespkg la llamaremos de la forma en que est en la segunda lnea. Estas libreras vienen incluidas en la versin 3.5 del programa WARP, de Cypress Semiconductor. Como ejemplo se lista el cdigo de un multiplexor implementado por descripcin estructural.

library ieee; use work.gatespkg.all; entity multi is port( a,b : in bit; control : in bit; enable : in bit; c : out bit ); end multi; architecture archmul of multi is signal aux0,aux1,aux2,aux3: bit; begin

Llamamos a la librera IEEE Llamamos a la librera que tiene las puertas lgicas

Cabecera del programa Declaracin de seales Empieza el programa

puerta0:inv port map(control,aux0); puerta1:and2 port map(b,aux0,aux1); puerta2:and2 port map(a,control,aux2); puerta3:or2 port map(aux1,aux2,aux3); puerta4:and2 port map(enable,aux3,c); end archmul;

Sentencia concurrente Sentencia concurrente Sentencia concurrente Sentencia concurrente Sentencia concurrente Finalizamos el programa

La funcionalidad de este fragmento de cdigo se basa en los elementos "inv", "and2" y "or2", que se encuentran en la librera gatespkg, que listamos a continuacin:

package gatespkg is component and2 port ( a,b : in bit; q : out bit); end component; component or2 port ( a,b : in bit; q : out bit); end component; component inv port ( a : in bit; qn : out bit); end component; use work.cypress.all; entity and2 is port ( a,b : in bit; q : out bit); end and2; architecture archand2 of and2 is begin q <= (a and b); end archand2; use work.cypress.all; entity or2 is port ( a,b : in bit; q : out bit); end or2; architecture archor2 of or2 is begin q <= (a or b); end archor2;

Incluimos el nombre del paquete Empezamos el componente and2

Empezamos el componente or2

Empezamos el componente inv

Empezamos la entidad and2

Empezamos la entidad or2

use work.cypress.all; entity inv is port ( a : in bit; qn : out bit); end inv; architecture archinv of inv is begin qn <= not (a); end archinv;

Empezamos la entidad inv

8. Subprogramas
Los subprogramas se usan para describir algoritmos de cualquier tipo que son ms tarde usados tantas veces como se desee. Un subprograma consta de una parte declarativa en la cual se definen los datos de entrada y de salida al mismo, y una parte de sentencias en la cual se indica que operaciones se realizan sobre los datos. Los subprogramas constan de dos partes: la definicin del subprograma y la definicin del cuerpo del subprograma. En la primera se define el nombre del mismo y los parmetros que son introducidos en l. En la segunda se incluye el algoritmo que va a realizar el subprograma. Hay dos tipos de subprogramas, las funciones y los procedimientos, los cuales tratamos en puntos separados a ste.

9. Funciones
Las funciones estn destinadas a realizar clculos, siendo una nueva forma de definir nuevos operadores que pueden aparecer en una expresin. A las funciones se le pueden introducir todos los valores que se necesiten, pero slo devuelven un nico valor, siendo las variables internas a ella imposibles de recuperar para otras operaciones. Una funcin est formada por: Parte declarativa: En ella indicamos cuales son los parmetros que introducimos en la funcin, la cual entender que son constantes, y de modo in (por defecto). Podemos definir, adems, todas las estructuras de datos que necesitemos (tipos, constantes, variables,...), pero slo existirn cuando la funcin haya sido llamada y se crean e inicializan cada vez que esto ocurra. Esta es la razn de no poder incluir seales en la parte declarativa. Parte de sentencias: En ella se transforman los objetos que introducimos en la funcin para obtener la salida. En esta parte podremos usar el valor de seales y variables externas, pero no podremos modificarlas. Tampoco podremos usar la sentencia wait. Como ejemplo crearemos una funcin que realiza una operacin tan sencilla como asignar a la salida de la funcin, suma, la suma de dos nmeros, a y b. La parte declarativa sera: function sumar (a,b: std_logic_vector(3 downto 0))

return std_logic_vector(3 downto 0); Empieza por la palabra reservada function y seguido va el nombre de la funcin y entre parntesis los objetos de entrada con su tipo correspondiente. Despus va la palabra return y el tipo del resultado de la funcin. Tiene el mismo sentido que las entidades. La parte de sentencias sera: function sumar (a,b: std_logic_vector(3 downto 0)) return std_logic_vector(3 downto 0) is variable suma: std_logic_vector begin suma := a + b ; return suma end function sumar; Las primeras lneas de la parte de sentencias coinciden con la parte declarativa, slo que la primera lleva al final la palabra is, tal y como se aprecia en el ejemplo. Seguido viene la declaracin de tipos, subtipos y variables, etc. en la cual debe incluirse la variable que va a ser devuelta por la funcin, que en este caso es suma. Entre la palabra reservada begin y end debemos incluir el algoritmo que dar un valor a la variable que ser el resultado, y la sentencia return suma. Esta ltima sentencia es imprescindible para definir la funcin, ya que de no hacerlo sta se quedara sin resultado. Para llamar a esta funcin deberemos escribir un cdigo parecido a este en nuestro programa, teniendo en cuenta que la llamada a una funcin no es por si misma una sentencia: Process variable numero1, numero2: std_logic_vector(3 downto 0); variable salida: std_logic_vector(3 downto 0); begin ... salida := sumar (numero1,numero2); ... end process; En esta ocasin hemos hecho la asignacin de las entradas por posicin: al ejecutarse la funcin, el compilador usa el valor de numero1 como a, ya que numero1 es el primer valor que se introduce en la funcin y a es el primero incluido en la declaracin de la funcin. Lo mismo ocurre con numero2 y con b. Tambin podamos haber hecho el asignamiento por nombre de cualquiera de las siguientes formas, siendo ambas equivalentes: salida := sumar ( numero1=>a, numero2=>b ); salida := sumar ( numero2=>b, numero1=>a ); Sea cual sea la forma en la cual asignemos las seales a la entrada del subprograma, stas deben coincidir en el tipo, es decir, en el ejemplo no podamos haber introducido en la funcin numero1 y numero2 si stos hubieran sido del tipo entero o bit. De la misma forma la variable o la seal a la cual asignamos el valor de la funcin debe coincidir con el tipo del objeto que hemos especificado para la salida en la funcin. Es decir, no podemos asignar a salida el valor de la funcin que hemos creado si es del tipo integer (por ejemplo), ya que la salida de la funcin es suma que es del tipo std_logic_vector.

10. Procedimientos

Los procedimientos estn destinados a realizar alteraciones en los datos a los que tienen acceso, tanto internos como externos. De forma distinta a las funciones, un procedimiento puede devolvernos ms de un valor e incluso modificar alguno de los valores que le introducimos. Un procedimiento o procedure consta al igual que las funciones de una parte declarativa y otra de sentencias:

Parte declarativa: En ella indicamos cuales son los parmetros que introducimos en la procedure, pudiendo ser de tres modos posibles: in, out, e inout, y son por defecto del modo in. Si el modo de una seal de entrada es in, no podremos modificar su valor, solamente usarlo, y a ojos de la procedure ser una constante. Si el modo es out podrn ser modificados en la parte de sentencias, pero al igual que pasa en una entidad no podremos leer su valor. Solamente si es de modo inout podremos leer su valor y adems modificarlo. Al igual que en las funciones podremos declarar todos los tipos, constantes, variables, etc. pero slo existirn cuando se haga un llamamiento a la procedure y se reinicializarn cada vez que se vuelva a llamar. Parte de sentencias: En ella se modifican seales y variables tanto internas como externas al procedure, pudiendo adems usar la sentencia wait.

Para aclarar conceptos, se muestra el siguiente cdigo, en el cual se consigue el mismo resultado que en el ejemplo expuesto en el apartado de funciones. La parte declarativa es la siguiente: procedure sumar (a,b: std_logic_vector(3 downto 0), suma: out std_logic_vector(3 downto 0)); Su estructura se asemeja a la de una entidad y empieza con la palabra reservada procedure seguida del nombre que le vamos a asignar a la misma (en este caso es sumar), y entre parntesis se declaran los objetos de entrada como si de una entidad se tratase. En los procedimientos no hace falta usar la palabra return, ya que se especifica cul de las seales es de entrada y/o salida. La parte de declaraciones sera como sigue: procedure sumar (a,b: std_logic_vector(3 downto 0), suma: out std_logic_vector(3 downto 0)); begin suma <= a + b ; end procedure sumar; La primera parte consiste en repetir la parte declarativa y seguidamente, el subprograma con sus algoritmos correspondientes. Una vez definido el procedimiento podremos usarlo en cualquier parte del programa ya sea secuencial o combinacional como por ejemplo: Process variable numero1, numero2: std_logic_vector(3 downto 0); variable salida: std_logic_vector(3 downto 0); begin ... sumar (numero1,numero2,salida); ... end process; Al igual que en una funcin, los tipos de los objetos de entrada y salida a una funcin deben coincidir con los declarados en el procedimiento. Es importante notar que una llamada a una procedure es una sentencia, no como una llamada a una funcin.

En este caso hemos hecho la asignacin por posicin, ya que al no indicar nada, el compilador supone que queremos asignar el primer objeto que hemos introducido en la funcin al primer objeto que habamos declarado cuando creamos el procedimiento. Esto es numero1 se corresponde a a, numero2 se corresponde con b, y as sucesivamente. Si queremos asignarlos por nombre deberemos hacerlo como se describe a continuacin: sumar ( numero1=>a, numero2=>b, salida =>suma ); sumar ( salida=> suma, numero2=>b, numero1=>a ); Ambas formas de llamar al procedimiento son vlidas y equivalentes.

Leccin No 6 Interface, compilador e implementacin fsica


1. VHDL sintetizable
En un principo VHDL, al igual que los dems HDL'S, nacieron con el proposito de facilitar la labor de los diseadores de circuitos electrnicos, agilizando su diseo y haciendo ms flexible su posterior depuracin y mantenimiento. Por este motivo se dot a VHDL con abundantes instrucciones ms orientadas a la simulacin que a la implementacin fsica del diseo. Ello trajo consigo la diferenciacion del VHDL sintetizable del simulable, siendo este ltimo el ms extendido y el que cuenta con ms herramientas en los programas. Si trabajamos con VHDL sintetizable, slo podremos hacer uso de un conjunto de instrucciones vlidas.

El lenguaje nos permite describir circuitos complejos manejando todas las sentencias y herramientas de las que dispone, pero no siempre se garantiza que se pueda llegar a grabar en un dispositivo de lgica programable (PLD), ya que ciertas instrucciones no tienen equivalente fsico. Como conclusin, se puede decir que todo el cdigo de un programa en VHDL es simulable, pero no siempre ser sintetizable.

2. Galaxy de Cypress
Dado que el VHDL es el lenguaje estndar, todas las empresas fabricantes de PLDs y FPGAs (Cypress, Xilinx, Altera, Actel, etc.) han desarrollado su propio compilador cada uno con sus propias funciones y caractersticas especiales. Este turorial ha sido realizado basndose en el programa Warp2, del cual se muestran varias ventanas cortesa de la compaa Cypress Semiconductor. A pesar de ser un producto no muy pensado de cara al usuario, la herramienta de Cypress es tan potente como las dems, contando adems con un gran soporte tcnico va e-mail. El nombre de la herramienta se llama WARP 2, que actualmente va por su versin 4.3. Este conjunto de programas est orientado a la creacin de un fichero propio de VHDL (*.vhd), para compilarlo (Galaxy) y posteriormente simularlo (Nova). Para conseguir este software se puede solicitar por correo ordinario o electrnico en la pgina web de Cypress. El programa Galaxy es el ncleo de la suite WARP2, ya que nos gestiona los programas creados, nos permite editarlos y elegir distintas opciones de compilacin. Su pantalla principal es la siguiente:

Con este programa podremos describir un circuito en VHDL, compilarlo y simularlo, sin ms que usar el men adecuado. Al arrancar por primera vez el programa, nos aparecer una pantalla que nos gestionar el control de un proyecto, entendindose por proyecto la creacin de una serie de PLDs concernientes al mismo trabajo o tema. Deberemos introducir en este cuadro de dilogo, la ruta y nombre del proyecto, segn nuestras preferencias, y aadirle la extensin wpr:

En este caso hemos creado un proyecto llamado "proyecto.wpr" en la ruta "c:\warp\proyecto". Una vez hecho esto pasamos a la ventana principal del programa. Si queremos crear un nuevo fichero para compilar, deberemos llamar al editor de texto, para lo que deberemos pulsar el botn llamado selected o el botn llamdo new, en la parte de edit, segn querramos modificar un fichero ya creado o bien hacer uno nuevo, respectivamente. Entonces se nos abrir una ventana similar a la siguiente:

En esta ventana crearemos o modificaremos el cdigo fuente de VHDL segn lo que queramos realizar. Este editor tiene una serie de guas para ayudarnos a programar, por si se nos olvida la sintaxis. Una vez escrito todo el cdigo del programa, lo deberemos guardar, con extensin vhd, en el mismo subdirectorio en el cual hemos creado el fichero de extensin wpr (en este caso es c:\warp\proyecto) para que pueda ser compilado sin ningn problema por el programa. Si queremos crear una librera nueva para este proyecto, deberemos especificarla despus de haber creado el fichero de extensin wpr. Para ello deberemos ir al comando files/libraries y crear una nueva si as lo deseamos. Una vez creada la librera, deberemos decir al programa qu queremos compilar, para lo cual deberemos ir al men files/add y seleccionar el fichero que queramos compilar. Una vez hecho esto, aparecer el nombre de dicho fichero en la parte izquierda de la ventana, debajo del men de comandos. Antes de pulsar los botones que nos compilarn el programa creado, deberemos seleccionar qu tipo de PLD vamos a usar, el tipo de optimizacin, etc. Esta tarea la realizamos con los botones de la parte inferior del programa: file, set top, generic y device. El botn file nos servir para decirle al programa que queremos usar la librera por defecto (es lo ms habitual) o si queremos usar un creada. Su aspecto es el siguiente:

El botn set top sirve para indicar cual de los ficheros a compilar es el principal, del cual cuelgan los dems ficheros. El botn generic nos lleva al men que nos permitir elegir ciertas opciones como si deseamos optimizar la velocidad o el rea usada del dispositivo de lgica programable. El aspecto del men es el siguiente:

El botn device nos permitir elegir el tipo de PLD que usaremos para grabar nuestro diseo, que hacer con las salidas no usadas, que tipo de FlipFlops queremos usar, etc. El aspecto del men es el siguiente:

Una vez hechas todas estas operaciones habremos dejado todo preparado para empezar a compilar.

Pulsando en los botones selected o smart, de la parte compile, podremos compilar uno o ms ficheros de VHDL simultneamente. Una vez pulsado cualquiera de los botones de compilacin, nos aparecer una pantalla con las incidencias de la misma, incluyendo las libreras usadas, fecha, hora, errores, etc. Desde esta pantalla podremos acceder a las lneas del cdigo errneas directamente y modificarlas para solucionar el problema, lo cual es una gran ayuda para eliminar errores de nuestros programas. En esta ventana apreciamos la forma de trabajar interna del programa, ya que nos dice el nombre de los programas que van verificando el fichero en busca de errores, y como se va transformando el cdigo original en un fichero que nos permitir grabarlo en una PLD. Dicha pantalla tiene el aspecto siguiente:

Si en la barra de estados de la ventana de compilacin aparece la leyenda "Compilation successful" (como aparece en la figura), querr decir que la compilacin ha tenido xito y que el fichero de vectores JEDEC, de extensin jed, necesario para la grabacin de las PLDs ha sido creado correctamente. Una vez compilado el programa, llamaremos al programa simulador de ficheros de VHDL compilados (de extensin jed), llamado Nova, pulsando en el men "Tools/Nova", tal y como se aprecia en al siguiente figura:

3. Nova de Cypress
El programa Nova es el complemento a Galaxy, ya que nos va a simular los ficheros compilados previamente. Su aspecto es similar a un analizador lgico, y le podremos introducir las entradas que queramos para ver si las salidas que vayamos a obtener son las correctas. Su aspecto es el siguiente:

Para simular un fichero jed (de vectores JEDEC) deberemos primero abrirlo con el comando "file/open". Lo siguiente que nos aparece es un cronograma con las entradas y las salidas que admitir la PLD. Nosotros podremos introducir las entradas y darle la forma que queramos (nivel lgico alto o bajo, que sea un reloj, que tenga un pulso,...) segn lo que deseemos, sin ms que acceder al men "edit". Una vez modificada la forma de las entradas, y accediendo al comando "execute" del men "simulate", el programa nos ofrecer en rojo las salidas que hubiramos obtenido de haber grabado la PLD con este fichero.

Haciendo doble clic en la pare inferior de la ventana nos aparecer una lnea de gua para poder seguir mejor el resultado de la simulacin. Tambin nos permite el organizar las entradas y salidas en forma de bus para controlar mejor los resultados. Esto es muy til si estamos manejando entradas y/o salidas de varios bits de anchura y necesitamos saber su valor en todo momento. Un ejemplo de cmo es til la creacin de un bus se muestra en las siguientes imgenes, donde, en la superior no se usa un bus y en la inferior donde s se usa. En ambas hemos introducido la misma entrada aleatoria y queremos saber el resultado de al simulacin para las salidas en el instante 50ns. En el primer caso, sin bus, deberemos analizar cual es el valor de cada uno de los bits de salida, e interpretarlo para ver que es "111", o bien, "7".

Si hemos creado un bus, como en la siguiente imagen. El resultado de los bits de salida los va marcando el programa sin ms que desplazar la gua hasta el instante deseado, para ver que la salida es "00x7". Para crear un bus hay que ejecutar el comando edit/create bus, y seleccionar que seales queremos que formen parte del bus.

Una vez que hayamos dado este paso, estaremos preparados para grabar nuestra PLD en las mquinas dispuestas a tal efecto.

4. Grabacin de nuestros diseos Para poder implementar las descripciones realizadas en VHDL en un dispositivo de lgica programable, se necesita un programador de PLD's y el software de que nos grabar el circuito usando el fichero compilado por Warp (de extensin jed). Como ejemplo usaremos el software y la mquina de Advantech Lab Tool, del cual se muestra a continuacin la pantalla principal.

Para comenzar, se debe indicar al grabador el tipo de dispositivo en el cual vamos a programar nuestro diseo. Esto se lleva a cabo pulsando el botn select de la barra de herramientas del Lab Tool. Una vez hecho esto, aparecer un cuadro de dilogo en el cual se pide al usuario que elija el tipo de dispositivo a utilizar (tipo, marca y modelo), como se muestra en la imagen.

Una vez seleccionado el dispositivo es conveniente comprobar que el mismo est en blanco (sin usar), pulsando el botn blank . En el caso de que el PLD no estuviera vaco, deberemos borrarlo (si se nos permite) usando el botn erase . Una vez que se haya seleccionado el tipo de encapsulado y lo hemos verificado, se indica al software grabador qu queremos implementar en el dispositivo elegido. Para esta tarea deberemos indicar mediante un cuadro de dialogo estndar de Windows el fichero deseado, como se aprecia a continuacin.

Cuando se haya elegido el encapsulado y el fichero a programar, con tan slo pulsar el botn prog se grabar la PLD de forma automtica, y habremos concluido el proceso, ya que el mismo programa, despus de grabar el dispositivo, lo verifica.