目录
RAL(Register Abstract Layer,寄存器抽象层),也被称之为寄存器模型,顾名思义就是对寄存器这个部件的建模。本文主要内容包括:为何应用寄存器模型,UVM寄存器模型基础概念,如何构建寄存器模型,如何将寄存器模型实例到验证环境中。
一,为何应用寄存器模型
前面,我们提到,寄存器的使用,在如今的design 中十分普遍。对于实际的DUT, 我们可以选择不同的配置组合,达到DUT 实现不同的功能,比如配置不同的寄存器功能,实现不同的状态机跳转,进而实现不同的功能。有些人把这种design 方式,称之为 基于寄存器的设计。我们身为DV人员,当然着重关注我们验证人员该关注的事情。
寄存器设计,作为DUT 设计的一部分,当然在整个design Verification 过程中,也是验证人员必须面对和打交道的一部分。对REG 的读写配置,包括验证覆盖率的统计,都是值得验证人员该花功夫考虑的问题,也是项目signoff 阶段,项目验收的环节之一。
大部分DUT设计,对于内部寄存器的access, 大部分公司都会选择当今比较流行总线方式。一方面,选取标准的寄存器配置总线协议,可以加速项目迭代;另一方面,选取标准的协议,一般都会购买第三方IP,可以保证很好的quality。比如:I2C,SPI,AXI,AHB 、APB等总线 ,复杂到PCIE、SATA、GMI 等复杂协议。
实际激励中,不仅包括接口正常transaction,还有寄存器的读写激励,所以有必要针对寄存器的access , 构建寄存器访问机制,方便验证环境的搭建和集成,加速项目的验收。
为什么要对寄存器建模,可能是初学者问得较多的问题。简单地说,寄存器建模要做的事情,就是在软件的世界里面,复刻RTL中的寄存器。既然是面向软件世界做的事情,自然就是为软件所用,要么方便软件观测,要么方便软件使用。这里的软件,指的是整个验证环境所构造出来的面向对象的世界。有了寄存器模型,软件世界中的参考模型(reference model)可以很方便的获取到当前RTL的功能配置和状态,也可以很方便的收集到对寄存器各个域段甚至位的测试覆盖情况等。
二,寄存器模型基础概念
2.1 uvm_reg_field
这是寄存器模型中的最小单位。什么是reg_field?假如有一个状态寄存器,
如上的状态寄存器共有四个域,分别是empty、full、overflow、underflow。这四个域对应寄存器模型中的uvm_reg_field。名字reserved”的并不是一个域。
uvm_reg_field 源码分析:
1)属性声明
2)方法声明
2.2 uvm_reg
它比uvm_reg_field高一个级别,依然是比较小的单位。一个寄存器中至少包一个uvm_reg_field。
uvm_reg源码概览:
1)属性声明
2)方法声明
extern virtual function void set_offset (uvm_reg_map map,
/*local*/ extern virtual function void set_parent (uvm_reg_block blk_parent,
/*local*/ extern virtual function void add_field (uvm_reg_field field);
/*local*/ extern virtual function void add_map (uvm_reg_map map);
extern virtual function string get_full_name();
extern virtual function uvm_reg_block get_parent ();
extern virtual function uvm_reg_block get_block ();
extern virtual function uvm_reg_file get_regfile ();
extern virtual function int get_n_maps ();
extern virtual function void get_maps (ref uvm_reg_map maps[$]);
/*local*/ extern virtual function uvm_reg_map get_local_map (uvm_reg_map map,
/*local*/ extern virtual function uvm_reg_map get_default_map (string caller = "");
extern virtual function string get_rights (uvm_reg_map map = null);
extern virtual function int unsigned get_n_bits ();
extern virtual function int unsigned get_n_bytes();
extern virtual function void get_fields (ref uvm_reg_field fields[$]);
extern virtual function uvm_reg_field get_field_by_name(string name);
extern virtual function uvm_reg_addr_t get_offset (uvm_reg_map map = null);
extern virtual function uvm_reg_addr_t get_address (uvm_reg_map map = null);
extern virtual function int get_addresses (uvm_reg_map map = null,
extern virtual function void set (uvm_reg_data_t value,
extern virtual function uvm_reg_data_t get(string fname = "",
extern virtual function uvm_reg_data_t get_mirrored_value(string fname = "",
extern virtual function bit needs_update();
extern virtual function void reset(string kind = "HARD");
extern virtual function uvm_reg_data_t
extern virtual function bit has_reset(string kind = "HARD",
extern virtual function void
extern virtual task write(output uvm_status_e status,
extern virtual task read(output uvm_status_e status,
extern virtual task poke(output uvm_status_e status,
extern virtual task peek(output uvm_status_e status,
extern virtual task update(output uvm_status_e status,
extern virtual task mirror(output uvm_status_e status,
extern virtual function bit predict (uvm_reg_data_t value,
/*local*/ extern virtual function bit Xcheck_accessX
extern virtual function bit do_check(uvm_reg_data_t expected,
extern virtual task do_write(uvm_reg_item rw);
extern virtual task do_read(uvm_reg_item rw);
extern virtual function void do_predict
extern virtual task backdoor_read(uvm_reg_item rw);
extern virtual task backdoor_write(uvm_reg_item rw);
extern virtual function uvm_status_e backdoor_read_func(uvm_reg_item rw);
extern virtual protected function void add_coverage(uvm_reg_cvr_t models);
extern virtual function bit has_coverage(uvm_reg_cvr_t models);
extern virtual function uvm_reg_cvr_t set_coverage(uvm_reg_cvr_t is_on);
extern virtual function bit get_coverage(uvm_reg_cvr_t is_on);
extern virtual function void do_print (uvm_printer printer);
extern virtual function string convert2string();
extern virtual function uvm_object clone ();
extern virtual function void do_copy (uvm_object rhs);
extern virtual function bit do_compare (uvm_object rhs,
extern virtual function void do_pack (uvm_packer packer);
extern virtual function void do_unpack (uvm_packer packer);
2.3 uvm_reg_block
它是一个比较大的单位,在其中可以加入许多的uvm_reg,也可以加入其他的uvm_reg_block。一个寄存器模型中至少包含一个uvm_reg_block。
同uvm_reg派生的类一样,每一个由uvm_reg_block派生的类也要定义一个build函数,一般在此函数中实现所有寄存器的实例化。
一个uvm_reg_block中一定要对应一个uvm_reg_map,系统已经有一个声明好的default_map,只需要在build中将其实例化。这个实例化的过程并不是直接调用uvm_reg_map的new函数,而是通过调用uvm_reg_block的create_map来实现,create_map有众多的参数,其中第一个参数是名字,第二个参数是基地址,第三个参数则是系统总线的宽度,这里的单位是byte而不是bit,第四个参数是大小端,最后一个参数表示是否能够按照byte寻址。
随后实例化invert并调用invert.configure函数。这个函数的主要功能是指定寄存器进行后门访问操作时的路径。其第一个参数是此寄存器所在uvm_reg_block的指针,这里填写this,第二个参数是reg_file的指针(7.4.2节将会介绍reg_file的概念)这里暂时填写null,第三个参数是此寄存器的后门访问路径,关于这点请参考7.3节,这里暂且为空。当调用完configure时,需要手动调用
invert的build函数,将invert中的域实例化。
最后一步则是将此寄存器加入default_map中。uvm_reg_map的作用是存储所有寄存器的地址,因此必须将实例化的寄存器加入default_map中,否则无法进行前门访问操作。add_reg函数的第一个参数是要加入的寄存器,第二个参数是寄存器的地址,这里是16’h9,第三个参数是此寄存器的存取方式。
uvm_reg_block 源码概览:
1)属性声明
2)方法声明
extern virtual function uvm_reg_map create_map(string name,
extern virtual function void set_parent(uvm_reg_block parent);
extern virtual function void lock_model();
extern virtual function string get_full_name();
extern virtual function uvm_reg_block get_parent();
extern virtual function void get_blocks (ref uvm_reg_block blks[$],
extern virtual function void get_maps (ref uvm_reg_map maps[$]);
extern virtual function void get_registers (ref uvm_reg regs[$],
extern virtual function void get_fields (ref uvm_reg_field fields[$],
extern virtual function void get_memories (ref uvm_mem mems[$],
extern virtual function void get_virtual_registers(ref uvm_vreg regs[$],
extern virtual function void get_virtual_fields (ref uvm_vreg_field fields[$],
extern virtual function uvm_reg_block get_block_by_name (string name);
extern virtual function uvm_reg_map get_map_by_name (string name);
extern virtual function uvm_reg get_reg_by_name (string name);
extern virtual function uvm_reg_field get_field_by_name (string name);
extern virtual function uvm_mem get_mem_by_name (string name);
extern virtual function uvm_vreg get_vreg_by_name (string name);
extern virtual function uvm_vreg_field get_vfield_by_name (string name);
extern virtual protected function void add_coverage(uvm_reg_cvr_t models);
extern virtual function bit has_coverage(uvm_reg_cvr_t models);
extern virtual function uvm_reg_cvr_t set_coverage(uvm_reg_cvr_t is_on);
extern virtual function bit get_coverage(uvm_reg_cvr_t is_on = UVM_CVR_ALL);
extern virtual function void sample_values();
extern virtual function uvm_path_e get_default_path();
extern virtual function void reset(string kind = "HARD");
extern virtual function bit needs_update();
extern virtual task update(output uvm_status_e status,
extern virtual task mirror(output uvm_status_e status,
extern virtual task write_reg_by_name(
extern virtual task read_reg_by_name(
extern virtual task write_mem_by_name(
extern virtual task read_mem_by_name(
extern virtual task readmemh(string filename);
extern virtual task writememh(string filename);
extern virtual function void do_print (uvm_printer printer);
extern virtual function void do_copy (uvm_object rhs);
extern virtual function bit do_compare (uvm_object rhs,
extern virtual function void do_pack (uvm_packer packer);
extern virtual function void do_unpack (uvm_packer packer);
extern virtual function string convert2string ();
extern virtual function uvm_object clone();
2.4 uvm_reg_map
每个寄存器在加入寄存器模型时都有其地址,uvm_reg_map就是存储这些地址,并将其转换成可以访问的物理地址(因为加入寄存器模型中的寄存器地址一般都是偏移地址,而不是绝对地址)。当寄存器模型使用前门访问方式来实现读或写操作时,uvm_reg_map就会将地址转换成绝对地址,启动一个读或写的sequence,并将读或写的结果返回。在每个reg_block内部,至少有一个(通常也只有一个)uvm_reg_map。
extern virtual function void add_reg (uvm_reg rg,
extern virtual function void add_mem (uvm_mem mem,
extern virtual function void add_submap (uvm_reg_map child_map,
extern virtual function void set_sequencer (uvm_sequencer_base sequencer,
extern virtual function void set_submap_offset (uvm_reg_map submap,
extern virtual function uvm_reg_addr_t get_submap_offset (uvm_reg_map submap);
extern virtual function void set_base_addr (uvm_reg_addr_t offset);
extern virtual function void reset(string kind = "SOFT");
/*local*/ extern virtual function void add_parent_map(uvm_reg_map parent_map,
/*local*/ extern virtual function void Xverify_map_configX();
/*local*/ extern virtual function void m_set_reg_offset(uvm_reg rg,
/*local*/ extern virtual function void m_set_mem_offset(uvm_mem mem,
extern virtual function string get_full_name();
extern virtual function uvm_reg_map get_root_map();
extern virtual function uvm_reg_block get_parent();
extern virtual function uvm_reg_map get_parent_map();
extern virtual function uvm_reg_addr_t get_base_addr (uvm_hier_e hier=UVM_HIER);
extern virtual function int unsigned get_n_bytes (uvm_hier_e hier=UVM_HIER);
extern virtual function int unsigned get_addr_unit_bytes();
extern virtual function uvm_endianness_e get_endian (uvm_hier_e hier=UVM_HIER);
extern virtual function uvm_sequencer_base get_sequencer (uvm_hier_e hier=UVM_HIER);
extern virtual function uvm_reg_adapter get_adapter (uvm_hier_e hier=UVM_HIER);
extern virtual function void get_submaps (ref uvm_reg_map maps[$],
extern virtual function void get_registers (ref uvm_reg regs[$],
extern virtual function void get_fields (ref uvm_reg_field fields[$],
extern virtual function void get_memories (ref uvm_mem mems[$],
extern virtual function void get_virtual_registers (ref uvm_vreg regs[$],
extern virtual function void get_virtual_fields (ref uvm_vreg_field fields[$],
extern virtual function uvm_reg_map_info get_reg_map_info(uvm_reg rg, bit error=1);
extern virtual function uvm_reg_map_info get_mem_map_info(uvm_mem mem, bit error=1);
extern virtual function int unsigned get_size();
extern virtual function int get_physical_addresses(uvm_reg_addr_t base_addr,
extern virtual function uvm_reg get_reg_by_offset(uvm_reg_addr_t offset,
extern virtual function uvm_mem get_mem_by_offset(uvm_reg_addr_t offset);
extern virtual task do_bus_write (uvm_reg_item rw,
extern virtual task do_bus_read (uvm_reg_item rw,
extern virtual task do_write(uvm_reg_item rw);
extern virtual task do_read(uvm_reg_item rw);
extern virtual function string convert2string();
extern virtual function uvm_object clone();
extern virtual function void do_print (uvm_printer printer);
extern virtual function void do_copy (uvm_object rhs);
//extern virtual function bit do_compare (uvm_object rhs, uvm_comparer comparer);
//extern virtual function void do_pack (uvm_packer packer);
//extern virtual function void do_unpack (uvm_packer packer);
2.5 uvm_reg_file
UVM还提供了uvm_reg_file类。这个类更像是一个对象容器,可以用来装载多个寄存器(uvm_reg)和其他uvm_reg_file,以便对相同规格的寄存器进行多次例化。
extern virtual function string get_full_name();
extern virtual function uvm_reg_block get_parent ();
extern virtual function uvm_reg_block get_block ();
extern virtual function uvm_reg_file get_regfile ();
extern virtual function void do_print (uvm_printer printer);
extern virtual function string convert2string();
extern virtual function uvm_object clone ();
extern virtual function void do_copy (uvm_object rhs);
extern virtual function bit do_compare (uvm_object rhs,
extern virtual function void do_pack (uvm_packer packer);
extern virtual function void do_unpack (uvm_packer packer);
2.6 uvm_mem
在同一类族中,UVM还提供了uvm_mem类,用于对连续地址存储空间的建模。uvm_mem对象也可以被集成到uvm_reg_block中,并通过uvm_reg_map做地址映射,
extern virtual function void set_offset (uvm_reg_map map,
/*local*/ extern virtual function void set_parent(uvm_reg_block parent);
extern virtual function string get_full_name();
extern virtual function uvm_reg_block get_parent ();
extern virtual function uvm_reg_block get_block ();
extern virtual function int get_n_maps ();
extern virtual function void get_maps (ref uvm_reg_map maps[$]);
extern virtual function string get_rights (uvm_reg_map map = null);
extern virtual function string get_access(uvm_reg_map map = null);
extern virtual function void get_virtual_registers(ref uvm_vreg regs[$]);
extern virtual function void get_virtual_fields(ref uvm_vreg_field fields[$]);
extern virtual function uvm_vreg get_vreg_by_name(string name);
extern virtual function uvm_vreg_field get_vfield_by_name(string name);
extern virtual function uvm_vreg get_vreg_by_offset(uvm_reg_addr_t offset,
extern virtual function uvm_reg_addr_t get_offset (uvm_reg_addr_t offset = 0,
extern virtual function uvm_reg_addr_t get_address(uvm_reg_addr_t offset = 0,
extern virtual function int get_addresses(uvm_reg_addr_t offset = 0,
extern virtual task write(output uvm_status_e status,
extern virtual task read(output uvm_status_e status,
extern virtual task burst_write(output uvm_status_e status,
extern virtual task burst_read(output uvm_status_e status,
extern virtual task poke(output uvm_status_e status,
extern virtual task peek(output uvm_status_e status,
extern virtual task do_write (uvm_reg_item rw);
extern virtual task do_read (uvm_reg_item rw);
extern virtual protected task backdoor_read(uvm_reg_item rw);
extern virtual task backdoor_write(uvm_reg_item rw);
extern virtual function uvm_status_e backdoor_read_func(uvm_reg_item rw);
extern virtual protected function void add_coverage(uvm_reg_cvr_t models);
extern virtual function bit has_coverage(uvm_reg_cvr_t models);
extern virtual function uvm_reg_cvr_t set_coverage(uvm_reg_cvr_t is_on);
extern virtual function bit get_coverage(uvm_reg_cvr_t is_on);
extern virtual function void do_print (uvm_printer printer);
extern virtual function string convert2string();
extern virtual function uvm_object clone();
extern virtual function void do_copy (uvm_object rhs);
extern virtual function bit do_compare (uvm_object rhs,
extern virtual function void do_pack (uvm_packer packer);
extern virtual function void do_unpack (uvm_packer packer);
三,一个完备的寄存器模型
注意:多个寄存器及其访问译码表最终构成寄存器组。在同个数字系统的不同总线视角下,寄存器组可以映射到不同的基地址(base)。因此,一个寄存器组除了可以包含多个寄存器,还可以有多个译码表。
三, 如何instance到UVM验证环境
试想,如果仅仅是简单把寄存器模型集成到验证环境,那么只要例化寄存器模型就可以了。
现在主要的问题是,建立怎样的机制才可以让寄存器模型“实时”复刻RTL寄存器的值。
为了解决这个问题,UVM引入Prediction机制,而且用到了两个新的组件:Adapter和Predictor。请看下节内容。