Hallo,
ich möchte mal einen Thread für Einsteiger in die VHDL-Programmierung
aufmachen in dem eine Sammlung von "Do's und Do not's" enstehen soll.
Es ist (gerade) für Leute die sich mit Software beschäftigen und dann
mit VHDL in Berührung kommen eine kleine Hilfe aufwendige Fehlersuche zu
vermeiden.
Ich mache mal den anfang :
(man möge mich korrigieren wenn ich quark-mist erzähle ...)
Do Not :
--------
process (...)
begin
if clk'event and clk = '1' and clk_enable = '1' then
...
end if;
end process;
Das ist ein gated Clock. Führt dazu das glitches auftreten können und
der "gegatete" Clock nicht mehr 100% synchron zum eigentlichen Clock ist
(lautzeit des und gatters). Böse Falle.
Do Not :
--------
Bsp :
signal a : std_logic;
signal b : std_logic;
signal c : std_logic;
process (clk)
begin
if clk'event and clk = '1' then
begin
a <= b and c;
end if;
end;
Man sollte immer alle beteiligten (eingangs-)signale in der sensivity
list eines prozesses haben.
Sonst kann es passieren das der Synthesizer was anderes synthetisiert
als man ursprünglich vorhatte zu implementieren (Beispiel Latch <->
Flipflop).
Es sollte dann heißen :
process (clk, b, c)
...
Erstes Don't stimmt so. Man sollte noch hinzufügen dass bei gated Clocks
A) Glitches auftreten können und b) Clock Skew. Beides ist böse ;-)
Und man sollte noch die korrekte Version hinschreiben.
Das zweite ist falsch! Es gibt praktisch nur zwei Sorten von Prozessen,
getaktete und rein kombinatorische. Erstere brauchen nur den Takt und
ein evtl. vorhandenes asynchrones reset in der Sensitivity List, der
Rest ist vollkommen egal und korrekt! Kombinatorische Prozesse brauchen
natürlich alle Eingangsvariablen in der Sensitivity List, sonst gibts
böse Simulationsfehler !!! (IIRC, Modelsim meldet keine Fehler bei
fehlenden Signalen in der Sensitivity List, was auch vom Konzept von
VHDL vollkommen in Ordnung ist). Das Syntheseergebnis wird AFAIK dadurch
nicht verfälscht, weil die Compiler meist gutmütig genug sind, und
"intern" alle Eingangsvariablen in die Sensitivity List eintragen
(während der Synthese).
MfG
Falk
Ich bin absolut dafür, daß nur KOMPETENTE Personen sich aufschwingen,
und dd-Listen in Newsgroups posten, sodaß nichr diskutiert werden muss.
sonst bringt man den Leuten noch einen Mist bei
> sonst bringt man den Leuten noch einen Mist bei
so what?
TheMason bekommt seine Selbstbestätigung, ein Neuling glaubt etwas Mist.
Maßt du dir an zu beurteilen ob die Nachteile die Vorteile überwiegen?
Ohne Anspruch auf allgeingültiges "mach immer" oder "Mach Nie"
Für VHDL Code der zu FPGA/CPLD synthetisiert wird:
-Nur Richtung IN und OUT an Ports verwenden, bei der Top Entity an
Tristate-Bussen auch IONOUT.
-Zuweisung auf Z nur in der architecture der TOP Entity.
(das thema interne Tristates bei Spartan2/2E lassen wir hier aus)
-Genau eine Bibliothek mit unsigned verwenden.
(also nicht USE IEEE.numeric_std.all,USE IEEE.std_logic_arith.all, ...
in einem File oder in mehreren Files zu einem Design) mischen
-Möglichst Nur prozesse mit Takt und evt. asynchronen reset verwenden
Siehe Vorredner. Kombinatorische Prozesse (prozess ohne clk, aber allen
anderenEingangssignalen in der sense list) nur bei Strukturen mit
wählbarer Bitbreite einsetzen.
-für Indezies von vectoren Zählrichtung und grenze nicht mischen.
( also nur ...(.. DOWNTO 0) verwenden.
-feldattribute wie 'range 'low 'high benutzen
-die feldattribute 'left 'right nicht benutzen
-eigene Typen definieren, nicht nur für FSM:
1
ausgang_o<=adu1_wert_iwhenmux_select=ADUelse
2
Status_reg_qwhenmux_select=STATUSelse
3
C_Version_numberwhenmux_select=VERSION;
-beautifier benutzen (z.b Emacs vhdl mode)
-Prä/postfixe an signal namen etc. verwenden
z.B. o für Ausgangsport _i für Eingänge _q für Signale aus FF V für
variablen
...
Die Signalnamen auf den verschiedenen Designebenen geignet benennen,
sodaß z.B: verbindende Signale auf der top level Ebene immer mit tl_
anfangen, in einem modul, daß z.B. uart realisiert, alle signale mit
ua_.
Richtungskritsche Signale , die Instanzen verbinden immer als "from-to",
d..h. tl_data_mctrl_ram wäre ein top level Datensignal VOM main
controller ZUM Ram. Damit verdeutlichlicht sich die Datenrichtung.
Vermeiden sollte man betrachtungsabhängige Bezeichung, wie IN und OUT,
sondern lieber "to_modul_x" oder "from_data_modul_x". Damit ist die
Flussrichtung klar und man kann auch anonym deklarierte Ports iwe "in,
out" fehlerfrei ohne Nachzudenken andrahten. Optimal ist es natürlich,
wenn auch die Ports der Komponenten und Instanzen einddeutige Ins und
Outs haben. Oft sehe ich aber leider designs, wo Ins mit Ins und Ins mit
Outs verbunden sind, die Betrachtung als mischt.
Für Komponenten empfiehlt sich eine Gruppierung der Ports in System, In,
InOut und Out, bei "System" die für den Betrieb und Test nötigen Signale
enthält, während die anderen 3 echte logische Datenpfade sind. So kennt
ein Videocontroller (vc), der einen Datentakt aber natürlich auch noch
einen FPGA-Systemtakt hat und zu Testzwecken abgeschaltet und
paramteriert werden kann, folgende Signale: (downtos für Buse
weggelassen und auch suffixe _i, _o fallen an den ports dann weg, dann
in und out ja klar wird)
-- system
vc_fpgaclock_i, vc_test_enable_i, vc_testpattern_i, vc_test_error_o
-- inputs
vc_ videoclock, vc_data_from_adc, vc_from_dsp_chain, vc_adr_from_dsp,
vc_test_image
-- inouts
vc_video_databus
-- outputs
vc_vid_signals_out, vc_to_statusreg, vc_to_dsp_chain, vc_error_out
Man beachte z.B. die dsp_chain Verdrahtung sowie die Tatsache, daß der
FGPA-Clock ein FPGA-Signals, während der Videotakt ein
Applikationssignal darstellt, das es auch in einer Analogelektronik
gäbe. Man unterscheide vor allem auch die Testmuster, die man in jedem
Modul eines jeden FPGA-Designs anlegen könnte, um Module anzuregen,
Standarddaten zu senden (System) und das Videotestmuster, dass es nur in
einem Video-FPGA gibt, ergo bei den operational signals steht.
Das, was hier im Bereich System steht, könnte (und sollte?) also in
JEDEM FGPA-Desing zu finden sein, zumindest bei logisch komplex
agierenden Modulen mit vielen Zustanden und Datenoperationen.
Bei größeren Designs lohnt der Einsatz von Mentor's FLI. Ersatzmodelle
in C können aufwendige Simulationen deutlich beschleunigen (natürlich
ist ein Ersatzmodell immer mit Vorsicht zu behandeln). Ausserdem lassen
sich per FLI sehr bequem große Datenmengen in das eigene Design
einspeisen bzw. daraus abführen (z.B. Videosequenzen).
Sinnvoll:
* Lesbaren Code schreiben
- einheitliche Notation
- sinnvolle Signalnamen
- alles ordentlich einrücken
- Kommentare einfügen
- File-Header mit Autor, Kurzbeschreibung, evt. History
- kurze Bezeichner wählen
- alle Möglichkeiten von VHDL konsequent nutzen
- keinen Code schreiben, der aussieht wie von einem Tool erzeugt ;-)
- rising_edge() falling_edge() anstelle des unsäglichen clk'EVENT and
clk='1'...
* Synchrone Designs erstellen
- in einem synchr. Design sind alle Signale synchron zu einem Takt, auch
die I/O-Signale
- manchmal benötigt man mehrere Clocks, diese sollten ebenfalls alle
synchron sein
* sparsam mit Variablen umgehen
- Variablen können zu unerwünschten Effekten führen, wenn man den
Unterschied zu Signalen nicht verstanden hat. Deshalb so viele Signale
wie möglich
* Wiederverwendbaren VHDL-Code schreiben
- mit Generics arbeiten
- Konstanten in Packages verwenden
- klare Gliederung des Codes
- Bitbreiten sollten leicht anzupassen sein, also wie schon oben
beschrieben mit Feldattributen arbeiten, dabei gibt es keine Verbote
- wenn möglich und sinnvoll, dann alles parametrierbar machen
... die Liste ist unvollständig ...
Noch ein paar Bemerkungen zu dem, was ich weiter oben gelesen habe:
'Zuweisung auf Z nur in der Top-architecture' ... was soll der Unfug,
ich möchte im Prozessor-Interface oder im I2C-Core schon Z zuweisen
können!
'Signalnamen mit Präfix für die Hierarchieebene' ... jedes Synthese- und
Simulationstool kann mit Hierarchien umgehen, das habe ich noch nie
benötigt
Kombinatorische Prozesse sind genauso erlaubt wie getaktete. Wie soll
man sonst z.B. den Adressdecoder für ein Prozessorinterface beschreiben?
Dafür krieg ich jetzt bestimmt Klassenkeile, aber ich würde sagen: Leute
die keine ausreichende Erfahrung mit VHDL haben, sollten keine DOs und
DONTs schreiben. Das schafft mehr Verwirrung als Aufklärung und führt zu
irgendwelchen Mythen.
FPGA-User schrieb:
>- rising_edge() falling_edge() anstelle des unsäglichen clk'EVENT and>clk='1'...
...dagegen habe ich gerade heute bei einem kleinen Modul namens
"simple_SPI" verstossen, denn mit
> if clk'event and clk=activeClockLevel then ...
liess sich schnell und einfach via Generic der SPI-Mode definieren.
(Geht sicher auch anders, aber ich hab' das Modul nur schnell mal
heruntergeklopft...)
Hi Stefan,
klar, in dem Falle ist das sinnvoll - sind ja alles keine Gesetze,
sondern nur Vorschläge.
Aber da muss man wirklich wissen was man tut. Ich kenne das Design
nicht, aber der Wechsel auf eine andere Taktflanke könnte auch dazu
führen, dass nichts mehr geht.
Die Code-Lesbarkeit halte ich übrigens für genauso wichtig wie synchrone
Designs und Timing-Constraints, nichts ist schlimmer, als ein Stück VHDL
bei dem man erst wieder Stunden braucht um durchzublicken.
> - manchmal benötigt man mehrere Clocks, diese sollten ebenfalls alle> synchron sein
Das ist aber ein wenig unverständlich. Wenn ich mehrere Taktblöcke
(Clock domains) habe, dann können die ruhig zueinander asynchron sein
(sind es meist auch), allerding die einzelnen Blöcke an sich sind ein
synchrones Design. Der Übergang von Daten und Steuersignalen muss dann
vorichtig und gemäss bekanter Reglen erfolgen (Asynchrone FIFOs,
Synchonizer FlipFlops, Gray Code, etc.)
MFG
Falk
"'Signalnamen mit Präfix für die Hierarchieebene' ... jedes Synthese-
und
Simulationstool kann mit Hierarchien umgehen, das habe ich noch nie
benötigt"
Das genau ist der häufig gemachte Denkfehler. Es geht nicht darum, daß
das Tool es etwa nicht könnte oder man sich selber nicht zurecht findet,
sondern um das Erkennen und Wiedererkennen durch andere Teamarbeiter,
wenn sie sich in einem Design zurechtfinden müssen. In vielen Tools oder
nach Export der Netzliste geht die vordergrüngie Hierarchie darüber
hinaus verloren.