UVM sequencer通过使用锁定机制向driver提供对序列的独占访问权限(exclusive access)。此锁定机制是使用lock和grab方法实现的。
例如:在控制器或微处理器中,internal core中断服务处理以及其他操作。有时,如果设备引发特定中断,需要立即关注并停止正在进行的进程执行。一旦core为这个高优先级中断提供服务,就可以恢复之前的进程。
sequence调用lock方法时,sequencer将在sequence通过sequencer仲裁机制获得下一个可用slot时,授予driver对sequence的独占访问权限。在sequence调用unlock方法之前,没有其他sequence可以访问driver。调用unlock方法时,之前的锁定被释放。lock是一种阻塞方法,一旦锁定被granted就会return。
task lock (uvm_sequencer_base sequencer = null)
The grab method is similar to the lock method except it takes immediate control to grab the next sequencer arbitration slot itself by overriding any other sequence priorities.
The pre-existing lock or grab condition on the sequence will stop from grabbing the sequence for the current sequence.
task grab (uvm_sequencer_base sequencer = null)
sequencer的lock方法从sequence中调用,以释放lock或grab。必须调用unlock方法以避免sequencer锁定情况。
function void unlock (uvm_sequencer_base sequencer = null)
ungrab方法是unlock方法的别称。
function void ungrab( uvm_sequencer_base sequencer = null )
is_block方法可用于查找由于sequencer lock条件而被block的当前sequence,并返回1。它返回0值,则sequence未被阻止,可在sequencer arbitration(仲裁器)中获取下一个slot。如果sequencer在sequence发出请求之前被lock,则sequence可能无法获得slot。
function bit is_blocked()
如果当前sequence被lock返回1,否则返回0。
function bit has_lock()
kill函数用于终止sequence,并删除序列默认sequencer中的所有当前locks和requests。这将不允许执行post_body和post_start回调方法,sequence状态将更改为UVM_STOPPED。
function void kill()
do_kill是一个用户钩子,当使用sequence kill()或sequencer.stop_sequences()终止序列时,将调用它。
注:sequencer.stop_sequences()最终调用sequence.kill方法。
virtual function void do_kill()
注:
有三个sequence:seq_A、seq_B和seq_C并行。只有seq_B调用lock和unlock方法。
class seq_A extends uvm_sequence #(seq_item);
seq_item req;
`uvm_object_utils(seq_A)
function new (string name = "seq_A");
super.new(name);
endfunction
task body();
req = seq_item::type_id::create("req");
wait_for_grant();
assert(req.randomize());
send_request(req);
`uvm_info(get_type_name(), $sformatf("%0t: seq_item is sent", $time), UVM_LOW);
wait_for_item_done();
endtask
endclass
class seq_B extends uvm_sequence #(seq_item);
seq_item req;
`uvm_object_utils(seq_B)
function new (string name = "seq_B");
super.new(name);
endfunction
task body();
lock(m_sequencer);
req = seq_item::type_id::create("req");
wait_for_grant();
assert(req.randomize());
send_request(req);
`uvm_info(get_type_name(), $sformatf("%0t: seq_item is sent", $time), UVM_LOW);
wait_for_item_done();
unlock(m_sequencer);
endtask
endclass
class seq_C extends uvm_sequence #(seq_item);
seq_item req;
`uvm_object_utils(seq_C)
function new (string name = "seq_C");
super.new(name);
endfunction
task body();
req = seq_item::type_id::create("req");
wait_for_grant();
assert(req.randomize());
send_request(req);
`uvm_info(get_type_name(), $sformatf("%0t: seq_item is sent", $time), UVM_LOW);
wait_for_item_done();
endtask
endclass
Output:
UVM_INFO sequences.sv(14) @ 0: uvm_test_top.env_o.agt.seqr@@seq_a [seq_A] 0: seq_item is sent
UVM_INFO sequences.sv(33) @ 50: uvm_test_top.env_o.agt.seqr@@seq_b [seq_B] 50: seq_item is sent
UVM_INFO sequences.sv(52) @ 100: uvm_test_top.env_o.agt.seqr@@seq_c [seq_C] 100: seq_item is sent
UVM_INFO sequences.sv(14) @ 150: uvm_test_top.env_o.agt.seqr@@seq_a [seq_A] 150: seq_item is sent
UVM_INFO sequences.sv(33) @ 200: uvm_test_top.env_o.agt.seqr@@seq_b [seq_B] 200: seq_item is sent
UVM_INFO sequences.sv(52) @ 250: uvm_test_top.env_o.agt.seqr@@seq_c [seq_C] 250: seq_item is sent
UVM_INFO sequences.sv(14) @ 300: uvm_test_top.env_o.agt.seqr@@seq_a [seq_A] 300: seq_item is sent
UVM_INFO sequences.sv(33) @ 350: uvm_test_top.env_o.agt.seqr@@seq_b [seq_B] 350: seq_item is sent
UVM_INFO sequences.sv(52) @ 400: uvm_test_top.env_o.agt.seqr@@seq_c [seq_C] 400: seq_item is sent
log显示,seq_B的lock请求按默认仲裁模式放到了仲裁队列的后面。因此,所有请求按分配的slot提供服务,seq_B具有独占访问权限。
有三个sequence:seq_A、seq_B和seq_C并行。只有seq_B调用grab和ungrab方法。
class seq_A extends uvm_sequence #(seq_item);
seq_item req;
`uvm_object_utils(seq_A)
function new (string name = "seq_A");
super.new(name);
endfunction
task body();
req = seq_item::type_id::create("req");
wait_for_grant();
assert(req.randomize());
send_request(req);
`uvm_info(get_type_name(), $sformatf("%0t: seq_item is sent", $time), UVM_LOW);
wait_for_item_done();
endtask
endclass
class seq_B extends uvm_sequence #(seq_item);
seq_item req;
`uvm_object_utils(seq_B)
function new (string name = "seq_B");
super.new(name);
endfunction
task body();
grab(m_sequencer);
req = seq_item::type_id::create("req");
wait_for_grant();
assert(req.randomize());
send_request(req);
`uvm_info(get_type_name(), $sformatf("%0t: seq_item is sent", $time), UVM_LOW);
wait_for_item_done();
ungrab(m_sequencer);
endtask
endclass
class seq_C extends uvm_sequence #(seq_item);
seq_item req;
`uvm_object_utils(seq_C)
function new (string name = "seq_C");
super.new(name);
endfunction
task body();
req = seq_item::type_id::create("req");
wait_for_grant();
assert(req.randomize());
send_request(req);
`uvm_info(get_type_name(), $sformatf("%0t: seq_item is sent", $time), UVM_LOW);
wait_for_item_done();
endtask
endclass
Output:
UVM_INFO sequences.sv(33) @ 0: uvm_test_top.env_o.agt.seqr@@seq_b [seq_B] 0: seq_item is sent
UVM_INFO sequences.sv(33) @ 50: uvm_test_top.env_o.agt.seqr@@seq_b [seq_B] 50: seq_item is sent
UVM_INFO sequences.sv(33) @ 100: uvm_test_top.env_o.agt.seqr@@seq_b [seq_B] 100: seq_item is sent
UVM_INFO sequences.sv(14) @ 150: uvm_test_top.env_o.agt.seqr@@seq_a [seq_A] 150: seq_item is sent
UVM_INFO sequences.sv(52) @ 200: uvm_test_top.env_o.agt.seqr@@seq_c [seq_C] 200: seq_item is sent
UVM_INFO sequences.sv(14) @ 250: uvm_test_top.env_o.agt.seqr@@seq_a [seq_A] 250: seq_item is sent
UVM_INFO sequences.sv(52) @ 300: uvm_test_top.env_o.agt.seqr@@seq_c [seq_C] 300: seq_item is sent
UVM_INFO sequences.sv(14) @ 350: uvm_test_top.env_o.agt.seqr@@seq_a [seq_A] 350: seq_item is sent
UVM_INFO sequences.sv(52) @ 400: uvm_test_top.env_o.agt.seqr@@seq_c [seq_C] 400: seq_item is sent
log显示,seq_B grab请求被放到l仲裁队列的前面。因此,seq_B请求被提前服务,随后是其他请求。