Forum: FPGA, VHDL & Co. Verilog blocking assignment vs wire


von tobias (Gast)


Lesenswert?

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

von Gustl B. (-gb-)


Lesenswert?

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.

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


Lesenswert?

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.

: Bearbeitet durch Moderator
von tobias (Gast)


Lesenswert?

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!

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


Lesenswert?

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...

von tobias (Gast)


Lesenswert?

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

von Andi (Gast)


Lesenswert?

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
  assign r = 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.

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.