🚀 Giriş#
Bu sayfada UVM TLM’de Blocking ve Non-blocking put/get portlarının kullanımı ile port-export-imp topolojisi anlatılmaktadır. Ayrıca, her port tipi için gönderici (driver) ve alıcı (monitor) taraflarının hangi metodları implemente etmesi gerektiğine de değinilecektir.
1️⃣ Blocking Put Kullanımı#
📌 Açıklama#
- Blocking put port, veriyi gönderirken gönderici tarafı bloke eder ve alıcı tarafından işlem tamamlanana kadar bekler.
- put() metodu, sender tarafından çağrılır ve receiver tarafından implement edilir.
📌 Gönderici#
uvm_blocking_put_port
kullanır.- put() metodunu çağırır.
📌 Alıcı#
uvm_blocking_put_imp
kullanır.- put() metodunu implement eder.
📦 Örnek#
import uvm_pkg::*;
`include "uvm_macros.svh"
// Transaction Class
class my_transaction extends uvm_sequence_item;
rand int data;
`uvm_object_utils(my_transaction)
function new(string name = "my_transaction");
super.new(name);
endfunction
function string convert2string();
return $sformatf("data = %0d", data);
endfunction
endclass
// Driver
class my_driver extends uvm_driver #(my_transaction);
`uvm_component_utils(my_driver)
uvm_blocking_put_port #(my_transaction) put_port;
function new(string name, uvm_component parent);
super.new(name, parent);
put_port = new("put_port", this);
endfunction
task run_phase(uvm_phase phase);
my_transaction tr;
phase.raise_objection(this);
tr = my_transaction::type_id::create("tr");
assert(tr.randomize() with { data inside {[1:100]}; });
`uvm_info("DRV", $sformatf("Sending: %s", tr.convert2string()), UVM_LOW)
put_port.put(tr);
phase.drop_objection(this);
endtask
endclass
// Monitor
class my_monitor extends uvm_component;
`uvm_component_utils(my_monitor)
uvm_blocking_put_imp #(my_transaction, my_monitor) put_imp;
function new(string name, uvm_component parent);
super.new(name, parent);
put_imp = new("put_imp", this);
endfunction
task put(my_transaction tr);
`uvm_info("MON", $sformatf("Received: %s", tr.convert2string()), UVM_LOW)
endtask
endclass
2️⃣ Non-blocking Put Kullanımı#
📌 Açıklama#
- Non-blocking put port, veriyi gönderirken receiver hazır olup olmadığını kontrol eder ve anında cevap döner.
- try_put() ve can_put() metodları kullanılır.
📌 Gönderici#
uvm_nonblocking_put_port
kullanır.- try_put() metodunu çağırır.
📌 Alıcı#
uvm_nonblocking_put_imp
kullanır.- try_put() ve can_put() metodlarını implement eder.
📦 Kod Örneği#
package my_pkg;
`include "uvm_macros.svh"
import uvm_pkg::*;
// Transaction sınıfı
class my_transaction extends uvm_sequence_item;
rand int data;
`uvm_object_utils(my_transaction) // type_id için gerekli
function new(string name = "my_transaction");
super.new(name);
endfunction
endclass
// Alıcı (Consumer)
class my_consumer extends uvm_component;
uvm_nonblocking_put_imp #(my_transaction, my_consumer) put_imp;
`uvm_component_utils(my_consumer)
function new(string name = "my_consumer", uvm_component parent = null);
super.new(name, parent);
put_imp = new("put_imp", this);
endfunction
// try_put() implementasyonu
function bit try_put(my_transaction tr); // 'from' parametresi eklendi
if (can_put()) begin
`uvm_info("CONSUMER", $sformatf("Received data: %0d", tr.data), UVM_LOW)
return 1; // Başarılı
end
return 0; // Başarısız
endfunction
// can_put() implementasyonu
function bit can_put();
return 1; // Her zaman hazır
endfunction
endclass
// Gönderici (Producer)
class my_producer extends uvm_component;
uvm_nonblocking_put_port #(my_transaction) put_port;
`uvm_component_utils(my_producer) // type_id için gerekli
function new(string name = "my_producer", uvm_component parent = null);
super.new(name, parent);
put_port = new("put_port", this);
endfunction
task send_data(int data);
my_transaction tr;
tr = my_transaction::type_id::create("tr"); // Doğru kullanım
tr.data = data;
if (put_port.try_put(tr)) begin
`uvm_info("PRODUCER", $sformatf("Sent data: %0d", data), UVM_LOW)
end else begin
`uvm_warning("PRODUCER", "Failed to send data")
end
endtask
endclass
// Testbench
class my_env extends uvm_env;
my_producer producer;
my_consumer consumer;
`uvm_component_utils(my_env) // type_id için gerekli
function new(string name = "my_env", uvm_component parent = null);
super.new(name, parent);
producer = my_producer::type_id::create("producer", this);
consumer = my_consumer::type_id::create("consumer", this);
producer.put_port.connect(consumer.put_imp);
endfunction
endclass
// Test
class my_test extends uvm_test;
my_env env;
`uvm_component_utils(my_test)
function new(string name = "my_test", uvm_component parent = null);
super.new(name, parent);
endfunction
function void build_phase(uvm_phase phase);
super.build_phase(phase);
env = my_env::type_id::create("env", this);
endfunction
task run_phase(uvm_phase phase);
phase.raise_objection(this);
#100;
env.producer.send_data(42);
#100;
phase.drop_objection(this);
endtask
endclass
endpackage
// Test çalıştırma
module top;
import uvm_pkg::*;
import my_pkg::*; // Paketi dahil et
initial begin
uvm_top.enable_print_topology = 1;
run_test("my_test");
end
endmodule
3️⃣ Blocking Get Kullanımı#
📌 Açıklama#
- Blocking get port, veri almak isteyen bileşen tarafından çağrılır ve sender tarafından implement edilir.
- get() metodu, receiver tarafından çağrılır ve sender tarafından implement edilir.
📌 Gönderici#
uvm_blocking_get_imp
kullanır.- get() metodunu implement eder.
📌 Alıcı#
uvm_blocking_get_port
kullanır.- get() metodunu çağırır.
📦 Kod Örneği#
package my_pkg;
`include "uvm_macros.svh"
import uvm_pkg::*;
// Transaction sınıfı
class my_transaction extends uvm_sequence_item;
rand int data;
`uvm_object_utils(my_transaction)
function new(string name = "my_transaction");
super.new(name);
endfunction
endclass
// Gönderici (Sender)
class my_sender extends uvm_component;
uvm_blocking_get_imp #(my_transaction, my_sender) get_imp;
`uvm_component_utils(my_sender)
function new(string name = "my_sender", uvm_component parent = null);
super.new(name, parent);
get_imp = new("get_imp", this);
endfunction
// get() implementasyonu
virtual task get(output my_transaction tr);
tr = my_transaction::type_id::create("tr");
assert(tr.randomize()) else `uvm_error("SENDER", "Failed to randomize transaction")
`uvm_info("SENDER", $sformatf("Sent data: %0d", tr.data), UVM_LOW)
endtask
endclass
// Alıcı (Receiver)
class my_receiver extends uvm_component;
uvm_blocking_get_port #(my_transaction) get_port;
`uvm_component_utils(my_receiver)
function new(string name = "my_receiver", uvm_component parent = null);
super.new(name, parent);
get_port = new("get_port", this);
endfunction
task receive_data();
my_transaction tr;
get_port.get(tr); // Blocking get çağrısı
`uvm_info("RECEIVER", $sformatf("Received data: %0d", tr.data), UVM_LOW)
endtask
endclass
// Testbench
class my_env extends uvm_env;
my_sender sender;
my_receiver receiver;
`uvm_component_utils(my_env)
function new(string name = "my_env", uvm_component parent = null);
super.new(name, parent);
sender = my_sender::type_id::create("sender", this);
receiver = my_receiver::type_id::create("receiver", this);
receiver.get_port.connect(sender.get_imp); // Portları bağla
endfunction
endclass
// Test
class my_test extends uvm_test;
my_env env;
`uvm_component_utils(my_test)
function new(string name = "my_test", uvm_component parent = null);
super.new(name, parent);
endfunction
function void build_phase(uvm_phase phase);
super.build_phase(phase);
env = my_env::type_id::create("env", this);
endfunction
task run_phase(uvm_phase phase);
phase.raise_objection(this);
#100; // Örnek veri alma
env.receiver.receive_data();
#100;
phase.drop_objection(this);
endtask
endclass
endpackage
// Test çalıştırma
module top;
import uvm_pkg::*;
import my_pkg::*;
initial begin
uvm_top.enable_print_topology = 1;
run_test("my_test");
end
endmodule
4️⃣ Non-blocking Get Kullanımı#
📌 Açıklama#
- Non-blocking get port, veri almak isteyen bileşen tarafından try_get() veya can_get() ile çağrılır.
- Sender, try_get() ve can_get() metodlarını implement eder.
📌 Gönderici#
uvm_nonblocking_get_imp
kullanır.- try_get() ve can_get() metodlarını implement eder.
📌 Alıcı#
uvm_nonblocking_get_port
kullanır.- try_get() veya can_get() metodlarını çağırır.
📦 Kod Örneği#
package my_pkg;
`include "uvm_macros.svh"
import uvm_pkg::*;
// Transaction sınıfı
class my_transaction extends uvm_sequence_item;
rand int data;
`uvm_object_utils(my_transaction)
function new(string name = "my_transaction");
super.new(name);
endfunction
endclass
// Gönderici (Sender)
class my_sender extends uvm_component;
uvm_nonblocking_get_imp #(my_transaction, my_sender) get_imp;
my_transaction available_tr; // Mevcut transaction
`uvm_component_utils(my_sender)
function new(string name = "my_sender", uvm_component parent = null);
super.new(name, parent);
get_imp = new("get_imp", this);
endfunction
// try_get() implementasyonu
// try_get() implementasyonu
function bit try_get(output my_transaction tr);
if (can_get()) begin
tr = available_tr;
available_tr = null; // Transaction'ı teslim ettik
`uvm_info("SENDER", $sformatf("Sent data: %0d", tr.data), UVM_LOW)
return 1; // Başarılı
end
return 0; // Başarısız
endfunction
// can_get() implementasyonu
function bit can_get();
return (available_tr != null); // Transaction mevcut mu?
endfunction
// Transaction hazırlama
task prepare_transaction();
available_tr = my_transaction::type_id::create("tr");
assert(available_tr.randomize()) else `uvm_error("SENDER", "Failed to randomize transaction")
`uvm_info("SENDER", $sformatf("Prepared data: %0d", available_tr.data), UVM_LOW)
endtask
endclass
// Alıcı (Receiver)
class my_receiver extends uvm_component;
uvm_nonblocking_get_port #(my_transaction) get_port;
`uvm_component_utils(my_receiver)
function new(string name = "my_receiver", uvm_component parent = null);
super.new(name, parent);
get_port = new("get_port", this);
endfunction
task receive_data();
my_transaction tr;
if (get_port.can_get()) begin // Transaction mevcut mu kontrol et
if (get_port.try_get(tr)) begin // Non-blocking get çağrısı
`uvm_info("RECEIVER", $sformatf("Received data: %0d", tr.data), UVM_LOW)
end else begin
`uvm_warning("RECEIVER", "Failed to get data")
end
end else begin
`uvm_info("RECEIVER", "No data available", UVM_LOW)
end
endtask
endclass
// Testbench
class my_env extends uvm_env;
my_sender sender;
my_receiver receiver;
`uvm_component_utils(my_env)
function new(string name = "my_env", uvm_component parent = null);
super.new(name, parent);
sender = my_sender::type_id::create("sender", this);
receiver = my_receiver::type_id::create("receiver", this);
receiver.get_port.connect(sender.get_imp); // Portları bağla
endfunction
task run_phase(uvm_phase phase);
phase.raise_objection(this);
sender.prepare_transaction(); // Transaction hazırla
#100;
receiver.receive_data(); // Veri al
#100;
phase.drop_objection(this);
endtask
endclass
// Test
class my_test extends uvm_test;
my_env env;
`uvm_component_utils(my_test)
function new(string name = "my_test", uvm_component parent = null);
super.new(name, parent);
endfunction
function void build_phase(uvm_phase phase);
super.build_phase(phase);
env = my_env::type_id::create("env", this);
endfunction
endclass
endpackage
// Test çalıştırma
module top;
import uvm_pkg::*;
import my_pkg::*;
initial begin
uvm_top.enable_print_topology = 1;
run_test("my_test");
end
endmodule
5️⃣ Port-Export-Imp Topolojisi#
📌 Açıklama#
- Port: Transaction başlatan bileşende tanımlanır.
- Export: Port ile imp arasında köprü görevi görür.
- Imp: Transaction’ı sonlandıran bileşende implement edilir.
📦 Bağlantı Örneği#
// Bağlantı Topolojisi
driver.put_port.connect(env.put_export);
env.put_export.connect(monitor.put_imp);
📌 İpuçları#
- Port doğrudan imp’e de bağlanabilir.
- Export, hiyerarşik yapılarda portu alt bileşenlerden almak için kullanılır.
- Imp, her zaman receiver bileşeninde implement edilir.