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.