Buscar..


Observaciones

Antes de VHDL 1993, dos procesos concurrentes solo podían comunicarse con señales. Gracias a la semántica de simulación del lenguaje que actualiza las señales solo entre los pasos de simulación, el resultado de una simulación fue determinista: no dependía del orden elegido por el programador de simulación para ejecutar los procesos.

[De hecho, esto no es 100% cierto. Los procesos también pueden comunicarse utilizando la entrada / salida de archivos. Pero si un diseñador estaba comprometiendo el determinismo mediante el uso de archivos, realmente no podría ser un error.]

El lenguaje era así seguro. Excepto a propósito, fue casi imposible diseñar modelos VHDL no deterministas.

VHDL 1993 introdujo variables compartidas y el diseño de modelos VHDL no deterministas se hizo muy fácil.

VHDL 2000 introdujo los tipos protegidos y la restricción de que las variables compartidas deben ser de tipo protegido.

En VHDL, los tipos protegidos son lo que más se asemeja al concepto de objetos en lenguajes orientados a objetos (OO). Implementan la encapsulación de estructuras de datos y sus métodos. También garantizan el acceso exclusivo y atómico a sus miembros de datos. Esto no evita completamente el no determinismo pero, al menos, agrega exclusividad y atomicidad a las variables compartidas.

Los tipos protegidos son muy útiles cuando se diseñan modelos VHDL de alto nivel diseñados solo para simulación. Tienen varias propiedades muy buenas de idiomas OO. Su uso frecuente hace que el código sea más legible, mantenible y reutilizable.

Notas:

  • Algunas cadenas de herramientas de simulación, de forma predeterminada, solo emiten advertencias cuando una variable compartida no es de un tipo protegido.
  • Algunas herramientas de síntesis no admiten tipos protegidos.
  • Algunas herramientas de síntesis tienen un soporte limitado de variables compartidas.
  • Se podría pensar que las variables compartidas no se pueden usar para modelar hardware y deben reservarse para instrumentación de código sin efectos secundarios. Pero los patrones VHDL recomendados por varios proveedores de EDA para modelar el plano de memoria de memorias de acceso aleatorio (RAM) de múltiples puertos utilizan variables compartidas. Entonces, sí, las variables compartidas pueden ser sintetizables en ciertas circunstancias.

Un generador pseudoaleatorio.

Los generadores peudoaleatorios suelen ser útiles para diseñar entornos de simulación. El siguiente paquete VHDL muestra cómo usar tipos protegidos para diseñar un generador pseudoaleatorio de boolean , bit y bit_vector . Se puede extender fácilmente para generar también std_ulogic_vector aleatorio, signed , unsigned . Extenderlo para generar enteros aleatorios con límites arbitrarios y una distribución uniforme es un poco más complicado pero factible.

La declaración del paquete

Un tipo protegido tiene una declaración donde se declaran todos los accesores públicos de subprogramas. Para nuestro generador aleatorio, haremos público un procedimiento de inicialización de inicialización y tres funciones impuras que devuelven un boolean aleatorio, bit o bit_vector . Tenga en cuenta que las funciones no pueden ser puras, ya que las diferentes llamadas de cualquiera de ellas, con los mismos parámetros, pueden devolver valores diferentes.

-- file rnd_pkg.vhd
package rnd_pkg is
    type rnd_generator is protected
        procedure init(seed: bit_vector);
        impure function get_boolean return boolean;
        impure function get_bit return bit;
        impure function get_bit_vector(size: positive) return bit_vector;
    end protected rnd_generator;
end package rnd_pkg;

El cuerpo del paquete

El cuerpo de tipo protegido define las estructuras de datos internas (miembros) y los cuerpos del subprograma. Nuestro generador aleatorio se basa en un Registro de Cambio de Retroalimentación Lineal (LFSR) de 128 bits con cuatro pulsaciones. La variable de state almacena el estado actual del LFSR. Un procedimiento de throw privado cambia el LFSR cada vez que se usa el generador.

-- file rnd_pkg.vhd
package body rnd_pkg is
    type rnd_generator is protected body
        constant len: positive := 128;
        constant default_seed: bit_vector(1 to len) := X"8bf052e898d987c7c31fc71c1fc063bc";
        type tap_array is array(natural range <>) of positive range 1 to len;
        constant taps: tap_array(0 to 3) := (128, 126, 101, 99);

        variable state: bit_vector(1 to len) := default_seed;

        procedure throw(n: positive := 1) is
            variable tmp: bit;
        begin
            for i in 1 to n loop
                tmp := '1';
                for j in taps'range loop
                    tmp := tmp xnor state(taps(j));
                end loop;
                state := tmp & state(1 to len - 1);
            end loop;
        end procedure throw;

        procedure init(seed: bit_vector) is
            constant n:   natural            := seed'length;
            constant tmp: bit_vector(1 to n) := seed;
            constant m:   natural            := minimum(n, len);
        begin
            state         := (others => '0');
            state(1 to m) := tmp(1 to m);
        end procedure init;

        impure function get_boolean return boolean is
            constant res: boolean := state(len) = '1';
        begin
            throw;
            return res;
        end function get_boolean;

        impure function get_bit return bit is
            constant res: bit := state(len);
        begin
            throw;
            return res;
        end function get_bit;

        impure function get_bit_vector(size: positive) return bit_vector is
            variable res: bit_vector(1 to size);
        begin
            if size <= len then
                res := state(len + 1 - size to len);
                throw(size);
            else
                res(1 to len) := state;
                throw(len);
                res(len + 1 to size) := get_bit_vector(size - len);
            end if;
            return res;
        end function get_bit_vector;
    end protected body rnd_generator;
end package body rnd_pkg;

El generador aleatorio se puede usar en un estilo OO como en:

-- file rnd_sim.vhd
use std.env.all;
use std.textio.all;
use work.rnd_pkg.all;

entity rnd_sim is
end entity rnd_sim;

architecture sim of rnd_sim is
    shared variable rnd: rnd_generator;
begin
    process
        variable l: line;
    begin
        rnd.init(X"fe39_3d9f_24bb_5bdc_a7d0_2572_cbff_0117");
        for i in 1 to 10 loop
            write(l, rnd.get_boolean);
            write(l, HT);
            write(l, rnd.get_bit);
            write(l, HT);
            write(l, rnd.get_bit_vector(10));
            writeline(output, l);
        end loop;
        finish;
    end process;
end architecture sim;
$ mkdir gh_work
$ ghdl -a --std=08 --workdir=gh_work rnd_pkg.vhd rnd_sim.vhd
$ ghdl -r --std=08 --workdir=gh_work rnd_sim
TRUE    1    0001000101
FALSE   0    1111111100
TRUE    1    0010110010
TRUE    1    0010010101
FALSE   0    0111110100
FALSE   1    1101110010
TRUE    1    1011010110
TRUE    1    0010010010
TRUE    1    1101100111
TRUE    1    0011100100
simulation finished @0ms


Modified text is an extract of the original Stack Overflow Documentation
Licenciado bajo CC BY-SA 3.0
No afiliado a Stack Overflow