Hallo,
die Zuweisungen in Verilog sind als Anfänger schwer zu verstehen und
bereiten oft Probleme. Ich glaube, ich habe non blocking und blocking
verstanden. Was ich jedoch nicht verstanden habe ist der Unterschied
zwischen einem Ausdruck als wire und einem als blocking assignment in
einem always block. Und da komme ich nun zu meiner absoluten Noobfrage.
Beispiel:
1
wire a = sigA & sigB & sigC;
vs
1
reg a;
2
always @(posegde clk) a = sigA & sigB & sigC;
Wäre die Anweisung eine non blocking Zuweisung, dann würde nach der
rising Edge von clk das Ergebnis in a landen. So weit so gut. Aber jetzt
ist es eine blockierende Zuweisung. Das heißt, wie bei einem wire würde
dem Register a kontinuierlich der neue Wert zugewiesen werden wenn sich
eines der Signale ändert, ganz gleich was mit clk passiert?
Wenn ich jetzt auf a von außen zugreife, wann kann ich erwarten das a
den Wert zugewiesen bekommt? Wie verhält sich das Konstrukt?
Grüße
Tobias
So wie ich das verstanden habe ist reg ein Speicher, also FlipFlop und
wire quasi eben ein Draht.
Ich weiß nicht, was du mit non blocking und blocking meinst.
wire a = sigA & sigB & sigC;
Diese Zuweisung findet immer statt. Quasi sofort oder eben so schnell
wie die Logik im FPGA kann. Jederzeit hat a den Wert von sigA & sigB &
sigC.
Wenn sich also sigC irgendwann ändert, dann ändert sich sofort auch a.
tobias schrieb:> reg a;> always @(posegde clk) a = sigA & sigB & sigC;
Das ist getaktet. Das bedeutet, dass a nur bei der steigenden Flanke von
clk neu zugewiesen wird. Aber eben bei jeder steigenden Flanke von
clk.
Ändert sich also sigC irgendwann, dann ändert sich der Wert von a erst
kurz nach der nächsten steigenden Flanke von clk. Wenn sich danach dann
sigB ändert, dann ändert sich a wieder erst mit oder kurz nach der
nächsten Taktflanke. a behält also zwischen zwei steigenden Flanken von
clk seinen Wert bei, egal wie sich sigA, sigB und sigC ändern.
Gustl B. schrieb:> Ich weiß nicht, was du mit non blocking und blocking meinst.
Das ist ein Formalismus der Sprache, der in der realen Hardware
eigentlich kein Äquivalent hat:
http://www.asic-world.com/tidbits/blocking.html
Blockierende Anweisungen in einem Codeblock werden "sequentiell
nacheinander" ausgeführt. Nicht blockierende werden "gleichzeitig"
ausgeführt.
(In VHDL enspricht ein "blocking assignment" der Zuweisung an eine
Variable, "non blocking" wäre die Zuweisung an ein Signal)
tobias schrieb:> wire a = sigA & sigB & sigC;> vs> reg a;> always @(posegde clk) a = sigA & sigB & sigC;
Das Dreifach-UND-Gatter ist eigentlich beide Male das selbe. Nur ist im
zweiten Fall ein Flipflop dahinter geschaltet.
> Wäre die Anweisung eine non blocking Zuweisung, dann würde nach der> rising Edge von clk das Ergebnis in a landen.
Der Witz ist übrigens, dass nicht "nach" der steigenden Flanke das
Ergebnis in a landet, sondern "wegen" der steigenden Flanke. Denn das
Flipflop übernimmt "wegen" der Flanke den Eingangswert und überträgt ihn
auf seinen Ausgang. Das ist eine grundlegend andere Denkweise.
Vielen Dank für die Antworten. Das heißt, die blockierende Zuweisung hat
nur Gültigkeit innerhalb eines always Blocks? Um mein Beispiel nochmal
ein wenig zu erweitern.
z.B.
1
reg sigA = 1;
2
reg sigB = 1;
3
reg sigC = 1;
4
5
wire w = sigA & sigB & sigC;
6
7
reg r = 0;
8
reg a = 0;
9
reg b = 0;
10
always @(posegde clk) // Block 1
11
begin
12
r = sigA & sigB & sigC;
13
a <= r;
14
b <= w;
15
end
16
17
reg c = 0;
18
always @(posedge clk) // Block 2
19
begin
20
c <= r;
21
end
Angenommen es gibt einen Taktzyklus. Ich würde jetzt folgende Werte
erwarten:
a = 1
b = 1
c = ?
Für Block 1 würde es für a keinen Unterschied machen ob es den Wert von
r oder w zugewiesen bekommen würde, nach der Flanke sind a und b immer
äquivalent da a auf r "warten" würde.
Aber was passiert bei Block 2 mit c? Wenn ich das richtig verstanden
habe, dann ist die blockierende Zuweisung von r nur innerhalb von Block
1 gültig für andere Blöcke wäre es hingegen eine nichtblockierende
Zuweisung und der Wert von r würde sich erst nach dem Takt ändern?
Demzufolge wäre c:
Taktzyklus 1: c = 0 (da der initiale Wert von r noch 0 ist)
Taktzyklus 2: c = 1
Ist da mein Verständnis korrekt?
Vielen Dank für eure Hilfe!
tobias schrieb:> Taktzyklus 1: c = 0 (da der initiale Wert von r noch 0 ist)> Taktzyklus 2: c = 1
Würde ich (als VHDL Spezialist) auch erwarten, weil r ja ein mit '0'
initialisiertes Flipflop ist, das die '1' aus der logischen Verknüpfung
erst mit der steigenden Flanke übernimmt. Und deshalb übernimmt c mit
der selben steigenden Flanke noch den bisherigen Wert '0' von r.
Und jetzt die Frage: was kommt tatsächlich heraus?
Ich würde das an deiner Stelle einfach mal ausprobieren und das dem
Simulator und dem Synthesizer vorlegen. Und dann auf jeden Fall auch mal
die Schaltung ansehen, die der Synthesizer aus deiner Beschreibung
macht. Denn das ist ja, was da letzlich passieren soll: der Synthesizer
soll deine Hardwarebeschreibung verstehen und die von dir gewünschte
Hardware draus machen. Da kann man schon ab&an mal nachschauen, ob der
da schon richtig kapiert hat, was gemaint war...
Hi,
das klingt logisch was du da sagst. Das heißt die blockierende Zuweisung
ist nur innerhalb eines always Blocks gültig. Sprich ich kann mir jeden
always Block wie eine eigene Schaltung vorstellen, welche diverse
Ausgänge in Form eines getakteten Registers hat. Innerhalb eines always
Blocks kann ich eben mit den blockierenden Anweisungen das Ergebnis für
Register r direkt mit a verdrahten, während ich aber außerhalb von
diesem always Block auf die Taktflanke warten muss.
Natürlich kann ich das einfach mit einem Simulator ausprobieren, jedoch
geht es mir hierbei darum die Sprache zu verstehen. Schließlich will ich
das mein Code so portabel wie möglich ist. Angenommen es würde sich bei
diesem Konstrukt um eines handeln, welches unter die Kategorie undefined
behavior fällt, dann wären die Ergebnisse nur Zufall und würden mich zu
falschen Schlussfolgerungen führen.
Ein einfaches Beispiel wäre die Registerinitialisierung wenn ich keinen
Wert angebe. Ein Simulator würde da direkt streiken, ein Synthesetool
muss hingegen einen Wert für das Register im FPGA angeben. Welcher
bleibt dem Hersteller überlassen.
Ein komplexeres Beispiel wäre die Ausführungsreihenfolge der always
Blöcke, die ebenfalls nicht definiert ist.
Ich hoffe du Verstehst damit die Intension dieser Frage.
Grüße
Tobias
tobias schrieb:> Schließlich will ich> das mein Code so portabel wie möglich ist.
Dann darfst du keine blockierende Zuweisungen in getakteten always
Blöcken verwenden. Vor allem nicht, wenn es synthetisierbar sein soll.
In einem always Block mit posedge geschieht alles gleichzeitig bei der
steigenden Flanke des Clocks, ganz egal in welcher Reihenfolge du es
geschrieben hast.
Es gibt allerdings auch kombinatorische always Blöcke:
1
always@*
2
r=sigA&sigB&sigC;
Das entspricht einem
1
assignr=sigA&sigB&sigC;
nur dass das r im ersten Fall als register und im zweiten Fall als wire
definiert sein muss.
Kombinatorische Signale als 'reg' definieren zu müssen ist natürlich ein
ziemlicher Murks, deshalb gibt es in SystemVerilog: signal für beides.
Eine eigene Frage?
Dieser Thread ist über 6 Jahre alt.
Stell sie in einem eigenen Thread – dort lesen mehr Leute mit, und sie wird öfter und schneller beantwortet.