UVM'e Giriş
UVM (Universal Verification Methodology), SystemVerilog tabanlı doğrulama ortamları oluşturmak için kullanılan standart bir metodolojidir. Accellera tarafından geliştirilmiş olup, yeniden kullanılabilir, ölçeklenebilir ve modüler doğrulama bileşenleri yazmayı sağlar.
UVM Neden Gerekli?
Donanım tasarımları karmaşıklaştıkça, doğrulama süreci de zorlaşır. UVM aşağıdaki avantajları sağlar:
- Yeniden kullanılabilirlik: Bileşenler farklı projelerde tekrar kullanılabilir
- Standart yapı: Tüm ekip aynı mimariyi kullanır
- Rastgele test üretimi: Constrained random ile kapsamlı test senaryoları
- Fonksiyonel kapsam: Coverage ile doğrulama ilerlemesini ölçme
- Fazlara ayrılmış simülasyon: Build, connect, run gibi aşamalar
UVM Test Ortamı Mimarisi
Tipik bir UVM test ortamı şu bileşenlerden oluşur:
┌─────────────────────────────────────────────┐
│ Test │
│ ┌───────────────────────────────────────┐ │
│ │ Environment │ │
│ │ ┌─────────────┐ ┌───────────────┐ │ │
│ │ │ Agent │ │ Scoreboard │ │ │
│ │ │ ┌─────────┐ │ │ │ │ │
│ │ │ │Sequencer│ │ └───────────────┘ │ │
│ │ │ ├─────────┤ │ │ │
│ │ │ │ Driver │ │ ┌───────────────┐ │ │
│ │ │ ├─────────┤ │ │ Coverage │ │ │
│ │ │ │ Monitor │ │ │ │ │ │
│ │ │ └─────────┘ │ └───────────────┘ │ │
│ │ └─────────────┘ │ │
│ └───────────────────────────────────────┘ │
│ DUT │
└─────────────────────────────────────────────┘
İlk UVM Bileşenlerimiz
Transaction (Sequence Item)
Her şey bir veri nesnesiyle başlar. UVM'de buna sequence item denir:
class simple_txn extends uvm_sequence_item;
`uvm_object_utils(simple_txn)
rand logic [7:0] addr;
rand logic [31:0] data;
rand logic write;
constraint addr_range_c {
addr inside {[8'h00 : 8'hFF]};
}
constraint data_align_c {
data[1:0] == 2'b00;
}
function new(string name = "simple_txn");
super.new(name);
endfunction
function string convert2string();
return $sformatf("addr=0x%02h data=0x%08h write=%0b",
addr, data, write);
endfunction
endclass
Driver
Driver, transaction'ları DUT'un pin seviyesine çevirir:
class simple_driver extends uvm_driver #(simple_txn);
`uvm_component_utils(simple_driver)
virtual simple_if vif;
function new(string name, uvm_component parent);
super.new(name, parent);
endfunction
function void build_phase(uvm_phase phase);
super.build_phase(phase);
if (!uvm_config_db#(virtual simple_if)::get(this, "", "vif", vif))
`uvm_fatal("NOVIF", "Virtual interface not found")
endfunction
task run_phase(uvm_phase phase);
simple_txn txn;
forever begin
seq_item_port.get_next_item(txn);
drive_transaction(txn);
seq_item_port.item_done();
end
endtask
task drive_transaction(simple_txn txn);
@(posedge vif.clk);
vif.addr <= txn.addr;
vif.data <= txn.data;
vif.write <= txn.write;
vif.valid <= 1'b1;
@(posedge vif.clk);
vif.valid <= 1'b0;
`uvm_info("DRV", $sformatf("Driven: %s", txn.convert2string()), UVM_MEDIUM)
endtask
endclass
Monitor
Monitor, DUT'un çıkışlarını izler ve analiz bileşenlerine iletir:
class simple_monitor extends uvm_monitor;
`uvm_component_utils(simple_monitor)
virtual simple_if vif;
uvm_analysis_port #(simple_txn) ap;
function new(string name, uvm_component parent);
super.new(name, parent);
endfunction
function void build_phase(uvm_phase phase);
super.build_phase(phase);
ap = new("ap", this);
if (!uvm_config_db#(virtual simple_if)::get(this, "", "vif", vif))
`uvm_fatal("NOVIF", "Virtual interface not found")
endfunction
task run_phase(uvm_phase phase);
simple_txn txn;
forever begin
@(posedge vif.clk);
if (vif.valid) begin
txn = simple_txn::type_id::create("txn");
txn.addr = vif.addr;
txn.data = vif.data;
txn.write = vif.write;
ap.write(txn);
`uvm_info("MON", $sformatf("Observed: %s", txn.convert2string()), UVM_HIGH)
end
end
endtask
endclass
Sequence
Sequence, test senaryolarını tanımlar:
class simple_sequence extends uvm_sequence #(simple_txn);
`uvm_object_utils(simple_sequence)
int unsigned num_txns = 10;
function new(string name = "simple_sequence");
super.new(name);
endfunction
task body();
simple_txn txn;
repeat (num_txns) begin
txn = simple_txn::type_id::create("txn");
start_item(txn);
if (!txn.randomize())
`uvm_error("RAND", "Randomization failed")
finish_item(txn);
end
`uvm_info("SEQ", $sformatf("%0d transactions sent", num_txns), UVM_LOW)
endtask
endclass
UVM Fazları (Phases)
UVM simülasyonu belirli fazlar halinde çalışır:
| Faz | Açıklama | Tür |
|---|---|---|
build_phase |
Bileşenleri oluştur | Fonksiyon |
connect_phase |
Portları bağla | Fonksiyon |
run_phase |
Simülasyonu çalıştır | Task |
report_phase |
Sonuçları raporla | Fonksiyon |
class simple_test extends uvm_test;
`uvm_component_utils(simple_test)
simple_env env;
function new(string name, uvm_component parent);
super.new(name, parent);
endfunction
// 1. Bileşenleri oluştur
function void build_phase(uvm_phase phase);
super.build_phase(phase);
env = simple_env::type_id::create("env", this);
endfunction
// 2. Simülasyonu çalıştır
task run_phase(uvm_phase phase);
simple_sequence seq;
phase.raise_objection(this);
seq = simple_sequence::type_id::create("seq");
seq.num_txns = 20;
seq.start(env.agent.sequencer);
phase.drop_objection(this);
endtask
// 3. Sonuçları raporla
function void report_phase(uvm_phase phase);
uvm_report_server svr = uvm_report_server::get_server();
if (svr.get_severity_count(UVM_ERROR) > 0)
`uvm_info("TEST", "*** TEST FAILED ***", UVM_NONE)
else
`uvm_info("TEST", "*** TEST PASSED ***", UVM_NONE)
endfunction
endclass
Özet
Bu derste UVM'in temel kavramlarını öğrendik:
- UVM'in amacı: Yeniden kullanılabilir, standart doğrulama ortamı
- Temel bileşenler: Transaction, Driver, Monitor, Sequence
- Fazlar: build, connect, run, report
- Config DB: Bileşenler arası veri paylaşımı
Bir sonraki derste Agent ve Environment yapısını detaylı inceleyeceğiz.