vhdl
Geschützte Typen
Suche…
Bemerkungen
Vor VHDL 1993 konnten zwei gleichzeitige Prozesse nur mit Signalen kommunizieren. Dank der Simulationssemantik der Sprache, die Signale nur zwischen den Simulationsschritten aktualisiert, war das Ergebnis einer Simulation deterministisch: Es hing nicht von der Reihenfolge ab, die der Simulationsplaner für die Ausführung der Prozesse gewählt hatte.
[Tatsächlich ist das nicht 100% wahr. Prozesse können auch über Dateieingabe / -ausgabe kommunizieren. Wenn ein Designer den Determinismus jedoch durch die Verwendung von Dateien gefährdet, könnte dies nicht wirklich ein Fehler sein.]
Die Sprache war also sicher. Außer mit Absicht war es fast unmöglich, nicht deterministische VHDL-Modelle zu entwerfen.
VHDL 1993 führte gemeinsame Variablen ein und das Entwerfen nicht deterministischer VHDL-Modelle wurde sehr einfach.
In VHDL 2000 wurden geschützte Typen eingeführt und die Einschränkung, dass gemeinsame Variablen vom geschützten Typ sein müssen.
In VHDL ähneln geschützte Typen dem Konzept von Objekten in objektorientierten (OO) Sprachen. Sie implementieren die Kapselung von Datenstrukturen und deren Methoden. Sie garantieren auch den exklusiven und atomaren Zugriff auf ihre Datenmitglieder. Dies verhindert den Nicht-Determinismus nicht vollständig, sondern fügt den gemeinsam genutzten Variablen zumindest Exklusivität und Atomizität hinzu.
Geschützte Typen sind sehr nützlich, wenn Sie VHDL-Modelle auf hohem Niveau entwerfen, die nur für die Simulation vorgesehen sind. Sie haben mehrere sehr gute Eigenschaften von OO-Sprachen. Die häufige Verwendung macht den Code lesbarer, wartbarer und wiederverwendbar.
Anmerkungen:
- Einige Simulationswerkzeugketten geben standardmäßig nur dann Warnungen aus, wenn eine gemeinsam genutzte Variable keinen geschützten Typ hat.
- Einige Synthesetools unterstützen keine geschützten Typen.
- Einige Synthesetools unterstützen Shared Variablen nur begrenzt.
- Man könnte meinen, dass gemeinsame Variablen nicht für die Modellierung von Hardware geeignet sind und für die Code-Instrumentierung ohne Nebenwirkungen reserviert werden sollen. Die von mehreren EDA-Anbietern empfohlenen VHDL-Muster zum Modellieren der Speicherebene von RAMs mit mehreren Ports (Random Access Memory) verwenden jedoch gemeinsame Variablen. Ja, gemeinsame Variablen können unter bestimmten Umständen synthetisierbar sein.
Ein Pseudo-Zufallsgenerator
Peudo-Zufallsgeneratoren sind häufig beim Entwerfen von Simulationsumgebungen hilfreich. Das folgende VHDL-Paket zeigt, wie geschützte Typen zum Entwerfen eines Pseudo-Zufallsgenerators aus boolean
, bit
und bit_vector
. Es kann leicht erweitert werden , um auch zufällig zu erzeugen std_ulogic_vector
, signed
, unsigned
. Es zu erweitern, um zufällige Ganzzahlen mit beliebigen Grenzen und einer gleichmäßigen Verteilung zu erzeugen, ist etwas schwieriger, aber machbar.
Die Paketdeklaration
Ein geschützter Typ hat eine Deklaration, in der alle öffentlichen Unterprogramm-Zugriffsmethoden deklariert werden. Für unseren Zufallsgenerator veröffentlichen wir eine Initialisierungsprozedur und drei unreine Funktionen, die einen zufälligen boolean
, bit
oder bit_vector
. Beachten Sie, dass die Funktionen nicht rein sein können, da verschiedene Aufrufe von ihnen mit denselben Parametern unterschiedliche Werte zurückgeben können.
-- 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;
Der Paketkörper
Der geschützte Typkörper definiert die inneren Datenstrukturen (Mitglieder) und die Unterprogrammkörper. Unser Zufallsgenerator basiert auf einem 128-Bit Linear Feedback Shift Register (LFSR) mit vier Abgriffen. Die state
speichert den aktuellen Zustand des LFSR. Bei einem privaten throw
wird der LFSR bei jeder Verwendung des Generators verschoben.
-- 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;
Der Zufallsgenerator kann dann in einem OO-Stil verwendet werden:
-- 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