📄 _decl
Makrosu Kullanımı#
📌 Giriş#
UVM’de transaction seviyesinde veri iletişimi için kullanılan TLM (Transaction-Level Modeling) interface’lerinde genelde tek bir kaynak (uvm_analysis_port
) ile tek bir hedef (uvm_analysis_imp
) bağlantısı kurarız. Ancak bazen aynı kaynaktan (örneğin bir producer) gelen verileri subscriber tarafında farklı fonksiyonlarla işlemek isteyebiliriz.
İşte bu noktada uvm_*_imp_decl()
makrosu devreye girer. Bu makro, interface’lerde birden fazla “imp” tanımlamamızı ve her biri için farklı fonksiyonlar yazmamızı sağlar.
🔎 _decl
Makrosunun Amacı#
- Bir subscriber içerisinde birden fazla port implementasyonu tanımlamak.
- Gelen verileri farklı fonksiyonlara yönlendirmek.
- Testbench’te farklı komponentlerden veya aynı komponentten gelen verileri kolayca ayırmak.
📌 Kullanımı#
1️⃣ Önce _decl
makrosunu tanımla:
`uvm_analysis_imp_decl(_1)
`uvm_analysis_imp_decl(_2)
2️⃣ Subscriber içinde:
uvm_analysis_imp_1 #(my_transaction, my_subscriber) analysis_imp1;
uvm_analysis_imp_2 #(my_transaction, my_subscriber) analysis_imp2;
3️⃣ Farklı write_*()
fonksiyonları yaz:
virtual function void write_1(my_transaction t);
...
endfunction
virtual function void write_2(my_transaction t);
...
endfunction
4️⃣ Producer portunu bu subscriber portlarına bağla:
producer.analysis_port.connect(subscriber.analysis_imp1);
producer.analysis_port.connect(subscriber.analysis_imp2);
🚀 Örnek Kod#
Aşağıda _decl
kullanımını gösteren tam bir örnek verilmiştir:
package my_pkg;
`include "uvm_macros.svh"
import uvm_pkg::*;
`uvm_analysis_imp_decl(_1)
`uvm_analysis_imp_decl(_2)
// Transaction
class my_transaction extends uvm_sequence_item;
int data;
`uvm_object_utils(my_transaction)
function new(string name = "my_transaction");
super.new(name);
endfunction
endclass
// Producer
class my_producer extends uvm_component;
uvm_analysis_port #(my_transaction) analysis_port;
`uvm_component_utils(my_producer)
function new(string name = "my_producer", uvm_component parent = null);
super.new(name, parent);
analysis_port = new("analysis_port", this);
endfunction
task run_phase(uvm_phase phase);
my_transaction tr;
phase.raise_objection(this);
for (int i = 0; i < 5; i++) begin
tr = my_transaction::type_id::create("tr");
tr.data = i;
`uvm_info("PRODUCER", $sformatf("Sending data: %0d", tr.data), UVM_LOW)
analysis_port.write(tr);
#100;
end
phase.drop_objection(this);
endtask
endclass
// Subscriber
class my_subscriber extends uvm_component;
`uvm_component_utils(my_subscriber)
uvm_analysis_imp_1 #(my_transaction, my_subscriber) analysis_imp1;
uvm_analysis_imp_2 #(my_transaction, my_subscriber) analysis_imp2;
function new(string name = "my_subscriber", uvm_component parent = null);
super.new(name, parent);
analysis_imp1 = new("analysis_imp1", this);
analysis_imp2 = new("analysis_imp2", this);
endfunction
virtual function void write_1(my_transaction t);
`uvm_info("SUBSCRIBER", $sformatf("write_1: Received data: %0d", t.data), UVM_LOW)
endfunction
virtual function void write_2(my_transaction t);
`uvm_info("SUBSCRIBER", $sformatf("write_2: Received data: %0d", t.data), UVM_LOW)
endfunction
endclass
// Environment
class my_env extends uvm_env;
my_producer producer;
my_subscriber subscriber;
`uvm_component_utils(my_env)
function new(string name = "my_env", uvm_component parent = null);
super.new(name, parent);
producer = my_producer::type_id::create("producer", this);
subscriber = my_subscriber::type_id::create("subscriber", this);
endfunction
function void connect_phase(uvm_phase phase);
super.connect_phase(phase);
producer.analysis_port.connect(subscriber.analysis_imp1);
producer.analysis_port.connect(subscriber.analysis_imp2);
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
endclass
endpackage
// Top module
module top;
import uvm_pkg::*;
import my_pkg::*;
initial begin
uvm_top.enable_print_topology = 1;
run_test("my_test");
end
endmodule
✨ Özet#
✅ _decl
makrosu ile birden fazla port implementasyonu oluşturabiliriz.
✅ Her implementasyon farklı bir write_*()
fonksiyonuna yönlenir.
✅ Bu, verileri kaynağa göre veya port’a göre ayrı ayrı işlemek için idealdir.