Hallo zusammen, vor kurzem bin ich auf den Artikel "Digitaler Rauschgenerator im FPGA" von J.S. gestoßen: https://www.mikrocontroller.net/articles/Digitaler_Rauschgenerator_im_FPGA und wollten den vorgestellten Realisationsvorschlag umsetzen. Das RTL Schematic sieht so aus, wie ich es mir vorstelle. Leider habe ich aber bei der Simulation Probleme. Ich vermute eine "Functional Simulation" kann hier gar nicht funktionieren. Die "Post-Synthesis Timing Simulation" läuft so, wie ich es erwarte. Aber auch die "Post-Implementation Timing Simulation" wirft einen Fehler (fatal run-time error). Weiß jemand woran das liegen kann bzw. ob es an irgendwelchen Simulationseinstellungen liegt? Ich dachte eigentlich, dass gerade diese Simulation die realistischsten Ergebnisse liefern würde und wundere mich, warum es nicht geht. Ich verwende Vivado 2016.4 mit einem Artix-7 (XC7A15T). Vielen Dank bereits im Voraus für alle Tipps und Kommentare!
Welchen der Vorschläge hast du umgesetzt? Diese Seite zeigt mehrere. Poste am Besten dein RTL oder den Code. Womit hast du es simuliert? Bei der Simulation von Rückkoppelungen muss an irgendeiner Stelle eine Zeitverzögerung eingebaut werden, damit es klappt.
Vielen Dank für die Antwort! Ich habe (versucht) den Realisationsvorschlag aus der Grafik in der Mitte der Seite umgesetzt (umzusetzen). Eine Verzögerung für die Simulation habe ich nicht eingebaut. Das könnte es also schon sein... Würde hier etwas wie "wait for xxx ns" in der Inverterkette reichen? Hier noch mein Code (um einen Fehler bei der Nutzung einer als Generic übergebenen Anzahl an Invertern auszuschließen, habe ich die Anzahl der Inverter hier noch fix umgesetzt):
1 | library IEEE; |
2 | use IEEE.STD_LOGIC_1164.ALL; |
3 | |
4 | entity noise_bit_gen is |
5 | Generic ( n_invChain_osc1 : integer := 8; |
6 | n_invChain_osc2 : integer := 12); |
7 | Port ( rst : in std_logic; |
8 | output : out std_logic); |
9 | end noise_bit_gen; |
10 | |
11 | -- Quelle:
|
12 | -- https://www.mikrocontroller.net/articles/Digitaler_Rauschgenerator_im_FPGA
|
13 | |
14 | architecture Behavioral of noise_bit_gen is |
15 | |
16 | constant k1 : integer := 13; |
17 | constant k2 : integer := 27; |
18 | |
19 | constant n_invChain_secondBlock : integer := 4; |
20 | |
21 | signal cnt1 : integer range 0 to k1 := 0; |
22 | signal cnt2 : integer range 0 to k2 := 0; |
23 | |
24 | signal invChain_osc1 : std_logic_vector(n_invChain_osc1 - 1 downto 0) := (others => '0'); |
25 | signal invChain_osc2 : std_logic_vector(n_invChain_osc2 - 1 downto 0) := (others => '0'); |
26 | |
27 | signal invChain_secondBlock_1 : std_logic_vector(n_invChain_secondBlock - 1 downto 0) := (others => '0'); |
28 | signal invChain_secondBlock_2 : std_logic_vector(n_invChain_secondBlock - 1 downto 0) := (others => '0'); |
29 | |
30 | signal mux1_out : std_logic := '0'; |
31 | signal mux2_out : std_logic := '0'; |
32 | |
33 | signal short_feedback_osc1 : std_logic := '0'; |
34 | signal short_feedback_osc2 : std_logic := '0'; |
35 | |
36 | |
37 | attribute dont_touch : string; |
38 | attribute dont_touch of cnt1 : signal is "true"; |
39 | attribute dont_touch of cnt2 : signal is "true"; |
40 | attribute dont_touch of invChain_osc1 : signal is "true"; |
41 | attribute dont_touch of invChain_osc2 : signal is "true"; |
42 | attribute dont_touch of invChain_secondBlock_1 : signal is "true"; |
43 | attribute dont_touch of invChain_secondBlock_2 : signal is "true"; |
44 | attribute dont_touch of mux1_out : signal is "true"; |
45 | attribute dont_touch of mux2_out : signal is "true"; |
46 | attribute dont_touch of short_feedback_osc1 : signal is "true"; |
47 | attribute dont_touch of short_feedback_osc2 : signal is "true"; |
48 | |
49 | |
50 | begin
|
51 | |
52 | ----------------------------------------------------------------------------
|
53 | -- OSC 1
|
54 | |
55 | -- inverter chain OSC1
|
56 | invChain_osc1(0) <= not(mux2_out) when (rst = '0') else '0'; |
57 | invChain_osc1(1) <= not(invChain_osc1(0)) when (rst = '0') else '0'; |
58 | invChain_osc1(2) <= not(invChain_osc1(1)) when (rst = '0') else '0'; |
59 | invChain_osc1(3) <= not(invChain_osc1(2)) when (rst = '0') else '0'; |
60 | invChain_osc1(4) <= not(invChain_osc1(3)) when (rst = '0') else '0'; |
61 | invChain_osc1(5) <= not(invChain_osc1(4)) when (rst = '0') else '0'; |
62 | invChain_osc1(6) <= not(invChain_osc1(5)) when (rst = '0') else '0'; |
63 | invChain_osc1(7) <= not(invChain_osc1(6)) when (rst = '0') else '0'; |
64 | |
65 | -- signle inverter
|
66 | short_feedback_osc1 <= not(invChain_osc1(invChain_osc1'left)) when (rst = '0') else '0'; |
67 | |
68 | -- inverter chain OSC1 second block
|
69 | invChain_secondBlock_1(0) <= not(short_feedback_osc1) when (rst = '0') else '0'; |
70 | invChain_secondBlock_1(1) <= not(invChain_secondBlock_1(0)) when (rst = '0') else '0'; |
71 | invChain_secondBlock_1(2) <= not(invChain_secondBlock_1(1)) when (rst = '0') else '0'; |
72 | invChain_secondBlock_1(3) <= not(invChain_secondBlock_1(2)) when (rst = '0') else '0'; |
73 | |
74 | -- counter for OSC1
|
75 | process
|
76 | begin
|
77 | wait until rising_edge(invChain_osc1(invChain_osc1'left)); |
78 | if cnt1 < k1 then |
79 | cnt1 <= cnt1 + 1; |
80 | else
|
81 | cnt1 <= 0; |
82 | end if; |
83 | end process; |
84 | |
85 | -- comparator and multiplexer
|
86 | mux1_out <= short_feedback_osc1 when (cnt1 < (k1/2)) else |
87 | invChain_secondBlock_1(3); |
88 | |
89 | ----------------------------------------------------------------------------
|
90 | ----------------------------------------------------------------------------
|
91 | |
92 | |
93 | ----------------------------------------------------------------------------
|
94 | -- OSC 2
|
95 | |
96 | -- inverter chain OSC1
|
97 | invChain_osc2(0) <= not(mux1_out) when (rst = '0') else '0'; |
98 | invChain_osc2(1) <= not(invChain_osc2(0)) when (rst = '0') else '0'; |
99 | invChain_osc2(2) <= not(invChain_osc2(1)) when (rst = '0') else '0'; |
100 | invChain_osc2(3) <= not(invChain_osc2(2)) when (rst = '0') else '0'; |
101 | invChain_osc2(4) <= not(invChain_osc2(3)) when (rst = '0') else '0'; |
102 | invChain_osc2(5) <= not(invChain_osc2(4)) when (rst = '0') else '0'; |
103 | invChain_osc2(6) <= not(invChain_osc2(5)) when (rst = '0') else '0'; |
104 | invChain_osc2(7) <= not(invChain_osc2(6)) when (rst = '0') else '0'; |
105 | invChain_osc2(8) <= not(invChain_osc2(7)) when (rst = '0') else '0'; |
106 | invChain_osc2(9) <= not(invChain_osc2(8)) when (rst = '0') else '0'; |
107 | invChain_osc2(10) <= not(invChain_osc2(9)) when (rst = '0') else '0'; |
108 | invChain_osc2(11) <= not(invChain_osc2(10)) when (rst = '0') else '0'; |
109 | |
110 | -- signle inverter
|
111 | short_feedback_osc2 <= not(invChain_osc2(invChain_osc2'left)) when (rst = '0') else '0'; |
112 | |
113 | -- inverter chain OSC1 second block
|
114 | invChain_secondBlock_2(0) <= not(short_feedback_osc2) when (rst = '0') else '0'; |
115 | invChain_secondBlock_2(1) <= not(invChain_secondBlock_2(0)) when (rst = '0') else '0'; |
116 | invChain_secondBlock_2(2) <= not(invChain_secondBlock_2(1)) when (rst = '0') else '0'; |
117 | invChain_secondBlock_2(3) <= not(invChain_secondBlock_2(2)) when (rst = '0') else '0'; |
118 | |
119 | -- counter for OSC1
|
120 | process
|
121 | begin
|
122 | wait until rising_edge(invChain_osc2(invChain_osc2'left)); |
123 | if cnt2 < k2 then |
124 | cnt2 <= cnt2 + 1; |
125 | else
|
126 | cnt2 <= 0; |
127 | end if; |
128 | end process; |
129 | |
130 | -- comparator and multiplexer
|
131 | mux2_out <= short_feedback_osc2 when (cnt2 < (k2/2)) else |
132 | invChain_secondBlock_2(3); |
133 | |
134 | ----------------------------------------------------------------------------
|
135 | ----------------------------------------------------------------------------
|
136 | |
137 | |
138 | ----------------------------------------------------------------------------
|
139 | -- output
|
140 | |
141 | output <= invChain_osc1(invChain_osc1'left) XOR invChain_osc2(invChain_osc2'left); |
142 | |
143 | ----------------------------------------------------------------------------
|
144 | ----------------------------------------------------------------------------
|
145 | |
146 | end Behavioral; |
Man soll nicht alles ungeprüft nachbauen, was andere empfehlen :-) Nee, also die Schaltung funktioniert schon. Am Wochenende kann ich was posten, wenn du möchtest. Was ich auf den ersten Blick sehe: Soweit ist es richtig umgesetzt. Anders ist nur: - Ich habe zu den "don't touch" noch "keep" kommandiert. - Wichtig scheint mir der Verzicht auf eine Initialisierung, weil sich die ja mit dem Syntheseergebnis beißt - Auch habe ich nur ein Bit resettet und zwar jeweils das, welches anhand der MUX rückkoppelt. - Etwas aufpassen muss man mit der Weiterverwendung der toggelnden LUTs als Takt: Da muss ein Buffer dazwischen gesetzt werden. War jedenfalls bei der Xilinx Version in der ISE so. Werde das am WE mal ins Vivado importieren. - Ich meine es in einer späteren Version so gemacht zu haben, dass das toogle-Bit mit einem regulären Takt einsynchronisiert wird und zweifach verzögert interpretiert wird. Bei Flankenwechsel wird der jeweilige MUX umgeschaltet, der die Inverterketten verkürzt. - verodert werden dann auch die einsynchronisierten Bits - ich habe in der finalen Version 3 Generatoren benutzt
Hallo Jürgen, vielen Dank für deine Antwort und die ganzen Tipps!! Ich versuche es gleich anzupassen! Arbeit am Wochenende musst du dir wegen mir wirklich nicht machen. Ich fand den Beitrag sehr interessant, will es aber derzeit nur als Spielerei nutzen und um meine VHDL Kenntnisse etwas zu erweitern.
Anbei die Timing Simulation von Vivado (post P&R) und ModelSIM (logisch). Um die logische Simulation ins Laufen zu bekommen, kann man "after"-Konstrukte einsetzen. Das unterbricht den unweigerlichen Loop. In beiden Simulationen bekommt man nichts Reales, weil die Einflüsse, die man ja haben möchte, fehlen. Man kann aber prüfen, ob es prinzipiell geht. Am Besten ist noch die post P&R bei Vivado. Insgesamt ist das Rauschen eben recht zufällig, d.h. eben auch zufällig schlecht mit seher ungleich verteilten Spektren. Wie im Artikel schon angedeutet, spielt da auch der Rest des designs im FPGA eine Rolle, z.B: was das an Strom zieht und wie. Sauberes Rauschen geht besser deterministisch, siehe Klangbeispiel: Beitrag "Re: Farbiges Rauschen im FPGA - the coloured noise generator"
Hallo Jürgen, vielen Dank für die Datei und deine Bemühungen! Und wieder mal habe ich viel dazugelernt!!
Jürgen S. schrieb: > In beiden Simulationen bekommt man nichts Reales, und damit stellt sich die Frage, was es denn dann bringt. Entweder, man kann das Verhalten einer Schaltung vorhersagen, oder nicht. Schaltungen deren Verhalten nicht durch Simulation vorhersagbar sind, lassen sich auch nicht sicher einsetzen, oder?
Rauschen will man für manche Anwendungen nicht vorhersagen können.
Gustl B. schrieb: > Rauschen will man für manche Anwendungen nicht vorhersagen können. Das ist auffallend richtig und aus dem Grund kann ich mit der mangelnden Simulationsfähigkeit meines RGs prima leben. :-)
Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.