UVM Eğitimi 3. Gün Laboratuvar Kılavuzu: TLM Haberleşmesi, Scoreboard ve Çevre (Environment) Kurulumu
Amaç
Bu laboratuvarın amacı, UVM bileşenleri arasında veri aktarımı sağlayan TLM (Transaction Level Modeling) portlarını kullanmak, verileri doğrulamak için bir Scoreboard tasarlamak ve fonksiyonel kapsama (coverage) verilerini toplamak için iki farklı yaklaşımı (Geleneksel TLM Tabanlı ve Modern Handle Tabanlı) karşılaştırmalı olarak uygulamaktır. Ayrıca simülasyon sonunda kapsama raporlarının nasıl alınacağını göreceğiz.
Ön Koşullar
- 1 ve 2. gün konuları (Agent hiyerarşisi, Sequence Item oluşturma).
- Nesne yönelimli programlamada (OOP) referanslar (handle) ve write gibi fonksiyonların işleyişi.
Lab 3.1: Monitor'e Analysis Port ve Coverage Handle Eklenmesi
Monitor, arayüzden okuduğu veriyi diğer bileşenlere iletmekle görevlidir. Bu veriyi standart TLM yapısıyla (Scoreboard ve TLM-Coverage için) "yayınlamak" (broadcast) için bir uvm_analysis_port kullanacağız. Ayrıca modern yaklaşımı göstermek için Handle-Based Coverage Collector sınıfımızın referansını da Monitor içine tanımlayacağız.
Görev: 2. Gün yazdığımız my_monitor sınıfını aşağıdaki gibi güncelleyin.
class my_monitor extends uvm_monitor;
`uvm_component_utils(my_monitor)
// 1. Declare the analysis port (Used for Scoreboard and TLM Coverage)
uvm_analysis_port #(my_transaction) ap;
// 2. Declare a handle for direct coverage sampling (Modern approach)
my_handle_coverage cov_handle;
// Constructor
function new(string name = "my_monitor", uvm_component parent = null);
super.new(name, parent);
endfunction
// Build phase: Instantiate the analysis port
virtual function void build_phase(uvm_phase phase);
super.build_phase(phase);
ap = new("ap", this);
endfunction
// Run phase: Monitor signals and broadcast/sample the transaction
virtual task run_phase(uvm_phase phase);
my_transaction tr;
super.run_phase(phase);
forever begin
#20; // Simulated sampling delay
// Create a dummy transaction to represent sampled data
tr = my_transaction::type_id::create("tr");
tr.addr = 8'hAA;
tr.data = 32'h12345678;
tr.write_en = 1'b1;
`uvm_info("MONITOR", "Sampled data from virtual interface...", UVM_LOW)
// 1. Broadcast via TLM (Will be received by Scoreboard and TLM Coverage)
ap.write(tr);
// 2. Send to modern coverage collector via direct function call
if (cov_handle != null) begin
cov_handle.sample_cov(tr.write_en);
end
end
endtask
endclass
Lab 3.2: UVM Scoreboard Tasarımı
Scoreboard, Monitor'den gelen işlemleri dinler (Analysis Implementation aracılığıyla) ve doğruluğunu kontrol eder.
Görev: my_scoreboard adında bir sınıf oluşturun. Bir uvm_analysis_imp portu ekleyin ve mecburi olan write() fonksiyonunu tanımlayın.
class my_scoreboard extends uvm_scoreboard;
`uvm_component_utils(my_scoreboard)
// Declare the analysis implementation port
uvm_analysis_imp #(my_transaction, my_scoreboard) ap_imp;
// Constructor
function new(string name = "my_scoreboard", uvm_component parent = null);
super.new(name, parent);
endfunction
// Build phase
virtual function void build_phase(uvm_phase phase);
super.build_phase(phase);
ap_imp = new("ap_imp", this);
endfunction
// The mandatory write() method triggered by ap.write()
virtual function void write(my_transaction tr);
if(tr.addr == 8'hAA && tr.data == 32'h12345678) begin
`uvm_info("SCOREBOARD", "Data matches expected values! [PASS]", UVM_LOW)
end else begin
`uvm_error("SCOREBOARD", "Data mismatch detected! [FAIL]")
end
endfunction
endclass
Lab 3.3: Kapsama (Coverage) Toplayıcıları ve Raporlama
Bu bölümde iki farklı Coverage Collector oluşturacağız ve her ikisine de simülasyon biterken nihai sonuçları ekrana yazdırması için report_phase metodunu ekleyeceğiz.
Yöntem 1: Geleneksel TLM Tabanlı (uvm_subscriber)
uvm_subscriber tek bir porta sahip olduğu için büyük projelerde yetersiz kalabilir.
// APPROACH 1: TLM-based using uvm_subscriber
class my_tlm_coverage extends uvm_subscriber #(my_transaction);
`uvm_component_utils(my_tlm_coverage)
my_transaction cov_tr;
covergroup cg;
option.per_instance = 1;
cp_write_en: coverpoint cov_tr.write_en {
bins read_op = {0};
bins write_op = {1};
}
endgroup
function new(string name = "my_tlm_coverage", uvm_component parent = null);
super.new(name, parent);
cg = new();
endfunction
// Mandatory write method for TLM
virtual function void write(my_transaction t);
cov_tr = t;
cg.sample();
`uvm_info("TLM_COV", $sformatf("Sampled via TLM. write_en=%0b", cov_tr.write_en), UVM_LOW)
endfunction
// Report phase to print the final coverage at the end of the simulation
virtual function void report_phase(uvm_phase phase);
super.report_phase(phase);
`uvm_info("TLM_COV_REPORT", $sformatf("Final Coverage (TLM-Based): %0.2f%%", cg.get_inst_coverage()), UVM_NONE)
endfunction
endclass
Yöntem 2: Modern Handle Tabanlı (Doğrudan Fonksiyon Çağrısı)
Sektörde tavsiye edilen, port kısıtlaması olmayan yöntem. Covergroup argümanları doğrudan fonksiyonla toplanır.
// APPROACH 2: Handle-based using standard uvm_component
class my_handle_coverage extends uvm_component;
`uvm_component_utils(my_handle_coverage)
// Covergroup with arguments passed to its sample function
covergroup cg with function sample(bit w_en);
option.per_instance = 1;
cp_write_en: coverpoint w_en {
bins read_op = {0};
bins write_op = {1};
}
endgroup
function new(string name = "my_handle_coverage", uvm_component parent = null);
super.new(name, parent);
cg = new();
endfunction
// Custom function to be called directly from anywhere
function void sample_cov(bit w_en);
cg.sample(w_en);
`uvm_info("HANDLE_COV", $sformatf("Sampled via Handle. write_en=%0b", w_en), UVM_LOW)
endfunction
// Report phase to print the final coverage at the end of the simulation
virtual function void report_phase(uvm_phase phase);
super.report_phase(phase);
`uvm_info("HANDLE_COV_REPORT", $sformatf("Final Coverage (Handle-Based): %0.2f%%", cg.get_inst_coverage()), UVM_NONE)
endfunction
endclass
Lab 3.4: Çevre (Environment) İçinde Bağlantıların Yapılması
Scoreboard ve TLM tabanlı Coverage için geleneksel port bağlantılarını (connect) kullanacağız. Handle tabanlı modern Coverage sınıfı için ise referans ataması (=) yapacağız.
Görev: my_env sınıfını güncelleyerek build_phase ve connect_phase mekanizmalarını kurun.
class my_env extends uvm_env;
`uvm_component_utils(my_env)
// Component handles
my_agent agent_inst;
my_scoreboard sb_inst;
my_tlm_coverage tlm_cov_inst;
my_handle_coverage handle_cov_inst;
// Constructor
function new(string name = "my_env", uvm_component parent = null);
super.new(name, parent);
endfunction
// Build phase
virtual function void build_phase(uvm_phase phase);
super.build_phase(phase);
agent_inst = my_agent::type_id::create("agent_inst", this);
sb_inst = my_scoreboard::type_id::create("sb_inst", this);
tlm_cov_inst = my_tlm_coverage::type_id::create("tlm_cov_inst", this);
handle_cov_inst = my_handle_coverage::type_id::create("handle_cov_inst", this);
endfunction
// Connect phase
virtual function void connect_phase(uvm_phase phase);
super.connect_phase(phase);
// 1. TLM Connections: ap is a broadcast port, it can connect to multiple destinations
agent_inst.mon.ap.connect(sb_inst.ap_imp);
agent_inst.mon.ap.connect(tlm_cov_inst.analysis_export);
// 2. Handle Passing: Pass the coverage collector handle directly to the monitor
agent_inst.mon.cov_handle = this.handle_cov_inst;
`uvm_info("ENV_CONN", "TLM connections and handle passing completed successfully.", UVM_LOW)
endfunction
endclass
Özet ve Beklenen Sonuç
base_test içerisinde #100 zaman birimi boyunca beklenildiğinde, Monitor (her 20 birimde bir çalıştığı için) 5 adet işlem (transaction) üretecektir.
Simülasyon çalıştırıldığında testin run_phase'i süresince ekranda Scoreboard eşleşmeleri [PASS] ve her iki Coverage örneklendirme [TLM_COV], [HANDLE_COV] logları art arda düşecektir.
Simülasyon kapatılırken (UVM report_phase'e geçtiğinde), terminalde aşağıdaki nihai rapor çıktılarını görmelisiniz:
UVM_INFO @ 100: uvm_test_top.env_inst.tlm_cov_inst [TLM_COV_REPORT] Final Coverage (TLM-Based): 50.00%
UVM_INFO @ 100: uvm_test_top.env_inst.handle_cov_inst [HANDLE_COV_REPORT] Final Coverage (Handle-Based): 50.00%
(Not: Dummy verimiz sürekli write_en = 1 ürettiği için coverpoint içindeki "write" durumu %100, "read" durumu %0 kapsanmıştır. İkisinin ortalaması %50'dir.)