Hallo,
habe hier ein sonderbares Problem.
Ich werte einen 4bit-Vektor aus (TR_IN), und zwar jeweils 2 bits
zusammen
(also bit 3 und 2 und bit 1 und 0). Dies hatte ich ursprünglich so
gemacht:
---------------
if (TR_IN (1 downto 0) = "01") OR (TR_IN (1 downto 0) = "10") then
tr_imp_k1_tmp <= '1';
count_tr_of_k1 <= count_tr_of_k1 + 1;
end if;
if (TR_IN (3 downto 2) = "01") OR (TR_IN (3 downto 2) = "10") then
tr_imp_k2_tmp <= '1';
count_tr_of_k2 <= count_tr_of_k2 + 1;
end if;
if (TR_IN (1 downto 0) = "01") then
ef_1 <= '1';
end if;
if (TR_IN (3 downto 2) = "01") then
ef_2 <= '1';
end if;
----------------
Dieser Code verursachte im ganzen Projekt große Fehler.
Daraufhin habe ich nach langer Fehlersuche eine case-Anweisung daraus
gemacht, in der alle möglichen Konstellationen von TR_IN enthalten sind:
----------------
case TR_IN is
when "0001" =>
tr_imp_k1_tmp <= '1';
count_tr_of_k1 <= count_tr_of_k1 + 1;
ef_1 <= '1';
when "0010" =>
tr_imp_k1_tmp <= '1';
count_tr_of_k1 <= count_tr_of_k1 + 1;
when "0100" =>
tr_imp_k2_tmp <= '1';
count_tr_of_k2 <= count_tr_of_k2 + 1;
ef_2 <= '1';
when "1000" =>
tr_imp_k2_tmp <= '1';
count_tr_of_k2 <= count_tr_of_k2 + 1;
when "0101" =>
tr_imp_k1_tmp <= '1';
count_tr_of_k1 <= count_tr_of_k1 + 1;
ef_1 <= '1';
tr_imp_k2_tmp <= '1';
count_tr_of_k2 <= count_tr_of_k2 + 1;
ef_2 <= '1';
when "0110" =>
tr_imp_k1_tmp <= '1';
count_tr_of_k1 <= count_tr_of_k1 + 1;
tr_imp_k2_tmp <= '1';
count_tr_of_k2 <= count_tr_of_k2 + 1;
ef_2 <= '1';
when "1001" =>
tr_imp_k1_tmp <= '1';
count_tr_of_k1 <= count_tr_of_k1 + 1;
tr_imp_k2_tmp <= '1';
count_tr_of_k2 <= count_tr_of_k2 + 1;
ef_1 <= '1';
when "1010" =>
tr_imp_k1_tmp <= '1';
count_tr_of_k1 <= count_tr_of_k1 + 1;
tr_imp_k2_tmp <= '1';
count_tr_of_k2 <= count_tr_of_k2 + 1;
when others =>
null;
end case;
--------------------
Und diese Anweisung funktioniert tadellos.
Damit ist ja eigentlich alles klar und schön, nur hätte ich sehr gerne
verstanden, was an den obigen IFs falsch ist.
Sieht oder weiß da jemand was?
>ich denke, es fehlen einfach die else-Zweige in den if-statements, die>Signale werden nur gesetzt.
Das gleiche passiert ja auch bei der Case-Anweisung.
Die Signale werden anderswo zurückgesetzt.
>Ausserdem scheint in beiden Versionen die Flankenauswertung für die>Zähler zu fehlen (rising_edge ode so)
Das rundherum habe ich jetzt aus Platzgründen weggelassen,
ich habe nur das wesentliche reinkopiert. Wie schon geschrieben
funktioniert
der Code mit der Case-Anweisung 100%ig.
Mich wurmt nur, dass ich nicht weiß, warum das mit den ifs nicht klappt.
Würd auch sagen, dass es an den fehlenden else liegt. Dann werden evtl.
Latches synthetisiert. Versuchs doch einfach mal mit den else, ist ja
nicht so aufwendig. Oder aber, du setzt in dem Prozess ganz am Anfang
Standardwerte für die Signale, die in den ifs Werte bekommen (alle auf 0
zum Beispiel).
So wie es aussieht, werden in beiden Beschreibungen Laches erzeugt. Und
das ist grundsätzlich schonmal schlecht.
Versuch entweder in allen Bedingugen alle Singale zuzuweisen oder mach
den Prozess getaktet und register deine Signale.
Wenn keiner eine prompte Lösung hat, dann weil das problem in der
fragestellung nicht sichtbar ist.
#Dieser Code verursachte im ganzen Projekt große Fehler.
Was sind für Dich große Fehler? Brechen die Tools ab? Ist das Verhalten
ein anderes? Was verhält sich anders als erwartet? Ohne diese Antworten
können wir den Code nur auf unpraktische Schreibweise durchsuchen.
Oder ich rate: Multiple sources?; X im in der simu?
#Das rundherum habe ich jetzt aus Platzgründen weggelassen,
#ich habe nur das wesentliche reinkopiert. Wie schon geschrieben
#funktioniert
Packe reinkopierten code zwischen vhdl und /vhdl in eckigen Klammern und
benutze den Vorschaue-Button, dann sieht der Code besser aus wie hier:
Ich habe vor dem Code eine Zeile mit vhdl in [ ] geschrieben und danach
eine mit /vhdl auch in [ ].
Und du kannst den Code in einer Datei an Deine Anfrage anhängen.
Dein Problem wird zu 50% die "Rücksetzbedingung woanders im Code" sein.
Da kommt nur Murks raus. Das muss im selben prozess stehen, es muß nicht
unbedingt eine Else oder ein Elsif sein, aber wenn du ein FliFlop habe
willst dann muß in einem Prozess das Setzen und das Rücksetzten
beschrieben sein. Beispiel
1
architecturekarnickelofZauberwaldis
2
begin
3
4
process(clk_i)
5
begin
6
ifrising_edge(clk_i)then
7
ifsetz_signal='1'then
8
beispiel_1<='1'
9
elsifruecksetz_signal='1'then
10
beispiel_1<='0'
11
endif;
12
endif;
13
endprocess;
14
15
16
17
--irgendwo anders, hier besipielsweise außerhalb eines prozesses
18
19
setz_signal<=eingang1_iANDeingeang_3_i;
20
21
rücksetzsignal<=NOTeingang2_i;
22
23
endarchitecture;
Wohlgemerkt das Rücksetzten muss im selben prozess beschrieben sein, das
signal das das Rücksetzen auslöst kann irgendwo anders stehen.
Die anderen 50% deines Problems, warum das case tut und das If nicht,
ist sicherlich der Others Zweig mit dem Null. IMHO heisst das, das die
Signale nicht vom Prozess getrieben werden, wenn die When bedingungen
nicht erfüllt werden. Du kannst ja mal schreiben
1
whenothers=>;
2
3
--oder
4
5
whenothers=>
6
dummy_signal<='1';
Dann könnte das Case-Konstrukt genauso wirken wie das If. Oder du
schreibst:
1
if(TR_IN(1downto0)="01")then
2
ef_1<='1';
3
else
4
ef_1<=null;--vielleicht auch nur null
5
endif;
Aber das ist mE nur Dein verständnisproblem, dein Designproblem ist die
"Rücksetzbedingung sonstwo". Das ist nicht C, das ist eine
Hardware-beschreibungssprache. Und falls due ein FF willst, musst du in
einem Prozess, setzen und Rücksetzten beschreiben, aber nicht die eine
Hälfte in diesem Prozess und die andere in einem Zweiten. Und dann
vielleicht noch mit unterschiedlichen Takt(-flanken) }:-0 das geht
nicht! Aber ohne kompletten Code und Fehlerbeschreibung können wir nur
weiter raten. Aber schau mal nach was eine null zuweisung oder null in
VHDL tut.
Hallo,
erstmal vielen Dank für die reichlichen Antworten.
Ok, hier ist zweimal der gesamte Prozess, in dem die Anweisungen von
oben stehen, zuerst mit IF (der "Böse"), und dann mit Case:
So, das sollte schonmal einige der Punkte von euch klären.
Sorry, dass ich nicht gleich den ganzen Prozess geschickt habe,
aber ich wollte nicht einen endlos langen Thread machen. :)
So, zuerst zu den Fehlern.
Also der Prozess ist Teil eines relativ großen Designs.
Keine der beiden Varianten macht beim Synthetisieren Probleme,
das Design macht auf dem FPGA Probleme, und zwar in einem
ganz anderen Teil, der diesem Prozess vorgeschaltet ist
(dort wird das TR_IN erzeugt) und auch kein Feedback von diesem
Prozess hier bekommt.
>Würd auch sagen, dass es an den fehlenden else liegt. Dann werden evtl.>Latches synthetisiert.>So wie es aussieht, werden in beiden Beschreibungen Laches erzeugt. Und>das ist grundsätzlich schonmal schlecht.
Also das ganze Design ist eigentlich streng getaktet,
das TR_IN wird getaktet erzeugt und kommt so rein.
Oder verstehe ich das jetzt falsch, also Latches sind doch
NICHTtaktgesteuerte Register, oder (Wie heißen taktgesteuerte
eigentlich)?
>Aber schau mal nach was eine null zuweisung oder null in VHDL tut.
Öhm, also in meinen Büchern steht prinzipiell "Nichts".
Also es macht nichts. Und das soll es hier ja auch.
Aber hier besteht (bei mir) durchaus noch Klärungsbedarf,
also bitte belehrt mich. :)
Habe ich das jetzt richtig verstanden, dass das ganze laufen sollte,
wenn ich bei den IFs jeweils schreibe "else NULL;" ?
Weil ich dachte, dass das sowieso nix macht, wenn da nur IF sowieso
steht.
IF Q = '1' then A = '1' heißt doch, wenn Q 1 ist, setze A auch auf 1.
Und wenn nicht, also wenn Q nicht 1 ist, mach bitte nix.
Oder verstehe ich das falsch?
Hm, also Null schaltet den Signaltreiber ab, ansosnsten treibt er den
vorhergehenden wert.
Also
(1)die bedingung zum setzten wird erfüllt dann wird eine '1' getrieben
(2)keine bedingung wird erfüllt, aber vorher war die setzbedingung wird
erfüllt -> es wird immer noch eine '1' getrieben
(3) es wird Null gesagt (wie auch immer) dann bleibt die eins wenn kein
andere Quelle das signal treibt, ansosonsten gewinnt das andere Signal
(4) es wird eine '1' getrieben (weil (1) oder (2) und wg. einer anderen
bedingung wird eine '0' getrieben, dann kommt X raus.
Also Null heisst nicht das nix passiert, es heisst das von dieser stelle
nix neues passiert (signaltreiber abgeschaltet), von anderen stellen
kann was passieren. Wenn zwei stellen treiben dann geht es durch die
resolution funktion also bei std_logic:
stelle 1 stelle2 Ergebnis
'1' '0' X
'1' 'Z' 1
'1' '1' 1 (?), ich bion mir nicht sicher eventuell auch X
'1' null '1'
'0' null '0'
'1' 'u' 'u' oder 'X'
u heisst unassigned, also wert wurde noch nie zugewiesen, nicht zu
wechseln mit 'X' -> unknown -unbekannt (z.B. wg. crash('1' und '0'von
zwei Quellen ))?
#IF Q = '1' then A = '1' heißt doch, wenn Q 1 ist, setze A auch auf 1.
#Und wenn nicht, also wenn Q nicht 1 ist, mach bitte nix.
#Oder verstehe ich das falsch?
wahrscheinlich, es heisst wenn Q nicht 1 dann ÄNDERE nix also der alte
Wert wird getrieben -> typ. VBerhalten eines FF.
Ändere Nix ist nicht da selbe wie MACH nix. Mach nix heisst Null
(Signaltreiber abschalten).
Vielleicht kann man sagen, mach nix gibt es im FPGA nicht und daher im
synthetisierbaren VHDL auch nicht. IM Fpga gibt es Änderen oder nicht
ändern, aber gemacht wird immer was. (schlecht zu beschreiben das ist)
Ok, das hab ich soweit verstanden.
Mach nix heißt in dem Fall dann halt nur "lass es so, wie es ist".
Ist dann dieses null gleichzusetzen mit einer Tristate-Konstruktion,
also wie z.B. bei einem bidirektionalen Datenbus, den ich so steuere:
Kann man sowas auch mit "null" machen?
Ich habe jetzt mal probehalber in der IF-Version
bei allen verzweigungen "else null;" eingefügt,
der Fehler bleibt aber der gleiche...
Ich glaube man muß unterscheiden zwischen dem NULL statement oder der
NULL Zuweisung.
if Q = '1' then
A <= '1';
else
null;
end if;
bewirkt daß A sich nicht ändert.
Aber
if Q = '1' then
A <= '1';
else
A <= null;
end if;
schaltet den Driver ab. Wird nicht sehr oft verwendet, mir war die null
Zuweisung jedenfalls unbekannt und kann für die Synthese sicher nicht
verwendet werden.
Also der erste sichtbare Unterschied den ich sehe ist das Null
statement, sonst ist alles gleich. wenn null nicht dasselbe macht wie <=
null (warum auch); da liege ich natürlich mit meiner vermutung falsch.
Und es kann nicht darin liegen.
Ein anderer Unterschied ist das when eigentlich mit if elsif übersetzt
wird. Also so wie du dein If schreibst, passt kein elsif, da sehe ich
also (noch) kein Problem.
Sowie es klingt, verhalten sich die synthetisierten designs
unterschiedlich,
also wird wohl der (eigentlich funktional identische) Code
unterschiedlich übersetzt. Da könnt was im synthesereport stehen
(Xilinx: *.syr).
Naja, ich behandele das TR_IN ja schon unterschiedlich,
bei den IFs frage ich die ersten und letzten beiden Bits getrennt ab,
wogegen ich bei dem Case-Statement alle möglichen auftretenden Fälle
abhandele.
In einem getakteten Prozess kann es nicht an Latches liegen und du
kannst die else weglassen, das stimmt, aber das konnte man aus deinem
ersten Post ja nicht ablesen.
Die Frage, die ich mal in den Raum stellen würde ist, ob dein Code
überhaupt das gleiche macht? Mit den if fragst du nur den folgende Fälle
ab, in denen was passiert:
"0101","0110","1001","1010"
Im case-statement wird z.B. auch bei "0001" was ausgeführt...? Wie das?
Vielleicht solltest du mal ein paar Differenzen der
Simulationsergebnisse posten, dann würde eine Analyse wesentlich besser
funktionieren. Oder funktioniert die Simulation gleich und nur direkt
der Test auf dem FPGA macht Probleme?
@Christian:
>können nur 00,01 oder 10 sein, nicht aber 11
Das weißt aber nur Du und nicht der Compiler. Änder doch mal den letzten
case -Fall, dass Du 10 und 11 zu "when others" zusammenfasst.
Rick
Ich vermute mal, dass deine großen Probleme darin liegen, dass das
Design so in etwa läuft, aber manchmal (jede Sekunde, jede Minute, jede
Stunde, einmal am Tag) nicht so richtig tut.
Das sind die wirklich großen Probleme.
And now ladies and gentlemen, we proudly present:
-->> Der kombinatorische asynchrone Reset <<--
1
:
2
if(RESET='1')OR(tr_count_del='1')OR(SOA='0')then
3
:
Ich hatte da auch mal so ein Design, da waren in der Rücksetz-Bedingung
so ähnliche Konstrukte. Das lief, solange die Steuerung kalt war, aber
nach einer Stunde wars vorbei. Dann habe ich irgendwas im Code geändert,
und dann hat sich irgendwas im Verhalten der Steuerung geändert.
1) So einen kombinatorischen Reset darf es nicht geben (es sei denn man
liebt Probleme)
2) in die Process-Sensitivity-List gehören maximal Reset und Takt,
besser noch: nur der Takt (Reset ist dann synchron)
Es ist eben so: wenn eines der Rücksetz-Signale z.B. von einem Zähler
kommt und/oder sonstwoher kombinatorisch erzeugt wird, gibt es einen
kurzen Glitch und ein paar der FFs werden zurückgesetzt (aber eben nicht
alle und noch fieser: nicht immer die selben).
Probiers doch mal eher so:
@Lothar: Vielen Dank für deine Antwort!
Erstmal nur ganz schnell: das "böse" Reset habe
ich doch aber auch in der anderen Variante, und dort
läuft das Design tadellos?!
@Christian: Ja, wie gesagt, es läuft schon, meistens.
Aber du darfst so ein Design nicht großartig ändern (z.B. auch andere
Zielhardware), denn sonst ändert sich das FPGA-interne Layout, damit das
Timing und: RUMMS.
Wirklich transportabel und reproduzierbar ist nur ein komplett
synchrones Design: alle Zustände ändern sich ausschliesslich mit dem
Takt, einzige Ausnahme: der (oft unnötige [aber das ist eine andere
Sache]) externe asynchrone Reset.
Wobei ich immer auch so einen Reset erst mal synchronisiere und dann im
FPGA intern verwende.