【System Verilog and UVM基础入门6】UVM寄存器模型

UVM寄存器模型


从小父亲就教育我,要做一个对社会有用的人!

目录

UVM寄存器模型

Part 1.概述

Part 2.set()和update()

Part 3.访问方式

Part 4.深入理解


VCS ralgen 可以自动生成寄存器模型!本文就以ral_tommi.sv文件举例,理解寄存器模型!想想寄存器模型的存在意义!

Part 1.概述

硬件中的各个功能模块可以由处理器来配置功能以及访问状态,而与处理器的对话即是通过寄存器的读写来实现的。

一个寄存器一般由32比特位构成,单个拆分,可以分为多个field!,对于外部读写而谈,可以分为,WO,RO,RW。

这些寄存器按照地址排列,既可以构成寄存器列表,我们称之为寄存器块(register block)

class ral_block_Global_Registers extends uvm_reg_block;
	rand ral_reg_Global_Registers_FPGA_VER FPGA_VER;
	rand ral_reg_Global_Registers_FPGA_SUBVER FPGA_SUBVER;
   local uvm_reg_data_t m_offset;
	uvm_reg_field FPGA_VER_Project;
	uvm_reg_field Project;
	uvm_reg_field FPGA_VER_FPGA;
	uvm_reg_field FPGA;
	uvm_reg_field FPGA_VER_Major;
	uvm_reg_field Major;
	uvm_reg_field FPGA_VER_Minor;
	uvm_reg_field Minor;
	uvm_reg_field FPGA_VER_Branch;
	uvm_reg_field Branch;
	uvm_reg_field FPGA_SUBVER_FPGA_Subversion;
	uvm_reg_field FPGA_Subversion;

然后结合用IE浏览器打开的(寄存器描述文档)xml文件,当然你也可以转换成CSV格式(Excel)。

Table: Global_Registers Register Summary
AddressRegister NameRegister Description
0xA100_0000FPGA_VERRevision Register - Note the value read will depend on the revision of the FPGA
0xA100_0004FPGA_SUBVERFPGA Subversion Register

Field:project

Bits: 31..20
Type: ro
Init Value: 0x542

...

Field:FPGA

Bits: 19..16
Type: ro
Init Value: 0x2

...

接着看看代码上是怎么写的!

  class ral_reg_Global_Registers_FPGA_VER extends uvm_reg;
	uvm_reg_field Project;
	uvm_reg_field FPGA;
	uvm_reg_field Major;
	uvm_reg_field Minor;
	uvm_reg_field Branch;

	function new(string name = "Global_Registers_FPGA_VER");
		super.new(name, 32,build_coverage(UVM_NO_COVERAGE));
	endfunction: new
   virtual function void build();
      this.Project = uvm_reg_field::type_id::create("Project",,get_full_name());
      this.Project.configure(this, 12, 20, "RO", 0, 12'h542, 1, 0, 0);
      this.FPGA = uvm_reg_field::type_id::create("FPGA",,get_full_name());
      this.FPGA.configure(this, 4, 16, "RO", 0, 4'h2, 1, 0, 0);
      this.Major = uvm_reg_field::type_id::create("Major",,get_full_name());
      this.Major.configure(this, 4, 12, "RO", 0, 4'h4, 1, 0, 0);
      this.Minor = uvm_reg_field::type_id::create("Minor",,get_full_name());
      this.Minor.configure(this, 8, 4, "RO", 0, 8'h05, 1, 0, 0);
      this.Branch = uvm_reg_field::type_id::create("Branch",,get_full_name());
      this.Branch.configure(this, 4, 0, "RO", 0, 4'h0, 1, 0, 0);
   endfunction: build

值得注意的是uvm_reg_map    

function void sample(uvm_reg_addr_t offset,
                     bit            is_read,
                     uvm_reg_map    map);
  if (get_coverage(UVM_CVR_ADDR_MAP)) begin
    m_offset = offset;
    cg_addr.sample();
  end
endfunction
endclass : ral_block_Global_Registers
类名功能
uvm_reg_field用来针对寄存器功能域来构建对应的比特位
uvm_reg与寄存器匹配,其内部可以例化和配置多个uvm_reg_field 对象
uvm_mem匹配硬件存储模型
uvm_reg_map用来指定寄存器列表中各个寄存器的偏移地址、访问属性以及对应的总线
uvm_reg_block用来容纳多个寄存器(uvm_reg),存储器(uvm_mem)和寄存器列表(uvm_reg_map)

      virtual function void build();
      this.default_map = create_map("", 0, 4, UVM_LITTLE_ENDIAN, 0);
      this.FPGA_VER = ral_reg_Global_Registers_FPGA_VER::type_id::create("FPGA_VER",,get_full_name());
      this.FPGA_VER.configure(this, null, "");
      this.FPGA_VER.build();
      this.default_map.add_reg(this.FPGA_VER, `UVM_REG_ADDR_WIDTH'h0, "RO", 0);
		this.FPGA_VER_Project = this.FPGA_VER.Project;
		this.Project = this.FPGA_VER.Project;
		this.FPGA_VER_FPGA = this.FPGA_VER.FPGA;
		this.FPGA = this.FPGA_VER.FPGA;
		this.FPGA_VER_Major = this.FPGA_VER.Major;
		this.Major = this.FPGA_VER.Major;
		this.FPGA_VER_Minor = this.FPGA_VER.Minor;
		this.Minor = this.FPGA_VER.Minor;
		this.FPGA_VER_Branch = this.FPGA_VER.Branch;
		this.Branch = this.FPGA_VER.Branch;
      this.FPGA_SUBVER = ral_reg_Global_Registers_FPGA_SUBVER::type_id::create("FPGA_SUBVER",,get_full_name());
      this.FPGA_SUBVER.configure(this, null, "");
      this.FPGA_SUBVER.build();
      this.default_map.add_reg(this.FPGA_SUBVER, `UVM_REG_ADDR_WIDTH'h4, "RO", 0);
		this.FPGA_SUBVER_FPGA_Subversion = this.FPGA_SUBVER.FPGA_Subversion;
		this.FPGA_Subversion = this.FPGA_SUBVER.FPGA_Subversion;
   endfunction : build

 每个寄存器的访问,都要在add_reg中添加它!因为考虑到寄存器模型是用EDA工具生成的因素,所以很多的细节我没有提到!


Part 2.set()和update()

首先set()方法的对象是寄存器本身,通过set()可以修改期望值,而在寄存器配置时不妨先对其模型随机化,在配置个别寄存器或者域,当寄存器的期望值与镜像值不相同时,可以通过update()方法来将不相同的寄存器通过前门或者后门访问的方式做全部修改。

工作中,也遇到过这样的问题,通常,我会选择用write()的方式。·

In our register model, we have mirror value and desired value. 
If we want to write 1 to this register, we could use write(‘h1),  mirror value and desired value are both update.
Another way, we could use set(‘h1), desired value ‘h1, but mirror value not change. So we need invoke update(),update() will check desired value and mirror value whether fit.
If not fit, update() will write desired value to DUT, and update mirror value.
So I think it is mainly reason :

“…  This tells me that because my write value(desire
value 0) is the same as what is in the register model(mirror value 0), it does
not actually do a bus write.  So I worked around it by setting values to
1, do update, and then set back to 0, another update, and that seems to work.”


Part 3.访问方式

前门访问(front-door),和后门访问(back-door)

前门访问,顾名思义是在寄存器模型上做的读写操作!最终会通过总线UVC来实现总线上的物理时序访问,因此是真实的物理操作!

  1. uvm_reg::read()/write()
  2. uvm_reg_sequence::read_reg()/write_reg()

后门访问,指的是利用UVM DPI(uvm_hdl_read())将寄存器的操作直接作用到DUT内的寄存器变量,而不是通过物理总线的访问!不消耗时间!

在进行后门访问时,用户首先要确保寄存器模型在建立时,是否将各个寄存器映射到了DUT一侧的HDL路径。

// 前门访问
class tommi_example_seq extends uvm_reg_sequence;
  tommi_rgm rgm;
  `uvm_object_utils(tommi_example_seq)
  `uvm_declare_p_sequencer(tommi_example_seq)
  ...
  task body();
    uvm_status_e status;
    uvm_reg_data_t data;
    if(!uvm_config_db#(tommi_rgm)::get(null,get_full_name(),"rgm",rgm))begin 
      `uvm_error("GETRGM", "no top_down RGM handle is assigned")
    end
    
    // register model access write()/read()
    rgm.chnl0_ctrl_reg.read(status,data,UVM_FRONTDOOR,.parent(this));
    rgm.chnl0_ctrl_reg.write(status,'h11,UVM_FRONTDOOR,.parent(this));
    rgm.chnl0_ctrl_reg.read(status,data,UVM_FRONTDOOR,.parent(this));
    // pre-define methods access
    read_reg(rgm.chnl1_ctrl_reg,status,data,UVM_FRONTDOOR);
    read_reg(rgm.chnl1_ctrl_reg,status,'h22,UVM_FRONTDOOR);
    read_reg(rgm.chnl1_ctrl_reg,status,data,UVM_FRONTDOOR);
  endtask
endclass

前门访问后门访问
通过总线协议访问需要耗时,且在总线访问结束时才能结束前门访问通过UVM DPI关联硬件寄存器哦信号路径,直接读取或修改硬件,不需要访问时间,零时科相应
一般读写只能按字(word)读写,无法直接读写寄存器域可以对寄存器或寄存器域直接做读写
依靠监测总线来对寄存器模型内容做预测依靠auto prediction 方式自动对寄存器内容做预测
正确反映了时序关系不受硬件时序控制。对硬件做的后门访问可能发生时序冲突
通过总线协议,可以有效捕捉总线错误,继而验证总线访问路径不受总线时序功能影响


Part 4.深入理解

寄存器模型中的每一个field,都有2个值!镜像值mirrired value和期望值desired value

状态寄存器的镜像值就无法与硬件实际值actual value保持同步更新!

期望值是先利用寄存器模型修改软件对象值,而后利用该值更新硬件值;镜像值是表示当前硬件的已知状态值。

期望值desired value先去更新软件model的期望值,再去更新硬件的actual value,然后更新软件model测得mirror value.(没有理解!)


Part 5.寄存器模型内建序列

序列禁止域名测试级别说明
uvm_reg_hw_reset_seqNO_REG_HW_RESRT_TEST

uvm_reg_block

uvm_reg

检查寄存器模型服为止是否与硬件复位值一致
uvm_reg_single_bit_bash_seqNO_REG_BIT_BASH_TESTuvm_reg检查所有支持读写访问的域,对每一个可读写域分别写入1和0并且读出后作比较,用来检查寄存器域属性的有效性
uvm_reg_bit_bash_seqNO_REG_BIT_BASH_TESTuvm_reg_block对包含的所有uvm_reg或者子uvm_reg_block执行uvm_reg_single)bit_bash_seq检查
uvm_reg_single_access_seqNO_REG_ACCESS_TESTuvm_reg先从前门写入寄存器,而后从后门读回数值比对;接下来从后门写入寄存器,又从前门读回写入之比对。这种方式要求寄存器的HDL路径已经完成映射,用来检查寄存器映射的有效性
uvm_reg_access_NO_REG_ACCESS_TESTNO_REG_ACCESS_TESTuvm_reg_block对包含的所有uvm_reg都执行uvm_reg_single_access_seq
uvm_reg_shared_access_seqNO_SHARED_ACESS_TESTuvm_reg针对uvm_reg被包含在多个uvm_reg_map中时,先从一个map写入数值,其后从所有的map中读回这个寄存器数值,用来检查所有可能访问寄存器路径的有效性

欢迎大家一起讨论学习!需要相关文档资料的同学可以给我发邮件!

tommi.wei@qq.com

振兴中华 


任何问题可以和我联系!推荐大家阅读张强的UVM实战白皮书和刘斌的验证漫游指南红宝书!

  • 0
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值