Ich bin blutiger Anfänger in Sachen VHDL und bekomme bestimmt die
Schelten um die Ohren gehauen. Ich versuche mich aber trotzdem mal, in
der Hoffnung, dass ja jeder mal ganz klein angefangen hat :)
Ich möchte einfach nur einen Block programmieren, der am Anfang (bei 0)
für einen Takt einen Highpegel ausgibt (SOP) und am Ende (bei 4095)
ebenfalls für einen Takt einen Highpegel (EOP) ausgibt. Wenn EOP
ausgegeben wurde, soll es wieder von vorne losgehen.
Folgendes habe ich mir zusammengeschrieben:
1
architectureAufbauofcounteris
2
3
begin
4
5
process(CLK)
6
sharedVARIABLEi:integer:=0;
7
begin
8
9
start:FORiIN0TO4095LOOP
10
IF(CLK'eventandCLK='1')THEN
11
IF(i=0)THEN
12
EOP<='0';-- end of packet 'last packet'
13
SOP<='1';-- start of packet 'new packet'
14
ELSIF(i=1)THEN
15
SOP<='0';
16
ELSIF(i=4095)THEN
17
EOP<='1';
18
i:=0;
19
NEXTstart;
20
ENDIF;
21
ELSE
22
i:=i+1;
23
ENDIF;
24
ENDLOOP;
25
26
endprocess;
27
endarchitecture;
Jetzt bekomme ich immer die Fehlermeldung, dass i eine "variable or
aggregate" sein muss. Habe jetzt soviel gelesen und komme einfach nicht
weiter. Daher hoffe ich auf eure professionellen Ratschläge :)
Vielen Dank schonmal im Voraus
Lars
> start:FOR i IN 0 TO 4095 LOOP
Diese For-Schleife macht in VHDL nicht das, was du z.B. von Basic oder C
her kennst.
So geht es eher:
1
architectureAufbauofcounteris
2
signali:integer:=0;
3
4
begin
5
process(CLK)begin
6
ifrising_edge(clk)then-- <-- besser so
7
-- IF (CLK'event and CLK='1') THEN -- mit einer steigenden Flanke
8
i<=i+1;-- den Zähler erhöhen
9
IF(i=0)THEN
10
EOP<='0';-- end of packet 'last packet'
11
SOP<='1';-- start of packet 'new packet'
12
ELSIF(i=1)THEN
13
SOP<='0';
14
ELSIF(i=4095)THEN
15
EOP<='1';
16
i<=0;
17
ENDIF;
18
ENDIF;
19
endprocess;
20
endarchitecture;
Sieh dir mal ein Buch zu dem Thema an.
Mein Tipp: VHDL-Synthese von Reichardt/Schwarz
In dem wird nicht VHDL erklärt (wie in so vielen anderen). Es werden
explizit VHDL-Templates für die Synthese vorgestellt und abgehandelt.
Danke für die rasendschnelle Antwort! Ich hatte die FOR-Schleife aus
einem Tutorial, daher dachte ich dass diese so funktioniert.
1
architectureAufbauofcounteris
2
signali:integer:=0;
3
4
begin
5
process(CLK)begin
6
start:ifrising_edge(clk)then-- <-- besser so
7
-- IF (CLK'event and CLK='1') THEN -- mit einer steigenden Flanke
8
i<=i+1;-- den Zähler erhöhen
9
IF(i=1)THEN
10
EOP<='0';-- end of packet 'last packet'
11
SOP<='1';-- start of packet 'new packet'
12
ELSIF(i=2)THEN
13
SOP<='0';
14
ELSIF(i=4096)THEN
15
EOP<='1';
16
i<=0;
17
NEXTstart;
18
ENDIF;
19
ENDIF;
20
endprocess;
21
endarchitecture;
22
-- Funktionsweise
23
-- SOP SOP
24
-- __________|-|_________________|-|_______
25
-- _______|-|_________________|-|_________
26
-- EOP EOP
27
-- 1.. ..4096 1..
So ich hab mal die Funktionsweise beschrieben und die Indizes geändert,
da es ja jetzt keine If-Abfrage mit "=0" mehr geben kann.
Funktioniert das "NEXT" denn so? Es soll ja sofort wieder vorne
angefangen werden.
Gruß,
Lars
Gute Lösung. Ich würde es noch etwas optimieren.
VHDL Neuling: rising_edge(clk) besagt schon, das zu jeder steigenden
flanke der clock alles innerhalb der if-anweisung ausgeführt wird.
NEXT ist nur für das vorzeitige verlassen eines schleifendurchlaufes.
hat hier irgendwie gar nix zu suchen.
Der Besucher
denn damit werden 32 Bit für den Zähler verwendet.
Besser wäre so:
1
signali:integerrange0to4095:=0;
@ Der Besucher
Ich würde das nicht mit std_logic_vector machen, weil dann je nach LIB
das nicht geht:
1
ELSIF(i=4095)THEN
Beim Zähler mit integer range 0 to 4095 wird (genau wie beim Vektor)
auch ein ordinärer Überlauf synthetisiert.
EDIT:
> Ich hatte die FOR-Schleife aus einem Tutorial,> daher dachte ich dass diese so funktioniert.
Für die Simulation wäre diese Schleife durchaus tauglich. Aber auf
einen programmierbaren Baustein bekommst du das nicht implementiert.
> @ Der Besucher> Ich würde das nicht mit std_logic_vector machen, weil dann je nach LIB> das nicht geht:>> ELSIF (i=4095) THEN
Stimmt, funktioniert dann nicht wenn man nicht die richtigen LIBs
verwendet.
Ich sehe nur den Vorteil, das man sofort ein Gefühl für die Bitbreiten
bekommt, und damit später für die vewendeten Zählerflipflops. Aber
sicherlich geschmackssache.
Der Besucher
Vielen Dank!
Die "Besucher"-Variante hat mich schon etwas beeindruckt, da muss man
erstmal drauf kommen. ;)
Aber damit ihr mir nicht in unerreichte Fachsimpeleien entschwindet,
habe ich mal noch eine Anfängerfrage:
Ich erzeuge aus dem Quelltext ein HDL-Design-File, baue das in mein
Design ein und programmiere dann mein Cyclone III-Board. Da ist es doch
egal welche Variante ich benutze, oder? (mit vector oder mit range)
Lars :o)
> das man sofort ein Gefühl für die Bitbreiten> bekommt, und damit später für die vewendeten Zählerflipflops.
Das stimmt allerdings ...
@ VHDL-Neuling
Merksatz:
Über den Daumen gepeilt gilt
1,000 = 10 Bit = 10 Zählerflipflops
1,000,000 = 20 Bit = 20 Zählerflipflops
1000,000,000 = 30 bit = 30 Zählerflipflops
integer = 32 Bit = 32 Zählerflipflops
Mir ist doch noch etwas aufgefallen:
Gibt es hierbei überhaupt jemals ein i=0? Wird das i nicht schon beim
ersten Durchlauf vor der Abfrage auf 1 erhöht?
1
ifrising_edge(clk)then
2
-- defaultanweisungen
3
i<=i+1;-- den Zähler erhöhen
4
EOP<='0';
5
SOP<='0';
6
-- ende defaultanweisungen
7
IF(i=0)THEN
8
SOP<='1';-- start of packet
9
ELSIF(i=4095)THEN
10
EOP<='1';-- end of packet
11
-- i <= 0; -- kann man jetzt weglassen (Ausnutzung des überlaufs bei 'range 0 to 4095')
@VHDL-Neuling
Löse dich bitte von der "sequentiellen Denkweise". Innerhalb des
getakteten Processes werden alle Signalezuweisungen parallel ausgeführt.
So greift man noch auf den alten Wert von i zu (also 0).
Gab es da nicht vor ein paar Tagen eine Anmerkung, das solche Dinge
uninteressant für Einsteiger sind ;)
Der Besucher
> Gab es da nicht vor ein paar Tagen eine Anmerkung, das solche Dinge> uninteressant für Einsteiger sind ;)
Das war im Beitrag "Re: Zwei Fragen zu VHDL"
Ohne weiteren Kommentar ;-)
> if rising_edge(clk) then
das sagt deinem Design: bei der steigenden Taktflanke tue etwas.
D.h. was danach passiert ist dem Prozess egal, der Zustand zur
Steigenden Flanke wird durch Speicherelemente "eingefroren".
Ich würde ein Signal nicht SIGNAL nene, das ist ein schlüsselwort und
man kommt schnell durcheiander.
Du würdest in C ja auch einen Integervariable nicht int nenen in der
Art:
Stimmt :)
Ich wollte das eigentlich auch nicht Signal nennen, nur hier damit jeder
schnell sieht was ich meine.
Also verstehe ich das richtig und es wäre besser, wenn ich die Abfragen
umdrehe?
Also:
1
if(Eingang='1')then
2
ifrising_edge(clk)then
3
.........
4
endif;
5
endif;
So würde das Hochzählen doch erst beginnen, wenn der Eingang gesetzt
ist?!
>> So würde das Hochzählen doch erst beginnen, wenn der Eingang gesetzt> ist?!
Hast du sowas schon mal in einem Buch (oder sonstwo) gesehen?
Wenn dann so:
Nein, das entsprang meinem eigenen Hirn :)
Tut mir leid, wenn ich manchmal "blöde" Fragen stelle, aber mich in die
FPGA-Programmierung reinzudenken, fällt mir noch etwas schwer.
> aber mich in die FPGA-Programmierung reinzudenken,> fällt mir noch etwas schwer.
Du mußt nur im Hinterkopf haben, dass sich deine Beschreibung auf die
Baugruppen eins FPGAs abbilden lassen muß. Und dort gibt es (grob
gesagt) nur Logik und FFs (und Latches, yeah).
> das entsprang meinem eigenen Hirn :)
Deine Beschreibung beschreibt zwar ein grundsätzlich anderes Verhalten,
sie würde aber von den Designtools in meine umgesetzt werden.
Siehe dort: http://www.lothar-miller.de/s9y/categories/6-Clock-Enable
Allerdings würde dann die Umsetzung nicht mehr zu deiner Denkweise
passen, und das kann ein böses Erwachen geben...
@ Lothar Miller
Ich habe zu dem Problem, wie ein FF beschrieben werden sollte noch eine
Frage:
Du hast ja auch auf Deine Webseite verwiesen und dort drei Varianten
aufgeschrieben.
Du sagst abschliessend, das nur die erste (erst clock, dann enable)
verwendet werden sollte, da die anderen überraschend seien.
Nimm mal an, das ich Überraschungen liebe und auch anderen gerne welche
bereite (auch dem FPGA): Gibt es technische Gründe, warum die anderen
Varianten nicht genommen werden sollten? Wenn ich Dich recht verstehe
sind sie doch funktional aquivalent?
> Gibt es technische Gründe, warum die anderen> Varianten nicht genommen werden sollten?
1.) Die Design-Tools sind zwar schon recht gut, aber für solche
Beschreibungen noch nicht optimiert.
Ergo: Nur wenn man sich an die Standard-Schreibweise hält, kann man
auch Standard-Ergebnisse erwarten.
2.) Bei diesen wirklich simplen Beispielen kann immer nur 1 Signal als
Takt-Enable beschrieben werden. Das oben beschriebene einfache Beispiel
mag ja so noch aufgehen, aber schon bei diesem (nicht viel
komplizierteren) Fall geht es in die Hose:
1
ifrising_edge(clk)then
2
if(Eingang1='1')then
3
.........
4
elsif(Eingang2='1')then
5
.........
6
elsif(Eingang3='1')then
7
.........
8
endif;
9
endif;
Wie würdest du das mit dieser anderen Clock-Enable Schreibweise
ausdrücken?
Na also: wenn schon so etwas einfaches nicht mehr geht, warum sollte man
sich so eine Schreibweise angewöhnen?
Bitte verzeihe mir, wenn ich auf eine sichtlich um Klärung bemühte
Antwort Deinerseits doch noch mal rückfragen möchte:
>> Gibt es technische Gründe, warum die anderen>> Varianten nicht genommen werden sollten?>1.) Die Design-Tools sind zwar schon recht gut, aber für solche>Beschreibungen noch nicht optimiert.>Ergo: Nur wenn man sich an die Standard-Schreibweise hält, kann man>auch Standard-Ergebnisse erwarten.
Soweit ich erkennen kann ersetzt Du hier den Grund "überraschend" durch
"Design-Tools nicht geeignet" aber auch durch "nicht-Standard".
Welche Tools können die fragliche Schreibweise (mit Enable erst nach
Clock) nicht? Welchem Standard entspricht diese Schreibweise nicht?
Stimmen wir eingentlich soweit überein, das all drei Schreibweisen, ein
FF mit Enable beschreiben?
Mit Deinem Beispiel kann ich in der Form nichts anfangen. Mehrere Enable
anstelle eines hört sich für mich erstmal nach einem "oder" zwischen
mehreren Enable an. Dein Beispiel aber suggeriert, das je nach gewähltem
Enabel verschiedene Aktionen erfolgen sollen, also sowas wie verschieden
FFs die an dem selben Takt hängen. Das würde man (ich) sowieso als
verschiedene Entitäten schreiben und nicht als eine. Was meinst Du dazu?
> Bitte verzeihe mir ...
Deine Bitte sei dir gewährt ;-)
> Mehrere Enable anstelle eines hört sich für mich erstmal nach> einem "oder" zwischen mehreren Enable an.
Nein, wie aus der Beschreibung hervorgeht, sind es mehrere Enable
innerhalb eines getakteten Prozesses. Machen wir an mein Beispiel noch
etwas Speck und lassen den Prozess auch mal was tun (nicht viel, aber
wenigstens irgendwas):
1
signalcounter:unsigned(3downto0);
2
:
3
process(clk)begin
4
ifrising_edge(clk)then
5
if(Eingang1='1')then
6
counter<="0011";
7
elsif(Eingang2='1')then
8
counter<="1011";
9
elsif(Eingang3='1')then
10
counter<="1001";
11
endif;
12
endif;
13
endprocess;
Wie könntest du dir jetzt eine Beschreibung mit "aussenliegenden" Enable
vorstellen?
Einfach auf mehrere Prozesse aufteilen? So etwa:
1
signalcounter:unsigned(3downto0);
2
:
3
:
4
process(clk)begin
5
if(Eingang1='1')then
6
ifrising_edge(clk)then
7
counter<="0011";
8
endif;
9
endif;
10
endprocess;
11
12
process(clk)begin
13
if(Eingang2='1')then
14
ifrising_edge(clk)then
15
counter<="1011";
16
endif;
17
endif;
18
endprocess;
19
20
process(clk)begin
21
if(Eingang3='1')then
22
ifrising_edge(clk)then
23
counter<="1001";
24
endif;
25
endif;
26
endprocess;
Ja, sowas gibt den berühmten Multisource-Fehler :-(
Dann also in einem Prozess und die Enable verodert?
Also so:
1
signalcounter:unsigned(3downto0);
2
:
3
process(clk)begin
4
if(Eingang1='1'orEingang2='1'orEingang3='1')then
5
ifrising_edge(clk)then
6
:
7
:
8
endif;
9
endif;
10
endprocess;
Ist da in etwa dein Vorschlag?
Damit ist nichts gewonnen, denn innerhalb des Prozesses müsste für die
Zuweisung jetzt noch einmal unterschieden werden. Dann wird daraus also:
1
process(clk)begin
2
if(Eingang1='1'orEingang2='1'orEingang3='1')then
3
ifrising_edge(clk)then
4
if(Eingang1='1')then
5
counter<="0011";
6
elsif(Eingang2='1')then
7
counter<="1011";
8
elsif(Eingang3='1')then
9
counter<="1001";
10
endif;
11
endif;
12
endif;
13
endprocess;
> Welchem Standard entspricht diese Schreibweise nicht?
Sie entspricht nicht dem Quasi-Industrie-Standard, den die
Synthesetools verwenden und umsetzen können.
Ich habe dieses Wort Standard extra kursiv geschlagen, damit man nicht
z.B. den VHDL-Standard meint. Ich kann hier mit einem kleinen
VHDL-Dreizeiler etwas beschreiben, das zwar problemlos simuliert aber
garantiert nicht in ein FPGAimplementiert werden kann.
Nehmen wir z.B. nur mal das hier:
1
counter<="1001"after2000ms;
Vollkommen VHDL-konform. Derzeit nicht implementierbar.
Aus langjähriger Erfahrung: Synthese-Tools sind doof !
Gut - nicht vollkommen doof, aber doof !
Wenn Du 'gute' Ergebnisse haben willst, solltest Du Deinen Dialekt
so 'einfach' wie möglich gestalten: je mehr Menschen auf dieser Welt
ein FlipFlop mit Reset und Clock-Enable EXAKT gleich beschreiben,
desto größer ist die Wahrscheinlichkeit, daß alle SW-Bugs die DIESE
Beschreibung betreffen, bereits gefunden wurden.
Je exotischer dein 'Style' desto größer die Wahrscheinlichkeit,
daß DU derjenige bist, der auf einen Bug aufmerksam werden wird !!!
Also: "Standard" haiß hier nicht IEEE oder so was, sondern,
"Was die meisten Anwender verwenden"
> Sie entspricht nicht dem Quasi-Industrie-Standard, den die> Synthesetools verwenden und umsetzen können.
Es gibt schon einen offiziellen Standard : IEEE 1076.6.
Niemand beruft sich aber explizit darauf (jedenfalls wäre es mir bis
jetzt nie aufgefallen), und so schnell nachschauen kann man darin auch
nicht, weil man ihn bezahlen muß.
@ Lothar Miller
Also, ich möchte wirklich gerne verstehen, was es damit (mit meiner
ursprünglichen Frage) auf sich hat.
Es würde mir helfen, wenn Du bitte meine nachfolgende Zusammenfassung
der Fragestellung und meine Wiedergabe Deiner Antwort lesen würdest und
sie (falls sie richtig ist) kurz bestätigst.
Die ursprüngliche Frage bezog sich darauf, ob das enable innerhalb oder
ausserhalb der clk-Abfrage sein darf oder nicht. Soweit ich auch Deinen
Text auf Deiner Webseite gelesen habe sind beide bzw. drei Varianten
funktional äquivalent und werden mit dem Tool das Du dazu verwendet hast
auch äquivalent synthetisiert. Soweit so gut.
Nun hast Du geschrieben, das die Varianten mit enable ausserhalb
"überraschend" bzw. "nicht-Standard" wären. Das wollte ich hinterfragen.
Wenn ich Deine zweite Antwort nun richtig verstehe, das meintest Du
nicht, das diese anderen Schreibweisen einem Standard widersprechen,
sondern vielmehr "unüblich" sind und Du (aus Erfahrung begründete)
Zweifel hast, das diese grundsätzlich die äquivalente Funktion ergeben.
(Die kursive Hervorhebung habe ich leider nicht so verstanden.).
Ist das so richtig?
Wenn Du mir bitte noch die Bemerkung erlaubst, ist mir durchaus klar,
das Dein Beispiel eine andere Beurteilung erfordert. Ich hatte ja auch
gesondert daruf hingewiesen das Dein Beispiel (vom 27.01.2009 00:46) aus
meiner Sicht nur dann Sinn macht, wenn in den if-zweigen
unterschiedliche Aktionen erfolgen.
Stimmst Du mir zu, wenn ich behaupte, das der Vergleich der drei
Alternativen nur dann Sinn macht, wenn innerhalb der IF-Abfragen auch
nur Aktionen erfolgen die sich mit der übergeordneten Bedingung
vertragen (sich also z.B. gleichermaßen synthetisieren lassen)?
Du aber hast mit Deinem Beispiel (noch mehr in der zweiten Antwort) eine
Variante eröffnet, die sich, auch nach meinen Kenntnisstand, nicht mit
allen drei Varianten verträgt.
Ich meine aber Deinem Beispiel zumindest soviel entnehmen zu dürfen, das
es sich im Sinne einer inkrementellen Bearbeitung der Beschreibung
anbietet, die enable-Bedingung nach innen zu legen, weil es dann
einfacher ist, weitere Bedingungen ohne überflüsse Schreibarbeit
hinzuzufügen. (Und weil es "üblicher" ist).
> Ist das so richtig?
FULL ACK
> Stimmst Du mir zu, wenn ich behaupte, das der Vergleich der drei> Alternativen nur dann Sinn macht, wenn innerhalb der IF-Abfragen auch> nur Aktionen erfolgen die sich mit der übergeordneten Bedingung> vertragen (sich also z.B. gleichermaßen synthetisieren lassen)?
## Ich bin mir nicht sicher ob ich den Kern deiner Frage erfasst habe
:-/
## Aber hier ein Antwortversuch ;-)
Ich meine, das Problem ist eher, dass genau dieser Sonderfall in der
Praxis kaum vertreten ist: Enable-Signale, die als eine einzige
If-Abfrage innerhalb eines getakteten Prozesses verwendet werden.
Also sowas z.B. stellt in der Praxis (in seiner Schlichtheit) den
Ausnahmefall dar:
1
if(Enable='1')then
2
ifrising_edge(clk)then
3
cnt<=cnt+1;
4
endif;
5
endif;
Wenn ich das Original von Lars mal nehme und die Punkte durch eine
Up-Down-Zähler-Funktion ersetze, wie sieht dann das Enable für jedes
einzelne Zähler-FF aus?
1
if(Enable='1')then-- enable counter
2
ifrising_edge(clk)then
3
if(up='1')then-- enable up
4
cnt<=cnt+1;
5
elsif(dn='1')then-- enable down
6
cnt<=cnt-1;
7
endif;
8
endif;
9
endif;
Ein Counter-Enable ausserhalb und zwei Richtungs-Enable innerhalb des
Taktes? Kann das synthetisiert werden?
Das müsste man erst mal ausprobieren...
Üblicherweise wird es aber so geschrieben:
1
ifrising_edge(clk)then
2
if(Enable='1')then
3
if(up='1')then
4
cnt<=cnt+1;
5
elsif(dn='1')then
6
cnt<=cnt-1;
7
endif;
8
endif;
9
endif;
Und das wird klappen, weil es jeder so (oder annähernd so) macht.
ist da nicht ein Latch drin?
Flanke geht hoch, up ist 0, dn ist 0
da cnt in der synchronen Umgebung zugewiesen wird,
wird es DFF, aber genaugenommen müsste doch im
oberen Fall Signal von Q auf D zurückgeführt werden.
bzw nicht auf D, sondern auf CE, um Q einzufrieren.
Der Takt hämmert ja am clock Eingang ständig und
würde andere Werte reinschieben.
grüsse.
ps:
daniel wrote:
> ist da nicht ein Latch drin?> Flanke geht hoch....
Nein, ein Latch ist per Definition kein getaktetes Bauelement. Deshalb
können in einem vollständig synchronen Prozess keine Latches entstehen.
Das nachfolgende wäre ein Latch (wird aus Versehen auch gern gemacht):
1
if(clk='1')then-- hier fehlt das 'event
2
if(enable='1')then
3
if(up='1')then
4
cnt<=cnt+1;
5
elsif(dn='1')then
6
cnt<=cnt-1;
7
endif;
8
endif;
9
endif;
Und als kleines Gimmick gibts hier auch noch eine kombinatorische
Schleife. In diesem Fall einen Zähler, der mit maximaler Geschwindigkeit
hoch- oder runterzählt wenn die Rahmenbedingungen stimmen (z.B. clk,
enable, up = '1') :-o
> ps:>
1
>ifrising_edge(clk)andenable='1'then
2
>
3
>endif;
4
>
> gibt es auch noch
Ja, wurde von mir schon untersucht und dort am Rande angeführt:
Beitrag "Re: Variablenfehler" ;-)