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<=clk1orclk2;-- 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
ifclk='1'andclk'eventthen
8
...
9
-- mal angenommen, eine steigende Flanke von clk1 wäre der Grund,
10
-- dass wir hierher kommen
11
ifenable1='1'andclk1='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
elsifenable2='1'andclk2='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...
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 :-(
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 ;-)
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.
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
libraryIEEE;
2
useIEEE.STD_LOGIC_1164.ALL;
3
useIEEE.NUMERIC_STD.ALL;
4
5
entityMehrstufigeAddiereris
6
Port(a:inunsigned(7downto0);
7
b:inunsigned(7downto0);
8
c:inunsigned(7downto0);
9
d:inunsigned(7downto0);
10
x:outunsigned(7downto0);
11
y:outunsigned(7downto0)
12
);
13
endMehrstufigeAddierer;
14
15
architectureBehavioralofMehrstufigeAddiereris
16
begin
17
process(a,b,c,d)
18
variablez:unsigned(7downto0);
19
begin
20
z:=a+b;
21
x<=c+z;
22
y<=d+z;
23
endprocess;
24
endBehavioral;
25
--> Macro Statistics 8-bit adder : 3
26
27
28
architectureBehavioralofMehrstufigeAddiereris
29
signalz:unsigned(7downto0);
30
begin
31
z<=a+b;
32
x<=c+z;
33
y<=d+z;
34
endBehavioral;
35
--> Macro Statistics 8-bit adder : 3
36
37
38
architectureBehavioralofMehrstufigeAddiereris
39
begin
40
process(a,b,c,d)
41
begin
42
x<=a+b+c;
43
y<=a+b+d;
44
endprocess;
45
endBehavioral;
46
--> Macro Statistics 8-bit adder : 3
47
48
49
architectureBehavioralofMehrstufigeAddiereris
50
begin
51
x<=a+b+c;
52
y<=a+b+d;
53
endBehavioral;
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..