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