VHDL (Very High Speed Integrated Circuit Hardware Description Language) es un lenguaje de descripción de hardware estructurado para modelar sistemas digitales, que vio su origen en el programa VHSIC(Very High Speed Integrated Circuit), VHDL es sólo uno de un conjunto de lenguajes especializados en la descripción de elementos de hardware como ABEL, Verilog, AHDL(Analog Hardware Description Language), entre otros; que se caracterizan por permitir implementar casi cualquier tipo de circuito lógico sin la necesidad de utilizar esquemáticos pues la descripción de los componentes y su comportamiento se hace por medio de instrucciones similares a las de un lenguaje de programación como PASCAL o C. Aún cuando el estándar no coloca ninguna limitación a la complejidad del diseño, no todos los circuitos descritos con VHDL pueden ser traducidos a una implementación física posterior. Este proceso de tomar el código en VHDL y generar los elementos lógicos que efectúan la función deseada se conoce como síntesis. Las descripciones que admiten este proceso se les denomina Sintetizables.
En 1983, IBM, Intermetrics y Texas Instruments empezaron a trabajar en el desarrollo de un lenguaje de diseño que permitiera la estandarización, facilitando con ello, el mantenimiento de los diseños y la depuración de los algoritmos, para ello el IEEE propuso su estándar en 1984.
Esta doble influencia, tanto de la empresa como de la universidad, hizo que el estándar asumido fuera un compromiso intermedio entre los lenguajes que ya habían desarrollado previamente los fabricantes, de manera que éste quedó como ensamblado y por consiguiente un tanto limitado en su facilidad de utilización haciendo dificultosa su total comprensión. Este hecho se ha visto incluso ahondado en su revisión de 1993.
Pero esta deficiencia se ve altamente recompensada por la disponibilidad pública, y la seguridad que le otorga el verse revisada y sometida a mantenimiento por el IEEE.La independencia en la metodología de diseño, su capacidad descriptiva en múltiples dominios y niveles de abstracción, su versatilidad para la descripción de sistemas complejos, su posibilidad de reutilización 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 descripción de hardware por excelencia.
VHDL es un lenguaje de tipos fuertes (strong typing) como el Ada o Pascal. Esto significa que no pueden asignarse valores a señales o variables que no sean del tipo declarado para esa señal o variable. Para poder asignar un tipo diferente, el programador debe llamar explícitamente a una función de conversión de tipo.
Hay cuatro clases de objetos en VHDL: constantes, variables, señales y archivos. El tipo de un objeto es muy importante, ya que no solo define que valores podrá tomar, sino también que operaciones se pueden realizar sobre él.
VHDL fue desarrollado como un lenguaje para el modelado y simulacion logica dirigida por eventos de sistemas digitales, y actualmente se lo utiliza tambien para la sintesis automatica de circuitos. El VHDL fue desarrollado de forma muy parecida al ADA debido a que el ADA fue tambien propuesto como un lenguaje puro pero que tuviera estructuras y elementos sintacticos que permitieran la programacion de cualquier sistema hardware sin limitacion de la arquitectura. El ADA tenia una orientacion hacia sistemas en tiempo real y al hardware en general, por lo que se lo escogio como modelo para desarrollar el VHDL.
- Al estar basado en un estandar (IEEE Std 1076-1987) los ingenieros de toda la industria de diseño pueden usar este lenguaje para minimizar errores de comunicacion y problemas de compatibilidad.
- VHDL permite diseño Top-Down, esto es, permite describir (modelado) el comportamiento de los bloques de alto nivel, analizandolos (simulacion), y rediseñar la funcionalidad de alto nivel requerida antes de llegar a niveles mas bajos de abstraccion de la implementacion del diseño.
VHDL describe estructura y comportamiento.
Existen dos formas de describir un circuito. Por un lado se puede describir un circuito indicando los diferentes componentes que lo forman y su interconexion, de esta manera tenemos especicado un circuito y sabemos como funciona; esta es la forma habitualen que se han venido describiendo circuitos y las herramientas utilizadas para ello han sido las de captura de esquemas y las descripciones netlist.
Comportamiento: VHDL tambien se puede utilizar para la descripcion comportamental o funcional de un circuito. Esto es lo que lo distingue de un lenguaje de Netlist. Sin necesidad de conocer la estructura interna de un circuito es posible describirlo explicando su funcionalidad. Esto es especialmente util en simulacion ya que permite simular un sistema sin conocer su estructura interna, pero este tipo de descripcion se esta volviendo cada dia mas importante porque las actuales herramientas de sintesis permiten la creacion automatica de circuitos a partir de una descripcion de su funcionamiento.
Ejemplo basico de descripcion VHDL
Lo que se va a realizar a continuacion es la descripcion comportamental del circuito de la figura 1, y luego se realizara la descripcion estructural para ver las diferencias. Mas adelante se vera que hay dos tipos de descripcion comportamental, pero de momento, el presente ejemplo unicamente pretende introducir el lenguaje VHDL y su estructura.
ENTITY mux IS
PORT ( a: IN bit;
b: IN bit;
selec: IN bit;
salida: OUT bit);
END mux;
Esta porcion del lenguaje indica que la entidad mux (que es el nombre que se le ha dado al circuito) tiene tres entradas de tipo bit, y una salida tambien del tipo bit. Los tipos de las entradas y salidas se veran mas adelante. El tipo bit simplemente indica una linea que puede tomar los valores '0' y '1'.
La entidad de un circuito es unica, sin embargo, se mostro que un mismo simbolo, en este caso entidad, podria tener varias vistas o en el caso de VHDL arquitecturas. Cada bloque de arquitectura, que es donde se describe el circuito, puede ser una representacion diferente del mismo circuito. Por ejemplo, puede haber una descripcion estructural y otra comportamental, ambas son descripciones diferentes, pero ambas descripciones corresponden al mismo circuito, simbolo, o entidad. Veamos entonces la descripcion comportamental:
ARCHITECTURE comportamental OF mux IS
BEGIN
PROCESS(a,b,selec)
BEGIN
IF (selec='0') THEN
salida<=a;
salida<=b; END IF; END PROCESS; END comportamental;
Elementos sintacticos del VHDL.
El lenguaje VHDL es verdaderamente un lenguaje, por lo que tiene sus elementos sintacticos, sus tipos de datos, y sus estructuras como cualquier otro tipo de lenguaje. El hecho de que sirva para la descripcion hardware lo hace un poco diferente de un lenguaje convencional. Una de estas diferencias es probablemente la posibilidad de ejecutar instrucciones a la vez de forma concurrente. Algunos de estos elementos sintacticos se muestran a continuacion:
Caracteres: Es cualquier letra o caracter entre comillas simples: 'l','3','t'.
Cadenas: Son un conjunto de caracteres englobados por comillas dobles: "Esto es una cadena".
Operadores varios.
& (concatenacion) Concatena matrices de manera que la dimension de la matriz resultante es la suma de las dimensiones de las matrices sobre las que opera:
punto<=x&y mete en la matriz punto la matriz x en las primeras posiciones, y la matriz y en las ultimas.
Operadores aritmeticos.
** (exponencial) Sirve para elevar un numero a una potencia: 4**2 es 42. El operador de la izquierda puede ser entero o real, pero el de la derecha solo puede ser entero.
ABS() (valor absoluto) Como su propio nombre indica esta funcion devuelve el valor absoluto de su argumento que puede ser de cualquier tipo numerico.
/ (division) Tambien funciona con cualquier dato de tipo numerico.
MOD (modulo) Calcula en modulo de dos numeros. Exactamente se define el modulo como la operacion que cumple: a=b*N+(a MOD b) donde N es un entero. Los operandos solo pueden ser enteros. El resultado toma el signo de b.
REM (resto) Calcula el resto de la division entera y se de ne como el operador que cumple: a=(a/b)*b+(a REM b), siendo la division entera. Los operandos solo pueden ser enteros. El resultado toma el signo de a.
+ (suma y signo positivo) Este operador sirve para indicar suma, si va entre dos operandos,
o signo, si va al principio de una expresion. La precedencia es diferente en cada caso. Opera sobre valores numericos de cualquier tipo.
- (resta y signo negativo) Cuando va entre dos operandos se realiza la operacion de sustraccion, y si va delante de una expresion le cambia el signo. Los operandos pueden ser numericos de cualquier tipo.
Operadores de desplazamiento.
SLL, SRL (desplazamiento logico a izquierda y a derecha) Desplaza un vector un numero de bits a izquierda (SLL) o derecha (SRL) rellenando con ceros los huecos libres. Se utiliza en notacion in ja de manera que la señal a la izquierda del operador es el vector que se quiere desplazar y el de la derecha es un valor que indica el numero de bits a desplazar. Por ejemplo dato SLL 2 desplaza a izquierda el vector dato, es decir, lo multiplica por 4.
SLA, SRA (desplazamiento aritmetico a izquierda y derecha)
ROL, ROR (rotacion a izquierda y a derecha) Es como el de desplazamiento pero los huecos son ocupados por los bits que van quedando fuera.
=, /= (igualdad) El primero devuelve TRUE si los operandos son iguales y FALSE en caso contrario. El segundo indica desigualdad, asi que funciona justo al reves.
Los operandos pueden ser de cualquier tipo con la condicion de que sean ambos
del mismo tipo.
<,<=,>,>= (menor mayor) Tienen el signi cado habitual. La diferencia con los anteriores
es que los tipos de datos que pueden manejar son siempre de tipo escalar o
matrices de una sola dimension de tipos discretos.
Son NOT, AND, NAND, OR, NOR y XOR. El funcionamiento es el habitual para este tipo de operadores. Actuan sobre los tipos bit, bit vector y boolean. En el caso de realizarse estas operaciones sobre un vector, la operacion se realiza bit a bit, incluyendo la operacion NOT.
Precedencia de operadores y sobrecarga
La precedencia de operadores se presenta en la siguiente tabla:
** ABS NOT Maxima precedencia
* / MOD REM
+(signo) -(signo)
+ - &
= /= < <= > >=
AND OR NAND NOR XOR Minima precedencia
Se ha visto que, por ejemplo, los operadores logicos solo operaban sobre unos tipos de datos determinados. Existe en VHDL la posibilidad de sobrecargar operadores y funciones, como se vera mas adelante, de manera que es posible extender la aplicacion de estos operadores para que trabajen con otros tipos aparte de los prede nidos. Asi, se podran redefinir los operadores logicos para que pudieran trabajar sobre enteros.
Como en cualquier lenguaje, VHDL tiene dos grupos de tipos de datos. Por un lado estan los escalares, con los que se pueden formar el otro grupo que son los compuestos.
Son tipos simples que contienen algun tipo de magnitud. Veamos a continuacion los tipos escalares presentes en VHDL:
Enteros: Son datos cuyo contenido es un valor numerico entero. La forma es que se definen estos datos es mediante la palabra clave RANGE, es decir, no se dice que un dato es de tipo entero, sino que se dice que un dato esta comprendido en cierto intervalo especi cando los limites del intervalo con valores enteros.
Ejemplos:
TYPE byte IS RANGE 0 TO 255;
TYPE index IS RANGE 7 DOWNTO 1;
TYPE integer IS -2147483647 TO 2147483647; -- Predefinido en el lenguaje
Este ultimo tipo viene ya prede nido en el lenguaje aunque no es muy conveniente su utilizacion, especialmente pensando en la posterior sintesis del circuito.
magnitudes fisicas, es decir, tienen un valor y unas unidades.
UNITS
um;
mm=1000 um;
m=1000 mm;
in=25.4 mm;
END UNITS;
TYPE nivel IS RANGE 0.0 TO 5.0;
TYPE real IS RANGE -1e38 TO 1e38; -- Predefinido en el lenguaje
Ejemplos:
TYPE nivel_logico IS (nose,alto,bajo,Z);
TYPE bit IS ('0','1'); -- Predefinido en el lenguaje
Son tipos de datos que estan compuestos por los tipos de datos escalares vistos anteriormente.
TYPE word IS ARRAY(31 DOWNTO 0) OF bit;
TYPE transformada IS ARRAY(1 TO 4, 1 TO 4) OF real;
TYPE positivo IS ARRAY(byte RANGE 0 TO 127) OF integer;
TYPE string IS ARRAY(positive RANGE <>) OF character; -- Predefinido en VHDL
TYPE bit_vector IS ARRAY(natural RANGE <>) OF bit; -- Predefinido en VHDL
TYPE vector IS ARRAY(integer RANGE <>) OF real;
Este ultimo ejemplo, y los dos anteriores, muestran una matriz cuyo indice no tiene rango sino que sirve cualquier entero. Mas tarde, en la declaracion del dato, se podra poner los limites de la matriz: SIGNAL cosa: vector(1 TO 20);
Los elementos de una matriz se acceden mediante el indice. Asi dato(3) es el elemento 3 del dato. De la misma manera se puede acceder a un rango:
Ejemplo:
TYPE trabajador IS
RECORD
nombre: string;
edad: integer;
END RECORD;
Declaracion de constantes, variables y señales.
Un elemento en VHDL contiene un valor de un tipo especificado. Hay tres tipos de elementos en VHDL, estan las variables, las señales y las constantes. Las variables y constantes son una cosa muy parecida a las variables y constantes que se encuentran en cualquier lenguaje. Las señales, en cambio, son elementos cuyo significado es bastante diferente y es consecuencia directa de que aunque VHDL es un lenguaje muy parecido a los convencionales, no deja en ningun momento de ser un lenguaje de descripcion hardware, por lo que cabe esperar algunas diferencias.
Una constante es un elemento que se inicializa a un determinado valor y no puede ser cambiado una vez inicializado, conservando para siempre su valor. Ejemplos:
CONSTANT retraso: time := 10 ns;
CONSTANT max_size: natural;
En la ultima sentencia, la constante max size no tiene ningun valor asociado. Esto se permite siempre y cuando el valor sea declarado en algun otro sitio. Esto se hace asi para las declaraciones en packages que se veran mas adelante.
Una variable es lo mismo que una constante con la diferencia de que su valor puede ser alterado en cualquier instante. A las variables tambien se les puede asignar un valor inicial.
VARIABLE aux: bit_vector(31 DOWNTO 0);
ALIAS codigo_op: bitvector(7 DOWNTO 0) IS instruccion(31 DOWNTO 24);
Las señales se declaran igual que las constantes y variables con la diferencia de que las señales pueden ademas ser de varios tipos que son normal, register y bus. Por defecto son de tipo normal. Al igual que en variables y constantes, a las señales se les puede dar un valor inicial si se quiere. Ejemplos:
SIGNAL selec: bit := '0';
SIGNAL datos: bit_vector(7 DOWNTO 0) BUS := B"00000000";
Constantes, se~nales y variables
Constantes, señales y variables son cosas diferentes. Las variables, por ejemplo, solo tienen sentido dentro de un proceso (PROCESS) o un subprograma, es decir, solo tienen sentido en entornos de programacion donde las sentencias son ejecutadas en serie, por tanto las variables solo se declaran en los procesos o subprogramas. Las señales pueden ser declaradas unicamente en las arquitecturas, paquetes (PACKAGE), o en los bloques concurrentes (BLOCK). Las constantes pueden ser habitualmente declaradas en los mismos sitios que las variables y señales.
Mientras que las variables son elementos abstractos con poco signi cado fisico, las señales tienen un significado fisico inmediato y es el de representar conexiones reales en el circuito. La señales pueden ser usadas en cualquier parte del programa o descripcion y son declaradas siempre en la parte de arquitectura antes del BEGIN. Esto indica que las señales son visibles por todos los procesos y bloques dentro de una arquitectura, por lo que en realidad representan interconexiones entre bloques dentro de la arquitectura. Desde un punto de vista software, las señales representan el mecanismo que va a permitir ejecutar en paralelo las instrucciones concurrentes, es decir, VHDL implementa el mecanismo de sincronizacion de procesos por monitorizacion para la ejecucion paralela de instrucciones.
En un diseño, las conexiones fisicas entre unos elementos y otros son habitualmente declaradas como señales. Las entradas y salidas, de nidas en la entidad, son, por lo tanto, consideradas señales. Aunque estas entradas y salidas son en realidad señales, hay algunas diferencias; por ejemplo las salidas no se pueden leer, es decir, no pueden formar parte del argumento de una asignacion. De la misma manera, a una entrada no se le puede asignar un valor en la descripcion.
La diferencia principal entre variables y señales es que una asignacion a una variable se realiza de forma inmediata, es decir, la variable toma el valor que se le asigna en el mismo momento de la asignacion. La señal, en cambio, no recibe el valor que se le esta asignando hasta el siguiente paso de simulacion, es decir, cuando el proceso se acaba al encontrar una sentencia WAIT dentro de un proceso sino tiene sentencias de espera. Esta forma extraña en que se les asignan valores a las señales se entendera mejor cuando se explique el signi cado de los procesos, la ejecucion
concurrente y secuencial, y los pasos de simulacion.
Diferencias entre variable y señal.
Hasta ahora, en la ejecucion concurrente, las variables no existan y solo se disponia de las señales. En la ejecucion concurrente no hay mucha diferencia entre lo que es una señal y lo que es una variable normal y corriente en cualquier otro lenguaje. Aparentemente, cuando en la ejecucion concurrente una se~nal recibe un valor, la señal toma inmediatamente este valor. Cuando se explique mas adelante el VHDL para simulacion, se vera que este inmediatamente es en realidad un paso de simulacion, que si no se especifica ningun retraso, implicara que la señal toma ese valor en el momento de la asignacion.
Un bloque de tipo PROCESS es equivalente a una unica instruccion concurrente formada por numerosas instrucciones en serie. Como se trata de una unica instruccion concurrente, todas las instrucciones serie internas ocurren en el mismo paso de simulacion, y no se pasa al siguiente paso de simulacion hasta que se haya completado la ejecucion del PROCESS. Esto quiere decir que dentro de un bloque PROCESS, las señales conservan su valor y no cambian hasta que el bloque termina de ejecutarse, momento en el cual, ya tienen el valor que se les haya asignado durante la ejecucion del proceso debido a que se encontrara en el siguiente paso de simulacion.
Para verlo un poco mas claro se puede decir que una señal es como una caja con dos secciones. Una, que es la seccion que se suele ver, y que es la que contiene el valor actual, y otra, separada, que contiene el valor futuro. Cuando leemos una señal estamos echando mano de la seccion donde se guarda el valor actual. Cuando se le asigna algo a una señal estamos escribiendo en la seccion dedicada al valor futuro. Solo cuando se acaba la ejecucion de la instruccion concurrente, lo que se encuentra en la seccion de valor futuro pasa a la seccion de valor actual.
La declaración de una entidad define la interfaz entre esta y el ambiente en el cual se utiliza. En este sentido, la entidad es una especie de bloque o caja negra que define como se “ve” el componente desde el exterior. La entidad define una serie de puertos que sus terminales visibles, quedando su estructura funcional oculta dentro de una o más arquitecturas.
Declaración de una entidad:
entity Nombre_de_la_entidad is
port ( Nombre_Señal : modo tipo;
Nombre_Señal : modo tipo;
Nombre_Señal : modo tipo);
end Nombre_de_la_entidad;
Los posibles modos de la señal son: in, out , buffer, inout.
- Arquitectura: Es la descripción detallada del comportamiento o estructura interna de un módulo (entidad). En el estándar IEEE 1076-2002, se define “Una arquitectura define el cuerpo de una entidad. Esta especifica las relaciones entre las entradas y las salidas de una entidad, pudiendo ser expresada en términos de estructura, flujo de datos o comportamiento”. La descripción estructural muestra a la entidad y sus componentes internos junto con las conexiones entre estos, siendo bastante similar al proceso de diseño basado en esquemáticos y componentes MSI (Micro-Star International) o SSI discretos. Cuando se utiliza una descripción de comportamiento (funcional), se especifica el algoritmo que describe la operación del circuito en forma bastante similar a un programa. En este caso, existen diferentes procesos que se activan según el estado de las entradas del diseño y en su interior contienen las acciones a ejecutar según sea el requerimiento del circuito. Por su parte, la descripción por medio de flujo de datos, establece una relación directa entre las señales de entrada y las salidas.
La arquitectura de una entidad de mayor nivel, puede hacer uso de entidades de nivel más bajo dentro de la estructura jerárquica, la implementación de cada entidad puede obedecer a cualquiera de las descripciones mencionadas anteriormente, permitiendo que en mismo diseño coexistan diferentes tipos de implementaciones operando en conjunto. De esta manera, los diseños extensos pueden ser fraccionados en varias entidades que residen en diferentes archivos, cada entidad puede ser verificada, simulada y depurada de forma independiente.
- Puertos: Los puertos son los puntos de conexión entre una entidad y el medio exterior. Se caracterizan por tener una representación física relacionada con un terminal de entrada/salida y requerir de una definición de sentido ya sea como entrada, salida o bidireccional.
- Variables: Se utilizan en las funciones, procedimientos y procesos, no tienen significado físico pero son elementos de gran utilidad al momento de efectuar la programación.
- División del diseño principal en módulos separado. La modularidad es uno de los conceptos principales de todo diseño. Normalmente se diferencia entre dos metodologías de diseño: top-down y botton-up.
La metodología botton-up consiste en construir un diseño complejo a partir de módulos, ya diseñados, más simples. En la práctica, un diseño usa generalmente ambas metodologías.
Identificar cada puerta con claridad. Las puertas lógicas y otros elementos tienen generalmente una estructura clara e incluso se pueden utilizar comandos directos que realizan estas funciones. Evitar las sentencias de espera. En algunos sintetizadores quizá sea posible utilizar sentencias de espera WAIT dentro de los procesos, pero no es nada aconsejable puesto que la herramienta puede tener dificultades en interpretar estas sentencias. Es aconsejable en cambio el uso de listas sensibles, y en muchos sintetizadores es casi la única posibilidad. El uso del WAIT está bastante restringido, así, si se usa, algunas herramientas exigen que sea la primera instrucción del PROCESS, y sólo se permite una condición. Cuidado con las listas sensibles. La mayoría de sintetizadores admiten la lista sensible o una sentencia WAIT al principio, pero no siempre la interpretan como lo hará un simulador ya que en determinadas ocasiones el proceso se ejecutará cuando cambia una señal que se encuentra en el proceso pero no en la lista sensible o en el WAIT.
Permitir discrepancia. Normalmente es fácil sintetizar algo simple como s<=NOT s ya que no es más que una puerta inversora conectada sobre si misma que puede servir muy bien para generar una señal de reloj con periodo el doble que el retraso que la puerta presente. Si se intenta simular algo como la instrucción anterior, se comprobará que la simulación se queda colgada en esa instrucción puesto que no hay retrasos y se llama a sí misma una y otra vez. Por lo tanto, en estos casos, aunque la simulación es incorrecta, la síntesis lo es.
Señales de reloj. Normalmente sólo se permite una señal de reloj por proceso, y además debe especificarse claramente el flanco de subida del reloj mediante la condición clk='1' AND clk'EVENT. En general sólo puede ponerse esta condición una vez por proceso y en ningún caso se puede poner ELSE en el IF en el que se usó a condición
Asignaciones únicas. Aunque en simulación es bastante corriente que a una señal se le asignen varios valores a lo largo de un mismo proceso, en síntesis esto resulta difícil de interpretar y no debe usarse (normalmente no se permite).
Evitar IFs anidados. Normalmente las herramientas tienden a no sintetizar de manera óptima varios condicionales anidados entre sí. Los condicionales es mejor utilizarlos a solas.
Utilizar CASE mejor que varios IFs Las estructuras CASE tienen para los sintetizadores un modelo optimizado de síntesis, generalmente mejor que lo mismo descrito mediante IFs.
Utilizar el estilo indicado para las máquinas de estado Muchos de los problemas digitales se pueden resolver de forma sencilla mediante una máquina de estados. En VHDL hay muchos estilos diferentes para poder describir máquinas de estados, entonces a veces ocurre que el sintetizador no se da cuenta de que lo que tiene delante es una máquina de estados y no optimiza bien el circuito resultante. En los manuales de los sintetizadores suelen venir ejemplos de lo que la herramienta entenderá que es una máquina de estados, entonces es mejor utilizar ese estilo aunque no nos resulte cómodo, el resultado final será bastante más óptimo.
Especificar la arquitectura. Es posible que se creen varias descripciones para un mismo circuito. Normalmente el sintetizador cogerá la primera que le parezca, por lo que conviene especificar cuál de todas las arquitecturas se desea sintetizar mediante un bloque de configuración CONFIGURATION.
No hay comentarios:
Publicar un comentario