1. 前面的my_print,my_copy,my_compare函数,虽然各自不同,但对于transaction来说,都是类似的。使用UVM中的field_automation机制,可以自动实现这3个函数,不需要我们写,my_transaction:
`ifndef MY_TRANSACTION__SV
`define MY_TRANSACTION__SV
class my_transaction extends uvm_sequence_item;
rand bit[47:0] dmac;
rand bit[47:0] smac;
rand bit[15:0] ether_type;
rand byte pload[];
rand bit[31:0] crc;
constraint pload_cons{
pload.size >= 46;
pload.size <= 1500;
}
function bit[31:0] calc_crc();
return 32'h0;
endfunction
function void post_randomize();
crc = calc_crc;
endfunction
`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
function new(string name = "my_transaction");
super.new();
endfunction
endclass
`endif
1)pload.size还是可以限制的。
2)使用uvm_object_utils_begin 和 uvm_object_utils_end 实现my_transaction 的factory注册。
3)uvm_field系列宏不同:uvm_field_int 对 int;uvm_field_array_int 对 byte。
2.my_model变为:
task my_model::main_phase(uvm_phase phase);
my_transaction tr;
my_transaction new_tr;
super.main_phase(phase);
while(1) begin
port.get(tr);
new_tr = new("new_tr");
new_tr.copy(tr);//<===========
`uvm_info("my_model", "get one transaction, copy and print it:", UVM_LOW)
new_tr.print();//<===========
ap.write(new_tr);
end
endtask
之前是my_copy 和 my_print。
3.my_scoreboard变为:
while (1) begin
act_port.get(get_actual);
if(expect_queue.size() > 0) begin
tmp_tran = expect_queue.pop_front();
result = get_actual.compare(tmp_tran);//<============
if(result) begin
`uvm_info("my_scoreboard", "Compare SUCCESSFULLY", UVM_LOW);
end
之前是my_compare。
4.field_automation的另一个好处是简化了driver 和 monitor。my_driver 的 drv_one_pkt任务和my_monitor的collect_one_pkt 很长,而且都是些重复性的代码。使用field_automation后,drv_one_pkt 可以简化为:
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
1)pack_bytes 将tr 中所有的字段变成byte流放入data_q中。字段按照uvm_field 系列宏的顺序排列。
5.my_monitor的collect_one_pkt :
task my_monitor::collect_one_pkt(my_transaction tr);
byte unsigned data_q[$];
byte unsigned data_array[];
logic [7:0] data;
logic valid = 0;
int data_size;
while(1) begin
@(posedge vif.clk);
if(vif.valid) break;
end
`uvm_info("my_monitor", "begin to collect one pkt", UVM_LOW);
while(vif.valid) begin
data_q.push_back(vif.data);
@(posedge vif.clk);
end
data_size = data_q.size();
data_array = new[data_size];
for ( int i = 0; i < data_size; i++ ) begin
data_array[i] = data_q[i];
end
tr.pload = new[data_size - 18]; //da sa, e_type, crc
data_size = tr.unpack_bytes(data_array) / 8;
`uvm_info("my_monitor", "end collect one pkt", UVM_LOW);
endtask
1)使用unpack_bytes (UVM的内容)函数将data_q 中的byte流转换成tr 中的各个字段。
2)unpack_bytes的输入参数必须为一个动态数组,所以把收集到的,放在data_q 中的数据复制到一个动态数组中。
3)由于tr中pload是一个动态数据,在调用unpack_bytes前,应该指定其大小。
问题:1)data_q这个queue 不是动态数组吗? 2)data_array不能直接用push_back吗?这样就不需要data_q[$]。
6.使用field_automation机制后,打印的信息室下面格式的: