Introducción
Un punto de mucha importancia cuando se escribe código VHDL es la escritura en forma parametrizada del mismo. Esto significa usar los distintos atributos e instrucciones de VHDL a fin de evitar hacer uso de referencias fijas las que deberán ser cambiadas si se modifica el tamaño de algún dato o señal del código escrito. Así, las referencias a tamaños de un dato o señal deberían ser expresadas en términos de atributos de VHDL o parámetros definidos por el diseñador.Aspectos Prácticos
Para simplificar los ejemplos comenzaremos con la inicialización de una señal. La asignación de un valor a una señal de tipo arreglo (array) normalmente se hace de la siguiente manera:
data_out <= "00000000";
Si bien esa asignación es correcta, no es la más adecuada si se quiere escribir el código de forma parametrizada. La misma función cumple la siguiente asignación conocida como aggregate:
data_out <= (others => '0');
Que también se puede usar para inicializar a todos ‘1’:
data_out <= (others => '1');
Similarmente se puede escribir:
data_out <= ( 0 => ‘1’, 3 => '1’, others => ‘0’);
Para formar de este modo el dato “00001010”.
Un error común cuando se escribe código parametrizado es que un aggregate no puede ser usado en una expresión y debe usarse con un objeto de tamaño conocido. Así, el siguiente código dará un error el ejecutarse:
signal internal_bus: std_logic_vector(width-1 downto 0);
. . .
output_bus <= x"FF" when (internal_bus=(others=>‘0’)) else . . .
. . .
output_bus <= x"FF" when (internal_bus=(others=>‘0’)) else . . .
En este comparación el tamaño de internal_bus es conocido, pero no el tamaño del dato con quien se esta comparando internal_bus. Para solucionar este problema se usa el atributo ‘range para proveer el tamaño del objeto.
output_bus <= x"FF" when (internal_bus=(internal_bus’range=>’0’)) else . . .
Otro manera de hacer algo similar a lo detallado en el ejemplo anterior, sería mediante el uso de una constante tal como se detalla a continuación:
constant all_zero: std_logic_vector(width-1 downto 0) := (others => ‘0’);
signal internal_bus: std_logic_vector (width-1 downto 0);
. . .
output_bus <= x"FF" when (internal_bus = all_zero) else . . .
signal internal_bus: std_logic_vector (width-1 downto 0);
. . .
output_bus <= x"FF" when (internal_bus = all_zero) else . . .
Una nota con respecto al uso de aggregate, es que cuando se usa en un arreglo compuesto por solo un elemento, la asociación por nombre debe ser usada para especificar el valor. Por ejemplo:
constant valor_ini: std_logic_vector(2 downto 2):= (2=>’’); -- correcto
constant valor_final: std_logic_vector(2 downto 2):= (‘0’); -- incorrecto
constant valor_final: std_logic_vector(2 downto 2):= (‘0’); -- incorrecto
Finalmente quiero recordarles que un aggregate también se usa para asignar valores de señales a otra señal en particular. Ejemplo:
signal a, b, c, d: std_logic;
signal tmp: std_logic_vector(3 downto 0);
.. .
tmp <= (a, b, c, d);
signal tmp: std_logic_vector(3 downto 0);
.. .
tmp <= (a, b, c, d);
De este modo tmp(3) toma el valor de a, tmp(2) el de b, tmp(1) el de c y tmp(0) el de d.
En caso de querer cambiar el orden se lo debe especificar en la asignación, por ejemplo:
tmp <= (3 => c, 2 => a, 1 => d, 0 => b);
Asi, tmp tiene los siguientes vlaores asignados (c, a, d, b).
Tambien se puede expresar un aggregate de la siguiente manera:
tmp <= (3 => ‘1’, 2 | 1 | 0 => ‘0’);
tmp <= (3 => ‘1’, (2 downto 0) => ‘0’);
tmp <= (3=> ’1’, others => ‘0’);
tmp <= (‘1’, ‘0’, ‘0’, ‘0’, ‘0’);
tmp <= (3 => ‘1’, (2 downto 0) => ‘0’);
tmp <= (3=> ’1’, others => ‘0’);
tmp <= (‘1’, ‘0’, ‘0’, ‘0’, ‘0’);
Todas estas ultimas cuatro asignaciones son equivalentes.
No hay comentarios:
Publicar un comentario