EDA Playground'da Dene

rand ve randc

Gün 3: Rastgele Üretim ve Kısıtlamalar | Rastgele değişkenler: rand (rastgele) ve randc (döngüsel)

Bu derste SystemVerilog'un kısıtlanmış-rastgele (constrained-random) doğrulama altyapısının temel yapı taşı olan rastgele değişkenleri öğreneceğiz: rand ve randc niteleyicileri ile std::randomize fonksiyonunu, bunların farklarını ve nerede kullanılacağını ele alacağız.

Neden Rastgele Üretim?

Modern donanım doğrulamasında, bir tasarımın tüm köşe durumlarını (corner case) elle yazılmış yönlü (directed) testlerle yakalamak neredeyse imkânsızdır. Bunun yerine kısıtlanmış-rastgele doğrulama yaklaşımı kullanılır: değişkenlere rastgele ama anlamlı (kısıtlanmış) değerler atayarak çok sayıda senaryo otomatik olarak üretilir. Bu sayede mühendisin aklına gelmeyen kombinasyonlar da test edilir.

SystemVerilog'da bir sınıf üyesini rastgele yapmak için iki niteleyici vardır:

  • rand: Her randomize() çağrısında değişkene, izin verilen aralık içinden bağımsız ve rastgele bir değer atar. Aynı değer arka arkaya birden fazla kez gelebilir (tekrar olabilir).
  • randc (cyclic random / döngüsel rastgele): Olası tüm değerleri bir kez üretmeden hiçbirini tekrar etmez. Tüm değerler tükendiğinde döngü baştan başlar ve yeni bir rastgele sıra ile devam eder. Genellikle dar bit genişlikli alanlar (örneğin adres seçici, kanal numarası) için kullanılır.

rand vs randc

  • rand değişkenleri bellek/performans açısından ucuzdur ve çoğu durumda tercih edilir.
  • randc değişkenleri tüm değer uzayını tarama garantisi verir; ancak bu uzayın küçük olması beklenir (örneğin 3 bit = 8 değer). Çok geniş randc alanları kaçınılması gereken bir kalıptır.

std::randomize

Sınıf dışındaki yerel değişkenleri rastgeleleştirmek için sınıfa bağlı olmayan std::randomize() fonksiyonu kullanılır. Buna with { ... } ekleyerek satır içi (inline) kısıtlamalar da verilebilir.

Kaynak Kod

// =============================================================================
// GUN 3 - Konu 1: Rastgele Test ve rand/randc Degiskenleri
// =============================================================================

class Packet;
  // rand: Her randomize() cagrisinda rastgele deger uretir
  rand bit [7:0]  data;
  rand bit [3:0]  addr;
  rand bit [1:0]  burst_type;
  
  // randc: Tum olasi degerleri tuketmeden tekrar etmez (cyclic random)
  randc bit [2:0] prio;  // 0-7 arasi, her biri bir kez, sonra tekrar

  // Rastgele olmayan degiskenler
  int id;
  static int count = 0;

  function new();
    this.id = count++;
  endfunction

  function void display();
    $display("  Paket #%0d: data=0x%02h, addr=0x%01h, burst=%0d, priority=%0d",
             id, data, addr, burst_type, prio);
  endfunction
endclass

module rand_ve_randc;
  initial begin
    Packet pkt;
    Packet pkt2;//randc gösterimi için
    
    $display("=== rand ve randc Degiskenleri ===\n");

    pkt = new();
    pkt2 = new();

    // --- rand: Her seferinde rastgele ---
    $display("--- rand: 10 rastgele paket ---");
    repeat (10) begin
      if (!pkt.randomize())
        $fatal(1, "Randomize basarisiz!");
      pkt.display();
    end

    // --- randc: Dongusel rastgele ---
    $display("\n--- randc: priority (0-7 dongusel) ---");
    $display("  Ilk dongu (8 deger):");
    repeat (8) begin
      void'(pkt2.randomize());
      $display("    priority = %0d", pkt2.prio);
    end
    $display("  Ikinci dongu (tekrar 8 deger, farkli sira):");
    repeat (8) begin
      void'(pkt2.randomize());
      $display("    priority = %0d", pkt2.prio);
    end

    // --- std::randomize (sinif disinda) ---
    $display("\n--- std::randomize (Bagimsiz) ---");
    begin
      int x, y;
      repeat (5) begin
        if (!std::randomize(x, y) with { x inside {[1:100]}; y < x; })
          $fatal(1, "std::randomize basarisiz!");
        $display("  x = %0d, y = %0d", x, y);
      end
    end

    $display("\n=== rand ve randc Sonu ===");
    $finish;
  end
endmodule

Kodun Açıklaması

  • Packet sınıfında üç adet rand değişkeni (data, addr, burst_type) ve bir adet randc değişkeni (prio) tanımlanmıştır. id ve statik count ise rastgele olmayan, normal üyelerdir.
  • new() kurucusunda her nesne için count++ ile artan bir id atanır; bu, üretilen paketleri birbirinden ayırmak için kullanılır.
  • İlk repeat (10) döngüsünde pkt.randomize() çağrılır. Dönüş değeri kontrol edilir; başarısız olursa $fatal ile simülasyon durdurulur. Her çağrıda data, addr ve burst_type bağımsız rastgele değerler alır.
  • İkinci bölümde pkt2 üzerindeki randc değişkeni prio gösterilir. İlk 8 çağrıda 0–7 arası her değer tam bir kez üretilir. İkinci 8 çağrıda yine tüm değerler çıkar, ancak farklı bir sırada — döngüsel davranışın kanıtı budur.
  • void'(pkt2.randomize()) ifadesindeki void'(...) cast'i, fonksiyonun dönüş değerini bilinçli olarak yok saymak içindir.
  • Son bölümde std::randomize(x, y) with { x inside {[1:100]}; y < x; } kullanılarak sınıfa ait olmayan iki yerel int değişkeni satır içi kısıtlamalarla rastgeleleştirilir: x 1–100 arasında, y ise x'ten küçük olur.

Önemli Noktalar

  • randomize() dönüş değerini her zaman kontrol edin. Başarısız bir randomize (kısıtlama çakışması) sessizce eski değerleri bırakır; bu yüzden if (!...) veya assert(...) kullanmak şarttır.
  • randc alanlarını dar tutun. Geniş bit genişliği, tüm değer uzayının izlenmesi nedeniyle performansı ciddi şekilde düşürür.
  • randc, tüm değerler tükenene kadar tekrar üretmez; bu yüzden "her değeri bir kez gör" tipi senaryolarda idealdir.
  • void'(...) cast'i ile dönüş değerini yok saymak yalnızca randomize'ın başarılı olacağından emin olduğunuz durumlarda tercih edilmelidir.
  • std::randomize, hızlı testlerde veya sınıf tanımlamadan birkaç değişkeni rastgeleleştirmek istediğinizde pratiktir, ancak büyük doğrulama ortamlarında sınıf tabanlı yaklaşım daha sürdürülebilirdir.