I am making an UVM environment which is used for exclusive APB bus by register model. But now, the grab() cannot return. So the sim process was hung there.
Let me introduce my situation.
ENV:
class tb_env extends uvm_env;
…...
virtual function void connect_phase(uvm_phase phase);
if (regmodel.get_parent() == null) begin
reg2apb_adapter reg2apb = reg2apb_adapter::type_id::create("reg2apb");
regmodel.default_map.set_sequencer(apb.sqr,reg2apb);
regmodel.default_map.set_auto_predict(1);
end
endfunction
endclass
Sequence :
class seq_mul extends seq_base ;
……
`uvm_object_utils(seq_mul)
virtual task body();
`uvm_info("TB/TRACE", "mul seq run phase...", UVM_NONE);
for ( int i = 0 ; i < 5 ; i++ ) begin
regmodel.IntMask.write(status, 8'hb0 +i ) ; // write some data to the apb bus.
end
endtask
endclass
class seq_add extends seq_base ;
……
virtual task body();
super.body ;
m_sequencer = regmodel.default_map.get_sequencer() ;
$display( "m_sequencer: %s " , m_sequencer.get_full_name() ) ;
m_sequencer.grab(this); // run process cannot go on.
for ( int i = 0 ; i < 5 ; i++ ) begin
regmodel.TxRx.write(status, 8'ha0 + i ) ;
end
m_sequencer.ungrab(this);
endtask
endclass
In the test’s run phase :
task run_phase(uvm_phase phase);
seq_mul m_seq_mul = seq_mul::type_id::create("m_seq_mul");
seq_add m_seq_add = seq_add::type_id::create("m_seq_add");
phase.raise_objection(this, "Test Started");
`uvm_info("TB/TRACE", "in test run phase...", UVM_NONE);
regmodel.IntSrc.write(status, 8'hff ) ;
fork
m_seq_mul.start(null) ;
m_seq_add.start(null) ;
join
phase.drop_objection(this, "Test Finished");
endtask: run_phase
when I run the case, the simulation hung at m_sequencer.grab(this);
if I remove the_m_sequencer.grab(this); and m_sequencer.ungrab(this);_ . The run phase could finish correct, and we can observe the write operation in the APB bus. Is the sequencer I figured incorrect? Or the register sequence has some special features? I suspect the adapter between the apb agent and regmodel is the reason. But I have no idea how to resolve it.
Would you please help me? Any advice is appreciated.
I would have to take a longer look at what you are doing, but the variable m_sequencer contains the handle to the sequencer that the sequence is running on. You are trying to change m_sequencer to point to a different sequencer and this might be causing issues.
He is starting ‘m_seq_add’ of type ‘seq_add’ on the a null sequencer, which will create an instance of a virtual sequencer to run on. He then seems to change the m_sequencer pointer to the sequencer used by the register model within the sequence itself. It’s hard to really tell without a complete example to trace through, but one should never have a need to change m_sequencer as it is set by UVM.
The various m_sequencer in the sequence will be a null. So I could not use the grab() function either.
On the other hand, if I specified the sequencer when I start the sequence like this
m_seq_mul.start(m_env.apb.sqr) ;
, the m_sequencer in the sequence will not be null, but the grab will not return either.
I have done the other two labs.
The one: I remove the grab function from the sequence seq_add; the test work correctly.
The other: I made an environment for the grab function without register model, the grab function work correctly.
Just when I use the register model in the sequence, with the adapter and the APB agent, in order to access DUT by APB BUS, the grab hang the test and have no return.
I think this is a very useful method for CPU’s interrupt verification. If you have made this process successfully, would you like to share your experience?
If I did not introduce clearly, please let me know. Thanks again for your comments .
You are incorrect in your assumption that m_sequencer will be null if you specify null in your start statement. If you pass in a null sequencer to your start command, a generic virtual sequencer will be automatically created and assigned to m_sequencer. Therefore, you should never have a need to change m_sequencer.
As your comments, I specify null in my start, and then, in the sequence, I printed the m_sequencer’s full name by m_sequencer.get_full_name(), and got the result : uvm_test_top.m_env.apb.sqr, what is the sequencer in my APB agent. I think this is because I have set the sequencer like this: regmodel.default_map.set_sequencer(apb.sqr,reg2apb); I think this is not a virtual sequencer assigned by UVM. correct me, Thanks.
And if I specified the sequencer when I start the sequence like this
m_seq_mul.start(m_env.apb.sqr) ; , the m_sequencer in the sequence will not be null, but the grab will not return either.
if possible, Could you please help me about this?
What Chuck meant is, if you print m_sequencer.get_full_name before you assign m_sequencer with some value. You shouldn’t get null.
Changing the order of your statements as below should not print you null.
$display( "m_sequencer: %s " , m_sequencer.get_full_name() ) ;
m_sequencer = regmodel.default_map.get_sequencer() ;
If I print m_sequencer.get_full_name before assign m_sequencer with some value, I really got the null. The log is below:
Error-[NOA] Null object access
sequence.sv, 76
The object is being used before it was constructed/allocated.
Please make sure that the object is newed before using it.
// note: in sequence.sv line 76, the m_sequencer appeared first time.
And if I remove various m_sequencer from sequence, the regmodel access ( write/read) is correct.