EDA Playground'da Dene

Döngüsel Kısıtlamalar

Gün 3: Rastgele Üretim ve Kısıtlamalar | foreach ile dizi kısıtlamaları, unique, matris kısıtlamaları

Bu derste diziler (array) üzerindeki kısıtlamaları öğreneceğiz: foreach ile her elemana kural uygulama, dinamik dizi boyutunu kısıtlama, unique ile benzersizlik garantisi ve çok boyutlu (matris) dizilerde toplam (sum()) tabanlı kısıtlamalar.

Döngüsel (Iterative) Kısıtlamalar

Bir diziyi rastgeleleştirirken, çoğu zaman her elemana ya da elemanlar arası ilişkilere kural koymak isteriz. Bunu foreach ile yaparız. foreach bir constraint bloğu içinde kullanıldığında, döngü değişkeni (örneğin i) tüm indeksler üzerinde gezer ve her indeks için ayrı bir kısıtlama üretilmiş gibi davranır.

Bu yapı şunları mümkün kılar:

  • Eleman bazlı kurallar: her payload[i] belirli bir aralıkta olsun.
  • Komşu eleman ilişkileri: payload[i] != payload[i-1] gibi ardışık farklılık ya da header[i] > header[i-1] gibi sıralama.
  • Boyut kısıtlamaları: dinamik dizinin size() değeri başka bir rastgele alana bağlanabilir.

unique

unique { ... } kısıtlaması, küme içindeki tüm elemanların birbirinden farklı olmasını garanti eder. Bu, çakışmasız adresler, benzersiz ID'ler veya tekrar etmeyen veri kümeleri üretmek için idealdir.

sum() ve Genişlik (Width) Tuzağı

Bir dizinin elemanlarının toplamını kısıtlamak için dizi.sum() kullanılır. Ancak sum(), varsayılan olarak sonucu eleman tipinin bit genişliğiyle hesaplar; bu, dar bitli elemanlarda taşmaya (overflow) yol açabilir. Çözüm, sum() with (int'(item)) yazarak her elemanı toplamaya katılmadan önce int'e dönüştürmektir.

Kaynak Kod

// =============================================================================
// GUN 3 - Konu 4: Dongusel Kisitlamalar (Iterative Constraints - foreach)
// =============================================================================

class ArrayPacket;
  rand bit [7:0] payload [];      // Dinamik dizi
  rand int       length;
  rand bit [3:0] header [4];      // Sabit boyutlu dizi

  // Dizi boyutu kisitlamasi
  constraint c_length {
    length inside {[4:16]};
    payload.size() == length;
  }

  // foreach ile eleman kisitlamalari
  constraint c_payload {
    foreach (payload[i]) {
      payload[i] inside {[8'h01:8'hFE]};  // 0x00 ve 0xFF haric
      if (i > 0)
        payload[i] != payload[i-1];        // Ardisik elemanlar farkli
    }
  }

  // Header: artan sira
  constraint c_header_ordered {
    foreach (header[i]) {
      if (i > 0)
        header[i] > header[i-1];           // Kesin artan
    }
    header[0] >= 1;
  }

  function void display();
    $display("  Length=%0d", length);
    $write("  Header: ");
    foreach (header[i]) $write("%0d ", header[i]);
    $display();
    $write("  Payload: ");
    foreach (payload[i]) $write("%02h ", payload[i]);
    $display();
  endfunction
endclass

class UniqueArray;
  rand int data [8];

  // Tum elemanlar benzersiz olmali
  constraint c_unique {
    unique {data};
    foreach (data[i])
      data[i] inside {[1:100]};
  }

  function void display();
    $write("  Unique data: ");
    foreach (data[i]) $write("%0d ", data[i]);
    $display();
  endfunction
endclass

class Matrix;
  rand bit [3:0] grid [4][4];


  // Satır toplamı 20'den küçük olsun
  // sum() sonucu array'deki item'ın width'i kadar olabiliyor normalde. Bu da toplamın overflow olmasına neden oluyor
  // O yüzden with kullanarak toplama dahil edilecek sayıları int'e dönüştürdük
  constraint c_row_sum {
    foreach (grid[i]) {
      grid[i].sum() with (int'(item)) < 20;
    }
  }

  // Koşegenler 0 olmasın
  constraint c_diagonal {
    foreach (grid[i]) {
      grid[i][i] > 0;
    }
  }

  function void display();
    $display("  4x4 Matrix:");
    foreach (grid[i]) begin
      $write("    [");
      foreach (grid[i][j])
        $write("%2d ", grid[i][j]);
      
  // sum() sonucu array'deki item'ın width'i kadar olabiliyor normalde. Bu da toplamın overflow olmasına neden oluyor
  // O yüzden with kullanarak toplama dahil edilecek sayıları int'e dönüştürdük
      $display("] sum=%0d", grid[i].sum() with (int'(item)));
    end
  endfunction
endclass

module iterative_constraints;
  initial begin
    ArrayPacket apkt;
    UniqueArray uarr;
    Matrix      mat;

    $display("=== Dongusel Kisitlamalar (foreach) ===\n");

    // --- Dizi kisitlamalari ---
    $display("--- ArrayPacket ---");
    apkt = new();
    repeat (3) begin
      assert(apkt.randomize()) else $fatal(1, "Randomize hata!");
      apkt.display();
      $display();
    end

    // --- Benzersiz elemanlar ---
    $display("--- UniqueArray ---");
    uarr = new();
    repeat (3) begin
      assert(uarr.randomize()) else $fatal(1, "Randomize hata!");
      uarr.display();
    end

    // --- Matris kisitlamalari ---
    $display("\n--- Matrix ---");
    mat = new();
    repeat (2) begin
      assert(mat.randomize()) else $fatal(1, "Randomize hata!");
      mat.display();
      $display();
    end

    $display("=== Dongusel Kisitlamalar Sonu ===");
    $finish;
  end
endmodule

Kodun Açıklaması

  • ArrayPacket sınıfında payload dinamik dizisi, length ve dört elemanlı sabit boyutlu header dizisi tanımlıdır.
    • c_length constraint'i length'i 4–16 arasına sınırlar ve payload.size() == length ile dizinin uzunluğunu bu rastgele değere eşitler.
    • c_payload içindeki foreach (payload[i]) her elemanı [8'h01:8'hFE] aralığına koyar (0x00 ve 0xFF hariç) ve if (i > 0) koşuluyla payload[i] != payload[i-1] diyerek ardışık elemanların farklı olmasını sağlar.
    • c_header_ordered, header dizisini kesin artan yapar (header[i] > header[i-1]) ve header[0] >= 1 ile başlangıcı sabitler.
  • UniqueArray sınıfında data sekiz elemanlı bir dizidir. c_unique constraint'i unique {data} ile tüm elemanları benzersiz kılar ve foreach ile her elemanı [1:100] aralığına yerleştirir.
  • Matrix sınıfında grid, 4×4'lük iki boyutlu bir dizidir.
    • c_row_sum, her satır için grid[i].sum() with (int'(item)) < 20 der; int'(item) cast'i toplama sırasında taşmayı önler.
    • c_diagonal, grid[i][i] > 0 ile köşegen elemanlarının sıfır olmamasını garanti eder.
  • module içinde ArrayPacket, UniqueArray ve Matrix nesneleri ayrı ayrı randomize() edilip assert(...) else $fatal(...) ile doğrulanır ve display() ile yazdırılır.

Önemli Noktalar

  • foreach constraint'i her indeks için ayrı bir kural üretir. İndeks değişkeni (i) yalnızca constraint bağlamında geçerlidir ve komşu elemanlara (i-1) erişerek ilişkiler kurmanızı sağlar.
  • Dinamik dizilerde önce boyutu kısıtlayın. payload.size() == length gibi bir kural olmadan çözücü dizi boyutunu serbestçe seçer; eleman kısıtlamalarının anlamlı olması için boyutun belirlenmesi önemlidir.
  • sum() taşmasına dikkat edin. Dar bitli dizilerde sum() with (int'(item)) kullanmazsanız toplam, eleman genişliğinde hesaplanır ve beklenmedik şekilde taşar — kod yorumlarında da bu özellikle vurgulanmıştır.
  • unique, çözücü için maliyetli olabilir. Büyük dizilerde veya dar değer aralıklarında benzersizlik sağlamak çözüm uzayını daraltır; aralığın eleman sayısından yeterince geniş olduğundan emin olun (örneğin 8 eleman için [1:100]).
  • Kesin artan (>) gibi sıkı sıralama kısıtlamalarında, değer aralığının eleman sayısını karşılayacak kadar geniş olması gerekir; aksi halde randomize başarısız olur.