目录
2.uvm_compoent继承于uvm_object,相对又有什么扩展?
3.uvm_compoent相对uvm_object有什么缺失?(纵然uvm_compoent继承于uvm_object)
1.为什么uvm_compoent在new()的时候要按参数列表指定第二个参数parent?
1.filed automation的引入给driver带来的精简变化
3.1 uvm_compoent和uvm_object
1.补一张更为全面的uvm库图
注意uvm_compoent和uvm_object的关系,按继承于uvm_object与否分类该图
2.uvm_compoent继承于uvm_object,相对又有什么扩展?
1.构造函数new(name,parent),可形成树形结构
2.phase自动执行,对比可以回顾transaction是怎么启动
3.uvm_compoent相对uvm_object有什么缺失?(纵然uvm_compoent继承于uvm_object)
由于其树形结构的特性(new时必须指明parent),无法使用uvm_object中的clone函数
3.2 UVM的树形结构
1.为什么uvm_compoent在new()的时候要按参数列表指定第二个参数parent?
更关键的是让每一个在树形图中的comp,能够找到自己的parent和child(如果有的话)
3.3 filed automation机制
1.filed automation的引入给driver带来的精简变化
实际上这部分应该在2.3.7阐述清楚.
在引入filed automation之前,driver代码:
//非完整代码
task my_driver::main_phase(uvm_phase phase);
my_transaction tr;
phase.raise_objection(this);
vif.data <= 8'b0;
vif.valid <= 1'b0;
while(!vif.rst_n)
@(posedge vif.clk);
for(int i = 0; i < 2; i++) begin
tr = new("tr");
assert(tr.randomize() with {pload.size == 200;});
drive_one_pkt(tr);
end
repeat(5) @(posedge vif.clk);
phase.drop_objection(this);
endtask
task my_driver::drive_one_pkt(my_transaction tr);
bit [47:0] tmp_data;
bit [7:0] data_q[$];
//push dmac to data_q
tmp_data = tr.dmac;
for(int i = 0; i < 6; i++) begin
data_q.push_back(tmp_data[7:0]);
tmp_data = (tmp_data >> 8);
end
//push smac to data_q
tmp_data = tr.smac;
for(int i = 0; i < 6; i++) begin
data_q.push_back(tmp_data[7:0]);
tmp_data = (tmp_data >> 8);
end
//push ether_type to data_q
tmp_data = tr.ether_type;
for(int i = 0; i < 2; i++) begin
data_q.push_back(tmp_data[7:0]);
tmp_data = (tmp_data >> 8);
end
//push payload to data_q
for(int i = 0; i < tr.pload.size; i++) begin
data_q.push_back(tr.pload[i]);
end
//push crc to data_q
tmp_data = tr.crc;
for(int i = 0; i < 4; i++) begin
data_q.push_back(tmp_data[7:0]);
tmp_data = (tmp_data >> 8);
end
`uvm_info("my_driver", "begin to drive one pkt", UVM_LOW);
repeat(3) @(posedge vif.clk);
while(data_q.size() > 0) begin
@(posedge vif.clk);
vif.valid <= 1'b1;
vif.data <= data_q.pop_front();
end
@(posedge vif.clk);
vif.valid <= 1'b0;
`uvm_info("my_driver", "end drive one pkt", UVM_LOW);
endtask
引入之后的driver:
//非完整代码
task my_driver::main_phase(uvm_phase phase);
my_transaction tr;
phase.raise_objection(this);
vif.data <= 8'b0;
vif.valid <= 1'b0;
while(!vif.rst_n)
@(posedge vif.clk);
for(int i = 0; i < 2; i++) begin
tr = new("tr");
assert(tr.randomize() with {pload.size == 200;});
drive_one_pkt(tr);
end
repeat(5) @(posedge vif.clk);
phase.drop_objection(this);
endtask
task my_driver::drive_one_pkt(my_transaction tr);
byte unsigned data_q[];
int data_size;
data_size = tr.pack_bytes(data_q) / 8;
`uvm_info("my_driver", "begin to drive one pkt", UVM_LOW);
repeat(3) @(posedge vif.clk);
for ( int i = 0; i < data_size; i++ ) begin
@(posedge vif.clk);
vif.valid <= 1'b1;
vif.data <= data_q[i];
end
@(posedge vif.clk);
vif.valid <= 1'b0;
`uvm_info("my_driver", "end drive one pkt", UVM_LOW);
endtask
注意观察drive_one_pkt的实现,繁琐重复的队列方法被pack_bytes替代,替代的前提是在transaction中进行了如下注册:
`uvm_object_utils_begin(my_transaction)
`uvm_field_int(dmac, UVM_ALL_ON)
`uvm_field_int(smac, UVM_ALL_ON)
`uvm_field_int(ether_type, UVM_ALL_ON)
`uvm_field_array_int(pload, UVM_ALL_ON)
`uvm_field_int(crc, UVM_ALL_ON)
`uvm_object_utils_end
2.关于filed automation要注意的点
1.给各个field注册的顺序决定push各个field进data_q的顺序
2.注册的第二个参数可以决定是否加入数据传输等动作中