APB_timer中的寄存器模型集成——代码理解

目录

一、建立寄存器模型步骤

1、在文件timer_regmodel.sv中:

首先声明寄存器(只举两个寄存器为例):

声明寄存器块:

2、Adapter的实现:

Adapter桥接器的作用:

timer_reg_adapter中:

3、Adapter等的集成

timer_env中:

(1)、声明:

​编辑

(2)、例化:

(3)、连接:

4、寄存器模型访问

timer_base_virtual_sequence中

寄存器模型的复位:

timer_integration_virt_seq中

寄存器访问和检查:

read和write任务:

mirror操作:

5、timer_base_test中


一、建立寄存器模型步骤

1、在文件timer_regmodel.sv中:
首先声明寄存器(只举两个寄存器为例):

APB_timer中的寄存器模型集成——代码理解_第1张图片

APB_timer中的寄存器模型集成——代码理解_第2张图片

声明寄存器块:

APB_timer中的寄存器模型集成——代码理解_第3张图片

  • 在这里可以设置覆盖率收集,也可以不设置,我们不设置,因为会生成一些不需要不期望的相关值,后续会从APB总线上来监测覆盖率并收集;
  • 寄存器模型 build()函数最后以 lock_model()结尾,该函数的功能是结束地址映射关系, 并且保证模型不会被其他用户修改

uvm_reg_map:

        用于存储寄存器映射的实例,用于在寄存器块中访问寄存器映射。

2、Adapter的实现:
Adapter桥接器的作用:
  • 在adapter中主要进行 uvm_reg_bus_op与总线transaction中各自的数据映射;
  • 实现reg2bus()和bus2reg()两个函数,这两个函数实现了两种transaction的数据映射;
  • 如果总线支持 byte 访问,可以使能 supports_byte_enable;如果总线 UVC 要返回 response 数据,则应当使能 provides_responses。
  • 在本例中,mcdf_bus_driver 在读数时 会将读回的数据填入到 RSP 并返回至 sequencer,因此需要在 adapter 中使能 provides_responses。由此使得 bus2reg()函数调用时得到的数据是总线返回时的 transaction ,但读者需要注意如果总线 UVC 不支持返回 RSP (没有调用 put_response(RSP)或 item_done(RSP)),那么不应该置此位,否则 adapter 将会使得验证环境挂起。默认情况下,上述的两个成员的复位值都是 0。
  • 如下所示,uvm_reg_bus_op 类的成员包含 6 个域。
  • APB_timer中的寄存器模型集成——代码理解_第4张图片
timer_reg_adapter中:

APB_timer中的寄存器模型集成——代码理解_第5张图片

3、Adapter等的集成
  • 在具备了寄存器模型 rgm、总线 UVC (总线通用验证组件)和桥接 adapter 后,就需要考虑如何将 adapter 集成到验证环境中去了
  •  对于 mcdf_rgm 的集成,我们倾向于顶层传递的方式,即最终从 test 层传入寄存器模型句柄。这种方式有利于验证环境env 的闭合性,在后期不同 test 对 rgm 做不同的配置时可以在顶层例化,而后通过 uvm_config_db 来传递。
  • 寄存器模型在创建之后要显式调用 build()函数。需要注意 uvm_reg_block 是 uvm_object 类型,因此其预定义的 build()函数并不自动执行,还需要单独调用。
  • 在顶层环境的 connect 阶段中,需要将寄存器模型的 map 组件与 bus sequencer 和 adapter 连接。这么做的必要性在于将 map(寄存器信息)、sequencer(总线侧激励驱动)和 adapter(寄存器级别和硬件总线级别的桥接)关联在一起。也只有通过这一 步,adapter 的桥接功能才可以工作。
timer_env中:
(1)、声明:
(2)、例化:

APB_timer中的寄存器模型集成——代码理解_第6张图片

调用build()函数才能创建uvm_reg,调用uvm_reg里的field等的例化配置

(3)、连接:

APB_timer中的寄存器模型集成——代码理解_第7张图片

  • set_sequencer的作用:

        adapter、squencer、map三者的关系,首先需要在环境(一般在env层次时)需要连接三者通过map.set_sequencer(squencer,adapter);因为本身rgm充当sequence,adapter充当转换的桥梁,而rgm中因为有lock_model只有map能访问内部reg的field,而对于传到bus上也需要用bus的sequencer进行和drv的传递,所以三者是要关联的,这样adapter才能工作。

  • 关于predictor的作用:

        这里使用了predictor的显式预测,如下:

        只用声明例化preditor,并且将map和adapter的句柄给它内部的map和adapter,monitor上要是analysis port然后连接到它的bus_in端口。//预定义好的bus_in  analysis port

APB_timer中的寄存器模型集成——代码理解_第8张图片

4、寄存器模型访问
timer_base_virtual_sequence中

声明了rgm句柄和一个变量uvm_status_e(详细看看用法)

APB_timer中的寄存器模型集成——代码理解_第9张图片

寄存器模型的复位:
  • 在task body()中进行
task body();
    fork
        wait_reset_asserted();      //复位函数
    join_none
endtask

task wait_reset_asserted();
    forever begin
        @(negedge vif.apb_rstn);
        rgm.reset();
    end
endtask
  • uvm_status_e status是前面uvm_reg_bus_op类的成员变量,有三种值UVM_IS_OK、UVM_IS_X、UVM_NOT_OK。
timer_integration_virt_seq中
寄存器访问和检查:

APB_timer中的寄存器模型集成——代码理解_第10张图片

APB_timer中的寄存器模型集成——代码理解_第11张图片

read和write任务:

        read任务的原型为:

extern virtual task read(output uvm_status_e status,
                         output uvm_reg_data_t value,
                         input uvm_path_e path = UVM_DEFAULT_PATH,
                         input uvm_reg_map map = null,
                         input uvm_sequence_base parent = null,
                         input int prior = -1,
                         input uvm_object extension = null,
                         input string fname = "",
                         input int lineno = 0);
  • 它有多个参数,常用的是其前三个参数。其中第一个是uvm_status_e型的变量,这是一个输出,用于表明读操作是否成功; 第二个是读取的数值,也是一个输出;第三个是读取的方式,可选UVM_FRONTDOOR和UVM_BACKDOOR。

        write任务的原型为:

extern virtual task write(output uvm_status_e status,
                          input uvm_reg_data_t value,
                          input uvm_path_e path = UVM_DEFAULT_PATH,
                          input uvm_reg_map map = null,
                          input uvm_sequence_base parent = null,
                          input int prior = -1,
                          input uvm_object extension = null,
                          input string fname = "",
                          input int lineno = 0);
  • 它的参数也有很多个,但是与read类似,常用的也只有前三个。其中第一个为uvm_status_e型的变量,这是一个输出,用于表 明写操作是否成功。第二个要写的值,是一个输入,第三个是写操作的方式,可选UVM_FRONTDOOR和UVM_BACKDOOR。
  • 寄存器模型对sequence的transaction类型没有任何要求。因此,可以在一个发送my_transaction的sequence中使用寄存器模型对寄存器进行读写操作。
mirror操作:
  • UVM提供mirror操作,用于读取DUT中寄存器的值并将它们更新到寄存器模型中。它的函数原型为:
task uvm_reg::mirror(output uvm_status_e status,
                    input uvm_check_e check = UVM_NO_CHECK,
                    input uvm_path_e path = UVM_DEFAULT_PATH,
…);
  • 它有多个参数,但是常用的只有前三个。其中第二个参数指的是如果发现DUT中寄存器的值与寄存器模型中的镜像值不一 致,那么在更新寄存器模型之前是否给出错误提示。其可选的值为UVM_CHECK和UVM_NO_CHECK。
  • 它有两种应用场景,一是在仿真中不断地调用它,使得到整个寄存器模型的值与DUT中寄存器的值保持一致,此时check选项 是关闭的。二是在仿真即将结束时,检查DUT中寄存器的值与寄存器模型中寄存器的镜像值是否一致,这种情况下,check选项是打开的。
  • mirror操作会更新期望值和镜像值。同update操作类似,mirror操作既可以在uvm_reg级别被调用,也可以在uvm_reg_block级别 被调用。当调用一个uvm_reg_block的mirror时,其实质是调用加入其中的所有寄存器的mirror。
5、timer_base_test中

主要进行寄存器块rgm句柄的顶层例化,并将句柄传递给下层environment

APB_timer中的寄存器模型集成——代码理解_第12张图片

你可能感兴趣的:(前端)