Bir Modülün Arayüzü
Bir modülün port listesi onun arayüzü'dür - dış dünyanın görebildiği ve dokunabildiği her şey. Modülün içinde gövde, girişlerden çıkışları hesaplar. Portlar sınırı geçen wire'lardır.
Modern ANSI tarzı tanımlama yönü, tipi ve genişliği inline koyar:
module my_module(
input wire clk,
input wire reset,
input wire [7:0] data_in,
output reg [7:0] data_out,
output wire valid
);
// gövde
endmodule
Bu tüm şekildir. Her port şunlara sahiptir:
- Bir yön:
input,outputveyainout. - Bir tip:
wireveyareg(veya SystemVerilog'dalogic). - Bir genişlik:
[7:0]gibi bir aralık veya atlanırsa tek bitlik. - Bir ad: gövde içinde kullanacağın tanımlayıcı.
Üç Yön
input - Dışarıdan Sürülür
Input'lar her zaman wire'dır. Sürücü modülün dışındadır - ya yüksek seviye bir modülün sinyali ya da testbench'in reg'i. Bu modül içinde input'ları ifadelerde okuyabilirsin ama asla atayamazsın:
module reader(input wire [7:0] data);
initial $display("data = %h", data);
endmodule
Modül içinde data = ... yazmak bir hata olurdu.
output - İçeriden Sürülür
Output'lar bu modülün içinde bir şey tarafından sürülür. wire (bir assign veya bir alt modül çıkışı tarafından sürülür) veya reg (always/initial'dan sürülür) olabilir.
module driver(
input wire a,
input wire b,
input wire clk,
output wire y, // wire - assign tarafından sürülür
output reg q // reg - always tarafından sürülür
);
assign y = a & b; // y wire olduğu için TAMAM
always @(posedge clk)
q <= a; // q reg olduğu için TAMAM
endmodule
always bloğu içinde y'ye atama yapmaya çalışmak veya q'yu bir assign ile sürmek derleme hatası olurdu. Anahtar sözcük seçimi sürücüyle eşleşmelidir.
inout - Çift Yönlü
inout portlar, modül veya dışarıda bağlı olan ne ise alternatif olarak sürülebilen wire'lardır. Chip sınırlarında ortaya çıkarlar - I²C SDA hatları, çift yönlü GPIO pin'leri, paylaşılan veri bus'ları. Modül içinde, yönü bir tri-state kalıbıyla kontrol edersin:
module bidir_pin(
input wire data_out,
input wire output_enable,
output wire data_in,
inout wire pin
);
assign pin = output_enable ? data_out : 1'bz;
assign data_in = pin;
endmodule
pin paylaşılan wire'dır. output_enable yüksek olduğunda, modül pin'i data_out'a sürer. Düşük olduğunda, pin'i yüksek empedansa (z) bırakır ve harici bir sürücünün kullanmasına izin verir. data_in her zaman pin'de o anda ne varsa onu gözlemler.
inout, saf dahili mantıkta nadirdir. Bir memory kontrolörü, CPU çekirdeği, görüntü işleme pipeline'ı kuruyorsan, ona hiç ihtiyacın olmayabilir. Bu chip sınırlarındaki I/O halkası için bir özelliktir.
Tek-Bitli ve Çok-Bitli Portlar
Genişlik aralığı isteğe bağlıdır - tek bitlik bir port için atla:
input wire valid, // 1 bit
input wire [7:0] data, // 8 bit
input wire [31:0] addr, // 32 bit
Genişlikler için parametreler kullanabilirsin, parametrelenmiş modüllerin çalışma şekli budur:
module bus #(
parameter WIDTH = 32
)(
input wire [WIDTH-1:0] in,
output wire [WIDTH-1:0] out
);
assign out = in;
endmodule
ANSI vs Verilog-1995 Stilleri
Bazen port listesini ve tanımlamaları ayıran eski kodu göreceksin:
// Eski Verilog-1995 stili - yeni kodda BUNU yapma
module foo(clk, data_in, data_out);
input clk;
input [7:0] data_in;
output reg [7:0] data_out;
// ...
endmodule
Port listesi yalnızca adları içerir; her port sonra gövdenin içinde ayrı olarak tanımlanır. Uzundur, "port listesinde adlandırıldı ama asla tanımlanmadı" hatalarına eğilimlidir ve iki kat daha fazla yazımdır. ANSI-2001 stili (bu doc'lar boyunca gösterilen) her ikisini de değiştirir:
module foo(
input wire clk,
input wire [7:0] data_in,
output reg [7:0] data_out
);
// ...
endmodule
ANSI stilini kullan. Araçlar 2001'den beri bunu destekliyor.
Tam Bir Örnek
O tek modül şunlara sahiptir:
- Bir parametre (
WIDTH). - Saat, reset, load enable, data ve shift enable için input'lar.
- Bir
alwaysbloğunun içinde sürülen birregçıkışı (data_out). - Bir continuous assignment tarafından sürülen bir
wireçıkışı (msb_out). - Her portun yönünü, tipini ve genişliğini inline listeleyen tam bir ANSI tarzı tanımlama.
Yazacağın hemen hemen her sentezlenebilir modül bu şekildedir.
Sırada Ne Var
Bir sonraki doc - Module Instantiation - bu modülü alıp daha büyük bir tasarımda nasıl kullanacağını gösterir. Az önce yazdığın shifter kendi başına yararlı değil; bir şey onu instantiate edip bir sisteme bağladığında hak ettiğini kazanır.
Sıkça Sorulan Sorular
Verilog'da üç port yönü nedir?
input, output ve inout. input dışarıdan sürülür. output modülün içinden sürülür. inout çift yönlüdür - modülün hem sürdüğü hem de okuduğu tri-state bus'lar için kullanışlıdır. Dahili portların büyük çoğunluğu input veya output'tur; inout yalnızca chip pin'lerinde görünür.
Output wire ile output reg arasındaki fark nedir?
output wire, çıkışın bir continuous assignment veya bir alt modül çıkışıyla sürüldüğü anlamına gelir - bir always bloğu dışındaki her şey. output reg, prosedürel bir bloktan (initial veya always) sürüldüğü anlamına gelir. Anahtar sözcük, sinyali bir always içinden hedefleyip hedefleyemeyeceğini kontrol eder, sentezlenmiş donanımın bir flip-flop içerip içermediğini değil.
Verilog portları için ANSI stili nedir?
ANSI stili her portun yönünü ve tipini port listesinde inline olarak tanımlar: module foo(input wire [7:0] data, output reg [7:0] result);. Eski Verilog-1995 stili port listesinde yalnızca adları listeler ve onları modülün içinde tekrar tanımlardı. Yeni kodda her zaman ANSI stilini kullan - daha kısa, daha az hata yapar ve modern her yerde standarttır.
Bir Verilog modülünde birden çok input ve output olabilir mi?
Evet - bir modül ihtiyacın olan kadar porta sahip olabilir, herhangi bir yön kombinasyonunda. Port listesinde virgüllerle ayır. Port listesindeki sıra instantiation'da positional bağlantı sırasını belirler, ama neredeyse her zaman sıraya bağlı kalmamak için adlandırılmış bağlantıları (.port(signal)) kullanırsın.