Szukaj…


Uwagi

Przed VHDL 1993 dwa równoległe procesy mogły komunikować się tylko z sygnałami. Dzięki semantyce symulacji języka, który aktualizuje sygnały tylko między krokami symulacji, wynik symulacji był deterministyczny: nie zależał on od kolejności wybranej przez program planujący symulację do wykonania procesów.

[W rzeczywistości nie jest to 100% prawda. Procesy mogą również komunikować się przy użyciu wejścia / wyjścia pliku. Ale jeśli projektant podważał determinizm za pomocą plików, to nie może być pomyłka.]

Język był więc bezpieczny. Z wyjątkiem celu zaprojektowanie niedeterministycznych modeli VHDL było prawie niemożliwe.

VHDL 1993 wprowadził wspólne zmienne, a projektowanie niedeterministycznych modeli VHDL stało się bardzo łatwe.

VHDL 2000 wprowadził typy chronione i ograniczenie, że zmienne współdzielone muszą być typu chronionego.

W VHDL typy chronione są najbardziej podobne do koncepcji obiektów w językach obiektowych (OO). Realizują enkapsulację struktur danych i ich metod. Gwarantują również wyłączny i atomowy dostęp do swoich członków danych. Nie zapobiega to całkowicie niedeterminizmowi, ale przynajmniej dodaje ekskluzywności i atomowości do wspólnych zmiennych.

Typy chronione są bardzo przydatne podczas projektowania modeli VHDL wysokiego poziomu przeznaczonych wyłącznie do symulacji. Mają kilka bardzo dobrych właściwości języków OO. Używanie ich często sprawia, że kod jest bardziej czytelny, łatwy w obsłudze i wielokrotnego użytku.

Uwagi:

  • Niektóre łańcuchy narzędzi do symulacji domyślnie wyświetlają ostrzeżenia tylko wtedy, gdy zmienna współdzielona nie jest typu chronionego.
  • Niektóre narzędzia do syntezy nie obsługują typów chronionych.
  • Niektóre narzędzia do syntezy mają ograniczone wsparcie dla wspólnych zmiennych.
  • Można by pomyśleć, że zmienne współdzielone nie są przydatne do modelowania sprzętu i powinny być zarezerwowane dla oprzyrządowania kodu bez skutków ubocznych. Ale wzorce VHDL zalecane przez kilku dostawców EDA do modelowania płaszczyzny pamięci dla wielu portów w pamięci o dostępie swobodnym (RAM) używają wspólnych zmiennych. Tak, tak, wspólne zmienne mogą być syntetyzowane w pewnych okolicznościach.

Generator pseudolosowy

Generatory peudo-losowe są często przydatne podczas projektowania środowisk symulacyjnych. Poniższy pakiet VHDL pokazuje, jak używać typów chronionych do projektowania pseudolosowego generatora wartości boolean , bit i bit_vector . Można go łatwo rozszerzyć, aby generował także losowy std_ulogic_vector , signed , unsigned . Rozszerzenie go w celu generowania losowych liczb całkowitych o dowolnych granicach i jednolitym rozkładzie jest nieco trudniejsze, ale wykonalne.

Deklaracja paczki

Typ chroniony ma deklarację, w której deklarowane są wszystkie publiczne akcesoria do podprogramów. Dla naszego generatora losowego upublicznimy jedną procedurę inicjalizacji zarodka i trzy nieczyste funkcje zwracające losowy boolean , bit lub bit_vector . Zauważ, że funkcje nie mogą być czyste, ponieważ różne wywołania któregokolwiek z nich, z tymi samymi parametrami, mogą zwracać różne wartości.

-- 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;

Treść opakowania

Treść typu chronionego definiuje wewnętrzne struktury danych (elementy) i treści podprogramu. Nasz generator losowy oparty jest na 128-bitowym Rejestrze Przesunięcia Liniowego (LFSR) z czterema dotknięciami. Zmienna state przechowuje bieżący stan LFSR. Procedura prywatnego throw zmienia LFSR za każdym razem, gdy używany jest generator.

-- 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;

Generator losowy może być następnie użyty w stylu OO, jak w:

-- 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
Licencjonowany na podstawie CC BY-SA 3.0
Nie związany z Stack Overflow