UVM driver和sequencer握手机制 get_next_item() 和 get() and put()

参考链接:UVM 源码

driver 和 sequencer 握手机制一:get_next_item():

在这里插入图片描述

// transaction 

class my_data extends uvm_sequence_item;  // 创建自己的transaction一般是从uvm_sequence_item,而不是uvm_transaction
  	rand bit [7:0]   data;
  	rand bit [7:0]   addr;

	// Rest of the class contents come here ...
endclass

// driver 

class my_driver extends uvm_driver #(my_data);  // my_driver被参数化为仅接受“my_data”类型的对象
	`uvm_component_utils (my_driver)
	
   	virtual task run_phase(uvm_phase phase);
      	super.run_phase(phase);
      
      	// 1. driver用get_next_item()从sequencer拿到item 
      	`uvm_info ("DRIVER", $sformatf ("Waiting for data from sequencer"), UVM_MEDIUM)
      	seq_item_port.get_next_item(req);
      
      	`uvm_info ("DRIVER", $sformatf ("Start driving tx addr=0x%0h data=0x%0h", req.addr, req.data), UVM_MEDIUM)
      	#20;  // 2.假设driver把接收到的数据包发给dut需要20ns
      
      	// 3. driver 调用 item_done() 让 sequencer 知道 driver 发送完 item
     	`uvm_info ("DRIVER", $sformatf ("Finish driving tx addr=0x%0h data=0x%0h", req.addr, req.data), UVM_MEDIUM)
     	seq_item_port.item_done();   // driver完成对item的处理
   endtask
   
endclass
// sequence
class my_sequence extends uvm_sequence #(my_data);  // my_sequence被参数化为仅接受“my_data”类型的对象
	`uvm_object_utils (my_sequence)
	
  	virtual task body();
  		// 1. 在 sequence body 中实例化item: create item 
  		my_data tx = my_data::type_id::create("tx");
	   	`uvm_info ("SEQ", $sformatf("About to call start_item"), UVM_MEDIUM)
    
    	// 2. 调用 start_item() ,将这个 item 发送给 driver 
    	start_item(tx);
    	`uvm_info ("SEQ", $sformatf("start_item() fn call done"), UVM_MEDIUM)
    
    	// 3. 因为传递给driver的类句柄指向同一个对象,可以先create再随机? 后随机
    	tx.randomize();
    	`uvm_info ("SEQ", $sformatf("tx randomized with addr=0x%0h data=0x%0h", tx.addr, tx.data), UVM_MEDIUM)
    
    	// 4. 调用 finish_item ,以便sequence等待,直到驱driver让sequencer知道该item已完成
    	finish_item(tx);
    	`uvm_info ("SEQ", $sformatf("finish_item() fn call done"), UVM_MEDIUM)
  	endtask
  
endclass

Driver 和 Sequencer 应该在 agent 实例化,agent 在 env 中实例化,env 在 test 中实例化

// test

class base_test extends uvm_test;

  	my_driver                	m_drv0;
  	uvm_sequencer #(my_data) 	m_seqr0;  // sequencer 被参数化为仅接受“my_data”类型的对象
  	my_sequence   				m_seq;

	// 在 build_phase 用 create 实例化 sequencer/driver 组件
  	virtual function void build_phase(uvm_phase phase);
     	super.build_phase(phase);
     	m_drv0 = my_driver::type_id::create ("m_drv0", this);
     	m_seqr0 = uvm_sequencer#(my_data)::type_id::create ("m_seqr0", this);
  	endfunction
  
   	// 在 connect_phase 连接 driver 的 port(seq_item_port) 到 sequencer 的 export(seq_item_export)
   	virtual function void connect_phase (uvm_phase phase);
     	super.connect_phase (phase);
     	m_drv0.seq_item_port.connect (m_seqr0.seq_item_export);
   	endfunction

	// 在run_phase中实例化sequence;  在sequencer上启动sequence
  	virtual task run_phase(uvm_phase phase);
    	m_seq = my_sequence::type_id::create("m_seq");   // 实例化sequence
    	phase.raise_objection(this);
    	m_seq.start(m_seqr0);  // 在sequencer上启动sequence
    	phase.drop_objection(this);
  	endtask
endclass

- [ ] 一周掌握 Java 入门知识


driver 和 sequencer 握手机制二: get() and put():

在这里插入图片描述

// transaction item 

class my_data extends uvm_sequence_item;
  	rand bit [7:0]   data;
  	rand bit [7:0]   addr;

	// Rest of the class contents come here ...
endclass
// driver

class my_driver extends uvm_driver #(my_data);  // driver 被参数化为仅接受“my_data”类型的对象
   `uvm_component_utils (my_driver)

   virtual task run_phase(uvm_phase phase);
      super.run_phase(phase);
      
      // 1.driver 使用get从sequencer拿到item,req是uvm_driver类的pre-defined变量
      `uvm_info ("DRIVER", $sformatf ("Waiting for data from sequencer"), UVM_MEDIUM)
      seq_item_port.get(req);
      
      // 2.假设的driver处理该item需要10ns
      uvm_info ("DRIVER", $sformatf ("Start driving tx addr=0x%0h data=0x%0h", req.addr, req.data), UVM_MEDIUM)
      #20;
      
      // 3. 假设 DUT 将一些读取数据返回给driver,这些数据需要发送回到sequence。 请注意,读取的数据被放入相同的request的对象句柄中
      `uvm_info ("DRIVER", $sformatf ("#20 delay over, curr data=0x%0h", req.data), UVM_MEDIUM)
      req.data = 8'hAA;  // 假设driver从dut拿到的响应数据是8'hAA
      
      // 4. driver调用put,并将响应数据发送回sequencer
      `uvm_info ("DRIVER", $sformatf ("About to call put() with new data=0x%0h", req.data), UVM_MEDIUM)
      seq_item_port.put(req);   // driver发回响应数据给sequencer
      `uvm_info ("DRIVER", $sformatf ("Finish driving tx addr=0x%0h data=0x%0h", req.addr, req.data), UVM_MEDIUM)
   endtask
   
endclass
// sequence

class my_sequence extends uvm_sequence #(my_data);  // sequence 被参数化为仅接受“my_data”类型的对象

  	virtual task body();
  		// 1. 实例化item 
  		my_data tx = my_data::type_id::create("tx");
    	`uvm_info ("SEQ", $sformatf("About to call start_item"), UVM_MEDIUM)
    	
    	// 2. sequence 启动item 
    	start_item(tx);
    	`uvm_info ("SEQ", $sformatf("start_item() fn call done"), UVM_MEDIUM)
    	
    	// 3. 对item后随机 (先create再随机?)
    	tx.randomize();
    	`uvm_info ("SEQ", $sformatf("tx randomized with addr=0x%0h data=0x%0h", tx.addr, tx.data), UVM_MEDIUM)
    	
    	// 4. sequence 调用 finish_item
    	finish_item(tx);
    	`uvm_info ("SEQ", $sformatf("finish_item() fn call done, wait for rsp"), UVM_MEDIUM)
    	
    	// 阻塞型get_response会等到driver发回数据响应
    	get_response(tx);
    	`uvm_info ("SEQ", $sformatf("get_response() fn call done rsp addr=0x%0h data=0x%0h, exit seq", tx.addr, tx.data), UVM_MEDIUM)
  	endtask
  	
endclass
// test

class base_test extends uvm_test;

	// sequencer 被参数化为仅接受“my_data”类型的对象
  	my_driver                	m_drv0;
  	uvm_sequencer #(my_data) 	m_seqr0;  // 使用了uvm自带的uvm_sequencer类,而没有自定义uvm_sequencer子类
  	my_sequence   				m_seq;

	// 在 build_phase 用 create 实例化 sequencer/driver 组件
  	virtual function void build_phase(uvm_phase phase);
     	super.build_phase(phase);
     	m_drv0 = my_driver::type_id::create ("m_drv0", this);
     	m_seqr0 = uvm_sequencer#(my_data)::type_id::create ("m_seqr0", this);
  	endfunction
  
   	// 在 connect_phase 连接 driver 的 port(seq_item_port) 到 sequencer 的 export(seq_item_export)
   	virtual function void connect_phase (uvm_phase phase);
     	super.connect_phase (phase);
     	m_drv0.seq_item_port.connect (m_seqr0.seq_item_export);
   	endfunction

	// 在run_phase中实例化sequence;  在sequencer上启动sequence
  	virtual task run_phase(uvm_phase phase);
    	m_seq = my_sequence::type_id::create("m_seq");  // 在run phase实例化sequence
    	phase.raise_objection(this);
    	m_seq.start(m_seqr0);
    	phase.drop_objection(this);
  	endtask
  	
endclass

在这里插入图片描述


driver seq_item_port TLM端口:

  • seq_item_port.get(req)
  • seq_item_port.put(req)
  • seq_item_port.get_next_item(req)
  • seq_item_port.item_done()
  • 一个 seq_item_port 只能 connect 一个 seq_item_export
  • 可以在一个 driver 中用数组的形式定义多个 uvm_seq_item_pull_port,用来连接多个 sequencer

get()和get_next_item()的区别在于get()中调用了item_done()函数,所以可以发现在上面的代码中,get到了transaction后并没有item_done()操作

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值