UVM学习------平台概要

类的定义与实例化

我们需要定义一个类,并且调用new()实例化对象使用方法和变量。

driver模块

diver模块一般负责接收sequencer发送的transaction(通过使用port封装好的方法),解析transaction对DUT产生激励,并且通过端口发送给moniter模块,这里一般使用interface关键字抽象化我们使用的变量,需要注意要加上virtual关键字实例化虚接口用,并且这里需要get我们的interface数据,与之对应的我们需要在上游agent模块中实例化driver时set我们get的interfac接口。

'include "uvm_macros.svh"
import uvm_pkg::*;
class my_driver extends uvm_driver #(my_transaction)
	virtual my_if vif;
	uvm_analysis_port #(my_transaction) ap;
	'uvm_component_utils(my_driver)
	extern function new(string name = "my_driver", uvm_component parent = NULL);
	extern virtual funtion void build_phase(uvm_phase phase);
	extern virtual task main_phase(uvm_phase phase);
	extern task drive_one_pkt(my_transaction)
	extern task drive_one_byte(bit [7:0] data)
endclsass;

function my_driver::new(string name, uvm_component parent);
	super.new(name,parent);
endfuntion

funtion void my_driver::build_phase(uvm_phase phase);
	super.build_phase(phase);
	if(!uvm_config_db#(vitual my_if)::get("this", "", "my_if", vif))
		'uvm_fatal("my_driver","error in geting interface");
	ap = new("ap", this);
endfuntion

task my_driver::main_phase(uvm_phase phase);
	my_transation req;
	super.main_phase(phase);
	vif.drv_cb.rxd <= 0;
	vif.drv_cb.rx_dv <= 1'b0;
	while(1) begin
		seq_item_port.get_next_item(req);
		drive_one_pkt(req);
		ap.write(req);
		seq_item_port.item_done;
	end
endtask;

task my_driver::drive_one_pkt(my_transation req);
	byte unsigned data_q[];
	int data_size;
	data_size = req.pack_bytes(data_q) / 8;#使用pack_bytes需要req里的uvm_field
	repeat(3) @vif.drv_cb;
	for(int i = 0; i < data_size; i++) begin
		drive_one_byte(data_q[i]);
	end
	@vif.drv_cb;
	vif.drv_cb.rx_dv <= 1'b0;
endtask

task my_driver::drive_one_byte(bit[7:0] data);
	@vif.drv_cb;
	vif.drv_cb.rxd <= data;
	vif.drv_cb.rx_dv <= 1'b1;
endtask;

transaction

模块间通信发送数据一般使用包的形式,需要看具体协议,比如以太网需要源地址、目的地址、数据、校验、包类型。

class my_transation extends uvm_sequence_item;
	rand bit [47:0] dmac;
	rand bit [47:0] smac;
	rand bit [15:0] type;
	rand byte pload[];
	rand bit [31:0] crc;
	
	constraint cons_pload_size{
		pload.size >= 47;
		pload.size <= 100;
	}
	
	funtion new(string name = "my_transaction");
		super.new(name);
	endfuntion;
	
	`uvm_object_utils_begin(my_transaction)
        `uvm_field_int(dmac,UVM_ALL_ON)
        `uvm_field_int(smac,UVM_ALL_ON)
        `uvm_field_int(ether_type,UVM_ALL_ON)
        `uvm_field_array_int(pload,UVM_ALL_ON)
        `uvm_field_int(crc,UVM_ALL_ON)
	`uvm_object_utils_end
endclass

monitor

monitor用来监测模块的输出,

class my_monitor extends uvm_monitor
	virtual my_if vif;
	uvm_analysis_port #(my_transaction) ap;
	funtion new(string name = "my_monitor", uvm_component parent = NULL);
		super.new(name, parent);
	endfunction
	
	funtion void build_phase(uvm_phase phase);
		super.build_phase(phase);
		if(!uvm_config_db#(virtual my_if)::get("this","","my_if",vif)
			uvm_report_fatal("my_monitor", "error in geting interface");
		ap = new("ap", this);
	endfuntion
	
	extern task main_phase(uvm_phase phase);
	extern task recive_one_packet(my_tansaction get_rpt);
	extern task get_one_byte(logic valid, logic [7:0] data);
endclass;

task my_monitor::main_phase(uvm_phase phase)
	super.main_phase(phase);
	my_transaction tr;
	while(1) begin
		tr = new("my_transacion");
		recive_one_packer(tr);
		ap.write(tr);
	end
endtask

task my_monitor::recive_one_packet(my_transaction get_rpt);
	byte unsigned data_q[];
	int data_size;
	while(1) begin
		@(vif.mon_cb);
		if(vif.mon_cb.tx_en)break;
	end
	while(vif.mon_cb.tx_en) begin
		data_q.push_back(vif.mon_cb.txd);
		@(vif.mon_cb);
	end
	data_size = data_q.size();
	get_rpt.pload = new[data_size];
	data_size = get_rpt.unpack_bytes(data_q) / 8; 

agent

因为monitor和driver有很多功能上的耦合,所以封装在一起,有agent负责实例化monitor、driver、sequencer,并根据不同状态的monitor实例化不同的monitor。

class my_agent extends uvm_agent;
	my_sequencer sqr;
	my_driver drv;
	my_monitor mon;
	
	uvm_analysis_port #(my_transaction) ap;
	function new(string name = "my_agent", uvm_component parent = NULL)
		super.new(name, parent);
	endfuntion
	
	funtion void build_phase(uvm_phase phase);
		super.build_phase(phase);
		if(is_active == UVM_ACTIVE) begin
			sqr = my_squencer::type_id::create("sqr", this);
			drv = my_driver::type_id::create("drv",this);
		end
		mon = my_monitor::type_id::create("mon",this);
	endfunction
	
	funtion void connect_phase(uvm_phase phase);
		super.connect_phase(phase);
		if(is_active == UVM_ACTIVE) begin
			drv.seq_item_port.connect(sqr.seq_item_export);
		end;
		ap = mon.ap;
	endfunction

	'uvm_component_utils(my_agent);
endclass

reference model

这个模块用于接收agent中monitor模块传输的数据,并将这个数据传输给scoreboard

class my_model extends uvm_model;
	uvm_blocking_get_port #(my_transaction) port;
	uvm_analysis_port #(my_transacion) ap;

	function new(string name = "my_model", uvm_component parent);
		super.new(name, parent);
	endfuntion

	function void build_phase(uvm_phase phase);
		super.build_phase(phase);
		port = new("port", this);
		ap = new("ap", this);
	endfuntion

	virtual task main_phase(uvm_phase phase);
		my_transaction tr;
		super.main_phase(phase);
		while(1) begin
			port.get(tr);
			tr.print();
			ap.write(tr);
		end
	endfuntion
	'uvm_component_utils(my_model);
endclass

scoreboard

这个模块主要是用来比较来自reference model和DUT的输出是否一致。

class my_scoreboard extends uvm_scoreboard;
	my_transaction expect_queue[$];
	uvm_blocking_get_port #(my_transaction) exp_port;
	uvm_blocking_get_port #(my_transaction) act_port;
	'uvm_component_utils(my_scoreboard)

	function new(string name = "my_scoreboard", uvm_component parent = NULL);
		super.new(name, parent);
	endfunction
	
	virtual function void build_phase(uvm_phase phase);
		super.build_phase(phase);
		exp_port = new("exp_port", this);
		act_port = new("act_port", this);
	endfunction
	
	extern virtual task main_phase(uvm_phase phase);
endclass

task my_scoreboard::main_phase(uvm_phase phase);
	my_transaction get_expect, get_actual, tmp_tran;
	bit result;
	super.main(phase);

	fork
		while(1) begin
			exp_port.get(get_expect);
			expect_queue.push_back(get_expect);
		end
		while(1) begin
			act_port.get(get_actual);
			if(expect_queue.size() > 0) begin
				temp_tran = expect_queue.pop_front();
				result = get_actual.compare(tem_tran);
				if(result) begin
					'uvm_info("my_socreboard", "compare successfully", UVM_LOW);
				end
				else begin
					'uvm_error("my_scoreboard", "compare falled");
				end
				else
					'uvm_error("my_scoreboard", "received from dut, while expect queue is empty");
			end
		end
	join
endtask
		

env

这是一个大容器,处于UVM树的最高层,控制着其他资源的实例化,并且通过fifo将reference model与dut输出结果和scoreboard相连。

class my_env extends uvm_env;
	my_agent i_agt;
	my_agent o_agt;
	my_model mdl;
	my_socerboard scb;
	
	uvm_tlm_analysis_fifo #(my_transaction) agt_scb_fifo;
	uvm_tlm_analysis_fifo #(my_transaction) agt_mdl_fifo;
	uvm_tlm_analysis_fifo #(my_transaction) mdl_scb_fifo;

	function new(string name = "my_env", uvm_component parent);
		super.new(name, parent);
	endfuntion

	virtual function void build_phase(uvm_phase phase);
		super.build_phase(phase);
		i_agt = new("i_agt", this);
		o_agt = new("o_agt", this);
		i_agt.is_active = UVM_ACTIVE;
		o_agt.is_active = UVM_PASSIVE;
		mdl = new("mdl", this);
		scb = new("scb", this);
		agt_scb_fifo = new("agt_scb_fifo", this);
		agt_mdl_fifo = new("agt_mdl_fifo", this);
		mdl_scb_fifo = new("mdl_scb_fifo", this);
	endfunction
	
	virtual function void connect_phase(uvm_phase);
		super.connect_phase(phase);
		i_agt.ap.connect(agt_mdl_fifo.analysis_export);
		mdl.port.connect(agt_mdl_fifo.blocking_get_export);
		mdl.ap.connect(mdl_scb_fifo.analysis_export);
		scb.exp_port.connect(mdl_scb_fifo.blocking_get_export);
		o_agt.ap.connect(agt_scb_fifo.analysis_export);
		scb.act_port.connect(agt_acb_fifo.blocking_get_export);
	endfuntion
endclass

sequence

用来产生数据并传输给sequencer,sequencer收到后传输给driver,这里有两种启动方式,一种是在env的main_phase中启动,一种是在自己的main_phase中启动。

class my_sequence extends uvm_sequence #(my_transaction);
	my_transaction m_trans;
	function new(string name = "my_sequence");
		super.new(name);
	endfunction

	virtual task body();
		if(starting_phase != null)
			starting_phase.raise_objection(this);
		repeat(10) begin
			'uvm_do(m_trans)
		end
		#1000;
		else
			starting_phase.drop_objection(this);
	endtask
	
	'uvm_object_utils(my_sequence)
endclass

case

一般在my_test里实例化env,在my_case里使用set使不同的sequence自启动。

class my_test extends uvm_test;
	my_env env;
	function new(string name = "my_test", uvm_component parent = NULL);
		super.new(name, parent);
	endfuntion
	
	virtual funtion void build_phase(uvm_phase);
		super.build_phase(phase);
		env = new("env", this);
	endfuncion
endclass
class my_case0 extends base_test;
	funtion new(string name = "my_case0", uvm_component parent = NULL);
		super.new(name, parent);
	endfunction
	
	virtual funtion void build_phase(uvm_phase phase);
		super.build_phase(phase);
		uvm_config_db#(uvm_object_wrapper)::set(this, "env.i_agt.sqr.main_phase", "default_sequence", case0_sequence::type_id::get());
	endfunction 
endclass

top

系统仿真时,首先进入top,当运行run_test时根据编译输入的命令实例化具体的case,在case里实例化env,env再实例化整个UVM树形结构。

`timescale 1ns/1ps
`include "uvm_macros.svh"
 
import uvm_pkg::*;
`include "my_if.sv"
`include "my_transaction.sv"
`include "my_driver.sv"
`include "my_monitor.sv"
`include "my_sequencer.sv"
`include "my_agent.sv"
`include "my_model.sv"
`include "my_scoreboard.sv"
`include "my_env.sv"
`include "base_test.sv"
`include "my_case0.sv"
`include "my_case1.sv"

module top_db;

reg clk;
reg rst_n;
my_if input_if(clk, rst_n);
my_if output_if(clk, rst_n);

dut my_dut(.clk(clk),
            .rst_n(rst_n),
            .rxd(input_if.data),
            .rx_dv(input_if.valid),
            .txd(output_if.data),
            .tx_en(output_if.valid));

initial begin
	clk = 0;
	forever begin
		#100 clk = ~clk;
	end
end

initial begin
	run_test();
end

initial begin
	uvm_config_db#(virtual my_if)::set(null,"uvm_test_top.env.i_agt.drv", "vif", input_if);
	uvm_config_db#(virtual my_if)::set(null,"uvm_test_top.env.i_agt.mon", "vif", input_if);
	uvm_config_db#(virtual my_if)::set(null,"uvm_test_top.env.i_agt.mon", "vif", output_if);
end

initial begin
       $shm_open("test.shm");
       $shm_probe(top_tb,"ACTFM");
       #1ms;
       $shm_close;
end
endmodule
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值