Hallo,
In einem (komplett synchronen) VHDL Design bin ich auf etwas
eigenartiges gestoßen: Ein Teil einer Statemachine wird abgearbeitet,
obwohl dieser Teil nicht erreicht werden kann. Ein Signal müsste dafür
'1' sein, wird aber mit '0' initialisiert und nur an verschiedenen
Stellen auf '0' gesetzt.
In der Simulation tut alles das, was es soll, in der Hardware nicht.
Vielleicht liegt es daran wie ich es beschrieben habe.
Mein Wissensstand: Wenn in einem Prozess ein Signal mehrfach zugewiesen
wird, so werden alle Zuweisungen ignoriert, bis auf die letzte.
Beispiel:
1
Process(CLK)isbegin
2
ifrising_edge(CLK)then
3
i<=i+1;
4
ifi=10then
5
i<=0;
6
endif;
7
endif;
8
endprocess;
Produziert meiner Meinung nach für i die Folge 0,1,2,...,10,0,1,...
Erste Frage: Ist das guter Stil? Mir gefällt es ehrlich gesagt. In VHDL
finde ich eine Art But-If-Statement gut. Zuerst den Standardfall, dann
den Spezialfall. So finde ich es einfacher ein Design zu beschreiben. Es
entspricht eher der Weise in der ich denke.
Zweite Frage: Funktioniert das immer?
In meinem aktuellen Design habe ich eine Statemachine, die nur im
Wartezustand Befehle annehmen kann. Normalerweise würde ich einfach ein
Busysignal verwenden. Allerdings kann die Statemachine auch den
Wartezustand verlassen, wenn kein Befehl von außen kam. D.h. wenn das
von außen auf den FPGA zugreifende C++-Programm abfragt ob die
Statemachine Busy und nein als Antwort erhält, so heißt das nicht, dass
das kurz später immernoch so sein muss.
Daher habe ich im gleichen Prozess eine Art query-Speicher eingebaut.
Der Befehl von Außen geht nicht mehr direkt an die Statemachine, sondern
an einen Puffer, der genau eine Anforderung samt Parametern
zwischenspeichern kann. Ist der Zwischenspeicher gefüllt, so sieht man
außen das busy-signal. Das funktioniert auch zusammen mit dem
C++-Programm, da der Zwischenspeicher sich nicht selbstständig füllen
kann. Die autonome Funktion läuft nur innerhalb der Statemachine.
Auszug aus der Implementation (aus dem Kopf geschrieben):
1
Process(CLK)isbegin
2
ifrising_edge(CLK)then
3
ifbusy='0'then
4
ifinit='1'then
5
init_request<='1';
6
busy<='1'
7
elsifanderer_befehl='1'then
8
9
(...anderebefehleabfangen...)
10
11
endif;
12
endif;
13
14
15
16
case(state)is
17
whenwaiting=>
18
ifinit_request='1'then
19
state<=init_start;
20
busy<='0';
21
init_request<='0';
22
elsif
23
24
(...weitereFälle)
25
26
elsifadc_busy='0'ANDautonomer_modus='1'then
27
state<=autonome_funktion;
28
endif;
29
30
(...weitereZuständedesAutomaten...)
31
32
endcase;
33
endif;
34
endprocess;
Nach meinem Verständnis müsste das so (oder ähnlich) funktionieren, hat
es in der Simulation auch, in Hardware aber nicht.
Prinzipieller Fehler? Oder irgendwo ein Bug, den ich nicht gefunden
habe?
Wie gesagt, in Hardware hat es nicht funktioniert. Daher habe ich nach
und nach Teile raus genommen. Nachdem ich alles vor case raus genommen
habe lief der autonome Teil wieder.
Dann habe ich einzelne Teile wieder rein genommen (z.B. den INIT-Teil
oben im Beispiel). Dort habe ich aber alle Zuweisungen auf <='0'
geändert. Der Teil der Statemachine sollte also nicht beeinträchtigt
sein. Dann lief es nicht. Der autonome Teil wurde nicht gestartet, es
muss also etwas vorher ausgeführt worden sein.
Ich fände es sehr ärgerlich, wenn dieses Überschreiben nicht
funktioniert.
An einer anderen Stelle habe ich ein Design, das ähnlich wie ein RAM
aufgebaut ist.
Implementiert ist es mit einer großen Case-Verzweigung. Je nach dem
welche "Adresse" anliegt, werden verschiedene Daten ausgegeben. Oft ist
bei dem Datenwort nur ein Bit oder einzelne Bits belegt. Früher wurden
in jedem Fall alle nicht verwendeten Bits mit '0' beschrieben.
Jetzt schreibe ich einmal vor der Case-Verzweigung
1
Datenwort<=(Others=>'0');
Danach werden innerhalb der einzelnen Fälle die genutzten Bits
überschrieben.
Erhöht die Lesbarkeit enorm, reduziert die Anzahl von Zeilen, die
geschrieben werden müssen. Hat bisher immer in Simulation und Hardware
funktioniert. War das nur Glück?
Schöne Grüße,
Christian
Mein Ziel ist es, dass ich nach 2 Jahren, wenn ich den Code wieder
herausholen muss, diesen auf Anhieb verstehe.
Der Code muss einfach sein, auf Anhieb klar erkennbar, ob die Schleife
nun bis 9,10 oder 11 geht. Man solle nicht nicht gross denken müssen.
Von daher kommt für mich nur
Process (CLK) is begin
if rising_edge(CLK) then
if i>=10 then
i<=0;
else
i<=i+1;
end if;
end if;
end process;
in Betracht. Da gibt es keinen Sonderfall, der noch mit ins Spiel kommt.
Meine Meinung.
...........Ist das guter Stil?............
Habe den Mut das selber zu entscheiden.
Mach es so wie es dir gefällt, sonst wirst du nicht glücklich.
Es gibt hier im Forum 100 Hinweise die richtig und falsch sind.
So etwas darfst du hier nicht fragen.
Gruss
PittyJ schrieb:> Von daher kommt für mich nur>> Process (CLK) is begin> if rising_edge(CLK) then> if i>=10 then> i<=0;> else> i<=i+1;> end if;> end if;> end process;>> in Betracht.
hast fuer den Fall auch Recht, das so zu schreiben. Die Synthese
optimiert das sowieso noch (meistens) recht gut.
Die Default-Zuweisung am Anfang (vor if oder case) ist sehr schoen, wenn
du z.B. viele if-elsif oder case hast, und nur in einem oder 2 Faellen
ein Signal gesetzt wird. Dann ist die Default-Zuweisung vor dem
conditional einfacher zu lesen und vor allem weniger zu tippen (x-mal
signal inaktiv z.B.).
Nur meine 2 cents...
Christian schrieb:> Produziert meiner Meinung nach für i die Folge 0,1,2,...,10,0,1,...
Überhaupt nicht d'accord. Ich finde eindeutige Beschreibungen nötig, wo
sofort erkennbar ist, welcher Fall eintritt und nicht erst gesucht
werden muss um zu erkennen, ob die Bedingungen nicht erfüllt sind und
deshalb der Standard gilt. Für den Standard schreibt man "else".
Habt Ihr Coding Styles in eurer Company?
Christian schrieb:> D.h. wenn das von außen auf den FPGA zugreifende C++-Programm abfragt
Wie kann ein C++ Programm auf ein FPGA zugreifen? M.E. sind das zwei
verschiedene Abstraktionsebenen...
Wie auch immer: ist "das C++ Programm" auch synchron?
Christian schrieb:> Nach meinem Verständnis müsste das so (oder ähnlich) funktionieren, hat> es in der Simulation auch, in Hardware aber nicht.
Immer nicht oder manchmal nicht?
Christian schrieb:> In meinem aktuellen Design habe ich eine Statemachine, die nur im> Wartezustand Befehle annehmen kann. Normalerweise würde ich einfach ein> Busysignal verwenden. Allerdings kann die Statemachine auch den> Wartezustand verlassen, wenn kein Befehl von außen kam. D.h. wenn das> von außen auf den FPGA zugreifende C++-Programm abfragt ob die> Statemachine Busy und nein als Antwort erhält, so heißt das nicht, dass> das kurz später immernoch so sein muss.
Deine Statemaschine scheint eigensinnig zu sein. Villeicht solltest du
dir eine Liste der Ereignisse aufstellen, die ein Verlassen des
Wartezustandes der Statemachine auslösen. Hierbei spielt es keine Rolle,
ob C++ das auslöst oder sonstwas, die Auslösung wird ausschliesslich
durch Signale der Statemaschine beschrieben. Dies ist der Sollzustand.
Entweder an diesem stimmt was nicht, oder es treten Zustände ein, die
nicht dem Sollzustand entsprechen und somit auch nicht in der Tabelle
enthalten sind. In beiden Fällen ist man einen Schritt weiter: man
weiss, was das Problem auslöst.
Viele Grüsse
Robert
Peter Bierbach schrieb:> Habe den Mut das selber zu entscheiden.> Mach es so wie es dir gefällt, sonst wirst du nicht glücklich.
Naja, guter Stil ist ja nicht nur Selbstzweck. Einerseits muss man
manchmal auch mit anderen zusammenarbeiten und denen will man die Arbeit
ja auch nicht unnötig schwer machen. Andererseits mögen sich in manchem
Stil manche Dinge schwieriger gestalten. Und das ist ja nicht immer
direkt klar. Wenn mir jemand der 1E6 Zeilen VHDL Code mehr Erfahrung hat
als ich, würde ich schon auf ihn hören.
Rolf Sassinger schrieb:> Habt Ihr Coding Styles in eurer Company?
Nein. Ich würde gerne mal was einführen. Kostet aber auch alles wieder
Zeit...
Lothar Miller schrieb:> Wie kann ein C++ Programm auf ein FPGA zugreifen? M.E. sind das zwei> verschiedene Abstraktionsebenen...> Wie auch immer: ist "das C++ Programm" auch synchron?
Das habe ich natürlich sehr verkürzt dargestellt, da meiner Meinung nach
nur am Rande relevant. Auf einem Rechner läuft ein Programm, das über
ein Interface mit einer FPGA kommunizieren kann. Im Prinzip verhält es
sich wie ein Speicher auf den man zugreifen kann. z.B. kann man über
einen Schreibzugriff eine Statemachine anschubsen, die einen DAC über
SPI konfiguriert.
Sendet man mehrere Befehle nacheinander muss klar sein das der folgende
Befehl verarbeitet werden kann oder im Buffer / FIFO Platz ist.
Kann man natürlich auch abfragen. Wenn sich das zwischen abfragen und
und Befehl senden zum schlechten ändert ist die abfrage vorher natürlich
zwecklos.
Was meinst du mit synchronem C++-Programm?
>> Nach meinem Verständnis müsste das so (oder ähnlich) funktionieren, hat>> es in der Simulation auch, in Hardware aber nicht.> Immer nicht oder manchmal nicht?
In Hardware immer nicht.
R. Freitag schrieb:> Deine Statemaschine scheint eigensinnig zu sein. Villeicht solltest du> dir eine Liste der Ereignisse aufstellen, die ein Verlassen des> Wartezustandes der Statemachine auslösen. Hierbei spielt es keine Rolle,> ob C++ das auslöst oder sonstwas, die Auslösung wird ausschliesslich> durch Signale der Statemaschine beschrieben. Dies ist der Sollzustand.
Was ich gesehen habe: Eigentlich sollte die Statemachine automatisch in
einen Zustand gehen, sofern keine Anfrage kommt, die höhere Priorität
hat.
Die Anfragen habe ich alle "deaktiviert" (Signal mit '0' initialisiert,
nirgendwo auf '1' gesetzt), trotzdem geht die Statemachine nicht
automatisch in den angesprochenen Zustand.
Ich habe es inzwischen anders gelöst:
Das ganze ist in zwei Prozesse aufgeteilt. Einer mit der Statemachine,
der andere in dem die Anfragen zwischengespeichert werden.
Sobald die Statemachine im Wartezustand ist wird das Register, in dem
die Anfrage gespeichert ist, wieder zurückgesetzt.
Nachteil: Meiner Meinung nach unübersichtlich, da man beide Prozesse
kennen muss, um zu wissen was das Design macht.
Vorteil: Funktioniert.
Die bisherigen Posts verstehe ich so, dass es eigentlich funktionieren
müsste, wie ich es ursprünglich gemacht habe.
Die mir wichtigste Frage, ob es prinzipiell geht, ist damit geklärt.
Eine rechte Idee warum es nicht lief habe ich aber nicht.
Dann habe ich wohl irgendwas übersehen.