Lab 2: Hiyerarşik Transaction
Gün 2: Nesne Yönelimli Programlama (OOP) | Transaction modeli, kalıtım ve hata enjeksiyonu
Bu lab, Gün 2 boyunca öğrendiğimiz tüm OOP kavramlarını (sınıf, kalıtım, polimorfizm, virtual metodlar, $cast) tek bir uygulamada bir araya getirir. Hiyerarşik bir Transaction modeli kurup polimorfik bir kuyruk üzerinde işlemleri yönetecek ve hata enjeksiyonu yapacağız.
Lab'da Neler Yapılıyor?
Gerçek doğrulama ortamlarında işlemler (transaction) tek tip değildir: okuma, yazma ve hatalı işlemler bir arada akar. Bu lab, ortak bir temel sınıftan türeyen özelleşmiş işlem türlerini tek bir polimorfik kuyrukta yönetmenin pratik bir örneğidir.
- Hiyerarşi: Temel
TransactionsınıfındanReadTransactionveWriteTransactiontüretilir;WriteTransaction'dan da hata enjeksiyonu yapanErrorTransactiontüretilir. - Polimorfik kuyruk: Farklı tipteki nesneler tek bir
Transactionkuyruğunda (txn_queue) tutulur vevirtualmetodlar sayesinde her biri kendi davranışını sergiler. - Hata enjeksiyonu:
ErrorTransaction, birenumile seçilen moda göre adres ve/veya veriyi kasıtlı olarak bozar; bu, DUT'un hatalı senaryolara tepkisini test etmek için kullanılır. $castile tür tespiti: Kuyruktaki her eleman çalışma zamanında$castile sınıflandırılıp ilgili işleme tabi tutulur.
Kaynak Kod
// =============================================================================
// GUN 2 - Lab 2: Hiyerarsik Transaction Modeli ve Hata Enjeksiyonu
// =============================================================================
// Bu lab'da:
// - Temel Transaction sinifi olusturulacak
// - Kalitim ile ReadTxn, WriteTxn alt siniflari turetilecek
// - Hata enjeksiyonu yapan ErrorTxn sinifi eklenecek
// - Polimorfizm ile heterojen kuyruk islenecek
// =============================================================================
// --- Temel Islem Sinifi ---
class Transaction;
static int global_id = 0;
int id;
logic [31:0] address;
logic [31:0] data;
bit valid;
int timestamp;
function new(logic [31:0] addr = 0, logic [31:0] data = 0);
this.id = global_id++;
this.address = addr;
this.data = data;
this.valid = 1;
this.timestamp = $time;
endfunction
virtual function string get_type();
return "BASE";
endfunction
virtual function void display();
$display(" [%5s] ID=%0d | Addr=0x%08h | Data=0x%08h | V=%0b | T=%0t",
get_type(), id, address, data, valid, timestamp);
endfunction
virtual function Transaction copy();
Transaction t = new(this.address, this.data);
t.id = this.id;
t.valid = this.valid;
return t;
endfunction
virtual function bit compare(Transaction other);
return (this.address == other.address && this.data == other.data);
endfunction
endclass
// --- Okuma Islemi ---
class ReadTransaction extends Transaction;
int burst_size;
logic [31:0] read_data [$];
function new(logic [31:0] addr, int burst = 1);
super.new(addr, 0);
this.burst_size = burst;
endfunction
virtual function string get_type();
return "READ";
endfunction
task execute();
$display(" >>> READ baslatildi: Addr=0x%08h, Burst=%0d", address, burst_size);
for (int i = 0; i < burst_size; i++) begin
#5;
read_data.push_back($urandom);
end
$display(" <<< READ tamamlandi: %0d veri okundu", read_data.size());
endtask
virtual function void display();
super.display();
$display(" Burst=%0d, Okunan=%0d adet", burst_size, read_data.size());
endfunction
endclass
// --- Yazma Islemi ---
class WriteTransaction extends Transaction;
logic [3:0] byte_enable;
logic [31:0] write_data [$];
function new(logic [31:0] addr, logic [31:0] data, logic [3:0] be = 4'hF);
super.new(addr, data);
this.byte_enable = be;
write_data.push_back(data);
endfunction
virtual function string get_type();
return "WRITE";
endfunction
function void add_data(logic [31:0] d);
write_data.push_back(d);
endfunction
virtual function void display();
super.display();
$display(" BE=0x%01h, WData=%p", byte_enable, write_data);
endfunction
endclass
// --- Hata Enjeksiyonu Sinifi ---
class ErrorTransaction extends WriteTransaction;
typedef enum {NO_ERROR, ADDR_CORRUPT, DATA_CORRUPT, BOTH_CORRUPT} error_type_e;
error_type_e error_mode;
function new(logic [31:0] addr, logic [31:0] data, error_type_e err = NO_ERROR);
super.new(addr, data);
this.error_mode = err;
endfunction
virtual function string get_type();
return "ERROR";
endfunction
function void inject_error();
case (error_mode)
ADDR_CORRUPT: begin
address ^= 32'hFFFF_0000;
$display(" [!] HATA ENJEKSIYONU: Adres bozuldu -> 0x%08h", address);
end
DATA_CORRUPT: begin
data ^= 32'h0000_FFFF;
$display(" [!] HATA ENJEKSIYONU: Veri bozuldu -> 0x%08h", data);
end
BOTH_CORRUPT: begin
address ^= 32'hFFFF_0000;
data ^= 32'h0000_FFFF;
$display(" [!] HATA ENJEKSIYONU: Her ikisi de bozuldu");
end
default: $display(" [OK] Hata yok");
endcase
valid = (error_mode == NO_ERROR);
endfunction
virtual function void display();
super.display();
$display(" Hata Modu: %s", error_mode.name());
endfunction
endclass
// =============================================================================
module lab2_hiyerarsik_transaction;
initial begin
Transaction txn_queue [$]; // Polimorfik kuyruk
$display("============================================================");
$display(" LAB 2: Hiyerarsik Transaction Modeli");
$display("============================================================\n");
// --- 1. Cesitli islemler olustur ---
$display("--- 1. Islem Olusturma ---");
begin
ReadTransaction r1, r2;
WriteTransaction w1, w2;
ErrorTransaction e1, e2, e3;
r1 = new(32'hA000_0000, 4);
r2 = new(32'hA000_0100, 1);
w1 = new(32'hB000_0000, 32'hDEAD_BEEF);
w2 = new(32'hB000_0004, 32'hCAFE_BABE, 4'h3);
e1 = new(32'hC000_0000, 32'h1234_5678, ErrorTransaction::ADDR_CORRUPT);
e2 = new(32'hC000_0004, 32'hABCD_EF01, ErrorTransaction::DATA_CORRUPT);
e3 = new(32'hC000_0008, 32'h9999_9999, ErrorTransaction::BOTH_CORRUPT);
// Polimorfik kuyruga ekle
txn_queue = {r1, r2, w1, w2, e1, e2, e3};
end
// --- 2. Tum islemleri goster ---
$display("\n--- 2. Tum Islemler (Polimorfik display) ---");
foreach (txn_queue[i]) begin
txn_queue[i].display();
$display();
end
// --- 3. Hata enjeksiyonu ---
$display("--- 3. Hata Enjeksiyonu ---");
foreach (txn_queue[i]) begin
ErrorTransaction et;
if ($cast(et, txn_queue[i])) begin
et.inject_error();
et.display();
$display();
end
end
// --- 4. Istatistikler ---
$display("--- 4. Istatistikler ---");
begin
int read_count = 0, write_count = 0, error_count = 0, valid_count = 0;
foreach (txn_queue[i]) begin
ReadTransaction rt;
WriteTransaction wt;
ErrorTransaction et;
if ($cast(et, txn_queue[i])) error_count++;
else if ($cast(rt, txn_queue[i])) read_count++;
else if ($cast(wt, txn_queue[i])) write_count++;
if (txn_queue[i].valid) valid_count++;
end
$display(" Toplam = %0d", txn_queue.size());
$display(" READ = %0d", read_count);
$display(" WRITE = %0d", write_count);
$display(" ERROR = %0d", error_count);
$display(" Gecerli = %0d", valid_count);
$display(" Gecersiz = %0d", txn_queue.size() - valid_count);
end
$display("\n============================================================");
$display(" LAB 2 TAMAMLANDI");
$display("============================================================");
$finish;
end
endmodule
Kodun Açıklaması
- Temel
Transactionsınıfı:id,address,data,valid,timestampalanlarını vestatic int global_idsayacını içerir. Constructor'dathis.id = global_id++ile her işleme benzersiz bir kimlik verilir,this.timestamp = $timeile oluşturulma anı kaydedilir.get_type(),display(),copy()vecompare()metodlarıvirtual'dır. ReadTransaction:burst_sizeveread_datakuyruğunu ekler.super.new(addr, 0)ile temeli kurar.execute()birtask'tır;#5gecikmelerleburst_sizekadar$urandomverisiniread_data'ya doldurur (zaman tüketen davranış).WriteTransaction:byte_enablevewrite_datakuyruğunu ekler; constructor'da gelen veriyiwrite_data'ya koyar.add_data()ile ek veri eklenebilir.get_type()"WRITE"döndürür.ErrorTransaction extends WriteTransaction: İki seviyeli kalıtım örneğidir. Sınıf içindeerror_type_eadlıenum(NO_ERROR,ADDR_CORRUPT,DATA_CORRUPT,BOTH_CORRUPT) tanımlanır.inject_error()metodu,error_mode'a göreaddressve/veyadata'yı XOR ile bozar vevalidbayrağını günceller (valid = (error_mode == NO_ERROR)).- Polimorfik
display(): Her sınıfdisplay()'ivirtualolarak override eder vesuper.display()ile temel çıktıyı koruyup üzerine kendi bilgisini ekler. Kuyruktakitxn_queue[i].display()çağrısı her elemanın gerçek tipine göre çözülür. - Polimorfik kuyruk kurulumu:
r1, r2, w1, w2, e1, e2, e3nesneleri oluşturuluptxn_queue = {r1, r2, w1, w2, e1, e2, e3};ile tek birTransactionkuyruğunda toplanır (upcasting). $castile hata enjeksiyonu: 3. adımda her eleman için$cast(et, txn_queue[i])denenir; yalnızcaErrorTransactionolanlar başarıyla dönüşür veinject_error()çağrılır.- İstatistikler: 4. adımda
$castsıralı kontrollerle her elemanın tipi tespit edilir. Önemli sıralama:ErrorTransactionbirWriteTransactionolduğundan,etkontrolüwtkontrolünden önce yapılır; aksi halde hatalı işlemler yazma olarak sayılırdı.validbayrağına göre geçerli/geçersiz sayımı da yapılır.
Önemli Noktalar
- Polimorfik bir kuyruk (
Transaction txn_queue[$]) farklı alt tipleri tek tip kodla işlemeyi sağlar; bu, ölçeklenebilir doğrulama ortamlarının temel kalıbıdır. $castile tür kontrolü yaparken sıralama kritiktir: en özelleşmiş (en alttaki) tipten en genele doğru kontrol edin.ErrorTransaction,WriteTransaction'dan türediği için önce ona bakılmalıdır.virtualmetodlar olmadan polimorfik kuyruktakidisplay()çağrıları temel sınıf sürümünü çalıştırırdı; doğru davranış için metodlarvirtualolmalıdır.static global_idsayacı tüm işlemler arasında paylaşıldığından, hangi alt sınıftan üretilirse üretilsin her nesne benzersiz biridalır.- Hata enjeksiyonu (
inject_error) gerçek doğrulamada DUT'un hatalı/bozuk işlemlere dayanıklılığını sınamak için kullanılır;validbayrağı sonrasında beklenen sonucu belirlemeye yardımcı olur. execute()birtaskolduğundan zaman tüketir; zamanlamaya duyarlı senaryolardafunctionyerinetaskkullanılması gerektiğini hatırlatır.