Hallo, ich versuche den Code combine.vhd zum laufen zu bewegen. Unter ModelSim funktioniert er wie er soll (siehe Anhang). Leider funktioniert er auf den FPGA nicht (der Counter zählt nicht). Über Testpins habe ich sichergestellt, dass die Eingangssignale gleich den in der Simulation sind. Die Frequenz von clk1 und clk2 betragen jeweils 40kHz und sind um 180° phasenverschoben. Das high von clk1 und clk2 liegen über 20ns an. Könnt ihr mir weiterhelfen? Wo ist der Fehler?
Tobi schrieb: > Wo ist der Fehler? In deiner Takterzeugung. So wird das niemals gehen. Hier werden Setup- und Hold-Zeiten verletzt, das wird niemals zuverlässig auf richtiger Hardware laufen:
1 | clk <= clk1 or clk2; -- Hoppala! Ein Kombinatorischer Takt. |
2 | -- So macht man das aber nicht.
|
3 | -- Da hat dir die Toolchain sicher was gesagt...
|
4 | |
5 | process(clk...) -- Siehe Kommentar unten... |
6 | begin
|
7 | if clk = '1' and clk'event then |
8 | ...
|
9 | -- mal angenommen, eine steigende Flanke von clk1 wäre der Grund,
|
10 | -- dass wir hierher kommen
|
11 | if enable1 = '1' and clk1 = '1' then |
12 | -- dann ist clk1 hier nicht sicher schon '1', weil in der
|
13 | -- Realität Laufzeiten im FPGA sind, und zudem noch eine
|
14 | -- logische Verknüpfung mit enable zu durchlaufen wäre.
|
15 | -- Auf jeden Fall erwarte ich hier in der Realität einen Takt Latency.
|
16 | elsif enable2 = '1' and clk2 = '1' then |
17 | ...
|
18 | else
|
BTW:
> process(clk,clk1,enable1,h1,clk2,enable2,h2)
Da ist viel zu viel in der Liste. clk allein würde reichen...
:
Bearbeitet durch Moderator
Ziemlich wilde Sache, die du da machst. Nur beim kurz drüber schauen sehe ich: kombinatorische Takte --> gefährlich Takt selbst nochmal kombinatorisch verknüpft --> sehr gefährlich Also alles in allem ist das echt ein ganz gruseliger Code und alles andere als synchron. Daran wird es auch irgendwo liegen, dass dein FPGA nicht das macht, was du gerne hättest. Du baust an einer Stelle ein Register für writedata wo du den Eingang des Registers mit dem Takt verknüpfst.. das geht mit großer wahrscheinlichkeit schief. Und wenn man genauer drüberschaut, wird man noch viele andere "Schweinereien" dieser Art in deinem Code finden. Woran es jetzt konkret liegt, sehe ich auf die Schnelle auch nicht. Aber was ich sehe ist, dass der ganze Code so ziemlich gegen alle Regeln verstößt, die man bei synchronen Designs einhalten sollte :-(
Vielen Dank :) habe jetzt den Code geändert und er Funktioniert jetzt:
1 | library ieee; |
2 | use ieee.std_logic_1164.all; |
3 | use ieee.numeric_std.all; |
4 | |
5 | library altera_mf; |
6 | use altera_mf.altera_mf_components.all; |
7 | |
8 | entity combine is |
9 | port
|
10 | (
|
11 | clk: in std_logic; |
12 | new_data1: in std_logic; |
13 | enable1: in std_logic; |
14 | h1: in std_logic_vector (15 downto 0); |
15 | new_data2: in std_logic; |
16 | enable2: in std_logic; |
17 | h2: in std_logic_vector (15 downto 0); |
18 | adress: out std_logic_vector (9 downto 0); |
19 | chipselect: out std_logic; |
20 | clken: out std_logic; |
21 | write: out std_logic; |
22 | writedata: out std_logic_vector (31 downto 0); |
23 | byteenable: out std_logic_vector (3 downto 0); |
24 | hig_val_pos: out std_logic_vector (15 downto 0); |
25 | a: out std_logic; |
26 | b: out std_logic |
27 | );
|
28 | end combine; |
29 | |
30 | architecture a01 of combine is |
31 | begin
|
32 | process(clk) |
33 | variable counter: unsigned(9 downto 0) := "0000000000"; |
34 | begin
|
35 | if clk = '1' and clk'event then |
36 | if (enable1 = '1') and (new_data1 = '1') then |
37 | byteenable <= "1111"; |
38 | write <= '1'; |
39 | chipselect <= '1'; |
40 | clken <= '1'; |
41 | writedata <= std_logic_vector(resize(signed(h1),32)); |
42 | if counter = "1111111111" then |
43 | counter := "0000000000"; |
44 | else
|
45 | counter := counter + 1; |
46 | end if; |
47 | elsif (enable2 = '1') and (new_data1 = '1') then |
48 | byteenable <= "1111"; |
49 | write <= '1'; |
50 | chipselect <= '1'; |
51 | clken <= '1'; |
52 | writedata <= std_logic_vector(resize(signed(h2),32)); |
53 | if counter = "1111111111" then |
54 | counter := "0000000000"; |
55 | else
|
56 | counter := counter + 1; |
57 | end if; |
58 | elsif (enable2 = '0') and (enable2 = '0') then |
59 | counter := "0000000000"; |
60 | byteenable <= "0000"; |
61 | write <= '0'; |
62 | chipselect <= '0'; |
63 | end if; |
64 | adress <= std_logic_vector(counter); |
65 | hig_val_pos <= std_logic_vector(resize(counter,16)); |
66 | a <= counter(0); |
67 | b <= counter(1); |
68 | end if; |
69 | end process; |
70 | |
71 | end a01; |
Das sieht doch zumindest auf den ersten Blick schon viel besser aus ;-)
Auch mein Gedanke, wobei mich die Variable counter noch ein wenig stört... ;-)
Ja, Variablen sind mir auch ein Dorn im Auge.. Außerdem würde ich den Counter noch komplett aus den ganzen IF´s rausnehmen und nur im letzten IF den Counter-Wert überbügeln und clken ist eh immer "1".. Aber alles in allem ein Quantensprung zu dem ursprünglichen Code ;-)
.. btw.. Wenn ein Signal "clken" heißt, dann ahne ich schon das nächste Problem ^^
Clken ist verbunden mit einen Speicher der zwischen den fpga und Mikrocontroller sitzt. Clken habe ich vergessen auf 0 zu setzen. Der Speicher ist eine Art fifo Speicher. Aus der variablen counter kann ich auch ein Signal machen.
Tobi schrieb: > Aus der variablen counter kann ich auch ein Signal machen. Tu das und lies auch mal den Beitrag "Variable vs Signal"
Stellen sich zwei Fragen: Wozu wird denn hier überhaupt eine Variable verwendet, wo doch garnichts variabel ist? Die Variable dient in dem einen Syntheselauf, der während der Umsetzung dieses Codestücks in eine Netzliste getätigt wird, nur dazu einmal einen Wert zu speichern. Dafür braucht es keine Variable, sondern man nimmt ein Signal, das man ohnehin verwenden will. Variablen benötigt man doch nur, wenn die Formulierung einer Funktion zu komplex ist, um sie in einer Zeile zu schreiben oder wenn in einem Syntheselauf im jeweiligen Codestück mehrfach gelooped wird und die dort verwendete Variable mehrere Werte annimmt, aus denen dann am Ende ein Wert für ein Signal abgeleitet wird. Sonst sind Variablen unnötig. Sie existieren nur zur Compilationszeit. So haben wir das einst gelernt. Und die zweite Frage: Woher haben die heutigen Hardwarebeschreiber nur die Manie, Variablen einzuführen? Zuviel C gemacht? Kann es eigentlich nicht sein. Ich hatte auch schon 10 Jahre C auf dem Buckel bevor der erste Verilogbefehl vor meinem geistigen Auge auftauchte. VHDL kam dann nochmals später.
Thomas Ulrich schrieb: > Woher haben die heutigen Hardwarebeschreiber nur die Manie, Variablen > einzuführen? Welche Alternative hat man denn wenn man Berechnungen anstellen will die aus mehreren Befehlen bestehen? Das einzige was mir einfällt wäre einen Automaten zu bauen der in jedem Zustand eine weitere Teilberechnung durchführt. Wenn die Zwischenergebnisse nicht außerhalb gebraucht werden ist das eine schöne Art viele Takte für etwas zu verschwenden, das von der Signallaufzeit her auch in einen gepasst hätte;)
Daniel R. schrieb: > Welche Alternative hat man denn wenn man Berechnungen anstellen will die > aus mehreren Befehlen bestehen? Dafür kann man ja auch Variablen nehmen. Aber auch in deinen Beispielen aus dem anderen Thread sind die Variablem komplett sinnbefreit und machen im Zweifelsfall nur Verwirrung. Wo immer es geht, Signale. So einfach ist das. Ein Anfänger braucht sowieso keine Variablen, mindestens ein Jahr lang nicht.
Daniel R. schrieb: > Welche Alternative hat man denn wenn man Berechnungen anstellen will die > aus mehreren Befehlen bestehen? Man schreibt sie ausserhalb des getakteten Prozesses als Kombinatorik hin. > Wenn die Zwischenergebnisse nicht außerhalb gebraucht werden > ist das eine schöne Art viele Takte für etwas zu verschwenden, das von > der Signallaufzeit her auch in einen gepasst hätte Davon ausgehend, dass es wirklich so klein ist, dass es in einen Takt passt, wird es mit der oben genannten Methode genau so funktionieren. Genaus so. Durch das Weglassen des Taktes gibt man sie zum Wegoptimieren in beide Richtungen frei, d.h. sie wird mit der davor liegenden oder danach kommenden Logik verbacken, sofern da an den FFs mal was gewändert wird oder es über Hierachiegrenzen geht. Im anderen Fall benutzt man register balancing, um Kombinatorik so verschieben zu lassen, dass sie mit andere Kombinatorik zusammenkommt. Variablen bringen da sicher keinen Vorteil, sondern hindern das eher. Christian R. schrieb: > Ein Anfänger braucht sowieso keine Variablen, > mindestens ein Jahr lang nicht. Lieber 2 Jahre, wie bei den jungen Autofahrern. Ich bin ohnehin ein Befürworter eines VHDL-Zertifikats, eine Art Führerschein :-)
Mal angenommen man will die Berechnungen x=a+b+c und y=a+b+d durchführen. Wäre es da nicht sinnvoller eine variable zu verwenden (z=a+b und x=c+z und y=d+z) als die Berechnungen auszuschreiben(x=a+b+c und y=a+b+d). Durch die variable bleibt die Laufzeit gleich jedoch wird die Zahl der Le verringert.
Tobi schrieb: > Durch die variable bleibt die Laufzeit gleich jedoch wird die Zahl der > Le verringert. Nur auf den ersten Blick. Aber natürlich kann die Toolchain (in diesem Fall schon der Synthesizer) diese simplen (und auch wesentlich komplexere Beziehungen) erkennen und optimieren. Aber wie gesagt: das kann man in 5 Minuten selber mal kurz ausprobieren... Wobei man ntürlich auch in den ersten zwei Jahren mal eine Variable verwenden darf. Nur muss man sich zuvor mindestens solche einfachen Überlegungen gemacht haben. Aber man sollte keine Variablen nehmen, weil es gerade hipp ist oder einfacher scheint, und ein Professor oder ein Gaisler diese Methoden präferieren. Wobei man beim Professor natürlich schnell aufs Glatteis kommt, wenn man den > Mal angenommen man will die Berechnungen x=a+b+c und y=a+b+d durchführen. Hier mal ein paar Versuche und das Ergebnis des Synthesizers:
1 | library IEEE; |
2 | use IEEE.STD_LOGIC_1164.ALL; |
3 | use IEEE.NUMERIC_STD.ALL; |
4 | |
5 | entity MehrstufigeAddierer is |
6 | Port ( a : in unsigned (7 downto 0); |
7 | b : in unsigned (7 downto 0); |
8 | c : in unsigned (7 downto 0); |
9 | d : in unsigned (7 downto 0); |
10 | x : out unsigned (7 downto 0); |
11 | y : out unsigned (7 downto 0) |
12 | );
|
13 | end MehrstufigeAddierer; |
14 | |
15 | architecture Behavioral of MehrstufigeAddierer is |
16 | begin
|
17 | process (a,b,c,d) |
18 | variable z : unsigned (7 downto 0); |
19 | begin
|
20 | z := a+b; |
21 | x <= c+z; |
22 | y <= d+z; |
23 | end process; |
24 | end Behavioral; |
25 | --> Macro Statistics 8-bit adder : 3
|
26 | |
27 | |
28 | architecture Behavioral of MehrstufigeAddierer is |
29 | signal z : unsigned (7 downto 0); |
30 | begin
|
31 | z <= a+b; |
32 | x <= c+z; |
33 | y <= d+z; |
34 | end Behavioral; |
35 | --> Macro Statistics 8-bit adder : 3
|
36 | |
37 | |
38 | architecture Behavioral of MehrstufigeAddierer is |
39 | begin
|
40 | process (a,b,c,d) |
41 | begin
|
42 | x <= a+b+c; |
43 | y <= a+b+d; |
44 | end process; |
45 | end Behavioral; |
46 | --> Macro Statistics 8-bit adder : 3
|
47 | |
48 | |
49 | architecture Behavioral of MehrstufigeAddierer is |
50 | begin
|
51 | x <= a+b+c; |
52 | y <= a+b+d; |
53 | end Behavioral; |
54 | --> Macro Statistics 8-bit adder : 3
|
Fazit: schon der Synthesizer erkennt das Optimierungspotential und macht den Zwischenschritt über a+b.
Wenn man bei VHDL in Hardware denkt, braucht man niemals Variablen. ALLES lässt sich über Signale lösen. Echte Hardware kennt nur Signale und keine Variablen. Und da man mit synthetisierbarem HDL echte Hardware beschreibt, sind Variablen unnötig. Vielleicht reduzieren sie an der einen oder anderen Stelle den Codierungsaufwand ein wenig, aber NÖTIG sind sie zumindest aus meiner Erfahrung nie!
Nötig nicht, aber es ist angenehm sie zu verwenden. Das mache ich hin und wieder mal, um Verknüpfungen zu vereinfachen die sich über mehrere Zeilen erstrecken. Dann wirds übersichtlicher. Genauso wie Variablen kann man auch for und while in VHDL verwenden, wenn man versteht was es jeweils macht! Man muss ich nur klar darüber sein, dass Variablen und Schleifen nie im FPGA ausgeführt werden, sondern eben schon zuvor beim Übersetzen bearbeitet werden. Sobald Signal und Variable als zwei völlig unterschiedliche Dinge aufgefasst wurden, kann man sie nahezu gefahrlos beide verwenden. @lkmiller: Da stimme ich durchaus zu, man kanns auch übertreiben. Soviele Variablen wie Gaisler würde ich nie einsetzen.
meckerziege schrieb: > Nötig nicht, aber es ist angenehm sie zu verwenden. Hab ich ja auch geschrieben. Sie können den Codieraufwand reduzieren (oder eben den Code übersichtlicher gestalten). Wobei ein kleiner Code nicht zwingend ein übersichtlicher Code sein muss. Wenn man immer aufpassen muss, ob man es gerade mit einem Signal oder einer Variablen zu tun hat, kann das auch zu Fehlern führen. Außerdem denke ich, dass es gerade für Anfänger und wenig Erfahrene einfacher ist, die Hardware im Hinterkopf zu behalten, wenn man sich auf Signale beschränkt. Aber das ist natürlich Geschmackssache und bleibt jedem selbst überlassen, wie er sich wohlfühlt. Ich wollte nur sagen, dass es IMMER eine Lösung ohne Variablen gibt. Ob das immer die eleganteste ist, sei mal dahingestellt ;-) meckerziege schrieb: > Man muss ich nur klar darüber sein, dass Variablen und Schleifen nie im > FPGA ausgeführt werden, sondern eben schon zuvor beim Übersetzen > bearbeitet werden. Und das ist vielen leider nicht klar ;-) Ich stimmt dir voll zu: Wenn man weiss, was man tut, kann man beides verwenden.
Schlumpf schrieb: > Ich wollte nur sagen, dass es IMMER eine Lösung ohne Variablen gibt. Das wäre schön, aber tatsächlich ist es leider nur so, dass es nicht IMMER eine Lösung gibt. Auch ohne Variablen... :-( Aber wenn es eine Lösung mit Variablen gibt, dann kann man das Problem auch ohne Variablen lösen.
Lothar Miller schrieb: > Aber wenn es eine Lösung mit Variablen gibt, dann kann man das Problem > auch ohne Variablen lösen. hmm, XST user guide, dual-ported (B)RAM. Da ist eine (sogar) shared variable notwendig. Ich hab' allerdings noch nie ausprobiert, ob das auch ohne variable geht. Und ja, das ist halt auch was sehr spezielles...
berndl schrieb: > Ich hab' allerdings noch nie ausprobiert, ob das auch ohne variable > geht. Es geht, wenn du das RAM manuell als Komponente instantiierst. Das würde ich bei so einem Bauteil mit vielen weiteren Parametern auch zwingend empfehlen.
Lothar Miller schrieb: > Das wäre schön, aber tatsächlich ist es leider nur so, dass es nicht > IMMER eine Lösung gibt. Auch ohne Variablen... :-( Wie konnte ich mich nur so unpräzise audrücken :-) Wobei mein Chef da manchmal anderer Meinung ist... > Aber wenn es eine Lösung mit Variablen gibt, dann kann man das Problem > auch ohne Variablen lösen. So war´s natürlich auch gemeint..
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.