Hi, All:
I noticed that there are some differences in the usage for uvm_recorder between UVM1.1 and UVM1.2. That made me a little confusion when trying the transaction recorder for verdi. Here is some example code for m_begin_tr task inside the uvm_component.
For UVM 1.1:
kind = (has_parent == 0) ? "Begin_No_Parent, Link" : "Begin_End, Link";
// Modified by Verdi
`ifdef UVM_VCS_RECORD
desc = {desc,
$psprintf("Object ID: %0s (@%0d)\n", $vcs_get_object_id(tr), tr.get_inst_id()),
$psprintf("Sequencer ID: %0s (@%0d)\n", $vcs_get_object_id(this), get_inst_id())};
if ($cast(seq_base,tr)) begin
desc = {desc,
"Phase: ", seq_base.starting_phase ? seq_base.starting_phase.get_name() : "N/A", "\n"};
if(seq_base.get_parent_sequence()!=null) begin
desc = {desc,
$psprintf("Parent Sequence ID: %0d\n", seq_base.get_parent_sequence().get_inst_id())};
end
end else if($cast(seq_item, tr)) begin
if(seq_item.get_parent_sequence()!=null) begin
desc = {desc,
$psprintf("Parent Sequence ID: %0d\n", seq_item.get_parent_sequence().get_inst_id())};
end
end
`endif
// End
tr_h = recordr.begin_tr(kind, stream_h, name, label, desc, begin_time);
if (has_parent && parent_handle != 0)
recordr.link_tr(parent_handle, tr_h, "child");
m_tr_h[tr] = tr_h;
if (recordr.check_handle_kind("Transaction", link_tr_h) == 1)
recordr.link_tr(tr_h,link_tr_h);
do_begin_tr(tr,stream_name,tr_h);
For UVM 1.2:
if (uvm_verbosity'(recording_detail) != UVM_NONE) begin
if ((stream_name == "") || (stream_name == "main")) begin
if (m_main_stream == null)
m_main_stream = db.open_stream("main", this.get_full_name(), "TVM");
stream = m_main_stream;
end
else
stream = get_tr_stream(stream_name);
if (stream != null ) begin
kind = (parent_recorder == null) ? "Begin_No_Parent, Link" : "Begin_End, Link";
recorder = stream.open_recorder(name, begin_time, kind);
if (recorder != null) begin
if (label != "")
recorder.record_string("label", label);
if (desc != "")
recorder.record_string("desc", desc);
if (parent_recorder != null) begin
tr_database.establish_link(uvm_parent_child_link::get_link(parent_recorder,
recorder));
end
if (link_recorder != null) begin
tr_database.establish_link(uvm_related_link::get_link(recorder,
link_recorder));
end
m_tr_h[tr] = recorder;
end
end
handle = (recorder == null) ? 0 : recorder.get_handle();
do_begin_tr(tr, stream_name, handle);
end
Please note, in UVM 1.1, it directly call the begin_tr of the recorder without any other behavior. In UVM 1.2, it will open the recorder by calling the stream.open_recorder. And in the open_recorder of stream, it will call the 'm_do_open' task from recorder. Here comes the problem, in m_do_open of recorder, it will check if the recorder has been opened more than onece like below. So if we have many sequencers running parallely, we can not guarantee the recorder is managed(open->free->open->free) in order. It will cause the recorder be opened many times and trigger the ERROR.
function void m_do_open(uvm_tr_stream stream, time open_time, string type_name);
uvm_tr_stream m_stream;
if (stream == null) begin
`uvm_error("UVM/REC/NULL_STREAM",
$sformatf("Illegal attempt to set STREAM for '%s' to '<null>'",
this.get_name()))
return;
end
if (-_stream_dap.try_get(m_stream)) begin
`uvm_error("UVM/REC/RE_INIT",
$sformatf("Illegal attempt to re-initialize '%s'",
this.get_name()))
return;
end
m_stream_dap.set(stream);
m_open_time = open_time;
m_is_opened = 1;
do_open(stream, open_time, type_name);
endfunction : m_do_open
Does anyone konw about this? Maybe I misunderstand the usage. Can anyone help to explain this? Thanks!