vhdl
Chronione typy
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