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:
1
testproc:process(clock)
2
begin
3
if(rising_edge(clock))then
4
SignalA<=SignalB;
5
SignalB<=SignalB+1;
6
endif;
7
endprocesstestproc;
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?
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.
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?
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.
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
1
____________________
2
| |
3
v |
4
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.
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.
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!
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-oder-Zwei-Prozess-Schreibweise-fuer-FSM.html).
So oder so: Wichtig ist es in Hardware, also Registern und einer
Übergangslogik (mit Propagationdelay > 0ns) zu denken, dann klappt es.
...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" !
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.
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.
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.
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-Einsynchronisieren 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!