Davranışsal Verilog'un İş Atı
assign, tek denklemli kombinasyonel mantığı tanımlar. if/else, case veya bellek gerektiren bir şey olduğu anda always'e uzanırsın. Bir always bloğu, belirli sinyaller değiştiğinde tekrar çalışan bir prosedürel kod parçasıdır. Yeniden çalışmayı tetikleyen sinyaller sensitivity list'tir.
En sık göreceğin iki always şekli vardır:
always @(*)- blokta okunan herhangi bir sinyal değiştiğinde tekrar çalışır. Kombinasyonel mantık kurar.always @(posedge clk)- yalnızcaclk'nin yükselen kenarında tekrar çalışır. Saatli sıralı mantık (flip-flop) kurar.
Diğer formlar da vardır (@(a or b), @(negedge clk), @(posedge clk or negedge reset_n)), ama yukarıdaki ikisi yazacağın neredeyse her sentezlenebilir bloğu kapsar.
Kombinasyonel always @(*)
Fark etmen gereken üç şey:
out,reg'dir.alwaysiçinde atanan her şeyregolmalıdır. Bu anahtar sözcük "bu bir flip-flop'tur" anlamına gelmez; burada yalnızca "prosedürel bir bloktan yazılıyorum" demektir.always @(*).*ifadesi "okuduğum bir şey her değiştiğinde uyan" der. Simülatör sensitivity list'i otomatik çıkarır. Listeyi elle de yazabilirsin -always @(sel)- ama@(*)daha güvenlidir çünkü bir sinyali unutmak klasik bir hata kaynağıdır.- Saat yok. Bu blok kombinasyonel mantığı tanımlar. Sentezleyici,
out'u doğrudansel'den hesaplayan bir mantık parçası üretir - flip-flop yok, saat ucuna gerek yok.
default durumu sözdizimi olarak isteğe bağlı olsa da ruhen değildir. Onu atlarsan, belirtilmemiş bir giriş değeri out'un önceki değerini korumasına neden olur - bu da istenmeyen bir latch olarak sentezlenir. Her zaman default ekle.
Sıralı always @(posedge clk)
Kombinasyonel sürümden temel farkları:
always @(posedge clk). Blok yalnızcaclk'nin yükselen kenarında tekrar çalışır. Kenarlar arasında hiçbir şey olmaz.- Non-blocking atama
<=. Saatli bir bloğun içinde doğru operatör budur. "Zaman adımı sonundacount'a yeni değerini al" demektir, ki bu tam olarak bir flip-flop'un davranışıdır. Nedeni ve alternatifi Blocking vs Non-blocking bölümündedir. defaultgerekmez.ifher iki dalı da (reset ve reset değil) kapsar. Latch riski yok.
Sentezleyici bu şekli görür - saatli sensitivity, non-blocking atama - ve 4 bitlik bir register (dört flip-flop) artı count + 1'i hesaplayan kombinasyonel mantık ve reset ile artış arasından seçen mux'ı üretir.
Sentez Ayrımı
Aynı modül kaynağı, always bloğunun şekline göre tamamen farklı iki donanım parçasını tanımlayabilir:
| Blok | Donanım |
|---|---|
always @(*) y = expr; | Saf kombinasyonel mantık. Bellek yok. |
always @(posedge clk) y <= expr; | Flip-flop. expr'i saat döngüsü başına bir kez yakalar. |
always @(*) if (en) y = expr; | Latch - genellikle bir hata. "else" durumu eski değeri tutar. |
always @(posedge clk) if (en) y <= expr; | Enable'lı flip-flop. Yalnızca en yüksekken yakalar. |
Üçüncü durum latch tuzağıdır. Latch, girişi onaylanmadığında çıkışını koruyan saydam bir bellek hücresidir - belirli tasarımlarda kullanışlı, kaza eseri ortaya çıktığında neredeyse her zaman bir hata. Çoğu sentez aracı, istemediğin bir latch çıkardığında yüksek sesle uyarır. Uyarıyı hata olarak değerlendir.
Sensitivity List Varyantları
Daha az yaygın bazı sensitivity list'leri göreceksin:
always @(a or b or c)- açık liste. Verilog-2001,,ayırıcısını ekledi:always @(a, b, c). İkisi de çalışır.always @(posedge clk or negedge reset_n)- asenkron reset. Blok, yükselen saat kenarında veya düşen reset kenarında çalışır. Reset'in sonraki saati beklemeden hemen etkili olması gereken durumlarda kullanılır.always @(negedge clk)- düşen-kenar saatleme. Nadirdir; bazı tasarımlar yükselen yerine düşen kenarda yakalayan "negatif-kenar-tetiklemeli" flip-flop'lar için kullanır.
Yeni tasarımlarda kombinasyonel için always @(*), sıralı için always @(posedge clk) tercih et. Asenkron reset'e yalnızca tasarım gerçekten gerektirdiğinde uzan.
İki Blok, İki Donanım Parçası
Aynı modüldeki birden çok always bloğu birbirinden bağımsızdır - her biri kendi donanım parçası olur:
Saatli blok bir flip-flop register üretir. Kombinasyonel blok bir XOR gate üretir. Yan yana yaşarlar; ikisi de diğerinden haberdar değildir. İki çıkış tamamen farklı takvimlerde değişir.
always Bloklarının Yapamayacakları
Çekici görünen ama izin verilmeyen birkaç şey:
- Bir
wire'a atama: hedefregolmalı. Derleyici zorlar. - Aynı
reg'e iki farklıalwaysbloğundan atama: simülasyonda tanımsız davranış üretir ve sentezlenmez. Sinyal başına tek sürücü. - Aynı kombinasyonel blokta aynı sinyali okuyup yazmak, geri besleme döngüsü oluşturacak şekilde:
always @(*) x = x + 1;simülatörün çözemediği sıfır gecikmeli bir döngüdür.
İlk ikisini derleyici yakalar. Üçüncüsü bazen yalnızca simülasyon sırasında bir takılma olarak ortaya çıkar.
Sırada Ne Var
Bir sonraki doc - Initial Block - always'in kardeşini kapsar: simülasyon başlangıcında tam olarak bir kez çalışan bir blok. Testbench'lerin iş atıdır. Ondan sonra, saatli bloğunun istediğin gibi çalışıp çalışmadığını belirleyen blocking ve non-blocking atama kuralları gelecek.
Sıkça Sorulan Sorular
Verilog'da always block nedir?
always, sensitivity list'indeki sinyaller her değiştiğinde yeniden çalışan bir prosedürel blok başlatır. İki çeşidi vardır: always @(*) kombinasyonel mantık kurar (herhangi bir giriş değiştiğinde tekrar çalışır), always @(posedge clk) sıralı mantık kurar (clk'nin her yükselen kenarında çalışır). Bir always bloğunun gövdesinde if, case, for ve prosedürel atamalar bulunabilir.
always @(*) ile always @(posedge clk) arasındaki fark nedir?
always @(*) blokta okunan herhangi bir sinyale duyarlıdır; belleksiz kombinasyonel mantık üretir. always @(posedge clk) yalnızca clk'nin yükselen kenarına duyarlıdır; saat döngüsü başına bir kez durumu yakalayan flip-flop'lar üretir. Birincisinde ne saat ne register vardır; ikincisinde her ikisi de vardır.
Verilog'da sensitivity list nedir?
@ sonrasındaki, always bloğunun ne zaman tekrar çalışacağını belirleyen sinyal listesidir. @(*), 'blokta okunan her sinyal' için kısaltmadır. @(posedge clk) yalnızca clk'nin yükselen kenarında çalışır. @(posedge clk or negedge reset_n) ikisinden birinde çalışır - asenkron reset için kullanılır. Sensitivity list'i yanlış yazmak, sim/synthesis uyuşmazlığının en yaygın kaynaklarından biridir.
always block içinde bir wire'a atama yapabilir misin?
Hayır. always blokları sadece reg'e (veya SystemVerilog'da logic'e) atama yapabilir. Derleyici bunu zorlar. Bir wire'ın prosedürel mantığın çıktısı olmasını istiyorsan, ara bir reg tanımla, onu always içinde sür ve dışarıdan wire'ı reg'den assign ile sür - ya da wire'ı doğrudan reg'e çevir.