Menu

Verilog Blocking vs Non-Blocking Atama: Ne Zaman = ve Ne Zaman <=

Yeni başlayan Verilog programcılarının en çok kafa karıştırdığı konu. Bir always bloğunun içinde = ve <= gerçekten ne anlama gelir ve race condition'ların çoğunu önleyen kural.

Bu sayfada çalıştırılabilir editörler var - düzenle, çalıştır ve sonucu anında gör.

İki Operatör

always ve initial bloklarının içinde Verilog'un iki atama operatörü vardır:

  • =, bir blocking atamadır. LHS'i şimdi, bir sonraki ifadeye geçmeden önce günceller.
  • <=, bir non-blocking atamadır. RHS'i şimdi hesaplar, LHS'in mevcut zaman adımı sonunda güncellenmesini planlar.

Prosedürel bloklar dışında (assign içinde) yalnızca = vardır - assign a <= b bir sözdizimi hatasıdır. Prosedürel bloklar içinde her ikisi de meşrudur ve doğru olanı seçmek, başlangıç seviyesi Verilog'daki en önemli karardır.

Blocking Ne Yapar

Blocking, bir yazılım dilinden bekleyeceğin şeydir: satır satır, yukarıdan aşağıya. N. ifade, N+1. ifade başlamadan tamamlanır:

Bu tamamen sıralıdır. Her ifade üstündekilerin etkisini görür. Bu yazılım sezgisiyle örtüşür.

Non-Blocking Ne Yapar

Non-blocking donanım şeklindedir. Tüm sağ tarafları zaman adımının başındaki değerleri kullanarak hesaplanır. Tüm sol tarafları zaman adımının sonunda güncellenir. Kaynaktaki ifade sırası sinyaller arasındaki bağımlılıkları değiştirmez:

O snippet, tek bir adımda a → b → c → a şeklinde 3 yönlü bir rotate uygular. Blocking ile, birini ezmemek için geçici bir değişkene ihtiyacın olurdu. Non-blocking ile, swap atomik olarak gerçekleşir çünkü her RHS adım-öncesi değerleri okur.

Bu tam olarak üç flip-flop'un bir saat kenarında nasıl davrandığıdır: aralarındaki bağımlılıklardan bağımsız olarak, hepsi girişlerini aynı anda yakalar.

Seni Kurtaran Kural

Saatli bloklarda <= kullan. Kombinasyonel bloklarda = kullan.

Hepsi bu. Ezberle. Düşünmeden kodla. Race condition'ların çoğu, simülasyon/sentez uyuşmazlıkları ve "bende çalışıyor ama sentezde çalışmıyor" hatalarının çoğu bu kuralı ihlal etmekten gelir.

Kuralın bir donanım nedeni var: saatli bloklar, hepsi girişlerini aynı anda örnekleyen flip-flop'ları modellemektedir. Kombinasyonel bloklar, olabildiğince hızlı yayılan mantığı modeller. Atama operatörü semantiği bu davranışlarla örtüşür.

Her <=, kaynak register'ın mevcut değerini okur ve hedef register'ın bu değeri zaman adımının sonunda almasını planlar. Net etki, bir donanım shift register'ının yaptığı şeyin tam olarak aynısıdır: her flip-flop, komşusunun değerini yakalar, hepsi aynı saat kenarında, race yok.

Şimdi blocking atama ile ne olacağını düşün:

// YANLIŞ - bu bir shift register değil!
always @(posedge clk) begin
    out[3] = out[2];   // out[3], out[2] olur
    out[2] = out[1];   // out[2], yukarıda yeni atadığımız out[1] olur
    out[1] = out[0];
    out[0] = in;
end

Her ifade, bir sonraki ifade okumadan kaynağı ezer. Tek bir saat döngüsünde in, ta out[3]'e kadar yayılırdı, çünkü her satır üstündekinin yeni yazılan değerini görür. Gerçek donanımdaki davranış (non-blocking semantiği kullanır) simülatörün gösterdiğinden tamamen farklı olurdu.

Kombinasyonel Bloklar: Blocking Doğrudur

always @(*) için blocking atama doğrudur. Flip-flop yok, eşzamanlı yakalama kuralı uygulanmıyor ve ara değişkenler yararlı:

sum önce hesaplanır, sonra result az önce hesaplanan değeri kullanır. Kombinasyonel mantık tek bir donanım parçasına düzleşir: result = ~(a + b). Saat olmadığı için flip-flop ortaya çıkmaz.

Burada <= kullansan, simülatör yine de result'ın değerlendirilmesinden önce sum'ı güncellerdi (çünkü her iki güncelleme de adım sonunda olur), ama sıra biraz farklı olurdu ve birçok sentez aracı şikayet eder. Karıştırma; blok tipiyle eşleşen operatörü seç.

En Çok Zarar Veren Hata

İşte burada: blocking atamalı saatli bir blok.

// HATA: olmayı bekleyen race condition
always @(posedge clk) begin
    a = b;
    b = c;
    c = a;
end

Simülasyonda, simülatör önce a, sonra b, sonra c verebilir ve bir değer kümesi üretir. Donanım başka bir değer kümesi üretecektir çünkü gerçek flip-flop'lar aynı anda yakalar. İkisi sessizce ayrışır ve bir gün hata ararken ziyan edersin. Saatli bloklarda <= kullan.

İki Operatör Neden Var

Verilog'un tasarımcıları tek bir atama semantiği seçip ona bağlı kalabilirdi. Yapmadılar, çünkü dilin iki farklı donanım davranışını modellemesi gerekir:

  • Kombinasyonel mantık: sinyaller sürekli yayılır, bağımlılıklar önemlidir, "bu gate ne hesaplıyor" mantıklıdır.
  • Sıralı mantık: bir saat kenarı olur, her flip-flop aynı anda yakalar, flip-flop girişleri ve çıkışları arasındaki bağımlılıklar ayrılır.

Blocking birincisi içindir. Non-blocking ikincisi içindir. Operatör semantiği seçer; simülatör geri kalanını yapar.

Sırada Ne Var

Artık herhangi bir prosedürel bloğu doğru yazmak için kurallara sahipsin. Bir sonraki bölüm bireysel bloklardan içlerine giren akış kontrol yapılarına çıkar: if/else, case ve for döngüleri. Blocking vs non-blocking kuralları bunların hepsinin içinde geçerli olmaya devam eder.

Sıkça Sorulan Sorular

Verilog'da blocking ve non-blocking atama arasındaki fark nedir?

Blocking (=) hedefi anında, bir sonraki ifade çalışmadan önce günceller. Sıralı yürütmeyi modeller. Non-blocking (<=) güncellemeyi mevcut zaman adımının sonuna planlar - her non-blocking RHS, tüm sinyallerin eski değerleri kullanılarak hesaplanır, sonra her LHS tek bir koordineli adımda güncellenir. Non-blocking, flip-flop'ların gerçekte nasıl davrandığıdır.

Verilog'da ne zaman = ne zaman <= kullanmalıyım?

Kural: saatli always @(posedge clk) bloklarında <=, kombinasyonel always @(*) bloklarında = kullan. Bu tek kural, karışık atamaların ürettiği tüm race condition sınıfını önler. Testbench'in initial blokları içinde = normal seçimdir; <= orada nadiren görünür.

Verilog'da neden non-blocking atamaya ihtiyaç var?

Çünkü donanımdaki flip-flop'lar bir saat kenarında girişlerini aynı anda yakalar. Saatli kodda = (blocking) kullansaydın, dosyadaki ifade sırası hangi sinyalin hangi diğer sinyalin yeni değerini gördüğünü değiştirirdi - simülasyon ile gerçek donanım arasında bir race condition. <= tüm RHS'leri önce hesaplayıp sonra tüm güncellemeleri yaparak donanım davranışını eşleştirir.

Aynı Verilog always block'unda = ve <= karıştırırsanız ne olur?

Bir race condition elde edersin. Karışım, davranışı simülatör iç dinamiklerine (olay planlama sırası) bağlı olan donanım üretir ve daha da kötüsü, simülasyon sentezin ürettiğiyle eşleşmeyebilir. Çoğu lint aracı bunu hata olarak işaretler. Düzeltme, bloğun rolüne göre birini seçmek - saatli için non-blocking, kombinasyonel için blocking.

Coddy programming languages illustration

Coddy ile kodlamayı öğren

BAŞLA