Modül Verilog'un Birimidir
Verilog'daki her şey bir module'ün içinde yaşar. Bir modül bir devre parçasını sarmalar: hangi sinyallerin geldiğini, hangi sinyallerin çıktığını ve aralarındaki wire/register/mantığı tanımlar. Gördüğün her chip, vendor tarafından sağlanan gate primitive'lerine kadar diğer modülleri instantiate eden bir modüller ağacıdır.
Şekil her zaman aynıdır:
module name(port_list);
// tanımlamalar: wire, reg, parameter
// gövde: assign'lar, instantiation'lar, always blokları
endmodule
Tam bir modüle aşamalarla kuracağız.
En Küçük Yararlı Modül: İki Girişli Bir AND Gate
Basit ve kendi kendine yeterli bir şeye ihtiyacımız var. İki girişli bir AND gate mükemmel: iki giriş, bir çıkış, bir mantık satırı.
Run'a bas. Bir AND truth table'ının dört satırını görmelisin. Her parçaya bakalım.
Modül Tanımlamasını Okuma
module and_gate(
input wire a,
input wire b,
output wire y
);
module and_gate,and_gateadlı bir modül tanımlar. Diğer modüllerin bunu instantiate etmek için kullanacağı isim.- Parantezli liste port listesidir - dışarıdan görünen sinyaller.
input wire a-abir input portudur; birwire'dır (dışarıdan sürülür).output wire y-ymodül içinde bir şey tarafından sürülen bir output portudur.
Kısa olmak istesen input wire a yerine input a yazabilirdin - yalnızca yön varsayılan tipi wire yapar. Ama açık olmak edinilmeye değer bir alışkanlıktır. Module Ports, tam port şekil setini kapsar.
Gövde
assign y = a & b;
Bu bir continuous assignment'tır. "Ne zaman a veya b değişirse, y'yi iki tanenin bitwise AND'i olarak yeniden hesapla" der. Saat yok, zamanlama yok - ilişki her zaman doğrudur. Bu saf kombinasyonel mantıktır.
endmodule bloğu kapatır. Modül bitti.
Testbench
and_gate'i tek başına çalıştıramazsın. Onun girişlerini süren ve çıkışlarını izleyen ikinci bir modüle ihtiyacın var. Bu testbench'tir ve genellikle test, tb veya <design>_tb olarak adlandırırız.
module test;
reg a, b;
wire y;
and_gate dut(.a(a), .b(b), .y(y));
...
endmodule
Dikkat edilecek üç şey:
- Port listesi yok. Bir testbench simülasyonun tepesidir - dışarıda hiçbir şey yok.
reg a, bvewire y. Design under test (DUT)'a girişler testbench'tereg'dir çünkü onları bir prosedürel bloktan sürüyoruz. Çıkış birwire'dır çünkü DUT onu sürer.and_gate dut(.a(a), .b(b), .y(y)). Bu instantiation'dır.and_gate'in bir kopyasını çıkarıyoruz ve onadut(yaygın bir ad - "design under test") diyoruz..a(a)sözdizimi "instance'takiaadlı portu yerelaadlı sinyale bağla" der. Module Instantiation daha derine iner.
Stimulus
initial begin
a = 0; b = 0; #1 $display("a=%b b=%b y=%b", a, b, y);
a = 0; b = 1; #1 $display("a=%b b=%b y=%b", a, b, y);
a = 1; b = 0; #1 $display("a=%b b=%b y=%b", a, b, y);
a = 1; b = 1; #1 $display("a=%b b=%b y=%b", a, b, y);
$finish;
end
initial bloğu simülasyon başlangıcında bir kez çalışır. İçinde:
a = 0; b = 0;girişleri sürer. Bunlar blocking atamalardır - sıra önemlidir ve her biri bir sonrakinden önce gerçekleşir.#1simüle edilen zamanı 1 birim ilerletir. Buna ihtiyacımız var kiy'nin giriş değişikliklerinden sonra yerleşmek için zamanı olsun.#1olmadan,$displayy'nin eski değerini yazdırırdı.$display(...)simülasyon konsoluna yazdırır. Format string C'ninprintf'ı gibi çalışır:%bbinary,%ddecimal,%hhex,%tsimülasyon zamanı.$finishsimülasyonu bitirir. Onsuz simülatör asla gelmeyen bir olayı bekleyerek zamanı ilerletmeye devam ederdi.
Kırmayı Dene
Modülü bir OR gate olacak şekilde değiştir (&'yi |'a değiştir) ve yeniden çalıştır. Truth table flip'lenir. Şimdi bir XOR dene:
Aynı iskelet. Farklı operatör. Kombinasyonel mantık için tüm oyun budur - portları tanımla, assign'lar yaz, girişleri süpür, çıkışları gözle.
İki Çıkışlı Bir Modül
Modüllerin birden fazla çıkışı olabilir. İşte bir half-adder - iki giriş, sum ve carry-out:
İki assign ifadesi yan yana yaşar ama paralel olarak gerçekleşir - "önce sum'ı hesapla sonra carry'yi hesapla" diye bir şey yoktur. Her ikisi de her zaman doğrudur. Bu, Hardware vs Software bölümünde konuştuğumuz eşzamanlılıktır, somut hale getirilmiş.
Şimdi Bildiğin Şey
Bir Verilog dosyasının tüm iskeletini gördün: tanımlı portları ve gövdesi olan bir tasarım modülü, artı onu instantiate eden, bir initial bloğunda girişlerini süren ve sonuçları raporlayan bir testbench modülü. Okuyacağın hemen hemen her Verilog kaynak dosyası bu şablona uyar. Dilin geri kalanı sadece daha zengin mantık, çok bitli sinyaller, saatli davranış ve daha büyük testbench'lerle doldurmaktır.
Sırada: modüllerin büyüdükçe okunabilir kalması için yorumlar ve kod stili.
Sıkça Sorulan Sorular
En basit Verilog modülü nedir?
En küçük yasal Verilog modülü sadece module name; endmodule'dür - port yok, gövde yok. En küçük yararlı olan, bir çıkışlı modüldür: module and_gate(input wire a, input wire b, output wire y); assign y = a & b; endmodule. Bu, herhangi bir daha büyük tasarıma bırakabileceğin gerçek bir kombinasyonel mantık parçasıdır.
Bir Verilog modülünü nasıl çalıştırırım?
Bir modülü tek başına çalıştıramazsın - bu bir devre tanımıdır, bir program değil. Tasarımını instantiate eden ve girişlerini süren bir testbench modülü yazarsın, sonra ikisini iverilog -o sim design.v test.v ile derler ve vvp sim çalıştırırsın. Bu sayfadaki browser editör, Run'a bastığında her iki adımı senin için yapar.
Verilog'da bir testbench nedir?
Bir testbench, ikinci bir modüldür - genellikle portsuz - işi tasarımını çalıştırmaktır. Tasarımı instantiate eder, bir initial bloğu aracılığıyla girişlerini salınır, çıkışlarını $display veya $monitor ile gözlemler ve bittiğinde $finish çağırır. Testbench'ler sentezlenebilir değildir; yalnızca davranışı doğrulamak için vardırlar.
Verilog kodumun neden $finish'e ihtiyacı var?
Çünkü donanım asla durmaz. Bir simülatör zamanın geçtiğini farz eder ve açık bir $finish olmadan yeni olaylar bekleyerek sonsuza kadar ilerlemeye devam ederdi. $finish simülatöre 'bittik, temiz çık' der. Bir testbench'te bu initial bloğunun son satırıdır - testi çalıştır, sonra finish.