Programación en VHDL/Elementos básicos del lenguaje
Antes de comenzar es preciso conocer algunos elementos básicos del lenguaje VHDL.
Comentarios
[editar]Los comentarios van precedidos de dos guiones. En una línea se ignorará todo aquello que vaya después de dos guiones seguidos. Ejemplo:
-- Esto es un comentario
Identificadores
[editar]Son cualquier cadena de caracteres que sirven para identificar variables, señales, procesos, etc. Puede ser cualquier nombre compuesto por letras (aux) o números y letras (aux1, aux2, aux3, ...), incluyendo el símbolo de subrayado "_". Las mayúsculas y minúsculas son consideradas iguales, por lo tanto los identificadores TMP y tmp representan el mismo elemento. No es posible crear un identificador que coincida con alguna palabra reservada del lenguaje.
Números
[editar]Cualquier número se representa en base 10. Aunque es posible poner los números en otras bases utilizando diferentes símbolos, como se muestra en la siguiente sección.
Bases
[editar]Para escribir un número se puede hacer en binario, octal, decimal y hexadecimal.
- Para vectores de bits:
- "01111" binario
- O"17" octal
- X"F" hexadecimal
- Para enteros y reales:
- 2#1100# binario
- 12 decimal
- 16#C# hexadecimal
l
Tipos de datos
[editar]Como en cualquier lenguaje de programación existen varios tipos de datos, en VHDL se pueden diferenciar dos: escalares y compuestos.
Tipos escalares
[editar]Son tipos simples que contienen algún tipo de magnitud.
- Enteros: Son datos con un valor numérico entero. La forma de definirlos es con la palabra RANGE. Realmente se dice que un número está en un límite establecido.
TYPE byte IS RANGE 0 TO 255;
- Físicos: Se trata de datos que corresponden con magnitudes físicas, que tienen un valor y unas unidades.
TYPE longitud IS RANGE 0 TO 1.0e9
UNITS
um;
mm=1000 um;
m=1000 mm;
in=25.4 mm;
END UNITS;
- Reales o coma flotante: Se definen igual que los enteros con la diferencia que los límites son números reales.
TYPE nivel IS RANGE 0.0 TO 5.0
- Enumerados: Son datos que puede tomar siempre que se encuentre en una lista o conjunto finito. Es idéntico a las enumeraciones en C (enum).
TYPE color IS (ROJO, VERDE, AMARILLO);
Tipos compuestos
[editar]Son tipos de datos compuestos por los que se han visto anteriormente.
- Matrices: Se trata de un conjunto de elementos del mismo tipo, accesibles mediante un índice. Los hay de dos tipos: monodimensionales o multidimensionales.
TYPE word IS ARRAY (31 DOWNTO 0) OF bit;
TYPE tabla IS ARRAY (1 TO 4, 1 TO 4) OF real;
En este punto es necesario explicar la palabra reservada OTHERS, donde es posible asignar un determinado valor a todos los elementos de la matriz.
word <= (OTHERS => '0'); -- Asigna '0' en todas las posiciones
Las palabras reservadas TO y DOWNTO sirven para indicar los índices de una matriz. El primero indica un rango ascendente (de x a y), mientras que el segundo es descendente (desde x hasta y).
-- word1 y word2 son elementos idénticos
TYPE word1 IS ARRAY (31 DOWNTO 0) OF bit;
TYPE word2 IS ARRAY (0 TO 31) OF bit;
Dependiendo de la opción elegida el bit más significativo corresponderá al primer bit (0) o al último (31). También es posible obtener un trozo de una matriz para poder realizar operaciones con ella.
TYPE word IS ARRAY (31 DOWNTO 0) OF bit;
TYPE subword IS ARRAY (7 DOWNTO 0) OF bit;
...
subword <= word(31 DOWNTO 24);
Además, es posible asignar a una matriz una lista separada por comas, de forma que el primer elemento de la lista corresponde al primero de la matriz.
semaforo <= (apagado, apagado, encendido);
luces <= (apagado, verde, azul, ..., amarillo);
- Registros: Es equivalente al tipo record de otros lenguajes.
TYPE trabajador IS
RECORD
nombre : string;
edad : integer;
END RECORD;
Para acceder a algún atributo del registro se utilizará el punto.
trabajadorA.nombre="Juan"
Subtipos de datos
[editar]En VHDL se pueden definir subtipos, los cuales corresponden a tipos ya existentes. Se pueden diferenciar dos tipos dependiendo de las restricciones que se apliquen.
- Restricciones de un tipo escalar a un rango:
SUBTYPE indice IS integer RANGE 0 TO 7;
SUBTYPE digitos IS character RANGE '0' TO '9';
- Restricciones del rango de una matriz:
SUBTYPE id IS string(0 TO 15);
SUBTYPE dir IS bit_vector(31 DOWNTO 0);
La ventaja de utilizar subtipos se basa a la hora de sintetizar un circuito, ya que si se utiliza el propio tipo, como puede ser el integer, se interpretará como un bus de 32 líneas, pero realmente sólo harán falta muchas menos.
Conversión de tipos
[editar]En ocasiones puede ser necesario convertir unos tipos a otros, esta operación es conocida como casting. Algunas de las conversiones son automáticas, como puede ser el paso de entero a real, otras conversiones deben realizarse de forma explícita, indicando el nombre del tipo al que se quiere pasar seguido del valor entre paréntesis.
real(15);
integer(3.5);
En muchos diseños es necesario realizar conversiones entre bits y enteros. A continuación se muestran varias funciones de conversión entre ambos tipos.
conv_integer(std_logic_vector); -- Conversión de vector a entero
conv_std_logic_vector(integer, numero_bits); -- Conversión de entero a vector de numero_bits de tamaño
Constantes, señales y variables
[editar]En VHDL existen tres tipos de elementos: señales, constantes y variables. Estas dos últimas tienen un significado similar a cualquier otro lenguaje de programación.
Todos estos elementos son diferentes. Las variables sólo tienen sentido dentro de los procesos o subprogramas, mientras que las señales pueden ser declaradas en arquitecturas, paquetes o bloques concurrentes. Las constantes pueden ser declaradas en los mismos sitios que las variables y señales.
Constantes
[editar]Es un elemento que se inicializa con un valor determinado, el cual no puede ser modificado, es decir siempre conserva el mismo valor. Esto se realiza con la palabra reservada CONSTANT.
CONSTANT e : real := 2.71828;
CONSTANT retraso : time := 10 ns;
También es posible no asociar un valor a una constante, siempre que el valor sea declarado en otro sitio.
CONSTANT max : natural;
Variables
[editar]Es lo mismo que una constante, pero con la diferencia que puede ser modificada en cualquier instante, aunque también es posible inicializarlas. La palabra reservada VARIABLE es la que permite declarar variables.
VARIABLE contador : natural := 0;
VARIABLE aux : bit_vector(31 DOWNTO 0);
Es posible, dado un elemento cambiarle el nombre o ponerle nombre a una parte mediante la palabra reservada ALIAS.
VARIABLE instruccion : bit_vector(31 DOWNTO 0);
ALIAS cod_op : bit_vector(7 DOWNTO 0) IS instruccion(31 DOWNTO 24);
Señales
[editar]Las señales se declaran con la palabra reservada SIGNAL, a diferencia con las anteriores este tipo de elementos pueden ser de varios tipos: normal, register o bus. Es posible asignarles un valor inicial.
SIGNAL sel : bit := '0';
SIGNAL datos : bit_vector(7 DOWNTO 0);
Atributos
[editar]Los elementos como señales y variables pueden tener atributos, éstos se indican a continuación del nombre, separados con una comilla simple " ' " y pueden incluir información adicional de algunos objetos desarrollados en VHDL, que servirán a las herramientas de diseño para obtener información a la hora de realizar una síntesis.
Existen muchos atributos, como LEFT, RIGHT, LOW, HIGH, RANGE, LENGTH... Pero el atributo más usado es EVENT, que indica si una señal ha cambiado de valor. Por ejemplo la siguiente sentencia captura un flanco de subida de una señal (clk).
....
if clk'event and clk = '1' then
....
Definición de atributos
[editar]Un atributo definido por el diseñador siempre devolverá un valor constante. En primer lugar se debe declarar el atributo, mediante la palabra reservada ATTRIBUTE, indicando el tipo de elemento que se devuelve, seguidos el valor que se retornará. La sintaxís para definir atributos sería la siguiente.
ATTRIBUTE nombre : tipo
ATTRIBUTE nombre OF id_elemento : clase IS valor
Donde nombre es el identificador del atributo, id_elemento corresponde al identificador de un elemento del lenguaje definido previamente (señal, variable, etc.), la clase es el tipo de elemento al que se le va añadir dicho atributo, es decir si es señal, constante, etc. y el valor será lo que devuelva al preguntar por dicho atributo. Un ejemplo de todo esto puede ser el siguiente.
SIGNAL control : std_logic;
ATTRIBUTE min : integer;
ATTRIBUTE min OF control : SIGNAL IS 4;
....
IF control'min > 20 THEN
Operadores
[editar]Los operadores que proporciona el lenguaje son:
- Lógicos: Actúan sobre los tipos bit, bit_vector y boolean. En el caso de utilizar este tipo de operadores en un vector, la operación se realizará bit a bit.
Operadores: AND, OR, NAND, NOR, XOR, XNOR y NOT.
- Aritméticos:
- + (suma o signo positivo): Sirve para indicar una suma entre dos números. También puede actuar como símbolo si se sitúa delante de una expresión.
- - (resta o signo negativo): Sirve para indicar la resta entre dos números. Si va delante de una expresión modifica el signo de la expresión.
- * (multiplicación): Multiplica dos números de cualquier tipo.
- / (división): Divide dos números de cualquier tipo.
- ** (exponencial): Eleva un número a una potencia. El número de la izquierda puede ser entero y real, pero el de la derecha sólo puede ser entero. Ejemplo: 4**2 sería 4².
- ABS() (valor absoluto): Devuelve el valor absoluto de su argumento.
- MOD (módulo): Calcula el módulo de dos números.
- REM (resto): Calcula el resto de la división.
- Relacionales: Siempre devuelven un valor booleano (true o false).
- ==, /= (igualdad): El primero devuelve verdadero si los operando son iguales y falso en caso contrario. El segundo indica desigualdad, funcionando al revés que el anterior.
- >, >=, <, <= (menor mayor): Poseen el significado habitual (mayor que, mayor o igual que, menor que, menor o igual que, respectivamente). La diferencia con los anteriores reside en su uso, en este caso los tipos de datos que pueden manejar son siempre de tipo escalar o matrices.
- Desplazamientos: (incluidas en la revisión de 1993)
- SLL (Shift Left Logic) y SRL (Shift Right Logic), desplazamiento lógico a la izquierda y desplazamiento lógico a la derecha, respectivamente, rellenando de ceros los huecos.
- SLA (Shift Left Arithmetic) y SRA (Shift Right Arithmetic), desplazamiento aritmético a la izquierda y derecha respectivamente.
- ROL (ROtate Left) y ROR (ROtate Right), rotación a la izquierda y a la derecha respectivamente. En este caso los huecos son ocupados por los bits que van quedando fuera.
A continuación se muestran ejemplos sobre los operadores de desplazamiento:
-- Inicialmente a vale 1100 1101
a sll 4 -- El resultado es 1101 0000
a sla 4 -- El resultado es 1101 1111 (extensión del último bit)
a srl 4 -- El resultado es 0000 1100
a sra 4 -- El resultado es 1111 1100
a rol 4 -- El resultado es 1101 1100 (los primeros 4 bits pasan a la última posición)
a ror 4 -- El resultado es 1101 1100
- Otros:
- & (concatenación): Concatena vectores de manera que la dimensión de la matriz resultante es la suma de las dimensiones de las matrices con las que se opera.
Hay que decir que no todos los operadores pueden funcionar sobre todos los tipos de datos. También hay operadores que en determinadas circunstancias no pueden ser utilizados, por ejemplo al hacer código sintetizable no es recomendable usar multiplicadores (excepto si uno de los operadores es potencia de dos, puesto que se trataría de un simple desplazamiento de bits).
El orden de preferencia, de mayor a menor es:
- **, ABS, NOT
- *, /, MOD, REM
- +, - (signo)
- +, -, & (operaciones)
- =, /=, <, <=, >, >=
- AND, OR, NAND, NOR, XOR