Menu

Verilog If-Else: Prosedürel Bloklarda Koşullu Mantık

if/else bir always bloğunun içinde nasıl çalışır, yeni başlayanları yakalayan latch tuzağı ve zincirlenmiş else if'lerin ürettiği priority encoder donanımı.

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

Tanıdık Sözdizimi, Farklı Mental Model

if/else, tam olarak C gibi görünür:

if (condition) begin
    // ... ifadeler ...
end else begin
    // ... ifadeler ...
end

Ama kurallar farklı çünkü Verilog yazılım değil. Akılda tutman gereken iki şey:

  1. if/else yalnızca bir prosedürel blok içinde yaşar. Modül seviyesinde serbest bir if yazamazsın.
  2. if/else'in neye sentezlendiği blok tipine bağlıdır. Bir kombinasyonel blokta, multiplexer veya priority encoder olur. Bir saatli blokta, koşullu güncelleme mantığıyla bir flip-flop olur.

Bir Kombinasyonel Blok İçinde

Kombinasyonel always @(*) bloğu, a, b veya c değiştiğinde tekrar çalışır. if/else zinciri bir dal seçer, max'a atar ve blok biter. max her zaman atandığı için (her yolun bir ataması var), sentezleyici saf kombinasyonel mantık üretir - latch yok.

Donanımda flip-flop olmamasına rağmen max'in reg olarak tanımlandığına dikkat et. Her zamanki gibi aynı kural: always içinde atanan her şey reg olmalıdır.

Latch Tuzağı

Bu, başlangıç kombinasyonel kodundaki en yaygın hatadır:

// YANLIŞ - bir latch çıkarır
always @(*) begin
    if (enable)
        out = data;
    // else yok! `enable` düşükken `out` ne yapar?
end

Sentezleyici "enable düşükken, out atanmamış" okur ve out'un önceki değerini hatırlaması gerektiğine karar verir. Bir değeri hatırlamak bir depolama hücresi gerektirir, bu yüzden araç bir latch ekler. Senkron tasarımlardaki latch'ler zamanlama sorunlarına neden olur, reset edilmeleri zordur ve neredeyse hiç ne demek istediğin değildir.

İki düzeltme yolu:

İkisi de aynı kombinasyonel donanımı üretir - bir 2-to-1 mux. "Başta varsayılan" kalıbı, aynı sinyale çok sayıda koşullu ataman olduğunda daha iyi ölçeklenir.

Bir Saatli Blok İçinde

Kombinasyonel durumdan farkına dikkat et:

  • Blok always @(posedge clk) - flip-flop bölgesi.
  • Atama <= (non-blocking) kullanır.
  • "Ne reset ne enable" durumu için bir else yok. Bu sorun değil. Saatli bir blokta, hiçbir dal tetiklenmediğinde, flip-flop sadece önceki değerini korur - ki bu fiziksel olarak bir flip-flop'un yaptığı şeydir. Sinyal zaten bir register olduğu için latch çıkarılmaz.

Bu, bir else'i atlamanın güvenli olduğu tek yerdir. Saatli bloklar dışında her zaman her yolu işle.

Zincirlenmiş else if: Bir Priority Encoder

else if ifadelerinin bir zinciri örtük önceliğe sahiptir - daha erken koşullar daha sonrakilerden öncelikli olur:

requests[0] en yüksek önceliktir - ayarlıysa, yüksek numaralı bitlerin ne yaptığına bakılmaksızın grant 0'dır. Sentezleyici zinciri zincirlenmiş bir mux'a dönüştürür: önce bit 0'ı, sonra bit 1'i, sonra bit 2'yi, sonra bit 3'ü kontrol et. Her seviye küçük bir gecikme ekler.

Koşullar birbirini dışlıyorsa - örneğin bir one-hot girişi decode etmek - bir case ifadesi (sonraki doc) else if zincirinden çok daha düz, daha hızlı donanım üretir. Gerçek bir öncelik gereksinimi olmadığında case formunu kullan.

Saatli Kodda else Olmadan if

Bir saatli bloğun else'e ihtiyacı yoktur çünkü "önceki değeri tut" varsayılandır. Enable'ları böyle kurarsın:

always @(posedge clk) begin
    if (load) target <= incoming;
    // else yok: load düşük olduğunda, target değerini korur
end

Bu bir load-enabled register'dır. Çoğu pipeline register'ı, counter ve konfigürasyon register'ı bu kalıbı kullanır.

begin/end ve Tek İfadeler

C gibi, tek bir ifade için begin/end'i atlayabilirsin:

if (a) out = 1;
else   out = 0;

Bir ifadeden fazlası için bloğu kullan:

if (a) begin
    out = 1;
    flag = 1;
end else begin
    out = 0;
    flag = 0;
end

İki kalıp serbestçe karışır. Stil kılavuzları genellikle ikinci bir ifade eklemeyi acısız hale getirmek için her zaman begin/end kullanmayı önerir.

Sırada Ne Var

Bir sonraki doc - Case Statement - çok yönlü decoding (state machine'ler, opcode dispatch, ROM tabloları) için doğru araç olan case'i kapsar. Ondan sonra, for döngüleri, elaboration zamanında açıldıkları için yazılım kuzenlerinden ince bir şekilde farklıdır.

Sıkça Sorulan Sorular

Verilog'da bir if ifadesi nasıl çalışır?

if (cond) statement;, cond sıfır olmayan olduğunda statement'ı çalıştırır. Birden çok ifadeyi begin ... end ile sarabilirsin. Alternatif dal için else statement; ekle veya else if (other_cond) ... ile zincirleme yap. if/else yalnızca prosedürel blokların - initial veya always - içinde bulunur, bir modülün üst seviyesinde değil.

Verilog'da inferred latch nedir?

Sentez aracının istemediğin halde oluşturduğu bir latch, çünkü kombinasyonel always bloğun bir sinyali her yolda atamadı. Araç 'a ise out = 1' görür, else olmadan, atanmamış durumun önceki değeri hatırlaması gerektiğine karar verir ve bir latch üretir. Latch'ler neredeyse her zaman yanlıştır; düzeltme her sinyale bloğun başında bir varsayılan değer veya açık bir else vermektir.

Verilog'da inferred latch'lerden nasıl kaçınılır?

Kombinasyonel bir always @(*) bloğunda, her çıkış reg'inin her kod yolunda atandığından emin ol. En temiz kalıp, bloğun başında varsayılanları ayarlamak ve sonra koşullu olarak override etmektir. Derleyici genellikle bir latch çıkardığında uyarır - uyarıyı hata olarak değerlendir.

Verilog'da bir if-else zincirinden ne sentezlenir?

Bir priority encoder. İlk if en yüksek önceliğe sahiptir, sonraki else if yalnızca ilki yanlış ise kontrol edilir ve böyle devam eder. Donanımda bu, öncelik sırasının pişirildiği bir mux zinciri olur. Koşullar birbirini dışlıyorsa, aynı mantıkla bir case ifadesi genellikle daha düz donanıma sentezlenir ve daha net okunur.

Coddy programming languages illustration

Coddy ile kodlamayı öğren

BAŞLA