EDA Playground'da Dene

Lab 3: Generator Sınıfı

Gün 3: Rastgele Üretim ve Kısıtlamalar | Senaryoya uygun rastgele veri üreten Generator tasarımı

Bu lab çalışmasında, Gün 3 boyunca öğrendiğimiz tüm constrained-random tekniklerini tek bir uygulamada birleştiriyoruz: kısıtlamalı bir transaction sınıfı ve onu farklı senaryolarda sürebilen bir Generator sınıfı tasarlayacağız. Bu yapı, gerçek doğrulama ortamlarının (testbench) çekirdeğini oluşturur.

Generator Deseni

Bir Generator (üretici), test sırasında tasarıma uygulanacak rastgele transaction'ları üreten bileşendir. Tipik olarak:

  • İçinde bir veya daha fazla transaction nesnesi tutar.
  • Belirli sayıda transaction'ı, belirli bir senaryoya göre rastgeleleştirir.
  • Senaryolar arasında geçiş yaparken constraint_mode() ve satır içi with kısıtlamalarını kullanır.

Bu derste birleştirdiğimiz kavramlar:

  • rand / randc değişkenler ve enum tipleri.
  • dist ile gerçekçi komut ve hata dağılımları.
  • implication (->) ile komut tipine bağlı kurallar.
  • constraint_mode() ile senaryoya özel kısıtlama açma/kapatma.
  • post_randomize() ile türetilmiş alan hesaplama ve hata enjeksiyonu.

Senaryo Tabanlı Doğrulama

Aynı transaction sınıfını birden çok senaryoda yeniden kullanmak, doğrulama ortamlarında temel bir verimlilik kaynağıdır. Generator, her senaryo için ayrı bir task tanımlayarak (normal trafik, sadece okuma, yüksek adres, hata enjeksiyonu) tek bir veri modelinden çok çeşitli test durumları üretir.

Kaynak Kod

// =============================================================================
// GUN 3 - Lab 3: Generator Sinifi - Senaryoya Uygun Rastgele Veri Uretimi
// =============================================================================

class BusTransaction;
  typedef enum logic [1:0] {READ=0, WRITE=1, BURST_READ=2, BURST_WRITE=3} cmd_e;
  typedef enum {VALID, ADDR_ERROR, DATA_ERROR, PROTOCOL_ERROR} status_e;

  rand cmd_e         command;
  rand logic [31:0]  address;
  rand logic [31:0]  data;
  rand int unsigned  burst_length;
  rand bit [3:0]     byte_strobe;
  rand bit [2:0]     id;
  rand status_e      status;
  
  bit [31:0] crc;
  int txn_id;
  static int count = 0;

  // --- Temel kisitlamalar ---
  constraint c_base {
    burst_length inside {[1:16]};
    (command inside {READ, WRITE}) -> burst_length == 1;
    (command inside {BURST_READ, BURST_WRITE}) -> burst_length inside {[2:16]};
  }

  // --- Gecerli paket ---
  constraint c_valid {
    status == VALID;
    address[1:0] == 2'b00;  // 4-byte hizali
    byte_strobe != 0;
  }

  // --- Adres araliklari ---
  constraint c_addr_region_A {
    address inside {[32'h0000_0000:32'h0000_FFFF]};
  }
  constraint c_addr_region_B {
    address inside {[32'h1000_0000:32'h1000_FFFF]};
  }
  constraint c_addr_region_C {
    address inside {[32'hFFFF_0000:32'hFFFF_FFFF]};
  }

  // --- Komut dagilimi ---
  constraint c_cmd_dist {
    command dist { READ := 30, WRITE := 30, BURST_READ := 20, BURST_WRITE := 20 };
  }

  // --- Hata enjeksiyonu ---
  constraint c_inject_error {
    status dist { VALID := 80, ADDR_ERROR := 10, DATA_ERROR := 5, PROTOCOL_ERROR := 5 };
  }

  function new();
    txn_id = count++;
    c_addr_region_B.constraint_mode(0);
    c_addr_region_C.constraint_mode(0);
    c_inject_error.constraint_mode(0);
  endfunction

  function void post_randomize();
    crc = address ^ data ^ {29'h0, command};
    if (status == ADDR_ERROR)
      address[1:0] = 2'b11;  // Hizalamayi boz
    else if (status == DATA_ERROR)
      data = ~data;
  endfunction

  function void display();
    $display("  TXN#%03d | %-11s | Addr=0x%08h | Data=0x%08h | Burst=%2d | BE=%04b | ID=%0d | %s",
             txn_id, command.name(), address, data, burst_length, 
             byte_strobe, id, status.name());
  endfunction
endclass

class Generator;
  BusTransaction txn;
  int num_transactions;
  string scenario_name;

  function new(int num = 10);
    this.num_transactions = num;
    this.txn = new();
  endfunction

  // Senaryo 1: Normal trafik
  task run_normal_traffic();
    scenario_name = "Normal Trafik";
    $display("\n=== Senaryo: %s (%0d txn) ===", scenario_name, num_transactions);
    repeat (num_transactions) begin
      assert(txn.randomize()) else $fatal(1, "Randomize hata!");
      txn.display();
    end
  endtask

  // Senaryo 2: Sadece okuma
  task run_read_only();
    scenario_name = "Sadece Okuma";
    $display("\n=== Senaryo: %s ===", scenario_name);
    repeat (num_transactions) begin
      assert(txn.randomize() with { command inside {BusTransaction::READ, BusTransaction::BURST_READ}; })
        else $fatal(1, "Randomize hata!");
      txn.display();
    end
  endtask

  // Senaryo 3: Yuksek adres bolgesi
  task run_high_address();
    scenario_name = "Yuksek Adres Bolgesi";
    $display("\n=== Senaryo: %s ===", scenario_name);
    txn.c_addr_region_A.constraint_mode(0);
    txn.c_addr_region_C.constraint_mode(1);
    repeat (num_transactions) begin
      assert(txn.randomize()) else $fatal(1, "Randomize hata!");
      txn.display();
    end
    txn.c_addr_region_A.constraint_mode(1);
    txn.c_addr_region_C.constraint_mode(0);
  endtask

  // Senaryo 4: Hata enjeksiyonu
  task run_error_injection();
    scenario_name = "Hata Enjeksiyonu";
    $display("\n=== Senaryo: %s ===", scenario_name);
    txn.c_valid.constraint_mode(0);
    txn.c_inject_error.constraint_mode(1);
    repeat (num_transactions) begin
      assert(txn.randomize()) else $fatal(1, "Randomize hata!");
      txn.display();
    end
    txn.c_valid.constraint_mode(1);
    txn.c_inject_error.constraint_mode(0);
  endtask
endclass

module lab3_generator;
  initial begin
    Generator gen;

    $display("============================================================");
    $display("  LAB 3: Generator Sinifi - Senaryolu Rastgele Uretim");
    $display("============================================================");

    gen = new(8);

    gen.run_normal_traffic();
    gen.run_read_only();
    gen.run_high_address();
    gen.run_error_injection();

    $display("\n============================================================");
    $display("  LAB 3 TAMAMLANDI");
    $display("============================================================");
    $finish;
  end
endmodule

Kodun Açıklaması

  • BusTransaction sınıfı iki enum kullanır: komut tipi için cmd_e (READ, WRITE, BURST_READ, BURST_WRITE) ve durum için status_e (VALID, ADDR_ERROR, DATA_ERROR, PROTOCOL_ERROR). Rastgele alanlar arasında command, address, data, burst_length, byte_strobe, id ve status yer alır.
  • Kısıtlamalar:
    • c_base, burst_length'i 1–16 arasına koyar ve implication ile tekil komutlarda (READ, WRITE) uzunluğu 1'e, burst komutlarında 2–16 arasına zorlar.
    • c_valid, geçerli paketler için status == VALID, 4-byte hizalı adres (address[1:0] == 2'b00) ve byte_strobe != 0 kurar.
    • c_addr_region_A/B/C, üç farklı adres bölgesi tanımlar; bunlar constraint_mode() ile teker teker açılıp kapatılacak şekilde kurgulanmıştır.
    • c_cmd_dist ve c_inject_error, sırasıyla komut ve hata durumu için dist ile olasılık dağılımları tanımlar.
  • new() kurucusu txn_id atar ve çakışmayı önlemek için c_addr_region_B, c_addr_region_C ile c_inject_error'ı baştan kapatır — yani varsayılan davranış: A bölgesi, geçerli paketler.
  • post_randomize(), türetilmiş crc alanını hesaplar ve hata durumlarına göre değer bozar: ADDR_ERROR'da adres hizasını bozar (address[1:0] = 2'b11), DATA_ERROR'da veriyi tersler (data = ~data). Bu, hatanın rastgeleleştirme sonrası enjekte edilmesinin örneğidir.
  • Generator sınıfı içinde bir BusTransaction nesnesi (txn) ve dört senaryo task'ı bulunur:
    • run_normal_traffic() varsayılan kısıtlamalarla normal trafik üretir.
    • run_read_only(), satır içi with { command inside {BusTransaction::READ, BusTransaction::BURST_READ}; } ile yalnızca okuma komutları üretir.
    • run_high_address(), c_addr_region_A'yı kapatıp c_addr_region_C'yi açar, senaryo bitince eski duruma döndürür.
    • run_error_injection(), c_valid'i kapatıp c_inject_error'ı açarak dağılımlı hata durumları üretir, sonra geri alır.
  • module içinde Generator 8 transaction ile oluşturulur ve dört senaryo sırayla çalıştırılır.

Önemli Noktalar

  • Senaryo task'ları durumu geri yükler. run_high_address() ve run_error_injection(), değiştirdikleri constraint modlarını sonunda eski haline getirir; bu, senaryoların birbirini etkilememesi için kritik bir pratiktir.
  • Enum değerlerine sınıf dışından erişirken kapsam belirtin. Satır içi kısıtlamada BusTransaction::READ gibi sinif::deger biçimi kullanılır.
  • Hata enjeksiyonunu post_randomize() içinde yapmak güçlüdür. Kısıtlamalarla geçerli bir paket üretip ardından bilinçli olarak bozmak, hem geçerli hem hatalı senaryoları tek modelden türetmeyi sağlar.
  • Çakışan adres bölgesi kısıtlamalarını aynı anda açmayın. A, B, C bölgeleri ayrık aralıklardır; aynı anda birden fazlası açıkken randomize() çözümsüz kalır.
  • dist ağırlıkları gerçekçi trafik modellemek içindir. c_cmd_dist ve c_inject_error ile üretilen dağılım, gerçek sistem davranışına yakın test senaryoları üretmenizi sağlar; istatistiksel anlamlılık için yeterli sayıda transaction üretin.
  • Bu Generator deseni, ileride UVM sequence/sequencer yapılarına geçişin temelini oluşturur; mantık aynıdır, yalnızca altyapı standartlaşır.