目录
0.前言
在UVM学习笔记—寄存器模型的搭建及使用中提到过前门访问和后门访问的概念,这篇文章将会详细的阐述一下这2种访问方式
1.前门访问
前门访问操作就是通过寄存器配置总线(如APB总线)来对DUT进行操作,因此其在波形上可见。无论在任何总线协议中,前门访问操作只有两种:读操作和写操作;前门访问实际上是一个贴合实际的访问方式,因为对于流片回来的芯片,其访问方式只能通过物理总线访问。
对于前门访问的读操作的执行过程在白皮书P230-231有详细的描述,在此不再copy,这里将整个过程画一个草图示意:
当在某个component或者seq中调用寄存器模型通过前门访问向DUT发起读操作时,寄存器模型产生uvm_reg_bus_op的变量,该变量通过adapter转换成sqr能接收的transaction类型交给sqr,sqr再交给driver,driver驱动到DUT上,然后得到读取的数值,该数值放入rsp中然后调用item done,该rsp直接返回到adapter的bus2reg中进行转换回uvm_reg_bus_op变量被reg model接收;为何需要用到rsp来返回,这里涉及到seq,sqr和driver的握手机制,后续会另写一篇文章讲解。
2.后门访问
后门访问是通过设置好每个寄存器的路径进行访问的,而且不消耗仿真时间,但因为未通过总线进行读写因此无法在波形上体现出来。
那么为何要存在后门访问这种形式呢?考虑到2点:一是当需要验证成百上千个寄存器时,通过前门访问需要消耗大量的时间,效率并不高;二十如果对于一个16位的计数器(计数时钟上升沿的个数),想要验证其在16'hffff时再加1是否会回到16'h0000,如果通过前门访问需要1位1位累加,这需要相当长的时间,但如果通过后门访问直接修改位16'hffff再开启时钟则瞬间就能验证完这个验证点。
2.1路径设置
后门访问最关键的就是要设置好每个寄存器的路径,那么该如何设置呢?
在UVM学习笔记—寄存器模型的搭建及使用中讲搭建reg block时,对于每个寄存器有一个configure操作:
class reg_block extends uvm_reg_block;
······
invert.configure(this, null, "invert");//第三个参数即后门访问路径
······
endclass
而在base test时有一个设置绝对路径的操作:
function void base_test::build_phase(uvm_phase phase);
······
rm.set_hdl_path_root("top_tb.my_dut");
······
endfunction
这两个路径合起来就是invert寄存器的路径,实际验证中这个路径类似于如下:
2.2操作类型
前面的前门/后门操作都有读写两种操作:
reg_model.INVERT_REG.read(status, value, UVM_FRONTDOOR);//前门读
reg_model.INVERT_REG.write(status, 16'h1, UVM_FRONTDOOR);//前门写
reg_model.INVERT_REG.read(status, value, UVM_BACKDOOR);//后门读
reg_model.INVERT_REG.write(status, 16'h1, UVM_BACKDOOR);//后门写
后门访问新增了peek/poke操作:
reg_model.INVERT_REG.peek(status, value, UVM_BACKDOOR);// 通过后门访问方式读取寄存器的值,不关心DUT的行为,即使寄存器的读写类型是不能读,也可以将值读出来
reg_model.INVERT_REG.poke(status, 16'h1, UVM_BACKDOOR);//通过后门访问方式写入寄存器的值,不关心DUT的行为,即使寄存器的读写类型是不能写,也可以将值写进去
对于read clear类型的field,peek读操作不会clear,所以有的时候peek和read操作结果不一样
对于write clear类型的filed,poke操作不会clear,所以有的时候poke和write操作结果不一样