Forum: FPGA, VHDL & Co. Vector Index VHDL


von Detlef _. (detlef_a)


Angehängte Dateien:

Lesenswert?

Hi,

das ist eine Anfängerfrage, trotzdem krieg ich es nicht raus.

Ich habe eine statemachine und in der toggle ich einen pin:

irgendwann:
spimiso <= outdata_sulv(0);
später
spimiso <= outdata_sulv(1);

mit
signal outdata_sulv : std_logic_vector(15 downto 0) ;
outdata_sulv <= "1001010101010010";
spimiso       : out  std_logic;

Der toggelt da munter vor sich hin, alles gut, erwartungskonform.

Jetz ändere ich das folgendermassen;
i1 <= 1;
spimiso <= outdata_sulv(i1);

später

i1 <= 0;
spimiso <= outdata_sulv(i1);

mit
signal i1  : natural range 0 to (2**32)-1;

Ich greife also nicht direkt auf das Element zu sondern über den Index 
i1.

Dann geht das nicht mehr, Syntax ok, aber toggeln tut nichts.

Danke für einen Hinweis.
Kompletter Code hängt dran.

Cheers
Detlef

von Fpgakuechle K. (Gast)


Lesenswert?

Wo kontrollierst Du das togglen? Im Simulator? Oder auf einem Board?

von Detlef _. (detlef_a)


Lesenswert?

Fpgakuechle K. schrieb:
> Wo kontrollierst Du das togglen? Im Simulator? Oder auf einem Board?

Hab nen board. Messe mit nem scope.

Cheers
Detlef

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


Lesenswert?

Detlef _. schrieb:
> signal i1  : natural range 0 to (2**32)-1;
Weil ein natural nur ein Subtype eines integer ist, kann es keinen 
größeren positiven Wertebereich als ein integer haben.
1
subtype NATURAL is integer range 0 to integer'high;
2
subtype POSITIVE is integer range 1 to integer'high;
Ein integer hat aber nur einen Wertebereich von -2**31 bis +(2**31)-1

Mich wundert sehr, dass du dafür keine Warnung bekommst.

Und ich bin mir (noch ohne die Beschreibung angeschaut zu haben) völlig 
sicher, dass du garatniert kein Array hast, das so einen mächtigen Index 
braucht.
Deshalb solltest du den Wertebereich des Index bei der Deklaration so 
eingrenzen, dass er nicht über das Array hinaus zugreifen kann. Nur dann 
kann dir der Simulator auf die Finger klopfen, wenn was nicht passt und 
dein Index Amok läuft...

In deinem Fall muss also eine formell korrekte Deklaration samt 
Initialisierung so aussehen:
1
 signal i1  : integer range 0 to 15 := 0;
Alles andere gibt Minuspunkte, weil es schlicht falsch ist.

So, nun zum Code:
1
Port {
2
          :
3
          spiclk        : in  std_logic;
4
          :
5
     };
6
:
7
:
8
    elsif (clk'event) and (clk='1') then
9
:
10
       case fsm is
11
         when idle =>
12
           if spiclk='1' then 
13
:
Niemals darfst du asynchrone externe Signale ohne 
Eintakten/Einsynchronisieren in FSM verwenden. Dein Design wird dann und 
wann eigenartige Fehler bringen und die FSM wilde Sprünge machen.
Mehr dazu dort:
http://www.lothar-miller.de/s9y/archives/64-State-Machine-mit-asynchronem-Eingang.html
http://www.lothar-miller.de/s9y/archives/41-Einsynchronisieren-von-asynchronen-Signalen.html

Ein Wort zu deinem "Programmierstil", der hier die Ursache allen Übels 
ist: VHDL ist keine Programmiersprache sondern, wie es der Name schon 
sagt, eine Beschreibungssprache. Deshalb solltest du das sequentielle 
"Top-Down" Programmieren von C oder Java oder sonstwelchen 
Programmiersprachen gleich mal vergessen.
Du musst dir auch unbedingt das Verhalten von Signalen in Prozessen 
näher ansehen!
Denn ein Signal ändert seinen Wert während eines Prozessdurchlaufs 
nicht!
Neu zugewiesene Werte werden lediglich "gemerkt" und vom Signal dann 
beim Prozessende oder beim nächsten wait übernommen. Dabei "gewinnt" 
jeweils die letzte Zuweisung:
1
:
2
:
3
-- mal angenommen, i1 hat bisher den Wert 0
4
-- und dann kommt diese Zuweisung:
5
              i1 <= 1;
6
-- jetzt merkt sich der Synthesizer, dass beim NÄCHSTEN wait 
7
-- bzw. am Prozessense i1 den Wert 1 annehmen soll
8
-- i1 bleibt aber weiterhin 0!
9
-- und deshalb wird hier auf den Index 0 zugegriffen:
10
              spimiso <= outdata_sulv(i1);
11
:
12
:
13
   end if;
14
-- erst jetzt, beim Prozessende, übernimmt das Signal i1 den Wert 1
15
end process ;
Das Stichwort dazu heißt Latency.
Und (nur, falls es dir jetzt dann in den Sinn kommt): Nein, du brauchst 
für diese simple Aufgabe keine Variablen.

BTW: wenn man dieses Verhalten von Signalen mal kapiert hat, kann man 
damit nette Beschreibungen formulieren.

Zu dieser Zeile auch noch ein Wort:
1
    -- geht nich warumnurwarum signal outdata_sulv : std_ulogic_vector(15 downto 0) := "16#deadbeef#";
Das geht nicht, weil 16#deadbeef# eben kein Vektor aus std_logic, 
sondern eine integer Zahl zur Basis 16 und VHDL eine streng typisierte 
Beschreibungssprache ist. Da kann man nicht einfach so ein Bitmuster 
"1010111010100101" mit einer Hexzahl AEA5 vergleichen oder eine integer 
Zahl einem Vektor mit völlig anderem Typ zuweisen. Es muss dazwischen 
eine Umwandlung passieren. Die numeric_std bietet dafür Casts und 
Umwandlungsfunktionen an:
http://www.lothar-miller.de/s9y/categories/16-Numeric_Std

Detlef _. schrieb:
> Hab nen board. Messe mit nem scope.
Falsche Vorgehensweise für so eine simple Beschreibung.
Simuliere dein Design!
Der Simulator ist der Debugger für VHDL. Dann kannst du ganz leicht 
sehen, dass deine Signale immer "irgendwie einen Takt versetzt" sind.

: Bearbeitet durch Moderator
von Fpgakuechle K. (Gast)


Lesenswert?

Lothar M. schrieb:

>> Hab nen board. Messe mit nem scope.
> Falsche Vorgehensweise für so eine simple Beschreibung.
> Simuliere dein Design!
> Der Simulator ist der Debugger für VHDL. Dann kannst du ganz leicht
> sehen, dass deine Signale immer "irgendwie einen Takt versetzt" sind.

Hinzu kommt, das das Synthesetool nur einen Teil des VHDL kennt, kleiner 
als das was der Simulator kennt. Und Das Synthesetool ignoriert für ihn 
unbekannten Teil des VHDL-Syntaxes und setzt damit nicht in das 
Konfigurationsfile des FPGA um.
Dazu sollte sich dann aber ne Meldung im Synthese-log finden lassen, 
Etwa "VHDL index Opeartion not supported, signal wille be pruned to GND" 
.

Wie eins drüber gesagt, VHDL ist keine Programmiersprache. In C lassen 
sich Indexoperationen auf Assembler umsetzen, in HDL ist das 
offensichtlich nicht selbstverständlich.

von Detlef S. (detlef_s435)


Lesenswert?

Hi, vielen Dank für die Hinweise.
Ich lernte:
Auf Warnungen achten.
Indizierung muss nicht gehen, in die Logs schauen.
Das externe Signal einsynchronisieren.
In die Simulation einfummeln.

Die strenge Typisierung kenne ich inzwischen.

Die Zuweisung von Signalen am Ende des Process ist mir allerdings 
bekannt. Wenn ich dem index 1 zuweise und dann zugreife benutze ich den 
'alten' Wert des Index.,  das war die 0. Das Toggeln muss aber trotzdem 
gehen .?????!!!!!!.

Bin am Anfang einer steilen Lernkurve. Vielen Dank, kenne Euch und weiß 
dass Ihr es drauf habt.

Cheers
Detlef

von Fpgakuechle K. (Gast)


Lesenswert?

Detlef S. schrieb:

> Bin am Anfang einer steilen Lernkurve.

Diese ist für manche nicht nur steil, sondern gerät regelrecht zum 
Looping!
Heisst , man muss sich manches abgewöhnen, wie man es in einer 
Programmiersprache macht (Index, Pointer) und von der Basis an aufwärts 
lernen wie Hardware aufgebaut ist.
Man könnte beispielsweise seine eigene CPU nach Blockbild im FPGA bauen:

https://forums.xilinx.com/t5/Xcell-Daily-Blog-Archived/Hidden-Gems-The-Xilinx-PicoBlaze-Microcontroller-a-tiny-RISC/ba-p/498470
https://www.elektormagazine.de/news/mikrocontroller-dokumentation-verstehen-teil-3-blockschaltungen-und-mehr

von Markus F. (mfro)


Lesenswert?

Detlef S. schrieb:
> Ich lernte:
> Auf Warnungen achten.
> Indizierung muss nicht gehen, in die Logs schauen.
> Das externe Signal einsynchronisieren.
> In die Simulation einfummeln.

Detlef S. schrieb:
> Das Toggeln muss aber trotzdem
> gehen .?????!!!!!!.

Dann hast Du den letzten Punkt deiner "Lernliste" noch nicht ausreichend 
beackert: Simulation. Das ist das Erste was Du angehen mußt, um wirklich 
zu verinnerlichen, was Du da tust.

Im übrigen "geht" Indizierung. Immer.
Nur vielleicht nicht so, wie Du's intuitiv erwartest (s.o.).

Abgesehen davon (aber das ist meine persönliche Meinung) kann ich mit 
der "Verteufelung" von Variablen nicht viel anfangen. Variablen sind ein 
(wichtiges) Sprachelement von VHDL und sind dazu gedacht, daß man sie 
benutzt.

Natürlich muß man wissen, was man tut, aber das ist ja immer und bei 
allem eine gute Idee.

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


Lesenswert?

Markus F. schrieb:
> kann ich mit der "Verteufelung" von Variablen nicht viel anfangen.
Zum Glück wenigstens mit Anführungszeichen.
> Variablen sind ein (wichtiges) Sprachelement von VHDL und sind dazu
> gedacht, daß man sie benutzt.
Klar, es ist auch gut, wenn man sie kennt und an der richtigen Stelle 
benutzt. Aber Variablen dafür zu nutzen, damit man wie mit C oder sonst 
einer sequentiellen Programmiersprache "von oben nach unten 
programmieren" kann, dafür sind die nicht gedacht.

Und wenn Variablen dann speicherndes Verhalten aufweisen, zwickts mich 
ganz gewaltig am Auge und ich trau dem "VHDL-Programmierer" ab da alles 
zu. 😉

: Bearbeitet durch Moderator
von Tobias B. (Firma: www.elpra.de) (ttobsen) Benutzerseite


Lesenswert?

Lothar M. schrieb:
> Und wenn Variablen dann speicherndes Verhalten aufweisen, zwickts mich
> ganz gewaltig am Auge und ich trau dem "VHDL-Programmierer" ab da alles
> zu. 😉

Hmmm, Xilinx empfiehlt im XST User Guide sogar shared Variablen zu 
nutzen um BRAM zu instanzieren. ;-)

von Fpgakuechle K. (Gast)


Lesenswert?

Tobias B. schrieb:

> Hmmm, Xilinx empfiehlt im XST User Guide sogar shared Variablen zu
> nutzen um BRAM zu instanzieren. ;-)

Das ist ja der entscheidende Punkt. Wenn du weist, das man da BRAM 
braucht dann kannst du shared variable verwenden, aber auch nur genauso 
wie im template wie im Synthesize-Guidbeschrieben.
Aber nicht anders rum, variable verwenden und hoffen&beten das XST da 
was passendes auf Lager hat und einbaut.

Synthesis Style Guide ist eben Pflichtlektüre, die Kenntnis der 
vHDL-Syntax Definition nach IEEE Standardisierungskomission reicht 
nicht.

Und die 'Schreibweise' mit arrays um sich eine explizite 
BRAM-Instanzierung (oder auch was aus dem Coregenerator) zu sparen, hat 
auch ihre Nachteile:

-passt nicht bei allen speicherport-Varianten, beispielsweise sollte die 
bitbreite beider Ports gleich sein
-ist nicht besonders gut auf andere Architekturen (bspw. Asic 
übertragbar). dafür muss der Speicher wieder als extra componente 
gekapselt werden.

von Tobias B. (Firma: www.elpra.de) (ttobsen) Benutzerseite


Lesenswert?

Da gebe ich dir in allen Punken recht. Mein Kommentar ist auch nur im 
Kontext des Zitats zu betrachten und das man nicht das eben nicht 
verallgemeinern kann. Dazu ist das ganze auch nicht mit einem ;-) 
versehen und sollte nicht so ernst genommen werden. ;-)

: Bearbeitet durch User
von Gustl B. (gustl_b)


Lesenswert?

Das mit der

Tobias B. schrieb:
> shared Variable

kenne ich, ist aber seltsam weil das bei Intel auch anders funktioniert. 
Das ist eigentlich eher traurig, dass die Synthesetools recht 
unterschiedlich sind. Auch in Puncto guter VHDL2008 Unterstützung die es 
für den Max10 nie geben wird.

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


Lesenswert?

Gustl B. schrieb:
> Auch in Puncto guter VHDL2008 Unterstützung
Na gut, nachdem der Synthesizer sowieso bestenfalls mit 5% des 
Sprachumfangs von VHDL was anfangen kann (nicht mal ein simples LED <= 
not LED after 500ms; bekommt er in Hardware gebacken ;-), ist das meist 
nur eine theoretische Einschränkung.

von Markus F. (mfro)


Lesenswert?

Gustl B. schrieb:
> Das mit der
>
> Tobias B. schrieb:
>> shared Variable
>
> kenne ich, ist aber seltsam weil das bei Intel auch anders funktioniert.

Ist generell die Frage, ob das mit der Shared Variable so schlau (von 
Xilinx) war: funktioniert nicht mit VHDL 2008, weil shared variables da 
(richtigerweise) protected sein müssen. Und protected shared variables 
sind wiederum nicht synthetisierbar...

: Bearbeitet durch User
von Testuser (Gast)


Lesenswert?

Lothar M. schrieb:
> ist das meist
> nur eine theoretische Einschränkung.

Naja generic Packages kann man schon gebrauchen, Case mit don't care, 
shift Operationen für unsigned/signed, ?? Operator, ...

Markus F. schrieb:
> funktioniert nicht mit VHDL 2008, weil shared variables da
> (richtigerweise) protected sein müssen. Und protected shared variables
> sind wiederum nicht synthetisierbar...

Genau, zum Glück geht das aber auch bei Xilinx ganz ohne Variablen.

von Detlef S. (detlef_s435)


Lesenswert?

Hi,
Eure guten Ratschläge werde ich beherzigen, die meisten jedenfalls. Das 
ist der langfristige Prozess der Lernkurve.

Kurzfristig würde ich gerne verstehen warum der nicht toggelt.

Signaltzuweisungszeitpunkt habe ich drauf.

Cheers
Detlef

von Detlef _. (detlef_a)


Angehängte Dateien:

Lesenswert?

Jungs,

looft, der Dreck. Gerne auch Kommentare zu meinen styles. Steile 
Lernkurve.

Cheers
Detlef

von gästchen (Gast)


Lesenswert?

moin
1
    if( cnt < 10000000) then -- blinkyblinky
2
      cnt <= cnt+1;
3
    else 
4
      cnt <= 0 ;
5
      --logikpegel <= not logikpegel;
6
    end if;

Ich bin etwas später dazu gekommen.
Mal abgesehen davon, dass das Toggeln von "logikpegel" auskommentiert 
ist: mit dem Zähler passiert doch gar nichts. Bleibt der überhaupt 
drinnen? Guck doch mal nach im rtl viewer.

von Detlef S. (detlef_s435)


Lesenswert?

Nein, debugleiche. Vivado optimiert den dann weg. Ich muss aber auch 
nicht sparen, die ganze Nummer nimmt 51 von ungefähr 64000 LUTs :) 
afair.Ich benötige nur die ca. 200 GPIOs, die innere Logik bleibt 
weitgehend ungenutzt.
Cheers
Detlef

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


Lesenswert?

gästchen schrieb:
> mit dem Zähler passiert doch gar nichts.
Dann blinkt halt auch nichts... ;-)
Und wenn was blinken würde, dann haben wir hier das berühmte 
"off-by-one" Problem: der Zähler zählt nämlich 10000000+1 Takte, weil er 
ja die 0 auch noch zählt.
Na gut, ich gebe zu, bei 10000000 Takten fällt das nicht arg auf, aber 
wenn man das mit 10 macht, dann wird diese "off-by-one" Thematik schon 
besser sichtbar.

Und  dann immer noch das hier:
1
    signal fsmcnt      : natural range 0 to (2**31)-1 := 0;
Mal abgesehen, dass du da auch gleich so schreiben könntest (weil 
"natural" sowieso nur den "range 0 to (2**31)-1" hat):
1
    signal fsmcnt      : natural := 0;
Der Witz an all diesen Deklarationen ist das, was ich schon geschrieben 
habe:
der fsmcnt läuft eben nicht und niemals bis 2147483647! Warum definierst 
du ihn dann so? Genau z.B. wegen des "off-by-one" Fehlers und wegen 
sonstigen amoklaufenden Zählern solltest du selber Wertebereiche 
sinnvoll einschränken. Und das eben nicht irgendwelchen 
Optimierungsschritten überlassen.
Es gilt was
ich schrieb:
> Deshalb solltest du den Wertebereich des Index bei der Deklaration so
> eingrenzen, dass er nicht über das Array hinaus zugreifen kann. Nur dann
> kann dir der Simulator auf die Finger klopfen, wenn was nicht passt und
> dein Index Amok läuft...

Optisch sieht auch dieser fsmcnt ziemlich "unsauber" aus. Irgendwann so 
um etwa 1001 (also nach 1002 Takten) herum schlägt der zu. Für mich ist 
das "irgendwie so geworden", aber sicher nicht "genau so geplant".

Das hier
1
 signal indcnt      : natural range 0 to 32 := 0;
sieht auch seltsam aus. Es ruft geradezu: "mit mir wirst du noch mal 
Probleme haben".

Und spätestens hier kommt dann auch der Flachmann ins Grübeln:
1
     indata_slv(15-(indcnt-1)) <= spimosisyn2;
Das sieht aus wie: "Durch ausgiebiges Ausprobieren haben wir 
festgestellt, dass..."

Noch ein Wort dazu:
1
   indata_slv(15-(indcnt-1)) <= spimosisyn2;
Mit ein wenig Nachdenken merkst du, dass du den MOSI nicht 
einsynchronisieren musst, weil der nämlich zu diesem Zeitpunkt, an dem 
du ihn einliest, völlig stabil dasteht. Und auch schon im Takt davor und 
auch dahinter. Der Master ändert den Pegel das MOSI erst bei der 
fallenden SCLK Flanke (wenn er sich SPI-konform verhält und bei der 
steigenden Flanke einliest).

von Detlef _. (detlef_a)


Lesenswert?

Vielen Dank für die Begutachtung, sie fällt milde aus, ne 3 vllt. .

Lothar M. schrieb:
> gästchen schrieb:

> der fsmcnt läuft eben nicht und niemals bis 2147483647! Warum definierst
> du ihn dann so? Genau z.B. wegen des "off-by-one" Fehlers und wegen

off-by-one hat mich schon viele Tage gekostet, kennick. Auf die 
notwendigen Bereiche der Zähler habe ich nicht geschaut, die hab ich so 
großzügig gewählt, dass nichts anbrennen kann. Dass man dann Fehler 
schwerer findet ist mir bewußt, war aber alles grün.


> Optisch sieht auch dieser fsmcnt ziemlich "unsauber" aus. Irgendwann so
> um etwa 1001 (also nach 1002 Takten) herum schlägt der zu. Für mich ist
> das "irgendwie so geworden", aber sicher nicht "genau so geplant".

Doch doch, geplant, nach 50mal clk muss die spiclk kommen, sonst ist was 
schief, das ist nen timeout, da hab ich ne glatte Zahl >50 gewählt.

>
> Das hier
>
1
>  signal indcnt      : natural range 0 to 32 := 0;
2
>
> sieht auch seltsam aus. Es ruft geradezu: "mit mir wirst du noch mal
> Probleme haben".

Unfertig, da kommen mal irgendwann ~200 GPIOs ran, das wird geändert, 
kein Fehler. Und ich weiß auch, dass das 33 Werte sind, kein off-by-one.

> Und spätestens hier kommt dann auch der Flachmann ins Grübeln:
>
1
>      indata_slv(15-(indcnt-1)) <= spimosisyn2;
2
>
> Das sieht aus wie: "Durch ausgiebiges Ausprobieren haben wir
> festgestellt, dass..."

Nein, das steht da so und nicht 16-indcnt damit ich das verstehe, wenn 
ich mir das in 2 Wochen anschaue, Eigenpädagogik, führt manchmal zu 
etwas komischer source.

>
> Noch ein Wort dazu:
>
1
>    indata_slv(15-(indcnt-1)) <= spimosisyn2;
2
>
> Mit ein wenig Nachdenken merkst du, dass du den MOSI nicht
> einsynchronisieren musst, weil der nämlich zu diesem Zeitpunkt, an dem
> du ihn einliest, völlig stabil dasteht. Und auch schon im Takt davor und
> auch dahinter. Der Master ändert den Pegel das MOSI erst bei der
> fallenden SCLK Flanke (wenn er sich SPI-konform verhält und bei der
> steigenden Flanke einliest).

Ja, stimmt, der kann sich nicht ändern, die spiclk muss 
einsynchronisiert werden, mosi nicht. Ich war durch deine klare Ansage 
'Niemals darfst du ....' da ein wenig gepolt :)).

Wieder was dabeigelernt, THX
Cheers
Detlef

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.