VHDL: Zufallswerte für die Initialisierung erzeugen

OP #7898379
Lesenswert?

Moin,

ich sitze gerade an einem kleinen Problem. In VHDL sollen für die Initialisierung, das heißt zur Synthesezeit, Zufallswerte erzeugt werden. Es gibt die Standardprozedur uniform. Ist es möglich, die für die Initialisierung zu nutzen? Unten steht ein kurzer Code dazu. Der funktioniert in der Simulation wie erwartet, aber bei der Synthese gibt es Probleme. Quartus gibt den Fehler "Error (10372): VHDL error at Top.vhdl(19): item cannot be assigned value " aus (Zeile 19 ist der Beginn der Funktionsdefinition). Vivado ist bei einem ähnlichen Code (den ich jetzt nicht hier habe) etwas genauer und gibt an, dass irgendwo in math_real ein nicht-konstantes real-Signal benutzt wird, das nicht synthetisiert werden kann. Ist es möglich, uniform oder eine andere Standardfunktion für Zufallszahlen in der Synthese zu nutzen?

Ich könnte ein LFSR benutzen oder die Zufallswerte extern erzeugen und im Code als Werte speichern. Darum geht es aber nicht. Und noch ganz klar: Es geht nicht darum, einen Zufallszahlengenerator zu synthetisieren. Es sollen einfach nur bei der Synthese pseudozufällige Initialisierungswerte erzeugt werden.

[Bearbeitung: Es geht auch nicht darum, dass die Werte bei jedem Synthesedurchlauf unterschiedlich sind.]

1
library ieee;
2

3
use ieee.std_logic_1164.all;
4
use ieee.numeric_std.all;
5
use ieee.math_real.all;
6

7
entity Top is
8
  port(
9
    clk           : in  std_logic;
10
    data_select   : in  unsigned(2 downto 0);
11
    data_out      : out unsigned(7 downto 0) := (others => '0')
12
  );
13
end entity;
14

15
architecture rtl of Top is
16
  -- Seeds für Uniform, die Werte werden bei jedem 'Aufruf' geändert
17
  shared variable seed_1, seed_2  : natural := 1;
18

19
  impure function random return natural is
20
    variable rand_real  : real;
21
    variable result    : integer;
22
  begin
23
    -- rand_real ist ein Zufallswert zwischen 0 und 1
24
    uniform(seed_1, seed_2, rand_real);
25
    -- Auf den Bereich 0 bis 100 abbilden
26
    return integer(round(rand_real * 100.0));
27
  end function;
28
  
29
  -- Ein Arry, das mit Zufallswerten initialisiert werden soll.
30
  type array_t is array (0 to 2**data_select'length) of integer;
31
  constant const_array  : array_t := (others => random);
32
  
33
begin
34

35
  -- Damit nicht alles wegoptimiert wird
36
  data_out <= to_unsigned(const_array(to_integer(data_select)), data_out'length);
37
    
38
end architecture;
#7898434
Lesenswert?

Die Synthese unterscheidet allgemein bei VHDL nicht zwischen 'Ausfuehrung von VHDL' und 'Umsetzung in Hardware'. Leider. Ob es in Verilog mit '$random' in der Initialisierung geht, weiss ich nicht.

Demnach ist dein Ansinnen in der Form vermutlich nicht umsetzbar, so dass es wohl das einfachere ist, die Initialwerte explizit mit einem Script zu generieren und dann die Synthese anzuwerfen. Oder du nutzt gemischt gut dokumentierte Mechanismen (je nach Vendor), um die Initialwerte nachtraeglich fuer entsprechende Location-Constraints ins BIT-File zu patchen. Bei Xilinx gibt es sonst noch einige ICAP-Hacks zur in-system-Rekonfiguration, falls es um Serien-Produktion ginge.

Nachtrag: Was du noch probieren koenntest: Die Zufalls-Sequenz als Generic von der Synthese aus uebergeben.

OP #7898597
Lesenswert?

Martin S. schrieb:

Die Synthese unterscheidet allgemein bei VHDL nicht zwischen 'Ausfuehrung von VHDL' und 'Umsetzung in Hardware'.

Grundsätzlich ist ja sowas wie [vhdl]constant WIDTH : natural := integer(ceil(log2(real(DATA_RANGE))));[vhdl] möglich, auch wenn die Formel nicht synthetisierbar ist. Deshalb habe ich mich gefragt, ob auch die Zufallsinitialisierung irgendwie geht. Allerdings müsste ja für die Zufallswerte bei der Synthese tatsächlich eine Funktion mit Variablen ausgeführt werden. Daran scheitert es wahrscheinlich.

(Firma: Starfleet) #7898685
Lesenswert?

Die Synthese unterscheidet allgemein bei VHDL nicht zwischen 'Ausfuehrung von VHDL' und 'Umsetzung in Hardware'.

Grundsätzlich ist ja sowas wie ... ob auch die Zufallsinitialisierung irgendwie geht.

Aehm, räusper, der Grundsatz in digitaler Logik wie FPGA als deterministisches System ist gerade, das es sowas wie "zufällige Anfangs-Speicherwerte nicht gibt, respektive bei PowerUp eine systemweite Initialisierung durchzuführen ist.

Das ist eben der Reset, den man entweder explizit im FPGA als POR (PowerOn Reset) definiert oder über die Konfiguration (Download Configurations bitstream) erreicht.

Bei Xilinx-FPGA's ist die zweite Methode möglich, manche Synthesetools vwerwenden den Initi-wert bei der Signaldeclaration dafür; bei Altera-Typen ist oft nur die "reset-Methode" anwendbar.

Wenn man den Zufall hier verwenden will, dann nennt man das "Fehler-injektion":

OP #7898736
Lesenswert?

Bradward B. schrieb:

der Grundsatz in digitaler Logik wie FPGA als deterministisches System ist gerade, das es sowas wie "zufällige Anfangs-Speicherwerte nicht gibt, respektive bei PowerUp eine systemweite Initialisierung durchzuführen ist.

Richtig. Deshalb schrieb ich: Florian schrieb im Beitrag #7898379:

In VHDL sollen für die Initialisierung, das heißt zur Synthesezeit, Zufallswerte erzeugt werden.

Florian schrieb:

Es sollen einfach nur bei der Synthese pseudozufällige Initialisierungswerte erzeugt werden.

#7898741
Lesenswert?

Florian schrieb:

Allerdings müsste ja für die Zufallswerte bei der Synthese tatsächlich eine Funktion mit Variablen ausgeführt werden. Daran scheitert es wahrscheinlich.

Die Synthese kann das nur aufloesen, wenn es sich um Konstanten handelt. A priori versucht sie, Hardware aus einem Ausdruck zu erzeugen. Mit real und random ist das nicht eindeutig aufloesbar, somit Bumm. Mit Verilog koenntest du mehr Glueck haben, da 'initial' in den meisten Faellen ausgefuehrt wird und teils sogar Einschleifen externer Routinen erlaubt. Portabel ist das sonst nur, wenn du dein Seed als Konstante explizit vor der Synthese extern generierst und uebergibst.

OP #7898757
Lesenswert?

Martin S. schrieb:

Die Synthese kann das nur aufloesen, wenn es sich um Konstanten handelt. A priori versucht sie, Hardware aus einem Ausdruck zu erzeugen. Mit real und random ist das nicht eindeutig aufloesbar

Eindeutig auflösbar ist es ja schon. Zur Synthesezeit sind grundsätzlich alle notwendigen Informationen da. Aber ja, es wird nur berechnet, nicht ausgeführt. Da war mein Brett vor dem Kopf.

Es gibt ja auch noch andere Wege.

Danke für die Denkhilfe.

#7901437
Lesenswert?

Salü Florian

Ich hab mir deinen Code angesehen und gedacht, das müsste eigentlich gehen. Ich hätte das sehr ähnlich geschrieben und wie andere schon bestätigt haben, funktioniert dieser Ansatz auch (Ich meine den Teil mit Initialisierung per Funktionsaufruf "constant const_array : array_t := (others => random);" )

Habe darum deinen Code mal genommen und bei mir in Synplify gesteckt. Dieser Synthesizer versteht oft etwas mehr als andere Synthesizer und versteht auch oft stärker abstrahierten Code als andere.

Dein Code hat aber auch in Synplify genau die gleiche Fehlermeldung wie bei dir erzeugt.

Man muss dem Synthesizer in diesem Fall einfach ein bisschen auf die Sprünge helfen und in der Funktion das ganze Array erzeugen und nicht nur die einzelnen Werte.

Dieser Code wird von Synplify 2020.03M erfolgreich für einen PolarFire FPGA synthesisiert:

1
library ieee;
2
use ieee.std_logic_1164.all;
3
use ieee.numeric_std.all;
4
use ieee.math_real.all;
5
entity Top is
6
  port(
7
    clk           : in  std_logic;
8
    data_select   : in  unsigned(2 downto 0);
9
    data_out      : out unsigned(7 downto 0) := (others => '0')
10
  );
11
end entity;
12
architecture rtl of Top is
13
  -- Ein Arry, das mit Zufallswerten initialisiert werden soll.
14
  type array_t is array (0 to 2**data_select'length) of integer;
15

16
  -- Seeds für Uniform, die Werte werden bei jedem 'Aufruf' geändert
17
  impure function random return array_t is
18
    variable seed_1, seed_2  : natural := 1;
19
    variable rand_real  : real;
20
    variable result    : array_t;
21
  begin
22
    for i in 0 to result'high loop
23
      -- rand_real ist ein Zufallswert zwischen 0 und 1
24
      uniform(seed_1, seed_2, rand_real);
25
      -- Auf den Bereich 0 bis 100 abbilden
26
      result(i) := integer(round(rand_real * 100.0));
27
    end loop;
28
    return result;
29
  end function;
30

31
  constant const_array  : array_t := random;
32
  
33
begin
34
  -- Damit nicht alles wegoptimiert wird
35
  data_out <= to_unsigned(const_array(to_integer(data_select)), data_out'length);
36
    
37
end architecture;
Persönliche Seite #8086745
Lesenswert?

Martin S. schrieb:

Mit real und random ist das nicht eindeutig aufloesbar,

Die Frage ist, was die Synthese zum Erstellungszeitpunkt dann für Werte nimmt?

Florian schrieb:

es sieht in der Simulation gut aus und es synthetisiert in Quartus.

Und was kommt dabei raus? Nimmt er bei jeder Synthese wirklich neue Werte mit ins Design?

Was ist eigentlich der Zweck?

In der Regel möchte man ja deterministische FPGA-Funktionen haben.

Ich habe aktuell einen Rauschgenerator implementiert, der mit vorberechneten Werten arbeitet. Beitrag "Re: Statistisches Runden mit HDL-Coder"

OP #8087314
Lesenswert?

J. S. schrieb:

Und was kommt dabei raus? Nimmt er bei jeder Synthese wirklich neue Werte mit ins Design?

Weiß ich nach der langen Zeit nicht mehr. Es kamen zufällige Werte raus, aber ich weiß nicht mehr, ob die bei jeder Synthese anders waren.

PS: Ich habe gerade nochmal nachgelesen. https://vhdlwhiz.com/random-numbers/ "Just like other pseudo-random number generators, uniform will generate the same sequence of numbers when called with the same initial seed values. Because of this behavior, you can rerun the testbench and get the same result when using the same seed values." Da in den hier gezeigten Codes die Seeds fest vorgegeben werden, werden wohl auch bei jeder Synthese die gleichen Werte rauskommen.

: Bearbeitet durch User
Persönliche Seite #8093806
Lesenswert?

Florian schrieb:

uniform will generate the same sequence of numbers when called with the same initial seed values.

das dachte ich mir. Damit ist es kein Zufall mehr.

Rolf E. schrieb:

eine asynchrone externe.

So schaut es aus. Man braucht eine externe Information, die der FPGA nicht selber hat.

Ich sehe da FPGA-intern zur Ausführungszeit 3 Möglichkeiten:

a) Man nimmt einen externen Oszillatortakt, der nichts mit dem Systemtakt zu tun hat b) Man baut sich einen selbstschwingenden Oszillator durch Inverter-Rückkopplung. c) Man benutzt eine interne Temperatur des FPGAs

Da der TE hier etwas zur Compilezeit haben will, könnte man per Python die Quersumme des VHDL-sheets bilden und an geeigneter Stelle eintragen, oder man benutzt die TAGs von Doxygen / Subversion, die den Code bei jeder Version des VHDL ändern.

Ein Kombination wäre es, interne Laufzeiten von langen Gattern / von Pin zu Pin zu messen, weil diese sich von Synthese zu Synthese verändern, durchaus auch in Abhängigkeit des PC-Zustandes.

(Firma: Starfleet) #8093842
Lesenswert?

Mit der einen die andere samplen und als Startwert für ein LFSR nehmen.

Vorsicht, es gibt Startwerte mit denen das rückgekoppelt Schieberegister keine neuen Werte generiert, die müsste man ausschliessen/aussortieren.

Und natürlich liefert ein LFSR nur pseudo Zufall. Der output ist periodisch, das heisst er wiederholt sich und nicht jede XOR Rückkopplung liefert auch ein "Maximum length" LSFR. das heisst, die beriode ist 2**n - 1, wobei n die Anzahl der bits des SR ist. Das Spektrum der generierten Werte soll ganz gut ausschauen (? wwißes Gauss-Rauschen ?) , ist also nicht die schlechteste Wahl.

Persönliche Seite #8095751
Lesenswert?

Bradward B. schrieb:

Vorsicht, es gibt Startwerte mit denen das rückgekoppelt Schieberegister keine neuen Werte generiert, die müsste man ausschliessen/aussortieren.

Korrekt. Das ist eine Falle bei vielen dieser Verfahren. Auch andere numerische Pseudozufallsgeneratoren leiden an diesem Problem. Ich habe das so gelöst, daß ich in einem BRAM einen Übersetzer habe, der ungünstige Codes auf günstige übersetzt. Die meisten gehen dann 1:1 für die anderen gibt es eine Translationsstrategie, d.h. es gibt eine Auswahl zulässiger Codes, die angehüpft werden dürfen und ihrerseits zufällig ausgewählt werden.

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren