Forum: FPGA, VHDL & Co. VHDL Grundlagen


von chris (Gast)


Lesenswert?

Bei VHDL verstehe ich den Sinn des Schlüsselworts "Process" nicht ganz 
und habe versucht, das ganze mit folgendem einfachen "blink" programm zu 
analysieren.

> IF(clk'EVENT AND clk = '1') THEN

dient ja dazu, den Counter bei der steigenden Flanke zu inkrementieren.
Ich habe gelesen, dass mit der "sensitive list" in "PROCESS(clk)" immer 
auf ein Wechsel des Signals getriggert wird.
Wenn ich also die Zeile für die steigende Flanke auskommentiere, sollte 
die LED eigentlich doppelt so schnell blinken, da ja jetzt auf jede 
Änderung von "clk" der Counter erhöht werden sollte.

Wo liegt der Denkfehler?
1
LIBRARY ieee;
2
USE ieee.std_logic_1164.all;
3
LIBRARY lattice;
4
USE lattice.components.all;
5
6
ENTITY blinking_led IS
7
   PORT(
8
      led  : BUFFER  STD_LOGIC);
9
END blinking_led;
10
11
ARCHITECTURE behavior OF blinking_led IS
12
   SIGNAL  clk  : STD_LOGIC;
13
   --internal oscillator
14
   -- lattice OSCH primitive
15
   COMPONENT OSCH
16
      GENERIC(
17
            NOM_FREQ: string := "53.20");
18
      PORT( 
19
            STDBY    : IN  STD_LOGIC;
20
            OSC      : OUT STD_LOGIC;
21
            SEDSTDBY : OUT STD_LOGIC);
22
   END COMPONENT;
23
BEGIN
24
   --internal oscillator
25
   OSCInst0: OSCH
26
      GENERIC MAP (NOM_FREQ  => "53.20")
27
      PORT MAP (STDBY => '0', OSC => clk, SEDSTDBY => OPEN);
28
   PROCESS(clk)
29
      VARIABLE count :   INTEGER RANGE 0 TO 25_000_000;
30
   BEGIN
31
      -- IF(clk'EVENT AND clk = '1') THEN
32
         IF(count < 25_000_000) THEN
33
            count := count + 1;
34
         ELSE
35
            count := 0;
36
            led <= NOT led;
37
         END IF;
38
      -- END IF;
39
   END PROCESS;
40
END behavior;

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


Lesenswert?

chris schrieb:
> Wo liegt der Denkfehler?
Die Sensitivliste ist NUR und AUSSCHLIEßLICH für die Simulation 
relevant.

> sollte die LED eigentlich doppelt so schnell blinken
Tut sie auch, wenn du das Design simulierst.

>> IF(clk'EVENT AND clk = '1') THEN
> dient ja dazu, den Counter bei der steigenden Flanke zu inkrementieren.
Durch das 'event werden vom Synthesizer Flipflops ins Design eingebaut.

von Dussel (Gast)


Lesenswert?

Meinst du in der Simulation oder auf dem Chip?
Auf dem Chip hat die Liste keine Auswirkung. Die gilt nur für die 
Simulation. Wenn sich auf dem Chip nichts ändert, liegt das wohl daran, 
dass Flip-Flops nur auf eine Flanke reagieren können und der Synthesizer 
deshalb den ganzen Prozess auf eine der Flanken reagieren lässt.

Noch zwei Anmerkungen:

chris schrieb:
>> IF(clk'EVENT AND clk = '1') THEN
>
> dient ja dazu, den Counter bei der steigenden Flanke zu inkrementieren.
Das gilt nicht für die Simulation. Da kann clk andere Zustände als 0 und 
1 haben und dieses if reagiert auf jede Zustandsänderung, die zu einem 
Wert von 1 führt.

Variablen sollte man als Anfänger aus irgendeinem Grund nicht verwenden. 
Da kann man wohl irgendwas Falsches erwarten. Mir ist das noch nicht 
passiert und ich verstehe auch das Problem nicht so ganz, aber so wird 
es gesagt.

von Tim (Gast)


Lesenswert?

sounds good, doesn't work :).

In der Simulation funktioniert das, falls dein Simulator dir nicht einen 
Strich dagegen zieht.

In der Realität ist das Ziel auf eine Hardware die Beschreibung zu 
synthetisieren. Sensitivity-Listen sind dafür nur für die Simulation 
wichtig und werden in der Synthese ignoriert. Und hier bekommst du nun 
mit deiner Beschreibung Probleme.

Falls du auf beide Flanken triggern möchtest, dann wäre das so "besser".
1
IF rising_edge(clk) or falling_edge(clk) then

In der Regel sollte dir die Synthese dir damit eine bessere Rückmeldung 
geben.

Ich denke mal, so oder so, bei dir sind noch größere 
Verständnisschwierigkeiten in VHDL.

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


Lesenswert?

Dussel schrieb:
> Variablen sollte man als Anfänger aus irgendeinem Grund nicht verwenden.
Einfach mal hier rumstöbern:
Beitrag "Variable vs Signal"

chris schrieb:
> ch habe gelesen, dass mit der "sensitive list" in "PROCESS(clk)" immer
> auf ein Wechsel des Signals getriggert wird.
Der Synthesizer wird aus dem Design ohne das 'event übrigens einfach 
eine üble kombinatorische Schleife machen:
http://www.lothar-miller.de/s9y/categories/36-Kombinatorische-Schleife
Sieh dort ganz unten... ;-)

Tim schrieb:
> Falls du auf beide Flanken triggern möchtest, dann wäre das so
> "besser".IF rising_edge(clk) or falling_edge(clk) then
Allerdings gibt es im FPGA eben kein Bauteil, das auf beide Flanken 
getriggert werden könnte. Und deshalb wird es für diese Beschreibung 
eine Fehlermeldung geben.
Man muss seine VHDL Beschreibung so verfassen, dass das Design letztlich 
aus LUT und Flipflops zusammengebaut werden kann. Und dafür müssen 
bestimmte Regeln eingehalten werden, die im Handbuch zum Synthesizer 
beschrieben sind.

Sagen wirs mal so: von 100% VHDL die für die Simulation verwendet werden 
dürfen, können etwa 5% für die Synthese genutzt werden.

: Bearbeitet durch Moderator
von chris (Gast)


Lesenswert?

Vielen Dank für eure hiflreichen Antworten. Ich bin sehr begeistert :-)

Das Beispiel habe ich von hier:
https://eewiki.net/display/LOGIC/Lattice+Diamond+and+MachXO2+Breakout+Board+Tutorial

Zum Testen verwende ich dieses Board:
http://www.mouser.de/new/Lattice-Semiconductor/lattice-machxo2-breakoutboard/

Interessanterweise ergibt sich nach dem Auskommentieren des Wartens auf 
die "rising edge" ein assymetrisches Ausgangssignal von ca. 4ms 
Periodendauer.
Kene Ahnung, wie diese Frequenz dann entsteht.

Autor: Lothar Miller (lkmiller) (Moderator) Benutzerseite
>Man muss seine VHDL Beschreibung so verfassen, dass das Design letztlich
>aus LUT und Flipflops zusammengebaut werden kann. Und dafür müssen
>bestimmte Regeln eingehalten werden, die im Handbuch zum Synthesizer
>beschrieben sind.

Gibt es eine Möglichkeit, wie man genau analysieren kann, wie der Code 
auf die Schaltung abgebildet wird? Beim MC kann man sich ja z.B. den aus 
C-Code generierten Assemblercode ansehen.

>>Tim schrieb:
>Ich denke mal, so oder so, bei dir sind noch größere
>Verständnisschwierigkeiten in VHDL.

Na so ganz "Sattelfest" scheinst Du ja auch nicht zu sein:

>>Tim schrieb:
>> Falls du auf beide Flanken triggern möchtest, dann wäre das so
>> "besser".IF rising_edge(clk) or falling_edge(clk) then
>Autor: Lothar Miller (lkmiller) (Moderator) Benutzerseite
>Allerdings gibt es im FPGA eben kein Bauteil, das auf beide Flanken
>getriggert werden könnte. Und deshalb wird es für diese Beschreibung
>eine Fehlermeldung geben.

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


Lesenswert?

chris schrieb:
> Gibt es eine Möglichkeit, wie man genau analysieren kann, wie der Code
> auf die Schaltung abgebildet wird?
Der RTL-Schaltplan (RTL schematic) ist das, was du suchst. Sieh dir 
einfach mal ein paar Beispiele auf meiner HP an. Wie der bei Altera 
erzeugt wird musst du allerdings selber rausfinden... ;-)

chris schrieb:
> Na so ganz "Sattelfest" scheinst Du ja auch nicht zu sein
Lass stecken.
Prinzipiell stimmt die Aussage und könnte mit einer passenden Library 
evtl. sogar irgendwo realisiert werden. Nur eben nicht in einem FPGA. 
Und ich vermute einfach mal, dass du ein FPGA als Zielsystem hast, denn 
Lattice macht keine ASICs.

: Bearbeitet durch Moderator
von chris (Gast)


Angehängte Dateien:

Lesenswert?

>Nur eben nicht in einem FPGA.
>Und ich vermute einfach mal, dass du ein FPGA als Zielsystem hast,

Bei Lattice nennt es im Datenblatt "PLD".
Im Bild sieht man ein "Slice" des MACHXO7000 PLDs.
Es hat 2 FlipFlops, aber die CLK Leitung triggert für beide auf "High", 
würde ich sagen.

von Dussel (Gast)


Lesenswert?

chris schrieb:
> Es hat 2 FlipFlops, aber die CLK Leitung triggert für beide auf "High",
> würde ich sagen.
Ich weiß nicht, wie es da ist, aber ich glaube, das kann man heute 
konfigurieren. Aber eben nur auf eine Flanke pro Flip-Flopf.

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


Lesenswert?

chris schrieb:
> Bei Lattice nennt es im Datenblatt "PLD".
Stimmt ja auch. Ist ein "Programmable Logic Device". Auf der HP von 
Lattice werden die einfach zusammengefasst:
http://www.latticesemi.com/Products.aspx#_D5A173024E414501B36997F26E842A31
Und tauchen dann als "FPGA & CPLD" auf:
http://www.latticesemi.com/en/Products/FPGAandCPLD/MachXO2.aspx

> Im Bild sieht man ein "Slice" des MACHXO7000 PLDs. Es hat 2 FlipFlops,
> aber die CLK Leitung triggert für beide auf "High", würde ich sagen.
Hilft alles nix, denn das sind 2 getrennte Flipflops, deren Ausgang 
eben auch getrennt ist. Man kann sie also nicht irgendwie wieder 
"automatisch" (z.B. in einer Prozessbeschreibung) zusammenfassen...

: Bearbeitet durch Moderator
von chris (Gast)


Lesenswert?

Nur zur Kontrolle:
1
IF rising_edge(clk) or falling_edge(clk) THEN
ERROR - blink.vhd(55): multiple signals in event expression is not 
synthesizable. VHDL-1136
Done: error code 2

von chris (Gast)


Lesenswert?

>Variablen sollte man als Anfänger aus irgendeinem Grund nicht verwenden.

Ok, ich habe im obigen Beispiel einfach mal den Counter durch einen 
Signalvektor ersetzt:

> SIGNAL count : STD_LOGIC_VECTOR( 31 downto 0 );

und schon compiliert nichts mehr ...

von Bitwurschtler (Gast)


Lesenswert?

> Ok, ich habe im obigen Beispiel einfach mal den Counter durch einen
> Signalvektor ersetzt:
>
>> SIGNAL count : STD_LOGIC_VECTOR( 31 downto 0 );
>
> und schon compiliert nichts mehr ...

weil du noch die passende Bibliothek fürs addieren mit std_logic 
einbinden musst und die Typen aller Operanden anpassen.

https://stackoverflow.com/questions/854684/why-cant-i-increment-this-std-logic-vector

von Markus F. (mfro)


Lesenswert?

chris schrieb:
>>Variablen sollte man als Anfänger aus irgendeinem Grund nicht verwenden.
>
> Ok, ich habe im obigen Beispiel einfach mal den Counter durch einen
> Signalvektor ersetzt:
>
>> SIGNAL count : STD_LOGIC_VECTOR( 31 downto 0 );
>
> und schon compiliert nichts mehr ...

Komisch. Man schreibt ahnungslos und unüberlegt irgendwas hin und schon 
geht's nicht mehr...

- ein integer läßt sich nicht "einfach so" durch einen std_logic_vector 
ersetzten. Sonst wäre ja beides dasselbe. Mit dem einen kann man andere 
Dinge machen als mit dem anderen. Mit "Variable oder Signal" hat das 
nichts zu tun.

- da, wo eine Variablendefinition stand, darf nicht unbedingt eine 
Signaldefinition stehen.


In jeder Sprache gibt es Regeln, die sollte man kennen und sich daran 
halten.

von Bitwurschtler (Gast)


Lesenswert?

Markus F. schrieb:
> - da, wo eine Variablendefinition stand, darf nicht unbedingt eine
> Signaldefinition stehen.

Stimmt, das ist auch falsch, also versuch das ganze erst mit sIGNAL 
STATT Varible ans tickern zu bringen (Tipp: schau ob es schon irgenwo 
eine signaldeklaration gibt, vielleicht wäre das ja der Platz für eine 
zweite?!) und dann strickst du den Typ um. Wobei der der ge-rangte 
integer IMHO die bessere Wahl ist.

Und als drittens  kannst Du ja noch schauen wie du die magic number für 
die Zählerweite ordentlich in ein package oder generic oder beides 
packst.

von Duke Scarring (Gast)


Lesenswert?

Bitwurschtler schrieb:
> weil du noch die passende Bibliothek fürs addieren mit std_logic
> einbinden musst und die Typen aller Operanden anpassen.
Aua.

Wenn man rechnen will, bindet man die ieee.numeric_std.all ein und 
castet std_logic_vector zu signed oder unsigned. Alles andere ist Murks, 
der später zu langer Fehlersuche führen kann. BTDT.

Duke

von chris (Gast)


Lesenswert?

Autor: Bitwurschtler (Gast)
>weil du noch die passende Bibliothek fürs addieren mit std_logic
>einbinden musst und die Typen aller Operanden anpassen.

Dankeschön, das war der Tipp :-)


Autor: Markus F. (mfro)
>Komisch. Man schreibt ahnungslos und unüberlegt irgendwas hin und schon
>geht's nicht mehr...

Kannst Du bitte in einem anderem Thread posten? Dein Ton stört mich.

von Tim (Gast)


Lesenswert?

chris schrieb:
> Nur zur Kontrolle:IF rising_edge(clk) or falling_edge(clk) THEN
> ERROR - blink.vhd(55): multiple signals in event expression is not
> synthesizable. VHDL-1136
> Done: error code 2

Genau diese (negative) Rückmeldung des Tools meinte ich. Scheinbar wurde 
ich nicht richtig verstanden :)

von Markus F. (mfro)


Lesenswert?

chris schrieb:
> Autor: Bitwurschtler (Gast)
>>weil du noch die passende Bibliothek fürs addieren mit std_logic
>>einbinden musst und die Typen aller Operanden anpassen.
>
> Dankeschön, das war der Tipp :-)
>
>
> Autor: Markus F. (mfro)
>>Komisch. Man schreibt ahnungslos und unüberlegt irgendwas hin und schon
>>geht's nicht mehr...
>
> Kannst Du bitte in einem anderem Thread posten? Dein Ton stört mich.

Nö. Ich schreib' nur, was ich denke.

Oder hast Du das etwa mit einer Ahnung und nach ausgiebiger 
Kontemplation hingeschrieben? Das wär' eigentlich sogar noch schlimmer.

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


Lesenswert?

chris schrieb:
> Dein Ton stört mich.
Sehr dünnhäutig...

Denn der Rest des Posts ist durchaus hilfreich: VHDL ist eben nicht 
Verilog oder gar C, wo viele Typumwandlungen implizit und "hintenrum" 
stattfinden. In VHDL muss jede Typumwandlung explizit ausgeschrieben 
werden. Und vom std_logic_vector zum integer und zurück geht das mit der 
numeric_std nur über einen Umweg:
http://www.lothar-miller.de/s9y/categories/16-Numeric_Std

: Bearbeitet durch Moderator
von chris (Gast)


Lesenswert?

> Autor: Markus F. (mfro)
> Komisch. Man schreibt ahnungslos und unüberlegt irgendwas hin und schon
> geht's nicht mehr...
> ..
> Nö. Ich schreib' nur, was ich denke.

Manchmal ist es aber besser, erst zu denken und dann zu schreiben

>In jeder Sprache gibt es Regeln, die sollte man kennen und sich daran
>halten.

Da bin ich zu 100% deiner Meinung. Auch was die Umgangsformen betrifft.

von chris (Gast)


Lesenswert?

Tim schrieb:
> Falls du auf beide Flanken triggern möchtest, dann wäre das so
> "besser".IF rising_edge(clk) or falling_edge(clk) then
> ...
> Scheinbar wurde ich nicht richtig verstanden :)

Naja, für mich sah dass so aus, als wenn es kompilieren sollte.
Nichts desto trozt nehme ich deinen Vorschlag "rising_edge(clk)" zu 
verwenden mal für das nächste Beispiel.

Die LED soll jetzt "faden". Dazu brauche ich also ein PWM.

Ich habe die PWM und die Zähler in eine Architektur gepackt. 
Wahrscheinlich wäre es besser, ein extra PWM-vhdl File zu machen, aber 
ich weiß nicht, wie man ein zweites "File" includiert.

Hier der erste funktionierende Anlauf:
1
LIBRARY ieee;
2
USE ieee.std_logic_1164.all;
3
USE ieee.std_logic_unsigned.all; -- unbedingt notwendig für die Addition von STD_LOGIC_VECTOR
4
5
LIBRARY lattice;
6
USE lattice.components.all;
7
8
ENTITY blinking_led IS
9
   PORT(
10
      led  : BUFFER STD_LOGIC;
11
    led2 : BUFFER STD_LOGIC
12
    );
13
END blinking_led;
14
15
ARCHITECTURE behavior OF blinking_led IS
16
  SIGNAL  sysclk     : STD_LOGIC;
17
  SIGNAL  vorteiler  : STD_LOGIC_VECTOR ( 31 downto 0 );
18
  SIGNAL  pwmCounter : STD_LOGIC_VECTOR (  7 downto 0 );
19
  SIGNAL  pwmValue   : STD_LOGIC_VECTOR (  7 downto 0 );
20
   
21
   -- lattice oscillator OSCH primitive
22
   COMPONENT OSCH
23
      GENERIC(
24
            NOM_FREQ: string := "53.20");
25
      PORT( 
26
            STDBY    : IN  STD_LOGIC;
27
            OSC      : OUT STD_LOGIC;
28
            SEDSTDBY : OUT STD_LOGIC);
29
   END COMPONENT;
30
31
BEGIN
32
   -- lattice oscillator OSCH primitive
33
   -- internal oscillator
34
   OSCInst0: OSCH
35
      GENERIC MAP (NOM_FREQ  => "53.20") -- 53.2 MHz syssysclk
36
      PORT MAP (STDBY => '0', OSC => sysclk, SEDSTDBY => OPEN);
37
    
38
   blink: PROCESS(sysclk)
39
   BEGIN
40
     IF falling_edge(sysclk) THEN
41
         IF(vorteiler < 53*100) THEN
42
            vorteiler <= vorteiler + 1;
43
         ELSE
44
            vorteiler  <= x"00000000";
45
      pwmCounter <= pwmCounter +1;
46
      IF ( pwmCounter = x"00" ) THEN
47
        pwmValue <= pwmValue + 1;
48
      END IF;
49
            led <= NOT led;
50
         END IF;
51
      END IF;
52
   END PROCESS blink;
53
   
54
   pwm: PROCESS(sysclk)
55
   BEGIN
56
    IF ( pwmValue > pwmCounter) THEN
57
      led2 <= '0';
58
    ELSE
59
      led2 <= '1';
60
    END IF;
61
   END PROCESS pwm;
62
   
63
   
64
END behavior;

von Markus F. (mfro)


Lesenswert?

Du hörst nicht (Beitrag "Re: VHDL Grundlagen"). 
Musst Du ja auch nicht, ist ja deine Sache...

Trotzdem.

Man rechnet nicht mit std_logic_vector. Punkt.

Oder nur, wenn man sich unbedingt (durchaus auch erst später) selbst ins 
Knie schiessen will.

Das Package ieee.std_logic_unsigned (das, obwohl's so heisst, 
tatsächlich nur ein "pseudo-standard" ist) mappt std_logic_vector auf 
unsigned. Bedingungslos.

Das ist zwar (erst mal) bequem, rächt sich aber spätestens dann, wenn Du 
mal vorzeichenbehaftete Arithmetik brauchst.

Dann musst Du - wenn Du die Vorzeichenbits nicht selbst verwurschteln 
willst - dir entweder doch die ieee.numeric_std oder die 
ieee.std_logic_signed  dazuholen und plötzlich hast Du in der Arithmetik 
Mehrdeutigkeiten, die dich von einer Verzweiflung in die nächste 
treiben.

Wie's richtig geht, steht hier: 
https://www.mikrocontroller.net/articles/Rechnen_in_VHDL oder hier: 
http://www.lothar-miller.de/s9y/categories/16-Numeric_Std .


Wenn dein Synthesetool VHDL 2008 kann, solltest Du das auch verwenden, 
dann werden ein paar Dinge (wie z.B. die eindeutige Typisierung von 
signed/unsigned Literalen) ein wenig einfacher.


Noch besser ist natürlich, unnötige Typumwandlungen gleich komplett zu 
vermeiden, indem man den Signalen bei der Definition schon genau den 
ihrer Verwendung entsprechenden Typ gibt. In deinem Code oben gibt's 
z.B. keinen Grund, warum vorteiler, pwmCounter oder pwmValue unbedingt 
ein std_logic_vector sein muss. Sie werden auch nirgends einem solchen 
zugewiesen (wo dann wieder eine Typumwandlung notwendig wäre).

Hättest Du die Signale gleich als integer oder unsigned definiert, 
hättest Du ganz bequem direkt damit rechnen können. Ganz ohne 
ieee.std_logic_unsigned.

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


Lesenswert?

chris schrieb:
> pwm: PROCESS(sysclk)
>    BEGIN
>     IF ( pwmValue > pwmCounter) THEN
>       led2 <= '0';
>     ELSE
>       led2 <= '1';
>     END IF;
>    END PROCESS pwm;
Die Sensitivliste ist falsch. Und folglich passt die Simulation nicht 
zur Realität. Ich hatte die entsprechenden Links schon gepostet. Du 
solltest sie lesen und versuchen ihren Inhalt zu verstehen.

Solche Kombinatorik schreibt man übrigens besser nebenläufig 
(concurrent) ganz ohne Prozess:
LED <= '0' when pwmValue > pwmCounter else '1';

Fazit: aus 8 Zeilen mitsamt falscher Sensitivliste ist 1 Zeile geworden.

Und zum Thema  std_logic_unsigned sieh dir den 
Beitrag "IEEE.STD_LOGIC_ARITH.ALL obsolete" inklusive der darin 
angeführten Links an.

: Bearbeitet durch Moderator
von Tim (Gast)


Lesenswert?

Ein paar Vorschläge :
Ich würde statt buffer lieber out nehmen. Schließlich treibst du den led 
Ausgang. Ob nun Strom in den pin reinfließt oder nicht, ist egal für die 
Beschreibung.
Selber habe ich auch noch nie buffer verwendet bzw. sah ich noch nie die 
Notwendigkeit.

Zweitens. Hast du schonmal simuliert das ganze? Led sollte nichts 
zeigen, da nichts initialisiert ist. Wenn du dann auf out gestellt hast, 
dann bekommst du sowieso ein Fehler. Den behebst du durch die Verwendung 
eines internen signals, dass du auf led führst. Interne Signale kannst 
du beim FPGA initialisieren mit Werten. Bei den meisten :)

Drittens. Ist es für deine Anwendung ok, dass zwei Zähler in den 
Überlauf gehen? Kann man machen.

Viertens. Simuliere mal. Spart Zeit beim Fehler finden.

von chris (Gast)


Lesenswert?

>Hast du schonmal simuliert das ganze? Led sollte nichts
>zeigen, da nichts initialisiert ist.

Ich habe noch kein "Simulation-File" deshalb konnte ich es nicht 
simulieren.
Deshalb habe ich es einfach runter geladen und mit dem Logik-Analysator 
überprüft.
Ergebnis: es funktioniert ;-)

von chris (Gast)


Lesenswert?

>Drittens. Ist es für deine Anwendung ok, dass zwei Zähler in den
>Überlauf gehen? Kann man machen.

Da ich ja noch in der Experimentalphase bin, ist es eher ein Test als 
eine Anwendung.
Die Zähler sind absichtlich mit 8Bit realisiert, so dass sie immer von
0-255 durchlaufen.
Damit wird erreicht, dass die LED langsam immer heller wird und dann 
schlagartig wieder dunkel.

von chris (Gast)


Lesenswert?

Die Entwicklungsumgebung von Altera "Diamond" hat auch den sogenannten 
"Reveal In-Circuit Debugger" damit kann man direkt in das Design rein 
schauen:

https://youtu.be/SmdEP_ZsBgM
( Minute 23:30 )

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


Lesenswert?

chris schrieb:
> Altera "Diamond"
Klingt wie "Opel Golf"....

Ich empfehle dir dringendst, von der (aus der Software bekannten) 
"AufderHardwareausprobierem"-Designstrategie wegzukommen und das 
Hardwaredesign schon vorher funktional zu simulieren.
Wenn ein Design nämlich funktional fehlerfrei durch die Simulation geht 
und grundlegende Designregeln (Einsynchronisieren...)  eingehalten 
wurden, dann läuft es hinterher mit.hoher Wahrscheinlichkeit ganz ohne 
Herumgebastel mit internen oder externen Logikanalysern.
Die werden nur dann gebraucht, wenn etwas trotzdem nicht funktioniert...

von chris (Gast)


Angehängte Dateien:

Lesenswert?

Gemach, Gemach kommt schon noch. Ich muss die Dinge nacheinander 
ausprobieren.

Mittlerweile habe ich einen Weg gefunden, den RTL-Level des PWM 
Beispiels graphisch darzustellen.
Das Tool bei Lattice heißt "simplified Pro".

Ein wenig unübersichtlich sieht das Ganze schon aus ...

von chris (Gast)


Lesenswert?

Tim schrieb
>Ein paar Vorschläge :
>Ich würde statt buffer lieber out nehmen. Schließlich treibst du den led
>Ausgang. Ob nun Strom in den pin reinfließt oder nicht, ist egal für die
>Beschreibung.

Die Grundlage für den Code habe ich ja aus dem Blink-Beispiel vom Anfang 
kopiert.
Buffer hat den Vorteil, dass die LED gelesen und invertiert werden kann:
1
..
2
led  : BUFFER  STD_LOGIC);
3
..
4
led <= NOT led;
5
..

Die Verwendung von "OUT" wirft folgenden Fehler:
> cannot read from 'out' object led ; use 'buffer' or 'inout'

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


Lesenswert?

chris schrieb:
> Die Verwendung von "OUT" wirft folgenden Fehler:
>> cannot read from 'out' object led ; use 'buffer' or 'inout'
Das wäre jetzt ein guter Zeitpunkt für ein Google-Fenster im Browser...

Buffer oder Inout zu nehmen, nur um den Port zurücklesen zu können und 
sich sich ein lokales Signal zu sparen, ist eigentlich ein 
Kündigungsgrund.

Nimm meinen Blink-Code, der ist sauber mit lokalem Signal x und einem 
integer als Zähler gemacht:
http://www.lothar-miller.de/s9y/archives/80-Hello-World!.html

BTW: auf dem Rest der Seiten dort findest du Antworten auf etwa 99% der 
üblichen Anfängerfragen und Anfängerfehler...  ;-)

: Bearbeitet durch Moderator
von chris (Gast)


Lesenswert?

>Nimm meinen Blink-Code, der ist sauber mit lokalem Signal x und einem
>integer als Zähler gemacht:
>http://www.lothar-miller.de/s9y/archives/80-Hello-...

Da hast Du eine sehr schöne Seite gemacht.
Das ist eigentlich genau das was ich suche :-)

Was mir gerade auffällt: In Deinen Beispielen ist ein SPI-Master. 
Vielleicht wäre ein SPI-Slave auch gut. Ich plane, einen Mikrocontroller 
als "CPU" zu verwenden und das PLD damit zu steuern. Die Kombination 
scheint mir sehr günstig, weil sich ein MC viel einfacher programmieren 
lässt und wesentlich komplexere Programme erlaubt.

von Markus F. (mfro)


Lesenswert?

chris schrieb:
> Die Verwendung von "OUT" wirft folgenden Fehler:
>> cannot read from 'out' object led ; use 'buffer' or 'inout'

Ich wiederhole mich: wenn dein Synthesetool VHDL 2008 kann, schalt's 
ein.

Da kann man OUT-Signale lesen.

von Sigi (Gast)


Lesenswert?

Markus F. schrieb:
> Da kann man OUT-Signale lesen.

IA nein, oft aber ja.
Betrachtet man als Beispiel ein Enable-Signal
für ein Port-OUT-Signal, das registriert werden
soll. Wird das entsprechende Register in die
IO-Zelle des FPGA gelegt, dann ist das
Register-OUT-Signal nicht mehr lesbar. Wie das
das 2008er VHDL umgehen will..?

von Markus F. (mfro)


Lesenswert?

Sigi schrieb:
> Wird das entsprechende Register in die
> IO-Zelle des FPGA gelegt, dann ist das
> Register-OUT-Signal nicht mehr lesbar. Wie das
> das 2008er VHDL umgehen will..?

Macht die Synthese so was, wenn ich das OUT-Signal lese?

von Sigi (Gast)


Lesenswert?

Markus F. schrieb:
> Macht die Synthese so was, wenn ich das OUT-Signal lese?

Natürlich kannst du (bzw. der Synthesizer) das so
implementieren, dass das OUT-Signal noch gelesen
werden kann (einfach das OutputEN-Register in eine
benachbarten Logikzelle setzen). Wenn du aber
zusätzlich zu deinem VHDL-Design nich Location-
oder harte Timing- Constraints setzt, dann erzwingst
du damit idR einen Konflikt, d.h. der Synthesizer
gibt eine Warnung oder einen Fehler aus.

Konkrekt bei einem "schnellen" SDRAM-Controller: Wenn
du die entsprechenden OUT-Signale liest, dann zerstörst
du das Timing, d.h. der Controller wird langsamer.

Andere Beispiele sind z.B. schnelle PHYs/Tranceiver
oder Hardwired-Controller.

von Markus F. (mfro)


Lesenswert?

Sigi schrieb:
> Konkrekt bei einem "schnellen" SDRAM-Controller: Wenn
> du die entsprechenden OUT-Signale liest, dann zerstörst
> du das Timing, d.h. der Controller wird langsamer.

Nun, das ist ja klar. Die Frage ist, was das Tool macht.

Quartus meckert öfters mal, es könne Signale nicht als "Fast 
Out-/Input-Register" constrainen. Warum nicht, ist oft kaum rauszufinden 
(nein, an VHDL 2008 liegt's in den Fällen nicht).

von Sigi (Gast)


Lesenswert?

Markus F. schrieb:
> Quartus meckert öfters mal, es könne Signale nicht als "Fast
> Out-/Input-Register" constrainen. Warum nicht, ist oft kaum rauszufinden

Da wär für mich der Hauptgrund, dass das OUT-Signal
irgendwo nochmal gelesen wird, z.B. auch durch den
Quartus-LogicAnalizer (SignalTapII etc.). Aber das
lässt sich z.B. im RTL-Viewer etc. rauslesen.

Es kann aber auch sein, dass durch Timing-Constraints
das "Valid"-Fenster so gesetzt ist, dass eine
Instantiierung in der IO-Zelle nicht in Frage kommt.
Sicherlich gibt's aber noch andere Gründe.

von Sigi (Gast)


Lesenswert?

..aber unabhängig von meinen Beispiel, in 99%
aller Fälle hast du natürlich recht, man kann
es immer so Implementieren, dass eben das
OUT-Signal auch noch gelesen werden kann
(99%: idR sind hier die Fälle gemeint, wo
die OUT-Signale in übergeordnete, nicht
TOP-Level Komponenten wandern).

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


Lesenswert?

Markus F. schrieb:
> Macht die Synthese so was, wenn ich das OUT-Signal lese?
Festzulegen, wo was hinkommt ist eigentlich nicht Aufgabe des 
Synthesizers...

chris schrieb:
> Vielleicht wäre ein SPI-Slave auch gut.
Sieh dir mal den Beitrag "Erfahrung mit SPI Slave und Spartan 6 FPGA?" von vorn 
bis hinten an.

: Bearbeitet durch Moderator
von chris (Gast)


Lesenswert?

Hier Dein BlinkLed example um den Oscillator für das MACHXO2 breakout 
board erweitert, damit es dort gleich blinkt.
1
-- http://www.lothar-miller.de/s9y/archives/80-Hello-World.html
2
-- extended with clock generator for MACHXO2
3
library ieee;
4
use IEEE.STD_LOGIC_1164.ALL; 
5
use IEEE.NUMERIC_STD.ALL; 
6
7
LIBRARY lattice;
8
USE lattice.components.all;
9
 
10
entity BlinkLED is 
11
    Port (  
12
           led : out  STD_LOGIC); 
13
end BlinkLED; 
14
 
15
architecture Behavioral of BlinkLED is 
16
17
signal c : integer range 0 to 24999999 := 0; -- 0,5s bei 50MHz fosc
18
signal x : std_logic:= '0';  
19
signal clk : STD_LOGIC;
20
21
   -- lattice oscillator OSCH primitive
22
   COMPONENT OSCH
23
      GENERIC(
24
            NOM_FREQ: string := "53.20");
25
      PORT( 
26
            STDBY    : IN  STD_LOGIC;
27
            OSC      : OUT STD_LOGIC;
28
            SEDSTDBY : OUT STD_LOGIC);
29
   END COMPONENT;
30
31
begin 
32
   -- lattice oscillator OSCH primitive
33
   -- internal oscillator
34
   OSCInst0: OSCH
35
      GENERIC MAP (NOM_FREQ  => "53.20") -- 53.2 MHz syssysclk
36
      PORT MAP (STDBY => '0', OSC => clk, SEDSTDBY => OPEN);
37
    
38
   process begin  
39
      wait until rising_edge(clk); -- warten bis zum nächsten Takt 
40
      if (c<24999999) then         -- 0…24999999 = 25000000 Takte = 1/2 Sekunde bei 50MHz 
41
          c <= c+1;                -- wenn kleiner: weiterzählen 
42
      else                         -- wenn Zählerende erreicht: 
43
          c <= 0;                  -- Zähler zurücksetzen 
44
          x <= not x;              -- und Signal x togglen 
45
      end if; 
46
   end process; 
47
   led <= x;                       -- Signal x an LED ausgeben 
48
end Behavioral;

von chris (Gast)


Lesenswert?

Hier mein erstes Lauflicht ( aus dem modifizierten BlinkLed ).

Das Lauflicht hat 8 Zustände für die 8 LEDs.
Eigentlich wollte ich ein "Knight Rider" Lauflicht machen:

https://www.youtube.com/watch?v=4fjDWSFsv8o

wobei die originale Version sogar mit "Fading" wäre, was aber die ganze
Sache ziemlich kompliziert machen dürfte:

https://www.youtube.com/watch?v=iQwlrEdka6Q

Für ein hin und zurücklaufen der Lichterkette bräuchte man mehr als 8 
Zustände. Sobald ich aber
1
signal x : integer range 0 to 7 := 0;

um nur einen Zustand erhöhe, geht nichts mehr.
1
-- http://www.lothar-miller.de/s9y/archives/80-Hello-World.html
2
-- extended with clock generator for MACHXO2
3
library ieee;
4
use IEEE.STD_LOGIC_1164.ALL; 
5
use IEEE.NUMERIC_STD.ALL; 
6
7
LIBRARY lattice;
8
USE lattice.components.all;
9
 
10
entity BlinkLED is 
11
    Port (  
12
           led : out  STD_LOGIC_VECTOR ( 7 downto 0 )
13
      ); 
14
end BlinkLED; 
15
 
16
architecture Behavioral of BlinkLED is 
17
18
signal c : integer range 0 to 24999999 := 0; -- 0,5s bei 50MHz fosc
19
signal x : integer range 0 to 7 := 0;  
20
signal clk : STD_LOGIC;
21
22
   -- lattice oscillator OSCH primitive
23
   COMPONENT OSCH
24
      GENERIC(
25
            NOM_FREQ: string := "53.20");
26
      PORT( 
27
            STDBY    : IN  STD_LOGIC;
28
            OSC      : OUT STD_LOGIC;
29
            SEDSTDBY : OUT STD_LOGIC);
30
   END COMPONENT;
31
32
begin 
33
   -- lattice oscillator OSCH primitive
34
   -- internal oscillator
35
   OSCInst0: OSCH
36
      GENERIC MAP (NOM_FREQ  => "53.20") -- 53.2 MHz syssysclk
37
      PORT MAP (STDBY => '0', OSC => clk, SEDSTDBY => OPEN);
38
    
39
   process begin  
40
      wait until rising_edge(clk); -- warten bis zum nächsten Takt 
41
      if ( c < 24999999/4 ) then  
42
          c <= c+1;                -- wenn kleiner: weiterzählen 
43
      else                         -- wenn Zählerende erreicht: 
44
          c <= 0;                  -- Zähler zurücksetzen 
45
          x <= x + 1 ;             
46
      end if; 
47
   end process; 
48
   
49
   led(0) <= '0' when x=0 else '1';
50
   led(1) <= '0' when x=1 else '1';
51
   led(2) <= '0' when x=2 else '1';
52
   led(3) <= '0' when x=3 else '1';
53
   led(4) <= '0' when x=4 else '1';
54
   led(5) <= '0' when x=5 else '1';
55
   led(6) <= '0' when x=6 else '1';
56
   led(7) <= '0' when x=7 else '1';
57
      
58
end Behavioral;

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


Lesenswert?

chris schrieb:
> Für ein hin und zurücklaufen der Lichterkette bräuchte man mehr als 8
> Zustände. Sobald ich aber
> signal x : integer range 0 to 7 := 0;
> um nur einen Zustand erhöhe, geht nichts mehr
Ich würde das jetzt einfach mal simulieren. Und wie "Zustand"? Das ist 
ja einfach ein Zähler für den Index...

> Sobald ich aber
> signal x : integer range 0 to 7 := 0;
> um nur einen Zustand erhöhe, geht nichts mehr
Sieh dir die Meldungen an. Ratzfatz optimiert dir der Synthesizer die 
Schaltung weg, wenn er erkennt, dass die aus einem Zustand nicht mehr 
rauskommen wird.

>     if ( c < 24999999/4 ) then
Hast du dir da schon richtig überlegt, ob das mit dem /4 richtig ist? 
Daraus wird ganz schnell so eine "Off by one" Geschichte...


Da ist übrigens der Knight Rider mit Fading:
http://www.lothar-miller.de/s9y/archives/61-Lauflicht.html

: Bearbeitet durch Moderator
von chris (Gast)


Angehängte Dateien:

Lesenswert?

>Ich würde das jetzt einfach mal simulieren. Und wie "Zustand"? Das ist
>ja einfach ein Zähler für den Index...

Akademisch gesprochen ist ein Zähler eine Zustandsmaschine.
Der Zustand des Zählers kann auf verschiedene Weisen auf die LEDs 
abgebildet werden ( mit Vergleichsoperationen oder ROM usw .. so wie Du 
es in Deinen Beispielen gemacht hast ).
Das ist die Strutur eines "Moore-Automaten":
https://de.wikipedia.org/wiki/Moore-Automat#/media/File:Moore-Automat-de.svg

>Hast du dir da schon richtig überlegt, ob das mit dem /4 richtig ist?
>Daraus wird ganz schnell so eine "Off by one" Geschichte...

Ich bin davon ausgegangen, dass das Ergebnis eine Integer Zahl wie bei 
'c' ist. Ebenso dass durch die Priorität der Operatoren '/' vor '<' 
berechnet wird. Und dass die Division ein MACRO für den Precompiler ist.
Wenn dem so wäre, sollte es für diesen Fall kein Problem sein.

>Ich würde das jetzt einfach mal simulieren.
Simulieren kann ich noch nicht. Aber im Anhang sind die beiden 
RTL-Schaltplane für den Entwurf für 8 und 9 Zuständen ( Zähler von 0..7 
und Zähler von 0..8 ).
Auf RTL Level kann ich nicht erkennen, dass da was wegoptimiert wird.

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


Lesenswert?

chris schrieb:
>> Ich würde das jetzt einfach mal simulieren. Und wie "Zustand"? Das ist
>> ja einfach ein Zähler für den Index...
> Akademisch gesprochen ist ein Zähler eine Zustandsmaschine.
Richtig. Allerdings spricht man zur Klarstellung, dass hier ein solch 
"einfacher Automat" eingesetzt wird, trotzdem vom Zählerwert und nicht 
vom Zählerzustand.

> Ich bin davon ausgegangen,
Kann man machen...

> dass das Ergebnis eine Integer Zahl wie bei c' ist. Ebenso dass
> durch die Priorität der Operatoren '/' vor '<' berechnet wird.
> Und dass die Division ein MACRO für den Precompiler ist.
Soweit alles richtig.
> Wenn dem so wäre, sollte es für diesen Fall kein Problem sein.
Mit meiner Off-by-one Bemerkung geht es um die formale Korrektheit der 
Berechnung. Denn 24999/4 sind 6249.75, und diese 0.75 werden (zum Glück) 
"einfach abgeschnitten" auf den richigen Wert 6249. Formal richtig (ohne 
diese implizite Abrundung) wäre die Berechnung des Zählerendwerts aber 
so: (25000/4)-1, weil die 24999 ja von 25000-1 kommen.

> Auf RTL Level kann ich nicht erkennen, dass da was wegoptimiert wird.
Ja, das sieht klar so aus als ob der Zähler jetzt 4 Bit breit ist und 
dass das MSB nicht verwendet wird und konstant 0 ist. Es wird also 
trotzdem später noch wegoptimiert.
Wie gesagt: simuliere deine Beschreibung!
Du verlässt dich bei x (schon wieder) auf einen impliziten Überlauf oder 
hoffst gar auf ein Zurücksetzen das nie stattfindet:
1
signal x : integer range 0 to 8 := 0;  
2
:
3
:   
4
   process begin  
5
      wait until rising_edge(clk); -- warten bis zum nächsten Takt 
6
        :
7
        x <= x + 1 ;             
8
        :
9
   end process;
Was wird deiner Meinung nach hier das Signal x machen, wenn es den 
Maximalwert 8 hat und weitergezählt wird?

Fazit: behandle auch die obere Grenze von x formal korrekt wie die von 
c:
1
signal x : integer range 0 to 8 := 0;  
2
:
3
:
4
   process begin  
5
      wait until rising_edge(clk); -- warten bis zum nächsten Takt 
6
      if ( c < 24999999/4 ) then  
7
          c <= c+1;                -- wenn kleiner: weiterzählen 
8
      else                         -- wenn Zählerende erreicht: 
9
          c <= 0;                  -- Zähler zurücksetzen 
10
          if (x<8) then            -- Zähler x formal korrekt abhandeln
11
             x <= x+1 ; 
12
          else
13
             x <= 0;
14
          end if;
15
      end if; 
16
   end process;

: Bearbeitet durch Moderator
von chris (Gast)


Lesenswert?

>Richtig. Allerdings spricht man zur Klarstellung, dass hier ein solch
>"einfacher Automat" eingesetzt wird, trotzdem vom Zählerwert und nicht
>vom Zählerzustand.
Ich denke mal, das hängt vom jeweiligen Erfahrungshintergrund ab. Für 
Leute, die sich relativ viel mit der "Zustandsbetrachtung" technischer 
Systeme befassen, dürfte der Begriff weniger ein Problem sein.
Wenn's dem Verständnis dient, können wir aber auch den anderen Begriff 
verwenden.

>Was wird deiner Meinung nach hier das Signal x machen, wenn es den
>Maximalwert 8 hat und weitergezählt wird?

Dort spielt wieder mein 'c'-Erfahrungshintergrund eine Rolle.
Ich bin davon ausgegangen, dass der Wert 8 ein Minimum für den zu 
synthetisierenden Zähler darstellt und also ein 4Bit Zähler 
synthetisiert wird und dieser dann beim Zählerstand ;-) 15 umklappt. Für 
den Test mit den Vergleichen wäre das erst mal egal gewesen. Es hätte 
halt vom Zählerstand 9 bis 15 keine LED geleuchtet.

>> Auf RTL Level kann ich nicht erkennen, dass da was wegoptimiert wird.
>Ja, das sieht klar so aus als ob der Zähler jetzt 4 Bit breit ist und
>dass das MSB nicht verwendet wird und konstant 0 ist. Es wird also
>trotzdem später noch wegoptimiert.
Theoretisch dürfte es ja nicht konstant '0' weil 8=0b1000 ;
Dehalb hätte es mit meiner obigen Annahme funktionieren müssen und im 
RTL-Schaltplan sieht man es auch nicht. Dort bin ich wirklich davon 
ausgegangen, dass das die "Wahrheit" darstellt, die auf dem Chip 
programmiert wird, so wie Assembler im Gegensatz zu 'c'.

>Fazit: behandle auch die obere Grenze von x formal korrekt
Tatsächlich, damit geht es, danke ;-)
Ich habe also gelernt: "in VHDL niemals auf das nicht formulierte 
umklappen eines Zählerstandes vertrauen" ( obwohl es beim Zählerendwert 
7 noch funktioniert )

Hier Knight Rider V1:
1
library ieee;
2
use IEEE.STD_LOGIC_1164.ALL; 
3
use IEEE.NUMERIC_STD.ALL; 
4
5
LIBRARY lattice;
6
USE lattice.components.all;
7
 
8
entity BlinkLED is 
9
    Port (  
10
           led : out  STD_LOGIC_VECTOR ( 7 downto 0 )
11
      ); 
12
end BlinkLED; 
13
 
14
architecture Behavioral of BlinkLED is 
15
16
signal c : integer range 0 to 24999999 := 0; -- 0,5s bei 50MHz fosc
17
signal x : integer range 0 to 15 := 0;  
18
signal clk : STD_LOGIC;
19
20
   -- lattice oscillator OSCH primitive
21
   COMPONENT OSCH
22
      GENERIC(
23
            NOM_FREQ: string := "53.20");
24
      PORT( 
25
            STDBY    : IN  STD_LOGIC;
26
            OSC      : OUT STD_LOGIC;
27
            SEDSTDBY : OUT STD_LOGIC);
28
   END COMPONENT;
29
30
begin 
31
   -- lattice oscillator OSCH primitive
32
   -- internal oscillator
33
   OSCInst0: OSCH
34
      GENERIC MAP (NOM_FREQ  => "53.20") -- 53.2 MHz syssysclk
35
      PORT MAP (STDBY => '0', OSC => clk, SEDSTDBY => OPEN);
36
    
37
   process begin  
38
      wait until rising_edge(clk); -- warten bis zum nächsten Takt 
39
      if ( c < 24999999/4 ) then  
40
          c <= c+1;                -- wenn kleiner: weiterzählen 
41
      else                         -- wenn Zählerende erreicht: 
42
          c <= 0;                  -- Zähler zurücksetzen 
43
      if (x <13) then
44
        x <= x + 1 ;
45
      else
46
        x <= 0;
47
    end if;
48
      end if; 
49
50
   end process; 
51
   
52
   led(0) <= '0' when x=0 else '1';
53
   led(1) <= '0' when x=1 or x=13 else '1';
54
   led(2) <= '0' when x=2 or x=12 else '1';
55
   led(3) <= '0' when x=3 or x=11 else '1';
56
   led(4) <= '0' when x=4 or x=10 else '1';
57
   led(5) <= '0' when x=5 or x=9  else '1';
58
   led(6) <= '0' when x=6 or x=8  else '1';
59
   led(7) <= '0' when x=7 else '1';
60
         
61
end Behavioral;

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


Lesenswert?

chris schrieb:
> mein 'c'-Erfahrungshintergrund
Ist für Hardwarebeschreibung (besonders mit der Beschreibungssprache 
VHDL) unnütz. Die ganzen impliziten Annahmen die dir das Leben in C so 
angenehm (und auch überraschend) machen, die gibt es in VHDL nicht. Dort 
zählt nur, was explizit geschrieben steht. Von allem anderen darf die 
Toolchain annehmen, dass sie freie Hand hat. Und die nützt sie gnadenlos 
aus: wenn du einen Zähler so beschreibst, dass er nicht zurückgesetzt 
wird, dann darf die Toolchain annehmen, dass der bis "unendlich" zählt. 
Und für "unendlich" optimieren. Wenn du "unendlich" nicht auswertest, 
dann optimiert sie einfach alles weg, was von "unendlich" nicht 
betroffen ist.

> Ich habe also gelernt: "in VHDL niemals auf das nicht formulierte
> umklappen eines Zählerstandes vertrauen" ( obwohl es beim Zählerendwert
> 7 noch funktioniert )
Weil zusätzlich auch zufällig alle Zählerwerte verwendet werden...

> Ich bin davon ausgegangen
> Theoretisch dürfte es ja nicht konstant '0' weil 8=0b1000
Wie gesagt: nimm nichts an und erwarte nichts (von "drarauf vertrauen" 
gar nicht zu reden). Es gilt in VHDL nur und ausschließlich das 
geschriebene Wort.

von Andreas S. (Firma: Schweigstill IT) (schweigstill) Benutzerseite


Lesenswert?

Lothar M. schrieb:
> Die ganzen impliziten Annahmen die dir das Leben in C so
> angenehm (und auch überraschend) machen, die gibt es in VHDL nicht.

Gerade in C machen sich viele Entwickler leider überhaupt keine Gedanken 
über Wertebereiche und die Gültigkeit von Ausdrücken. Die Compiler 
drücken da insbesondere auf niedrigen Optimierungsstufen häufig auch ein 
Auge zu und greifen nicht allzu tief in die Trickkiste des Optimierers.

Beispiel:
1
uint32_t a;
2
3
...
4
5
a = 10;
6
a = a >> 35;
7
8
...

Welchen Wert hat "a" anschließend? Die intuitive Annahme, dass auf jeden 
Fall "a=0" wäre, entspricht nicht der Definition im C-Standard. Dieser 
besagt nämlich, dass Schiebeoperationen um mehr als die Breite des 
Datentyps undefiniert sind. Deswegen kann der Compiler die obige 
Berechnung wie folgt umsetzen (ohne Anspruch auf Vollständigkeit):

1. Er ist "nett" und setzt "a" auf den zur Kompilierzeit vorberechneten 
Wert "a=0".

2. Er stellt fest, dass a in ein Register passt und mit einem 
Schiebebefehl des Befehlssatzes entsprechend geschoben werden kann. 
Dabei ist er "nett" und begrenzt diesen Schiebebefehl auf den maximal 
möglichen Wert, ohne dass es zu einem Überlauf kommt.

3. Er stellt fest, dass a in ein Register passt und mit einem 
Schiebebefehl des Befehlssatzes entsprechend geschoben werden kann. 
Hierbei führt er keine Kontrolle des Wertebereichs durch, sondern 
verwendet einfach die unteren fünf Bit. Daher wird "a" nur um 3 statt 35 
Bit geschoben. Dies ist zulässig, da nach der Operation "a" eh 
undefiniert ist.

4. Nach der Berechnung ist "a" undefiniert und darf somit einen 
beliebigen Wert besitzen. Daher kann die Berechnung wegoptimiert werden, 
so dass weiterhin "a=10".

5. Ähnlich wie Möglichkeit 3, aber "a" befindet sich nicht im Speicher, 
sondern in einem Register. Bei der nächsten Verwendung von "a" darf also 
der Inhalt eines beliebigen Registers verwendet werden, z.B. aus dem 
Register, welches verwendet worden wäre, wenn keine Optimierung 
stattgefunden hätte. Dessen Inhalt ist entweder noch der alte Inhalt von 
"a" oder irgendein anderer Wert.

Bei konstantem Offset, um den "a" geschoben wird, ist es sehr 
wahrscheinlich, dass ein Compiler Möglichkeit 1 generiert. Ist jedoch 
der Offset nicht bekannt, sondern wird erst zur Laufzeit bestimmt, 
werden viele Compiler keine Bereichsüberprüfung durchführen, sondern ein 
Programm mit dem Verhalten gemäß 3. generieren.


Aus den obigen Gründen finde ich gerade in VHDL Datentypen wie std_logic 
usw. so toll, weil dort in der Simulation auch mit undefinierten Werten 
weitergearbeitet werden kann. Und dann stellt man sehr schnell fest, 
dass man an irgendeiner Stelle vergessen hat, ein Signal geeignet 
vorzubelegen bzw. einen korrekten Wert zuzuweisen.

: Bearbeitet durch User
Beitrag #5132364 wurde von einem Moderator gelöscht.
von Martin S. (strubi)


Lesenswert?

chris schrieb:
> Akademisch gesprochen ist ein Zähler eine Zustandsmaschine.

Aaargh. Vergiss das ganz schnell wieder, wenn ich schon "akademisch" 
höre, wachsen mir Nackenhaare. Lernt ihr sowas in der Vorlesung?
Ein Zähler ist immer noch ein Zähler. Wenn die Synthese daraus eine rohe 
Zustandsmachine (LUT-basiert) machen würde, wäre dein FPGA gleich voll.

chris schrieb:
> Dort spielt wieder mein 'c'-Erfahrungshintergrund eine Rolle.

Gut wäre, wenn man im Studium wenigstens konsequenterweise noch eine 
Ada-Einführung kriegen würde. Denn VHDL nutzt dieselbe Typensicherheit 
und Semantik. In C(++) Hardware zu beschreiben ist ein nicht elegant 
lösbarer gordischer Knoten, obwohl es immer wieder versucht wird.
Fazit: Du musst schliesslich viel Wissen drüber ansammeln, was genau 
geschieht, gerade in Bezug auf Andreas' prima Beispiel oben.

Da VHDL aber ein recht strenges Schwergewicht ist, gleichzeitig aber in 
der Lernphase doch oft viel zuwenig simuliert wird (was die 
Beitragszahlen zu dem Thema hier zeigen), empfehle ich immer wieder den 
Einstieg per MyHDL und von Anfang an zu SIMULIEREN! Vorher macht es kaum 
Sinn, sich mit semantischen Details von VHDL zu quälen und solche 
Diskussionen anzufangen.

Und: Darüber lässt sich streiten, aber ich würde mir auch angewöhnen, 
Zähler explizit hinzuschreiben und dafür unsigned anstatt integer zu 
verwenden. MyHDL geht da noch einen Schritt weiter und lässt explizite 
Wertebereichangaben für die intbv() Datentypen zu. Damit kann man prima 
numerisch relevante Rechenpipelines verifizieren.

von Michael W. (Gast)


Lesenswert?

Martin S. schrieb:
> Wenn die Synthese daraus eine rohe
> Zustandsmachine (LUT-basiert) machen würde, wäre dein FPGA gleich voll.
Wieso das denn?

> Zähler explizit hinzuschreiben und dafür unsigned anstatt integer zu
> verwenden.
+1

von C. A. Rotwang (Gast)


Lesenswert?

Markus W. schrieb:
> Martin S. schrieb:
>> Wenn die Synthese daraus eine rohe
>> Zustandsmachine (LUT-basiert) machen würde, wäre dein FPGA gleich voll.
> Wieso das denn?


Mit rowherr FSM ist wohl sowas gemeint:

case state_q is
when 0  => state_q  <= 1; end if;
when 1  => state_q  <= 2; end if;
...

Also für jeden Zähl-state einen Vergleicher aka eine LUT pro 
Zustandsbit.
Das das Synthesetool das automatisch zu einem Zähler optimiert ist 
unwahrscheinlich, bestenfalls wird draus ein BRAM-ROM gebastelt, das den 
LUT-Friedhof ersparen.

von chris (Gast)


Lesenswert?

Meiner Meinung nach ist ein Zähler immer eine Zustandsmaschine im 
akademischen Sinn.
Ähnlich wäre es, wenn man behaupten würde, ein Apfel wäre kein Obst oder 
eine Opel Corsa wäre kein Auto.
Das eine ist die Untermenge des anderen.

von C. A. Rotwang (Gast)


Lesenswert?

chris schrieb:
> Meiner Meinung nach ist ein Zähler immer eine Zustandsmaschine im
> akademischen Sinn.

Ja, ist er. Es geht hier eber weniger ob es ein Automat ist sondern wie 
er implementiert ist. Und mit FSM meint man unter FPGA-Entwicklern eben 
eine Implementierung aus einen Speicher des Zustandsvektor als FF mit 
ein paar LUT's für die Transitionsübergänge und den Ausgangsvektor. Für 
einen Zähler braucht es diesen "aufwand" bei dem einzigen Übergang pro 
state nicht viel an Ausgangsvektor gibt es auch nicht. Also 
implementiert man einen Zähler, der ja bekanntermassen genau einen 
Übergang per State hat. Und je nach Zustandskodierung kann man auch eine 
Alternative zum Up/Down Binärcounter wählen, wie den Gray-encoded 
counter oder ein ruckgekoppeltes Schieberegister (LFSR). Diese Auswahl 
an greundverschiedenen Implementierungen einer FSM hat man in C 
üblicherweise nicht. Deshalb treten hier die Unterschiede zwischen eine 
Implementierung als Zähler oder Roher FSM nicht gleich zu Tage.

>Ähnlich wäre es, wenn man behaupten würde, ein Apfel wäre kein Obst oder
>eine Opel Corsa wäre kein Auto.
>Das eine ist die Untermenge des anderen.

Beim FPGA besteht aber die Menge "Auto" nicht nur aus Opel Corsa oder 
BMW Fünfer sondern umfasst auch Marsrover, Handwagen oder 
Tunnelbohrmaschine. Und folglich muss man sich mehr Gedanken drüber 
machen, welches Fahrzeug in dieser Situation am cleversten ist.

von chris (Gast)


Lesenswert?

Im Moment kämpfe ich immer noch ein wenig mit der Entwicklungsumgebung 
für das MACHXO2 CPLD und muss erst mal raus kriegen, wie man damit 
simuliert.

Hier habe ich ein gutes Tutorial gefunden, aber es ist leider für 
Verilog:

http://www.farrellf.com/projects/hardware/2016-01-03_Lattice_MachXO2_Breakout_Board_HelloWorld/

von Ale (Gast)


Lesenswert?

Tutorial ist gut, Verilog ist nur einer kleinen Teil des Ganzes.
 Du kannst auch den User Guide für Active HDL irgendwo hier:

C:\lscc\diamond\3.5_x64\active-hdl

oder Äq. Ist alles da :).

Ich würde trotzdem ghdl+gtkwave auch empfehlen :). (Oder icarus 
verilog+gtkwave für Verilog).

> Und mit FSM meint man unter FPGA-Entwicklern eben
> eine Implementierung aus einen Speicher des Zustandsvektor als FF mit
> ein paar LUT's für die Transitionsübergänge und den Ausgangsvektor.

Den Zähler wird auch mit FFs realisiert...

von chris (Gast)


Lesenswert?

Danke ;-)
Ich habe einfach mal ein Beispiel von der Webseite von Lothar Miller 
genommen, da dort auch eine Testbench mit dabei ist.
http://www.lothar-miller.de/s9y/categories/18-Flankenerkennung

Dabei folgendes Vorgehen:
1. edge_detect.vhd anlegen
2. testbench.vhd anlegen und rechte Maustaste "exclude von 
implementation" wählen
3. tools->simulation wizard starten

Danach geht Atcive-HDL 10.3 auf. Es zeigt ein Diagram mit den 4 signalen 
ysync-sig, clk, fall, rise und folgender Ausgabe:


# KERNEL: ASDB file was created in location 
D:\tools\3.9.0.99.2_Diamond_x64\latticeWorkspace\testbench1\simTestBench 
\src\wave.asdb
#  11:36, Sonntag, 17. September 2017
#  Simulation has been initialized
add wave *
# 4 signal(s) traced.
run 1000ns
# Waveform file 'untitled.awc' connected to 
'D:/tools/3.9.0.99.2_Diamond_x64/latticeWorkspace/testbench1/simTestBenc 
h/src/wave.asdb'.
# KERNEL: stopped at time: 1 us
# KERNEL: Simulation has finished. There are no more test vectors to 
simulate.

Aber leider sind im Diagramm keine Signale zu sehen, nur Striche. Woran 
kann das liegen?

von chris (Gast)


Lesenswert?

Habe das Problem gefunden, Schritt 2 ist falsch:

2. testbench.vhd anlegen und rechte Maustaste "exclude von
implementation" wählen

richtig ist

2. testbench.vhd anlegen und rechte Maustaste " -> include for -> 
simulation

von chris (Gast)


Lesenswert?

Hier noch der Link auf den 2.ten Teil der Grundlagen:
Beitrag "VHDL Grundlagen Tonerzeugung"

von chris (Gast)


Lesenswert?

Mir ist der Sinn von "process" immer noch nicht richtig klar.

Ich habe mal einen Blinker auf zwei unterschiedliche Arten gemacht:

1.
1
PROCESS(clk)
2
 BEGIN  
3
 IF rising_edge(clk) THEN
4
  clkCounter <= clkCounter +1;
5
 END IF;  
6
7
 led        <= clkCounter(24); -- output the highest bit to the led
8
9
END PROCESS;

2. wenn ich das Mapping der LED mit in den Prozess stopfe, kommt genau 
der gleiche RTL-Level raus.
1
PROCESS(clk)
2
 BEGIN  
3
 IF rising_edge(clk) THEN
4
  clkCounter <= clkCounter +1;
5
 END IF;  
6
END PROCESS;
7
  led        <= clkCounter(24); -- output the highest bit to the led

Warum ist das so? Warum kann ich die Zuweisung innerhalb oder außerhalb 
des Prozesses schreiben?

von Andreas S. (Firma: Schweigstill IT) (schweigstill) Benutzerseite


Lesenswert?

Einfache nicht getaktete Zuweisungen verhalten sich so, als wären sie 
jeweils als eigener Prozess definiert, d.h. die Anweisung ließe sich wie 
folgt lesen:
1
PROCESS(clkCounter(24))
2
BEGIN
3
  led        <= clkCounter(24);
4
END PROCESS;

Ein Unterschied tritt erst dann auf, wenn die Zuweisung in einem 
getakteten Bereich erfoglt, d.h. wenn Dein Prozess wie folgt aussähe:
1
PROCESS
2
BEGIN
3
 WAIT UNTIL rising_edge(clk);
4
 clkCounter <= clkCounter +1;
5
6
 led        <= clkCounter(24); -- output the highest bit to the led
7
 other_output <= other_input;
8
END PROCESS;

Die Zuweisung an led erfolgt hier erst einen Takt später als in der o.a. 
Version. Und die Zuweisung von other_output erfolgt auch mit clk 
getaktet, was bei einem rein kombinatorischen Signal ggf. unerwünscht 
sein kann.

Beitrag #5161045 wurde von einem Moderator gelöscht.
von Andreas S. (Firma: Schweigstill IT) (schweigstill) Benutzerseite


Lesenswert?

Markus W. schrieb im Beitrag #5161045:
> Hängt aber von der Lautzeit ab.

Falls damit die Signallaufzeit gemeint sein sollte, trifft dies nicht 
zu.

In der Simulation erfolgen alle Zuweisungen erst dann, wenn alle aktiven 
Prozesse abgearbeitet wurden. Hierdurch gibt es keine Abhängigkeit der 
Zuweisungsreihenfolge von der Position innerhalb des Quelltextes. Es 
bedeutet auch, dass man z.B. für den Tausch der Inhalte zweier Signale 
nicht etwa wie in der Softwareentwicklung eine Hilfsvariable (oder einen 
anderen üblen Trick) benötigt,
1
tmp = a;
2
a = b;
3
b = tmp;

sondern z.B. direkt schreiben kann:
1
A <= B;
2
B <= A;

In der Hardware werden ohnehin flankengesteuerte Latches verwendet. Bei 
dem o.a. Beispiel befinden sich alle Signale in der Taktdomäne, die 
durch clk definiert wird.

von chris (Gast)


Lesenswert?

Es gibt hier einen Grundlagenartikel:

https://www.mikrocontroller.net/articles/FPGA

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.