EDA Playground'da Dene

String İşlemleri

Gün 1: SystemVerilog'a Giriş ve Veri Tipleri | String manipülasyonları ve dönüşüm metodları

⭐⭐Repo Önerisi: ClueLogic'in geliştirmiş olduğu generic bir SystemVerilog kütüphanesi var. Bu kütüphanede string işlemleriyle ilgili çok güzel fonksiyonlar mevcut.

İncelemek isterseniz: ClueLib

Bu derste SystemVerilog'un yerleşik string tipini ve onun zengin metodlarını öğreneceğiz: birleştirme, uzunluk, karşılaştırma, karakter erişimi, alt string, harf dönüşümü ve sayı çevrimleri.

SystemVerilog string Tipi

Verilog'da metinler ham bit vektörlerinde saklanırken, SystemVerilog ayrı bir string tipi sunar. Bu tip dinamik uzunluktadır (boyut yönetimi otomatiktir) ve yazılım dillerine benzer pratik metodlar içerir. Doğrulama dünyasında log mesajları, paket isimleri ve rapor üretimi için sürekli kullanılır.

Temel İşlemler ve Metodlar

  • Birleştirme (concatenation): {str1, " ", str2} sözdizimiyle stringler birleştirilir.
  • Uzunluk: .len() karakter sayısını verir.
  • Karşılaştırma: == doğrudan eşitlik; .icompare() büyük/küçük harf duyarsız karşılaştırma yapar (0 ise eşit).
  • Karakter erişimi: .getc(i) i'inci karakterin ASCII kodunu okur, .putc(i, c) o konumdaki karakteri değiştirir.
  • Alt string: .substr(a, b) a ile b indeksleri arasındaki (her ikisi dahil) parçayı verir.
  • Harf dönüşümü: .toupper() ve .tolower().

Sayı Dönüşümleri ve Formatlama

String ↔ sayı çevrimi doğrulamada sık gerekir:

  • String'den sayıya: .atoi() (decimal), .atohex() (hex), .atobin() (binary), .atooct() (octal)
  • Sayıdan string'e: .itoa(val), .hextoa(val)
  • Formatlı string: $sformatf(...), tıpkı $display gibi biçim belirteçleri kullanır ama sonucu ekrana basmak yerine bir string olarak döndürür.

Kaynak Kod

// =============================================================================
// GUN 1 - Konu 7: String Manipulasyonlari
// =============================================================================

module string_manipulasyonlari;

  string str1, str2, str3;
  string str_arr [$];

  initial begin
    $display("=== SystemVerilog String Islemleri ===\n");

    // --- Temel Atama ve Birlestirme ---
    $display("--- Temel Islemler ---");
    str1 = "Merhaba";
    str2 = "SystemVerilog";
    str3 = {str1, " ", str2, "!"};  // Birlestirme (concatenation)
    $display("  str1 = %s", str1);
    $display("  str2 = %s", str2);
    $display("  Birlesik = %s", str3);

    // --- Uzunluk ---
    $display("\n--- String Uzunlugu ---");
    $display("  \"%s\" uzunluk = %0d", str3, str3.len());

    // --- Karsilastirma ---
    $display("\n--- Karsilastirma ---");
    str1 = "ABC";
    str2 = "abc";
    $display("  \"%s\" == \"%s\" -> %0b", str1, str2, (str1 == str2));
    $display("  icompare (buyuk/kucuk harf duyarsiz) -> %0d", str1.icompare(str2));
    // icompare: 0 ise esit, negatifse str1 < str2

    // --- Alt String ve Karakter Erisimi ---
    $display("\n--- Karakter Erisimi ---");
    str1 = "SystemVerilog";
    $display("  String = %s", str1);
    $display("  str[0] = %c (ASCII: %0d)", str1.getc(0), str1.getc(0));
    $display("  str[6] = %c", str1.getc(6));
    
    // Karakter degistirme
    str1.putc(0, "s");  // S -> s
    $display("  putc(0,'s') -> %s", str1);

    // --- Substring ---
    $display("\n--- Alt String (substr) ---");
    str1 = "Dogrulama_Muhendisi";
    str2 = str1.substr(0, 8);   // 0'dan 8'e kadar (dahil)
    $display("  \"%s\".substr(0,8) = \"%s\"", str1, str2);

    // --- Buyuk/Kucuk Harf ---
    $display("\n--- Harf Donusumu ---");
    str1 = "Hello World";
    $display("  toupper = %s", str1.toupper());
    $display("  tolower = %s", str1.tolower());

    // --- Sayi Donusumleri ---
    $display("\n--- String <-> Sayi Donusumu ---");
    str1 = "255";
    $display("  \"%s\".atoi()  = %0d (decimal)", str1, str1.atoi());
    
    str1 = "FF";
    $display("  \"%s\".atohex() = %0d (hex -> decimal)", str1, str1.atohex());

    str1 = "11111111";
    $display("  \"%s\".atobin() = %0d (bin -> decimal)", str1, str1.atobin());

    str1 = "377";
    $display("  \"%s\".atooct() = %0d (oct -> decimal)", str1, str1.atooct());

    // Sayidan stringe
    begin
      int val = 42;
      str1.itoa(val);
      $display("  itoa(%0d)  = \"%s\"", val, str1);
      str2.hextoa(val);
      $display("  hextoa(%0d) = \"%s\"", val, str2);
    end

    // --- Formatli String ---
    $display("\n--- $sformatf (Formatli String) ---");
    begin
      int addr = 'hABCD;
      int data = 'hDEAD;
      string msg;
      msg = $sformatf("Adres: 0x%04h, Veri: 0x%04h, Zaman: %0t", addr, data, $time);
      $display("  %s", msg);
    end

    // --- String Kuyruk ---
    $display("\n--- String Kuyruk ---");
    str_arr = '{"Generator", "Driver", "Monitor", "Scoreboard"};
    $display("  Testbench Bilesenleri:");
    foreach (str_arr[i])
      $display("    [%0d] %s", i, str_arr[i]);

    $display("\n=== String Islemleri Sonu ===");
    $finish;
  end

endmodule

Kodun Açıklaması

  • str3 = {str1, " ", str2, "!"}; birleştirme işlemini gösterir; "Merhaba", boşluk, "SystemVerilog" ve "!" tek bir string'e birleştirilir.
  • str3.len() birleşik string'in karakter sayısını döndürür.
  • Karşılaştırma bölümünde str1 = "ABC", str2 = "abc" için (str1 == str2) farklı oldukları için 0 verir; str1.icompare(str2) ise büyük/küçük harf duyarsız olduğundan 0 (eşit) döndürür.
  • str1.getc(0) ilk karakterin ASCII kodunu verir; %c ile karakter, %0d ile sayısal kodu basılır. str1.putc(0, "s"); ilk karakteri (S) küçük s ile değiştirir.
  • str1.substr(0, 8) "Dogrulama_Muhendisi" içinden 0–8 indeksleri arasını ("Dogrulama") çıkarır; her iki uç da dahildir.
  • str1.toupper() ve str1.tolower() orijinal string'i değiştirmeden büyük/küçük harfe çevrilmiş bir kopya döndürür.
  • Sayı dönüşümleri: "255".atoi() → 255, "FF".atohex() → 255, "11111111".atobin() → 255, "377".atooct() → 255. Dört farklı tabandaki gösterimin aynı değere karşılık gelmesi öğreticidir.
  • str1.itoa(val) 42 sayısını "42" string'ine; str2.hextoa(val) ise onaltılık gösterimine çevirir. Bu metodlar sonucu çağrıldıkları string değişkenine yazar.
  • $sformatf("Adres: 0x%04h, ...", addr, data, $time) biçimli bir metni msg değişkenine üretir; $display gibi formatlar ama ekrana basmaz.
  • Sonda str_arr string kuyruğu '{"Generator", "Driver", "Monitor", "Scoreboard"} ile doldurulup foreach ile listelenir.

Önemli Noktalar

  • string tipi dinamik uzunluktadır; Verilog'daki gibi sabit bit vektörü genişliği ayırmanıza gerek yoktur.
  • == büyük/küçük harf duyarlıdır; harf durumunu yok saymak istiyorsanız .icompare() kullanın (0 eşitliği gösterir).
  • getc/putc indeksleri 0 tabanlıdır; sınır dışı erişimden kaçının. substr(a, b) aralığında hem a hem b dahildir.
  • .toupper()/.tolower() yeni bir string döndürür, orijinali değiştirmez; oysa .putc(), .itoa(), .hextoa() çağrıldıkları değişkeni yerinde günceller.
  • atoi/atohex/atobin/atooct taban seçimini siz yaparsınız; girdinin tabanına uygun metodu seçmek doğru sonucu garanti eder.
  • Log ve rapor üretiminde $display yerine $sformatf ile string oluşturup saklamak, mesajları yeniden kullanmayı ve scoreboard'a iletmeyi kolaylaştırır.
  • str1.getc(i) bir byte döndürür; bu yüzden %c ile karakter, %0d ile ASCII kodu basabilirsiniz. Tek bir karakteri string'e çevirmek için string'(str1.getc(i)) ya da $sformatf("%c", ...) kullanın.
  • substr(a, b) çağrısında b < a ise ya da indeksler sınır dışıysa boş string döner, hata vermez. Bu sessiz davranış, ayrıştırma (parsing) kodunda beklenmedik boş sonuçlara yol açabilir; len() ile sınır kontrolü yapın.

String Metodları Özet Tablosu

Metod Açıklama Örnek Sonuç
len() Karakter sayısı "abc".len() 3
getc(i) i. karakterin ASCII kodu "abc".getc(1) 98 (b)
putc(i, c) i. karakteri değiştirir (yerinde) s.putc(0, "X") "Xbc"
substr(a, b) a..b arası (dahil) "SystemVerilog".substr(6, 12) "Verilog"
toupper() / tolower() Harf dönüşümü (kopya döndürür) "Abc".toupper() "ABC"
compare(s) / icompare(s) Duyarlı / duyarsız karşılaştırma "abc".icompare("ABC") 0 (eşit)
atoi() / atohex() / atobin() / atooct() Metinden sayıya "FF".atohex() 255
atoreal() Metinden gerçek sayıya "3.14".atoreal() 3.14
itoa(v) / hextoa(v) / bintoa(v) / octtoa(v) / realtoa(r) Sayıdan metne (yerinde yazar) s.hextoa(255) "ff"
{a, b} Birleştirme {"a", "b"} "ab"
==, !=, <, > Karşılaştırma operatörleri "abc" < "abd" 1
$sformatf(fmt, ...) Biçimli string üretir $sformatf("%0d", 42) "42"

Doğrulamada String Nerede Karşımıza Çıkar?

  • Bileşen isimleri ve log etiketleri: UVM'de her bileşenin bir string name vardır ve get_full_name() hiyerarşik yolu string olarak döndürür.
  • Komut satırı argümanları: $value$plusargs("TEST=%s", test_name) ile test adı string olarak alınır (Gün 7'de göreceksiniz).
  • Enum ↔ string dönüşümü: op.name() ile enum değerini metne çevirip raporlarda kullanırız.
  • Dosya okuma / yazma: $fgets, $sscanf ile dosyadan satır okuyup ayrıştırmak (örneğin beklenen değerler dosyası) tamamen string işlemidir.

Sık Yapılan Hatalar

  • toupper() sonucunu kullanmamak: str1.toupper(); tek başına yazılırsa orijinal değişmez; sonuç yeni bir string'tir. str1 = str1.toupper(); yazın.
  • atoi()'ye hex metin vermek: "FF".atoi() → 0 döner (sayı olmayan ilk karakterde durur). Tabana uygun metodu seçin.
  • Sayıyı %s ile basmak: $display("%s", 42) anlamsız karakter üretir. Önce $sformatf ile biçimlendirin ya da doğru belirteci kullanın.
  • Sınır dışı getc/putc: str.getc(str.len()) son karakterden bir sonrasıdır; 0 döndürür. putc sınır dışına yazmak ise hiçbir etki yapmaz.

Kendinizi Deneyin

  1. "192.168.1.10" string'ini noktalardan ayırıp dört sayıyı int olarak elde eden bir döngü yazın (ipucu: getc ile "." karakterini arayıp substr + atoi kullanın).
  2. "deadbeef".atohex() sonucunu %h ile yazdırın. Ardından aynı değeri hextoa ile geri string'e çevirin; büyük/küçük harf ne oldu?
  3. Bir string kuyruğundaki tüm isimleri {prefix, "_", name} biçiminde birleştirip yeni bir kuyruk üretin.
  4. $sformatf("%-10s|", "ab") ve $sformatf("%10s|", "ab") çıktılarını karşılaştırın; - işaretinin hizalamaya etkisini not edin.
Hızlı Kontrol: str.icompare(other) hangi değeri döndürdüğünde string'ler eşittir?

0 döndürdüğünde eşittir. Negatif değer str'nin sözlük sırasında daha önce, pozitif değer daha sonra geldiğini gösterir. == operatörü ise büyük/küçük harfe duyarlıdır; harf durumunu yok saymak için icompare gerekir.