Forum: FPGA, VHDL & Co. Zuweisungen überschreiben in VHDL


von Christian (Gast)


Lesenswert?

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) is begin
2
   if rising_edge(CLK) then
3
      i<=i+1;
4
      if i=10 then
5
         i<=0;
6
      end if;
7
   end if;
8
end process;

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) is begin
2
   if rising_edge(CLK) then
3
      if busy='0' then
4
         if init='1' then
5
            init_request<='1';
6
            busy<='1'
7
         elsif anderer_befehl='1' then 
8
9
(... andere befehle abfangen...)
10
11
         end if;
12
      end if;
13
14
15
16
      case (state) is
17
         when waiting =>
18
            if init_request='1' then
19
               state <=init_start;
20
               busy<='0';
21
               init_request<='0';
22
            elsif
23
24
(... weitere Fälle)
25
26
            elsif adc_busy ='0' AND autonomer_modus='1' then
27
               state <= autonome_funktion;
28
            end if;
29
30
(... weitere Zustände des Automaten ...)
31
32
         end case;
33
   end if;
34
end process;

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

von PittyJ (Gast)


Lesenswert?

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.

von Peter B. (funkheld)


Lesenswert?

...........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

von berndl (Gast)


Lesenswert?

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...

von Rolf S. (audiorolf)


Lesenswert?

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?

von Lothar M. (Firma: Titel) (lkmiller) (Moderator) Benutzerseite


Lesenswert?

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?

von R. F. (rfr)


Lesenswert?

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

von Christian (Gast)


Lesenswert?

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.

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
Noch kein Account? Hier anmelden.