EDA Playground'da Dene

UVM Eğitimi 2. Gün Laboratuvar Kılavuzu: Veri Modeli ve Agent Bileşenleri

Amaç

Bu laboratuvarın amacı, UVM testbench'inde uyarıcıları (stimulus) modellemek için uvm_sequence_item oluşturmak ve bu verileri işleyecek olan temel Agent bileşenlerini (uvm_sequencer, uvm_driver, uvm_monitor) tasarlayıp birbirine bağlamaktır.

Ön Koşullar

  • 1.Gün laboratuvarında oluşturulan temel hiyerarşi kavramlarına (build_phase, connect_phase) hakimiyet.
  • SystemVerilog rand ve OOP sınıfları hakkında temel bilgi.

Lab 2.1: Transaction (Veri Modeli) Oluşturma

UVM'de DUT'a (Design Under Test) gönderilecek veya DUT'tan okunacak her veri paketi uvm_sequence_item sınıfından türetilir.

Görev: my_transaction adında bir sınıf oluşturun. İçine rastgele (random) üretilebilecek adres, veri ve yazma/okuma kontrol sinyallerini ekleyin. Ayrıca UVM alan (field) makrolarını kullanarak bu değişkenleri UVM sistemine tanıtın.

class my_transaction extends uvm_sequence_item;  
    
  // Random payload variables  
  rand bit [31:0] data;  
  rand bit [7:0]  addr;  
  rand bit        write_en; // 1: Write, 0: Read  
    
  // Register fields to UVM factory and enable generic functions (print, copy, compare)  
  `uvm_object_utils_begin(my_transaction)  
    `uvm_field_int(data,     UVM_ALL_ON)  
    `uvm_field_int(addr,     UVM_ALL_ON)  
    `uvm_field_int(write_en, UVM_ALL_ON)  
  `uvm_object_utils_end  
    
  // Constructor  
  function new(string name = "my_transaction");  
    super.new(name);  
  endfunction  
    
endclass

Lab 2.2: Sequencer ve Driver Tasarımı

Sequencer, üretilen transaction'ları sıraya koyan bir hakemdir. Driver ise bu transaction'ları Sequencer'dan çekip donanıma (fiziksel pinlere) süren işçidir.

Görev: my_sequencer ve my_driver sınıflarını my_transaction tipinde çalışacak şekilde oluşturun. Driver'ın run_phase'i içerisinde Sequencer'dan veri çekme (get_next_item) ve işi bitirme (item_done) adımlarını kodlayın.

// ----------------------------------------------------------------------------  
// SEQUENCER  
// ----------------------------------------------------------------------------  
// Typedef is often enough for a simple sequencer, but we define a class for clarity  
class my_sequencer extends uvm_sequencer #(my_transaction);  
  `uvm_component_utils(my_sequencer)  
    
  // Constructor  
  function new(string name = "my_sequencer", uvm_component parent = null);  
    super.new(name, parent);  
  endfunction  
endclass

// ----------------------------------------------------------------------------  
// DRIVER  
// ----------------------------------------------------------------------------  
class my_driver extends uvm_driver #(my_transaction);  
  `uvm_component_utils(my_driver)  
    
  // Constructor  
  function new(string name = "my_driver", uvm_component parent = null);  
    super.new(name, parent);  
  endfunction  
    
  // Run phase: Continuously fetch items from sequencer and "drive" them  
  virtual task run_phase(uvm_phase phase);  
    super.run_phase(phase);  
      
    forever begin  
      // 1. Ask sequencer for the next item  
      seq_item_port.get_next_item(req);  
        
      `uvm_info("DRIVER", $sformatf("Driving Transaction: Addr=0x%0h, Data=0x%0h, WE=%0b",   
                                     req.addr, req.data, req.write_en), UVM_LOW)  
        
      // Simulate hardware driving delay (e.g., waiting for clock edges)  
      #20;   
        
      // 2. Tell sequencer we are done with this item  
      seq_item_port.item_done();  
    end  
  endtask  
endclass

Lab 2.3: Monitor Tasarımı

Monitor'ün görevi veri sürmek değil, fiziksel arayüzdeki (interface) sinyalleri izleyip, bunlardan tekrar bir Transaction (veri paketi) oluşturmaktır (Bu laboratuvarda arayüz olmadığı için sanal bir izleme simüle edeceğiz). Monitor asla sinyalleri değiştirmez, sadece okur (Passive).

Görev: my_monitor sınıfını oluşturun.

class my_monitor extends uvm_monitor;  
  `uvm_component_utils(my_monitor)  
    
  // Constructor  
  function new(string name = "my_monitor", uvm_component parent = null);  
    super.new(name, parent);  
  endfunction  
    
  // Run phase: Continuously monitor interface signals  
  virtual task run_phase(uvm_phase phase);  
    super.run_phase(phase);  
      
    // In a real testbench, this would wait for clock edges and sample virtual interface  
    forever begin  
      #20; // Simulated sampling delay  
      `uvm_info("MONITOR", "Sampled data from virtual interface...", UVM_HIGH)  
    end  
  endtask  
endclass

Lab 2.4: Agent'ı Güncelleme (Bağlantıların Yapılması)

Şimdi 1. gün yazdığımız içi boş Agent'ı, yeni oluşturduğumuz bu 3 bileşenle (Sequencer, Driver, Monitor) dolduracağız. Ayrıca TLM (Transaction Level Modeling) portlarını connect_phase içinde bağlayacağız.

Görev: 1. Gün'den kalan my_agent sınıfınızı aşağıdaki gibi güncelleyerek build_phase ve connect_phase mekanizmalarını ekleyin.

class my_agent extends uvm_agent;  
  `uvm_component_utils(my_agent)  
    
  // Declare handles for agent components  
  my_sequencer sqr;  
  my_driver    drv;  
  my_monitor   mon;  
    
  // Constructor  
  function new(string name = "my_agent", uvm_component parent = null);  
    super.new(name, parent);  
  endfunction  
    
  // Build phase: Create components based on is_active status  
  virtual function void build_phase(uvm_phase phase);  
    super.build_phase(phase);  
      
    // Monitor is ALWAYS built  
    mon = my_monitor::type_id::create("mon", this);  
      
    // Sequencer and Driver are only built if the agent is ACTIVE  
    if(get_is_active() == UVM_ACTIVE) begin  
      sqr = my_sequencer::type_id::create("sqr", this);  
      drv = my_driver::type_id::create("drv", this);  
    end  
  endfunction  
    
  // Connect phase: Connect Driver and Sequencer TLM ports  
  virtual function void connect_phase(uvm_phase phase);  
    super.connect_phase(phase);  
      
    // Check if components exist before connecting  
    if(get_is_active() == UVM_ACTIVE) begin  
      // Connect driver's sequence item port to sequencer's sequence item export  
      drv.seq_item_port.connect(sqr.seq_item_export);  
      `uvm_info("AGENT_CONN", "Connected Driver and Sequencer.", UVM_LOW)  
    end  
  endfunction  
endclass

Çalıştırma Öncesi Not

Bu laboratuvar, sadece Agent'ın iç mimarisini kurar. Driver'ın içindeki get_next_item komutu, Sequencer'a bir "Sequence" (Senaryo) gönderilmediği sürece sonsuza kadar bekler (Block olur). Simülasyonu çalıştırdığınızda herhangi bir transaction ekrana basılmayacaktır. Veri üretimini tetikleyecek senaryoların (Sequences) yazılması 4. Gün'ün konusudur.