uvm sequencer和driver通信

uvm driver从sequencer FIFO中获取request类型的sequence item(REQ), 类似握手协议, 返回一个response类型的(RSP)。如下图所示:

本篇主要介绍在driver中使用get_next_item的方法。

这种情况下, driver获取sequence item主要是通过seq_item_port, 比如下面的代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
class  extends uvm_driver #(my_data);
uvm_component_utils (my_driver)</span><br/><span class="line"> </span><br/><span class="line"> <span class="function"><span class="keyword">virtual</span> task <span class="title">run_phase</span><span class="params">(uvm_phase phase)</span></span>;</span><br/><span class="line"> super.run_phase(phase);</span><br/><span class="line"> </span><br/><span class="line"> </span><br/><span class="line"> uvm_info ("DRIVER", $sformatf ("Waiting for data from sequencer"), UVM_MEDIUM)
seq_item_port.get_next_item(req);

// 2. For simplicity, lets just assume the driver drives the received packet
// during this time and consumes 20ns to complete driving the transaction
uvm_info (<span class="string">"DRIVER"</span>, $sformatf (<span class="string">"Start driving tx addr=0x%0h data=0x%0h"</span>, req.addr, req.data), UVM_MEDIUM)</span><br/><span class="line"> #<span class="number">20</span>;</span><br/><span class="line"> </span><br/><span class="line"> <span class="comment">// 3. After driver has finished the transaction, it has to let the sequencer know</span></span><br/><span class="line"> <span class="comment">// by calling item_done()</span></span><br/><span class="line"> uvm_info ("DRIVER", $sformatf ("Finish driving tx addr=0x%0h data=0x%0h", req.addr, req.data), UVM_MEDIUM)
seq_item_port.item_done();
endtask

一旦driver完成驱动interface上的信号, 就可以用item_done的方法通知sequencer。

那么sequencer又是如何获取sequence item的呢?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
class my_sequence extends uvm_sequence;
uvm_object_utils (my_sequence)</span><br/><span class="line"> </span><br/><span class="line"> </span><br/><span class="line"> <span class="function"><span class="keyword">virtual</span> task <span class="title">body</span><span class="params">()</span></span>;</span><br/><span class="line"> <span class="comment">// 1. Create an item the connected sequencer can accept</span></span><br/><span class="line"> my_data tx = my_data::type_id::create(<span class="string">"tx"</span>);</span><br/><span class="line"> uvm_info ("SEQ", $sformatf("About to call start_item"), UVM_MEDIUM)

// 2. Call the start_item() task which will send this object to the driver
start_item(tx);
uvm_info (<span class="string">"SEQ"</span>, $sformatf(<span class="string">"start_item() fn call done"</span>), UVM_MEDIUM)</span><br/><span class="line"> </span><br/><span class="line"> <span class="comment">// 3. Because the class handle passed to the driver points to the same object, we </span></span><br/><span class="line"> <span class="comment">// can do late randomization</span></span><br/><span class="line"> tx.randomize();</span><br/><span class="line"> uvm_info ("SEQ", $sformatf("tx randomized with addr=0x%0h data=0x%0h", tx.addr, tx.data), UVM_MEDIUM)

// 4. Call finish_item method so that the sequence waits until the driver lets the
// sequencer know that this item has finished
finish_item(tx);
`uvm_info ("SEQ", $sformatf("finish_item() fn call done"), UVM_MEDIUM)
endtask
endclass