目录
1.2 在mcdf_env中声明并例化block、adapter、predictor,最后connect起来
2.2 mcdf_data_consistence_basic_virtual_sequence类中原来是由总线seq实现的reg读写,现在改为又rgm操作的reg读写方式
2.3 mcdf_full_random_virtual_sequence做相同的操作
UVM入门实验5
实验目标
问题清单
- 什么是uvm_reg类?
- 用来例化和配置reg中各个field
- 如何定义uvm_reg?
- 是一个class,各个子类继承于它。子类(控制寄存器+只读寄存器)在完成field的声明后需要new函数和build函数(例化与配置都在build中)
- 声明,例化和配置field的语句是什么?
uvm_reg_field reserved;
rand uvm_reg_field pkt_len;//声明域,且可以随机化
rand uvm_reg_field prio_level;
rand uvm_reg_field chnl_en;
reserved = uvm_reg_field::type_id::create("");
pkt_len = uvm_reg_field::type_id::create("");
prio_level = uvm_reg_field::type_id::create("");
chnl_en = uvm_reg_field::type_id::create("");//例化
reserved.configure(this, 26, 6, "RO", 0, 26'h0, 1, 0 , 0);//配置
pkt_len.configure(this,3,3,"RW",0,3'h0,1,1,0);//前两个表示位,后面的具体数表示默认值
prio_level.configure(this,2,1,"RW",0,2'h3,1,1,0);
chnl_en.configure(this,1,0,"RW",0,1'h0,1,1,0);
- 什么是uvm_reg_block?
- 一个class包含了map,rgm和mem
- 什么是uvm_reg_adapter?
- 完成rgm到硬件reg的桥接,将reg_item转换成总线UVC需要的信息bus_seq_item,再由总线给到硬件reg
- 如何编写adapter?
- 主要是定义2个reg和bus之间的函数
class reg2mcdf_adapter extends uvm_reg_adapter;
`uvm_object_utils()
function new(string name ="");
super.new(name);
provides_responses=1;//enable了provides_responses,总线可以返回rsp的数据
endfunction
//预定义的,也是必须实现的,名字一个字都不能差
function uvm_sequence_item reg2bus (const ref uvm_reg_bus_op rw);
mcdf_bus_trans t=mcdf_bus_trnas::type_id::create("t");//创建子类对象
t.cmd=(rw.kind == UVM_WRITE)? `WRITE : `READ;
t.addr=rw.addr;
t.wdata=rw.data;
return t;//做了隐式转换
endfunction//完成了寄存器级别操作rw到bus上的桥接,下面的func反之
function void bus2reg(uvm_sequence_item bus_item, ref uvm_reg_bus_op rw);
//从driver将数据写会sequencer,adapter从sqr拿到rsp(t)后自动调用
mcdf_bus_trans t;
if(!$cast(t, bus_item)) begin//父类句柄,转换成子类mcdf_bus_trans句柄
`uvm_fatal("", "")
return; end
rw.kind=(t.cmd==`WRITE)? UVM_WRITE : UVM_READ;//转换后才可以访问子类对象
rw.addr=t.addr;
rw.data=(t.cmd==`WRITE)? t.wdata : t.rdata;
rw.status=UVM_IS_OK;
endfunction
endclass
- 实现了adapter之后,如何将其集成到环境中?
- 从test层传入寄存器模型rgm句柄,在顶层例化后通过uvm_config_db进行配置
- rgm在创建后要调用build()函数,因为uvm_reg_block是object类型,其预定义的build()不会自动执行
- 顶层连接时,需要将rgm的map组件和bus sequencer和adapter连接(reg信息-总线侧激励驱动-reg级别和硬件总线级别的桥接),adapter的桥接功能才可以工作
class mcdf_bus_env extends uvm_env;
mcdf_bus_agent agent;
mcdf_rgm rgm;
reg2mcdf_adapter reg2mcdf;//先声明
...//注册+例化
function void build_phase(u p);
agent=mcdf_bus_agent::type_id::create("", this);
if(!uvm_config_db#(mcdf_rgm)::get(this, "", "rgm", rgm)) begin
`uvm_info()
rgm=mcdf_rgm::type_id::create("", this);
end
rgm.build();//创建,配置reg,调用各个reg的build,以及它们的field
rgm.map.set_auto_predict();//还没集成predictor,所以调用set_auto_predict(),采用auto prediction方式
reg2mcdf=reg2mcdf_adapter::type_id::create("");//例化adapter
endfunction
function void connect_phase(u p);
rgm.map.set_sequencer(agent.sequencer, reg2mcdf);//!连接:将adapter连接到sequencer上
endfunction
endclass
class test1 extends uvm_test;
mcdf_rgm rgm;
mcdf_bus_env env;
...//注册+例化
function void build_phase(u p);
rgm=mcdf_rgm::type_id::create("", this);
uvm_config_db#(mcdf_rgm)::set(this, "env*", "rgm", rgm)
env=mcdf_bus_env::type_id::create("", this);
endfunction
task run_phase(u p); ...
endclass
- uvm_reg_adapter和uvm_reg_block的关系?
- block>rgm>map>adapter
- uvm_reg_predictor是什么?
- 跟踪寄存器值,分为自动预测ap和显式预测ep
- 显式预测ep其实就是在物理总线上用monitor来捕捉trans,通过analysis port传递给在外部例化的predictor(集成在顶层环境),集成时需要将adapter和map的句柄也传给predictor
//和上一段代码的差别并不大,注释的部分就是新加的
class mcdf_bus_env extends uvm_env;
mcdf_bus_agent agent;
mcdf_rgm rgm;
reg2mcdf_adapter reg2mcdf;
uvm_reg_predictor mcdf2reg_predictor;//先声明
...
function void build_phase(u p);
agent=mcdf_bus_agent::type_id::create("", this);
if(!uvm_config_db#(mcdf_rgm)::get(this, "", "rgm", rgm)) begin
`uvm_info()
rgm=mcdf_rgm::type_id::create("", this);
end
rgm.build();
mcdf2reg_predictor=uvm_reg_predictor::type_id::create("",this);//例化
reg2mcdf=reg2mcdf_adapter::type_id::create("");
mcdf2reg_predictor.map=rgm.map;//把rgm的map给到predictor的map
mcdf2reg_predictor.adapter=reg2mcdf;//把rgm的adapter给到predictor的map
endfunction
function void connect_phase(u p);
rgm.map.set_sequencer(agent.sequencer, reg2mcdf);
agent.monitor.ap.connect(mcdf2reg_predictor.bus_in);//!连接:将adapter连接到sequencer上
endfunction
endclass
- adapter,block,predictor三者的关系是什么?
- 见示意图
- 如何用uvm_reg的操作方式去发送reg序列?
- 如何用内建寄存器序列做全面的reg测试?
- 在body()中例化内建序列,将rgm给到内建序列的model并调用序列的start即可,参数是m_sequencer
- 放置功能覆盖率covergroup在rgm中,通过reg model generator的功能可以使生成的rgm模型自动包含各个field的功能覆盖率,rgm已经内置了方法来使能covergroup,同时调用读写方法时会自动调用covergroup::sample()完成功能覆盖率的收集
class mcdf_example_seq extends uvm_reg_sequence;
mcdf_rgm rgm;
`uvm_object_utils()
`uvm_declare_p_sequencer()
...
task body();
uvm_status_e status;
uvm_reg_data_t data;
uvm_reg_hw_reset_seq reg_rst_seq=new();//先例化
uvm_reg_bit_bash_seq reg_bit_bas_seq=new();
uvm_reg_access_seq reg_acc_seq=new();
if(!uvm_config_db#(mcdf_rgm)::get(null, get_full_name(), "rgm", rgm)) begin
`uvm_error() end
@(negedge p_sequencer.vif.rstn);
@(posedge p_sequencer.vif.rstn);
`uvm_info()
reg_rst_seq.model=rgm;//给模型
reg_rst_seq.start(m_sequencer);//start即可
`uvm_info()
`uvm_info()
reg_bit_bash_seq.model=rgm;
reg_bit_bash_seq.start(m_sequencer);
`uvm_info()
`uvm_info()
reg_acc_seq.model=rgm;
reg_acc_seq.start(m_sequencer);
`uvm_info()
endtask
endclass
- reg功能覆盖率收集方式1:内部自动收集
//缺点:默认采样所有field,不够灵活不够智能
class ctrl_reg extends uvm_reg;
`uvm_object_utils(ctrl_reg)
uvm_reg_field reserved;
rand uvm_reg_field pkt_len;
rand uvm_reg_field prio_level;
rand uvm_reg_field chnl_en;
covergroup value_cg;//定义一个覆盖组
option.per_instance=1;
reserved: coverpoint reserved.value[25: