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

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