mikrocontroller.net

Forum: FPGA, VHDL & Co. Verständniss Signale und wann sind ihre Werte valide


Autor: Paule (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo,

ich versuche mich gerade etwas in die Welt der Hardwarebeschreibung 
einzuarbeiten und dabei habe ich anscheinend ein kleines 
Verständnissproblem. Folgendes Szenario : in einem Prozess soll zu jedem 
neuen Takt dem Signal A der Wert von Signal B zugewiesen werden UND dann 
der Wert von Signal B sagen wir mal enfach um 1 erhöht werden.
Da könnte man ja schnell auf die Idee kommen das sowas funktionieren 
würde:
testproc : process (clock)
begin
  if (rising_edge(clock)) then
    SignalA <= SignalB;
    SignalB <= SignalB + 1;
  end if;
end process testproc;
ABER es heißt doch, vereinfacht, ein Signal erhällt seinen engültigen 
Zustand erst am Ende eines Prozesses und da man, so wie ich das ganze 
verstehe, nicht davon ausgehen kann das die beiden Zuweisung sequentiell 
ausgeführt werden, wie verhällt sich das dann wirklich?
Hat SignalA am Ende des Prozesses wirklich den Wert von SignalB VOR dem 
+ 1? Und wenn nicht, wovon ich ausgehe (ich kann es leider gerade nicht 
simulieren bzw. auf richtiger hardware ausprobieren wobei ich schätze 
auch mal das bei der Synthese was anderes rauskommt als bei der 
Simulation), wie kann man so etwas evtl. doch realisieren?

Autor: F. F. (foldi)
Datum:

Bewertung
-5 lesenswert
nicht lesenswert
Paule schrieb:
> dabei habe ich anscheinend ein kleines Verständnissproblem.

Ein kleines ist ja niedlich ausgedrückt.

Du hast das noch gar nicht begriffen.

Dein SignalA ist eine Variable, der du den Wert deines SignalB zuweist. 
SignalB musst du erstmal einlesen und dann ist natürlich der Wert deines 
SignalA gleich dem Wert des SignalB+1.
Das "echte" Signal ist in diesem Fall dein SignalB.
Selbst das "+1", was der Realität entsprechen mag, ist ja nur eine 
mathematische Anweisung, die du bestimmst. Es könnte genauso gut "+10" 
sein.
Was aber in der Realität keinen Sinn ergeben würde, wenn du das Signal 
zählen  und auswerten willst.

: Bearbeitet durch User
Autor: Paule (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
F. F. schrieb:
> Dein SignalA ist eine Variable, der du den Wert deines SignalB zuweist.
> SignalB musst du erstmal einlesen und dann ist natürlich der Wert deines
> SignalA gleich dem Wert des SignalB+1.
...ok dann hab ich DAS ja doch richtig verstanden: SignalA hat nachher 
den Wert von SignalB +1

> Das "echte" Signal ist in diesem Fall dein SignalB.
> Selbst das "+1", was der Realität entsprechen mag, ist ja nur eine
> mathematische Anweisung, die du bestimmst. Es könnte genauso gut "+10"
> sein.
> Was aber in der Realität keinen Sinn ergeben würde, wenn du das Signal
> zählen  und auswerten willst.
... da komm ich jetzt nicht ganz dahinter was mir das sagen soll... als 
praktischeres Beispiel könnte man auch sagen SignalA ist das 
Adressregister eines Speichers, SignalB ist ein integer der die Adresse 
hällt und der Prozess sollte bei jedem neuen Takt fortlaufend etwas in 
den Speicher schreiben (der Teil fehlt natürlich in dem Beispiel code, 
und das evtl benötigte konvertieren von integer in std_logic_vector 
spare ich mir jetzt auch mal).

Wie sollte man das denn angehen ohne einen weiteren Takt zu brauchen um 
dann darin SignalB zu erhöhen?

Autor: ollib (Gast)
Datum:

Bewertung
3 lesenswert
nicht lesenswert
Also vielleicht stehe ich ja auf dem Schlauch, aber ich glaube foldi hat 
das noch nicht richtig begriffen.
SignalA und SignalB sind eben gerade KEINE Variablen, sondern Signale. 
Das ist in VHDL ein Unterschied. Und Signale bekommen den neuen Zustand 
erst im nächsten Takt. Von daher hat SignalA natürlich den Wert von 
SignalB bevor dieses erhöht wurde.

Autor: VHDL hotline (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Falls das hier auf Mehrheitsentscheidung hinausläuft: Ich schließe mich 
ollib an.
In Hardware hast du ein Register für SignalA und eines für SignalB und 
einen kombinatorischen Adder für das increment
    ____________________
   |                    |
   v                    |
 adder -> Register -SignalB-> Register -SignalA->



In welcher Reihenfolge du die Zuweisungen schreibst ist bei Signalen 
egal. Virtuell gedacht werden die Zuweisungen erst zu Prozessende alle 
gleichzeitig ausgeführt. Sequentiell ist innerhalb einen Prozesses nur 
wichtig, wenn du mehrere male das gleiche Signal (Register) beschreibst, 
dann wird einfach die letzte Zuweisung umgesetzt.

Autor: F. F. (foldi)
Datum:

Bewertung
-3 lesenswert
nicht lesenswert
ollib schrieb:
> Das ist in VHDL ein Unterschied.

Ups, Vhdl. Klar, da ist das anders.
Ich habe das nur als Beispiel angesehen, wie ein uC das verarbeitet.

Autor: Paule (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
ollib schrieb:
> und Signale bekommen den neuen Zustand
> erst im nächsten Takt. Von daher hat SignalA natürlich den Wert von
> SignalB bevor dieses erhöht wurde.
wenn die Signale ihren Zustand erst im nächsten Takt erhalten und das 
alles nahezu parallel ausgeführt wird, wie kann dann bitte SignalA den 
Wert von SignalB VOR dem erhöhen erhalten??? Also um jetzt endgültig 
sicher zugehen werde ichs später mal einfach auf richtiger hardware 
ausprobieren, ist dann doch praktikabler als Rätselraten.
Aber trotzdem Vielen Dank euch!

Autor: P. K. (pek)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Paule schrieb:
> wie kann dann bitte SignalA den
> Wert von SignalB VOR dem erhöhen erhalten???

Weil in einem geclockten Prozess vor der Signalzuweisung "<=" jeweils 
der nächste Zustand des Registers, hinter der Signalzuweisung "<=" 
jeweils der aktuelle Zustand des Registers (zum Zeitpunkt der Flanke) 
relevant ist.

Auch wenn viele alte Hasen diese als unschön empfinden: Für Einsteiger 
ist die Zweiprozessschreibweise vermutlich plausibler, weil da dann 
explizit zwischen SignalA_cur und SignalA_next unterschieden wird (lies 
Dich mal durch 
http://www.lothar-miller.de/s9y/archives/43-Ein-od...).

So oder so: Wichtig ist es in Hardware, also Registern und einer 
Übergangslogik (mit Propagationdelay > 0ns) zu denken, dann klappt es.

Autor: Paule (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
...so um die Sache abzuschließen hab ich es einfach grad ausprobiert auf 
einem de0-nano board und tja wer hätts gedacht, der folgende code gibt 
als erste Bitfolge mit den LEDs eine "1" aus und nicht etwa eine "2" !
library IEEE;
use IEEE.std_logic_1164.all;
use IEEE.numeric_std.all;

entity SignalTest is 
  port(
    clock : in std_logic;
    leds : out std_logic_vector(7 downto 0);
    btn : in std_logic
  );
end entity;
    
architecture behave of SignalTest is

Type Tstate is (idle, run, waiting);
signal state : Tstate := idle;
signal waitCounter : integer range 0 to 50000000 := 50000000;
signal signala : std_logic_vector(7 downto 0) := (others => '0');
signal signalb : integer range 0 to 256 := 0;

begin

  process
  begin
    wait until rising_edge(clock);
    
    case state is
    
      when idle =>
        signala <= (others => '0');
        signalb <= 1;
        leds <= (others => '0');
        if (btn = '0') then
          state <= run;
        end if;
        
      when run =>
        if (signalb < 8) then
          signala <= std_logic_vector(to_unsigned(signalb, 8));
          signalb <= signalb + 1;
          waitCounter <= 50000000;
          state <= waiting;
        else
          state <= idle;
        end if;
      
      when waiting =>
        leds <= signala;
        if (waitCounter > 0) then
          waitCounter <= waitCounter - 1;
        else
          state <= run;
        end if;
    
    end case;
  end process;

end behave;

Autor: Schlumpf (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
P. K. schrieb:
> Weil in einem geclockten Prozess vor der Signalzuweisung "<=" jeweils
> der nächste Zustand des Registers, hinter der Signalzuweisung "<="
> jeweils der aktuelle Zustand des Registers (zum Zeitpunkt der Flanke)
> relevant ist.

Oder anders ausgedrückt:

In einem getakteten Prozess baut die Synthese aus jeder "<=" Zuweisung 
erst mal nur ein Register und zwar der Form:

Registerausgang <= Registereingang

Diese Register haben alle den gleichen Takt (in deinem Fall clock)

Der Rest ist kombinatorik zwischen den Registern.

In deinem Fall werden also zwei 8-Bit Register gebaut "signala" und 
"signalb".
signala übernimmt mit jedem Takt den Wert von signalb.
Der Ausgang des signalb-Registers ist auf dessen Eingang mit einem 
Addierer zurückgekoppelt.

Dazu kannst dir ja mal den Schaltplan hinzeichnen und dann wird dir 
vielleicht einiges klarer.

Anmerkung:
Was ich geschrieben habe, gilt natürlich nicht 1:1 für deinen 
Beispielcode.
Denn hier wirkt z.B. auch der Zustand der FSM noch zusätzlich 
kombinatorisch auf deine Registereingänge.
Aber für den Code im Eingangspost passt das.

Autor: Schlumpf (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
ach ja.. und brandgefährlich ist die Tatsache, dass du den btn-Eingang 
nicht synchronisiert hast.
Das kann im ungünstigen Fall deine FSM, den signalb-Counter und deinen 
Waitcounter total aus dem Tritt bringen.

Also, falls du dich irgendwann wunderst, warum das Ganze nicht immer so 
läuft, wie du dir das vorstellst, dann liegt das mit großer 
Wahrscheinlichkeit daran.

Erklärung für die FSM:

Der Zustand der FSM wird in Registern gespeichert.
state <= ......

Diese Register arbeiten alle mit dem gleichen Takt.
Das Signal deines Tasters kommt jetzt zu irgendeinem beliebigen 
Zeitpunkt.
Wenn das jetzt mehr oder weniger gleichzeitig mit der Flanke des Taktes 
geschieht, dann passiert Folgendes:

Die Kombinatorik, die den Zustand des Buttons mit dem aktuellen Zustand 
von "state" verwurschtelt und daraus den Folgezustand ermittelt, wirkt 
auf die Eingänge des "state"-Registers.
Nun sind aber die logischen Pfade vom BTN-Eingang zu den 
Registereingängen nicht identisch gleich lang. Es kann dann also 
passieren, dass für einen Teil der state-Register an deren Dateneingang 
schon der Folgezustand anliegt und an einem anderen Teil noch nicht. Und 
dann kommt der Takt...
Dann kann es also passieren, dass ein "Zustandsmischmasch" in "state" 
gespeichert wird.
Entweder gibt es diesen Zustand tatsächlich, dann springt die FSM dort 
hin und kommt "vielleicht" wieder raus (je nachdem, was du in diesem 
Zustand codiert hast). Oder dieser Zustand ist gar nicht von dir 
codiert, dann hat sich die Schaltung definitiv verklemmt.

Autor: Paule (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Schlumpf schrieb:
> Wenn das jetzt mehr oder weniger gleichzeitig mit der Flanke des Taktes
... ok, verstehe das sowas generell ein Problem geben könnte, aber ich 
dachte durch das wait until rising_edge(clock) am Anfang des Prozess 
wird das ganze synchron da ich ja sonst nirgendswo anders btn einlese 
und das immer nur zur steigenden Flanke des Taktes.

Autor: Paule (Gast)
Datum:

Bewertung
1 lesenswert
nicht lesenswert
Paule schrieb:
> Schlumpf schrieb:
>> Wenn das jetzt mehr oder weniger gleichzeitig mit der Flanke des Taktes
> ... ok, verstehe das sowas generell ein Problem geben könnte, aber ich
> dachte durch das wait until rising_edge(clock) am Anfang des Prozess
> wird das ganze synchron da ich ja sonst nirgendswo anders btn einlese
> und das immer nur zur steigenden Flanke des Taktes.
ok hatte es wohl doch noch nicht richtig verstanden, das mit den 
unterschiedlich langen Signallaufzeiten durchs routing hatte ich 
ignoriert aber 
http://www.lothar-miller.de/s9y/categories/35-Eins... hats 
mir dann nochmal verdeutlicht, die dort gezeigte 2 FlipFlop Lösung 
sollte für das simple design ja ausreichend sein. Da mal ein generelles 
Danke dafür das es diese geniale webseite überhaupt gibt! Natürlich auch 
Danke allen anderen für die Erklärungen!

Autor: Weltbester FPGA-Pongo (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Bin nicht sicher, ob Du das verstanden hast. Die Zeitpunkte, bei denen 
Signale gültig werden, hat nichts mit den Durchlaufzeiten zu tun.

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [vhdl]VHDL-Code[/vhdl]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.