🛠️ Verilog RTL Tasarımı – Yazım Kuralları ve En İyi Uygulamalar #
Verilog ile RTL modülleri yazarken tutarlı bir yapı ve sözdizimi kullanmak okunabilirlik, sentezlenebilirlik ve ölçeklenebilirlik açısından çok önemlidir. İşte uyulması gereken temel kurallar:
📌 1. Modül Tanımı #
Her tasarım bloğuna module
ile başlayın ve endmodule
ile bitirin.
Aşağıdaki görselde bu modülün soyut bir gösterimini görüyorsunuz. Sadece modül tanımı ve port tanımları yer alıyor. Bu haliyle artık başka bir modüle bağlanabilir veya başka bir modülün içinde örneklenebilir.
module module_name(
input wire clk,
input wire rst,
input wire a,
output wire y
);
// İç mantık burada
endmodule
📌 2. Anlamlı Port İsimleri Kullanın #
Gerçek tasarımlarda tek harfli isimlerden kaçının — clk
, rst_n
, data_in
, valid
gibi anlamlı isimler tercih edin.
📌 3. Port Yönü ve Tip Tanımı #
input
, output
ve gerektiğinde inout
kullanın. Varsayılan olarak portlar wire
olmalıdır. reg
sadece always
blokları içinde sürülen sinyaller için kullanılmalıdır.
input wire clk;
output reg valid_out; // always bloğunda sürülüyor
📌 4. Tutarlı Biçimlendirme #
Girintilere dikkat edin, okunaklı ve düzenli kod yazın.
assign y = a & b;
📌 5. Kombinasyonel Mantık: assign
veya always @(*)
#
Basit ifadeler için assign
kullanın:
assign y = a & b;
Daha karmaşık mantıklar için:
always @(*) begin
case (sel)
2'b00: out = in0;
2'b01: out = in1;
...
endcase
end
📌 6. Ardışıl Mantık: always @(posedge clk)
#
Ardışıl mantık için reg
tipi ve <=
(non-blocking) atama kullanın.
always @(posedge clk or posedge rst) begin
if (rst)
count <= 0;
else
count <= count + 1;
end
📌 7. Blocking ve Non-blocking Atamaları Karıştırmayın #
Aynı always
bloğu içinde sadece bir tür atama kullanın:
=
→ kombinasyonel mantık için (always @(*)
)<=
→ ardışıl mantık için (always @(posedge clk)
)
📌 8. Reset Mantığını Tanımlayın #
Donanım başlangıcı için reset davranışını açıkça belirtin.
if (rst) begin
state <= IDLE;
end
📌 9. RTL’de #
Gecikmelerinden Kaçının
#
#10
gibi gecikmeler sadece testbench içinde kullanılmalıdır. Sentezlenemezler.
📌 10. RTL’de initial
Kullanmayın
#
initial
sadece testbench ya da sadece simülasyon kodlarında kullanılmalıdır.
✅ Özet Tablosu #
Kural | Doğru Kullanım | Kaçınılması Gereken |
---|---|---|
module /endmodule kullan |
✅ module mymod(...); |
❌ İsimsiz ya da satır içi kod |
assign /always kullan |
✅ assign y = a & b; |
❌ always y = a & b; |
Sıralı mantıkta <= kullan |
✅ count <= count + 1; |
❌ count = count + 1; |
always içinde reg kullan |
✅ reg valid; always @(...) |
❌ always içinde wire atanması |
RTL’de gecikmeden kaçın | ✅ Gecikmesiz assign |
❌ #10 , #5 içeren RTL kodu |
Reset kullan | ✅ if (rst) q <= 0; |
❌ Reset olmayan veya belirsiz |
🧪 Verilog Testbench – Yazım Kuralları ve En İyi Uygulamalar #
Testbench, RTL tasarımınızı uyarmak ve gözlemlemek için kullanılan, yalnızca simülasyon amaçlı bir Verilog modülüdür. Sentezlenemez ve donanım üretiminden önce doğrulama için gereklidir.
📌 1. Testbench Modülünde Port Olmaz #
Testbench modülü dış dünya ile bağlantılı değildir, bu yüzden input
/output
tanımlanmaz.
module tb_my_design;
📌 2. DUT için Sinyalleri Tanımla #
Girişler için reg
, çıkışlar için wire
tanımlayın.
reg clk, rst, a, b;
wire y;
📌 3. DUT’yi Örnekle (Design Under Test) #
Tanımladığınız sinyalleri RTL modülüne bağlayın.
my_design dut (
.clk(clk),
.rst(rst),
.a(a),
.b(b),
.y(y)
);
📌 4. Saat Sinyali Üretimi #
Bir always
bloğu ile saat üretin.
initial clk = 0;
always #5 clk = ~clk; // 10ns saat periyodu
📌 5. Uyarıcıları initial
Bloğu ile Uygula
#
Test senaryosunu initial
bloğu ile tanımlayın.
initial begin
rst = 1; a = 0; b = 0;
#10 rst = 0;
#10 a = 1;
#10 b = 1;
#20 $finish;
end
📌 6. Çıktıları $monitor
veya $display
ile İzle
#
Sinyal değerlerini terminal ya da waveformda gözlemlemek için kullanılır.
initial begin
$monitor("Time=%0t : a=%b b=%b y=%b", $time, a, b, y);
end
📌 7. Waveform için $dumpfile
ve $dumpvars
Kullan
#
GTKWave gibi araçlarla dalga formu görüntülemek için kullanılır.
initial begin
$dumpfile("wave.vcd");
$dumpvars(0, tb_my_design);
end
✅ Örnek Testbench Şablonu #
module tb_and_gate;
reg a, b;
wire y;
// DUT’yi örnekle
and_gate dut (
.a(a),
.b(b),
.y(y)
);
initial begin
$dumpfile("wave.vcd");
$dumpvars(0, tb_and_gate);
$monitor("Time: %0t | a=%b b=%b y=%b", $time, a, b, y);
// Uyarıcılar
a = 0; b = 0; #10;
a = 1; b = 0; #10;
a = 0; b = 1; #10;
a = 1; b = 1; #10;
$finish;
end
endmodule
🎯 Özet Tablosu #
Kural | Doğru Kullanım | Yanlış Kullanım |
---|---|---|
Testbench’te port olmasın | ✅ module tb_my_module; |
❌ input/output kullanımı |
Saat üretimi | ✅ always #5 clk = ~clk; |
❌ initial içinde elle toggle |
Uyarıcı için initial |
✅ a = 1; #10; |
❌ always içinde gecikmeli işlemler |
Çıktıyı izle | ✅ $monitor , $display |
❌ Gözlemlenemeyen test |
Waveform al | ✅ $dumpfile("wave.vcd") |
❌ Waveform yok = debug yok |
📚 Önerilen Verilog Kodlama Stili Rehberi #
Verilog kodu yazarken — ister FPGA prototipleme, ister ASIC tasarımı, isterse formal doğrulama için olsun — açık ve tutarlı bir kodlama stilini takip etmek çok önemlidir. Bu, sadece okunabilirliği ve sürdürülebilirliği artırmakla kalmaz, aynı zamanda ekiplerin daha verimli çalışmasını da sağlar.
Bu nedenle, lowRISC Verilog Kodlama Stili Rehberi’ni en iyi uygulamalar için temel kaynak olarak öneriyorum.
🔗 Rehber Linki: 👉
Bu rehberi neden takip etmelisiniz? #
- ✅ Sinyal isimlendirme ve modül hiyerarşisi için net kurallar
- ✅ Biçimlendirme, boşluk ve girintileme için yönergeler
- ✅ Sentezlenebilir ve sentezlenemez yapılar için tavsiyeler
- ✅ Simülasyon netliği ve debug kolaylığı için pratikler
İster Verilog’a yeni başlıyor olun, ister büyük ölçekli bir tasarım projesi üzerinde çalışıyor olun, bu rehberi benimsemek zaman kazandırır ve karmaşık hataların önüne geçer.